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
