[cfe-commits] r108595 - in /cfe/trunk: lib/CodeGen/CGException.cpp lib/CodeGen/CGException.h test/CodeGenObjC/gnu-exceptions.m
John McCall
rjmccall at apple.com
Fri Jul 16 17:43:08 PDT 2010
Author: rjmccall
Date: Fri Jul 16 19:43:08 2010
New Revision: 108595
URL: http://llvm.org/viewvc/llvm-project?rev=108595&view=rev
Log:
The GNU-runtime ObjC personality function doesn't let us rethrow with URR for
multiple reasons. Rethrow with _objc_exception_throw instead. Fixes PR7656.
Added:
cfe/trunk/test/CodeGenObjC/gnu-exceptions.m
Modified:
cfe/trunk/lib/CodeGen/CGException.cpp
cfe/trunk/lib/CodeGen/CGException.h
Modified: cfe/trunk/lib/CodeGen/CGException.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.cpp?rev=108595&r1=108594&r2=108595&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGException.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGException.cpp Fri Jul 16 19:43:08 2010
@@ -317,74 +317,88 @@
CGF.CGM.getLangOptions().CPlusPlus ? "_ZSt9terminatev" : "abort");
}
-static const char *getCPersonalityFn(CodeGenFunction &CGF) {
- return "__gcc_personality_v0";
+static llvm::Constant *getCatchallRethrowFn(CodeGenFunction &CGF,
+ const char *Name) {
+ const llvm::Type *Int8PtrTy =
+ llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ std::vector<const llvm::Type*> Args(1, Int8PtrTy);
+
+ const llvm::Type *VoidTy = llvm::Type::getVoidTy(CGF.getLLVMContext());
+ const llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, Args, false);
+
+ return CGF.CGM.CreateRuntimeFunction(FTy, Name);
}
-static const char *getObjCPersonalityFn(CodeGenFunction &CGF) {
- if (CGF.CGM.getLangOptions().NeXTRuntime) {
- if (CGF.CGM.getLangOptions().ObjCNonFragileABI)
- return "__objc_personality_v0";
- else
- return getCPersonalityFn(CGF);
+const EHPersonality EHPersonality::GNU_C("__gcc_personality_v0");
+const EHPersonality EHPersonality::NeXT_ObjC("__objc_personality_v0");
+const EHPersonality EHPersonality::GNU_CPlusPlus("__gxx_personality_v0");
+const EHPersonality EHPersonality::GNU_CPlusPlus_SJLJ("__gxx_personality_sj0");
+const EHPersonality EHPersonality::GNU_ObjC("__gnu_objc_personality_v0",
+ "objc_exception_throw");
+
+static const EHPersonality &getCPersonality(const LangOptions &L) {
+ return EHPersonality::GNU_C;
+}
+
+static const EHPersonality &getObjCPersonality(const LangOptions &L) {
+ if (L.NeXTRuntime) {
+ if (L.ObjCNonFragileABI) return EHPersonality::NeXT_ObjC;
+ else return getCPersonality(L);
} else {
- return "__gnu_objc_personality_v0";
+ return EHPersonality::GNU_ObjC;
}
}
-static const char *getCXXPersonalityFn(CodeGenFunction &CGF) {
- if (CGF.CGM.getLangOptions().SjLjExceptions)
- return "__gxx_personality_sj0";
+static const EHPersonality &getCXXPersonality(const LangOptions &L) {
+ if (L.SjLjExceptions)
+ return EHPersonality::GNU_CPlusPlus_SJLJ;
else
- return "__gxx_personality_v0";
+ return EHPersonality::GNU_CPlusPlus;
}
/// Determines the personality function to use when both C++
/// and Objective-C exceptions are being caught.
-static const char *getObjCXXPersonalityFn(CodeGenFunction &CGF) {
+static const EHPersonality &getObjCXXPersonality(const LangOptions &L) {
// The ObjC personality defers to the C++ personality for non-ObjC
// handlers. Unlike the C++ case, we use the same personality
// function on targets using (backend-driven) SJLJ EH.
- if (CGF.CGM.getLangOptions().NeXTRuntime) {
- if (CGF.CGM.getLangOptions().ObjCNonFragileABI)
- return "__objc_personality_v0";
+ if (L.NeXTRuntime) {
+ if (L.ObjCNonFragileABI)
+ return EHPersonality::NeXT_ObjC;
// In the fragile ABI, just use C++ exception handling and hope
// they're not doing crazy exception mixing.
else
- return getCXXPersonalityFn(CGF);
+ return getCXXPersonality(L);
}
- // I'm pretty sure the GNU runtime doesn't support mixed EH.
- // TODO: we don't necessarily need mixed EH here; remember what
- // kind of exceptions we actually try to catch in this function.
- CGF.CGM.ErrorUnsupported(CGF.CurCodeDecl,
- "the GNU Objective C runtime does not support "
- "catching C++ and Objective C exceptions in the "
- "same function");
- // Use the C++ personality just to avoid returning null.
- return getCXXPersonalityFn(CGF);
-}
-
-static llvm::Constant *getPersonalityFn(CodeGenFunction &CGF) {
- const char *Name;
- const LangOptions &Opts = CGF.CGM.getLangOptions();
- if (Opts.CPlusPlus && Opts.ObjC1)
- Name = getObjCXXPersonalityFn(CGF);
- else if (Opts.CPlusPlus)
- Name = getCXXPersonalityFn(CGF);
- else if (Opts.ObjC1)
- Name = getObjCPersonalityFn(CGF);
+ // The GNU runtime's personality function inherently doesn't support
+ // mixed EH. Use the C++ personality just to avoid returning null.
+ return getCXXPersonality(L);
+}
+
+const EHPersonality &EHPersonality::get(const LangOptions &L) {
+ if (L.CPlusPlus && L.ObjC1)
+ return getObjCXXPersonality(L);
+ else if (L.CPlusPlus)
+ return getCXXPersonality(L);
+ else if (L.ObjC1)
+ return getObjCPersonality(L);
else
- Name = getCPersonalityFn(CGF);
+ return getCPersonality(L);
+}
- llvm::Constant *Personality =
+static llvm::Constant *getPersonalityFn(CodeGenFunction &CGF,
+ const EHPersonality &Personality) {
+ const char *Name = Personality.getPersonalityFnName();
+
+ llvm::Constant *Fn =
CGF.CGM.CreateRuntimeFunction(llvm::FunctionType::get(
llvm::Type::getInt32Ty(
CGF.CGM.getLLVMContext()),
true),
Name);
- return llvm::ConstantExpr::getBitCast(Personality, CGF.CGM.PtrToInt8Ty);
+ return llvm::ConstantExpr::getBitCast(Fn, CGF.CGM.PtrToInt8Ty);
}
/// Returns the value to inject into a selector to indicate the
@@ -753,6 +767,9 @@
// Save the current IR generation state.
CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
+ const EHPersonality &Personality =
+ EHPersonality::get(CGF.CGM.getLangOptions());
+
// Create and configure the landing pad.
llvm::BasicBlock *LP = createBasicBlock("lpad");
EmitBlock(LP);
@@ -768,7 +785,7 @@
// Build the selector arguments.
llvm::SmallVector<llvm::Value*, 8> EHSelector;
EHSelector.push_back(Exn);
- EHSelector.push_back(getPersonalityFn(*this));
+ EHSelector.push_back(getPersonalityFn(*this, Personality));
// Accumulate all the handlers in scope.
llvm::DenseMap<llvm::Value*, JumpDest> EHHandlers;
@@ -1008,8 +1025,12 @@
// This can always be a call because we necessarily didn't find
// anything on the EH stack which needs our help.
- Builder.CreateCall(getUnwindResumeOrRethrowFn(),
- Builder.CreateLoad(getExceptionSlot()))
+ llvm::Constant *RethrowFn;
+ if (const char *RethrowName = Personality.getCatchallRethrowFnName())
+ RethrowFn = getCatchallRethrowFn(CGF, RethrowName);
+ else
+ RethrowFn = getUnwindResumeOrRethrowFn();
+ Builder.CreateCall(RethrowFn, Builder.CreateLoad(getExceptionSlot()))
->setDoesNotReturn();
Builder.CreateUnreachable();
}
@@ -1437,10 +1458,12 @@
llvm::CallInst *Exn =
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::eh_exception), "exn");
Exn->setDoesNotThrow();
+
+ const EHPersonality &Personality = EHPersonality::get(CGM.getLangOptions());
// Tell the backend what the exception table should be:
// nothing but a catch-all.
- llvm::Value *Args[3] = { Exn, getPersonalityFn(*this),
+ llvm::Value *Args[3] = { Exn, getPersonalityFn(*this, Personality),
getCatchAllValue(*this) };
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::eh_selector),
Args, Args+3, "eh.selector")
Modified: cfe/trunk/lib/CodeGen/CGException.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.h?rev=108595&r1=108594&r2=108595&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGException.h (original)
+++ cfe/trunk/lib/CodeGen/CGException.h Fri Jul 16 19:43:08 2010
@@ -27,6 +27,32 @@
namespace clang {
namespace CodeGen {
+/// The exceptions personality for a function. When
+class EHPersonality {
+ const char *PersonalityFn;
+
+ // If this is non-null, this personality requires a non-standard
+ // function for rethrowing an exception after a catchall cleanup.
+ // This function must have prototype void(void*).
+ const char *CatchallRethrowFn;
+
+ EHPersonality(const char *PersonalityFn,
+ const char *CatchallRethrowFn = 0)
+ : PersonalityFn(PersonalityFn),
+ CatchallRethrowFn(CatchallRethrowFn) {}
+
+public:
+ static const EHPersonality &get(const LangOptions &Lang);
+ static const EHPersonality GNU_C;
+ static const EHPersonality GNU_ObjC;
+ static const EHPersonality NeXT_ObjC;
+ static const EHPersonality GNU_CPlusPlus;
+ static const EHPersonality GNU_CPlusPlus_SJLJ;
+
+ const char *getPersonalityFnName() const { return PersonalityFn; }
+ const char *getCatchallRethrowFnName() const { return CatchallRethrowFn; }
+};
+
/// A protected scope for zero-cost EH handling.
class EHScope {
llvm::BasicBlock *CachedLandingPad;
Added: cfe/trunk/test/CodeGenObjC/gnu-exceptions.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/gnu-exceptions.m?rev=108595&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/gnu-exceptions.m (added)
+++ cfe/trunk/test/CodeGenObjC/gnu-exceptions.m Fri Jul 16 19:43:08 2010
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -fexceptions -fgnu-runtime -o - %s | FileCheck %s
+
+void opaque(void);
+void log(int i);
+
+ at class C;
+
+// CHECK: define void @test0() {
+void test0() {
+ @try {
+ // CHECK: invoke void @opaque()
+ opaque();
+ } @catch (C *c) {
+ // CHECK: call i8* @llvm.eh.exception()
+ // CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector({{.*}} @__gnu_objc_personality_v0
+ // CHECK: br i1
+ // CHECK: call void @objc_exception_throw
+
+ // CHECK: call void @log(i32 0)
+ log(0);
+ }
+
+ // CHECK: call void @log(i32 1)
+ log(1);
+}
More information about the cfe-commits
mailing list