]> granicus.if.org Git - clang/commitdiff
Merging r302817:
authorTom Stellard <tstellar@redhat.com>
Tue, 16 May 2017 13:33:48 +0000 (13:33 +0000)
committerTom Stellard <tstellar@redhat.com>
Tue, 16 May 2017 13:33:48 +0000 (13:33 +0000)
------------------------------------------------------------------------
r302817 | rsmith | 2017-05-11 14:58:24 -0400 (Thu, 11 May 2017) | 9 lines

PR22877: When constructing an array via a constructor with a default argument
in list-initialization, run cleanups for the default argument after each
iteration of the initialization loop.

We previously only ran the destructor for any temporary once, at the end of the
complete loop, rather than once per iteration!

Re-commit of r302750, reverted in r302776.

------------------------------------------------------------------------

git-svn-id: https://llvm.org/svn/llvm-project/cfe/branches/release_40@303167 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGExprAgg.cpp
test/CodeGenCXX/array-default-argument.cpp [new file with mode: 0644]

index 009244784e5046c5f9d44724bbbc6e3085456af3..b10a549338fddec21bcafe40b9d84ccf8a3d90b8 100644 (file)
@@ -505,12 +505,20 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
     currentElement->addIncoming(element, entryBB);
 
     // Emit the actual filler expression.
-    LValue elementLV =
-      CGF.MakeAddrLValue(Address(currentElement, elementAlign), elementType);
-    if (filler)
-      EmitInitializationToLValue(filler, elementLV);
-    else
-      EmitNullInitializationToLValue(elementLV);
+    {
+      // C++1z [class.temporary]p5:
+      //   when a default constructor is called to initialize an element of
+      //   an array with no corresponding initializer [...] the destruction of
+      //   every temporary created in a default argument is sequenced before
+      //   the construction of the next array element, if any
+      CodeGenFunction::RunCleanupsScope CleanupsScope(CGF);
+      LValue elementLV =
+        CGF.MakeAddrLValue(Address(currentElement, elementAlign), elementType);
+      if (filler)
+        EmitInitializationToLValue(filler, elementLV);
+      else
+        EmitNullInitializationToLValue(elementLV);
+    }
 
     // Move on to the next element.
     llvm::Value *nextElement =
diff --git a/test/CodeGenCXX/array-default-argument.cpp b/test/CodeGenCXX/array-default-argument.cpp
new file mode 100644 (file)
index 0000000..8376b4f
--- /dev/null
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s -triple %itanium_abi_triple | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -o - %s -triple %itanium_abi_triple -fexceptions -fcxx-exceptions | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-EH
+
+struct A {
+  A();
+  ~A();
+};
+
+struct B {
+  B(A = A());
+  ~B();
+};
+
+void f();
+// CHECK-LABEL: define void @_Z1gv()
+void g() {
+  // CHECK: br label %[[LOOP:.*]]
+
+  // [[LOOP]]:
+  // CHECK: {{call|invoke}} {{.*}} @_ZN1AC1Ev([[TEMPORARY:.*]])
+  // CHECK-EH:  unwind label %[[PARTIAL_ARRAY_LPAD:.*]]
+  // CHECK: {{call|invoke}} {{.*}} @_ZN1BC1E1A({{.*}}, [[TEMPORARY]])
+  // CHECK-EH:  unwind label %[[A_AND_PARTIAL_ARRAY_LPAD:.*]]
+  // CHECK: {{call|invoke}} {{.*}} @_ZN1AD1Ev([[TEMPORARY]])
+  // CHECK-EH:  unwind label %[[PARTIAL_ARRAY_LPAD]]
+  // CHECK: getelementptr {{.*}}, i{{[0-9]*}} 1
+  // CHECK: icmp eq
+  // CHECK: br i1 {{.*}} label %[[LOOP]]
+  B b[5];
+
+  // CHECK: {{call|invoke}} void @_Z1fv()
+  f();
+
+  // CHECK-NOT: @_ZN1AD1Ev(
+  // CHECK: {{call|invoke}} {{.*}} @_ZN1BD1Ev(
+}