summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/CodeGen/CGDeclCXX.cpp72
-rw-r--r--clang/lib/CodeGen/CGException.cpp22
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.h1
-rw-r--r--clang/test/CodeGenCXX/threadsafe-statics-exceptions.cpp26
4 files changed, 102 insertions, 19 deletions
diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp
index 036be928852..f94ddd98866 100644
--- a/clang/lib/CodeGen/CGDeclCXX.cpp
+++ b/clang/lib/CodeGen/CGDeclCXX.cpp
@@ -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);
}
diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp
index c1d05bf233b..9fa195235ff 100644
--- a/clang/lib/CodeGen/CGException.cpp
+++ b/clang/lib/CodeGen/CGException.cpp
@@ -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
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 151c13c8088..4f85878f0c0 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -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;
diff --git a/clang/test/CodeGenCXX/threadsafe-statics-exceptions.cpp b/clang/test/CodeGenCXX/threadsafe-statics-exceptions.cpp
new file mode 100644
index 00000000000..9347cc9616a
--- /dev/null
+++ b/clang/test/CodeGenCXX/threadsafe-statics-exceptions.cpp
@@ -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();
+}
OpenPOWER on IntegriCloud