[CFG] Provide construction contexts for temporaries in conditional operators.
authorArtem Dergachev <artem.dergachev@gmail.com>
Sat, 24 Feb 2018 03:10:15 +0000 (03:10 +0000)
committerArtem Dergachev <artem.dergachev@gmail.com>
Sat, 24 Feb 2018 03:10:15 +0000 (03:10 +0000)
When a lifetime-extended temporary is on a branch of a conditional operator,
materialization of such temporary occurs after the condition is resolved.

This change allows us to understand, by including the MaterializeTemporaryExpr
in the construction context, the target for temporary materialization in such
cases.

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

llvm-svn: 326019

clang/lib/Analysis/CFG.cpp
clang/test/Analysis/cfg-rich-constructors.cpp
clang/test/Analysis/temp-obj-dtors-cfg-output.cpp

index 4c6eff3..7ad6fbb 100644 (file)
@@ -1187,6 +1187,9 @@ void CFGBuilder::findConstructionContexts(
         ConstructionContext::create(cfg->getBumpVectorContext(), BTE,
                                     ContextSoFar),
         BTE->getSubExpr());
+  } else if (auto *CO = dyn_cast<ConditionalOperator>(Child)) {
+    findConstructionContexts(ContextSoFar, CO->getLHS());
+    findConstructionContexts(ContextSoFar, CO->getRHS());
   }
 }
 
index 6dee2dc..9613fa2 100644 (file)
@@ -105,7 +105,6 @@ void simpleVariableInitializedByValue() {
   C c = C::get();
 }
 
-// TODO: Should find construction target for the elidable constructors as well.
 // CHECK: void simpleVariableWithTernaryOperator(bool coin)
 // CHECK:        [B1]
 // CHECK-NEXT:     1: [B4.2] ? [B2.5] : [B3.6]
