PR35039: Materialize temporary objects before wrapping them in an
authorRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 28 Oct 2017 18:59:51 +0000 (18:59 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 28 Oct 2017 18:59:51 +0000 (18:59 +0000)
OpaqueValueExpr in a GNU binary conditional expression.

It's not meaningful for a non-materialized temporary object to be used as a
common subexpression of multiple expressions.

llvm-svn: 316836

clang/lib/Sema/SemaExpr.cpp
clang/test/Analysis/temp-obj-dtors-cfg-output.cpp
clang/test/CodeGenCXX/cxx1z-copy-omission.cpp

index 1d8b9bc..d80237d 100644 (file)
@@ -7242,6 +7242,16 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
       commonExpr = commonRes.get();
     }
 
+    // If the common expression is a class or array prvalue, materialize it
+    // so that we can safely refer to it multiple times.
+    if (commonExpr->isRValue() && (commonExpr->getType()->isRecordType() ||
+                                   commonExpr->getType()->isArrayType())) {
+      ExprResult MatExpr = TemporaryMaterializationConversion(commonExpr);
+      if (MatExpr.isInvalid())
+        return ExprError();
+      commonExpr = MatExpr.get();
+    }
+
     opaqueValue = new (Context) OpaqueValueExpr(commonExpr->getExprLoc(),
                                                 commonExpr->getType(),
                                                 commonExpr->getValueKind(),
index 372443b..05b6a31 100644 (file)
@@ -834,7 +834,8 @@ int testConsistencyNestedNormalReturn(bool value) {
 // CHECK:     Preds (1): B4
 // CHECK:     Succs (1): B1
 // CHECK:   [B4]
-// CHECK:     1: [B7.2] ?: [B6.6]
+// CXX98:     1: [B7.2] ?: [B6.6]
+// CXX11:     1: [B7.3] ?: [B6.6]
 // CHECK:     2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
 // CHECK:     3: [B4.2]
 // CHECK:     4: [B4.3] (CXXConstructExpr, class A)
@@ -843,10 +844,13 @@ int testConsistencyNestedNormalReturn(bool value) {
 // CHECK:     Preds (2): B5 B6
 // CHECK:     Succs (2): B3 B2
 // CHECK:   [B5]
-// CHECK:     1: [B7.2] (ImplicitCastExpr, NoOp, const class A)
-// CHECK:     2: [B5.1]
-// CHECK:     3: [B5.2] (CXXConstructExpr, class A)
-// CHECK:     4: [B5.3] (BindTemporary)
+// CXX98:     1: [B7.2] (ImplicitCastExpr, NoOp, const class A)
+// CXX98:     2: [B5.1]
+// CXX98:     3: [B5.2] (CXXConstructExpr, class A)
+// CXX98:     4: [B5.3] (BindTemporary)
+// CXX11:     1: [B7.3] (ImplicitCastExpr, NoOp, const class A)
+// CXX11:     2: [B5.1] (CXXConstructExpr, class A)
+// CXX11:     3: [B5.2] (BindTemporary)
 // CHECK:     Preds (1): B7
 // CHECK:     Succs (1): B4
 // CHECK:   [B6]
@@ -861,10 +865,15 @@ int testConsistencyNestedNormalReturn(bool value) {
 // CHECK:   [B7]
 // CHECK:     1: A() (CXXConstructExpr, class A)
 // CHECK:     2: [B7.1] (BindTemporary)
-// CHECK:     3: [B7.2].operator bool
-// CHECK:     4: [B7.2]
-// CHECK:     5: [B7.4] (ImplicitCastExpr, UserDefinedConversion, _Bool)
-// CHECK:     T: [B7.5] ? ... : ...
+// CXX98:     3: [B7.2].operator bool
+// CXX98:     4: [B7.2]
+// CXX98:     5: [B7.4] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX98:     T: [B7.5] ? ... : ...
+// CXX11:     3: [B7.2]
+// CXX11:     4: [B7.3].operator bool
+// CXX11:     5: [B7.3]
+// CXX11:     6: [B7.5] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX11:     T: [B7.6] ? ... : ...
 // CHECK:     Preds (1): B8
 // CHECK:     Succs (2): B5 B6
 // CHECK:   [B0 (EXIT)]
@@ -886,7 +895,8 @@ int testConsistencyNestedNormalReturn(bool value) {
 // CHECK:     Preds (1): B4
 // CHECK:     Succs (1): B1
 // CHECK:   [B4]
-// CHECK:     1: [B7.4] ?: [B6.6]
+// CXX98:     1: [B7.4] ?: [B6.6]
+// CXX11:     1: [B7.5] ?: [B6.6]
 // CHECK:     2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
 // CHECK:     3: [B4.2]
 // CHECK:     4: [B7.2]([B4.3])
@@ -894,10 +904,13 @@ int testConsistencyNestedNormalReturn(bool value) {
 // CHECK:     Preds (2): B5 B6
 // CHECK:     Succs (2): B3 B2
 // CHECK:   [B5]
-// CHECK:     1: [B7.4] (ImplicitCastExpr, NoOp, const class A)
-// CHECK:     2: [B5.1]
-// CHECK:     3: [B5.2] (CXXConstructExpr, class A)
-// CHECK:     4: [B5.3] (BindTemporary)
+// CXX98:     1: [B7.4] (ImplicitCastExpr, NoOp, const class A)
+// CXX98:     2: [B5.1]
+// CXX98:     3: [B5.2] (CXXConstructExpr, class A)
+// CXX98:     4: [B5.3] (BindTemporary)
+// CXX11:     1: [B7.5] (ImplicitCastExpr, NoOp, const class A)
+// CXX11:     2: [B5.1] (CXXConstructExpr, class A)
+// CXX11:     3: [B5.2] (BindTemporary)
 // CHECK:     Preds (1): B7
 // CHECK:     Succs (1): B4
 // CHECK:   [B6]
@@ -914,10 +927,15 @@ int testConsistencyNestedNormalReturn(bool value) {
 // CHECK:     2: [B7.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
 // CHECK:     3: A() (CXXConstructExpr, class A)
 // CHECK:     4: [B7.3] (BindTemporary)
-// CHECK:     5: [B7.4].operator bool
-// CHECK:     6: [B7.4]
-// CHECK:     7: [B7.6] (ImplicitCastExpr, UserDefinedConversion, _Bool)
-// CHECK:     T: [B7.7] ? ... : ...
+// CXX98:     5: [B7.4].operator bool
+// CXX98:     6: [B7.4]
+// CXX98:     7: [B7.6] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX98:     T: [B7.7] ? ... : ...
+// CXX11:     5: [B7.4]
+// CXX11:     6: [B7.5].operator bool
+// CXX11:     7: [B7.5]
+// CXX11:     8: [B7.7] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX11:     T: [B7.8] ? ... : ...
 // CHECK:     Preds (2): B8 B9
 // CHECK:     Succs (2): B5 B6
 // CHECK:   [B8]
@@ -925,7 +943,8 @@ int testConsistencyNestedNormalReturn(bool value) {
 // CHECK:     Preds (1): B9
 // CHECK:     Succs (1): B7
 // CHECK:   [B9]
-// CHECK:     1: [B12.2] ?: [B11.6]
+// CXX98:     1: [B12.2] ?: [B11.6]
+// CXX11:     1: [B12.3] ?: [B11.6]
 // CHECK:     2: [B9.1] (ImplicitCastExpr, NoOp, const class A)
 // CHECK:     3: [B9.2]
 // CHECK:     4: const A &a = A() ?: A();
@@ -933,10 +952,13 @@ int testConsistencyNestedNormalReturn(bool value) {
 // CHECK:     Preds (2): B10 B11
 // CHECK:     Succs (2): B8 B7
 // CHECK:   [B10]
-// CHECK:     1: [B12.2] (ImplicitCastExpr, NoOp, const class A)
-// CHECK:     2: [B10.1]
-// CHECK:     3: [B10.2] (CXXConstructExpr, class A)
-// CHECK:     4: [B10.3] (BindTemporary)
+// CXX98:     1: [B12.2] (ImplicitCastExpr, NoOp, const class A)
+// CXX98:     2: [B10.1]
+// CXX98:     3: [B10.2] (CXXConstructExpr, class A)
+// CXX98:     4: [B10.3] (BindTemporary)
+// CXX11:     1: [B12.3] (ImplicitCastExpr, NoOp, const class A)
+// CXX11:     2: [B10.1] (CXXConstructExpr, class A)
+// CXX11:     3: [B10.2] (BindTemporary)
 // CHECK:     Preds (1): B12
 // CHECK:     Succs (1): B9
 // CHECK:   [B11]
@@ -951,10 +973,15 @@ int testConsistencyNestedNormalReturn(bool value) {
 // CHECK:   [B12]
 // CHECK:     1: A() (CXXConstructExpr, class A)
 // CHECK:     2: [B12.1] (BindTemporary)
-// CHECK:     3: [B12.2].operator bool
-// CHECK:     4: [B12.2]
-// CHECK:     5: [B12.4] (ImplicitCastExpr, UserDefinedConversion, _Bool)
-// CHECK:     T: [B12.5] ? ... : ...
+// CXX98:     3: [B12.2].operator bool
+// CXX98:     4: [B12.2]
+// CXX98:     5: [B12.4] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX98:     T: [B12.5] ? ... : ...
+// CXX11:     3: [B12.2]
+// CXX11:     4: [B12.3].operator bool
+// CXX11:     5: [B12.3]
+// CXX11:     6: [B12.5] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX11:     T: [B12.6] ? ... : ...
 // CHECK:     Preds (1): B13
 // CHECK:     Succs (2): B10 B11
 // CHECK:   [B0 (EXIT)]
index 234e4b1..b33a218 100644 (file)
@@ -6,6 +6,8 @@ struct A {
   A(const A&);
   ~A();
 
+  operator bool();
+
   int arr[10];
 };
 
@@ -79,3 +81,27 @@ void i() {
 
   // CHECK-LABEL: }
 }
+
+// CHECK-LABEL: define {{.*}} @_Z1jv(
+void j() {
+  // CHECK:   alloca %{{.*}}*
+  // CHECK:   %[[OUTERTEMP:.*]] = alloca %{{.*}}
+  // CHECK:   %[[INNERTEMP:.*]] = alloca %{{.*}}
+  // CHECK:   call void @_ZN1AC1Ei(%{{.*}} %[[INNERTEMP]], i32 1)
+  // CHECK:   call zeroext i1 @_ZN1AcvbEv(%{{.*}} %[[INNERTEMP]])
+  // CHECK:   br i1
+  //
+  // CHECK:   call void @_ZN1AC1EOS_(%{{.*}} %[[OUTERTEMP]], %{{.*}} %[[INNERTEMP]])
+  // CHECK:   br label
+  //
+  // CHECK:   call void @_ZN1AC1Ei(%{{.*}} %[[OUTERTEMP]], i32 2)
+  // CHECK:   br label
+  //
+  // CHECK:   call void @_ZN1AD1Ev(%{{.*}} %[[INNERTEMP]])
+  A &&a = A(1) ?: A(2);
+
+  // CHECK:   call void @_Z1iv()
+  i();
+
+  // CHECK:   call void @_ZN1AD1Ev(%{{.*}} %[[OUTERTEMP]])
+}