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(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; +}