r174146 - Destroy arrays and ARC fields when throwing out of ctors.
John McCall
rjmccall at apple.com
Thu Jan 31 21:11:40 PST 2013
Author: rjmccall
Date: Thu Jan 31 23:11:40 2013
New Revision: 174146
URL: http://llvm.org/viewvc/llvm-project?rev=174146&view=rev
Log:
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.
Modified:
cfe/trunk/lib/CodeGen/CGClass.cpp
cfe/trunk/lib/CodeGen/CGDecl.cpp
cfe/trunk/lib/CodeGen/CodeGenFunction.h
cfe/trunk/test/CodeGenCXX/exceptions.cpp
cfe/trunk/test/CodeGenObjCXX/arc-exceptions.mm
Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=174146&r1=174145&r2=174146&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGClass.cpp Thu Jan 31 23:11:40 2013
@@ -532,21 +532,6 @@ static void EmitAggMemberInitializer(Cod
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::EmitInitializerFor
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
Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=174146&r1=174145&r2=174146&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Thu Jan 31 23:11:40 2013
@@ -1242,7 +1242,18 @@ CodeGenFunction::getDestroyer(QualType::
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");
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=174146&r1=174145&r2=174146&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Thu Jan 31 23:11:40 2013
@@ -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,
Modified: cfe/trunk/test/CodeGenCXX/exceptions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/exceptions.cpp?rev=174146&r1=174145&r2=174146&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/exceptions.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/exceptions.cpp Thu Jan 31 23:11:40 2013
@@ -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.)
+}
Modified: cfe/trunk/test/CodeGenObjCXX/arc-exceptions.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/arc-exceptions.mm?rev=174146&r1=174145&r2=174146&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjCXX/arc-exceptions.mm (original)
+++ cfe/trunk/test/CodeGenObjCXX/arc-exceptions.mm Thu Jan 31 23:11:40 2013
@@ -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
+}
More information about the cfe-commits
mailing list