From ff267df0de9664fa9af06987d455ae5f02425c3f Mon Sep 17 00:00:00 2001 From: Artem Dergachev Date: Thu, 28 Jun 2018 00:04:54 +0000 Subject: [PATCH] [CFG] [analyzer] Add construction contexts that explain pre-C++17 copy elision. Before C++17 copy elision was optional, even if the elidable copy/move constructor had arbitrary side effects. The elidable constructor is present in the AST, but marked as elidable. In these cases CFG now contains additional information that allows its clients to figure out if a temporary object is only being constructed so that to pass it to an elidable constructor. If so, it includes a reference to the elidable constructor's construction context, so that the client could elide the elidable constructor and construct the object directly at its final destination. Differential Revision: https://reviews.llvm.org/D47616 llvm-svn: 335795 --- clang/include/clang/Analysis/AnalysisDeclContext.h | 1 + clang/include/clang/Analysis/CFG.h | 1 + clang/include/clang/Analysis/ConstructionContext.h | 80 ++++++++++++++++--- .../clang/StaticAnalyzer/Core/AnalyzerOptions.h | 10 +++ clang/lib/Analysis/AnalysisDeclContext.cpp | 4 +- clang/lib/Analysis/CFG.cpp | 77 ++++++++++++------ clang/lib/Analysis/ConstructionContext.cpp | 56 +++++++++++++- clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp | 1 + clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp | 6 ++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 6 +- clang/test/Analysis/analyzer-config.c | 3 +- clang/test/Analysis/analyzer-config.cpp | 3 +- clang/test/Analysis/cfg-rich-constructors.cpp | 90 +++++++++++++++------- clang/test/Analysis/temp-obj-dtors-cfg-output.cpp | 34 ++++---- 14 files changed, 285 insertions(+), 87 deletions(-) diff --git a/clang/include/clang/Analysis/AnalysisDeclContext.h b/clang/include/clang/Analysis/AnalysisDeclContext.h index d6eb5e4..8c391b5 100644 --- a/clang/include/clang/Analysis/AnalysisDeclContext.h +++ b/clang/include/clang/Analysis/AnalysisDeclContext.h @@ -451,6 +451,7 @@ public: bool addStaticInitBranches = false, bool addCXXNewAllocator = true, bool addRichCXXConstructors = true, + bool markElidedCXXConstructors = true, CodeInjector *injector = nullptr); AnalysisDeclContext *getContext(const Decl *D); diff --git a/clang/include/clang/Analysis/CFG.h b/clang/include/clang/Analysis/CFG.h index 580cbd6..f257898 100644 --- a/clang/include/clang/Analysis/CFG.h +++ b/clang/include/clang/Analysis/CFG.h @@ -1025,6 +1025,7 @@ public: bool AddCXXNewAllocator = false; bool AddCXXDefaultInitExprInCtors = false; bool AddRichCXXConstructors = false; + bool MarkElidedCXXConstructors = false; BuildOptions() = default; diff --git a/clang/include/clang/Analysis/ConstructionContext.h b/clang/include/clang/Analysis/ConstructionContext.h index 8df95a8a..40cb0e7 100644 --- a/clang/include/clang/Analysis/ConstructionContext.h +++ b/clang/include/clang/Analysis/ConstructionContext.h @@ -107,7 +107,10 @@ public: INITIALIZER_BEGIN = SimpleConstructorInitializerKind, INITIALIZER_END = CXX17ElidedCopyConstructorInitializerKind, NewAllocatedObjectKind, - TemporaryObjectKind, + SimpleTemporaryObjectKind, + ElidedTemporaryObjectKind, + TEMPORARY_BEGIN = SimpleTemporaryObjectKind, + TEMPORARY_END = ElidedTemporaryObjectKind, SimpleReturnedValueKind, CXX17ElidedCopyReturnedValueKind, RETURNED_VALUE_BEGIN = SimpleReturnedValueKind, @@ -305,16 +308,15 @@ class TemporaryObjectConstructionContext : public ConstructionContext { const CXXBindTemporaryExpr *BTE; const MaterializeTemporaryExpr *MTE; - friend class ConstructionContext; // Allows to create<>() itself. - +protected: explicit TemporaryObjectConstructionContext( - const CXXBindTemporaryExpr *BTE, const MaterializeTemporaryExpr *MTE) - : ConstructionContext(ConstructionContext::TemporaryObjectKind), - BTE(BTE), MTE(MTE) { + ConstructionContext::Kind K, const CXXBindTemporaryExpr *BTE, + const MaterializeTemporaryExpr *MTE) + : ConstructionContext(K), BTE(BTE), MTE(MTE) { // Both BTE and MTE can be null here, all combinations possible. // Even though for now at least one should be non-null, we simply haven't - // implemented this case yet (this would be a temporary in the middle of - // nowhere that doesn't have a non-trivial destructor). + // implemented the other case yet (this would be a temporary in the middle + // of nowhere that doesn't have a non-trivial destructor). } public: @@ -334,7 +336,67 @@ public: } static bool classof(const ConstructionContext *CC) { - return CC->getKind() == TemporaryObjectKind; + return CC->getKind() >= TEMPORARY_BEGIN && CC->getKind() <= TEMPORARY_END; + } +}; + +/// Represents a temporary object that is not constructed for the purpose of +/// being immediately copied/moved by an elidable copy/move-constructor. +/// This includes temporary objects "in the middle of nowhere" like T(123) and +/// lifetime-extended temporaries. +class SimpleTemporaryObjectConstructionContext + : public TemporaryObjectConstructionContext { + friend class ConstructionContext; // Allows to create<>() itself. + + explicit SimpleTemporaryObjectConstructionContext( + const CXXBindTemporaryExpr *BTE, const MaterializeTemporaryExpr *MTE) + : TemporaryObjectConstructionContext( + ConstructionContext::SimpleTemporaryObjectKind, BTE, MTE) {} + +public: + static bool classof(const ConstructionContext *CC) { + return CC->getKind() == SimpleTemporaryObjectKind; + } +}; + +/// Represents a temporary object that is constructed for the sole purpose +/// of being immediately copied by an elidable copy/move constructor. +/// For example, T t = T(123); includes a temporary T(123) that is immediately +/// copied to variable t. In such cases the elidable copy can (but not +/// necessarily should) be omitted ("elided") accodring to the rules of the +/// language; the constructor would then construct variable t directly. +/// This construction context contains information of the elidable constructor +/// and its respective construction context. +class ElidedTemporaryObjectConstructionContext + : public TemporaryObjectConstructionContext { + const CXXConstructExpr *ElidedCE; + const ConstructionContext *ElidedCC; + + friend class ConstructionContext; // Allows to create<>() itself. + + explicit ElidedTemporaryObjectConstructionContext( + const CXXBindTemporaryExpr *BTE, const MaterializeTemporaryExpr *MTE, + const CXXConstructExpr *ElidedCE, const ConstructionContext *ElidedCC) + : TemporaryObjectConstructionContext( + ConstructionContext::ElidedTemporaryObjectKind, BTE, MTE), + ElidedCE(ElidedCE), ElidedCC(ElidedCC) { + // Elided constructor and its context should be either both specified + // or both unspecified. In the former case, the constructor must be + // elidable. + assert(ElidedCE && ElidedCE->isElidable() && ElidedCC); + } + +public: + const CXXConstructExpr *getConstructorAfterElision() const { + return ElidedCE; + } + + const ConstructionContext *getConstructionContextAfterElision() const { + return ElidedCC; + } + + static bool classof(const ConstructionContext *CC) { + return CC->getKind() == ElidedTemporaryObjectKind; } }; diff --git a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h index a3f4c38..367591a 100644 --- a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -327,6 +327,9 @@ private: /// \sa naiveCTUEnabled Optional NaiveCTU; + /// \sa shouldElideConstructors + Optional ElideConstructors; + /// A helper function that retrieves option for a given full-qualified /// checker name. @@ -703,6 +706,13 @@ public: /// This is an experimental feature to inline functions from another /// translation units. bool naiveCTUEnabled(); + + /// Returns true if elidable C++ copy-constructors and move-constructors + /// should be actually elided during analysis. Both behaviors are allowed + /// by the C++ standard, and the analyzer, like CodeGen, defaults to eliding. + /// Starting with C++17 some elisions become mandatory, and in these cases + /// the option will be ignored. + bool shouldElideConstructors(); }; using AnalyzerOptionsRef = IntrusiveRefCntPtr; diff --git a/clang/lib/Analysis/AnalysisDeclContext.cpp b/clang/lib/Analysis/AnalysisDeclContext.cpp index e746e8d..486fffb 100644 --- a/clang/lib/Analysis/AnalysisDeclContext.cpp +++ b/clang/lib/Analysis/AnalysisDeclContext.cpp @@ -71,7 +71,8 @@ AnalysisDeclContextManager::AnalysisDeclContextManager( bool addInitializers, bool addTemporaryDtors, bool addLifetime, bool addLoopExit, bool addScopes, bool synthesizeBodies, bool addStaticInitBranch, bool addCXXNewAllocator, - bool addRichCXXConstructors, CodeInjector *injector) + bool addRichCXXConstructors, bool markElidedCXXConstructors, + CodeInjector *injector) : Injector(injector), FunctionBodyFarm(ASTCtx, injector), SynthesizeBodies(synthesizeBodies) { cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG; @@ -84,6 +85,7 @@ AnalysisDeclContextManager::AnalysisDeclContextManager( cfgBuildOptions.AddStaticInitBranches = addStaticInitBranch; cfgBuildOptions.AddCXXNewAllocator = addCXXNewAllocator; cfgBuildOptions.AddRichCXXConstructors = addRichCXXConstructors; + cfgBuildOptions.MarkElidedCXXConstructors = markElidedCXXConstructors; } void AnalysisDeclContextManager::clear() { Contexts.clear(); } diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index b02fbe1..62803f4 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -1252,10 +1252,22 @@ void CFGBuilder::findConstructionContexts( if (!Child) return; + auto withExtraLayer = [this, Layer](Stmt *S) { + return ConstructionContextLayer::create(cfg->getBumpVectorContext(), S, + Layer); + }; + switch(Child->getStmtClass()) { case Stmt::CXXConstructExprClass: case Stmt::CXXTemporaryObjectExprClass: { - consumeConstructionContext(Layer, cast(Child)); + // Support pre-C++17 copy elision AST. + auto *CE = cast(Child); + if (BuildOpts.MarkElidedCXXConstructors && CE->isElidable()) { + assert(CE->getNumArgs() == 1); + findConstructionContexts(withExtraLayer(CE), CE->getArg(0)); + } + + consumeConstructionContext(Layer, CE); break; } // FIXME: This, like the main visit, doesn't support CUDAKernelCallExpr. @@ -1294,10 +1306,21 @@ void CFGBuilder::findConstructionContexts( } case Stmt::CXXBindTemporaryExprClass: { auto *BTE = cast(Child); - findConstructionContexts( - ConstructionContextLayer::create(cfg->getBumpVectorContext(), - BTE, Layer), - BTE->getSubExpr()); + findConstructionContexts(withExtraLayer(BTE), BTE->getSubExpr()); + break; + } + case Stmt::MaterializeTemporaryExprClass: { + // Normally we don't want to search in MaterializeTemporaryExpr because + // it indicates the beginning of a temporary object construction context, + // so it shouldn't be found in the middle. However, if it is the beginning + // of an elidable copy or move construction context, we need to include it. + if (const auto *CE = + dyn_cast_or_null(Layer->getTriggerStmt())) { + if (CE->isElidable()) { + auto *MTE = cast(Child); + findConstructionContexts(withExtraLayer(MTE), MTE->GetTemporaryExpr()); + } + } break; } case Stmt::ConditionalOperatorClass: { @@ -4931,7 +4954,7 @@ static void print_initializer(raw_ostream &OS, StmtPrinterHelper &Helper, static void print_construction_context(raw_ostream &OS, StmtPrinterHelper &Helper, const ConstructionContext *CC) { - const Stmt *S1 = nullptr, *S2 = nullptr; + SmallVector Stmts; switch (CC->getKind()) { case ConstructionContext::SimpleConstructorInitializerKind: { OS << ", "; @@ -4944,52 +4967,56 @@ static void print_construction_context(raw_ostream &OS, const auto *CICC = cast(CC); print_initializer(OS, Helper, CICC->getCXXCtorInitializer()); - S2 = CICC->getCXXBindTemporaryExpr(); + Stmts.push_back(CICC->getCXXBindTemporaryExpr()); break; } case ConstructionContext::SimpleVariableKind: { const auto *SDSCC = cast(CC); - S1 = SDSCC->getDeclStmt(); + Stmts.push_back(SDSCC->getDeclStmt()); break; } case ConstructionContext::CXX17ElidedCopyVariableKind: { const auto *CDSCC = cast(CC); - S1 = CDSCC->getDeclStmt(); - S2 = CDSCC->getCXXBindTemporaryExpr(); + Stmts.push_back(CDSCC->getDeclStmt()); + Stmts.push_back(CDSCC->getCXXBindTemporaryExpr()); break; } case ConstructionContext::NewAllocatedObjectKind: { const auto *NECC = cast(CC); - S1 = NECC->getCXXNewExpr(); + Stmts.push_back(NECC->getCXXNewExpr()); break; } case ConstructionContext::SimpleReturnedValueKind: { const auto *RSCC = cast(CC); - S1 = RSCC->getReturnStmt(); + Stmts.push_back(RSCC->getReturnStmt()); break; } case ConstructionContext::CXX17ElidedCopyReturnedValueKind: { const auto *RSCC = cast(CC); - S1 = RSCC->getReturnStmt(); - S2 = RSCC->getCXXBindTemporaryExpr(); + Stmts.push_back(RSCC->getReturnStmt()); + Stmts.push_back(RSCC->getCXXBindTemporaryExpr()); break; } - case ConstructionContext::TemporaryObjectKind: { - const auto *TOCC = cast(CC); - S1 = TOCC->getCXXBindTemporaryExpr(); - S2 = TOCC->getMaterializedTemporaryExpr(); + case ConstructionContext::SimpleTemporaryObjectKind: { + const auto *TOCC = cast(CC); + Stmts.push_back(TOCC->getCXXBindTemporaryExpr()); + Stmts.push_back(TOCC->getMaterializedTemporaryExpr()); break; } + case ConstructionContext::ElidedTemporaryObjectKind: { + const auto *TOCC = cast(CC); + Stmts.push_back(TOCC->getCXXBindTemporaryExpr()); + Stmts.push_back(TOCC->getMaterializedTemporaryExpr()); + Stmts.push_back(TOCC->getConstructorAfterElision()); + break; } - if (S1) { - OS << ", "; - Helper.handledStmt(const_cast(S1), OS); - } - if (S2) { - OS << ", "; - Helper.handledStmt(const_cast(S2), OS); } + for (auto I: Stmts) + if (I) { + OS << ", "; + Helper.handledStmt(const_cast(I), OS); + } } static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, diff --git a/clang/lib/Analysis/ConstructionContext.cpp b/clang/lib/Analysis/ConstructionContext.cpp index 9db6f21..de00375 100644 --- a/clang/lib/Analysis/ConstructionContext.cpp +++ b/clang/lib/Analysis/ConstructionContext.cpp @@ -61,7 +61,6 @@ const ConstructionContext *ConstructionContext::createFromLayers( // For temporaries with destructors, there may or may not be // lifetime extension on the parent layer. if (const ConstructionContextLayer *ParentLayer = TopLayer->getParent()) { - assert(ParentLayer->isLast()); // C++17 *requires* elision of the constructor at the return site // and at variable/member initialization site, while previous standards // were allowing an optional elidable constructor. @@ -77,8 +76,33 @@ const ConstructionContext *ConstructionContext::createFromLayers( // both destruction and materialization info attached to it in the AST. if ((MTE = dyn_cast( ParentLayer->getTriggerStmt()))) { - return create(C, BTE, MTE); + // Handle pre-C++17 copy and move elision. + const CXXConstructExpr *ElidedCE = nullptr; + const ConstructionContext *ElidedCC = nullptr; + if (const ConstructionContextLayer *ElidedLayer = + ParentLayer->getParent()) { + ElidedCE = cast(ElidedLayer->getTriggerStmt()); + assert(ElidedCE->isElidable()); + // We're creating a construction context that might have already + // been created elsewhere. Maybe we should unique our construction + // contexts. That's what we often do, but in this case it's unlikely + // to bring any benefits. + ElidedCC = createFromLayers(C, ElidedLayer->getParent()); + if (!ElidedCC) { + // We may fail to create the elided construction context. + // In this case, skip copy elision entirely. + return create(C, BTE, + MTE); + } else { + return create( + C, BTE, MTE, ElidedCE, ElidedCC); + } + } + assert(ParentLayer->isLast()); + return create(C, BTE, MTE); } + assert(ParentLayer->isLast()); + // This is a constructor into a function argument. Not implemented yet. if (isa(ParentLayer->getTriggerStmt())) return nullptr; @@ -99,7 +123,11 @@ const ConstructionContext *ConstructionContext::createFromLayers( llvm_unreachable("Unexpected construction context with destructor!"); } // A temporary object that doesn't require materialization. - return create(C, BTE, /*MTE=*/nullptr); + // In particular, it shouldn't require copy elision, because + // copy/move constructors take a reference, which requires + // materialization to obtain the glvalue. + return create(C, BTE, + /*MTE=*/nullptr); } if (const auto *MTE = dyn_cast(S)) { // If the object requires destruction and is not lifetime-extended, @@ -110,8 +138,28 @@ const ConstructionContext *ConstructionContext::createFromLayers( MTE->getStorageDuration() != SD_FullExpression)) return nullptr; + // Handle pre-C++17 copy and move elision. + const CXXConstructExpr *ElidedCE = nullptr; + const ConstructionContext *ElidedCC = nullptr; + if (const ConstructionContextLayer *ElidedLayer = TopLayer->getParent()) { + ElidedCE = cast(ElidedLayer->getTriggerStmt()); + assert(ElidedCE->isElidable()); + // We're creating a construction context that might have already + // been created elsewhere. Maybe we should unique our construction + // contexts. That's what we often do, but in this case it's unlikely + // to bring any benefits. + ElidedCC = createFromLayers(C, ElidedLayer->getParent()); + if (!ElidedCC) { + // We may fail to create the elided construction context. + // In this case, skip copy elision entirely. + return create(C, nullptr, + MTE); + } + return create( + C, nullptr, MTE, ElidedCE, ElidedCC); + } assert(TopLayer->isLast()); - return create(C, nullptr, MTE); + return create(C, nullptr, MTE); } if (const auto *RS = dyn_cast(S)) { assert(TopLayer->isLast()); diff --git a/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp index af107ab..dc0d3ec 100644 --- a/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp @@ -31,6 +31,7 @@ AnalysisManager::AnalysisManager( Options.shouldConditionalizeStaticInitializers(), /*addCXXNewAllocator=*/true, Options.includeRichConstructorsInCFG(), + Options.shouldElideConstructors(), injector), Ctx(ASTCtx), Diags(diags), LangOpts(lang), PathConsumers(PDC), CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr), diff --git a/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp index bddd443..6fa5fec 100644 --- a/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp +++ b/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp @@ -321,6 +321,12 @@ bool AnalyzerOptions::shouldSerializeStats() { /* Default = */ false); } +bool AnalyzerOptions::shouldElideConstructors() { + return getBooleanOption(ElideConstructors, + "elide-constructors", + /* Default = */ true); +} + int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal, const CheckerBase *C, bool SearchInParents) { diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index f85bfc6..497e1fa 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -209,7 +209,11 @@ std::pair ExprEngine::prepareForObjectConstruction( } llvm_unreachable("Unhandled return value construction context!"); } - case ConstructionContext::TemporaryObjectKind: { + case ConstructionContext::ElidedTemporaryObjectKind: + assert(AMgr.getAnalyzerOptions().shouldElideConstructors()); + // FALL-THROUGH + case ConstructionContext::SimpleTemporaryObjectKind: { + // TODO: Copy elision implementation goes here. const auto *TCC = cast(CC); const CXXBindTemporaryExpr *BTE = TCC->getCXXBindTemporaryExpr(); const MaterializeTemporaryExpr *MTE = TCC->getMaterializedTemporaryExpr(); diff --git a/clang/test/Analysis/analyzer-config.c b/clang/test/Analysis/analyzer-config.c index 40f86e1..2105a4f 100644 --- a/clang/test/Analysis/analyzer-config.c +++ b/clang/test/Analysis/analyzer-config.c @@ -18,6 +18,7 @@ void foo() { // CHECK-NEXT: cfg-rich-constructors = true // CHECK-NEXT: cfg-scopes = false // CHECK-NEXT: cfg-temporary-dtors = true +// CHECK-NEXT: elide-constructors = true // CHECK-NEXT: exploration_strategy = unexplored_first_queue // CHECK-NEXT: faux-bodies = true // CHECK-NEXT: graph-trim-interval = 1000 @@ -35,4 +36,4 @@ void foo() { // CHECK-NEXT: unroll-loops = false // CHECK-NEXT: widen-loops = false // CHECK-NEXT: [stats] -// CHECK-NEXT: num-entries = 23 +// CHECK-NEXT: num-entries = 24 diff --git a/clang/test/Analysis/analyzer-config.cpp b/clang/test/Analysis/analyzer-config.cpp index 888cd77..0eaefe2 100644 --- a/clang/test/Analysis/analyzer-config.cpp +++ b/clang/test/Analysis/analyzer-config.cpp @@ -32,6 +32,7 @@ public: // CHECK-NEXT: cfg-rich-constructors = true // CHECK-NEXT: cfg-scopes = false // CHECK-NEXT: cfg-temporary-dtors = true +// CHECK-NEXT: elide-constructors = true // CHECK-NEXT: experimental-enable-naive-ctu-analysis = false // CHECK-NEXT: exploration_strategy = unexplored_first_queue // CHECK-NEXT: faux-bodies = true @@ -50,4 +51,4 @@ public: // CHECK-NEXT: unroll-loops = false // CHECK-NEXT: widen-loops = false // CHECK-NEXT: [stats] -// CHECK-NEXT: num-entries = 30 +// CHECK-NEXT: num-entries = 31 diff --git a/clang/test/Analysis/cfg-rich-constructors.cpp b/clang/test/Analysis/cfg-rich-constructors.cpp index 42fe853..a07bdc7 100644 --- a/clang/test/Analysis/cfg-rich-constructors.cpp +++ b/clang/test/Analysis/cfg-rich-constructors.cpp @@ -1,7 +1,11 @@ // RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -triple x86_64-apple-darwin12 -std=c++11 -w %s > %t 2>&1 -// RUN: FileCheck --input-file=%t -check-prefixes=CHECK,CXX11 %s +// RUN: FileCheck --input-file=%t -check-prefixes=CHECK,CXX11,ELIDE,CXX11-ELIDE %s // RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -triple x86_64-apple-darwin12 -std=c++17 -w %s > %t 2>&1 -// RUN: FileCheck --input-file=%t -check-prefixes=CHECK,CXX17 %s +// RUN: FileCheck --input-file=%t -check-prefixes=CHECK,CXX17,ELIDE,CXX17-ELIDE %s +// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -triple x86_64-apple-darwin12 -std=c++11 -w -analyzer-config elide-constructors=false %s > %t 2>&1 +// RUN: FileCheck --input-file=%t -check-prefixes=CHECK,CXX11,NOELIDE,CXX11-NOELIDE %s +// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -triple x86_64-apple-darwin12 -std=c++17 -w -analyzer-config elide-constructors=false %s > %t 2>&1 +// RUN: FileCheck --input-file=%t -check-prefixes=CHECK,CXX17,NOELIDE,CXX17-NOELIDE %s class C { public: @@ -99,10 +103,12 @@ void simpleVariableWithOperatorNewInBraces() { // CHECK: void simpleVariableInitializedByValue() // CHECK: 1: C::get // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void)) -// CHECK-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.4]) +// 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], class C) // CXX11-NEXT: 6: C c = C::get(); +// CXX17-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.4]) // CXX17-NEXT: 4: C c = C::get(); void simpleVariableInitializedByValue() { C c = C::get(); @@ -122,17 +128,21 @@ void simpleVariableInitializedByValue() { // CHECK: [B2] // CHECK-NEXT: 1: C::get // CHECK-NEXT: 2: [B2.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void)) -// CXX11-NEXT: 3: [B2.2]() (CXXRecordTypedCall, [B2.4]) +// CXX11-ELIDE-NEXT: 3: [B2.2]() (CXXRecordTypedCall, [B2.4], [B2.5]) +// CXX11-NOELIDE-NEXT: 3: [B2.2]() (CXXRecordTypedCall, [B2.4]) // CXX11-NEXT: 4: [B2.3] -// CXX11-NEXT: 5: [B2.4] (CXXConstructExpr, [B1.2], class C) +// CXX11-ELIDE-NEXT: 5: [B2.4] (CXXConstructExpr, [B1.2], [B1.3], class C) +// CXX11-NOELIDE-NEXT: 5: [B2.4] (CXXConstructExpr, [B1.2], class C) // CXX17-NEXT: 3: [B2.2]() // CHECK: [B3] // CHECK-NEXT: 1: 0 // CHECK-NEXT: 2: [B3.1] (ImplicitCastExpr, NullToPointer, class C *) -// CXX11-NEXT: 3: [B3.2] (CXXConstructExpr, [B3.5], class C) +// CXX11-ELIDE-NEXT: 3: [B3.2] (CXXConstructExpr, [B3.5], [B3.6], class C) +// CXX11-NOELIDE-NEXT: 3: [B3.2] (CXXConstructExpr, [B3.5], class C) // CXX11-NEXT: 4: C([B3.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C) // CXX11-NEXT: 5: [B3.4] -// CXX11-NEXT: 6: [B3.5] (CXXConstructExpr, [B1.2], class C) +// CXX11-ELIDE-NEXT: 6: [B3.5] (CXXConstructExpr, [B1.2], [B1.3], class C) +// CXX11-NOELIDE-NEXT: 6: [B3.5] (CXXConstructExpr, [B1.2], class C) // CXX17-NEXT: 3: [B3.2] (CXXConstructExpr, class C) // CXX17-NEXT: 4: C([B3.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C) // CHECK: [B4] @@ -146,7 +156,9 @@ void simpleVariableWithTernaryOperator(bool coin) { // CHECK: void simpleVariableWithElidableCopy() // CHECK: 1: 0 // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, NullToPointer, class C *) -// CHECK-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.5], class C) +// CXX11-ELIDE-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.5], [B1.6], class C) +// CXX11-NOELIDE-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.5], class C) +// CXX17-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.5], class C) // CHECK-NEXT: 4: C([B1.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C) // CXX11-NEXT: 5: [B1.4] // CXX11-NEXT: 6: [B1.5] (CXXConstructExpr, [B1.7], class C) @@ -185,14 +197,16 @@ void referenceVariableWithInitializer() { // CHECK: [B2] // CHECK-NEXT: 1: C::get // CHECK-NEXT: 2: [B2.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void)) -// CXX11-NEXT: 3: [B2.2]() (CXXRecordTypedCall, [B2.4]) +// CXX11-ELIDE-NEXT: 3: [B2.2]() (CXXRecordTypedCall, [B2.4], [B2.5]) +// CXX11-NOELIDE-NEXT: 3: [B2.2]() (CXXRecordTypedCall, [B2.4]) // CXX11-NEXT: 4: [B2.3] // CXX11-NEXT: 5: [B2.4] (CXXConstructExpr, [B1.3], class C) // CXX17-NEXT: 3: [B2.2]() (CXXRecordTypedCall, [B1.3]) // CHECK: [B3] // CHECK-NEXT: 1: 0 // CHECK-NEXT: 2: [B3.1] (ImplicitCastExpr, NullToPointer, class C *) -// CXX11-NEXT: 3: [B3.2] (CXXConstructExpr, [B3.5], class C) +// CXX11-ELIDE-NEXT: 3: [B3.2] (CXXConstructExpr, [B3.5], [B3.6], class C) +// CXX11-NOELIDE-NEXT: 3: [B3.2] (CXXConstructExpr, [B3.5], class C) // CXX11-NEXT: 4: C([B3.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C) // CXX11-NEXT: 5: [B3.4] // CXX11-NEXT: 6: [B3.5] (CXXConstructExpr, [B1.3], class C) @@ -242,7 +256,8 @@ public: // CHECK-NEXT: 7: CFGNewAllocator(C *) // CHECK-NEXT: 8: C::get // CHECK-NEXT: 9: [B1.8] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void)) -// CXX11-NEXT: 10: [B1.9]() (CXXRecordTypedCall, [B1.11]) +// 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], class C) // CXX11-NEXT: 13: new C([B1.12]) @@ -270,7 +285,8 @@ public: // CHECK: F() // CHECK: 1: E::get // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class ctor_initializers::E (*)( -// CXX11-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.4], [B1.6]) +// CXX11-ELIDE-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.4], [B1.6], [B1.7]) +// CXX11-NOELIDE-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.4], [B1.6]) // CXX11-NEXT: 4: [B1.3] (BindTemporary) // CXX11-NEXT: 5: [B1.4] (ImplicitCastExpr, NoOp, const class ctor_initializers::E) // CXX11-NEXT: 6: [B1.5] @@ -326,10 +342,12 @@ C returnBracesWithMultipleItems() { } // CHECK: C returnTemporary() -// CHECK: 1: C() (CXXConstructExpr, [B1.2], class C) +// CXX11-ELIDE: 1: C() (CXXConstructExpr, [B1.2], [B1.3], class C) +// CXX11-NOELIDE: 1: C() (CXXConstructExpr, [B1.2], class C) // CXX11-NEXT: 2: [B1.1] // CXX11-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.4], class C) // CXX11-NEXT: 4: return [B1.3]; +// CXX17: 1: C() (CXXConstructExpr, [B1.2], class C) // CXX17-NEXT: 2: return [B1.1]; C returnTemporary() { return C(); @@ -338,7 +356,9 @@ C returnTemporary() { // CHECK: C returnTemporaryWithArgument() // CHECK: 1: nullptr // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, NullToPointer, class C *) -// CHECK-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.5], class C) +// CXX11-ELIDE-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.5], [B1.6], class C) +// CXX11-NOELIDE-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.5], class C) +// CXX17-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.5], class C) // CHECK-NEXT: 4: C([B1.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C) // CXX11-NEXT: 5: [B1.4] // CXX11-NEXT: 6: [B1.5] (CXXConstructExpr, [B1.7], class C) @@ -352,10 +372,12 @@ C returnTemporaryWithArgument() { // CHECK: C returnTemporaryConstructedByFunction() // CHECK: 1: C::get // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void)) -// CHECK-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.4]) +// 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], class C) // CXX11-NEXT: 6: return [B1.5]; +// CXX17-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.4]) // CXX17-NEXT: 4: return [B1.3]; C returnTemporaryConstructedByFunction() { return C::get(); @@ -364,9 +386,11 @@ C returnTemporaryConstructedByFunction() { // CHECK: C returnChainOfCopies() // CHECK: 1: C::get // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void)) -// CXX11-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.4]) +// 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.7], class C) +// CXX11-ELIDE-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.7], [B1.8], class C) +// CXX11-NOELIDE-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.7], class C) // CXX11-NEXT: 6: C([B1.5]) (CXXFunctionalCastExpr, ConstructorConversion, class C) // CXX11-NEXT: 7: [B1.6] // CXX11-NEXT: 8: [B1.7] (CXXConstructExpr, [B1.9], class C) @@ -390,7 +414,8 @@ public: // FIXME: There should be no temporary destructor in C++17. // CHECK: return_stmt_with_dtor::D returnTemporary() -// CXX11: 1: return_stmt_with_dtor::D() (CXXConstructExpr, [B1.2], [B1.4], class return_stmt_with_dtor::D) +// CXX11-ELIDE: 1: return_stmt_with_dtor::D() (CXXConstructExpr, [B1.2], [B1.4], [B1.5], class return_stmt_with_dtor::D) +// CXX11-NOELIDE: 1: return_stmt_with_dtor::D() (CXXConstructExpr, [B1.2], [B1.4], class return_stmt_with_dtor::D) // CXX11-NEXT: 2: [B1.1] (BindTemporary) // CXX11-NEXT: 3: [B1.2] (ImplicitCastExpr, NoOp, const class return_stmt_with_dtor::D) // CXX11-NEXT: 4: [B1.3] @@ -409,7 +434,8 @@ D returnTemporary() { // CHECK: void returnByValueIntoVariable() // CHECK: 1: returnTemporary // CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class return_stmt_with_dtor::D (*)(void)) -// CXX11-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.4], [B1.6]) +// CXX11-ELIDE-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.4], [B1.6], [B1.7]) +// CXX11-NOELIDE-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.4], [B1.6]) // CXX11-NEXT: 4: [B1.3] (BindTemporary) // CXX11-NEXT: 5: [B1.4] (ImplicitCastExpr, NoOp, const class return_stmt_with_dtor::D) // CXX11-NEXT: 6: [B1.5] @@ -451,7 +477,8 @@ void temporaryInCondition() { } // CHECK: void temporaryInConditionVariable() -// CHECK: 1: C() (CXXConstructExpr, [B2.2], class C) +// CXX11-ELIDE: 1: C() (CXXConstructExpr, [B2.2], [B2.3], class C) +// CXX11-NOELIDE: 1: C() (CXXConstructExpr, [B2.2], class C) // CXX11-NEXT: 2: [B2.1] // CXX11-NEXT: 3: [B2.2] (CXXConstructExpr, [B2.4], class C) // CXX11-NEXT: 4: C c = C(); @@ -461,6 +488,7 @@ void temporaryInCondition() { // CXX11-NEXT: 8: [B2.6] // CXX11-NEXT: 9: [B2.8] (ImplicitCastExpr, UserDefinedConversion, _Bool) // CXX11-NEXT: T: if [B2.9] +// CXX17: 1: C() (CXXConstructExpr, [B2.2], class C) // CXX17-NEXT: 2: C c = C(); // CXX17-NEXT: 3: c // CXX17-NEXT: 4: [B2.3] (ImplicitCastExpr, NoOp, const class C) @@ -475,7 +503,8 @@ void temporaryInConditionVariable() { // CHECK: void temporaryInForLoopConditionVariable() // CHECK: [B2] -// CXX11-NEXT: 1: C() (CXXConstructExpr, [B2.2], class C) +// CXX11-ELIDE-NEXT: 1: C() (CXXConstructExpr, [B2.2], [B2.3], class C) +// CXX11-NOELIDE-NEXT: 1: C() (CXXConstructExpr, [B2.2], class C) // CXX11-NEXT: 2: [B2.1] // CXX11-NEXT: 3: [B2.2] (CXXConstructExpr, [B2.4], class C) // CXX11-NEXT: 4: C c2 = C(); @@ -494,7 +523,8 @@ void temporaryInConditionVariable() { // CXX17-NEXT: 7: [B2.6] (ImplicitCastExpr, UserDefinedConversion, _Bool) // CXX17-NEXT: T: for (...; [B2.7]; ) // CHECK: [B3] -// CXX11-NEXT: 1: C() (CXXConstructExpr, [B3.2], class C) +// CXX11-ELIDE-NEXT: 1: C() (CXXConstructExpr, [B3.2], [B3.3], class C) +// CXX11-NOELIDE-NEXT: 1: C() (CXXConstructExpr, [B3.2], class C) // CXX11-NEXT: 2: [B3.1] // CXX11-NEXT: 3: [B3.2] (CXXConstructExpr, [B3.4], class C) // CXX11-NEXT: 4: C c1 = C(); @@ -505,9 +535,9 @@ void temporaryInForLoopConditionVariable() { } -// FIXME: Find construction context for the loop condition variable. // CHECK: void temporaryInWhileLoopConditionVariable() -// CXX11: 1: C() (CXXConstructExpr, [B2.2], class C) +// CXX11-ELIDE: 1: C() (CXXConstructExpr, [B2.2], [B2.3], class C) +// CXX11-NOELIDE: 1: C() (CXXConstructExpr, [B2.2], class C) // CXX11-NEXT: 2: [B2.1] // CXX11-NEXT: 3: [B2.2] (CXXConstructExpr, [B2.4], class C) // CXX11-NEXT: 4: C c = C(); @@ -603,7 +633,8 @@ void referenceVariableWithInitializer() { // CXX11: [B5] // CXX11-NEXT: 1: D::get // CXX11-NEXT: 2: [B5.1] (ImplicitCastExpr, FunctionToPointerDecay, class temporary_object_expr_with_dtors::D (*)(void)) -// CXX11-NEXT: 3: [B5.2]() (CXXRecordTypedCall, [B5.4], [B5.6]) +// CXX11-ELIDE-NEXT: 3: [B5.2]() (CXXRecordTypedCall, [B5.4], [B5.6], [B5.7]) +// CXX11-NOELIDE-NEXT: 3: [B5.2]() (CXXRecordTypedCall, [B5.4], [B5.6]) // CXX11-NEXT: 4: [B5.3] (BindTemporary) // CXX11-NEXT: 5: [B5.4] (ImplicitCastExpr, NoOp, const class temporary_object_expr_with_dtors::D) // CXX11-NEXT: 6: [B5.5] @@ -611,7 +642,8 @@ void referenceVariableWithInitializer() { // CXX11-NEXT: 8: [B5.7] (BindTemporary) // CXX11: [B6] // CXX11-NEXT: 1: 0 -// CXX11-NEXT: 2: [B6.1] (CXXConstructExpr, [B6.3], [B6.6], class temporary_object_expr_with_dtors::D) +// CXX11-ELIDE-NEXT: 2: [B6.1] (CXXConstructExpr, [B6.3], [B6.6], [B6.7], class temporary_object_expr_with_dtors::D) +// CXX11-NOELIDE-NEXT: 2: [B6.1] (CXXConstructExpr, [B6.3], [B6.6], class temporary_object_expr_with_dtors::D) // CXX11-NEXT: 3: [B6.2] (BindTemporary) // CXX11-NEXT: 4: temporary_object_expr_with_dtors::D([B6.3]) (CXXFunctionalCastExpr, ConstructorConversion, class temporary_object_expr_with_dtors::D) // CXX11-NEXT: 5: [B6.4] (ImplicitCastExpr, NoOp, const class temporary_object_expr_with_dtors::D) @@ -699,7 +731,8 @@ public: // CHECK: 1: implicit_constructor_conversion::A() (CXXConstructExpr, [B1.3], class implicit_constructor_conversion::A) // CXX11-NEXT: 2: [B1.1] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::A) // CXX11-NEXT: 3: [B1.2] -// CXX11-NEXT: 4: [B1.3] (CXXConstructExpr, [B1.6], [B1.8], class implicit_constructor_conversion::B) +// CXX11-ELIDE-NEXT: 4: [B1.3] (CXXConstructExpr, [B1.6], [B1.8], [B1.9], class implicit_constructor_conversion::B) +// CXX11-NOELIDE-NEXT: 4: [B1.3] (CXXConstructExpr, [B1.6], [B1.8], class implicit_constructor_conversion::B) // CXX11-NEXT: 5: [B1.4] (ImplicitCastExpr, ConstructorConversion, class implicit_constructor_conversion::B) // CXX11-NEXT: 6: [B1.5] (BindTemporary) // CXX11-NEXT: 7: [B1.6] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::B) @@ -724,7 +757,8 @@ void implicitConstructionConversionFromTemporary() { // CHECK-NEXT: 3: [B1.2]() (CXXRecordTypedCall, [B1.5]) // CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::A) // CHECK-NEXT: 5: [B1.4] -// CXX11-NEXT: 6: [B1.5] (CXXConstructExpr, [B1.8], [B1.10], class implicit_constructor_conversion::B) +// CXX11-ELIDE-NEXT: 6: [B1.5] (CXXConstructExpr, [B1.8], [B1.10], [B1.11], class implicit_constructor_conversion::B) +// CXX11-NOELIDE-NEXT: 6: [B1.5] (CXXConstructExpr, [B1.8], [B1.10], class implicit_constructor_conversion::B) // CXX11-NEXT: 7: [B1.6] (ImplicitCastExpr, ConstructorConversion, class implicit_constructor_conversion::B) // CXX11-NEXT: 8: [B1.7] (BindTemporary) // CXX11-NEXT: 9: [B1.8] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::B) diff --git a/clang/test/Analysis/temp-obj-dtors-cfg-output.cpp b/clang/test/Analysis/temp-obj-dtors-cfg-output.cpp index 29d327e..a0e5015 100644 --- a/clang/test/Analysis/temp-obj-dtors-cfg-output.cpp +++ b/clang/test/Analysis/temp-obj-dtors-cfg-output.cpp @@ -235,7 +235,7 @@ const C &bar3(bool coin) { // CHECK: Succs (1): B1 // CHECK: [B1] // WARNINGS: 1: A() (CXXConstructExpr, class A) -// ANALYZER: 1: A() (CXXConstructExpr, [B1.2], [B1.4], class A) +// ANALYZER: 1: A() (CXXConstructExpr, [B1.2], [B1.4], [B1.5], class A) // CHECK: 2: [B1.1] (BindTemporary) // CHECK: 3: [B1.2] (ImplicitCastExpr, NoOp, const class A) // CHECK: 4: [B1.3] @@ -295,7 +295,7 @@ const C &bar3(bool coin) { // CHECK: Succs (1): B1 // CHECK: [B1] // WARNINGS: 1: A() (CXXConstructExpr, class A) -// ANALYZER: 1: A() (CXXConstructExpr, [B1.2], [B1.4], class A) +// ANALYZER: 1: A() (CXXConstructExpr, [B1.2], [B1.4], [B1.5], class A) // CHECK: 2: [B1.1] (BindTemporary) // CHECK: 3: [B1.2] (ImplicitCastExpr, NoOp, const class A) // CHECK: 4: [B1.3] @@ -550,12 +550,12 @@ const C &bar3(bool coin) { // CHECK: Succs (2): B6 B5 // CHECK: [B8] // WARNINGS: 1: A() (CXXConstructExpr, class A) -// ANALYZER: 1: A() (CXXConstructExpr, [B8.2], [B8.4], class A) +// ANALYZER: 1: A() (CXXConstructExpr, [B8.2], [B8.4], [B8.5], class A) // CHECK: 2: [B8.1] (BindTemporary) // CHECK: 3: [B8.2] (ImplicitCastExpr, NoOp, const class A) // CHECK: 4: [B8.3] // WARNINGS: 5: [B8.4] (CXXConstructExpr, class A) -// ANALYZER: 5: [B8.4] (CXXConstructExpr, [B8.6], [B7.3], class A) +// ANALYZER: 5: [B8.4] (CXXConstructExpr, [B8.6], [B7.3], [B7.4], class A) // CHECK: 6: [B8.5] (BindTemporary) // CHECK: Preds (1): B10 // CHECK: Succs (1): B7 @@ -570,13 +570,13 @@ const C &bar3(bool coin) { // CHECK: 7: [B9.6] (ImplicitCastExpr, NoOp, const class A) // CHECK: 8: [B9.7] // WARNINGS: 9: [B9.8] (CXXConstructExpr, class A) -// ANALYZER: 9: [B9.8] (CXXConstructExpr, [B9.10], [B9.13], class A) +// ANALYZER: 9: [B9.8] (CXXConstructExpr, [B9.10], [B9.13], [B9.14], class A) // CHECK: 10: [B9.9] (BindTemporary) // CHECK: 11: A([B9.10]) (CXXFunctionalCastExpr, ConstructorConversion, class A) // CHECK: 12: [B9.11] (ImplicitCastExpr, NoOp, const class A) // CHECK: 13: [B9.12] // WARNINGS: 14: [B9.13] (CXXConstructExpr, class A) -// ANALYZER: 14: [B9.13] (CXXConstructExpr, [B9.15], [B7.3], class A) +// ANALYZER: 14: [B9.13] (CXXConstructExpr, [B9.15], [B7.3], [B7.4], class A) // CHECK: 15: [B9.14] (BindTemporary) // CHECK: Preds (1): B10 // CHECK: Succs (1): B7 @@ -680,7 +680,7 @@ const C &bar3(bool coin) { // CHECK: Succs (1): B0 // CHECK: [B4] // WARNINGS: 1: C() (CXXConstructExpr, struct C) -// ANALYZER: 1: C() (CXXConstructExpr, [B4.2], [B4.4], struct C) +// ANALYZER: 1: C() (CXXConstructExpr, [B4.2], [B4.4], [B4.5], struct C) // CHECK: 2: [B4.1] (BindTemporary) // CHECK: 3: [B4.2] (ImplicitCastExpr, NoOp, const struct C) // CHECK: 4: [B4.3] @@ -733,7 +733,7 @@ const C &bar3(bool coin) { // CHECK: Succs (1): B0 // CHECK: [B3] // CXX98-WARNINGS: 1: D() (CXXConstructExpr, struct D) -// CXX98-ANALYZER: 1: D() (CXXConstructExpr, [B3.3], struct D) +// CXX98-ANALYZER: 1: D() (CXXConstructExpr, [B3.3], [B3.4], struct D) // CXX98: 2: [B3.1] (ImplicitCastExpr, NoOp, const struct D) // CXX98: 3: [B3.2] // CXX98-WARNINGS: 4: [B3.3] (CXXConstructExpr, struct D) @@ -745,7 +745,7 @@ const C &bar3(bool coin) { // CXX98: 9: [B3.8] (ImplicitCastExpr, UserDefinedConversion, _Bool) // CXX98: T: if [B3.9] // CXX11-WARNINGS: 1: D() (CXXConstructExpr, struct D) -// CXX11-ANALYZER: 1: D() (CXXConstructExpr, [B3.2], struct D) +// CXX11-ANALYZER: 1: D() (CXXConstructExpr, [B3.2], [B3.3], struct D) // CXX11: 2: [B3.1] // CXX11-WARNINGS: 3: [B3.2] (CXXConstructExpr, struct D) // CXX11-ANALYZER: 3: [B3.2] (CXXConstructExpr, [B3.4], struct D) @@ -789,7 +789,7 @@ const C &bar3(bool coin) { // CHECK: Succs (2): B3 B2 // CHECK: [B5] // WARNINGS: 1: A() (CXXConstructExpr, class A) -// ANALYZER: 1: A() (CXXConstructExpr, [B5.2], [B5.4], class A) +// ANALYZER: 1: A() (CXXConstructExpr, [B5.2], [B5.4], [B5.5], class A) // CHECK: 2: [B5.1] (BindTemporary) // CHECK: 3: [B5.2] (ImplicitCastExpr, NoOp, const class A) // CHECK: 4: [B5.3] @@ -809,7 +809,7 @@ const C &bar3(bool coin) { // CHECK: 7: [B6.6] (ImplicitCastExpr, NoOp, const class A) // CHECK: 8: [B6.7] // WARNINGS: 9: [B6.8] (CXXConstructExpr, class A) -// ANALYZER: 9: [B6.8] (CXXConstructExpr, [B6.10], [B6.13], class A) +// ANALYZER: 9: [B6.8] (CXXConstructExpr, [B6.10], [B6.13], [B6.14], class A) // CHECK: 10: [B6.9] (BindTemporary) // CHECK: 11: A([B6.10]) (CXXFunctionalCastExpr, ConstructorConversion, class A) // CHECK: 12: [B6.11] (ImplicitCastExpr, NoOp, const class A) @@ -852,7 +852,7 @@ const C &bar3(bool coin) { // CHECK: Succs (2): B9 B8 // CHECK: [B11] // WARNINGS: 1: A() (CXXConstructExpr, class A) -// ANALYZER: 1: A() (CXXConstructExpr, [B11.2], [B11.4], class A) +// ANALYZER: 1: A() (CXXConstructExpr, [B11.2], [B11.4], [B11.5], class A) // CHECK: 2: [B11.1] (BindTemporary) // CHECK: 3: [B11.2] (ImplicitCastExpr, NoOp, const class A) // CHECK: 4: [B11.3] @@ -872,7 +872,7 @@ const C &bar3(bool coin) { // CHECK: 7: [B12.6] (ImplicitCastExpr, NoOp, const class A) // CHECK: 8: [B12.7] // WARNINGS: 9: [B12.8] (CXXConstructExpr, class A) -// ANALYZER: 9: [B12.8] (CXXConstructExpr, [B12.10], [B12.13], class A) +// ANALYZER: 9: [B12.8] (CXXConstructExpr, [B12.10], [B12.13], [B12.14], class A) // CHECK: 10: [B12.9] (BindTemporary) // CHECK: 11: A([B12.10]) (CXXFunctionalCastExpr, ConstructorConversion, class A) // CHECK: 12: [B12.11] (ImplicitCastExpr, NoOp, const class A) @@ -935,7 +935,7 @@ const C &bar3(bool coin) { // CHECK: Succs (1): B4 // CHECK: [B6] // WARNINGS: 1: A() (CXXConstructExpr, class A) -// ANALYZER: 1: A() (CXXConstructExpr, [B6.2], [B6.4], class A) +// ANALYZER: 1: A() (CXXConstructExpr, [B6.2], [B6.4], [B6.5], class A) // CHECK: 2: [B6.1] (BindTemporary) // CHECK: 3: [B6.2] (ImplicitCastExpr, NoOp, const class A) // CHECK: 4: [B6.3] @@ -1001,7 +1001,7 @@ const C &bar3(bool coin) { // CHECK: Succs (1): B4 // CHECK: [B6] // WARNINGS: 1: A() (CXXConstructExpr, class A) -// ANALYZER: 1: A() (CXXConstructExpr, [B6.2], [B6.4], class A) +// ANALYZER: 1: A() (CXXConstructExpr, [B6.2], [B6.4], [B6.5], class A) // CHECK: 2: [B6.1] (BindTemporary) // CHECK: 3: [B6.2] (ImplicitCastExpr, NoOp, const class A) // CHECK: 4: [B6.3] @@ -1086,7 +1086,7 @@ const C &bar3(bool coin) { // CHECK: Succs (1): B1 // CHECK: [B1] // WARNINGS: 1: A() (CXXConstructExpr, class A) -// ANALYZER: 1: A() (CXXConstructExpr, [B1.2], [B1.4], class A) +// ANALYZER: 1: A() (CXXConstructExpr, [B1.2], [B1.4], [B1.5], class A) // CHECK: 2: [B1.1] (BindTemporary) // CHECK: 3: [B1.2] (ImplicitCastExpr, NoOp, const class A) // CHECK: 4: [B1.3] @@ -1130,7 +1130,7 @@ const C &bar3(bool coin) { // CHECK: 1: A::make // CHECK: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class A (*)(void)) // WARNINGS: 3: [B1.2]() -// ANALYZER: 3: [B1.2]() (CXXRecordTypedCall, [B1.4], [B1.6]) +// ANALYZER: 3: [B1.2]() (CXXRecordTypedCall, [B1.4], [B1.6], [B1.7]) // CHECK: 4: [B1.3] (BindTemporary) // CHECK: 5: [B1.4] (ImplicitCastExpr, NoOp, const class A) // CHECK: 6: [B1.5] -- 2.7.4