r328248 - [CFG] [analyzer] Add C++17-specific variable and return construction contexts.

Artem Dergachev via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 22 14:37:39 PDT 2018


Author: dergachev
Date: Thu Mar 22 14:37:39 2018
New Revision: 328248

URL: http://llvm.org/viewvc/llvm-project?rev=328248&view=rev
Log:
[CFG] [analyzer] Add C++17-specific variable and return construction contexts.

In C++17 copy elision is mandatory for variable and return value constructors
(as long as it doesn't involve type conversion) which results in AST that does
not contain elidable constructors in their usual places. In order to provide
construction contexts in this scenario we need to cover more AST patterns.

This patch makes the CFG prepared for these scenarios by:

- Fork VariableConstructionContext and ReturnedValueConstructionContext into
  two different sub-classes (each) one of which indicates the C++17 case and
  contains a reference to an extra CXXBindTemporaryExpr.
- Allow CFGCXXRecordTypedCall element to accept VariableConstructionContext and
  ReturnedValueConstructionContext as its context.

Differential Revision: https://reviews.llvm.org/D44597

Modified:
    cfe/trunk/include/clang/Analysis/CFG.h
    cfe/trunk/include/clang/Analysis/ConstructionContext.h
    cfe/trunk/lib/Analysis/CFG.cpp
    cfe/trunk/lib/Analysis/ConstructionContext.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
    cfe/trunk/test/Analysis/cfg-rich-constructors.cpp

Modified: cfe/trunk/include/clang/Analysis/CFG.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/CFG.h?rev=328248&r1=328247&r2=328248&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/CFG.h (original)
+++ cfe/trunk/include/clang/Analysis/CFG.h Thu Mar 22 14:37:39 2018
@@ -17,6 +17,7 @@
 
 #include "clang/AST/ExprCXX.h"
 #include "clang/Analysis/Support/BumpVector.h"
+#include "clang/Analysis/ConstructionContext.h"
 #include "clang/Basic/LLVM.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/GraphTraits.h"
@@ -38,8 +39,6 @@ namespace clang {
 class ASTContext;
 class BinaryOperator;
 class CFG;
-class ConstructionContext;
-class TemporaryObjectConstructionContext;
 class CXXBaseSpecifier;
 class CXXBindTemporaryExpr;
 class CXXCtorInitializer;
@@ -171,14 +170,11 @@ private:
 };
 
 /// CFGCXXRecordTypedCall - Represents a function call that returns a C++ object
-/// by value. This, like constructor, requires a construction context, which
-/// will always be that of a temporary object - usually consumed by an elidable
-/// constructor. For such value-typed calls the ReturnedValueConstructionContext
-/// of their return value is naturally complemented by the
-/// TemporaryObjectConstructionContext at the call site (here). In C such
-/// tracking is not necessary because no additional effort is required for
-/// destroying the object or modeling copy elision. Like CFGConstructor, this is
-/// for now only used by the analyzer's CFG.
+/// by value. This, like constructor, requires a construction context in order
+/// to understand the storage of the returned object . In C such tracking is not
+/// necessary because no additional effort is required for destroying the object
+/// or modeling copy elision. Like CFGConstructor, this element is for now only
+/// used by the analyzer's CFG.
 class CFGCXXRecordTypedCall : public CFGStmt {
 public:
   /// Returns true when call expression \p CE needs to be represented
@@ -187,19 +183,19 @@ public:
     return CE->getCallReturnType(ACtx).getCanonicalType()->getAsCXXRecordDecl();
   }
 
-  explicit CFGCXXRecordTypedCall(CallExpr *CE,
-                                 const TemporaryObjectConstructionContext *C)
+  explicit CFGCXXRecordTypedCall(CallExpr *CE, const ConstructionContext *C)
       : CFGStmt(CE, CXXRecordTypedCall) {
     // FIXME: This is not protected against squeezing a non-record-typed-call
     // into the constructor. An assertion would require passing an ASTContext
     // which would mean paying for something we don't use.
-    assert(C);
-    Data2.setPointer(const_cast<TemporaryObjectConstructionContext *>(C));
+    assert(C && (isa<TemporaryObjectConstructionContext>(C) ||
+                 isa<ReturnedValueConstructionContext>(C) ||
+                 isa<VariableConstructionContext>(C)));
+    Data2.setPointer(const_cast<ConstructionContext *>(C));
   }
 
-  const TemporaryObjectConstructionContext *getConstructionContext() const {
-    return static_cast<TemporaryObjectConstructionContext *>(
-        Data2.getPointer());
+  const ConstructionContext *getConstructionContext() const {
+    return static_cast<ConstructionContext *>(Data2.getPointer());
   }
 
 private:
@@ -881,7 +877,7 @@ public:
   }
 
   void appendCXXRecordTypedCall(CallExpr *CE,
-                                const TemporaryObjectConstructionContext *CC,
+                                const ConstructionContext *CC,
                                 BumpVectorContext &C) {
     Elements.push_back(CFGCXXRecordTypedCall(CE, CC), C);
   }

Modified: cfe/trunk/include/clang/Analysis/ConstructionContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/ConstructionContext.h?rev=328248&r1=328247&r2=328248&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/ConstructionContext.h (original)
+++ cfe/trunk/include/clang/Analysis/ConstructionContext.h Thu Mar 22 14:37:39 2018
@@ -99,22 +99,26 @@ class ConstructionContext {
 public:
   enum Kind {
     SimpleVariableKind,
+    CXX17ElidedCopyVariableKind,
+    VARIABLE_BEGIN = SimpleVariableKind,
+    VARIABLE_END = CXX17ElidedCopyVariableKind,
     ConstructorInitializerKind,
     NewAllocatedObjectKind,
     TemporaryObjectKind,
-    ReturnedValueKind
+    SimpleReturnedValueKind,
+    CXX17ElidedCopyReturnedValueKind,
+    RETURNED_VALUE_BEGIN = SimpleReturnedValueKind,
+    RETURNED_VALUE_END = CXX17ElidedCopyReturnedValueKind
   };
 
 protected:
   Kind K;
 
-protected:
   // Do not make public! These need to only be constructed
   // via createFromLayers().
   explicit ConstructionContext(Kind K) : K(K) {}
 
 public:
-
   /// Consume the construction context layer, together with its parent layers,
   /// and wrap it up into a complete construction context.
   static const ConstructionContext *
@@ -124,23 +128,68 @@ public:
   Kind getKind() const { return K; }
 };
 
-/// Represents construction into a simple local variable, eg. T var(123);.
-class SimpleVariableConstructionContext : public ConstructionContext {
+/// An abstract base class for local variable constructors.
+class VariableConstructionContext : public ConstructionContext {
   const DeclStmt *DS;
 
-public:
-  explicit SimpleVariableConstructionContext(const DeclStmt *DS)
-      : ConstructionContext(ConstructionContext::SimpleVariableKind), DS(DS) {
+protected:
+  VariableConstructionContext(ConstructionContext::Kind K, const DeclStmt *DS)
+      : ConstructionContext(K), DS(DS) {
+    assert(classof(this));
     assert(DS);
   }
 
+public:
   const DeclStmt *getDeclStmt() const { return DS; }
 
   static bool classof(const ConstructionContext *CC) {
+    return CC->getKind() >= VARIABLE_BEGIN &&
+           CC->getKind() <= VARIABLE_END;
+  }
+};
+
+/// Represents construction into a simple local variable, eg. T var(123);.
+/// If a variable has an initializer, eg. T var = makeT();, then the final
+/// elidable copy-constructor from makeT() into var would also be a simple
+/// variable constructor handled by this class.
+class SimpleVariableConstructionContext : public VariableConstructionContext {
+public:
+  explicit SimpleVariableConstructionContext(const DeclStmt *DS)
+      : VariableConstructionContext(ConstructionContext::SimpleVariableKind,
+                                    DS) {}
+
+  static bool classof(const ConstructionContext *CC) {
     return CC->getKind() == SimpleVariableKind;
   }
 };
 
+/// Represents construction into a simple variable with an initializer syntax,
+/// with a single constructor, eg. T var = makeT();. Such construction context
+/// may only appear in C++17 because previously it was split into a temporary
+/// object constructor and an elidable simple variable copy-constructor and
+/// we were producing separate construction contexts for these constructors.
+/// In C++17 we have a single construction context that combines both.
+/// Note that if the object has trivial destructor, then this code is
+/// indistinguishable from a simple variable constructor on the AST level;
+/// in this case we provide a simple variable construction context.
+class CXX17ElidedCopyVariableConstructionContext
+    : public VariableConstructionContext {
+  const CXXBindTemporaryExpr *BTE;
+
+public:
+  explicit CXX17ElidedCopyVariableConstructionContext(
+      const DeclStmt *DS, const CXXBindTemporaryExpr *BTE)
+      : VariableConstructionContext(CXX17ElidedCopyVariableKind, DS), BTE(BTE) {
+    assert(BTE);
+  }
+
+  const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { return BTE; }
+
+  static bool classof(const ConstructionContext *CC) {
+    return CC->getKind() == CXX17ElidedCopyVariableKind;
+  }
+};
+
 /// Represents construction into a field or a base class within a bigger object
 /// via a constructor initializer, eg. T(): field(123) { ... }.
 class ConstructorInitializerConstructionContext : public ConstructionContext {
@@ -219,24 +268,68 @@ public:
   }
 };
 
+class ReturnedValueConstructionContext : public ConstructionContext {
+  const ReturnStmt *RS;
+
+protected:
+  explicit ReturnedValueConstructionContext(ConstructionContext::Kind K,
+                                            const ReturnStmt *RS)
+      : ConstructionContext(K), RS(RS) {
+    assert(classof(this));
+    assert(RS);
+  }
+
+public:
+  const ReturnStmt *getReturnStmt() const { return RS; }
+
+  static bool classof(const ConstructionContext *CC) {
+    return CC->getKind() >= RETURNED_VALUE_BEGIN &&
+           CC->getKind() <= RETURNED_VALUE_END;
+  }
+};
+
 /// Represents a temporary object that is being immediately returned from a
 /// function by value, eg. return t; or return T(123);. In this case there is
 /// always going to be a constructor at the return site. However, the usual
 /// temporary-related bureaucracy (CXXBindTemporaryExpr,
 /// MaterializeTemporaryExpr) is normally located in the caller function's AST.
-class ReturnedValueConstructionContext : public ConstructionContext {
-  const ReturnStmt *RS;
+class SimpleReturnedValueConstructionContext
+    : public ReturnedValueConstructionContext {
+public:
+  explicit SimpleReturnedValueConstructionContext(const ReturnStmt *RS)
+      : ReturnedValueConstructionContext(
+            ConstructionContext::SimpleReturnedValueKind, RS) {}
+
+  static bool classof(const ConstructionContext *CC) {
+    return CC->getKind() == SimpleReturnedValueKind;
+  }
+};
+
+/// Represents a temporary object that is being immediately returned from a
+/// function by value, eg. return t; or return T(123); in C++17.
+/// In C++17 there is not going to be an elidable copy constructor at the
+/// return site.  However, the usual temporary-related bureaucracy (CXXBindTemporaryExpr,
+/// MaterializeTemporaryExpr) is normally located in the caller function's AST.
+/// Note that if the object has trivial destructor, then this code is
+/// indistinguishable from a simple returned value constructor on the AST level;
+/// in this case we provide a simple returned value construction context.
+class CXX17ElidedCopyReturnedValueConstructionContext
+    : public ReturnedValueConstructionContext {
+  const CXXBindTemporaryExpr *BTE;
 
 public:
-  explicit ReturnedValueConstructionContext(const ReturnStmt *RS)
-      : ConstructionContext(ConstructionContext::ReturnedValueKind), RS(RS) {
-    assert(RS);
+  explicit CXX17ElidedCopyReturnedValueConstructionContext(
+      const ReturnStmt *RS, const CXXBindTemporaryExpr *BTE)
+      : ReturnedValueConstructionContext(
+            ConstructionContext::CXX17ElidedCopyReturnedValueKind, RS),
+        BTE(BTE) {
+    assert(BTE);
   }
 
-  const ReturnStmt *getReturnStmt() const { return RS; }
+  const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { return BTE; }
 
   static bool classof(const ConstructionContext *CC) {
-    return CC->getKind() == ReturnedValueKind;
+    return CC->getKind() == CXX17ElidedCopyReturnedValueKind;
   }
 };
 

Modified: cfe/trunk/lib/Analysis/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=328248&r1=328247&r2=328248&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CFG.cpp (original)
+++ cfe/trunk/lib/Analysis/CFG.cpp Thu Mar 22 14:37:39 2018
@@ -760,9 +760,7 @@ private:
           const ConstructionContext *CC =
               ConstructionContext::createFromLayers(cfg->getBumpVectorContext(),
                                                     Layer);
-          B->appendCXXRecordTypedCall(
-              CE, cast<TemporaryObjectConstructionContext>(CC),
-              cfg->getBumpVectorContext());
+          B->appendCXXRecordTypedCall(CE, CC, cfg->getBumpVectorContext());
           cleanupConstructionContext(CE);
           return;
         }
@@ -1284,7 +1282,7 @@ void CFGBuilder::findConstructionContext
   }
   case Stmt::ImplicitCastExprClass: {
     auto *Cast = cast<ImplicitCastExpr>(Child);
-    // TODO: We need to support CK_ConstructorConversion, maybe other kinds?
+    // Should we support other implicit cast kinds?
     switch (Cast->getCastKind()) {
     case CK_NoOp:
     case CK_ConstructorConversion:
@@ -4920,8 +4918,14 @@ static void print_construction_context(r
     break;
   }
   case ConstructionContext::SimpleVariableKind: {
-    const auto *DSCC = cast<SimpleVariableConstructionContext>(CC);
-    S1 = DSCC->getDeclStmt();
+    const auto *SDSCC = cast<SimpleVariableConstructionContext>(CC);
+    S1 = SDSCC->getDeclStmt();
+    break;
+  }
+  case ConstructionContext::CXX17ElidedCopyVariableKind: {
+    const auto *CDSCC = cast<CXX17ElidedCopyVariableConstructionContext>(CC);
+    S1 = CDSCC->getDeclStmt();
+    S2 = CDSCC->getCXXBindTemporaryExpr();
     break;
   }
   case ConstructionContext::NewAllocatedObjectKind: {
@@ -4929,9 +4933,16 @@ static void print_construction_context(r
     S1 = NECC->getCXXNewExpr();
     break;
   }
-  case ConstructionContext::ReturnedValueKind: {
-    const auto *RSCC = cast<ReturnedValueConstructionContext>(CC);
+  case ConstructionContext::SimpleReturnedValueKind: {
+    const auto *RSCC = cast<SimpleReturnedValueConstructionContext>(CC);
+    S1 = RSCC->getReturnStmt();
+    break;
+  }
+  case ConstructionContext::CXX17ElidedCopyReturnedValueKind: {
+    const auto *RSCC =
+        cast<CXX17ElidedCopyReturnedValueConstructionContext>(CC);
     S1 = RSCC->getReturnStmt();
+    S2 = RSCC->getCXXBindTemporaryExpr();
     break;
   }
   case ConstructionContext::TemporaryObjectKind: {

Modified: cfe/trunk/lib/Analysis/ConstructionContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ConstructionContext.cpp?rev=328248&r1=328247&r2=328248&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/ConstructionContext.cpp (original)
+++ cfe/trunk/lib/Analysis/ConstructionContext.cpp Thu Mar 22 14:37:39 2018
@@ -64,11 +64,43 @@ const ConstructionContext *ConstructionC
       // lifetime extension on the parent layer.
       if (const ConstructionContextLayer *ParentLayer = TopLayer->getParent()) {
         assert(ParentLayer->isLast());
-        MTE = cast<MaterializeTemporaryExpr>(ParentLayer->getTriggerStmt());
+        if ((MTE = dyn_cast<MaterializeTemporaryExpr>(
+                 ParentLayer->getTriggerStmt()))) {
+          // A temporary object which has both destruction and
+          // materialization info.
+          auto *CC =
+              C.getAllocator().Allocate<TemporaryObjectConstructionContext>();
+          return new (CC) TemporaryObjectConstructionContext(BTE, MTE);
+        }
+        // C++17 *requires* elision of the constructor at the return site
+        // and at variable initialization site, while previous standards
+        // were allowing an optional elidable constructor.
+        if (auto *RS = dyn_cast<ReturnStmt>(ParentLayer->getTriggerStmt())) {
+          assert(!RS->getRetValue()->getType().getCanonicalType()
+                    ->getAsCXXRecordDecl()->hasTrivialDestructor());
+          auto *CC =
+              C.getAllocator()
+                  .Allocate<
+                      CXX17ElidedCopyReturnedValueConstructionContext>();
+          return new (CC)
+              CXX17ElidedCopyReturnedValueConstructionContext(RS, BTE);
+        }
+        if (auto *DS = dyn_cast<DeclStmt>(ParentLayer->getTriggerStmt())) {
+          assert(!cast<VarDecl>(DS->getSingleDecl())->getType()
+                      .getCanonicalType()->getAsCXXRecordDecl()
+                      ->hasTrivialDestructor());
+          auto *CC =
+              C.getAllocator()
+                  .Allocate<CXX17ElidedCopyVariableConstructionContext>();
+          return new (CC) CXX17ElidedCopyVariableConstructionContext(DS, BTE);
+        }
+        llvm_unreachable("Unexpected construction context with destructor!");
       }
+      // A temporary object that doesn't require materialization.
       auto *CC =
           C.getAllocator().Allocate<TemporaryObjectConstructionContext>();
-      return new (CC) TemporaryObjectConstructionContext(BTE, MTE);
+      return new (CC)
+          TemporaryObjectConstructionContext(BTE, /*MTE=*/nullptr);
     } else if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(S)) {
       // If the object requires destruction and is not lifetime-extended,
       // then it must have a BTE within its MTE.
@@ -82,8 +114,8 @@ const ConstructionContext *ConstructionC
     } else if (const auto *RS = dyn_cast<ReturnStmt>(S)) {
       assert(TopLayer->isLast());
       auto *CC =
-          C.getAllocator().Allocate<ReturnedValueConstructionContext>();
-      return new (CC) ReturnedValueConstructionContext(RS);
+          C.getAllocator().Allocate<SimpleReturnedValueConstructionContext>();
+      return new (CC) SimpleReturnedValueConstructionContext(RS);
     }
   } else if (const CXXCtorInitializer *I = TopLayer->getTriggerInit()) {
     assert(TopLayer->isLast());

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=328248&r1=328247&r2=328248&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Thu Mar 22 14:37:39 2018
@@ -196,7 +196,7 @@ ExprEngine::getRegionForConstructedObjec
       CallOpts.IsTemporaryCtorOrDtor = true;
       return MRMgr.getCXXTempObjectRegion(CE, LCtx);
     }
-    case ConstructionContext::ReturnedValueKind: {
+    case ConstructionContext::SimpleReturnedValueKind: {
       // The temporary is to be managed by the parent stack frame.
       // So build it in the parent stack frame if we're not in the
       // top frame of the analysis.
@@ -211,6 +211,10 @@ ExprEngine::getRegionForConstructedObjec
       CallOpts.IsTemporaryCtorOrDtor = true;
       return MRMgr.getCXXTempObjectRegion(CE, TempLCtx);
     }
+    case ConstructionContext::CXX17ElidedCopyVariableKind:
+    case ConstructionContext::CXX17ElidedCopyReturnedValueKind:
+      // Not implemented yet.
+      break;
     }
   }
   // If we couldn't find an existing region to construct into, assume we're

Modified: cfe/trunk/test/Analysis/cfg-rich-constructors.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cfg-rich-constructors.cpp?rev=328248&r1=328247&r2=328248&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/cfg-rich-constructors.cpp (original)
+++ cfe/trunk/test/Analysis/cfg-rich-constructors.cpp Thu Mar 22 14:37:39 2018
@@ -1,5 +1,7 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -triple x86_64-apple-darwin12 -analyzer-config cfg-temporary-dtors=true -std=c++11 -w %s > %t 2>&1
-// RUN: FileCheck --input-file=%t %s
+// RUN: FileCheck --input-file=%t -check-prefixes=CHECK,CXX11 %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -triple x86_64-apple-darwin12 -analyzer-config cfg-temporary-dtors=true -std=c++17 -w %s > %t 2>&1
+// RUN: FileCheck --input-file=%t -check-prefixes=CHECK,CXX17 %s
 
 class C {
 public:
@@ -98,32 +100,38 @@ void simpleVariableWithOperatorNewInBrac
 // CHECK:          1: C::get
 // CHECK-NEXT:     2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void))
 // CHECK-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.4])
-// CHECK-NEXT:     4: [B1.3]
-// CHECK-NEXT:     5: [B1.4] (CXXConstructExpr, [B1.6], class C)
-// CHECK-NEXT:     6: C c = C::get();
+// CXX11-NEXT:     4: [B1.3]
+// CXX11-NEXT:     5: [B1.4] (CXXConstructExpr, [B1.6], class C)
+// CXX11-NEXT:     6: C c = C::get();
+// CXX17-NEXT:     4: C c = C::get();
 void simpleVariableInitializedByValue() {
   C c = C::get();
 }
 
 // CHECK: void simpleVariableWithTernaryOperator(bool coin)
 // CHECK:        [B1]
-// CHECK-NEXT:     1: [B4.2] ? [B2.5] : [B3.6]
-// CHECK-NEXT:     2: [B1.1]
-// CHECK-NEXT:     3: [B1.2] (CXXConstructExpr, [B1.4], class C)
-// CHECK-NEXT:     4: C c = coin ? C::get() : C(0);
+// CXX11-NEXT:     1: [B4.2] ? [B2.5] : [B3.6]
+// CXX11-NEXT:     2: [B1.1]
+// CXX11-NEXT:     3: [B1.2] (CXXConstructExpr, [B1.4], class C)
+// CXX11-NEXT:     4: C c = coin ? C::get() : C(0);
+// CXX17-NEXT:     1: [B4.2] ? [B2.3] : [B3.4]
+// CXX17-NEXT:     2: C c = coin ? C::get() : C(0);
 // CHECK:        [B2]
 // CHECK-NEXT:     1: C::get
 // CHECK-NEXT:     2: [B2.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void))
-// CHECK-NEXT:     3: [B2.2]() (CXXRecordTypedCall, [B2.4])
-// CHECK-NEXT:     4: [B2.3]
-// CHECK-NEXT:     5: [B2.4] (CXXConstructExpr, [B1.2], class C)
+// CXX11-NEXT:     3: [B2.2]() (CXXRecordTypedCall, [B2.4])
+// CXX11-NEXT:     4: [B2.3]
+// CXX11-NEXT:     5: [B2.4] (CXXConstructExpr, [B1.2], class C)
+// CXX17-NEXT:     3: [B2.2]() (CXXRecordTypedCall, [B1.2])
 // CHECK:        [B3]
 // CHECK-NEXT:     1: 0
 // CHECK-NEXT:     2: [B3.1] (ImplicitCastExpr, NullToPointer, class C *)
-// CHECK-NEXT:     3: [B3.2] (CXXConstructExpr, [B3.5], class C)
-// CHECK-NEXT:     4: C([B3.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C)
-// CHECK-NEXT:     5: [B3.4]
-// CHECK-NEXT:     6: [B3.5] (CXXConstructExpr, [B1.2], class C)
+// CXX11-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)
+// CXX17-NEXT:     3: [B3.2] (CXXConstructExpr, [B1.2], class C)
+// CXX17-NEXT:     4: C([B3.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C)
 // CHECK:        [B4]
 // CHECK-NEXT:     1: coin
 // CHECK-NEXT:     2: [B4.1] (ImplicitCastExpr, LValueToRValue, _Bool)
@@ -137,9 +145,10 @@ void simpleVariableWithTernaryOperator(b
 // CHECK-NEXT:     2: [B1.1] (ImplicitCastExpr, NullToPointer, class C *)
 // CHECK-NEXT:     3: [B1.2] (CXXConstructExpr, [B1.5], class C)
 // CHECK-NEXT:     4: C([B1.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C)
-// CHECK-NEXT:     5: [B1.4]
-// CHECK-NEXT:     6: [B1.5] (CXXConstructExpr, [B1.7], class C)
-// CHECK-NEXT:     7: C c = C(0);
+// CXX11-NEXT:     5: [B1.4]
+// CXX11-NEXT:     6: [B1.5] (CXXConstructExpr, [B1.7], class C)
+// CXX11-NEXT:     7: C c = C(0);
+// CXX17-NEXT:     5: C c = C(0);
 void simpleVariableWithElidableCopy() {
   C c = C(0);
 }
@@ -165,23 +174,27 @@ void referenceVariableWithInitializer()
 
 // CHECK: void referenceVariableWithTernaryOperator(bool coin)
 // CHECK:        [B1]
-// CHECK-NEXT:     1: [B4.2] ? [B2.5] : [B3.6]
+// CXX11-NEXT:     1: [B4.2] ? [B2.5] : [B3.6]
+// CXX17-NEXT:     1: [B4.2] ? [B2.3] : [B3.4]
 // CHECK-NEXT:     2: [B1.1] (ImplicitCastExpr, NoOp, const class C)
 // CHECK-NEXT:     3: [B1.2]
 // CHECK-NEXT:     4: const C &c = coin ? C::get() : C(0);
 // CHECK:        [B2]
 // CHECK-NEXT:     1: C::get
 // CHECK-NEXT:     2: [B2.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void))
-// CHECK-NEXT:     3: [B2.2]() (CXXRecordTypedCall, [B2.4])
-// CHECK-NEXT:     4: [B2.3]
-// CHECK-NEXT:     5: [B2.4] (CXXConstructExpr, [B1.3], class C)
+// CXX11-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 *)
-// CHECK-NEXT:     3: [B3.2] (CXXConstructExpr, [B3.5], class C)
-// CHECK-NEXT:     4: C([B3.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C)
-// CHECK-NEXT:     5: [B3.4]
-// CHECK-NEXT:     6: [B3.5] (CXXConstructExpr, [B1.3], class C)
+// CXX11-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)
+// CXX17-NEXT:     3: [B3.2] (CXXConstructExpr, [B1.3], class C)
+// CXX17-NEXT:     4: C([B3.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C)
 // CHECK:        [B4]
 // CHECK-NEXT:     1: coin
 // CHECK-NEXT:     2: [B4.1] (ImplicitCastExpr, LValueToRValue, _Bool)
@@ -214,6 +227,8 @@ public:
 // CHECK-NEXT:     2: D([B1.1]) (Delegating initializer)
   D(int): D() {}
 
+// FIXME: Why is CXXRecordTypedCall not present in C++17? Note that once it gets
+// detected the test would not fail, because FileCheck allows partial matches.
 // CHECK: D(double)
 // CHECK:          1: C::get
 // CHECK-NEXT:     2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void))
@@ -224,12 +239,16 @@ public:
 // CHECK-NEXT:     7: CFGNewAllocator(C *)
 // CHECK-NEXT:     8: C::get
 // CHECK-NEXT:     9: [B1.8] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void))
-// CHECK-NEXT:    10: [B1.9]() (CXXRecordTypedCall, [B1.11])
-// CHECK-NEXT:    11: [B1.10]
-// CHECK-NEXT:    12: [B1.11] (CXXConstructExpr, [B1.13], class C)
-// CHECK-NEXT:    13: new C([B1.12])
-// CHECK-NEXT:    14: [B1.13] (CXXConstructExpr, c1([B1.13]) (Member initializer), class C)
-// CHECK-NEXT:    15: c1([B1.14]) (Member initializer)
+// CXX11-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])
+// CXX11-NEXT:    14: [B1.13] (CXXConstructExpr, c1([B1.13]) (Member initializer), class C)
+// CXX11-NEXT:    15: c1([B1.14]) (Member initializer)
+// CXX17-NEXT:    10: [B1.9]()
+// CXX17-NEXT:    11: new C([B1.10])
+// CXX17-NEXT:    12: [B1.11] (CXXConstructExpr, c1([B1.11]) (Member initializer), class C)
+// CXX17-NEXT:    13: c1([B1.12]) (Member initializer)
   D(double): C(C::get()), c1(new C(C::get())) {}
 };
 
@@ -277,9 +296,10 @@ C returnBracesWithMultipleItems() {
 
 // CHECK: C returnTemporary()
 // CHECK:          1: C() (CXXConstructExpr, [B1.2], class C)
-// CHECK-NEXT:     2: [B1.1]
-// CHECK-NEXT:     3: [B1.2] (CXXConstructExpr, [B1.4], class C)
-// CHECK-NEXT:     4: return [B1.3];
+// CXX11-NEXT:     2: [B1.1]
+// CXX11-NEXT:     3: [B1.2] (CXXConstructExpr, [B1.4], class C)
+// CXX11-NEXT:     4: return [B1.3];
+// CXX17-NEXT:     2: return [B1.1];
 C returnTemporary() {
   return C();
 }
@@ -289,9 +309,11 @@ C returnTemporary() {
 // CHECK-NEXT:     2: [B1.1] (ImplicitCastExpr, NullToPointer, class C *)
 // CHECK-NEXT:     3: [B1.2] (CXXConstructExpr, [B1.5], class C)
 // CHECK-NEXT:     4: C([B1.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C)
-// CHECK-NEXT:     5: [B1.4]
-// CHECK-NEXT:     6: [B1.5] (CXXConstructExpr, [B1.7], class C)
-// CHECK-NEXT:     7: return [B1.6];
+// CXX11-NEXT:     5: [B1.4]
+// CXX11-NEXT:     6: [B1.5] (CXXConstructExpr, [B1.7], class C)
+// CXX11-NEXT:     7: return [B1.6];
+// CXX17-NEXT:     5: return [B1.4];
+
 C returnTemporaryWithArgument() {
   return C(nullptr);
 }
@@ -300,9 +322,10 @@ C returnTemporaryWithArgument() {
 // CHECK:          1: C::get
 // CHECK-NEXT:     2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void))
 // CHECK-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.4])
-// CHECK-NEXT:     4: [B1.3]
-// CHECK-NEXT:     5: [B1.4] (CXXConstructExpr, [B1.6], class C)
-// CHECK-NEXT:     6: return [B1.5];
+// CXX11-NEXT:     4: [B1.3]
+// CXX11-NEXT:     5: [B1.4] (CXXConstructExpr, [B1.6], class C)
+// CXX11-NEXT:     6: return [B1.5];
+// CXX17-NEXT:     4: return [B1.3];
 C returnTemporaryConstructedByFunction() {
   return C::get();
 }
@@ -310,13 +333,16 @@ C returnTemporaryConstructedByFunction()
 // CHECK: C returnChainOfCopies()
 // CHECK:          1: C::get
 // CHECK-NEXT:     2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void))
-// CHECK-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.4])
-// CHECK-NEXT:     4: [B1.3]
-// CHECK-NEXT:     5: [B1.4] (CXXConstructExpr, [B1.7], class C)
-// CHECK-NEXT:     6: C([B1.5]) (CXXFunctionalCastExpr, ConstructorConversion, class C)
-// CHECK-NEXT:     7: [B1.6]
-// CHECK-NEXT:     8: [B1.7] (CXXConstructExpr, [B1.9], class C)
-// CHECK-NEXT:     9: return [B1.8];
+// CXX11-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.4])
+// CXX11-NEXT:     4: [B1.3]
+// CXX11-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)
+// CXX11-NEXT:     9: return [B1.8];
+// CXX17-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.5])
+// CXX17-NEXT:     4: C([B1.3]) (CXXFunctionalCastExpr, NoOp, class C)
+// CXX17-NEXT:     5: return [B1.4];
 C returnChainOfCopies() {
   return C(C::get());
 }
@@ -331,18 +357,44 @@ public:
   ~D();
 };
 
+// FIXME: There should be no temporary destructor in C++17.
 // CHECK:  return_stmt_with_dtor::D returnTemporary()
-// CHECK:          1: return_stmt_with_dtor::D() (CXXConstructExpr, [B1.2], [B1.4], class return_stmt_with_dtor::D)
-// CHECK-NEXT:     2: [B1.1] (BindTemporary)
-// CHECK-NEXT:     3: [B1.2] (ImplicitCastExpr, NoOp, const class return_stmt_with_dtor::D)
-// CHECK-NEXT:     4: [B1.3]
-// CHECK-NEXT:     5: [B1.4] (CXXConstructExpr, [B1.7], class return_stmt_with_dtor::D)
-// CHECK-NEXT:     6: ~return_stmt_with_dtor::D() (Temporary object destructor)
-// CHECK-NEXT:     7: return [B1.5];
+// CXX11:          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]
+// CXX11-NEXT:     5: [B1.4] (CXXConstructExpr, [B1.7], class return_stmt_with_dtor::D)
+// CXX11-NEXT:     6: ~return_stmt_with_dtor::D() (Temporary object destructor)
+// CXX11-NEXT:     7: return [B1.5];
+// CXX17:          1: return_stmt_with_dtor::D() (CXXConstructExpr, [B1.4], [B1.2], class return_stmt_w
+// CXX17-NEXT:     2: [B1.1] (BindTemporary)
+// CXX17-NEXT:     3: ~return_stmt_with_dtor::D() (Temporary object destructor)
+// CXX17-NEXT:     4: return [B1.2];
 D returnTemporary() {
   return D();
 }
 
+// FIXME: There should be no temporary destructor in C++17.
+// 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-NEXT:     4: [B1.3] (BindTemporary)
+// CXX11-NEXT:     5: [B1.4] (ImplicitCastExpr, NoOp, const class return_stmt_with_dtor::D)
+// CXX11-NEXT:     6: [B1.5]
+// CXX11-NEXT:     7: [B1.6] (CXXConstructExpr, [B1.8], class return_stmt_with_dtor::D)
+// CXX11-NEXT:     8: return_stmt_with_dtor::D d = returnTemporary();
+// CXX11-NEXT:     9: ~return_stmt_with_dtor::D() (Temporary object destructor)
+// CXX11-NEXT:    10: [B1.8].~D() (Implicit destructor)
+// CXX17-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.5], [B1.4])
+// CXX17-NEXT:     4: [B1.3] (BindTemporary)
+// CXX17-NEXT:     5: return_stmt_with_dtor::D d = returnTemporary();
+// CXX17-NEXT:     6: ~return_stmt_with_dtor::D() (Temporary object destructor)
+// CXX17-NEXT:     7: [B1.5].~D() (Implicit destructor)
+void returnByValueIntoVariable() {
+  D d = returnTemporary();
+}
+
 } // end namespace return_stmt_with_dtor
 
 namespace temporary_object_expr_without_dtors {
@@ -426,34 +478,60 @@ void referenceVariableWithInitializer()
 }
 
 // CHECK: void referenceVariableWithTernaryOperator(bool coin)
-// CHECK:        [B4]
-// CHECK-NEXT:     1: [B7.2] ? [B5.8] : [B6.8]
-// CHECK-NEXT:     2: [B4.1] (ImplicitCastExpr, NoOp, const class temporary_object_expr_with_dtors::D)
-// CHECK-NEXT:     3: [B4.2]
-// CHECK-NEXT:     4: const temporary_object_expr_with_dtors::D &d = coin ? D::get() : temporary_object_expr_with_dtors::D(0);
-// CHECK-NEXT:     T: (Temp Dtor) [B6.3]
-// CHECK:        [B5]
-// CHECK-NEXT:     1: D::get
-// CHECK-NEXT:     2: [B5.1] (ImplicitCastExpr, FunctionToPointerDecay, class temporary_object_expr_with_dtors::D (*)(void))
-// CHECK-NEXT:     3: [B5.2]() (CXXRecordTypedCall, [B5.4], [B5.6])
-// CHECK-NEXT:     4: [B5.3] (BindTemporary)
-// CHECK-NEXT:     5: [B5.4] (ImplicitCastExpr, NoOp, const class temporary_object_expr_with_dtors::D)
-// CHECK-NEXT:     6: [B5.5]
-// CHECK-NEXT:     7: [B5.6] (CXXConstructExpr, [B5.8], [B4.3], class temporary_object_expr_with_dtors::D)
-// CHECK-NEXT:     8: [B5.7] (BindTemporary)
-// CHECK:        [B6]
-// CHECK-NEXT:     1: 0
-// CHECK-NEXT:     2: [B6.1] (CXXConstructExpr, [B6.3], [B6.6], class temporary_object_expr_with_dtors::D)
-// CHECK-NEXT:     3: [B6.2] (BindTemporary)
-// CHECK-NEXT:     4: temporary_object_expr_with_dtors::D([B6.3]) (CXXFunctionalCastExpr, ConstructorConversion, class temporary_object_expr_with_dtors::D)
-// CHECK-NEXT:     5: [B6.4] (ImplicitCastExpr, NoOp, const class temporary_object_expr_with_dtors::D)
-// CHECK-NEXT:     6: [B6.5]
-// CHECK-NEXT:     7: [B6.6] (CXXConstructExpr, [B6.8], [B4.3], class temporary_object_expr_with_dtors::D)
-// CHECK-NEXT:     8: [B6.7] (BindTemporary)
-// CHECK:        [B7]
-// CHECK-NEXT:     1: coin
-// CHECK-NEXT:     2: [B7.1] (ImplicitCastExpr, LValueToRValue, _Bool)
-// CHECK-NEXT:     T: [B7.2] ? ... : ...
+// CXX11:        [B1]
+// CXX11-NEXT:     1: [B4.4].~D() (Implicit destructor)
+// CXX11:        [B2]
+// CXX11-NEXT:     1: ~temporary_object_expr_with_dtors::D() (Temporary object destructor)
+// CXX11:        [B3]
+// CXX11-NEXT:     1: ~temporary_object_expr_with_dtors::D() (Temporary object destructor)
+// CXX11:        [B4]
+// CXX11-NEXT:     1: [B7.2] ? [B5.8] : [B6.8]
+// CXX11-NEXT:     2: [B4.1] (ImplicitCastExpr, NoOp, const class temporary_object_expr_with_dtors::D)
+// CXX11-NEXT:     3: [B4.2]
+// CXX11-NEXT:     4: const temporary_object_expr_with_dtors::D &d = coin ? D::get() : temporary_object_expr_with_dtors::D(0);
+// CXX11-NEXT:     T: (Temp Dtor) [B6.3]
+// 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-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]
+// CXX11-NEXT:     7: [B5.6] (CXXConstructExpr, [B5.8], [B4.3], class temporary_object_expr_with_dtors::D)
+// 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-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)
+// CXX11-NEXT:     6: [B6.5]
+// CXX11-NEXT:     7: [B6.6] (CXXConstructExpr, [B6.8], [B4.3], class temporary_object_expr_with_dtors::D)
+// CXX11-NEXT:     8: [B6.7] (BindTemporary)
+// CXX11:        [B7]
+// CXX11-NEXT:     1: coin
+// CXX11-NEXT:     2: [B7.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CXX11-NEXT:     T: [B7.2] ? ... : ...
+// CXX17:        [B1]
+// CXX17-NEXT:     1: [B4.2] ? [B2.4] : [B3.4]
+// CXX17-NEXT:     2: [B1.1] (ImplicitCastExpr, NoOp, const class temporary_object_expr_with_dtors::D)
+// CXX17-NEXT:     3: [B1.2]
+// CXX17-NEXT:     4: const temporary_object_expr_with_dtors::D &d = coin ? D::get() : temporary_object_expr_with_dtors::D(0);
+// CXX17-NEXT:     5: [B1.4].~D() (Implicit destructor)
+// CXX17:        [B2]
+// CXX17-NEXT:     1: D::get
+// CXX17-NEXT:     2: [B2.1] (ImplicitCastExpr, FunctionToPointerDecay, class temporary_object_expr_with_dtors::D (*)(void))
+// CXX17-NEXT:     3: [B2.2]() (CXXRecordTypedCall, [B2.4], [B1.3])
+// CXX17-NEXT:     4: [B2.3] (BindTemporary)
+// CXX17:        [B3]
+// CXX17-NEXT:     1: 0
+// CXX17-NEXT:     2: [B3.1] (CXXConstructExpr, [B3.3], [B1.3], class temporary_object_expr_with_dtors::D)
+// CXX17-NEXT:     3: [B3.2] (BindTemporary)
+// CXX17-NEXT:     4: temporary_object_expr_with_dtors::D([B3.3]) (CXXFunctionalCastExpr, ConstructorConversion, class temporary_object_expr_with_dtors::D)
+// CXX17:        [B4]
+// CXX17-NEXT:     1: coin
+// CXX17-NEXT:     2: [B4.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CXX17-NEXT:     T: [B4.2] ? ... : ...
 void referenceVariableWithTernaryOperator(bool coin) {
   const D &d = coin ? D::get() : D(0);
 }
@@ -472,15 +550,24 @@ void referenceWithFunctionalCast() {
 
 // Test the condition constructor, we don't care about branch constructors here.
 // CHECK: void constructorInTernaryCondition()
-// CHECK:          1: 1
-// CHECK-NEXT:     2: [B7.1] (CXXConstructExpr, [B7.3], class temporary_object_expr_with_dtors::D)
-// CHECK-NEXT:     3: [B7.2] (BindTemporary)
-// CHECK-NEXT:     4: temporary_object_expr_with_dtors::D([B7.3]) (CXXFunctionalCastExpr, ConstructorConv
-// CHECK-NEXT:     5: [B7.4] (ImplicitCastExpr, NoOp, const class temporary_object_expr_with_dtors::D)
-// CHECK-NEXT:     6: [B7.5].operator bool
-// CHECK-NEXT:     7: [B7.5]
-// CHECK-NEXT:     8: [B7.7] (ImplicitCastExpr, UserDefinedConversion, _Bool)
-// CHECK-NEXT:     T: [B7.8] ? ... : ...
+// CXX11:          1: 1
+// CXX11-NEXT:     2: [B7.1] (CXXConstructExpr, [B7.3], class temporary_object_expr_with_dtors::D)
+// CXX11-NEXT:     3: [B7.2] (BindTemporary)
+// CXX11-NEXT:     4: temporary_object_expr_with_dtors::D([B7.3]) (CXXFunctionalCastExpr, ConstructorConversion, class temporary_object_expr_with_dtors::D)
+// CXX11-NEXT:     5: [B7.4] (ImplicitCastExpr, NoOp, const class temporary_object_expr_with_dtors::D)
+// CXX11-NEXT:     6: [B7.5].operator bool
+// CXX11-NEXT:     7: [B7.5]
+// CXX11-NEXT:     8: [B7.7] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX11-NEXT:     T: [B7.8] ? ... : ...
+// CXX17:          1: 1
+// CXX17-NEXT:     2: [B4.1] (CXXConstructExpr, [B4.3], class temporary_object_expr_with_dtors::D)
+// CXX17-NEXT:     3: [B4.2] (BindTemporary)
+// CXX17-NEXT:     4: temporary_object_expr_with_dtors::D([B4.3]) (CXXFunctionalCastExpr, ConstructorConversion, class temporary_object_expr_with_dtors::D)
+// CXX17-NEXT:     5: [B4.4] (ImplicitCastExpr, NoOp, const class temporary_object_expr_with_dtors::D)
+// CXX17-NEXT:     6: [B4.5].operator bool
+// CXX17-NEXT:     7: [B4.5]
+// CXX17-NEXT:     8: [B4.7] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX17-NEXT:     T: [B4.8] ? ... : ...
 void constructorInTernaryCondition() {
   const D &d = D(1) ? D(2) : D(3);
 }
@@ -500,17 +587,23 @@ public:
 
 // CHECK: void implicitConstructionConversionFromTemporary()
 // CHECK:          1: implicit_constructor_conversion::A() (CXXConstructExpr, [B1.3], class implicit_constructor_conversion::A)
-// CHECK-NEXT:     2: [B1.1] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::A)
-// CHECK-NEXT:     3: [B1.2]
-// CHECK-NEXT:     4: [B1.3] (CXXConstructExpr, [B1.6], [B1.8], class implicit_constructor_conversion::B)
-// CHECK-NEXT:     5: [B1.4] (ImplicitCastExpr, ConstructorConversion, class implicit_constructor_conversion::B)
-// CHECK-NEXT:     6: [B1.5] (BindTemporary)
-// CHECK-NEXT:     7: [B1.6] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::B)
-// CHECK-NEXT:     8: [B1.7]
-// CHECK-NEXT:     9: [B1.8] (CXXConstructExpr, [B1.10], class implicit_constructor_conversion::B)
-// CHECK-NEXT:    10: implicit_constructor_conversion::B b = implicit_constructor_conversion::A();
-// CHECK-NEXT:    11: ~implicit_constructor_conversion::B() (Temporary object destructor)
-// CHECK-NEXT:    12: [B1.10].~B() (Implicit destructor)
+// 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-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)
+// CXX11-NEXT:     8: [B1.7]
+// CXX11-NEXT:     9: [B1.8] (CXXConstructExpr, [B1.10], class implicit_constructor_conversion::B)
+// CXX11-NEXT:    10: implicit_constructor_conversion::B b = implicit_constructor_conversion::A();
+// CXX11-NEXT:    11: ~implicit_constructor_conversion::B() (Temporary object destructor)
+// CXX11-NEXT:    12: [B1.10].~B() (Implicit destructor)
+// CXX17-NEXT:     2: [B1.1] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::A)
+// CXX17-NEXT:     3: [B1.2]
+// CXX17-NEXT:     4: [B1.3] (CXXConstructExpr, [B1.6], class implicit_constructor_conversion::B)
+// CXX17-NEXT:     5: [B1.4] (ImplicitCastExpr, ConstructorConversion, class implicit_constructor_conversion::B)
+// CXX17-NEXT:     6: implicit_constructor_conversion::B b = implicit_constructor_conversion::A();
+// CXX17-NEXT:     7: [B1.6].~B() (Implicit destructor)
 void implicitConstructionConversionFromTemporary() {
   B b = A();
 }
@@ -521,15 +614,19 @@ void implicitConstructionConversionFromT
 // 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]
-// CHECK-NEXT:     6: [B1.5] (CXXConstructExpr, [B1.8], [B1.10], class implicit_constructor_conversion::B)
-// CHECK-NEXT:     7: [B1.6] (ImplicitCastExpr, ConstructorConversion, class implicit_constructor_conversion::B)
-// CHECK-NEXT:     8: [B1.7] (BindTemporary)
-// CHECK-NEXT:     9: [B1.8] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::B)
-// CHECK-NEXT:    10: [B1.9]
-// CHECK-NEXT:    11: [B1.10] (CXXConstructExpr, [B1.12], class implicit_constructor_conversion::B)
-// CHECK-NEXT:    12: implicit_constructor_conversion::B b = get();
-// CHECK-NEXT:    13: ~implicit_constructor_conversion::B() (Temporary object destructor)
-// CHECK-NEXT:    14: [B1.12].~B() (Implicit destructor)
+// CXX11-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)
+// CXX11-NEXT:    10: [B1.9]
+// CXX11-NEXT:    11: [B1.10] (CXXConstructExpr, [B1.12], class implicit_constructor_conversion::B)
+// CXX11-NEXT:    12: implicit_constructor_conversion::B b = get();
+// CXX11-NEXT:    13: ~implicit_constructor_conversion::B() (Temporary object destructor)
+// CXX11-NEXT:    14: [B1.12].~B() (Implicit destructor)
+// CXX17-NEXT:     6: [B1.5] (CXXConstructExpr, [B1.8], class implicit_constructor_conversion::B)
+// CXX17-NEXT:     7: [B1.6] (ImplicitCastExpr, ConstructorConversion, class implicit_constructor_conversion::B)
+// CXX17-NEXT:     8: implicit_constructor_conversion::B b = get();
+// CXX17-NEXT:     9: [B1.8].~B() (Implicit destructor)
 void implicitConstructionConversionFromFunctionValue() {
   B b = get();
 }
@@ -548,7 +645,6 @@ void implicitConstructionConversionFromT
   const B &b = A();
 }
 
-// FIXME: Find construction context for the implicit constructor conversion.
 // CHECK: void implicitConstructionConversionFromFunctionValueWithLifetimeExtension()
 // CHECK:          1: get
 // CHECK-NEXT:     2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class implicit_constructor_conver




More information about the cfe-commits mailing list