return false;
}
+static void EmitLValueForAnyFieldInitialization(CodeGenFunction &CGF,
+ CXXCtorInitializer *MemberInit,
+ LValue &LHS) {
+ FieldDecl *Field = MemberInit->getAnyMember();
+ if (MemberInit->isIndirectMemberInitializer()) {
+ // If we are initializing an anonymous union field, drill down to the field.
+ IndirectFieldDecl *IndirectField = MemberInit->getIndirectMember();
+ for (const auto *I : IndirectField->chain())
+ LHS = CGF.EmitLValueForFieldInitialization(LHS, cast<FieldDecl>(I));
+ } else {
+ LHS = CGF.EmitLValueForFieldInitialization(LHS, Field);
+ }
+}
+
static void EmitMemberInitializer(CodeGenFunction &CGF,
const CXXRecordDecl *ClassDecl,
CXXCtorInitializer *MemberInit,
QualType RecordTy = CGF.getContext().getTypeDeclType(ClassDecl);
LValue LHS = CGF.MakeNaturalAlignAddrLValue(ThisPtr, RecordTy);
- if (MemberInit->isIndirectMemberInitializer()) {
- // If we are initializing an anonymous union field, drill down to
- // the field.
- IndirectFieldDecl *IndirectField = MemberInit->getIndirectMember();
- for (const auto *I : IndirectField->chain())
- LHS = CGF.EmitLValueForFieldInitialization(LHS, cast<FieldDecl>(I));
- FieldType = MemberInit->getIndirectMember()->getAnonField()->getType();
- } else {
- LHS = CGF.EmitLValueForFieldInitialization(LHS, Field);
- }
+ EmitLValueForAnyFieldInitialization(CGF, MemberInit, LHS);
// Special case: if we are in a copy or move constructor, and we are copying
// an array of PODs or classes with trivial copy constructors, ignore the
CopyingValueRepresentation CVR(CGF);
EmitMemberInitializer(CGF, ConstructorDecl->getParent(),
AggregatedInits[0], ConstructorDecl, Args);
+ AggregatedInits.clear();
}
reset();
return;
LValue LHS = CGF.MakeNaturalAlignAddrLValue(ThisPtr, RecordTy);
for (unsigned i = 0; i < AggregatedInits.size(); ++i) {
- QualType FieldType = AggregatedInits[i]->getMember()->getType();
+ CXXCtorInitializer *MemberInit = AggregatedInits[i];
+ QualType FieldType = MemberInit->getAnyMember()->getType();
QualType::DestructionKind dtorKind = FieldType.isDestructedType();
- if (CGF.needsEHCleanup(dtorKind))
- CGF.pushEHDestroy(dtorKind, LHS.getAddress(), FieldType);
+ if (!CGF.needsEHCleanup(dtorKind))
+ continue;
+ LValue FieldLHS = LHS;
+ EmitLValueForAnyFieldInitialization(CGF, MemberInit, FieldLHS);
+ CGF.pushEHDestroy(dtorKind, FieldLHS.getAddress(), FieldType);
}
}
--- /dev/null
+// 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;
+}
--- /dev/null
+// 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;
+}