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