When initializing thread-safe statics, put the call to

__cxa_guard_abort along the exceptional edge into (in effect) a nested
"try" that rethrows after aborting. Fixes PR7144 and the remaining
Boost.ProgramOptions failures, along with the regressions that r103880
caused.

The crucial difference between this and r103880 is that we now follow
LLVM's little dance with the llvm.eh.exception and llvm.eh.selector
calls, then use _Unwind_Resume_or_Rethrow to rethrow.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@103892 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2010-05-16 01:24:12 +00:00
Родитель 1eb2e59338
Коммит 86a3a03667
4 изменённых файлов: 102 добавлений и 19 удалений

Просмотреть файл

@ -13,6 +13,8 @@
#include "CodeGenFunction.h"
#include "clang/CodeGen/CodeGenOptions.h"
#include "llvm/Intrinsics.h"
using namespace clang;
using namespace CodeGen;
@ -321,7 +323,10 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
EmitBlock(InitCheckBlock);
if (ThreadsafeStatics) {
// Variables used when coping with thread-safe statics and exceptions.
llvm::BasicBlock *SavedLandingPad = 0;
llvm::BasicBlock *LandingPad = 0;
if (ThreadsafeStatics) {
// Call __cxa_guard_acquire.
V = Builder.CreateCall(getGuardAcquireFn(*this), GuardVariable);
@ -330,14 +335,13 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
Builder.CreateCondBr(Builder.CreateIsNotNull(V, "tobool"),
InitBlock, EndBlock);
EmitBlock(InitBlock);
if (Exceptions) {
EHCleanupBlock Cleanup(*this);
// Call __cxa_guard_abort.
Builder.CreateCall(getGuardAbortFn(*this), GuardVariable);
SavedLandingPad = getInvokeDest();
LandingPad = createBasicBlock("guard.lpad");
setInvokeDest(LandingPad);
}
EmitBlock(InitBlock);
}
if (D.getType()->isReferenceType()) {
@ -353,7 +357,7 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
if (ThreadsafeStatics) {
// Call __cxa_guard_release.
Builder.CreateCall(getGuardReleaseFn(*this), GuardVariable);
Builder.CreateCall(getGuardReleaseFn(*this), GuardVariable);
} else {
llvm::Value *One =
llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 1);
@ -364,5 +368,57 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
if (!D.getType()->isReferenceType())
EmitDeclDestroy(*this, D, GV);
if (ThreadsafeStatics && Exceptions) {
// If an exception is thrown during initialization, call __cxa_guard_abort
// along the exceptional edge.
EmitBranch(EndBlock);
// Construct the landing pad.
EmitBlock(LandingPad);
// Personality function and LLVM intrinsics.
llvm::Constant *Personality =
CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
(VMContext),
true),
"__gxx_personality_v0");
Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty);
llvm::Value *llvm_eh_exception =
CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
llvm::Value *llvm_eh_selector =
CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
// Exception object
llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow");
// Call the selector function.
const llvm::PointerType *PtrToInt8Ty
= llvm::PointerType::getUnqual(llvm::Type::getInt8Ty(VMContext));
llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty);
llvm::Value* SelectorArgs[3] = { Exc, Personality, Null };
Builder.CreateCall(llvm_eh_selector, SelectorArgs, SelectorArgs + 3,
"selector");
Builder.CreateStore(Exc, RethrowPtr);
// Call __cxa_guard_abort along the exceptional edge.
Builder.CreateCall(getGuardAbortFn(*this), GuardVariable);
setInvokeDest(SavedLandingPad);
// Rethrow the current exception.
if (getInvokeDest()) {
llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
Builder.CreateInvoke(getUnwindResumeOrRethrowFn(), Cont,
getInvokeDest(),
Builder.CreateLoad(RethrowPtr));
EmitBlock(Cont);
} else
Builder.CreateCall(getUnwindResumeOrRethrowFn(),
Builder.CreateLoad(RethrowPtr));
Builder.CreateUnreachable();
}
EmitBlock(EndBlock);
}

Просмотреть файл

@ -100,17 +100,17 @@ static llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) {
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected");
}
static llvm::Constant *getUnwindResumeOrRethrowFn(CodeGenFunction &CGF) {
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
llvm::Constant *CodeGenFunction::getUnwindResumeOrRethrowFn() {
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
std::vector<const llvm::Type*> Args(1, Int8PtrTy);
const llvm::FunctionType *FTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), Args,
llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()), Args,
false);
if (CGF.CGM.getLangOptions().SjLjExceptions)
return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume");
return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow");
if (CGM.getLangOptions().SjLjExceptions)
return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume");
return CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow");
}
static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) {
@ -397,7 +397,7 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) {
if (Proto->getNumExceptions()) {
EmitBlock(Unwind);
Builder.CreateCall(getUnwindResumeOrRethrowFn(*this),
Builder.CreateCall(getUnwindResumeOrRethrowFn(),
Builder.CreateLoad(RethrowPtr));
Builder.CreateUnreachable();
}
@ -631,12 +631,12 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S,
// here.
if (getInvokeDest()) {
llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
Builder.CreateInvoke(getUnwindResumeOrRethrowFn(*this), Cont,
Builder.CreateInvoke(getUnwindResumeOrRethrowFn(), Cont,
getInvokeDest(),
Builder.CreateLoad(RethrowPtr));
EmitBlock(Cont);
} else
Builder.CreateCall(getUnwindResumeOrRethrowFn(*this),
Builder.CreateCall(getUnwindResumeOrRethrowFn(),
Builder.CreateLoad(RethrowPtr));
Builder.CreateUnreachable();
@ -687,11 +687,11 @@ CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() {
// Rethrow the exception.
if (CGF.getInvokeDest()) {
llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont");
CGF.Builder.CreateInvoke(getUnwindResumeOrRethrowFn(CGF), Cont,
CGF.Builder.CreateInvoke(CGF.getUnwindResumeOrRethrowFn(), Cont,
CGF.getInvokeDest(), Exc);
CGF.EmitBlock(Cont);
} else
CGF.Builder.CreateCall(getUnwindResumeOrRethrowFn(CGF), Exc);
CGF.Builder.CreateCall(CGF.getUnwindResumeOrRethrowFn(), Exc);
CGF.Builder.CreateUnreachable();
// Resume inserting where we started, but put the new cleanup

Просмотреть файл

@ -929,6 +929,7 @@ public:
void EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S);
void EmitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt &S);
llvm::Constant *getUnwindResumeOrRethrowFn();
struct CXXTryStmtInfo {
llvm::BasicBlock *SavedLandingPad;
llvm::BasicBlock *HandlerBlock;

Просмотреть файл

@ -0,0 +1,26 @@
// RUN: %clang_cc1 -emit-llvm -o - -fexceptions -triple x86_64-apple-darwin10 %s | FileCheck %s
struct X {
X();
~X();
};
struct Y { };
// CHECK: define void @_Z1fv
void f() {
// CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZ1fvE1x)
// CHECK: invoke void @_ZN1XC1Ev
// CHECK: call void @__cxa_guard_release(i64* @_ZGVZ1fvE1x)
// CHECK: call i32 @__cxa_atexit
// CHECK: br
static X x;
// CHECK: call i8* @llvm.eh.exception()
// CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector
// CHECK: call void @__cxa_guard_abort(i64* @_ZGVZ1fvE1x)
// CHECK: call void @_Unwind_Resume_or_Rethrow
// CHECK: unreachable
// CHECK: call i8* @__cxa_allocate_exception
throw Y();
}