https://github.com/AbhinavPradeep updated https://github.com/llvm/llvm-project/pull/177985
>From 8bae199a384392630a2189467c5be254b9abc05b Mon Sep 17 00:00:00 2001 From: Abhinav Pradeep <[email protected]> Date: Tue, 27 Jan 2026 01:20:55 +1000 Subject: [PATCH 1/3] Modify CFG to have a CFGFullExprCleanup marker. --- clang/include/clang/Analysis/CFG.h | 32 ++++++++++++ clang/lib/Analysis/CFG.cpp | 71 ++++++++++++++++++++++++--- clang/lib/Analysis/PathDiagnostic.cpp | 1 + 3 files changed, 98 insertions(+), 6 deletions(-) diff --git a/clang/include/clang/Analysis/CFG.h b/clang/include/clang/Analysis/CFG.h index a4bafd4927df0..c021ffcf85785 100644 --- a/clang/include/clang/Analysis/CFG.h +++ b/clang/include/clang/Analysis/CFG.h @@ -62,6 +62,7 @@ class CFGElement { NewAllocator, LifetimeEnds, LoopExit, + FullExprCleanup, // stmt kind Statement, Constructor, @@ -313,6 +314,32 @@ class CFGLifetimeEnds : public CFGElement { } }; +class CFGFullExprCleanup : public CFGElement { + using MTEVecTy = BumpVector<const MaterializeTemporaryExpr *>; + +public: + explicit CFGFullExprCleanup(const MTEVecTy *vec) + : CFGElement(FullExprCleanup, vec, nullptr) {} + + ArrayRef<const MaterializeTemporaryExpr *> getExpiringMTEs() const { + const MTEVecTy *ExpiringMTEs = + static_cast<const MTEVecTy *>(Data1.getPointer()); + if (!ExpiringMTEs) + return {}; + return ArrayRef<const MaterializeTemporaryExpr *>(ExpiringMTEs->begin(), + ExpiringMTEs->end()); + } + +private: + friend class CFGElement; + + CFGFullExprCleanup() = default; + + static bool isKind(const CFGElement &elem) { + return elem.getKind() == FullExprCleanup; + } +}; + /// Represents beginning of a scope implicitly generated /// by the compiler on encountering a CompoundStmt class CFGScopeBegin : public CFGElement { @@ -1183,6 +1210,11 @@ class CFGBlock { Elements.push_back(CFGLifetimeEnds(VD, S), C); } + void appendFullExprCleanup(BumpVector<const MaterializeTemporaryExpr *> *BV, + BumpVectorContext &C) { + Elements.push_back(CFGFullExprCleanup(BV), C); + } + void appendLoopExit(const Stmt *LoopStmt, BumpVectorContext &C) { Elements.push_back(CFGLoopExit(LoopStmt), C); } diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index a9c7baa00543c..03b3fd7efe89e 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -55,6 +55,7 @@ #include "llvm/Support/TimeProfiler.h" #include "llvm/Support/raw_ostream.h" #include <cassert> +#include <cstddef> #include <memory> #include <optional> #include <string> @@ -698,7 +699,9 @@ class CFGBuilder { TempDtorContext() = default; TempDtorContext(TryResult KnownExecuted) : IsConditional(true), KnownExecuted(KnownExecuted) {} - + TempDtorContext(TryResult KnownExecuted, bool TrackExpiringMTEs) + : IsConditional(true), TrackExpiringMTEs(TrackExpiringMTEs), + KnownExecuted(KnownExecuted) {} /// Returns whether we need to start a new branch for a temporary destructor /// call. This is the case when the temporary destructor is /// conditionally executed, and it is the first one we encounter while @@ -716,7 +719,16 @@ class CFGBuilder { TerminatorExpr = E; } + void track(const MaterializeTemporaryExpr *MTE) { + // Must only be invoked when TrackMTE is true + assert(TrackExpiringMTEs); + if (MTE) + CollectedMTEs.push_back(MTE); + } + const bool IsConditional = false; + bool TrackExpiringMTEs = false; + SmallVector<const MaterializeTemporaryExpr *, 5> CollectedMTEs; const TryResult KnownExecuted = true; CFGBlock *Succ = nullptr; CXXBindTemporaryExpr *TerminatorExpr = nullptr; @@ -803,6 +815,7 @@ class CFGBuilder { void addScopeChangesHandling(LocalScope::const_iterator SrcPos, LocalScope::const_iterator DstPos, Stmt *S); + void addFullExprCleanupMarker(TempDtorContext &Context); CFGBlock *createScopeChangesHandlingBlock(LocalScope::const_iterator SrcPos, CFGBlock *SrcBlk, LocalScope::const_iterator DstPost, @@ -1816,8 +1829,11 @@ CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) { if (BuildOpts.AddTemporaryDtors && HasTemporaries) { // Generate destructors for temporaries in initialization expression. TempDtorContext Context; + Context.TrackExpiringMTEs = true; VisitForTemporaryDtors(cast<ExprWithCleanups>(Init)->getSubExpr(), /*ExternallyDestructed=*/false, Context); + + addFullExprCleanupMarker(Context); } } @@ -2065,6 +2081,23 @@ void CFGBuilder::addScopeChangesHandling(LocalScope::const_iterator SrcPos, addAutomaticObjHandling(SrcPos, BasePos, S); } +void CFGBuilder::addFullExprCleanupMarker(TempDtorContext &Context) { + assert(Context.TrackExpiringMTEs); + + using MTEVecTy = BumpVector<const MaterializeTemporaryExpr *>; + MTEVecTy *ExpiringMTEs = nullptr; + BumpVectorContext &BVC = cfg->getBumpVectorContext(); + + size_t NumCollected = Context.CollectedMTEs.size(); + if (NumCollected > 0) { + autoCreateBlock(); + ExpiringMTEs = new (cfg->getAllocator()) MTEVecTy(BVC, NumCollected); + for (const MaterializeTemporaryExpr *MTE : Context.CollectedMTEs) + ExpiringMTEs->push_back(MTE, BVC); + Block->appendFullExprCleanup(ExpiringMTEs, BVC); + } +} + /// createScopeChangesHandlingBlock - Creates a block with cfgElements /// corresponding to changing the scope from the source scope of the GotoStmt, /// to destination scope. Add destructor, lifetime and cfgScopeEnd @@ -3113,8 +3146,11 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) { if (BuildOpts.AddTemporaryDtors && HasTemporaries) { // Generate destructors for temporaries in initialization expression. TempDtorContext Context; + Context.TrackExpiringMTEs = true; VisitForTemporaryDtors(cast<ExprWithCleanups>(Init)->getSubExpr(), /*ExternallyDestructed=*/true, Context); + + addFullExprCleanupMarker(Context); } } @@ -4924,13 +4960,17 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) { } CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E, - AddStmtChoice asc, bool ExternallyDestructed) { + AddStmtChoice asc, + bool ExternallyDestructed) { if (BuildOpts.AddTemporaryDtors) { // If adding implicit destructors visit the full expression for adding // destructors of temporaries. TempDtorContext Context; + Context.TrackExpiringMTEs = true; VisitForTemporaryDtors(E->getSubExpr(), ExternallyDestructed, Context); + addFullExprCleanupMarker(Context); + // Full expression has to be added as CFGStmt so it will be sequenced // before destructors of it's temporaries. asc = asc.withAlwaysAdd(true); @@ -5117,6 +5157,8 @@ CFGBlock *CFGBuilder::VisitForTemporaryDtors(Stmt *E, bool ExternallyDestructed, case Stmt::MaterializeTemporaryExprClass: { const MaterializeTemporaryExpr* MTE = cast<MaterializeTemporaryExpr>(E); ExternallyDestructed = (MTE->getStorageDuration() != SD_FullExpression); + if (Context.TrackExpiringMTEs && !ExternallyDestructed) + Context.track(MTE); SmallVector<const Expr *, 2> CommaLHSs; SmallVector<SubobjectAdjustment, 2> Adjustments; // Find the expression whose lifetime needs to be extended. @@ -5208,10 +5250,14 @@ CFGBlock *CFGBuilder::VisitBinaryOperatorForTemporaryDtors( // executed, thus we add a branch node that depends on the temporary // constructor call. TempDtorContext RHSContext( - bothKnownTrue(Context.KnownExecuted, RHSExecuted)); + bothKnownTrue(Context.KnownExecuted, RHSExecuted), + Context.TrackExpiringMTEs); VisitForTemporaryDtors(E->getRHS(), false, RHSContext); InsertTempDtorDecisionBlock(RHSContext); + if (Context.TrackExpiringMTEs) + Context.CollectedMTEs.append(RHSContext.CollectedMTEs); + return Block; } @@ -5290,14 +5336,15 @@ CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors( if (NegatedVal.isKnown()) NegatedVal.negate(); TempDtorContext TrueContext( - bothKnownTrue(Context.KnownExecuted, ConditionVal)); + bothKnownTrue(Context.KnownExecuted, ConditionVal), + Context.TrackExpiringMTEs); VisitForTemporaryDtors(E->getTrueExpr(), ExternallyDestructed, TrueContext); CFGBlock *TrueBlock = Block; Block = ConditionBlock; Succ = ConditionSucc; - TempDtorContext FalseContext( - bothKnownTrue(Context.KnownExecuted, NegatedVal)); + TempDtorContext FalseContext(bothKnownTrue(Context.KnownExecuted, NegatedVal), + Context.TrackExpiringMTEs); VisitForTemporaryDtors(E->getFalseExpr(), ExternallyDestructed, FalseContext); if (TrueContext.TerminatorExpr && FalseContext.TerminatorExpr) { @@ -5308,6 +5355,11 @@ CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors( } else { InsertTempDtorDecisionBlock(FalseContext); } + if (Context.TrackExpiringMTEs) { + Context.CollectedMTEs.append(TrueContext.CollectedMTEs); + Context.CollectedMTEs.append(FalseContext.CollectedMTEs); + } + return Block; } @@ -5989,6 +6041,13 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, OS << " (Lifetime ends)"; break; + case CFGElement::Kind::FullExprCleanup: + OS << "(FullExprCleanup collected " + << std::to_string( + E.castAs<CFGFullExprCleanup>().getExpiringMTEs().size()) + << " MTEs)"; + break; + case CFGElement::Kind::LoopExit: OS << E.castAs<CFGLoopExit>().getLoopStmt()->getStmtClassName() << " (LoopExit)"; diff --git a/clang/lib/Analysis/PathDiagnostic.cpp b/clang/lib/Analysis/PathDiagnostic.cpp index e42731b93bfb2..5e387e086a5a7 100644 --- a/clang/lib/Analysis/PathDiagnostic.cpp +++ b/clang/lib/Analysis/PathDiagnostic.cpp @@ -564,6 +564,7 @@ getLocationForCaller(const StackFrameContext *SFC, case CFGElement::CleanupFunction: llvm_unreachable("not yet implemented!"); case CFGElement::LifetimeEnds: + case CFGElement::FullExprCleanup: case CFGElement::LoopExit: llvm_unreachable("CFGElement kind should not be on callsite!"); } >From 5cc1973c118ea08159b197836c79af5551354b94 Mon Sep 17 00:00:00 2001 From: Abhinav Pradeep <[email protected]> Date: Wed, 28 Jan 2026 03:12:45 +1000 Subject: [PATCH 2/3] Fixed solver related issues by no-oping new CFGElement --- clang/lib/Analysis/CFG.cpp | 1 + clang/lib/StaticAnalyzer/Core/CoreEngine.cpp | 6 ++++++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 1 + clang/lib/StaticAnalyzer/Core/SymbolManager.cpp | 2 ++ 4 files changed, 10 insertions(+) diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index 03b3fd7efe89e..ca47c644228f4 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -5477,6 +5477,7 @@ CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const { case CFGElement::CXXRecordTypedCall: case CFGElement::ScopeBegin: case CFGElement::ScopeEnd: + case CFGElement::FullExprCleanup: case CFGElement::CleanupFunction: llvm_unreachable("getDestructorDecl should only be used with " "ImplicitDtors"); diff --git a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp index 95a843ee87571..49835a0224171 100644 --- a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -524,6 +524,12 @@ void CoreEngine::HandlePostStmt(const CFGBlock *B, unsigned StmtIdx, assert(B); assert(!B->empty()); + // We no-op by skipping any FullExprCleanup + while (StmtIdx < B->size() && + (*B)[StmtIdx].getKind() == CFGElement::FullExprCleanup) { + StmtIdx++; + } + if (StmtIdx == B->size()) HandleBlockExit(B, Pred); else { diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index a6a96b594fe85..da176ebd20bb4 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -995,6 +995,7 @@ void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred, return; case CFGElement::LifetimeEnds: case CFGElement::CleanupFunction: + case CFGElement::FullExprCleanup: case CFGElement::ScopeBegin: case CFGElement::ScopeEnd: return; diff --git a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp index d03f47fa301e6..35fbe4d60c3f2 100644 --- a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp @@ -115,6 +115,8 @@ const Stmt *SymbolConjured::getStmt() const { return Elem->castAs<CFGTemporaryDtor>().getBindTemporaryExpr(); case CFGElement::CleanupFunction: return nullptr; + case CFGElement::FullExprCleanup: + return nullptr; } return nullptr; } >From 9782c9c0bd6d28596118e3fca7f2f8597ce93777 Mon Sep 17 00:00:00 2001 From: Abhinav Pradeep <[email protected]> Date: Tue, 3 Feb 2026 00:07:14 +1000 Subject: [PATCH 3/3] Fixed tests to reflect new CFG --- .../Analysis/auto-obj-dtors-cfg-output.cpp | 172 +++++++++--------- clang/test/Analysis/cfg-rich-constructors.cpp | 155 +++++++++------- clang/test/Analysis/cfg-rich-constructors.mm | 8 +- clang/test/Analysis/cfg.cpp | 1 + .../test/Analysis/missing-bind-temporary.cpp | 15 +- .../Analysis/temp-obj-dtors-cfg-output.cpp | 166 ++++++++++------- 6 files changed, 293 insertions(+), 224 deletions(-) diff --git a/clang/test/Analysis/auto-obj-dtors-cfg-output.cpp b/clang/test/Analysis/auto-obj-dtors-cfg-output.cpp index 96b9a5508cc08..4790469850107 100644 --- a/clang/test/Analysis/auto-obj-dtors-cfg-output.cpp +++ b/clang/test/Analysis/auto-obj-dtors-cfg-output.cpp @@ -188,50 +188,52 @@ void test_aggregate_lifetime_extension() { // CXX11-NEXT: 14: {[B1.13]} // Double curly braces trigger regexps, escape as per FileCheck manual. // CXX11-NEXT: 15: C c = {{[{][{]}}A(), A(){{[}][}]}}; -// CXX11-NEXT: 16: ~A() (Temporary object destructor) +// CXX11-NEXT: 16: (FullExprCleanup collected 2 MTEs) // CXX11-NEXT: 17: ~A() (Temporary object destructor) -// CXX11-WARNINGS-NEXT: 18: A() (CXXConstructExpr, A) -// CXX11-ANALYZER-NEXT: 18: A() (CXXConstructExpr, [B1.19], [B1.21], A) -// CXX11-NEXT: 19: [B1.18] (BindTemporary) -// CXX11-NEXT: 20: [B1.19] (ImplicitCastExpr, NoOp, const A) -// CXX11-NEXT: 21: [B1.20] -// CXX11-NEXT: 22: [B1.21] (CXXConstructExpr, const A) -// CXX11-WARNINGS-NEXT: 23: A() (CXXConstructExpr, A) -// CXX11-ANALYZER-NEXT: 23: A() (CXXConstructExpr, [B1.24], [B1.26], A) -// CXX11-NEXT: 24: [B1.23] (BindTemporary) -// CXX11-NEXT: 25: [B1.24] (ImplicitCastExpr, NoOp, const A) -// CXX11-NEXT: 26: [B1.25] -// CXX11-NEXT: 27: [B1.26] (CXXConstructExpr, const A) +// CXX11-NEXT: 18: ~A() (Temporary object destructor) +// CXX11-WARNINGS-NEXT: 19: A() (CXXConstructExpr, A) +// CXX11-ANALYZER-NEXT: 19: A() (CXXConstructExpr, [B1.20], [B1.22], A) +// CXX11-NEXT: 20: [B1.19] (BindTemporary) +// CXX11-NEXT: 21: [B1.20] (ImplicitCastExpr, NoOp, const A) +// CXX11-NEXT: 22: [B1.21] +// CXX11-NEXT: 23: [B1.22] (CXXConstructExpr, const A) +// CXX11-WARNINGS-NEXT: 24: A() (CXXConstructExpr, A) +// CXX11-ANALYZER-NEXT: 24: A() (CXXConstructExpr, [B1.25], [B1.27], A) +// CXX11-NEXT: 25: [B1.24] (BindTemporary) +// CXX11-NEXT: 26: [B1.25] (ImplicitCastExpr, NoOp, const A) +// CXX11-NEXT: 27: [B1.26] +// CXX11-NEXT: 28: [B1.27] (CXXConstructExpr, const A) // FIXME: Why does it look as if the initializer list consumes uncopied objects? -// CXX11-NEXT: 28: {[B1.19], [B1.24]} -// CXX11-NEXT: 29: [B1.28] (BindTemporary) -// CXX11-NEXT: 30: [B1.29] -// CXX11-NEXT: 31: {[B1.30]} -// CXX11-WARNINGS-NEXT: 32: A() (CXXConstructExpr, A) -// CXX11-ANALYZER-NEXT: 32: A() (CXXConstructExpr, [B1.33], [B1.35], A) -// CXX11-NEXT: 33: [B1.32] (BindTemporary) -// CXX11-NEXT: 34: [B1.33] (ImplicitCastExpr, NoOp, const A) -// CXX11-NEXT: 35: [B1.34] -// CXX11-NEXT: 36: [B1.35] (CXXConstructExpr, const A) -// CXX11-WARNINGS-NEXT: 37: A() (CXXConstructExpr, A) -// CXX11-ANALYZER-NEXT: 37: A() (CXXConstructExpr, [B1.38], [B1.40], A) -// CXX11-NEXT: 38: [B1.37] (BindTemporary) -// CXX11-NEXT: 39: [B1.38] (ImplicitCastExpr, NoOp, const A) -// CXX11-NEXT: 40: [B1.39] -// CXX11-NEXT: 41: [B1.40] (CXXConstructExpr, const A) +// CXX11-NEXT: 29: {[B1.20], [B1.25]} +// CXX11-NEXT: 30: [B1.29] (BindTemporary) +// CXX11-NEXT: 31: [B1.30] +// CXX11-NEXT: 32: {[B1.31]} +// CXX11-WARNINGS-NEXT: 33: A() (CXXConstructExpr, A) +// CXX11-ANALYZER-NEXT: 33: A() (CXXConstructExpr, [B1.34], [B1.36], A) +// CXX11-NEXT: 34: [B1.33] (BindTemporary) +// CXX11-NEXT: 35: [B1.34] (ImplicitCastExpr, NoOp, const A) +// CXX11-NEXT: 36: [B1.35] +// CXX11-NEXT: 37: [B1.36] (CXXConstructExpr, const A) +// CXX11-WARNINGS-NEXT: 38: A() (CXXConstructExpr, A) +// CXX11-ANALYZER-NEXT: 38: A() (CXXConstructExpr, [B1.39], [B1.41], A) +// CXX11-NEXT: 39: [B1.38] (BindTemporary) +// CXX11-NEXT: 40: [B1.39] (ImplicitCastExpr, NoOp, const A) +// CXX11-NEXT: 41: [B1.40] +// CXX11-NEXT: 42: [B1.41] (CXXConstructExpr, const A) // FIXME: Why does it look as if the initializer list consumes uncopied objects? -// CXX11-NEXT: 42: {[B1.33], [B1.38]} -// CXX11-NEXT: 43: [B1.42] (BindTemporary) -// CXX11-NEXT: 44: [B1.43] -// CXX11-NEXT: 45: {[B1.44]} +// CXX11-NEXT: 43: {[B1.34], [B1.39]} +// CXX11-NEXT: 44: [B1.43] (BindTemporary) +// CXX11-NEXT: 45: [B1.44] +// CXX11-NEXT: 46: {[B1.45]} // Double curly braces trigger regexps, escape as per FileCheck manual. -// CXX11-NEXT: 46: {{[{][{]}}[B1.30]}, {[B1.44]{{[}][}]}} +// CXX11-NEXT: 47: {{[{][{]}}[B1.31]}, {[B1.45]{{[}][}]}} // Double curly braces trigger regexps, escape as per FileCheck manual. -// CXX11-NEXT: 47: C cc[2] = {{[{][{][{]}}A(), A(){{[}][}]}}, {{[{][{]}}A(), A(){{[}][}][}]}}; -// CXX11-NEXT: 48: ~A() (Temporary object destructor) -// CXX11-NEXT: 49: ~A() (Temporary object destructor) +// CXX11-NEXT: 48: C cc[2] = {{[{][{][{]}}A(), A(){{[}][}]}}, {{[{][{]}}A(), A(){{[}][}][}]}}; +// CXX11-NEXT: 49: (FullExprCleanup collected 4 MTEs) // CXX11-NEXT: 50: ~A() (Temporary object destructor) // CXX11-NEXT: 51: ~A() (Temporary object destructor) +// CXX11-NEXT: 52: ~A() (Temporary object destructor) +// CXX11-NEXT: 53: ~A() (Temporary object destructor) // CXX11-NEXT: Preds (1): B2 // CXX11-NEXT: Succs (1): B0 // CXX11: [B0 (EXIT)] @@ -277,65 +279,67 @@ void test_aggregate_array_lifetime_extension() { // FIXME: Why does it look as if the initializer list consumes uncopied objects? // CHECK-NEXT: 17: {[B1.2], {[B1.7], [B1.12]}} // CHECK-NEXT: 18: D d = {A(), {A(), A()}}; -// CHECK-NEXT: 19: ~A() (Temporary object destructor) +// CHECK-NEXT: 19: (FullExprCleanup collected 3 MTEs) // CHECK-NEXT: 20: ~A() (Temporary object destructor) // CHECK-NEXT: 21: ~A() (Temporary object destructor) -// WARNINGS-NEXT: 22: A() (CXXConstructExpr, A) -// ANALYZER-NEXT: 22: A() (CXXConstructExpr, [B1.23], [B1.25], A) -// CHECK-NEXT: 23: [B1.22] (BindTemporary) -// CHECK-NEXT: 24: [B1.23] (ImplicitCastExpr, NoOp, const A) -// CHECK-NEXT: 25: [B1.24] -// CHECK-NEXT: 26: [B1.25] (CXXConstructExpr, A) -// WARNINGS-NEXT: 27: A() (CXXConstructExpr, A) -// ANALYZER-NEXT: 27: A() (CXXConstructExpr, [B1.28], [B1.30], A) -// CHECK-NEXT: 28: [B1.27] (BindTemporary) -// CHECK-NEXT: 29: [B1.28] (ImplicitCastExpr, NoOp, const A) -// CHECK-NEXT: 30: [B1.29] -// CHECK-NEXT: 31: [B1.30] (CXXConstructExpr, A) -// WARNINGS-NEXT: 32: A() (CXXConstructExpr, A) -// ANALYZER-NEXT: 32: A() (CXXConstructExpr, [B1.33], [B1.35], A) -// CHECK-NEXT: 33: [B1.32] (BindTemporary) -// CHECK-NEXT: 34: [B1.33] (ImplicitCastExpr, NoOp, const A) -// CHECK-NEXT: 35: [B1.34] -// CHECK-NEXT: 36: [B1.35] (CXXConstructExpr, A) +// CHECK-NEXT: 22: ~A() (Temporary object destructor) +// WARNINGS-NEXT: 23: A() (CXXConstructExpr, A) +// ANALYZER-NEXT: 23: A() (CXXConstructExpr, [B1.24], [B1.26], A) +// CHECK-NEXT: 24: [B1.23] (BindTemporary) +// CHECK-NEXT: 25: [B1.24] (ImplicitCastExpr, NoOp, const A) +// CHECK-NEXT: 26: [B1.25] +// CHECK-NEXT: 27: [B1.26] (CXXConstructExpr, A) +// WARNINGS-NEXT: 28: A() (CXXConstructExpr, A) +// ANALYZER-NEXT: 28: A() (CXXConstructExpr, [B1.29], [B1.31], A) +// CHECK-NEXT: 29: [B1.28] (BindTemporary) +// CHECK-NEXT: 30: [B1.29] (ImplicitCastExpr, NoOp, const A) +// CHECK-NEXT: 31: [B1.30] +// CHECK-NEXT: 32: [B1.31] (CXXConstructExpr, A) +// WARNINGS-NEXT: 33: A() (CXXConstructExpr, A) +// ANALYZER-NEXT: 33: A() (CXXConstructExpr, [B1.34], [B1.36], A) +// CHECK-NEXT: 34: [B1.33] (BindTemporary) +// CHECK-NEXT: 35: [B1.34] (ImplicitCastExpr, NoOp, const A) +// CHECK-NEXT: 36: [B1.35] +// CHECK-NEXT: 37: [B1.36] (CXXConstructExpr, A) // FIXME: Why does it look as if the initializer list consumes uncopied objects? -// CHECK-NEXT: 37: {[B1.28], [B1.33]} +// CHECK-NEXT: 38: {[B1.29], [B1.34]} // FIXME: Why does it look as if the initializer list consumes uncopied objects? -// CHECK-NEXT: 38: {[B1.23], {[B1.28], [B1.33]}} -// WARNINGS-NEXT: 39: A() (CXXConstructExpr, A) -// ANALYZER-NEXT: 39: A() (CXXConstructExpr, [B1.40], [B1.42], A) -// CHECK-NEXT: 40: [B1.39] (BindTemporary) -// CHECK-NEXT: 41: [B1.40] (ImplicitCastExpr, NoOp, const A) -// CHECK-NEXT: 42: [B1.41] -// CHECK-NEXT: 43: [B1.42] (CXXConstructExpr, A) -// WARNINGS-NEXT: 44: A() (CXXConstructExpr, A) -// ANALYZER-NEXT: 44: A() (CXXConstructExpr, [B1.45], [B1.47], A) -// CHECK-NEXT: 45: [B1.44] (BindTemporary) -// CHECK-NEXT: 46: [B1.45] (ImplicitCastExpr, NoOp, const A) -// CHECK-NEXT: 47: [B1.46] -// CHECK-NEXT: 48: [B1.47] (CXXConstructExpr, A) -// WARNINGS-NEXT: 49: A() (CXXConstructExpr, A) -// ANALYZER-NEXT: 49: A() (CXXConstructExpr, [B1.50], [B1.52], A) -// CHECK-NEXT: 50: [B1.49] (BindTemporary) -// CHECK-NEXT: 51: [B1.50] (ImplicitCastExpr, NoOp, const A) -// CHECK-NEXT: 52: [B1.51] -// CHECK-NEXT: 53: [B1.52] (CXXConstructExpr, A) +// CHECK-NEXT: 39: {[B1.24], {[B1.29], [B1.34]}} +// WARNINGS-NEXT: 40: A() (CXXConstructExpr, A) +// ANALYZER-NEXT: 40: A() (CXXConstructExpr, [B1.41], [B1.43], A) +// CHECK-NEXT: 41: [B1.40] (BindTemporary) +// CHECK-NEXT: 42: [B1.41] (ImplicitCastExpr, NoOp, const A) +// CHECK-NEXT: 43: [B1.42] +// CHECK-NEXT: 44: [B1.43] (CXXConstructExpr, A) +// WARNINGS-NEXT: 45: A() (CXXConstructExpr, A) +// ANALYZER-NEXT: 45: A() (CXXConstructExpr, [B1.46], [B1.48], A) +// CHECK-NEXT: 46: [B1.45] (BindTemporary) +// CHECK-NEXT: 47: [B1.46] (ImplicitCastExpr, NoOp, const A) +// CHECK-NEXT: 48: [B1.47] +// CHECK-NEXT: 49: [B1.48] (CXXConstructExpr, A) +// WARNINGS-NEXT: 50: A() (CXXConstructExpr, A) +// ANALYZER-NEXT: 50: A() (CXXConstructExpr, [B1.51], [B1.53], A) +// CHECK-NEXT: 51: [B1.50] (BindTemporary) +// CHECK-NEXT: 52: [B1.51] (ImplicitCastExpr, NoOp, const A) +// CHECK-NEXT: 53: [B1.52] +// CHECK-NEXT: 54: [B1.53] (CXXConstructExpr, A) // FIXME: Why does it look as if the initializer list consumes uncopied objects? -// CHECK-NEXT: 54: {[B1.45], [B1.50]} +// CHECK-NEXT: 55: {[B1.46], [B1.51]} // FIXME: Why does it look as if the initializer list consumes uncopied objects? -// CHECK-NEXT: 55: {[B1.40], {[B1.45], [B1.50]}} +// CHECK-NEXT: 56: {[B1.41], {[B1.46], [B1.51]}} // Double curly braces trigger regexps, escape as per FileCheck manual. -// CHECK-NEXT: 56: {{[{][{]}}[B1.23], {[B1.28], [B1.33]{{[}][}]}}, {[B1.40], {[B1.45], [B1.50]{{[}][}][}]}} +// CHECK-NEXT: 57: {{[{][{]}}[B1.24], {[B1.29], [B1.34]{{[}][}]}}, {[B1.41], {[B1.46], [B1.51]{{[}][}][}]}} // Double curly braces trigger regexps, escape as per FileCheck manual. -// CHECK-NEXT: 57: D dd[2] = {{[{][{]}}A(), {A(), A(){{[}][}]}}, {A(), {A(), A(){{[}][}][}]}}; -// CHECK-NEXT: 58: ~A() (Temporary object destructor) -// CHECK-NEXT: 59: ~A() (Temporary object destructor) +// CHECK-NEXT: 58: D dd[2] = {{[{][{]}}A(), {A(), A(){{[}][}]}}, {A(), {A(), A(){{[}][}][}]}}; +// CHECK-NEXT: 59: (FullExprCleanup collected 6 MTEs) // CHECK-NEXT: 60: ~A() (Temporary object destructor) // CHECK-NEXT: 61: ~A() (Temporary object destructor) // CHECK-NEXT: 62: ~A() (Temporary object destructor) // CHECK-NEXT: 63: ~A() (Temporary object destructor) -// CHECK-NEXT: 64: [B1.57].~D[2]() (Implicit destructor) -// CHECK-NEXT: 65: [B1.18].~D() (Implicit destructor) +// CHECK-NEXT: 64: ~A() (Temporary object destructor) +// CHECK-NEXT: 65: ~A() (Temporary object destructor) +// CHECK-NEXT: 66: [B1.58].~D[2]() (Implicit destructor) +// CHECK-NEXT: 67: [B1.18].~D() (Implicit destructor) // CHECK-NEXT: Preds (1): B2 // CHECK-NEXT: Succs (1): B0 // CHECK: [B0 (EXIT)] diff --git a/clang/test/Analysis/cfg-rich-constructors.cpp b/clang/test/Analysis/cfg-rich-constructors.cpp index aea983f1f74da..c91eec9fda871 100644 --- a/clang/test/Analysis/cfg-rich-constructors.cpp +++ b/clang/test/Analysis/cfg-rich-constructors.cpp @@ -253,20 +253,22 @@ class D: public C { // CHECK-NEXT: 4: [B1.3] // CHECK-NEXT: 5: [B1.4] (CXXConstructExpr, C([B1.4]) (Base initializer), C) // CHECK-NEXT: 6: C([B1.5]) (Base initializer) -// CHECK-NEXT: 7: CFGNewAllocator(C *) -// CHECK-NEXT: 8: C::get -// CHECK-NEXT: 9: [B1.8] (ImplicitCastExpr, FunctionToPointerDecay, C (*)(void)) -// CXX11-ELIDE-NEXT: 10: [B1.9]() (CXXRecordTypedCall, [B1.11], [B1.12]) -// CXX11-NOELIDE-NEXT: 10: [B1.9]() (CXXRecordTypedCall, [B1.11]) -// CXX11-NEXT: 11: [B1.10] -// CXX11-NEXT: 12: [B1.11] (CXXConstructExpr, [B1.13], C) -// CXX11-NEXT: 13: new C([B1.12]) -// CXX11-NEXT: 14: [B1.13] (CXXConstructExpr, c1([B1.13]) (Member initializer), C) -// CXX11-NEXT: 15: c1([B1.14]) (Member initializer) -// CXX17-NEXT: 10: [B1.9]() -// CXX17-NEXT: 11: new C([B1.10]) -// CXX17-NEXT: 12: [B1.11] (CXXConstructExpr, c1([B1.11]) (Member initializer), C) -// CXX17-NEXT: 13: c1([B1.12]) (Member initializer) +// CHECK-NEXT: 7: (FullExprCleanup collected 1 MTEs) +// CHECK-NEXT: 8: CFGNewAllocator(C *) +// CHECK-NEXT: 9: C::get +// CHECK-NEXT: 10: [B1.9] (ImplicitCastExpr, FunctionToPointerDecay, C (*)(void)) +// CXX11-ELIDE-NEXT: 11: [B1.10]() (CXXRecordTypedCall, [B1.12], [B1.13]) +// CXX11-NOELIDE-NEXT: 11: [B1.10]() (CXXRecordTypedCall, [B1.12]) +// CXX11-NEXT: 12: [B1.11] +// CXX11-NEXT: 13: [B1.12] (CXXConstructExpr, [B1.14], C) +// CXX11-NEXT: 14: new C([B1.13]) +// CXX11-NEXT: 15: [B1.14] (CXXConstructExpr, c1([B1.14]) (Member initializer), C) +// CXX11-NEXT: 16: c1([B1.15]) (Member initializer) +// CXX11-NEXT: 17: (FullExprCleanup collected 1 MTEs) +// CXX17-NEXT: 11: [B1.10]() +// CXX17-NEXT: 12: new C([B1.11]) +// CXX17-NEXT: 13: [B1.12] (CXXConstructExpr, c1([B1.12]) (Member initializer), C) +// CXX17-NEXT: 14: c1([B1.13]) (Member initializer) D(double): C(C::get()), c1(new C(C::get())) {} }; @@ -292,7 +294,8 @@ class F { // CXX11-NEXT: 6: [B1.5] // CXX11-NEXT: 7: [B1.6] (CXXConstructExpr, e([B1.6]) (Member initializer), E) // CXX11-NEXT: 8: e([B1.7]) (Member initializer) -// CXX11-NEXT: 9: ~E() (Temporary object destructor) +// CXX11-NEXT: 9: (FullExprCleanup collected 1 MTEs) +// CXX11-NEXT: 10: ~E() (Temporary object destructor) // CXX17-NEXT: 3: [B1.2]() (CXXRecordTypedCall, e([B1.4]) (Member initializer), [B1.4]) // CXX17-NEXT: 4: [B1.3] (BindTemporary) // CXX17-NEXT: 5: e([B1.4]) (Member initializer) @@ -345,8 +348,9 @@ C returnBracesWithMultipleItems() { // CXX11-ELIDE: 1: C() (CXXConstructExpr, [B1.2], [B1.3], C) // CXX11-NOELIDE: 1: C() (CXXConstructExpr, [B1.2], C) // CXX11-NEXT: 2: [B1.1] -// CXX11-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.4], C) -// CXX11-NEXT: 4: return [B1.3]; +// CXX11-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.5], C) +// CXX11-NEXT: 4: (FullExprCleanup collected 1 MTEs) +// CXX11-NEXT: 5: return [B1.3]; // CXX17: 1: C() (CXXConstructExpr, [B1.2], C) // CXX17-NEXT: 2: return [B1.1]; C returnTemporary() { @@ -361,8 +365,9 @@ C returnTemporary() { // CXX17-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.5], C) // CHECK-NEXT: 4: C([B1.3]) (CXXFunctionalCastExpr, ConstructorConversion, C) // CXX11-NEXT: 5: [B1.4] -// CXX11-NEXT: 6: [B1.5] (CXXConstructExpr, [B1.7], C) -// CXX11-NEXT: 7: return [B1.6]; +// CXX11-NEXT: 6: [B1.5] (CXXConstructExpr, [B1.8], C) +// CXX11-NEXT: 7: (FullExprCleanup collected 1 MTEs) +// CXX11-NEXT: 8: return [B1.6]; // CXX17-NEXT: 5: return [B1.4]; C returnTemporaryWithArgument() { @@ -375,8 +380,9 @@ C returnTemporaryWithArgument() { // CXX11-ELIDE-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.4], [B1.5]) // CXX11-NOELIDE-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.4]) // CXX11-NEXT: 4: [B1.3] -// CXX11-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.6], C) -// CXX11-NEXT: 6: return [B1.5]; +// CXX11-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.7], C) +// CXX11-NEXT: 6: (FullExprCleanup collected 1 MTEs) +// CXX11-NEXT: 7: return [B1.5]; // CXX17-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.4]) // CXX17-NEXT: 4: return [B1.3]; C returnTemporaryConstructedByFunction() { @@ -393,8 +399,9 @@ C returnTemporaryConstructedByFunction() { // CXX11-NOELIDE-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.7], C) // CXX11-NEXT: 6: C([B1.5]) (CXXFunctionalCastExpr, ConstructorConversion, C) // CXX11-NEXT: 7: [B1.6] -// CXX11-NEXT: 8: [B1.7] (CXXConstructExpr, [B1.9], C) -// CXX11-NEXT: 9: return [B1.8]; +// CXX11-NEXT: 8: [B1.7] (CXXConstructExpr, [B1.10], C) +// CXX11-NEXT: 9: (FullExprCleanup collected 2 MTEs) +// CXX11-NEXT: 10: return [B1.8]; // CXX17-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.5]) // CXX17-NEXT: 4: C([B1.3]) (CXXFunctionalCastExpr, NoOp, C) // CXX17-NEXT: 5: return [B1.4]; @@ -418,9 +425,10 @@ class D { // CXX11-NEXT: 2: [B1.1] (BindTemporary) // CXX11-NEXT: 3: [B1.2] (ImplicitCastExpr, NoOp, const D) // CXX11-NEXT: 4: [B1.3] -// CXX11-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.7], D) -// CXX11-NEXT: 6: ~D() (Temporary object destructor) -// CXX11-NEXT: 7: return [B1.5]; +// CXX11-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.8], D) +// CXX11-NEXT: 6: (FullExprCleanup collected 1 MTEs) +// CXX11-NEXT: 7: ~D() (Temporary object destructor) +// CXX11-NEXT: 8: return [B1.5]; // CXX17: 1: D() (CXXConstructExpr, [B1.3], [B1.2], D) // CXX17-NEXT: 2: [B1.1] (BindTemporary) // CXX17-NEXT: 3: return [B1.2]; @@ -438,8 +446,9 @@ D returnTemporary() { // CXX11-NEXT: 6: [B1.5] // CXX11-NEXT: 7: [B1.6] (CXXConstructExpr, [B1.8], D) // CXX11-NEXT: 8: D d = returnTemporary(); -// CXX11-NEXT: 9: ~D() (Temporary object destructor) -// CXX11-NEXT: 10: [B1.8].~D() (Implicit destructor) +// CXX11-NEXT: 9: (FullExprCleanup collected 1 MTEs) +// CXX11-NEXT: 10: ~D() (Temporary object destructor) +// CXX11-NEXT: 11: [B1.8].~D() (Implicit destructor) // CXX17-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.5], [B1.4]) // CXX17-NEXT: 4: [B1.3] (BindTemporary) // CXX17-NEXT: 5: D d = returnTemporary(); @@ -466,6 +475,7 @@ void simpleTemporary() { // CHECK-NEXT: 4: [B2.3].operator bool // CHECK-NEXT: 5: [B2.3] // CHECK-NEXT: 6: [B2.5] (ImplicitCastExpr, UserDefinedConversion, _Bool) +// CHECK-NEXT: 7: (FullExprCleanup collected 1 MTEs) // CHECK-NEXT: T: if [B2.6] void temporaryInCondition() { if (C()); @@ -477,12 +487,13 @@ void temporaryInCondition() { // CXX11-NEXT: 2: [B2.1] // CXX11-NEXT: 3: [B2.2] (CXXConstructExpr, [B2.4], C) // CXX11-NEXT: 4: C c = C(); -// CXX11-NEXT: 5: c -// CXX11-NEXT: 6: [B2.5] (ImplicitCastExpr, NoOp, const class C) -// CXX11-NEXT: 7: [B2.6].operator bool -// CXX11-NEXT: 8: [B2.6] -// CXX11-NEXT: 9: [B2.8] (ImplicitCastExpr, UserDefinedConversion, _Bool) -// CXX11-NEXT: T: if [B2.9] +// CXX11-NEXT: 5: (FullExprCleanup collected 1 MTEs) +// CXX11-NEXT: 6: c +// CXX11-NEXT: 7: [B2.6] (ImplicitCastExpr, NoOp, const class C) +// CXX11-NEXT: 8: [B2.7].operator bool +// CXX11-NEXT: 9: [B2.7] +// CXX11-NEXT: 10: [B2.9] (ImplicitCastExpr, UserDefinedConversion, _Bool) +// CXX11-NEXT: T: if [B2.10] // CXX17: 1: C() (CXXConstructExpr, [B2.2], C) // CXX17-NEXT: 2: C c = C(); // CXX17-NEXT: 3: c @@ -501,14 +512,15 @@ void temporaryInConditionVariable() { // CXX11-ELIDE-NEXT: 1: C() (CXXConstructExpr, [B2.2], [B2.3], C) // CXX11-NOELIDE-NEXT: 1: C() (CXXConstructExpr, [B2.2], C) // CXX11-NEXT: 2: [B2.1] -// CXX11-NEXT: 3: [B2.2] (CXXConstructExpr, [B2.4], C) -// CXX11-NEXT: 4: C c2 = C(); -// CXX11-NEXT: 5: c2 -// CXX11-NEXT: 6: [B2.5] (ImplicitCastExpr, NoOp, const class C) -// CXX11-NEXT: 7: [B2.6].operator bool -// CXX11-NEXT: 8: [B2.6] -// CXX11-NEXT: 9: [B2.8] (ImplicitCastExpr, UserDefinedConversion, _Bool) -// CXX11-NEXT: T: for (...; [B2.9]; ) +// CXX11-NEXT: 3: [B2.2] (CXXConstructExpr, [B2.5], C) +// CXX11-NEXT: 4: (FullExprCleanup collected 1 MTEs) +// CXX11-NEXT: 5: C c2 = C(); +// CXX11-NEXT: 6: c2 +// CXX11-NEXT: 7: [B2.6] (ImplicitCastExpr, NoOp, const class C) +// CXX11-NEXT: 8: [B2.7].operator bool +// CXX11-NEXT: 9: [B2.7] +// CXX11-NEXT: 10: [B2.9] (ImplicitCastExpr, UserDefinedConversion, _Bool) +// CXX11-NEXT: T: for (...; [B2.10]; ) // CXX17-NEXT: 1: C() (CXXConstructExpr, [B2.2], C) // CXX17-NEXT: 2: C c2 = C(); // CXX17-NEXT: 3: c2 @@ -534,14 +546,15 @@ void temporaryInForLoopConditionVariable() { // CXX11-ELIDE: 1: C() (CXXConstructExpr, [B2.2], [B2.3], C) // CXX11-NOELIDE: 1: C() (CXXConstructExpr, [B2.2], C) // CXX11-NEXT: 2: [B2.1] -// CXX11-NEXT: 3: [B2.2] (CXXConstructExpr, [B2.4], C) -// CXX11-NEXT: 4: C c = C(); -// CXX11-NEXT: 5: c -// CXX11-NEXT: 6: [B2.5] (ImplicitCastExpr, NoOp, const class C) -// CXX11-NEXT: 7: [B2.6].operator bool -// CXX11-NEXT: 8: [B2.6] -// CXX11-NEXT: 9: [B2.8] (ImplicitCastExpr, UserDefinedConversion, _Bool) -// CXX11-NEXT: T: while [B2.9] +// CXX11-NEXT: 3: [B2.2] (CXXConstructExpr, [B2.5], C) +// CXX11-NEXT: 4: (FullExprCleanup collected 1 MTEs) +// CXX11-NEXT: 5: C c = C(); +// CXX11-NEXT: 6: c +// CXX11-NEXT: 7: [B2.6] (ImplicitCastExpr, NoOp, const class C) +// CXX11-NEXT: 8: [B2.7].operator bool +// CXX11-NEXT: 9: [B2.7 +// CXX11-NEXT: 10: [B2.9] (ImplicitCastExpr, UserDefinedConversion, _Bool) +// CXX11-NEXT: T: while [B2.10] // CXX17: 1: C() (CXXConstructExpr, [B2.2], C) // CXX17-NEXT: 2: C c = C(); // CXX17-NEXT: 3: c @@ -585,7 +598,8 @@ void simpleTemporary() { // CHECK-NEXT: 5: [B2.4].operator bool // CHECK-NEXT: 6: [B2.4] // CHECK-NEXT: 7: [B2.6] (ImplicitCastExpr, UserDefinedConversion, _Bool) -// CHECK-NEXT: 8: ~D() (Temporary object destructor) +// CHECK-NEXT: 8: (FullExprCleanup collected 1 MTEs) +// CHECK-NEXT: 9: ~D() (Temporary object destructor) // CHECK-NEXT: T: if [B2.7] void temporaryInCondition() { if (D()); @@ -625,6 +639,7 @@ void referenceVariableWithInitializer() { // CXX11-NEXT: 2: [B4.1] (ImplicitCastExpr, NoOp, const D) // CXX11-NEXT: 3: [B4.2] // CXX11-NEXT: 4: const D &d = coin ? D::get() : D(0); +// CXX11-NEXT: 5: (FullExprCleanup collected 2 MTEs) // CXX11-NEXT: T: (Temp Dtor) [B6.3] // CXX11: [B5] // CXX11-NEXT: 1: D::get @@ -737,14 +752,16 @@ class B { // CXX11-NEXT: 8: [B1.7] // CXX11-NEXT: 9: [B1.8] (CXXConstructExpr, [B1.10], B) // CXX11-NEXT: 10: B b = A(); -// CXX11-NEXT: 11: ~B() (Temporary object destructor) -// CXX11-NEXT: 12: [B1.10].~B() (Implicit destructor) +// CXX11-NEXT: 11: (FullExprCleanup collected 2 MTEs) +// CXX11-NEXT: 12: ~B() (Temporary object destructor) +// CXX11-NEXT: 13: [B1.10].~B() (Implicit destructor) // CXX17-NEXT: 2: [B1.1] (ImplicitCastExpr, NoOp, const A) // CXX17-NEXT: 3: [B1.2] // CXX17-NEXT: 4: [B1.3] (CXXConstructExpr, [B1.6], B) // CXX17-NEXT: 5: [B1.4] (ImplicitCastExpr, ConstructorConversion, B) // CXX17-NEXT: 6: B b = A(); -// CXX17-NEXT: 7: [B1.6].~B() (Implicit destructor) +// CXX17-NEXT: 7: (FullExprCleanup collected 1 MTEs) +// CXX17-NEXT: 8: [B1.6].~B() (Implicit destructor) void implicitConstructionConversionFromTemporary() { B b = A(); } @@ -763,12 +780,14 @@ void implicitConstructionConversionFromTemporary() { // CXX11-NEXT: 10: [B1.9] // CXX11-NEXT: 11: [B1.10] (CXXConstructExpr, [B1.12], B) // CXX11-NEXT: 12: B b = get(); -// CXX11-NEXT: 13: ~B() (Temporary object destructor) -// CXX11-NEXT: 14: [B1.12].~B() (Implicit destructor) +// CXX11-NEXT: 13: (FullExprCleanup collected 2 MTEs) +// CXX11-NEXT: 14: ~B() (Temporary object destructor) +// CXX11-NEXT: 15: [B1.12].~B() (Implicit destructor) // CXX17-NEXT: 6: [B1.5] (CXXConstructExpr, [B1.8], B) // CXX17-NEXT: 7: [B1.6] (ImplicitCastExpr, ConstructorConversion, B) // CXX17-NEXT: 8: B b = get(); -// CXX17-NEXT: 9: [B1.8].~B() (Implicit destructor) +// CXX17-NEXT: 9: (FullExprCleanup collected 1 MTEs) +// CXX17-NEXT: 10: [B1.8].~B() (Implicit destructor) void implicitConstructionConversionFromFunctionValue() { B b = get(); } @@ -782,7 +801,8 @@ void implicitConstructionConversionFromFunctionValue() { // CHECK-NEXT: 6: [B1.5] (ImplicitCastExpr, NoOp, const B) // CHECK-NEXT: 7: [B1.6] // CHECK-NEXT: 8: const B &b = A(); -// CHECK-NEXT: 9: [B1.8].~B() (Implicit destructor) +// CHECK-NEXT: 9: (FullExprCleanup collected 1 MTEs) +// CHECK-NEXT: 10: [B1.8].~B() (Implicit destructor) void implicitConstructionConversionFromTemporaryWithLifetimeExtension() { const B &b = A(); } @@ -798,7 +818,8 @@ void implicitConstructionConversionFromTemporaryWithLifetimeExtension() { // CHECK-NEXT: 8: [B1.7] (ImplicitCastExpr, NoOp, const B) // CHECK-NEXT: 9: [B1.8] // CHECK-NEXT: 10: const B &b = get(); -// CHECK-NEXT: 11: [B1.10].~B() (Implicit destructor) +// CHECK-NEXT: 11: (FullExprCleanup collected 1 MTEs) +// CHECK-NEXT: 12: [B1.10].~B() (Implicit destructor) void implicitConstructionConversionFromFunctionValueWithLifetimeExtension() { const B &b = get(); // no-crash } @@ -854,8 +875,9 @@ void passArgument() { // CXX11-NEXT: 10: [B1.9] (CXXConstructExpr, [B1.11], [B1.12]+1, D) // CXX11-NEXT: 11: [B1.10] (BindTemporary) // CXX11-NEXT: 12: [B1.2]([B1.5], [B1.11]) -// CXX11-NEXT: 13: ~D() (Temporary object destructor) +// CXX11-NEXT: 13: (FullExprCleanup collected 2 MTEs) // CXX11-NEXT: 14: ~D() (Temporary object destructor) +// CXX11-NEXT: 15: ~D() (Temporary object destructor) // CXX17-NEXT: 3: C() (CXXConstructExpr, [B1.6]+0, C) // CXX17-NEXT: 4: D() (CXXConstructExpr, [B1.5], [B1.6]+1, D) // CXX17-NEXT: 5: [B1.4] (BindTemporary) @@ -887,8 +909,9 @@ void passArgumentByReference() { // CXX11-NEXT: 7: [B1.6] (CXXConstructExpr, [B1.8], [B1.9]+0, D) // CXX11-NEXT: 8: [B1.7] (BindTemporary) // CXX11-NEXT: 9: [B1.2]([B1.8]) -// CXX11-NEXT: 10: ~D() (Temporary object destructor) +// CXX11-NEXT: 10: (FullExprCleanup collected 1 MTEs) // CXX11-NEXT: 11: ~D() (Temporary object destructor) +// CXX11-NEXT: 12: ~D() (Temporary object destructor) // CXX17-NEXT: 3: D() (CXXConstructExpr, [B1.4], [B1.5]+0, D) // CXX17-NEXT: 4: [B1.3] (BindTemporary) // CXX17-NEXT: 5: [B1.2]([B1.4]) @@ -905,7 +928,8 @@ void passArgumentWithDestructor() { // CHECK-NEXT: 5: [B1.4] (ImplicitCastExpr, NoOp, const D) // CHECK-NEXT: 6: [B1.5] // CHECK-NEXT: 7: [B1.2]([B1.6]) -// CHECK-NEXT: 8: ~D() (Temporary object destructor) +// CHECK-NEXT: 8: (FullExprCleanup collected 1 MTEs) +// CHECK-NEXT: 9: ~D() (Temporary object destructor) void passArgumentWithDestructorByReference() { useDByReference(D()); } @@ -924,8 +948,9 @@ void passArgumentWithDestructorByReference() { // CXX11-NEXT: 9: [B1.8] // CXX11-NEXT: 10: [B1.9] (CXXConstructExpr, [B1.11], E) // CXX11-NEXT: 11: E e = E(D()); -// CXX11-NEXT: 12: ~D() (Temporary object destructor) +// CXX11-NEXT: 12: (FullExprCleanup collected 2 MTEs) // CXX11-NEXT: 13: ~D() (Temporary object destructor) +// CXX11-NEXT: 14: ~D() (Temporary object destructor) // CXX17: 1: D() (CXXConstructExpr, [B1.2], [B1.3]+0, D) // CXX17-NEXT: 2: [B1.1] (BindTemporary) // CXX17-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.5], E) @@ -953,10 +978,11 @@ void passArgumentIntoAnotherConstructor() { // CXX11-NEXT: 11: [B1.10] (CXXConstructExpr, [B1.12], [B1.13]+1, D) // CXX11-NEXT: 12: [B1.11] (BindTemporary) // CXX11-NEXT: 13: E([B1.6], [B1.12]) (CXXConstructExpr, E) -// CXX11-NEXT: 14: ~D() (Temporary object destructor) +// CXX11-NEXT: 14: (FullExprCleanup collected 2 MTEs) // CXX11-NEXT: 15: ~D() (Temporary object destructor) // CXX11-NEXT: 16: ~D() (Temporary object destructor) // CXX11-NEXT: 17: ~D() (Temporary object destructor) +// CXX11-NEXT: 18: ~D() (Temporary object destructor) // CXX17: 1: D() (CXXConstructExpr, [B1.2], [B1.5]+0, D) // CXX17-NEXT: 2: [B1.1] (BindTemporary) // CXX17-NEXT: 3: D() (CXXConstructExpr, [B1.4], [B1.5]+1, D) @@ -1034,6 +1060,7 @@ int variadic(...); // This code is quite exotic, so let's not test the CFG for it, // but only make sure we don't crash. +// CHECK-LABEL: void testCrashOnVariadicArgument() void testCrashOnVariadicArgument() { C c(variadic(0 ? c : 0)); // no-crash } diff --git a/clang/test/Analysis/cfg-rich-constructors.mm b/clang/test/Analysis/cfg-rich-constructors.mm index f048f061e9fba..1b73c7ce55f76 100644 --- a/clang/test/Analysis/cfg-rich-constructors.mm +++ b/clang/test/Analysis/cfg-rich-constructors.mm @@ -30,8 +30,9 @@ -(D) bar; // CXX11-NEXT: 8: [B1.7] (BindTemporary) // Double brackets trigger FileCheck variables, escape. // CXX11-NEXT: 9: {{\[}}[B1.2] foo:[B1.8]] -// CXX11-NEXT: 10: ~D() (Temporary object destructor) +// CXX11-NEXT: 10: (FullExprCleanup collected 1 MTEs) // CXX11-NEXT: 11: ~D() (Temporary object destructor) +// CXX11-NEXT: 12: ~D() (Temporary object destructor) // CXX17-NEXT: 3: D() (CXXConstructExpr, [B1.4], [B1.5]+0, D) // CXX17-NEXT: 4: [B1.3] (BindTemporary) // Double brackets trigger FileCheck variables, escape. @@ -53,8 +54,9 @@ void passArgumentIntoMessage(E *e) { // CXX11-NEXT: 6: [B1.5] // CXX11-NEXT: 7: [B1.6] (CXXConstructExpr, [B1.8], D) // CXX11-NEXT: 8: D d = [e bar]; -// CXX11-NEXT: 9: ~D() (Temporary object destructor) -// CXX11-NEXT: 10: [B1.8].~D() (Implicit destructor) +// CXX11-NEXT: 9: (FullExprCleanup collected 1 MTEs) +// CXX11-NEXT: 10: ~D() (Temporary object destructor) +// CXX11-NEXT: 11: [B1.8].~D() (Implicit destructor) // Double brackets trigger FileCheck variables, escape. // CXX17-NEXT: 3: {{\[}}[B1.2] bar] (CXXRecordTypedCall, [B1.5], [B1.4]) // CXX17-NEXT: 4: [B1.3] (BindTemporary) diff --git a/clang/test/Analysis/cfg.cpp b/clang/test/Analysis/cfg.cpp index 2a88b73d27756..9a0a60110876b 100644 --- a/clang/test/Analysis/cfg.cpp +++ b/clang/test/Analysis/cfg.cpp @@ -390,6 +390,7 @@ void test_lifetime_extended_temporaries() { 3; } // CHECK: LifetimeExtend(4) + // CHECK-NEXT: (FullExprCleanup collected 2 MTEs) // CHECK-NEXT: ~LifetimeExtend() // CHECK-NEXT: ~LifetimeExtend() // CHECK-NEXT: : 4 diff --git a/clang/test/Analysis/missing-bind-temporary.cpp b/clang/test/Analysis/missing-bind-temporary.cpp index 3d1af469dc01c..78bcb570a3ce5 100644 --- a/clang/test/Analysis/missing-bind-temporary.cpp +++ b/clang/test/Analysis/missing-bind-temporary.cpp @@ -28,8 +28,9 @@ class B { // CHECK-NEXT: 7: [B1.6] (BindTemporary) // CHECK-NEXT: 8: [B1.7] // CHECK-NEXT: 9: [B1.5] = [B1.8] (OperatorCall) -// CHECK-NEXT: 10: ~B() (Temporary object destructor) -// CHECK-NEXT: 11: [B1.2].~B() (Implicit destructor) +// CHECK-NEXT: 10: (FullExprCleanup collected 1 MTEs) +// CHECK-NEXT: 11: ~B() (Temporary object destructor) +// CHECK-NEXT: 12: [B1.2].~B() (Implicit destructor) void foo(int) { B i; i = {}; @@ -65,8 +66,9 @@ class B { // CHECK-NEXT: 7: [B1.6] (BindTemporary) // CHECK-NEXT: 8: [B1.7] // CHECK-NEXT: 9: [B1.5] = [B1.8] (OperatorCall) -// CHECK-NEXT: 10: ~B() (Temporary object destructor) -// CHECK-NEXT: 11: [B1.2].~B() (Implicit destructor) +// CHECK-NEXT: 10: (FullExprCleanup collected 1 MTEs) +// CHECK-NEXT: 11: ~B() (Temporary object destructor) +// CHECK-NEXT: 12: [B1.2].~B() (Implicit destructor) template <typename T> void foo(T) { B i; i = {}; @@ -107,8 +109,9 @@ class B { // CHECK-NEXT: 8: [B1.7] (BindTemporary) // CHECK-NEXT: 9: [B1.8] // CHECK-NEXT: 10: [B1.5] = [B1.9] (OperatorCall) -// CHECK-NEXT: 11: ~B() (Temporary object destructor) -// CHECK-NEXT: 12: [B1.2].~B() (Implicit destructor) +// CHECK-NEXT: 11: (FullExprCleanup collected 1 MTEs) +// CHECK-NEXT: 12: ~B() (Temporary object destructor) +// CHECK-NEXT: 13: [B1.2].~B() (Implicit destructor) template <typename T> void foo(T) { B i; i = {}; diff --git a/clang/test/Analysis/temp-obj-dtors-cfg-output.cpp b/clang/test/Analysis/temp-obj-dtors-cfg-output.cpp index b496d261e92f4..22807741fdae1 100644 --- a/clang/test/Analysis/temp-obj-dtors-cfg-output.cpp +++ b/clang/test/Analysis/temp-obj-dtors-cfg-output.cpp @@ -240,9 +240,10 @@ const C &bar3(bool coin) { // CHECK: 3: [B1.2] (ImplicitCastExpr, NoOp, const A) // CHECK: 4: [B1.3] // WARNINGS: 5: [B1.4] (CXXConstructExpr, A) -// ANALYZER: 5: [B1.4] (CXXConstructExpr, [B1.7], A) -// CHECK: 6: ~A() (Temporary object destructor) -// CHECK: 7: return [B1.5]; +// ANALYZER: 5: [B1.4] (CXXConstructExpr, [B1.8], A) +// CHECK: 6: (FullExprCleanup collected 1 MTEs) +// CHECK: 7: ~A() (Temporary object destructor) +// CHECK: 8: return [B1.5]; // CHECK: Preds (1): B2 // CHECK: Succs (1): B0 // CHECK: [B0 (EXIT)] @@ -300,9 +301,10 @@ const C &bar3(bool coin) { // CHECK: 3: [B1.2] (ImplicitCastExpr, NoOp, const A) // CHECK: 4: [B1.3] // WARNINGS: 5: [B1.4] (CXXConstructExpr, A) -// ANALYZER: 5: [B1.4] (CXXConstructExpr, [B1.7], A) -// CHECK: 6: ~A() (Temporary object destructor) -// CHECK: 7: return [B1.5]; +// ANALYZER: 5: [B1.4] (CXXConstructExpr, [B1.8], A) +// CHECK: 6: (FullExprCleanup collected 1 MTEs) +// CHECK: 7: ~A() (Temporary object destructor) +// CHECK: 8: return [B1.5]; // CHECK: Preds (1): B2 // CHECK: Succs (1): B0 // CHECK: [B0 (EXIT)] @@ -328,31 +330,33 @@ const C &bar3(bool coin) { // CHECK: 14: int([B1.13]) (CXXFunctionalCastExpr, NoOp, int) // CHECK: 15: [B1.7] + [B1.14] // CHECK: 16: int a = int(A()) + int(B()); -// CHECK: 17: ~B() (Temporary object destructor) -// CHECK: 18: ~A() (Temporary object destructor) -// CHECK: 19: foo -// CHECK: 20: [B1.19] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int)) -// WARNINGS: 21: A() (CXXConstructExpr, A) -// ANALYZER: 21: A() (CXXConstructExpr, [B1.22], [B1.23], A) -// CHECK: 22: [B1.21] (BindTemporary) -// CHECK: 23: [B1.22] -// CHECK: 24: [B1.23].operator int -// CHECK: 25: [B1.23] -// CHECK: 26: [B1.25] (ImplicitCastExpr, UserDefinedConversion, int) -// CHECK: 27: int([B1.26]) (CXXFunctionalCastExpr, NoOp, int) -// WARNINGS: 28: B() (CXXConstructExpr, B) -// ANALYZER: 28: B() (CXXConstructExpr, [B1.29], [B1.30], B) -// CHECK: 29: [B1.28] (BindTemporary) -// CHECK: 30: [B1.29] -// CHECK: 31: [B1.30].operator int -// CHECK: 32: [B1.30] -// CHECK: 33: [B1.32] (ImplicitCastExpr, UserDefinedConversion, int) -// CHECK: 34: int([B1.33]) (CXXFunctionalCastExpr, NoOp, int) -// CHECK: 35: [B1.27] + [B1.34] -// CHECK: 36: [B1.20]([B1.35]) -// CHECK: 37: ~B() (Temporary object destructor) -// CHECK: 38: ~A() (Temporary object destructor) -// CHECK: 39: int b; +// CHECK: 17: (FullExprCleanup collected 2 MTEs) +// CHECK: 18: ~B() (Temporary object destructor) +// CHECK: 19: ~A() (Temporary object destructor) +// CHECK: 20: foo +// CHECK: 21: [B1.20] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int)) +// WARNINGS: 22: A() (CXXConstructExpr, A) +// ANALYZER: 22: A() (CXXConstructExpr, [B1.23], [B1.24], A) +// CHECK: 23: [B1.22] (BindTemporary) +// CHECK: 24: [B1.23] +// CHECK: 25: [B1.24].operator int +// CHECK: 26: [B1.24] +// CHECK: 27: [B1.26] (ImplicitCastExpr, UserDefinedConversion, int) +// CHECK: 28: int([B1.27]) (CXXFunctionalCastExpr, NoOp, int) +// WARNINGS: 29: B() (CXXConstructExpr, B) +// ANALYZER: 29: B() (CXXConstructExpr, [B1.30], [B1.31], B) +// CHECK: 30: [B1.29] (BindTemporary) +// CHECK: 31: [B1.30] +// CHECK: 32: [B1.31].operator int +// CHECK: 33: [B1.31] +// CHECK: 34: [B1.33] (ImplicitCastExpr, UserDefinedConversion, int) +// CHECK: 35: int([B1.34]) (CXXFunctionalCastExpr, NoOp, int) +// CHECK: 36: [B1.28] + [B1.35] +// CHECK: 37: [B1.21]([B1.36]) +// CHECK: 38: (FullExprCleanup collected 2 MTEs) +// CHECK: 39: ~B() (Temporary object destructor) +// CHECK: 40: ~A() (Temporary object destructor) +// CHECK: 41: int b; // CHECK: Preds (1): B2 // CHECK: Succs (1): B0 // CHECK: [B0 (EXIT)] @@ -371,6 +375,7 @@ const C &bar3(bool coin) { // CHECK: [B3] // CHECK: 1: [B5.9] && [B4.6] // CHECK: 2: [B5.3]([B3.1]) +// CHECK: 3: (FullExprCleanup collected 2 MTEs) // CHECK: T: (Temp Dtor) [B4.2] // CHECK: Preds (2): B4 B5 // CHECK: Succs (2): B2 B1 @@ -405,6 +410,7 @@ const C &bar3(bool coin) { // CHECK: [B7] // CHECK: 1: [B9.6] && [B8.6] // CHECK: 2: bool a = A() && B(); +// CHECK: 3: (FullExprCleanup collected 2 MTEs) // CHECK: T: (Temp Dtor) [B8.2] // CHECK: Preds (2): B8 B9 // CHECK: Succs (2): B6 B5 @@ -479,6 +485,7 @@ const C &bar3(bool coin) { // CHECK: [B7] // CHECK: 1: [B9.6] || [B8.6] // CHECK: 2: bool a = A() || B(); +// CHECK: 3: (FullExprCleanup collected 2 MTEs) // CHECK: T: (Temp Dtor) [B8.2] // CHECK: Preds (2): B8 B9 // CHECK: Succs (2): B6 B5 @@ -535,7 +542,8 @@ const C &bar3(bool coin) { // CHECK: 5: [B4.4].operator bool // CHECK: 6: [B4.4] // CHECK: 7: [B4.6] (ImplicitCastExpr, UserDefinedConversion, _Bool) -// CHECK: 8: ~B() (Temporary object destructor) +// CHECK: 8: (FullExprCleanup collected 1 MTEs) +// CHECK: 9: ~B() (Temporary object destructor) // CHECK: T: if [B4.7] // CHECK: Preds (2): B5 B6 // CHECK: Succs (2): B3 B2 @@ -558,6 +566,7 @@ const C &bar3(bool coin) { // WARNINGS: 4: [B7.3] (CXXConstructExpr, A) // ANALYZER: 4: [B7.3] (CXXConstructExpr, [B7.5], A) // CHECK: 5: A a = B() ? A() : A(B()); +// CHECK: 6: (FullExprCleanup collected 6 MTEs) // CHECK: T: (Temp Dtor) [B9.2] // CHECK: Preds (2): B8 B9 // CHECK: Succs (2): B6 B5 @@ -671,7 +680,8 @@ const C &bar3(bool coin) { // CHECK: 4: [B3.3].operator bool // CHECK: 5: [B3.3] // CHECK: 6: [B3.5] (ImplicitCastExpr, UserDefinedConversion, _Bool) -// CHECK: 7: ~C() (Temporary object destructor) +// CHECK: 7: (FullExprCleanup collected 1 MTEs) +// CHECK: 8: ~C() (Temporary object destructor) // CHECK: T: if [B3.6] // CHECK: Preds (1): B4 // CHECK: Succs (2): B2 B1 @@ -703,12 +713,13 @@ const C &bar3(bool coin) { // WARNINGS: 5: [B4.4] (CXXConstructExpr, C) // ANALYZER: 5: [B4.4] (CXXConstructExpr, [B4.6], C) // CHECK: 6: C c = C(); -// CHECK: 7: ~C() (Temporary object destructor) -// CHECK: 8: c -// CHECK: 9: [B4.8].operator bool -// CHECK: 10: [B4.8] -// CHECK: 11: [B4.10] (ImplicitCastExpr, UserDefinedConversion, _Bool) -// CHECK: T: if [B4.11] +// CHECK: 7: (FullExprCleanup collected 1 MTEs) +// CHECK: 8: ~C() (Temporary object destructor) +// CHECK: 9: c +// CHECK: 10: [B4.9].operator bool +// CHECK: 11: [B4.9] +// CHECK: 12: [B4.11] (ImplicitCastExpr, UserDefinedConversion, _Bool) +// CHECK: T: if [B4.12] // CHECK: Preds (1): B5 // CHECK: Succs (2): B3 B2 // CHECK: [B0 (EXIT)] @@ -732,6 +743,7 @@ const C &bar3(bool coin) { // CHECK: 3: [B3.2].operator bool // CHECK: 4: [B3.2] // CHECK: 5: [B3.4] (ImplicitCastExpr, UserDefinedConversion, _Bool) +// CHECK: 6: (FullExprCleanup collected 1 MTEs) // CHECK: T: if [B3.5] // CHECK: Preds (1): B4 // CHECK: Succs (2): B2 B1 @@ -757,22 +769,24 @@ const C &bar3(bool coin) { // CXX98-WARNINGS: 4: [B3.3] (CXXConstructExpr, D) // CXX98-ANALYZER: 4: [B3.3] (CXXConstructExpr, [B3.5], D) // CXX98: 5: D d = D(); -// CXX98: 6: d -// CXX98: 7: [B3.6].operator bool -// CXX98: 8: [B3.6] -// CXX98: 9: [B3.8] (ImplicitCastExpr, UserDefinedConversion, _Bool) -// CXX98: T: if [B3.9] +// CXX98: 6: (FullExprCleanup collected 1 MTEs) +// CXX98: 7: d +// CXX98: 8: [B3.7].operator bool +// CXX98: 9: [B3.7] +// CXX98: 10: [B3.9] (ImplicitCastExpr, UserDefinedConversion, _Bool) +// CXX98: T: if [B3.10] // CXX11-WARNINGS: 1: D() (CXXConstructExpr, D) // CXX11-ANALYZER: 1: D() (CXXConstructExpr, [B3.2], [B3.3], D) // CXX11: 2: [B3.1] // CXX11-WARNINGS: 3: [B3.2] (CXXConstructExpr, D) // CXX11-ANALYZER: 3: [B3.2] (CXXConstructExpr, [B3.4], D) // CXX11: 4: D d = D(); -// CXX11: 5: d -// CXX11: 6: [B3.5].operator bool -// CXX11: 7: [B3.5] -// CXX11: 8: [B3.7] (ImplicitCastExpr, UserDefinedConversion, _Bool) -// CXX11: T: if [B3.8] +// CXX11: 5: (FullExprCleanup collected 1 MTEs) +// CXX11: 6: d +// CXX11: 7: [B3.6].operator bool +// CXX11: 8: [B3.6] +// CXX11: 9: [B3.8] (ImplicitCastExpr, UserDefinedConversion, _Bool) +// CXX11: T: if [B3.9] // CHECK: Preds (1): B4 // CHECK: Succs (2): B2 B1 // CHECK: [B0 (EXIT)] @@ -802,6 +816,7 @@ const C &bar3(bool coin) { // CHECK: 2: [B4.1] (ImplicitCastExpr, NoOp, const A) // CHECK: 3: [B4.2] // CHECK: 4: [B7.3]([B4.3]) +// CHECK: 5: (FullExprCleanup collected 6 MTEs) // CHECK: T: (Temp Dtor) [B6.2] // CHECK: Preds (2): B5 B6 // CHECK: Succs (2): B3 B2 @@ -867,6 +882,7 @@ const C &bar3(bool coin) { // CHECK: 2: [B10.1] (ImplicitCastExpr, NoOp, const A) // CHECK: 3: [B10.2] // CHECK: 4: const A &a = B() ? A() : A(B()); +// CHECK: 5: (FullExprCleanup collected 5 MTEs) // CHECK: T: (Temp Dtor) [B12.2] // CHECK: Preds (2): B11 B12 // CHECK: Succs (2): B9 B8 @@ -940,6 +956,8 @@ const C &bar3(bool coin) { // WARNINGS: 4: [B4.3] (CXXConstructExpr, A) // ANALYZER: 4: [B4.3] (CXXConstructExpr, [B4.5], A) // CHECK: 5: A a = A() ?: A(); +// CXX98: 6: (FullExprCleanup collected 4 MTEs) +// CXX11: 6: (FullExprCleanup collected 2 MTEs) // CHECK: T: (Temp Dtor) [B6.2] // CHECK: Preds (2): B5 B6 // CHECK: Succs (2): B3 B2 @@ -1002,6 +1020,8 @@ const C &bar3(bool coin) { // CHECK: 2: [B4.1] (ImplicitCastExpr, NoOp, const A) // CHECK: 3: [B4.2] // CHECK: 4: [B7.2]([B4.3]) +// CXX98: 5: (FullExprCleanup collected 4 MTEs) +// CXX11: 5: (FullExprCleanup collected 2 MTEs) // CHECK: T: (Temp Dtor) [B6.2] // CHECK: Preds (2): B5 B6 // CHECK: Succs (2): B3 B2 @@ -1052,6 +1072,8 @@ const C &bar3(bool coin) { // CHECK: 2: [B9.1] (ImplicitCastExpr, NoOp, const A) // CHECK: 3: [B9.2] // CHECK: 4: const A &a = A() ?: A(); +// CXX98: 5: (FullExprCleanup collected 3 MTEs) +// CXX11: 5: (FullExprCleanup collected 1 MTEs) // CHECK: T: (Temp Dtor) [B11.2] // CHECK: Preds (2): B10 B11 // CHECK: Succs (2): B8 B7 @@ -1103,9 +1125,10 @@ const C &bar3(bool coin) { // WARNINGS: 5: [B1.4] (CXXConstructExpr, A) // ANALYZER: 5: [B1.4] (CXXConstructExpr, [B1.6], A) // CHECK: 6: A a = A(); -// CHECK: 7: ~A() (Temporary object destructor) -// CHECK: 8: int b; -// CHECK: 9: [B1.6].~A() (Implicit destructor) +// CHECK: 7: (FullExprCleanup collected 1 MTEs) +// CHECK: 8: ~A() (Temporary object destructor) +// CHECK: 9: int b; +// CHECK: 10: [B1.6].~A() (Implicit destructor) // CHECK: Preds (1): B2 // CHECK: Succs (1): B0 // CHECK: [B0 (EXIT)] @@ -1127,9 +1150,10 @@ const C &bar3(bool coin) { // CHECK: 10: [B1.9] (ImplicitCastExpr, NoOp, const A) // CHECK: 11: [B1.10] // CHECK: 12: [B1.7]([B1.11]) -// CHECK: 13: ~A() (Temporary object destructor) -// CHECK: 14: int b; -// CHECK: 15: [B1.5].~A() (Implicit destructor) +// CHECK: 13: (FullExprCleanup collected 1 MTEs) +// CHECK: 14: ~A() (Temporary object destructor) +// CHECK: 15: int b; +// CHECK: 16: [B1.5].~A() (Implicit destructor) // CHECK: Preds (1): B2 // CHECK: Succs (1): B0 // CHECK: [B0 (EXIT)] @@ -1147,9 +1171,10 @@ const C &bar3(bool coin) { // WARNINGS: 7: [B1.6] (CXXConstructExpr, A) // ANALYZER: 7: [B1.6] (CXXConstructExpr, [B1.8], A) // CHECK: 8: A a = A::make(); -// CHECK: 9: ~A() (Temporary object destructor) -// CHECK: 10: int b; -// CHECK: 11: [B1.8].~A() (Implicit destructor) +// CHECK: 9: (FullExprCleanup collected 1 MTEs) +// CHECK: 10: ~A() (Temporary object destructor) +// CHECK: 11: int b; +// CHECK: 12: [B1.8].~A() (Implicit destructor) // CHECK: Preds (1): B2 // CHECK: Succs (1): B0 // CHECK: [B0 (EXIT)] @@ -1175,9 +1200,10 @@ const C &bar3(bool coin) { // CHECK: 14: [B1.13] (ImplicitCastExpr, NoOp, const A) // CHECK: 15: [B1.14] // CHECK: 16: [B1.9]([B1.15]) -// CHECK: 17: ~A() (Temporary object destructor) -// CHECK: 18: int b; -// CHECK: 19: [B1.7].~A() (Implicit destructor) +// CHECK: 17: (FullExprCleanup collected 1 MTEs) +// CHECK: 18: ~A() (Temporary object destructor) +// CHECK: 19: int b; +// CHECK: 20: [B1.7].~A() (Implicit destructor) // CHECK: Preds (1): B2 // CHECK: Succs (1): B0 // CHECK: [B0 (EXIT)] @@ -1195,8 +1221,9 @@ const C &bar3(bool coin) { // CHECK: 7: [B1.6] (ImplicitCastExpr, UserDefinedConversion, int) // CHECK: 8: a // CHECK: 9: [B1.8] = [B1.7] -// CHECK: 10: ~A() (Temporary object destructor) -// CHECK: 11: int b; +// CHECK: 10: (FullExprCleanup collected 1 MTEs) +// CHECK: 11: ~A() (Temporary object destructor) +// CHECK: 12: int b; // CHECK: Preds (1): B2 // CHECK: Succs (1): B0 // CHECK: [B0 (EXIT)] @@ -1222,9 +1249,10 @@ const C &bar3(bool coin) { // CHECK: 14: int([B1.13]) (CXXFunctionalCastExpr, NoOp, int) // CHECK: 15: [B1.7] + [B1.14] // CHECK: 16: a([B1.15]) (Member initializer) -// CHECK: 17: ~B() (Temporary object destructor) -// CHECK: 18: ~A() (Temporary object destructor) -// CHECK: 19: b(/*implicit*/(int)0) (Member initializer) +// CHECK: 17: (FullExprCleanup collected 2 MTEs) +// CHECK: 18: ~B() (Temporary object destructor) +// CHECK: 19: ~A() (Temporary object destructor) +// CHECK: 20: b(/*implicit*/(int)0) (Member initializer) // CHECK: Preds (1): B2 // CHECK: Succs (1): B0 // CHECK: [B0 (EXIT)] @@ -1243,7 +1271,8 @@ const C &bar3(bool coin) { // CHECK: 3: [B2.2] (BindTemporary) // CHECK: [[MEMBER:[45]]]: [B2.{{[34]}}].f // CHECK: {{[56]}}: [B2.[[MEMBER]]]() -// CHECK: {{[67]}}: ~NoReturn() (Temporary object destructor) +// CHECK: 7: (FullExprCleanup collected 1 MTEs) +// CHECK: {{[78]}}: ~NoReturn() (Temporary object destructor) // CHECK: Preds (1): B3 // CHECK: Succs (1): B0 // CHECK: [B0 (EXIT)] @@ -1288,6 +1317,7 @@ const C &bar3(bool coin) { // CHECK: Succs (1): B0 // CHECK: [B5] // CHECK: 1: [B7.3] || [B6.7] +// CHECK: 2: (FullExprCleanup collected 1 MTEs) // CHECK: T: (Temp Dtor) [B6.4] // CHECK: Preds (2): B6 B7 // CHECK: Succs (2): B4 B3 @@ -1339,6 +1369,7 @@ const C &bar3(bool coin) { // CHECK: Succs (1): B0 // CHECK: [B5] // CHECK: 1: [B8.3] || [B7.3] || [B6.7] +// CHECK: 2: (FullExprCleanup collected 1 MTEs) // CHECK: T: (Temp Dtor) [B6.4] // CHECK: Preds (3): B6 B7 B8 // CHECK: Succs (2): B4 B3 @@ -1397,6 +1428,7 @@ const C &bar3(bool coin) { // CHECK: Succs (1): B0 // CHECK: [B5] // CHECK: 1: [B8.3] || [B7.2] || [B6.7] +// CHECK: 2: (FullExprCleanup collected 1 MTEs) // CHECK: T: (Temp Dtor) [B6.4] // CHECK: Preds (3): B6 B7 B8 // CHECK: Succs (2): B4(Unreachable) B3 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
