summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Analysis/AnalysisDeclContext.h1
-rw-r--r--clang/include/clang/Analysis/CFG.h1
-rw-r--r--clang/include/clang/Analysis/ConstructionContext.h80
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h10
-rw-r--r--clang/lib/Analysis/AnalysisDeclContext.cpp4
-rw-r--r--clang/lib/Analysis/CFG.cpp77
-rw-r--r--clang/lib/Analysis/ConstructionContext.cpp56
-rw-r--r--clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp1
-rw-r--r--clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp6
-rw-r--r--clang/test/Analysis/analyzer-config.c3
-rw-r--r--clang/test/Analysis/analyzer-config.cpp3
-rw-r--r--clang/test/Analysis/cfg-rich-constructors.cpp90
-rw-r--r--clang/test/Analysis/temp-obj-dtors-cfg-output.cpp34
14 files changed, 285 insertions, 87 deletions
diff --git a/clang/include/clang/Analysis/AnalysisDeclContext.h b/clang/include/clang/Analysis/AnalysisDeclContext.h
index d6eb5e4d5f0..8c391b5ee1e 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 580cbd6ee3e..f25789822d1 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 8df95a8ada2..40cb0e7e5dd 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 a3f4c389441..367591ae1f6 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<bool> NaiveCTU;
+ /// \sa shouldElideConstructors
+ Optional<bool> 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<AnalyzerOptions>;
diff --git a/clang/lib/Analysis/AnalysisDeclContext.cpp b/clang/lib/Analysis/AnalysisDeclContext.cpp
index e746e8dfa53..486fffbe129 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 b02fbe10712..62803f4ba56 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<CXXConstructExpr>(Child));
+ // Support pre-C++17 copy elision AST.
+ auto *CE = cast<CXXConstructExpr>(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<CXXBindTemporaryExpr>(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<CXXConstructExpr>(Layer->getTriggerStmt())) {
+ if (CE->isElidable()) {
+ auto *MTE = cast<MaterializeTemporaryExpr>(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<const Stmt *, 3> Stmts;
switch (CC->getKind()) {
case ConstructionContext::SimpleConstructorInitializerKind: {
OS << ", ";
@@ -4944,52 +4967,56 @@ static void print_construction_context(raw_ostream &OS,
const auto *CICC =
cast<CXX17ElidedCopyConstructorInitializerConstructionContext>(CC);
print_initializer(OS, Helper, CICC->getCXXCtorInitializer());
- S2 = CICC->getCXXBindTemporaryExpr();
+ Stmts.push_back(CICC->getCXXBindTemporaryExpr());
break;
}
case ConstructionContext::SimpleVariableKind: {
const auto *SDSCC = cast<SimpleVariableConstructionContext>(CC);
- S1 = SDSCC->getDeclStmt();
+ Stmts.push_back(SDSCC->getDeclStmt());
break;
}
case ConstructionContext::CXX17ElidedCopyVariableKind: {
const auto *CDSCC = cast<CXX17ElidedCopyVariableConstructionContext>(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<NewAllocatedObjectConstructionContext>(CC);
- S1 = NECC->getCXXNewExpr();
+ Stmts.push_back(NECC->getCXXNewExpr());
break;
}
case ConstructionContext::SimpleReturnedValueKind: {
const auto *RSCC = cast<SimpleReturnedValueConstructionContext>(CC);
- S1 = RSCC->getReturnStmt();
+ Stmts.push_back(RSCC->getReturnStmt());
break;
}
case ConstructionContext::CXX17ElidedCopyReturnedValueKind: {
const auto *RSCC =
cast<CXX17ElidedCopyReturnedValueConstructionContext>(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<TemporaryObjectConstructionContext>(CC);
- S1 = TOCC->getCXXBindTemporaryExpr();
- S2 = TOCC->getMaterializedTemporaryExpr();
+ case ConstructionContext::SimpleTemporaryObjectKind: {
+ const auto *TOCC = cast<SimpleTemporaryObjectConstructionContext>(CC);
+ Stmts.push_back(TOCC->getCXXBindTemporaryExpr());
+ Stmts.push_back(TOCC->getMaterializedTemporaryExpr());
break;
}
+ case ConstructionContext::ElidedTemporaryObjectKind: {
+ const auto *TOCC = cast<ElidedTemporaryObjectConstructionContext>(CC);
+ Stmts.push_back(TOCC->getCXXBindTemporaryExpr());
+ Stmts.push_back(TOCC->getMaterializedTemporaryExpr());
+ Stmts.push_back(TOCC->getConstructorAfterElision());
+ break;
}
- if (S1) {
- OS << ", ";
- Helper.handledStmt(const_cast<Stmt *>(S1), OS);
- }
- if (S2) {
- OS << ", ";
- Helper.handledStmt(const_cast<Stmt *>(S2), OS);
}
+ for (auto I: Stmts)
+ if (I) {
+ OS << ", ";
+ Helper.handledStmt(const_cast<Stmt *>(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 9db6f214bee..de003753367 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<MaterializeTemporaryExpr>(
ParentLayer->getTriggerStmt()))) {
- return create<TemporaryObjectConstructionContext>(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<CXXConstructExpr>(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<SimpleTemporaryObjectConstructionContext>(C, BTE,
+ MTE);
+ } else {
+ return create<ElidedTemporaryObjectConstructionContext>(
+ C, BTE, MTE, ElidedCE, ElidedCC);
+ }
+ }
+ assert(ParentLayer->isLast());
+ return create<SimpleTemporaryObjectConstructionContext>(C, BTE, MTE);
}
+ assert(ParentLayer->isLast());
+
// This is a constructor into a function argument. Not implemented yet.
if (isa<CallExpr>(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<TemporaryObjectConstructionContext>(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<SimpleTemporaryObjectConstructionContext>(C, BTE,
+ /*MTE=*/nullptr);
}
if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(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<CXXConstructExpr>(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<SimpleTemporaryObjectConstructionContext>(C, nullptr,
+ MTE);
+ }
+ return create<ElidedTemporaryObjectConstructionContext>(
+ C, nullptr, MTE, ElidedCE, ElidedCC);
+ }
assert(TopLayer->isLast());
- return create<TemporaryObjectConstructionContext>(C, nullptr, MTE);
+ return create<SimpleTemporaryObjectConstructionContext>(C, nullptr, MTE);
}
if (const auto *RS = dyn_cast<ReturnStmt>(S)) {
assert(TopLayer->isLast());
diff --git a/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp
index af107ab224f..dc0d3ec8493 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 bddd4435a75..6fa5fec5288 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 f85bfc6e492..497e1fa5560 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -209,7 +209,11 @@ std::pair<ProgramStateRef, SVal> 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<TemporaryObjectConstructionContext>(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 40f86e1504d..2105a4faf4c 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 888cd77eef0..0eaefe2abf2 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 42fe8539a4e..a07bdc7b87f 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 29d327e3835..a0e50155356 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]
OpenPOWER on IntegriCloud