[cfe-commits] r124481 - in /cfe/trunk: lib/CodeGen/CGDecl.cpp lib/CodeGen/CGException.cpp lib/CodeGen/CGExprCXX.cpp lib/CodeGen/CodeGenFunction.h test/CodeGenCXX/eh.cpp
John McCall
rjmccall at apple.com
Fri Jan 28 00:37:24 PST 2011
Author: rjmccall
Date: Fri Jan 28 02:37:24 2011
New Revision: 124481
URL: http://llvm.org/viewvc/llvm-project?rev=124481&view=rev
Log:
Convert the exception-freeing cleanup over to the conditional cleanups code,
fixing a crash which probably nobody was ever going to see. In doing so,
fix a horrendous number of problems with the conditional-cleanups code.
Also, make conditional cleanups re-use the cleanup's activation variable,
which avoids some unfortunate repetitiveness.
Modified:
cfe/trunk/lib/CodeGen/CGDecl.cpp
cfe/trunk/lib/CodeGen/CGException.cpp
cfe/trunk/lib/CodeGen/CGExprCXX.cpp
cfe/trunk/lib/CodeGen/CodeGenFunction.h
cfe/trunk/test/CodeGenCXX/eh.cpp
Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=124481&r1=124480&r2=124481&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Fri Jan 28 02:37:24 2011
@@ -697,6 +697,7 @@
DidCallStackSave = true;
// Push a cleanup block and restore the stack there.
+ // FIXME: in general circumstances, this should be an EH cleanup.
EHStack.pushCleanup<CallStackRestore>(NormalCleanup, Stack);
}
Modified: cfe/trunk/lib/CodeGen/CGException.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.cpp?rev=124481&r1=124480&r2=124481&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGException.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGException.cpp Fri Jan 28 02:37:24 2011
@@ -172,19 +172,26 @@
BranchFixups.pop_back();
}
-llvm::Value *CodeGenFunction::initFullExprCleanup() {
+void CodeGenFunction::initFullExprCleanup() {
// Create a variable to decide whether the cleanup needs to be run.
- llvm::AllocaInst *run = CreateTempAlloca(Builder.getInt1Ty(), "cleanup.cond");
+ llvm::AllocaInst *active
+ = CreateTempAlloca(Builder.getInt1Ty(), "cleanup.cond");
// Initialize it to false at a site that's guaranteed to be run
// before each evaluation.
llvm::BasicBlock *block = OutermostConditional->getStartingBlock();
- new llvm::StoreInst(Builder.getFalse(), run, &block->back());
+ new llvm::StoreInst(Builder.getFalse(), active, &block->back());
// Initialize it to true at the current location.
- Builder.CreateStore(Builder.getTrue(), run);
+ Builder.CreateStore(Builder.getTrue(), active);
- return run;
+ // Set that as the active flag in the cleanup.
+ EHCleanupScope &cleanup = cast<EHCleanupScope>(*EHStack.begin());
+ assert(cleanup.getActiveFlag() == 0 && "cleanup already has active flag?");
+ cleanup.setActiveFlag(active);
+
+ if (cleanup.isNormalCleanup()) cleanup.setTestFlagInNormalCleanup();
+ if (cleanup.isEHCleanup()) cleanup.setTestFlagInEHCleanup();
}
static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) {
@@ -483,26 +490,11 @@
namespace {
/// A cleanup to free the exception object if its initialization
/// throws.
- struct FreeExceptionCleanup : EHScopeStack::Cleanup {
- FreeExceptionCleanup(llvm::Value *ShouldFreeVar,
- llvm::Value *ExnLocVar)
- : ShouldFreeVar(ShouldFreeVar), ExnLocVar(ExnLocVar) {}
-
- llvm::Value *ShouldFreeVar;
- llvm::Value *ExnLocVar;
-
- void Emit(CodeGenFunction &CGF, bool IsForEH) {
- llvm::BasicBlock *FreeBB = CGF.createBasicBlock("free-exnobj");
- llvm::BasicBlock *DoneBB = CGF.createBasicBlock("free-exnobj.done");
-
- llvm::Value *ShouldFree = CGF.Builder.CreateLoad(ShouldFreeVar,
- "should-free-exnobj");
- CGF.Builder.CreateCondBr(ShouldFree, FreeBB, DoneBB);
- CGF.EmitBlock(FreeBB);
- llvm::Value *ExnLocLocal = CGF.Builder.CreateLoad(ExnLocVar, "exnobj");
- CGF.Builder.CreateCall(getFreeExceptionFn(CGF), ExnLocLocal)
+ struct FreeException {
+ static void Emit(CodeGenFunction &CGF, bool forEH,
+ llvm::Value *exn) {
+ CGF.Builder.CreateCall(getFreeExceptionFn(CGF), exn)
->setDoesNotThrow();
- CGF.EmitBlock(DoneBB);
}
};
}
@@ -511,41 +503,17 @@
// differs from EmitAnyExprToMem only in that, if a final copy-ctor
// call is required, an exception within that copy ctor causes
// std::terminate to be invoked.
-static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *E,
- llvm::Value *ExnLoc) {
- // We want to release the allocated exception object if this
- // expression throws. We do this by pushing an EH-only cleanup
- // block which, furthermore, deactivates itself after the expression
- // is complete.
- llvm::AllocaInst *ShouldFreeVar =
- CGF.CreateTempAlloca(llvm::Type::getInt1Ty(CGF.getLLVMContext()),
- "should-free-exnobj.var");
- CGF.InitTempAlloca(ShouldFreeVar,
- llvm::ConstantInt::getFalse(CGF.getLLVMContext()));
-
- // A variable holding the exception pointer. This is necessary
- // because the throw expression does not necessarily dominate the
- // cleanup, for example if it appears in a conditional expression.
- llvm::AllocaInst *ExnLocVar =
- CGF.CreateTempAlloca(ExnLoc->getType(), "exnobj.var");
-
+static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *e,
+ llvm::Value *addr) {
// Make sure the exception object is cleaned up if there's an
// exception during initialization.
- // FIXME: stmt expressions might require this to be a normal
- // cleanup, too.
- CGF.EHStack.pushCleanup<FreeExceptionCleanup>(EHCleanup,
- ShouldFreeVar,
- ExnLocVar);
- EHScopeStack::stable_iterator Cleanup = CGF.EHStack.stable_begin();
-
- CGF.Builder.CreateStore(ExnLoc, ExnLocVar);
- CGF.Builder.CreateStore(llvm::ConstantInt::getTrue(CGF.getLLVMContext()),
- ShouldFreeVar);
+ CGF.pushFullExprCleanup<FreeException>(EHCleanup, addr);
+ EHScopeStack::stable_iterator cleanup = CGF.EHStack.stable_begin();
// __cxa_allocate_exception returns a void*; we need to cast this
// to the appropriate type for the object.
- const llvm::Type *Ty = CGF.ConvertTypeForMem(E->getType())->getPointerTo();
- llvm::Value *TypedExnLoc = CGF.Builder.CreateBitCast(ExnLoc, Ty);
+ const llvm::Type *ty = CGF.ConvertTypeForMem(e->getType())->getPointerTo();
+ llvm::Value *typedAddr = CGF.Builder.CreateBitCast(addr, ty);
// FIXME: this isn't quite right! If there's a final unelided call
// to a copy constructor, then according to [except.terminate]p1 we
@@ -554,22 +522,10 @@
// evaluated but before the exception is caught. But the best way
// to handle that is to teach EmitAggExpr to do the final copy
// differently if it can't be elided.
- CGF.EmitAnyExprToMem(E, TypedExnLoc, /*Volatile*/ false, /*IsInit*/ true);
+ CGF.EmitAnyExprToMem(e, typedAddr, /*Volatile*/ false, /*IsInit*/ true);
- CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(CGF.getLLVMContext()),
- ShouldFreeVar);
-
- // Technically, the exception object is like a temporary; it has to
- // be cleaned up when its full-expression is complete.
- // Unfortunately, the AST represents full-expressions by creating a
- // ExprWithCleanups, which it only does when there are actually
- // temporaries.
- //
- // If any cleanups have been added since we pushed ours, they must
- // be from temporaries; this will get popped at the same time.
- // Otherwise we need to pop ours off. FIXME: this is very brittle.
- if (Cleanup == CGF.EHStack.stable_begin())
- CGF.PopCleanupBlock();
+ // Deactivate the cleanup block.
+ CGF.DeactivateCleanupBlock(cleanup);
}
llvm::Value *CodeGenFunction::getExceptionSlot() {
@@ -1671,23 +1627,3 @@
EHScopeStack::Cleanup::~Cleanup() {
llvm_unreachable("Cleanup is indestructable");
}
-
-void EHScopeStack::ConditionalCleanup::Emit(CodeGenFunction &CGF,
- bool IsForEHCleanup) {
- // Determine whether we should run the cleanup.
- llvm::Value *condVal = CGF.Builder.CreateLoad(cond, "cond.should-run");
-
- llvm::BasicBlock *cleanup = CGF.createBasicBlock("cond-cleanup.run");
- llvm::BasicBlock *cont = CGF.createBasicBlock("cond-cleanup.cont");
-
- // If we shouldn't run the cleanup, jump directly to the continuation block.
- CGF.Builder.CreateCondBr(condVal, cleanup, cont);
- CGF.EmitBlock(cleanup);
-
- // Emit the core of the cleanup.
- EmitImpl(CGF, IsForEHCleanup);
- assert(CGF.HaveInsertPoint() && "cleanup didn't end with valid IP!");
-
- // Fall into the continuation block.
- CGF.EmitBlock(cont);
-}
Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=124481&r1=124480&r2=124481&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Fri Jan 28 02:37:24 2011
@@ -1197,6 +1197,8 @@
}
// Make sure that we call delete even if the dtor throws.
+ // This doesn't have to a conditional cleanup because we're going
+ // to pop it off in a second.
CGF.EHStack.pushCleanup<CallObjectDelete>(NormalAndEHCleanup,
Ptr, OperatorDelete, ElementType);
@@ -1361,7 +1363,7 @@
EmitBlock(DeleteEnd);
}
-llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
+llvm::Value *CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
QualType Ty = E->getType();
const llvm::Type *LTy = ConvertType(Ty)->getPointerTo();
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=124481&r1=124480&r2=124481&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Fri Jan 28 02:37:24 2011
@@ -103,9 +103,12 @@
template
<class T,
bool mustSave =
- llvm::is_base_of<llvm::Value, llvm::remove_pointer<T> >::value
- && !llvm::is_base_of<llvm::Constant, llvm::remove_pointer<T> >::value
- && !llvm::is_base_of<llvm::BasicBlock, llvm::remove_pointer<T> >::value>
+ llvm::is_base_of<llvm::Value,
+ typename llvm::remove_pointer<T>::type>::value
+ && !llvm::is_base_of<llvm::Constant,
+ typename llvm::remove_pointer<T>::type>::value
+ && !llvm::is_base_of<llvm::BasicBlock,
+ typename llvm::remove_pointer<T>::type>::value>
struct SavedValueInCond {
typedef T type;
typedef T saved_type;
@@ -193,24 +196,18 @@
virtual void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) = 0;
};
- /// A helper class for cleanups that execute conditionally.
- class ConditionalCleanup : public Cleanup {
- /// Either an i1 which directly indicates whether the cleanup
- /// should be run or an i1* from which that should be loaded.
- llvm::Value *cond;
-
+ /// UnconditionalCleanupN stores its N parameters and just passes
+ /// them to the real cleanup function.
+ template <class T, class A0>
+ class UnconditionalCleanup1 : public Cleanup {
+ A0 a0;
public:
- virtual void Emit(CodeGenFunction &CGF, bool IsForEHCleanup);
-
- protected:
- ConditionalCleanup(llvm::Value *cond) : cond(cond) {}
-
- /// Emit the non-conditional code for the cleanup.
- virtual void EmitImpl(CodeGenFunction &CGF, bool IsForEHCleanup) = 0;
+ UnconditionalCleanup1(A0 a0) : a0(a0) {}
+ void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) {
+ T::Emit(CGF, IsForEHCleanup, a0);
+ }
};
- /// UnconditionalCleanupN stores its N parameters and just passes
- /// them to the real cleanup function.
template <class T, class A0, class A1>
class UnconditionalCleanup2 : public Cleanup {
A0 a0; A1 a1;
@@ -223,22 +220,37 @@
/// ConditionalCleanupN stores the saved form of its N parameters,
/// then restores them and performs the cleanup.
+ template <class T, class A0>
+ class ConditionalCleanup1 : public Cleanup {
+ typedef typename SavedValueInCond<A0>::saved_type A0_saved;
+ A0_saved a0_saved;
+
+ void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) {
+ A0 a0 = SavedValueInCond<A0>::restore(CGF, a0_saved);
+ T::Emit(CGF, IsForEHCleanup, a0);
+ }
+
+ public:
+ ConditionalCleanup1(A0_saved a0)
+ : a0_saved(a0) {}
+ };
+
template <class T, class A0, class A1>
- class ConditionalCleanup2 : public ConditionalCleanup {
+ class ConditionalCleanup2 : public Cleanup {
typedef typename SavedValueInCond<A0>::saved_type A0_saved;
typedef typename SavedValueInCond<A1>::saved_type A1_saved;
A0_saved a0_saved;
A1_saved a1_saved;
- void EmitImpl(CodeGenFunction &CGF, bool IsForEHCleanup) {
+ void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) {
A0 a0 = SavedValueInCond<A0>::restore(CGF, a0_saved);
A1 a1 = SavedValueInCond<A1>::restore(CGF, a1_saved);
T::Emit(CGF, IsForEHCleanup, a0, a1);
}
public:
- ConditionalCleanup2(llvm::Value *cond, A0_saved a0, A1_saved a1)
- : ConditionalCleanup(cond), a0_saved(a0), a1_saved(a1) {}
+ ConditionalCleanup2(A0_saved a0, A1_saved a1)
+ : a0_saved(a0), a1_saved(a1) {}
};
private:
@@ -602,8 +614,9 @@
llvm::BasicBlock *getInvokeDestImpl();
- /// Sets up a condition for a full-expression cleanup.
- llvm::Value *initFullExprCleanup();
+ /// Set up the last cleaup that was pushed as a conditional
+ /// full-expression cleanup.
+ void initFullExprCleanup();
template <class T>
typename SavedValueInCond<T>::saved_type saveValueInCond(T value) {
@@ -629,23 +642,40 @@
/// pushFullExprCleanup - Push a cleanup to be run at the end of the
/// current full-expression. Safe against the possibility that
/// we're currently inside a conditionally-evaluated expression.
+ template <class T, class A0>
+ void pushFullExprCleanup(CleanupKind kind, A0 a0) {
+ // If we're not in a conditional branch, or if none of the
+ // arguments requires saving, then use the unconditional cleanup.
+ if (!isInConditionalBranch()) {
+ typedef EHScopeStack::UnconditionalCleanup1<T, A0> CleanupType;
+ return EHStack.pushCleanup<CleanupType>(kind, a0);
+ }
+
+ typename SavedValueInCond<A0>::saved_type a0_saved = saveValueInCond(a0);
+
+ typedef EHScopeStack::ConditionalCleanup1<T, A0> CleanupType;
+ EHStack.pushCleanup<CleanupType>(kind, a0_saved);
+ initFullExprCleanup();
+ }
+
+ /// pushFullExprCleanup - Push a cleanup to be run at the end of the
+ /// current full-expression. Safe against the possibility that
+ /// we're currently inside a conditionally-evaluated expression.
template <class T, class A0, class A1>
void pushFullExprCleanup(CleanupKind kind, A0 a0, A1 a1) {
// If we're not in a conditional branch, or if none of the
// arguments requires saving, then use the unconditional cleanup.
- if (!(isInConditionalBranch() ||
- SavedValueInCond<A0>::needsSaving(a0) ||
- SavedValueInCond<A1>::needsSaving(a1))) {
+ if (!isInConditionalBranch()) {
typedef EHScopeStack::UnconditionalCleanup2<T, A0, A1> CleanupType;
return EHStack.pushCleanup<CleanupType>(kind, a0, a1);
}
- llvm::Value *condVar = initFullExprCleanup();
typename SavedValueInCond<A0>::saved_type a0_saved = saveValueInCond(a0);
typename SavedValueInCond<A1>::saved_type a1_saved = saveValueInCond(a1);
typedef EHScopeStack::ConditionalCleanup2<T, A0, A1> CleanupType;
- EHStack.pushCleanup<CleanupType>(kind, condVar, a0_saved, a1_saved);
+ EHStack.pushCleanup<CleanupType>(kind, a0_saved, a1_saved);
+ initFullExprCleanup();
}
/// PushDestructorCleanup - Push a cleanup to call the
Modified: cfe/trunk/test/CodeGenCXX/eh.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/eh.cpp?rev=124481&r1=124480&r2=124481&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/eh.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/eh.cpp Fri Jan 28 02:37:24 2011
@@ -10,16 +10,10 @@
}
// CHECK: define void @_Z5test1v()
-// CHECK: [[FREEVAR:%.*]] = alloca i1
-// CHECK-NEXT: [[EXNOBJVAR:%.*]] = alloca i8*
-// CHECK-NEXT: store i1 false, i1* [[FREEVAR]]
-// CHECK-NEXT: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 8)
-// CHECK-NEXT: store i8* [[EXNOBJ]], i8** [[EXNOBJVAR]]
-// CHECK-NEXT: store i1 true, i1* [[FREEVAR]]
+// CHECK: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 8)
// CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[DSTAR:%[^*]*\*]]
// CHECK-NEXT: [[EXN2:%.*]] = bitcast [[DSTAR]] [[EXN]] to i8*
// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[EXN2]], i8* bitcast ([[DSTAR]] @d1 to i8*), i64 8, i32 8, i1 false)
-// CHECK-NEXT: store i1 false, i1* [[FREEVAR]]
// CHECK-NEXT: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast (%0* @_ZTI7test1_D to i8*), i8* null) noreturn
// CHECK-NEXT: unreachable
@@ -36,20 +30,14 @@
}
// CHECK: define void @_Z5test2v()
-// CHECK: [[FREEVAR:%.*]] = alloca i1
-// CHECK-NEXT: [[EXNOBJVAR:%.*]] = alloca i8*
-// CHECK-NEXT: [[EXNSLOTVAR:%.*]] = alloca i8*
+// CHECK: [[EXNSLOTVAR:%.*]] = alloca i8*
// CHECK-NEXT: [[CLEANUPDESTVAR:%.*]] = alloca i32
-// CHECK-NEXT: store i1 false, i1* [[FREEVAR]]
// CHECK-NEXT: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 16)
-// CHECK-NEXT: store i8* [[EXNOBJ]], i8** [[EXNOBJVAR]]
-// CHECK-NEXT: store i1 true, i1* [[FREEVAR]]
// CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[DSTAR:%[^*]*\*]]
// CHECK-NEXT: invoke void @_ZN7test2_DC1ERKS_([[DSTAR]] [[EXN]], [[DSTAR]] @d2)
// CHECK-NEXT: to label %[[CONT:.*]] unwind label %{{.*}}
// : [[CONT]]: (can't check this in Release-Asserts builds)
-// CHECK: store i1 false, i1* [[FREEVAR]]
-// CHECK-NEXT: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast (%{{.*}}* @_ZTI7test2_D to i8*), i8* null) noreturn
+// CHECK: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast (%{{.*}}* @_ZTI7test2_D to i8*), i8* null) noreturn
// CHECK-NEXT: unreachable
@@ -64,15 +52,9 @@
}
// CHECK: define void @_Z5test3v()
-// CHECK: [[FREEVAR:%.*]] = alloca i1
-// CHECK-NEXT: [[EXNOBJVAR:%.*]] = alloca i8*
-// CHECK-NEXT: store i1 false, i1* [[FREEVAR]]
-// CHECK-NEXT: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 8)
-// CHECK-NEXT: store i8* [[EXNOBJ]], i8** [[EXNOBJVAR]]
-// CHECK-NEXT: store i1 true, i1* [[FREEVAR]]
-// CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[DSS:%[^*]*\*]]*
-// CHECK-NEXT: store [[DSS]] null, [[DSS]]* [[EXN]]
-// CHECK-NEXT: store i1 false, i1* [[FREEVAR]]
+// CHECK: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 8)
+// CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[D:%[^*]+]]**
+// CHECK-NEXT: store [[D]]* null, [[D]]** [[EXN]]
// CHECK-NEXT: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast (%1* @_ZTIPV7test3_D to i8*), i8* null) noreturn
// CHECK-NEXT: unreachable
@@ -121,20 +103,14 @@
namespace test7 {
// CHECK: define i32 @_ZN5test73fooEv()
int foo() {
-// CHECK: [[FREEEXNOBJ:%.*]] = alloca i1
-// CHECK-NEXT: [[EXNALLOCVAR:%.*]] = alloca i8*
-// CHECK-NEXT: [[CAUGHTEXNVAR:%.*]] = alloca i8*
+// CHECK: [[CAUGHTEXNVAR:%.*]] = alloca i8*
// CHECK-NEXT: [[INTCATCHVAR:%.*]] = alloca i32
// CHECK-NEXT: [[EHCLEANUPDESTVAR:%.*]] = alloca i32
-// CHECK-NEXT: store i1 false, i1* [[FREEEXNOBJ]]
try {
try {
// CHECK-NEXT: [[EXNALLOC:%.*]] = call i8* @__cxa_allocate_exception
-// CHECK-NEXT: store i8* [[EXNALLOC]], i8** [[EXNALLOCVAR]]
-// CHECK-NEXT: store i1 true, i1* [[FREEEXNOBJ]]
// CHECK-NEXT: bitcast i8* [[EXNALLOC]] to i32*
// CHECK-NEXT: store i32 1, i32*
-// CHECK-NEXT: store i1 false, i1* [[FREEEXNOBJ]]
// CHECK-NEXT: invoke void @__cxa_throw(i8* [[EXNALLOC]], i8* bitcast (i8** @_ZTIi to i8*), i8* null
throw 1;
}
@@ -414,3 +390,49 @@
// CHECK: call void @_ZN6test151AD1Ev
}
}
+
+namespace test16 {
+ struct A { A(); ~A(); };
+ struct B { int x; B(const A &); ~B(); };
+ void foo();
+ bool cond();
+
+ // CHECK: define void @_ZN6test163barEv()
+ void bar() {
+ // CHECK: [[EXN_SAVE:%.*]] = alloca i8*
+ // CHECK-NEXT: [[EXN_ACTIVE:%.*]] = alloca i1
+ // CHECK-NEXT: [[TEMP:%.*]] = alloca [[A:%.*]],
+ // CHECK-NEXT: [[EXNSLOT:%.*]] = alloca i8*
+ // CHECK-NEXT: [[EHDEST:%.*]] = alloca i32
+ // CHECK-NEXT: [[TEMP_ACTIVE:%.*]] = alloca i1
+
+ cond() ? throw B(A()) : foo();
+
+ // CHECK-NEXT: [[COND:%.*]] = call zeroext i1 @_ZN6test164condEv()
+ // CHECK-NEXT: store i1 false, i1* [[EXN_ACTIVE]]
+ // CHECK-NEXT: store i1 false, i1* [[TEMP_ACTIVE]]
+ // CHECK-NEXT: br i1 [[COND]],
+
+ // CHECK: [[EXN:%.*]] = call i8* @__cxa_allocate_exception(i64 4)
+ // CHECK-NEXT: store i8* [[EXN]], i8** [[EXN_SAVE]]
+ // CHECK-NEXT: store i1 true, i1* [[EXN_ACTIVE]]
+ // CHECK-NEXT: [[T0:%.*]] = bitcast i8* [[EXN]] to [[B:%.*]]*
+ // CHECK-NEXT: invoke void @_ZN6test161AC1Ev([[A]]* [[TEMP]])
+ // CHECK: store i1 true, i1* [[TEMP_ACTIVE]]
+ // CHECK-NEXT: invoke void @_ZN6test161BC1ERKNS_1AE([[B]]* [[T0]], [[A]]* [[TEMP]])
+ // CHECK: store i1 false, i1* [[EXN_ACTIVE]]
+ // CHECK-NEXT: invoke void @__cxa_throw(i8* [[EXN]],
+
+ // CHECK: invoke void @_ZN6test163fooEv()
+ // CHECK: br label
+
+ // CHECK: invoke void @_ZN6test161AD1Ev([[A]]* [[TEMP]])
+ // CHECK: ret void
+
+ // CHECK: [[T0:%.*]] = load i1* [[EXN_ACTIVE]]
+ // CHECK-NEXT: br i1 [[T0]]
+ // CHECK: [[T1:%.*]] = load i8** [[EXN_SAVE]]
+ // CHECK-NEXT: call void @__cxa_free_exception(i8* [[T1]])
+ // CHECK-NEXT: br label
+ }
+}
More information about the cfe-commits
mailing list