https://github.com/KHicketts created 
https://github.com/llvm/llvm-project/pull/234916

None

>From 0862a455ce37eddd07b4fa6949da43e647b74d65 Mon Sep 17 00:00:00 2001
From: khickett <[email protected]>
Date: Fri, 23 Oct 2026 12:36:15 +0100
Subject: [PATCH] handle curiously recurring template pattern

---
 .../Models/UncheckedOptionalAccessModel.cpp   | 15 ++++++++++
 .../UncheckedOptionalAccessModelTest.cpp      | 29 +++++++++++++++++++
 2 files changed, 44 insertions(+)

diff --git 
a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp 
b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
index 568564fb361f4a..7c792c2c7dcf5e 100644
--- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
@@ -447,7 +447,22 @@ BoolValue *getHasValue(Environment &Env, 
RecordStorageLocation *OptionalLoc) {
 }
 
 QualType valueTypeFromOptionalDecl(const CXXRecordDecl &RD) {
+
   auto &CTSD = cast<ClassTemplateSpecializationDecl>(RD);
+
+  // handle curiously recurring template pattern
+  if (RD.hasDefinition()) {
+    IdentifierInfo &id = RD.getASTContext().Idents.get("value_type");
+    DeclContextLookupResult Lookup = RD.lookup(&id);
+    if (!Lookup.empty()) {
+      auto *TypeND = dyn_cast<TypedefNameDecl>(Lookup.front());
+      if (TypeND) {
+        return TypeND->getUnderlyingType();
+      }
+    }
+  }
+
+  // if this is a regular template with a type
   return CTSD.getTemplateArgs()[0].getAsType();
 }
 
diff --git 
a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp 
b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp
index f34568a072c324..d57da7bcf81cfa 100644
--- 
a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp
+++ 
b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp
@@ -3016,6 +3016,35 @@ TEST_P(UncheckedOptionalAccessTest, 
AssertFalseGtestMacroWithNullableValue) {
   )cc");
 }
 
+// The optional class is recognized by name, so its template parameters need
+// not start with the value type. Here the first parameter is the derived class
+// (CRTP); the value type must come from `value_type`, not template argument 0.
+TEST_P(UncheckedOptionalAccessTest, OptionalWithDerivedFirstTemplateParam) {
+  ExpectDiagnosticsFor(R"cc(
+    #include "unchecked_optional_access_test.h"
+
+    namespace folly {
+    template <typename Derived, typename T>
+    class Optional {
+    public:
+      using value_type = T;
+      bool has_value() const;
+      T &operator*();
+      T &value();
+    };
+    } // namespace folly
+
+    struct IntOptional : folly::Optional<IntOptional, int> {};
+
+    void target(IntOptional opt) {
+      *opt; // [[unsafe]]
+      if (opt.has_value()) {
+        opt.value();
+      }
+    }
+  )cc");
+}
+
 // FIXME: Add support for:
 // - constructors (copy, move)
 // - assignment operators (default, copy, move)

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to