https://github.com/NeKon69 updated https://github.com/llvm/llvm-project/pull/191731
>From 382e365ec09c88eb36fbd83874a5923295fe9b95 Mon Sep 17 00:00:00 2001 From: NeKon69 <[email protected]> Date: Sun, 12 Apr 2026 21:24:43 +0300 Subject: [PATCH 01/18] [LifetimeSafety] implement basic fix, add tests --- .../Analyses/LifetimeSafety/FactsGenerator.h | 2 ++ .../LifetimeSafety/FactsGenerator.cpp | 14 ++++++++ clang/test/Sema/warn-lifetime-safety.cpp | 32 +++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h index 2dbadb27981a7..a3b759c473a16 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h @@ -74,6 +74,8 @@ class FactsGenerator : public ConstStmtVisitor<FactsGenerator> { void handleExitBlock(); + void handleImplicitObjectFieldUses(const Expr *Call, const FunctionDecl *FD); + void handleGSLPointerConstruction(const CXXConstructExpr *CCE); /// Detects arguments passed to rvalue reference parameters and creates diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp index 82b890b57817e..eaf26cb49aba5 100644 --- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp +++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp @@ -723,6 +723,19 @@ void FactsGenerator::handleInvalidatingCall(const Expr *Call, ThisList->getOuterOriginID(), Call)); } +void FactsGenerator::handleImplicitObjectFieldUses(const Expr *Call, + const FunctionDecl *FD) { + const auto *MD = dyn_cast<CXXMethodDecl>(FD); + if (!MD || !MD->isInstance()) + return; + + for (const auto *Field : MD->getParent()->fields()) { + OriginList *FieldList = getOriginsList(*Field); + if (FieldList) + CurrentBlockFacts.push_back(FactMgr.createFact<UseFact>(Call, FieldList)); + } +} + void FactsGenerator::handleFunctionCall(const Expr *Call, const FunctionDecl *FD, ArrayRef<const Expr *> Args, @@ -737,6 +750,7 @@ void FactsGenerator::handleFunctionCall(const Expr *Call, handleUse(Arg); handleInvalidatingCall(Call, FD, Args); handleMovedArgsInCall(FD, Args); + handleImplicitObjectFieldUses(Call, FD); if (!CallList) return; auto IsArgLifetimeBound = [FD](unsigned I) -> bool { diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp index 77d8e3370676d..63a82680955ac 100644 --- a/clang/test/Sema/warn-lifetime-safety.cpp +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -2531,3 +2531,35 @@ int *noreturn_dead_nested(bool cond, bool cond2, int *num) { } } // namespace conditional_operator_control_flow + +namespace method_call_uses_field_origins { +// https://github.com/llvm/llvm-project/issues/182945 + +int val; + +struct S { +public: + int* p_; + void bar(); + void foo() { + { + int num; + this->p_ = # // expected-warning {{object whose reference is captured does not live long enough}} + } // expected-note {{destroyed here}} + bar(); // expected-note {{later used here}} + this->p_ = &val; + } +}; + +// FIXME: False-positive: the analysis tracks a, but not that it belongs to s1. +void foo() { + S s; + { + int num; + s.p_ = # + } + s.bar(); + s.p_ = &val; +} + +} // namespace method_call_uses_field_origins >From ae721e42f219fe61c85493c7699673b099838145 Mon Sep 17 00:00:00 2001 From: NeKon69 <[email protected]> Date: Sun, 12 Apr 2026 21:41:44 +0300 Subject: [PATCH 02/18] add a new test --- clang/test/Sema/warn-lifetime-safety.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp index 63a82680955ac..1864247e53886 100644 --- a/clang/test/Sema/warn-lifetime-safety.cpp +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -2551,6 +2551,16 @@ struct S { } }; +struct T { +public: + std::string_view v; + void bar(); + void foo() { + v = std::string("tmp"); // expected-warning {{object whose reference is captured does not live long enough}} expected-note {{destroyed here}} + bar(); // expected-note {{later used here}} + } +}; + // FIXME: False-positive: the analysis tracks a, but not that it belongs to s1. void foo() { S s; >From 69897653f520b9c26843ccf8aa51684420f32548 Mon Sep 17 00:00:00 2001 From: NeKon69 <[email protected]> Date: Sun, 12 Apr 2026 22:23:49 +0300 Subject: [PATCH 03/18] update failed test --- clang/unittests/Analysis/LifetimeSafetyTest.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/clang/unittests/Analysis/LifetimeSafetyTest.cpp b/clang/unittests/Analysis/LifetimeSafetyTest.cpp index 6cf65dd64ef83..879df0d147267 100644 --- a/clang/unittests/Analysis/LifetimeSafetyTest.cpp +++ b/clang/unittests/Analysis/LifetimeSafetyTest.cpp @@ -1408,7 +1408,6 @@ TEST_F(LifetimeAnalysisTest, TrivialClassDestructorsUAF) { } )"); EXPECT_THAT(Origin("ptr"), HasLoansTo({"s"}, "p1")); - EXPECT_THAT(Origins({"ptr"}), MustBeLiveAt("p1")); } TEST_F(LifetimeAnalysisTest, SimpleReturnStackAddress) { >From 806694352ec90e0785a10fe9254adf20f86b640b Mon Sep 17 00:00:00 2001 From: NeKon69 <[email protected]> Date: Mon, 13 Apr 2026 09:13:37 +0300 Subject: [PATCH 04/18] update test --- clang/test/Sema/warn-lifetime-safety.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp index 1864247e53886..ef1911ede59ad 100644 --- a/clang/test/Sema/warn-lifetime-safety.cpp +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -2533,9 +2533,8 @@ int *noreturn_dead_nested(bool cond, bool cond2, int *num) { } // namespace conditional_operator_control_flow namespace method_call_uses_field_origins { -// https://github.com/llvm/llvm-project/issues/182945 - int val; +std::string GLOBAL{"123"}; struct S { public: @@ -2559,9 +2558,16 @@ struct T { v = std::string("tmp"); // expected-warning {{object whose reference is captured does not live long enough}} expected-note {{destroyed here}} bar(); // expected-note {{later used here}} } + void baz(){ + std::vector<std::string> vec = {"42"}; + v = vec[0]; // expected-warning {{object whose reference is captured is later invalidated}} + vec.push_back("1"); // expected-note {{invalidated here}} + bar(); // expected-note {{later used here}} + v = GLOBAL; + } }; -// FIXME: False-positive: the analysis tracks a, but not that it belongs to s1. +// FIXME: False-negative: the analysis tracks `p_`, but not that it belongs to s1. void foo() { S s; { >From 91ce6ffbe52ae0a41c28629e40dc33b0efe2116a Mon Sep 17 00:00:00 2001 From: NeKon69 <[email protected]> Date: Mon, 13 Apr 2026 09:17:01 +0300 Subject: [PATCH 05/18] add a comment --- .../clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h index a3b759c473a16..000f0dde2217d 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h @@ -74,6 +74,8 @@ class FactsGenerator : public ConstStmtVisitor<FactsGenerator> { void handleExitBlock(); + /// Mark all fields of the implicit object as used for an instance method + /// call, since the callee may access any part of the object. void handleImplicitObjectFieldUses(const Expr *Call, const FunctionDecl *FD); void handleGSLPointerConstruction(const CXXConstructExpr *CCE); >From 13dc1c4a8d9d71874dd38197e1bec536166ccfa7 Mon Sep 17 00:00:00 2001 From: NeKon69 <[email protected]> Date: Mon, 13 Apr 2026 11:15:25 +0300 Subject: [PATCH 06/18] address review comments --- .../LifetimeSafety/FactsGenerator.cpp | 6 ++--- .../warn-lifetime-safety-invalidations.cpp | 15 +++++++++++ clang/test/Sema/warn-lifetime-safety.cpp | 25 +++++++++---------- 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp index eaf26cb49aba5..1fbee2f3598d9 100644 --- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp +++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp @@ -729,11 +729,9 @@ void FactsGenerator::handleImplicitObjectFieldUses(const Expr *Call, if (!MD || !MD->isInstance()) return; - for (const auto *Field : MD->getParent()->fields()) { - OriginList *FieldList = getOriginsList(*Field); - if (FieldList) + for (const auto *Field : MD->getParent()->fields()) + if (auto *FieldList = getOriginsList(*Field)) CurrentBlockFacts.push_back(FactMgr.createFact<UseFact>(Call, FieldList)); - } } void FactsGenerator::handleFunctionCall(const Expr *Call, diff --git a/clang/test/Sema/warn-lifetime-safety-invalidations.cpp b/clang/test/Sema/warn-lifetime-safety-invalidations.cpp index c7f920c03736a..5a77ac97d16b1 100644 --- a/clang/test/Sema/warn-lifetime-safety-invalidations.cpp +++ b/clang/test/Sema/warn-lifetime-safety-invalidations.cpp @@ -512,3 +512,18 @@ void ref_capture_reassigned_to_safe() { lambda(); // should not warn } } // namespace lambda_capture_invalidation + +namespace method_call_uses_field_invalidation { + +struct S { + std::string_view v; + void bar(); + void baz(){ + std::vector<std::string> vec = {"42"}; + v = vec[0]; // expected-warning {{object whose reference is captured is later invalidated}} + vec.push_back("1"); // expected-note {{invalidated here}} + bar(); // expected-note {{later used here}} + v = nullptr; + } +}; +} // namespace method_call_uses_field_invalidation diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp index ef1911ede59ad..4e562d6a7c06c 100644 --- a/clang/test/Sema/warn-lifetime-safety.cpp +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -2533,11 +2533,10 @@ int *noreturn_dead_nested(bool cond, bool cond2, int *num) { } // namespace conditional_operator_control_flow namespace method_call_uses_field_origins { -int val; -std::string GLOBAL{"123"}; +int GLOBAL_INT; +std::string GLOBAL_STRING{"123"}; struct S { -public: int* p_; void bar(); void foo() { @@ -2546,25 +2545,25 @@ struct S { this->p_ = # // expected-warning {{object whose reference is captured does not live long enough}} } // expected-note {{destroyed here}} bar(); // expected-note {{later used here}} - this->p_ = &val; + this->p_ = &GLOBAL_INT; + } + void baz() { + { + int num; + this->p_ = # + } + this->p_ = &GLOBAL_INT; + bar(); } }; struct T { -public: std::string_view v; void bar(); void foo() { v = std::string("tmp"); // expected-warning {{object whose reference is captured does not live long enough}} expected-note {{destroyed here}} bar(); // expected-note {{later used here}} } - void baz(){ - std::vector<std::string> vec = {"42"}; - v = vec[0]; // expected-warning {{object whose reference is captured is later invalidated}} - vec.push_back("1"); // expected-note {{invalidated here}} - bar(); // expected-note {{later used here}} - v = GLOBAL; - } }; // FIXME: False-negative: the analysis tracks `p_`, but not that it belongs to s1. @@ -2575,7 +2574,7 @@ void foo() { s.p_ = # } s.bar(); - s.p_ = &val; + s.p_ = &GLOBAL_INT; } } // namespace method_call_uses_field_origins >From 8d623bb7c8a74a5e08b02f68987e3ab86ba4a7e8 Mon Sep 17 00:00:00 2001 From: NeKon69 <[email protected]> Date: Mon, 13 Apr 2026 14:41:06 +0300 Subject: [PATCH 07/18] use base fields too (doesn't work currently) --- .../LifetimeSafety/FactsGenerator.cpp | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp index 1fbee2f3598d9..3e4807c5b2e48 100644 --- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp +++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp @@ -729,9 +729,26 @@ void FactsGenerator::handleImplicitObjectFieldUses(const Expr *Call, if (!MD || !MD->isInstance()) return; - for (const auto *Field : MD->getParent()->fields()) - if (auto *FieldList = getOriginsList(*Field)) - CurrentBlockFacts.push_back(FactMgr.createFact<UseFact>(Call, FieldList)); + const auto *ClassDecl = MD->getParent()->getDefinition(); + if (!ClassDecl) + return; + + const auto UseFields = + [&](const CXXRecordDecl *RD) { + for (const auto *Field : RD->fields()) + if (auto *FieldList = getOriginsList(*Field)) { + CurrentBlockFacts.push_back( + FactMgr.createFact<UseFact>(Call, FieldList)); + Field->dumpColor(); + } + }; + + UseFields(ClassDecl); + + ClassDecl->forallBases([&](const CXXRecordDecl *Base) { + UseFields(Base); + return true; + }); } void FactsGenerator::handleFunctionCall(const Expr *Call, >From d6e79449ea987347c94e8b86f44dad2b703bd7c1 Mon Sep 17 00:00:00 2001 From: NeKon69 <[email protected]> Date: Mon, 13 Apr 2026 14:45:35 +0300 Subject: [PATCH 08/18] cleanup lambda --- .../Analysis/LifetimeSafety/FactsGenerator.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp index 3e4807c5b2e48..71614407b8558 100644 --- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp +++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp @@ -733,15 +733,12 @@ void FactsGenerator::handleImplicitObjectFieldUses(const Expr *Call, if (!ClassDecl) return; - const auto UseFields = - [&](const CXXRecordDecl *RD) { - for (const auto *Field : RD->fields()) - if (auto *FieldList = getOriginsList(*Field)) { - CurrentBlockFacts.push_back( - FactMgr.createFact<UseFact>(Call, FieldList)); - Field->dumpColor(); - } - }; + const auto UseFields = [&](const CXXRecordDecl *RD) { + for (const auto *Field : RD->fields()) + if (auto *FieldList = getOriginsList(*Field)) + CurrentBlockFacts.push_back( + FactMgr.createFact<UseFact>(Call, FieldList)); + }; UseFields(ClassDecl); >From 8f3bc9471798647829e51af5bc41d78156f53e1d Mon Sep 17 00:00:00 2001 From: NeKon69 <[email protected]> Date: Mon, 13 Apr 2026 15:52:08 +0300 Subject: [PATCH 09/18] check if implicit object is `this` --- clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp index 71614407b8558..460783529e4dd 100644 --- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp +++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp @@ -734,6 +734,15 @@ void FactsGenerator::handleImplicitObjectFieldUses(const Expr *Call, return; const auto UseFields = [&](const CXXRecordDecl *RD) { + const auto *MemberCall = dyn_cast_or_null<CXXMemberCallExpr>(Call); + if (!MemberCall) + return; + + const auto *This = + dyn_cast_or_null<CXXThisExpr>(MemberCall->getImplicitObjectArgument()); + if (!This) + return; + for (const auto *Field : RD->fields()) if (auto *FieldList = getOriginsList(*Field)) CurrentBlockFacts.push_back( >From 26737cbb74eedab78e24dfa2d56ed20762c83857 Mon Sep 17 00:00:00 2001 From: NeKon69 <[email protected]> Date: Mon, 13 Apr 2026 16:00:18 +0300 Subject: [PATCH 10/18] update test --- clang/unittests/Analysis/LifetimeSafetyTest.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/unittests/Analysis/LifetimeSafetyTest.cpp b/clang/unittests/Analysis/LifetimeSafetyTest.cpp index 879df0d147267..6cf65dd64ef83 100644 --- a/clang/unittests/Analysis/LifetimeSafetyTest.cpp +++ b/clang/unittests/Analysis/LifetimeSafetyTest.cpp @@ -1408,6 +1408,7 @@ TEST_F(LifetimeAnalysisTest, TrivialClassDestructorsUAF) { } )"); EXPECT_THAT(Origin("ptr"), HasLoansTo({"s"}, "p1")); + EXPECT_THAT(Origins({"ptr"}), MustBeLiveAt("p1")); } TEST_F(LifetimeAnalysisTest, SimpleReturnStackAddress) { >From f14ecafda33a663e029d71b439f36b4db823244c Mon Sep 17 00:00:00 2001 From: NeKon69 <[email protected]> Date: Mon, 13 Apr 2026 17:00:04 +0300 Subject: [PATCH 11/18] move the check out of the lambda --- .../Analysis/LifetimeSafety/FactsGenerator.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp index 460783529e4dd..7ad4a6885e51d 100644 --- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp +++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp @@ -729,20 +729,18 @@ void FactsGenerator::handleImplicitObjectFieldUses(const Expr *Call, if (!MD || !MD->isInstance()) return; + const auto *MemberCall = dyn_cast_or_null<CXXMemberCallExpr>(Call); + if (!MemberCall) + return; + + if (!dyn_cast_or_null<CXXThisExpr>(MemberCall->getImplicitObjectArgument())) + return; + const auto *ClassDecl = MD->getParent()->getDefinition(); if (!ClassDecl) return; const auto UseFields = [&](const CXXRecordDecl *RD) { - const auto *MemberCall = dyn_cast_or_null<CXXMemberCallExpr>(Call); - if (!MemberCall) - return; - - const auto *This = - dyn_cast_or_null<CXXThisExpr>(MemberCall->getImplicitObjectArgument()); - if (!This) - return; - for (const auto *Field : RD->fields()) if (auto *FieldList = getOriginsList(*Field)) CurrentBlockFacts.push_back( >From 50175b1f13ac8272f5fb1d269504cda6c613e2e4 Mon Sep 17 00:00:00 2001 From: NeKon69 <[email protected]> Date: Mon, 13 Apr 2026 17:35:25 +0300 Subject: [PATCH 12/18] remove redundant check, update comments in test --- clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp | 4 +--- clang/test/Sema/warn-lifetime-safety.cpp | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp index 7ad4a6885e51d..5ca2fc7607d52 100644 --- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp +++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp @@ -726,14 +726,12 @@ void FactsGenerator::handleInvalidatingCall(const Expr *Call, void FactsGenerator::handleImplicitObjectFieldUses(const Expr *Call, const FunctionDecl *FD) { const auto *MD = dyn_cast<CXXMethodDecl>(FD); - if (!MD || !MD->isInstance()) - return; const auto *MemberCall = dyn_cast_or_null<CXXMemberCallExpr>(Call); if (!MemberCall) return; - if (!dyn_cast_or_null<CXXThisExpr>(MemberCall->getImplicitObjectArgument())) + if (!isa_and_present<CXXThisExpr>(MemberCall->getImplicitObjectArgument())) return; const auto *ClassDecl = MD->getParent()->getDefinition(); diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp index 4e562d6a7c06c..c7dec4db6d80e 100644 --- a/clang/test/Sema/warn-lifetime-safety.cpp +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -2566,12 +2566,12 @@ struct T { } }; -// FIXME: False-negative: the analysis tracks `p_`, but not that it belongs to s1. +// FIXME: false-negative void foo() { S s; { int num; - s.p_ = # + s.p_ = # // does not warn } s.bar(); s.p_ = &GLOBAL_INT; >From c5ecb50db9155c1aca8bb53ce1d6b3555c5a806e Mon Sep 17 00:00:00 2001 From: NeKon69 <[email protected]> Date: Mon, 13 Apr 2026 17:40:20 +0300 Subject: [PATCH 13/18] add a test for inheritance --- clang/test/Sema/warn-lifetime-safety.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp index c7dec4db6d80e..7a604888a79cc 100644 --- a/clang/test/Sema/warn-lifetime-safety.cpp +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -2577,4 +2577,16 @@ void foo() { s.p_ = &GLOBAL_INT; } +// FIXME: false-negative, should warn once inheritance is supported +struct S2 : S { + void foo2() { + { + int num; + this->p_ = # // does not warn + } + bar(); + this->p_ = &GLOBAL_INT; + } +}; + } // namespace method_call_uses_field_origins >From 7a3f4aea855ca2d6dbfe0ccc84dd6d64d00c68c0 Mon Sep 17 00:00:00 2001 From: NeKon69 <[email protected]> Date: Mon, 13 Apr 2026 21:00:24 +0300 Subject: [PATCH 14/18] update test --- clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp | 3 ++- clang/test/Sema/warn-lifetime-safety.cpp | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp index 23aab094ecf8d..6c18344336c10 100644 --- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp +++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp @@ -736,7 +736,8 @@ void FactsGenerator::handleImplicitObjectFieldUses(const Expr *Call, if (!MemberCall) return; - if (!isa_and_present<CXXThisExpr>(MemberCall->getImplicitObjectArgument())) + if (!isa_and_present<CXXThisExpr>( + MemberCall->getImplicitObjectArgument()->IgnoreImpCasts())) return; const auto *ClassDecl = MD->getParent()->getDefinition(); diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp index 7c2801af6335d..8e6f49b0a0c34 100644 --- a/clang/test/Sema/warn-lifetime-safety.cpp +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -2578,12 +2578,13 @@ void foo() { } struct S2 : S { + void bar2(); void foo2() { { int num; - this->p_ = # // does not warn - } - bar(); + this->p_ = # // expected-warning {{object whose reference is captured does not live long enough}} + } // expected-note {{destroyed here}} + bar(); // expected-note {{later used here}} this->p_ = &GLOBAL_INT; } }; >From 314a48687eaa4183d4d0f17a03cfc685cb728a9d Mon Sep 17 00:00:00 2001 From: NeKon69 <[email protected]> Date: Mon, 13 Apr 2026 21:11:15 +0300 Subject: [PATCH 15/18] add a new test --- clang/test/Sema/warn-lifetime-safety.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp index 8e6f49b0a0c34..015ea276e7bb6 100644 --- a/clang/test/Sema/warn-lifetime-safety.cpp +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -2587,6 +2587,14 @@ struct S2 : S { bar(); // expected-note {{later used here}} this->p_ = &GLOBAL_INT; } + void baz2() { + { + int num; + this->p_ = # + } + this->p_ = nullptr; + bar2(); + } }; } // namespace method_call_uses_field_origins >From be37320adf184c23d4e066f72b383bd11320e3ae Mon Sep 17 00:00:00 2001 From: NeKon69 <[email protected]> Date: Mon, 13 Apr 2026 21:12:17 +0300 Subject: [PATCH 16/18] add tests expectations --- clang/test/Sema/warn-lifetime-safety.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp index 015ea276e7bb6..f87b5cbdd0230 100644 --- a/clang/test/Sema/warn-lifetime-safety.cpp +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -2590,10 +2590,10 @@ struct S2 : S { void baz2() { { int num; - this->p_ = # - } + this->p_ = # // expected-warning {{object whose reference is captured does not live long enough}} + } // expected-note {{destroyed here}} + bar2(); // expected-note {{later used here}} this->p_ = nullptr; - bar2(); } }; >From 93fb7dfa4936b0de54b3b4995f1443a930ec1a20 Mon Sep 17 00:00:00 2001 From: NeKon69 <[email protected]> Date: Mon, 13 Apr 2026 21:39:42 +0300 Subject: [PATCH 17/18] add assert, move MD close to ClassDecl --- clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp index 6c18344336c10..6e0afbda40d55 100644 --- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp +++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp @@ -730,8 +730,6 @@ void FactsGenerator::handleInvalidatingCall(const Expr *Call, void FactsGenerator::handleImplicitObjectFieldUses(const Expr *Call, const FunctionDecl *FD) { - const auto *MD = dyn_cast<CXXMethodDecl>(FD); - const auto *MemberCall = dyn_cast_or_null<CXXMemberCallExpr>(Call); if (!MemberCall) return; @@ -740,6 +738,9 @@ void FactsGenerator::handleImplicitObjectFieldUses(const Expr *Call, MemberCall->getImplicitObjectArgument()->IgnoreImpCasts())) return; + const auto *MD = dyn_cast<CXXMethodDecl>(FD); + assert(MD && "Expected MD to be a non-null pointer"); + const auto *ClassDecl = MD->getParent()->getDefinition(); if (!ClassDecl) return; >From 662a2f58814b5dbd1b0cc09d0c2d97c73d635592 Mon Sep 17 00:00:00 2001 From: NeKon69 <[email protected]> Date: Tue, 14 Apr 2026 09:22:46 +0300 Subject: [PATCH 18/18] Update wording in the assert Co-authored-by: Utkarsh Saxena <[email protected]> --- clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp index 6e0afbda40d55..cae56ddd3d7c3 100644 --- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp +++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp @@ -739,7 +739,7 @@ void FactsGenerator::handleImplicitObjectFieldUses(const Expr *Call, return; const auto *MD = dyn_cast<CXXMethodDecl>(FD); - assert(MD && "Expected MD to be a non-null pointer"); + assert(MD && "Function must be a CXXMethodDecl for member calls"); const auto *ClassDecl = MD->getParent()->getDefinition(); if (!ClassDecl) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
