forked from OSchip/llvm-project
Destroy arrays and ARC fields when throwing out of ctors.
Previously we were only handling non-array fields of class type. Testcases derived from a patch by WenHan Gu. llvm-svn: 174146
This commit is contained in:
parent
bc0e5c0114
commit
12cc42aa1b
|
@ -532,21 +532,6 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF,
|
|||
CGF.EmitBlock(AfterFor, true);
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct CallMemberDtor : EHScopeStack::Cleanup {
|
||||
llvm::Value *V;
|
||||
CXXDestructorDecl *Dtor;
|
||||
|
||||
CallMemberDtor(llvm::Value *V, CXXDestructorDecl *Dtor)
|
||||
: V(V), Dtor(Dtor) {}
|
||||
|
||||
void Emit(CodeGenFunction &CGF, Flags flags) {
|
||||
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false,
|
||||
/*Delegating=*/false, V);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static void EmitMemberInitializer(CodeGenFunction &CGF,
|
||||
const CXXRecordDecl *ClassDecl,
|
||||
CXXCtorInitializer *MemberInit,
|
||||
|
@ -652,22 +637,13 @@ void CodeGenFunction::EmitInitializerForField(FieldDecl *Field,
|
|||
|
||||
EmitAggMemberInitializer(*this, LHS, Init, ArrayIndexVar, FieldType,
|
||||
ArrayIndexes, 0);
|
||||
|
||||
if (!CGM.getLangOpts().Exceptions)
|
||||
return;
|
||||
|
||||
// FIXME: If we have an array of classes w/ non-trivial destructors,
|
||||
// we need to destroy in reverse order of construction along the exception
|
||||
// path.
|
||||
const RecordType *RT = FieldType->getAs<RecordType>();
|
||||
if (!RT)
|
||||
return;
|
||||
|
||||
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
|
||||
if (!RD->hasTrivialDestructor())
|
||||
EHStack.pushCleanup<CallMemberDtor>(EHCleanup, LHS.getAddress(),
|
||||
RD->getDestructor());
|
||||
}
|
||||
|
||||
// Ensure that we destroy this object if an exception is thrown
|
||||
// later in the constructor.
|
||||
QualType::DestructionKind dtorKind = FieldType.isDestructedType();
|
||||
if (needsEHCleanup(dtorKind))
|
||||
pushEHDestroy(dtorKind, LHS.getAddress(), FieldType);
|
||||
}
|
||||
|
||||
/// Checks whether the given constructor is a valid subject for the
|
||||
|
|
|
@ -1242,7 +1242,18 @@ CodeGenFunction::getDestroyer(QualType::DestructionKind kind) {
|
|||
llvm_unreachable("Unknown DestructionKind");
|
||||
}
|
||||
|
||||
/// pushDestroy - Push the standard destructor for the given type.
|
||||
/// pushEHDestroy - Push the standard destructor for the given type as
|
||||
/// an EH-only cleanup.
|
||||
void CodeGenFunction::pushEHDestroy(QualType::DestructionKind dtorKind,
|
||||
llvm::Value *addr, QualType type) {
|
||||
assert(dtorKind && "cannot push destructor for trivial type");
|
||||
assert(needsEHCleanup(dtorKind));
|
||||
|
||||
pushDestroy(EHCleanup, addr, type, getDestroyer(dtorKind), true);
|
||||
}
|
||||
|
||||
/// pushDestroy - Push the standard destructor for the given type as
|
||||
/// at least a normal cleanup.
|
||||
void CodeGenFunction::pushDestroy(QualType::DestructionKind dtorKind,
|
||||
llvm::Value *addr, QualType type) {
|
||||
assert(dtorKind && "cannot push destructor for trivial type");
|
||||
|
|
|
@ -1282,6 +1282,8 @@ public:
|
|||
|
||||
void pushDestroy(QualType::DestructionKind dtorKind,
|
||||
llvm::Value *addr, QualType type);
|
||||
void pushEHDestroy(QualType::DestructionKind dtorKind,
|
||||
llvm::Value *addr, QualType type);
|
||||
void pushDestroy(CleanupKind kind, llvm::Value *addr, QualType type,
|
||||
Destroyer *destroyer, bool useEHCleanupForArray);
|
||||
void emitDestroy(llvm::Value *addr, QualType type, Destroyer *destroyer,
|
||||
|
|
|
@ -451,3 +451,70 @@ namespace test10 {
|
|||
// CHECK: invoke void @__cxa_rethrow()
|
||||
// CHECK: unreachable
|
||||
}
|
||||
|
||||
// Ensure that an exception in a constructor destroys
|
||||
// already-constructed array members. PR14514
|
||||
namespace test11 {
|
||||
struct A {
|
||||
A();
|
||||
~A() {}
|
||||
};
|
||||
|
||||
struct C {
|
||||
A single;
|
||||
A array[2][3];
|
||||
|
||||
C();
|
||||
};
|
||||
|
||||
C::C() {
|
||||
throw 0;
|
||||
}
|
||||
// CHECK: define void @_ZN6test111CC2Ev(
|
||||
// CHECK: [[THIS:%.*]] = load [[C:%.*]]** {{%.*}}
|
||||
// Construct single.
|
||||
// CHECK-NEXT: [[SINGLE:%.*]] = getelementptr inbounds [[C]]* [[THIS]], i32 0, i32 0
|
||||
// CHECK-NEXT: call void @_ZN6test111AC1Ev([[A:%.*]]* [[SINGLE]])
|
||||
// Construct array.
|
||||
// CHECK-NEXT: [[ARRAY:%.*]] = getelementptr inbounds [[C]]* [[THIS]], i32 0, i32 1
|
||||
// CHECK-NEXT: [[ARRAYBEGIN:%.*]] = getelementptr inbounds [2 x [3 x [[A]]]]* [[ARRAY]], i32 0, i32 0, i32 0
|
||||
// CHECK-NEXT: [[ARRAYEND:%.*]] = getelementptr inbounds [[A]]* [[ARRAYBEGIN]], i64 6
|
||||
// CHECK-NEXT: br label
|
||||
// CHECK: [[CUR:%.*]] = phi [[A]]* [ [[ARRAYBEGIN]], {{%.*}} ], [ [[NEXT:%.*]], {{%.*}} ]
|
||||
// CHECK-NEXT: invoke void @_ZN6test111AC1Ev([[A:%.*]]* [[CUR]])
|
||||
// CHECK: [[NEXT]] = getelementptr inbounds [[A]]* [[CUR]], i64 1
|
||||
// CHECK-NEXT: [[DONE:%.*]] = icmp eq [[A]]* [[NEXT]], [[ARRAYEND]]
|
||||
// CHECK-NEXT: br i1 [[DONE]],
|
||||
// throw 0;
|
||||
// CHECK: invoke void @__cxa_throw(
|
||||
// Landing pad 1, from constructor in array-initialization loop:
|
||||
// CHECK: landingpad
|
||||
// - First, destroy already-constructed bits of array.
|
||||
// CHECK: [[EMPTY:%.*]] = icmp eq [[A]]* [[ARRAYBEGIN]], [[CUR]]
|
||||
// CHECK-NEXT: br i1 [[EMPTY]]
|
||||
// CHECK: [[AFTER:%.*]] = phi [[A]]* [ [[CUR]], {{%.*}} ], [ [[ELT:%.*]], {{%.*}} ]
|
||||
// CHECK-NEXT: [[ELT]] = getelementptr inbounds [[A]]* [[AFTER]], i64 -1
|
||||
// CHECK-NEXT: invoke void @_ZN6test111AD1Ev([[A]]* [[ELT]])
|
||||
// CHECK: [[DONE:%.*]] = icmp eq [[A]]* [[ELT]], [[ARRAYBEGIN]]
|
||||
// CHECK-NEXT: br i1 [[DONE]],
|
||||
// - Next, chain to cleanup for single.
|
||||
// CHECK: br label
|
||||
// Landing pad 2, from throw site.
|
||||
// CHECK: landingpad
|
||||
// - First, destroy all of array.
|
||||
// CHECK: [[ARRAYBEGIN:%.*]] = getelementptr inbounds [2 x [3 x [[A]]]]* [[ARRAY]], i32 0, i32 0, i32 0
|
||||
// CHECK-NEXT: [[ARRAYEND:%.*]] = getelementptr inbounds [[A]]* [[ARRAYBEGIN]], i64 6
|
||||
// CHECK-NEXT: br label
|
||||
// CHECK: [[AFTER:%.*]] = phi [[A]]* [ [[ARRAYEND]], {{%.*}} ], [ [[ELT:%.*]], {{%.*}} ]
|
||||
// CHECK-NEXT: [[ELT]] = getelementptr inbounds [[A]]* [[AFTER]], i64 -1
|
||||
// CHECK-NEXT: invoke void @_ZN6test111AD1Ev([[A]]* [[ELT]])
|
||||
// CHECK: [[DONE:%.*]] = icmp eq [[A]]* [[ELT]], [[ARRAYBEGIN]]
|
||||
// CHECK-NEXT: br i1 [[DONE]],
|
||||
// - Next, chain to cleanup for single.
|
||||
// CHECK: br label
|
||||
// Finally, the cleanup for single.
|
||||
// CHECK: invoke void @_ZN6test111AD1Ev([[A]]* [[SINGLE]])
|
||||
// CHECK: br label
|
||||
// CHECK: resume
|
||||
// (After this is a terminate landingpad.)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fexceptions -fobjc-exceptions -fcxx-exceptions -fobjc-runtime-has-weak -o - %s | FileCheck %s
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fexceptions -fobjc-exceptions -fcxx-exceptions -fobjc-runtime-has-weak -o - -fobjc-arc-exceptions %s | FileCheck %s
|
||||
|
||||
@class Ety;
|
||||
|
||||
|
@ -81,3 +81,42 @@ void test3(void) {
|
|||
// CHECK-NEXT: [[T0:%.*]] = bitcast [[ETY]]** [[E]] to i8**
|
||||
// CHECK-NEXT: call void @objc_destroyWeak(i8** [[T0]]) nounwind
|
||||
// CHECK-NEXT: call void @__cxa_end_catch() nounwind
|
||||
|
||||
namespace test4 {
|
||||
struct A {
|
||||
id single;
|
||||
id array[2][3];
|
||||
|
||||
A();
|
||||
};
|
||||
|
||||
A::A() {
|
||||
throw 0;
|
||||
}
|
||||
// CHECK: define void @_ZN5test41AC2Ev(
|
||||
// CHECK: [[THIS:%.*]] = load [[A:%.*]]** {{%.*}}
|
||||
// Construct single.
|
||||
// CHECK-NEXT: [[SINGLE:%.*]] = getelementptr inbounds [[A]]* [[THIS]], i32 0, i32 0
|
||||
// CHECK-NEXT: store i8* null, i8** [[SINGLE]], align 8
|
||||
// Construct array.
|
||||
// CHECK-NEXT: [[ARRAY:%.*]] = getelementptr inbounds [[A]]* [[THIS]], i32 0, i32 1
|
||||
// CHECK-NEXT: [[T0:%.*]] = bitcast [2 x [3 x i8*]]* [[ARRAY]] to i8*
|
||||
// CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 48, i32 8, i1 false)
|
||||
// throw 0;
|
||||
// CHECK: invoke void @__cxa_throw(
|
||||
// Landing pad from throw site:
|
||||
// CHECK: landingpad
|
||||
// - First, destroy all of array.
|
||||
// CHECK: [[ARRAYBEGIN:%.*]] = getelementptr inbounds [2 x [3 x i8*]]* [[ARRAY]], i32 0, i32 0, i32 0
|
||||
// CHECK-NEXT: [[ARRAYEND:%.*]] = getelementptr inbounds i8** [[ARRAYBEGIN]], i64 6
|
||||
// CHECK-NEXT: br label
|
||||
// CHECK: [[AFTER:%.*]] = phi i8** [ [[ARRAYEND]], {{%.*}} ], [ [[ELT:%.*]], {{%.*}} ]
|
||||
// CHECK-NEXT: [[ELT]] = getelementptr inbounds i8** [[AFTER]], i64 -1
|
||||
// CHECK-NEXT: call void @objc_storeStrong(i8** [[ELT]], i8* null) nounwind
|
||||
// CHECK-NEXT: [[DONE:%.*]] = icmp eq i8** [[ELT]], [[ARRAYBEGIN]]
|
||||
// CHECK-NEXT: br i1 [[DONE]],
|
||||
// - Next, destroy single.
|
||||
// CHECK: call void @objc_storeStrong(i8** [[SINGLE]], i8* null) nounwind
|
||||
// CHECK: br label
|
||||
// CHECK: resume
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue