diff --git a/clang/include/clang/Analysis/CFG.h b/clang/include/clang/Analysis/CFG.h index 72b7ac013ccc2..6c214d9ce10e2 100644 --- a/clang/include/clang/Analysis/CFG.h +++ b/clang/include/clang/Analysis/CFG.h @@ -318,8 +318,15 @@ class CFGFullExprCleanup : public CFGElement { public: using MTEVecTy = BumpVector; - explicit CFGFullExprCleanup(const MTEVecTy *MTEs) - : CFGElement(FullExprCleanup, MTEs, nullptr) {} + explicit CFGFullExprCleanup(const MTEVecTy *MTEs, + const ExprWithCleanups *CleanupExpr) + : CFGElement(FullExprCleanup, MTEs, CleanupExpr) {} + + const ExprWithCleanups *getCleanupExpr() const { + return static_cast(Data2.getPointer()); + } + + SourceLocation getCleanupLoc() const { return getCleanupExpr()->getEndLoc(); } ArrayRef getExpiringMTEs() const { const MTEVecTy *ExpiringMTEs = @@ -1211,8 +1218,9 @@ class CFGBlock { } void appendFullExprCleanup(BumpVector *BV, + const ExprWithCleanups *CleanupExpr, BumpVectorContext &C) { - Elements.push_back(CFGFullExprCleanup(BV), C); + Elements.push_back(CFGFullExprCleanup(BV, CleanupExpr), C); } void appendLoopExit(const Stmt *LoopStmt, BumpVectorContext &C) { diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index 1b4d10b72e249..bb8e98a894dab 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -813,7 +813,8 @@ class CFGBuilder { void addScopeChangesHandling(LocalScope::const_iterator SrcPos, LocalScope::const_iterator DstPos, Stmt *S); - void addFullExprCleanupMarker(TempDtorContext &Context); + void addFullExprCleanupMarker(TempDtorContext &Context, + const ExprWithCleanups *CleanupExpr); CFGBlock *createScopeChangesHandlingBlock(LocalScope::const_iterator SrcPos, CFGBlock *SrcBlk, LocalScope::const_iterator DstPost, @@ -1841,10 +1842,11 @@ CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) { (BuildOpts.AddTemporaryDtors || BuildOpts.AddLifetime)) { // Generate destructors for temporaries in initialization expression. TempDtorContext Context; - VisitForTemporaries(cast(ActualInit)->getSubExpr(), + auto *FullExprWithCleanups = cast(ActualInit); + VisitForTemporaries(FullExprWithCleanups->getSubExpr(), /*ExternallyDestructed=*/false, Context); - addFullExprCleanupMarker(Context); + addFullExprCleanupMarker(Context, FullExprWithCleanups); } } @@ -2096,7 +2098,8 @@ void CFGBuilder::addScopeChangesHandling(LocalScope::const_iterator SrcPos, addAutomaticObjHandling(SrcPos, BasePos, S); } -void CFGBuilder::addFullExprCleanupMarker(TempDtorContext &Context) { +void CFGBuilder::addFullExprCleanupMarker(TempDtorContext &Context, + const ExprWithCleanups *CleanupExpr) { CFGFullExprCleanup::MTEVecTy *ExpiringMTEs = nullptr; BumpVectorContext &BVC = cfg->getBumpVectorContext(); @@ -2107,7 +2110,7 @@ void CFGBuilder::addFullExprCleanupMarker(TempDtorContext &Context) { CFGFullExprCleanup::MTEVecTy(BVC, NumCollected); for (const MaterializeTemporaryExpr *MTE : Context.CollectedMTEs) ExpiringMTEs->push_back(MTE, BVC); - Block->appendFullExprCleanup(ExpiringMTEs, BVC); + Block->appendFullExprCleanup(ExpiringMTEs, CleanupExpr, BVC); } } @@ -3173,10 +3176,11 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) { (BuildOpts.AddTemporaryDtors || BuildOpts.AddLifetime)) { // Generate destructors for temporaries in initialization expression. TempDtorContext Context; - VisitForTemporaries(cast(Init)->getSubExpr(), + auto *FullExprWithCleanups = cast(Init); + VisitForTemporaries(FullExprWithCleanups->getSubExpr(), /*ExternallyDestructed=*/true, Context); - addFullExprCleanupMarker(Context); + addFullExprCleanupMarker(Context, FullExprWithCleanups); } } @@ -4990,9 +4994,10 @@ CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E, // If adding implicit destructors visit the full expression for adding // destructors of temporaries. TempDtorContext Context; - VisitForTemporaries(E->getSubExpr(), ExternallyDestructed, Context); + Expr *FullExpr = E->getSubExpr(); + VisitForTemporaries(FullExpr, ExternallyDestructed, Context); - addFullExprCleanupMarker(Context); + addFullExprCleanupMarker(Context, E); // Full expression has to be added as CFGStmt so it will be sequenced // before destructors of it's temporaries. diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp index b34a04f1f3bda..02be730443d20 100644 --- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp +++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp @@ -726,8 +726,8 @@ void FactsGenerator::handleLifetimeEnds(const CFGLifetimeEnds &LifetimeEnds) { void FactsGenerator::handleFullExprCleanup( const CFGFullExprCleanup &FullExprCleanup) { for (const auto *MTE : FullExprCleanup.getExpiringMTEs()) - CurrentBlockFacts.push_back( - FactMgr.createFact(AccessPath(MTE), MTE->getEndLoc())); + CurrentBlockFacts.push_back(FactMgr.createFact( + AccessPath(MTE), FullExprCleanup.getCleanupLoc())); } void FactsGenerator::handleExitBlock() { diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp index 06097d4600af5..461287b4ecb9a 100644 --- a/clang/test/Sema/warn-lifetime-safety.cpp +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -1287,6 +1287,21 @@ void use_trivial_temporary_after_destruction() { use(a); // expected-note {{later used here}} } +namespace FullExprCleanupLoc { +void var_initializer() { + View v = non_trivially_destructed_temporary() // expected-warning {{local temporary object does not live long enough}} + .getView(); // expected-note {{destroyed here}} + v.use(); // expected-note {{later used here}} +} + +void expr_statement() { + View v; + v = non_trivially_destructed_temporary() // expected-warning {{local temporary object does not live long enough}} + .getView(); // expected-note {{destroyed here}} + v.use(); // expected-note {{later used here}} +} +} // namespace FullExprCleanupLoc + namespace GH162834 { // https://github.com/llvm/llvm-project/issues/162834 template @@ -2299,8 +2314,8 @@ struct S { void indexing_with_static_operator() { S()(1, 2); S& x = S()("1", - 2, // expected-warning {{local temporary object does not live long enough}} expected-note {{destroyed here}} - 3); // expected-warning {{local temporary object does not live long enough}} expected-note {{destroyed here}} + 2, // expected-warning {{local temporary object does not live long enough}} + 3); // expected-warning {{local temporary object does not live long enough}} expected-note 2 {{destroyed here}} (void)x; // expected-note 2 {{later used here}}