[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