diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp --- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp +++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp @@ -165,8 +165,8 @@ } auto isCallReturningOptional() { - return callExpr(callee(functionDecl(returns(anyOf( - optionalOrAliasType(), referenceType(pointee(optionalOrAliasType()))))))); + return callExpr(hasType(qualType(anyOf( + optionalOrAliasType(), referenceType(pointee(optionalOrAliasType())))))); } /// Creates a symbolic value for an `optional` value using `HasValueVal` as the diff --git a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp --- a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp @@ -179,6 +179,11 @@ namespace detail { +template +auto try_add_lvalue_reference(int) -> type_identity; +template +auto try_add_lvalue_reference(...) -> type_identity; + template auto try_add_rvalue_reference(int) -> type_identity; template @@ -186,6 +191,10 @@ } // namespace detail +template +struct add_lvalue_reference : decltype(detail::try_add_lvalue_reference(0)) { +}; + template struct add_rvalue_reference : decltype(detail::try_add_rvalue_reference(0)) { }; @@ -2318,6 +2327,26 @@ UnorderedElementsAre(Pair("merge", "unsafe: input.cc:19:7"))); } +TEST_P(UncheckedOptionalAccessTest, AssignThroughLvalueReferencePtr) { + ExpectLatticeChecksFor( + R"( + #include "unchecked_optional_access_test.h" + + template + struct smart_ptr { + typename std::add_lvalue_reference::type operator*() &; + }; + + void target() { + smart_ptr<$ns::$optional> x; + *x = $ns::nullopt; + (*x).value(); + /*[[check]]*/ + } + )", + UnorderedElementsAre(Pair("check", "unsafe: input.cc:12:7"))); +} + // FIXME: Add support for: // - constructors (copy, move) // - assignment operators (default, copy, move)