d.zobnin.bugzilla added reviewers: rsmith, rjmccall.
d.zobnin.bugzilla added a subscriber: cfe-commits.

The fix is to remove duplicate copy-initialization of the only memcpy-able 
struct member and to correct the address of aggregately initialized members in 
destructors' calls during stack unwinding (in order to obtain address of struct 
member by using GEP instead of 'bitcast').

Repository:
  rL LLVM

http://reviews.llvm.org/D10990

Files:
  lib/CodeGen/CGClass.cpp
  test/CodeGen/eh-aggregated-inits-unwind.cpp
  test/CodeGen/eh-aggregated-inits.cpp

Index: lib/CodeGen/CGClass.cpp
===================================================================
--- lib/CodeGen/CGClass.cpp
+++ lib/CodeGen/CGClass.cpp
@@ -1078,6 +1078,7 @@
           CopyingValueRepresentation CVR(CGF);
           EmitMemberInitializer(CGF, ConstructorDecl->getParent(),
                                 AggregatedInits[0], ConstructorDecl, Args);
+          AggregatedInits.clear();
         }
         reset();
         return;
@@ -1094,10 +1095,26 @@
       LValue LHS = CGF.MakeNaturalAlignAddrLValue(ThisPtr, RecordTy);
 
       for (unsigned i = 0; i < AggregatedInits.size(); ++i) {
-        QualType FieldType = AggregatedInits[i]->getMember()->getType();
+        const auto *MemberInit = AggregatedInits[i];
+        FieldDecl *Field = MemberInit->getMember();
+        IndirectFieldDecl *IndirectField = MemberInit->getIndirectMember();
+        LValue FieldLHS = LHS;
+        QualType FieldType =
+            MemberInit->isIndirectMemberInitializer()
+                ? IndirectField->getAnonField()->getType()
+                : Field->getType();
         QualType::DestructionKind dtorKind = FieldType.isDestructedType();
-        if (CGF.needsEHCleanup(dtorKind))
-          CGF.pushEHDestroy(dtorKind, LHS.getAddress(), FieldType);
+        if (!CGF.needsEHCleanup(dtorKind))
+          continue;
+        if (MemberInit->isIndirectMemberInitializer())
+          // If we are initializing an anonymous union field, drill down to
+          // the field.
+          for (const auto *I : IndirectField->chain())
+            FieldLHS = CGF.EmitLValueForFieldInitialization(FieldLHS,
+                                                            cast<FieldDecl>(I));
+        else
+          FieldLHS = CGF.EmitLValueForFieldInitialization(FieldLHS, Field);
+        CGF.pushEHDestroy(dtorKind, FieldLHS.getAddress(), FieldType);
       }
     }
 
Index: test/CodeGen/eh-aggregated-inits-unwind.cpp
===================================================================
--- test/CodeGen/eh-aggregated-inits-unwind.cpp
+++ test/CodeGen/eh-aggregated-inits-unwind.cpp
@@ -0,0 +1,47 @@
+// Check that destructors of memcpy-able struct members are called properly
+// during stack unwinding after an exception.
+//
+// Check that destructor's argument (address of member to be destroyed) is
+// obtained by taking offset from struct, not by bitcasting pointers.
+//
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -O0 -fno-elide-constructors -emit-llvm %s -o - | FileCheck %s
+
+struct ImplicitCopy {
+  int id;
+  ImplicitCopy() { id = 10; }
+  ~ImplicitCopy() { id = 20; }
+};
+
+struct ThrowCopy {
+  int id;
+  ThrowCopy() { id = 15; }
+  ThrowCopy(const ThrowCopy &x) {
+    id = 25;
+    throw 1;
+  }
+  ~ThrowCopy() { id = 35; }
+};
+
+struct Container {
+  int id;
+  ImplicitCopy o1;
+  ThrowCopy o2;
+
+  Container() { id = 1000; }
+  ~Container() { id = 2000; }
+};
+
+int main() {
+  try {
+    Container c1;
+    // CHECK-LABEL: main
+    // CHECK: %{{.+}} = getelementptr inbounds %struct.Container, %struct.Container* %{{.+}}, i32 0, i32 1
+    // CHECK-NOT: %{{.+}} = bitcast %struct.Container* %{{.+}} to %struct.ImplicitCopy*
+    Container c2(c1);
+
+    return 2;
+  } catch (...) {
+    return 1;
+  }
+  return 0;
+}
Index: test/CodeGen/eh-aggregated-inits.cpp
===================================================================
--- test/CodeGen/eh-aggregated-inits.cpp
+++ test/CodeGen/eh-aggregated-inits.cpp
@@ -0,0 +1,46 @@
+// Check that initialization of the only one memcpy-able struct member will not
+// be performed twice after successful non-trivial initializtion of the second
+// member.
+//
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -O0 -fno-elide-constructors -emit-llvm %s -o - | FileCheck %s
+
+int globId = 0;
+
+struct ImplicitCopy {
+  int id;
+
+  ImplicitCopy() { id = 10; }
+  ~ImplicitCopy() { id = 20; }
+};
+
+struct ExplicitCopy {
+  int id;
+
+  ExplicitCopy() { id = 15; }
+  ExplicitCopy(const ExplicitCopy &x) { id = 25; }
+  ~ExplicitCopy() { id = 35; }
+};
+
+struct Container {
+  ImplicitCopy o1; // memcpy-able member.
+  ExplicitCopy o2; // non-trivial initialization.
+
+  Container() { globId = 1000; }
+  ~Container() { globId = 2000; }
+};
+
+int main() {
+  try {
+    Container c1;
+    // CHECK-DAG: call void @llvm.memcpy
+    // CHECK-DAG: declare void @llvm.memcpy
+    // CHECK-NOT: @llvm.memcpy
+    Container c2(c1);
+
+    return 2;
+  }
+  catch (...) {
+    return 1;
+  }
+  return 0;
+}
_______________________________________________
cfe-commits mailing list
cfe-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to