NoQ updated this revision to Diff 139245.
NoQ added a comment.

Address review comments.


https://reviews.llvm.org/D44597

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

Index: test/Analysis/cfg-rich-constructors.cpp
===================================================================
--- test/Analysis/cfg-rich-constructors.cpp
+++ test/Analysis/cfg-rich-constructors.cpp
@@ -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 @@
 // 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 @@
 // 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 @@
 
 // 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 @@
 // 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 @@
 // 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 @@
 
 // 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,34 +309,40 @@
 // 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);
 }
 
 // CHECK: C returnTemporaryConstructedByFunction()
 // CHECK:          1: C::get
 // CHECK-NEXT:     2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void))
 // CHECK-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.4])
-// 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();
 }
 
 // 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 @@
   ~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 @@
 }
 
 // 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 @@
 
 // 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 @@
 
 // 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 @@
 // 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 @@
   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
Index: lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -196,7 +196,7 @@
       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 @@
       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
Index: lib/Analysis/ConstructionContext.cpp
===================================================================
--- lib/Analysis/ConstructionContext.cpp
+++ lib/Analysis/ConstructionContext.cpp
@@ -64,11 +64,43 @@
       // 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 @@
     } 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());
Index: lib/Analysis/CFG.cpp
===================================================================
--- lib/Analysis/CFG.cpp
+++ lib/Analysis/CFG.cpp
@@ -760,9 +760,7 @@
           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;
         }
@@ -4920,18 +4918,31 @@
     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: {
     const auto *NECC = cast<NewAllocatedObjectConstructionContext>(CC);
     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: {
Index: include/clang/Analysis/ConstructionContext.h
===================================================================
--- include/clang/Analysis/ConstructionContext.h
+++ include/clang/Analysis/ConstructionContext.h
@@ -99,22 +99,26 @@
 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 @@
   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 @@
   }
 };
 
+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;
   }
 };
 
Index: include/clang/Analysis/CFG.h
===================================================================
--- include/clang/Analysis/CFG.h
+++ include/clang/Analysis/CFG.h
@@ -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 @@
 class ASTContext;
 class BinaryOperator;
 class CFG;
-class ConstructionContext;
-class TemporaryObjectConstructionContext;
 class CXXBaseSpecifier;
 class CXXBindTemporaryExpr;
 class CXXCtorInitializer;
@@ -171,35 +170,32 @@
 };
 
 /// 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
   /// by CFGCXXRecordTypedCall, as opposed to a regular CFGStmt.
   static bool isCXXRecordTypedCall(CallExpr *CE, const ASTContext &ACtx) {
     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 @@
   }
 
   void appendCXXRecordTypedCall(CallExpr *CE,
-                                const TemporaryObjectConstructionContext *CC,
+                                const ConstructionContext *CC,
                                 BumpVectorContext &C) {
     Elements.push_back(CFGCXXRecordTypedCall(CE, CC), C);
   }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to