diff --git a/clang/lib/Analysis/LifetimeSafety/Origins.cpp b/clang/lib/Analysis/LifetimeSafety/Origins.cpp index ea51a75324e06..0f2eaa94a5987 100644 --- a/clang/lib/Analysis/LifetimeSafety/Origins.cpp +++ b/clang/lib/Analysis/LifetimeSafety/Origins.cpp @@ -34,6 +34,8 @@ Origin &OriginManager::addOrigin(OriginID ID, const clang::Expr &E) { // TODO: Mark this method as const once we remove the call to getOrCreate. OriginID OriginManager::get(const Expr &E) { + if (auto *ParenIgnored = E.IgnoreParens(); ParenIgnored != &E) + return get(*ParenIgnored); auto It = ExprToOriginID.find(&E); if (It != ExprToOriginID.end()) return It->second; diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp index 3460a8675bf04..b9368db550805 100644 --- a/clang/test/Sema/warn-lifetime-safety.cpp +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -655,3 +655,34 @@ void conditional_operator_lifetimebound_nested_deep(bool cond) { } // expected-note 4 {{destroyed here}} (void)*p; // expected-note 4 {{later used here}} } + +void parentheses(bool cond) { + MyObj* p; + { + MyObj a; + p = &((((a)))); // expected-warning {{object whose reference is captured does not live long enough}} + } // expected-note {{destroyed here}} + (void)*p; // expected-note {{later used here}} + + { + MyObj a; + p = ((GetPointer((a)))); // expected-warning {{object whose reference is captured does not live long enough}} + } // expected-note {{destroyed here}} + (void)*p; // expected-note {{later used here}} + + { + MyObj a, b, c, d; + p = &(cond ? (cond ? a // expected-warning {{object whose reference is captured does not live long enough}}. + : b) // expected-warning {{object whose reference is captured does not live long enough}}. + : (cond ? c // expected-warning {{object whose reference is captured does not live long enough}}. + : d)); // expected-warning {{object whose reference is captured does not live long enough}}. + } // expected-note 4 {{destroyed here}} + (void)*p; // expected-note 4 {{later used here}} + + { + MyObj a, b, c, d; + p = ((cond ? (((cond ? &a : &b))) // expected-warning 2 {{object whose reference is captured does not live long enough}}. + : &(((cond ? c : d))))); // expected-warning 2 {{object whose reference is captured does not live long enough}}. + } // expected-note 4 {{destroyed here}} + (void)*p; // expected-note 4 {{later used here}} +} diff --git a/clang/unittests/Analysis/LifetimeSafetyTest.cpp b/clang/unittests/Analysis/LifetimeSafetyTest.cpp index 9d61d56e078e3..601308c53f9a9 100644 --- a/clang/unittests/Analysis/LifetimeSafetyTest.cpp +++ b/clang/unittests/Analysis/LifetimeSafetyTest.cpp @@ -700,6 +700,23 @@ TEST_F(LifetimeAnalysisTest, GslPointerInConditionalOperator) { EXPECT_THAT(Origin("v"), HasLoansTo({"a", "b"}, "p1")); } +TEST_F(LifetimeAnalysisTest, ExtraParenthesis) { + SetupTest(R"( + void target() { + MyObj a; + View x = ((View((((a)))))); + View y = ((View{(((x)))})); + View z = ((View(((y))))); + View p = ((View{((x))})); + POINT(p1); + } + )"); + EXPECT_THAT(Origin("x"), HasLoansTo({"a"}, "p1")); + EXPECT_THAT(Origin("y"), HasLoansTo({"a"}, "p1")); + EXPECT_THAT(Origin("z"), HasLoansTo({"a"}, "p1")); + EXPECT_THAT(Origin("p"), HasLoansTo({"a"}, "p1")); +} + // FIXME: Handle temporaries. TEST_F(LifetimeAnalysisTest, ViewFromTemporary) { SetupTest(R"(