@@ -117,14 +116,14 @@ void simpleVariableInitializedByValue() {
 // CHECK-NEXT:     2: [B2.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void))
 // CHECK-NEXT:     3: [B2.2]()
 // CHECK-NEXT:     4: [B2.3]
-// CHECK-NEXT:     5: [B2.4] (CXXConstructExpr, class C)
+// CHECK-NEXT:     5: [B2.4] (CXXConstructExpr, [B1.2], class C)
 // 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, class C)
+// CHECK-NEXT:     6: [B3.5] (CXXConstructExpr, [B1.2], class C)
 // CHECK:        [B4]
 // CHECK-NEXT:     1: coin
 // CHECK-NEXT:     2: [B4.1] (ImplicitCastExpr, LValueToRValue, _Bool)
@@ -164,7 +163,6 @@ void referenceVariableWithInitializer() {
   const C &c = C();
 }
 
-// TODO: Should find construction targets for the elidable constructors as well.
 // CHECK: void referenceVariableWithTernaryOperator(bool coin)
 // CHECK:        [B1]
 // CHECK-NEXT:     1: [B4.2] ? [B2.5] : [B3.6]
@@ -176,14 +174,14 @@ void referenceVariableWithInitializer() {
 // CHECK-NEXT:     2: [B2.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void))
 // CHECK-NEXT:     3: [B2.2]()
 // CHECK-NEXT:     4: [B2.3]
-// CHECK-NEXT:     5: [B2.4] (CXXConstructExpr, class C)
+// CHECK-NEXT:     5: [B2.4] (CXXConstructExpr, [B1.3], class C)
 // 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, class C)
+// CHECK-NEXT:     6: [B3.5] (CXXConstructExpr, [B1.3], class C)
 // CHECK:        [B4]
 // CHECK-NEXT:     1: coin
 // CHECK-NEXT:     2: [B4.1] (ImplicitCastExpr, LValueToRValue, _Bool)
@@ -441,7 +439,7 @@ void referenceVariableWithInitializer() {
 // 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], class temporary_object_expr_with_dtors::D)
+// 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
@@ -450,7 +448,7 @@ void referenceVariableWithInitializer() {
 // 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], class temporary_object_expr_with_dtors::D)
+// 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
@@ -471,4 +469,19 @@ void referenceVariableWithTernaryOperator(bool coin) {
 void referenceWithFunctionalCast() {
   D &&d = D(1);
 }
+
+// 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] ? ... : ...
+void constructorInTernaryCondition() {
+  const D &d = D(1) ? D(2) : D(3);
+}
 } // end namespace temporary_object_expr_with_dtors
index 7d3a400..d17c5be 100644 (file)
@@ -537,7 +537,7 @@ int testConsistencyNestedNormalReturn(bool value) {
 // CHECK:     3: [B8.2] (ImplicitCastExpr, NoOp, const class A)
 // CHECK:     4: [B8.3]
 // WARNINGS:     5: [B8.4] (CXXConstructExpr, class A)
-// ANALYZER:     5: [B8.4] (CXXConstructExpr, [B8.6], class A)
+// ANALYZER:     5: [B8.4] (CXXConstructExpr, [B8.6], [B7.3], class A)
 // CHECK:     6: [B8.5] (BindTemporary)
 // CHECK:     Preds (1): B10
 // CHECK:     Succs (1): B7
@@ -558,7 +558,7 @@ int testConsistencyNestedNormalReturn(bool value) {
 // CHECK:    12: [B9.11] (ImplicitCastExpr, NoOp, const class A)
 // CHECK:    13: [B9.12]
 // WARNINGS:    14: [B9.13] (CXXConstructExpr, class A)
-// ANALYZER:    14: [B9.13] (CXXConstructExpr, [B9.15], class A)
+// ANALYZER:    14: [B9.13] (CXXConstructExpr, [B9.15], [B7.3], class A)
 // CHECK:    15: [B9.14] (BindTemporary)
 // CHECK:     Preds (1): B10
 // CHECK:     Succs (1): B7
@@ -776,7 +776,7 @@ int testConsistencyNestedNormalReturn(bool value) {
 // CHECK:     3: [B5.2] (ImplicitCastExpr, NoOp, const class A)
 // CHECK:     4: [B5.3]
 // WARNINGS:     5: [B5.4] (CXXConstructExpr, class A)
-// ANALYZER:     5: [B5.4] (CXXConstructExpr, [B5.6], class A)
+// ANALYZER:     5: [B5.4] (CXXConstructExpr, [B5.6], [B4.3], class A)
 // CHECK:     6: [B5.5] (BindTemporary)
 // CHECK:     Preds (1): B7
 // CHECK:     Succs (1): B4
@@ -797,7 +797,7 @@ int testConsistencyNestedNormalReturn(bool value) {
 // CHECK:    12: [B6.11] (ImplicitCastExpr, NoOp, const class A)
 // CHECK:    13: [B6.12]
 // WARNINGS:    14: [B6.13] (CXXConstructExpr, class A)
-// ANALYZER:    14: [B6.13] (CXXConstructExpr, [B6.15], class A)
+// ANALYZER:    14: [B6.13] (CXXConstructExpr, [B6.15], [B4.3], class A)
 // CHECK:    15: [B6.14] (BindTemporary)
 // CHECK:     Preds (1): B7
 // CHECK:     Succs (1): B4
@@ -839,7 +839,7 @@ int testConsistencyNestedNormalReturn(bool value) {
 // CHECK:     3: [B11.2] (ImplicitCastExpr, NoOp, const class A)
 // CHECK:     4: [B11.3]
 // WARNINGS:     5: [B11.4] (CXXConstructExpr, class A)
-// ANALYZER:     5: [B11.4] (CXXConstructExpr, [B11.6], class A)
+// ANALYZER:     5: [B11.4] (CXXConstructExpr, [B11.6], [B10.3], class A)
 // CHECK:     6: [B11.5] (BindTemporary)
 // CHECK:     Preds (1): B13
 // CHECK:     Succs (1): B10
@@ -860,7 +860,7 @@ int testConsistencyNestedNormalReturn(bool value) {
 // CHECK:    12: [B12.11] (ImplicitCastExpr, NoOp, const class A)
 // CHECK:    13: [B12.12]
 // WARNINGS:    14: [B12.13] (CXXConstructExpr, class A)
-// ANALYZER:    14: [B12.13] (CXXConstructExpr, [B12.15], class A)
+// ANALYZER:    14: [B12.13] (CXXConstructExpr, [B12.15], [B10.3], class A)
 // CHECK:    15: [B12.14] (BindTemporary)
 // CHECK:     Preds (1): B13
 // CHECK:     Succs (1): B10