r276180 - When copying an array into a lambda, destroy temporaries from

John McCall via cfe-commits cfe-commits at lists.llvm.org
Wed Jul 20 14:02:44 PDT 2016


Author: rjmccall
Date: Wed Jul 20 16:02:43 2016
New Revision: 276180

URL: http://llvm.org/viewvc/llvm-project?rev=276180&view=rev
Log:
When copying an array into a lambda, destroy temporaries from
the copy-constructor immediately and enter a partial array
cleanup for previously-copied elements.

Fixes PR28595.

Modified:
    cfe/trunk/lib/CodeGen/CGClass.cpp
    cfe/trunk/test/CodeGenCXX/lambda-expressions.cpp

Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=276180&r1=276179&r2=276180&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGClass.cpp Wed Jul 20 16:02:43 2016
@@ -562,6 +562,20 @@ static void EmitBaseInitializer(CodeGenF
                                           isBaseVirtual);
 }
 
+/// Initialize a member of aggregate type using the given expression
+/// as an initializer.
+///
+/// The member may be an array.  If so:
+/// - the destination l-value will be a pointer of the *base* element type,
+/// - ArrayIndexVar will be a pointer to a variable containing the current
+///   index within the destination array, and
+/// - ArrayIndexes will be an array of index variables, one for each level
+///   of array nesting, which will need to be updated as appropriate for the
+///   array structure.
+///
+/// On an array, this function will invoke itself recursively.  Each time,
+/// it drills into one nesting level of the member type and sets up a
+/// loop updating the appropriate array index variable.
 static void EmitAggMemberInitializer(CodeGenFunction &CGF,
                                      LValue LHS,
                                      Expr *Init,
@@ -569,10 +583,18 @@ static void EmitAggMemberInitializer(Cod
                                      QualType T,
                                      ArrayRef<VarDecl *> ArrayIndexes,
                                      unsigned Index) {
+  assert(ArrayIndexVar.isValid() == (ArrayIndexes.size() != 0));
+
   if (Index == ArrayIndexes.size()) {
     LValue LV = LHS;
 
+    Optional<CodeGenFunction::RunCleanupsScope> Scope;
+
     if (ArrayIndexVar.isValid()) {
+      // When we're processing an array, the temporaries from each
+      // element's construction are destroyed immediately.
+      Scope.emplace(CGF);
+
       // If we have an array index variable, load it and use it as an offset.
       // Then, increment the value.
       llvm::Value *Dest = LHS.getPointer();
@@ -586,6 +608,19 @@ static void EmitAggMemberInitializer(Cod
       CharUnits EltSize = CGF.getContext().getTypeSizeInChars(T);
       CharUnits Align = LV.getAlignment().alignmentOfArrayElement(EltSize);
       LV.setAddress(Address(Dest, Align));
+
+      // Enter a partial-array EH cleanup to destroy previous members
+      // of the array if this initialization throws.
+      if (CGF.CGM.getLangOpts().Exceptions) {
+        if (auto DtorKind = T.isDestructedType()) {
+          if (CGF.needsEHCleanup(DtorKind)) {
+            CGF.pushRegularPartialArrayCleanup(LHS.getPointer(),
+                                               LV.getPointer(), T,
+                                               LV.getAlignment(),
+                                               CGF.getDestroyer(DtorKind));
+          }
+        }
+      }
     }
 
     switch (CGF.getEvaluationKind(T)) {

Modified: cfe/trunk/test/CodeGenCXX/lambda-expressions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/lambda-expressions.cpp?rev=276180&r1=276179&r2=276180&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/lambda-expressions.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/lambda-expressions.cpp Wed Jul 20 16:02:43 2016
@@ -116,6 +116,56 @@ int *PR22071_fun() {
   return [&] { return &y; }();
 }
 
+namespace pr28595 {
+  struct Temp {
+    Temp();
+    ~Temp() noexcept(false);
+  };
+  struct A {
+    A();
+    A(const A &a, const Temp &temp = Temp());
+    ~A();
+  };
+
+  // CHECK-LABEL: define void @_ZN7pr285954testEv()
+  void test() {
+    // CHECK: [[ARRAY:%.*]] = alloca [3 x [5 x [[A:%.*]]]], align 1
+    // CHECK: [[DESTIDX:%.*]] = alloca i64, align 8
+    // CHECK: [[I0:%.*]] = alloca i64, align 8
+    // CHECK: [[I1:%.*]] = alloca i64, align 8
+    A array[3][5];
+
+    // CHECK: [[DESTBASE:%.*]] = bitcast [3 x [5 x [[A]]]]* {{.*}} to [[A]]*
+    // CHECK: store i64 0, i64* [[DESTIDX]], align 8
+    // CHECK: store i64 0, i64* [[I0]], align 8
+    // CHECK: br label
+    // CHECK: icmp ult
+    // CHECK: store i64 0, i64* [[I1]], align 8
+    // CHECK: br label
+    // CHECK: icmp ult
+    // CHECK: [[T0:%.*]] = load i64, i64* [[DESTIDX]], align 8
+    // CHECK: [[DEST:%.*]] = getelementptr inbounds [[A]], [[A]]* [[DESTBASE]], i64 [[T0]]
+    // CHECK: invoke void @_ZN7pr285954TempC1Ev
+    // CHECK: invoke void @_ZN7pr285951AC1ERKS0_RKNS_4TempE
+    // CHECK: invoke void @_ZN7pr285954TempD1Ev
+    // CHECK: landingpad
+    // CHECK: landingpad
+    // CHECK: br label [[CLEANUP:%.*]]{{$}}
+    // CHECK: landingpad
+    // CHECK: invoke void @_ZN7pr285954TempD1Ev
+    // CHECK: br label [[CLEANUP]]
+    // CHECK: icmp eq [[A]]* [[DESTBASE]], [[DEST]]
+    // CHECK: [[T0:%.*]] = phi [[A]]*
+    // CHECK: [[T1:%.*]] = getelementptr inbounds [[A]], [[A]]* [[T0]], i64 -1
+    // CHECK: call void @_ZN7pr285951AD1Ev([[A]]* [[T1]])
+    // CHECK: icmp eq [[A]]* [[T1]], [[DESTBASE]]
+    (void) [array]{};
+
+    //   Skip over the initialization loop.
+    // CHECK: [[BEGIN:%.*]] = getelementptr inbounds [3 x [5 x [[A]]]], [3 x [5 x [[A]]]]* [[ARRAY]], i32 0, i32 0, i32 0
+  }
+}
+
 // CHECK-LABEL: define internal void @"_ZZ1e1ES_bEN3$_5D2Ev"
 
 // CHECK-LABEL: define internal i32 @"_ZZ1fvEN3$_68__invokeEii"
@@ -126,9 +176,9 @@ int *PR22071_fun() {
 // CHECK-NEXT: call i32 @"_ZZ1fvENK3$_6clEii"
 // CHECK-NEXT: ret i32
 
-// CHECK-LABEL: define internal void @"_ZZ1hvEN4$_108__invokeEv"(%struct.A* noalias sret %agg.result) {{.*}} {
+// CHECK-LABEL: define internal void @"_ZZ1hvEN4$_118__invokeEv"(%struct.A* noalias sret %agg.result) {{.*}} {
 // CHECK-NOT: =
-// CHECK: call void @"_ZZ1hvENK4$_10clEv"(%struct.A* sret %agg.result,
+// CHECK: call void @"_ZZ1hvENK4$_11clEv"(%struct.A* sret %agg.result,
 // CHECK-NEXT: ret void
 struct A { ~A(); };
 void h() {




More information about the cfe-commits mailing list