r178599 - In ObjC++ on legacy runtimes, push an EH cleanup as well as

John McCall rjmccall at apple.com
Tue Apr 2 17:56:07 PDT 2013


Author: rjmccall
Date: Tue Apr  2 19:56:07 2013
New Revision: 178599

URL: http://llvm.org/viewvc/llvm-project?rev=178599&view=rev
Log:
In ObjC++ on legacy runtimes, push an EH cleanup as well as
a normal cleanup when entering a @try or @synchronized to
ensure that we clean that up if an exception is triggered.

Apparently GCC did this, so it's hard to argue that we shouldn't
do at least as much.

rdar://12364847

Added:
    cfe/trunk/test/CodeGenObjCXX/exceptions-legacy.mm
Modified:
    cfe/trunk/lib/CodeGen/CGObjCMac.cpp
    cfe/trunk/test/CodeGenObjC/exceptions.m

Modified: cfe/trunk/lib/CodeGen/CGObjCMac.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCMac.cpp?rev=178599&r1=178598&r2=178599&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjCMac.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjCMac.cpp Tue Apr  2 19:56:07 2013
@@ -3519,6 +3519,9 @@ namespace {
       if (isa<ObjCAtTryStmt>(S)) {
         if (const ObjCAtFinallyStmt* FinallyStmt =
               cast<ObjCAtTryStmt>(S).getFinallyStmt()) {
+          // Don't try to do the @finally if this is an EH cleanup.
+          if (flags.isForEHCleanup()) return;
+
           // Save the current cleanup destination in case there's
           // control flow inside the finally statement.
           llvm::Value *CurCleanupDest =
@@ -3860,7 +3863,7 @@ void CGObjCMac::EmitTryOrSynchronizedStm
   llvm::Value *PropagatingExnVar = 0;
 
   // Push a normal cleanup to leave the try scope.
-  CGF.EHStack.pushCleanup<PerformFragileFinally>(NormalCleanup, &S,
+  CGF.EHStack.pushCleanup<PerformFragileFinally>(NormalAndEHCleanup, &S,
                                                  SyncArgSlot,
                                                  CallTryExitVar,
                                                  ExceptionData,

Modified: cfe/trunk/test/CodeGenObjC/exceptions.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/exceptions.m?rev=178599&r1=178598&r2=178599&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjC/exceptions.m (original)
+++ cfe/trunk/test/CodeGenObjC/exceptions.m Tue Apr  2 19:56:07 2013
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -emit-llvm -fexceptions -fobjc-exceptions -O2 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -emit-llvm -fobjc-exceptions -O2 -o - %s | FileCheck %s
 //
 // <rdar://problem/7471679> [irgen] [eh] Exception code built with clang (x86_64) crashes
 
@@ -28,7 +28,7 @@ void f1() {
     // CHECK:      call void asm sideeffect "", "*m"
     // CHECK-NEXT: call void @foo()
       foo();
-    // CHECK-NEXT: call void @objc_exception_try_exit
+    // CHECK:      call void @objc_exception_try_exit
 
     // CHECK:      call void asm sideeffect "", "=*m"
     } @finally {

Added: cfe/trunk/test/CodeGenObjCXX/exceptions-legacy.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/exceptions-legacy.mm?rev=178599&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjCXX/exceptions-legacy.mm (added)
+++ cfe/trunk/test/CodeGenObjCXX/exceptions-legacy.mm Tue Apr  2 19:56:07 2013
@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -emit-llvm -fexceptions -fobjc-exceptions -O2 -o - %s | FileCheck %s
+
+// Test we maintain at least a basic amount of interoperation between
+// ObjC and C++ exceptions in the legacy runtime.
+
+// rdar://12364847
+
+void foo(void);
+
+void test0(id obj) {
+  @synchronized(obj) {
+    foo();
+  }
+}
+// CHECK:    define void @_Z5test0P11objc_object(
+//   Enter the @synchronized block.
+// CHECK:      call i32 @objc_sync_enter(i8* [[OBJ:%.*]])
+// CHECK:      call void @objc_exception_try_enter([[BUF_T:%.*]]* [[BUF:%.*]])
+// CHECK-NEXT: [[T0:%.*]] = getelementptr [[BUF_T]]* [[BUF]], i32 0, i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = call i32 @_setjmp(i32* [[T0]])
+// CHECK-NEXT: [[T2:%.*]] = icmp eq i32 [[T1]], 0
+// CHECK-NEXT: br i1 [[T2]],
+
+//   Body.
+// CHECK:      invoke void @_Z3foov()
+
+//   Leave the @synchronized.  The reload of obj here is unnecessary.
+// CHECK:      call void @objc_exception_try_exit([[BUF_T]]* [[BUF]])
+// CHECK-NEXT: [[T0:%.*]] = load i8**
+// CHECK-NEXT: call i32 @objc_sync_exit(i8* [[T0]])
+// CHECK-NEXT: ret void
+
+//   Real EH cleanup.
+// CHECK:      [[T0:%.*]] = landingpad
+// CHECK-NEXT:    cleanup
+// CHECK-NEXT: call void @objc_exception_try_exit([[BUF_T]]* [[BUF]])
+// CHECK-NEXT: [[T0:%.*]] = load i8**
+// CHECK-NEXT: call i32 @objc_sync_exit(i8* [[T0]])
+// CHECK-NEXT: resume
+
+//   ObjC EH "cleanup".
+// CHECK:      [[T0:%.*]] = load i8**
+// CHECK-NEXT: call i32 @objc_sync_exit(i8* [[T0]])
+// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_exception_extract([[BUF_T]]* [[BUF]])
+// CHECK-NEXT: call void @objc_exception_throw(i8* [[T0]])
+// CHECK-NEXT: unreachable
+
+void test1(id obj, bool *failed) {
+  @try {
+    foo();
+  } @catch (...) {
+    *failed = true;
+  }
+}
+// CHECK:    define void @_Z5test1P11objc_objectPb(
+//   Enter the @try block.
+// CHECK:      call void @objc_exception_try_enter([[BUF_T]]* [[BUF:%.*]])
+// CHECK-NEXT: [[T0:%.*]] = getelementptr [[BUF_T]]* [[BUF]], i32 0, i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = call i32 @_setjmp(i32* [[T0]])
+// CHECK-NEXT: [[T2:%.*]] = icmp eq i32 [[T1]], 0
+// CHECK-NEXT: br i1 [[T2]],
+
+//   Body.
+// CHECK:      invoke void @_Z3foov()
+
+//   Leave the @try.
+// CHECK:      call void @objc_exception_try_exit([[BUF_T]]* [[BUF]])
+// CHECK-NEXT: br label
+// CHECK:      ret void
+
+//   Real EH cleanup.
+// CHECK:      [[T0:%.*]] = landingpad
+// CHECK-NEXT:    cleanup
+// CHECK-NEXT: call void @objc_exception_try_exit([[BUF_T]]* [[BUF]])
+// CHECK-NEXT: resume
+
+//   Catch handler.  Reload of 'failed' address is unnecessary.
+// CHECK:      [[T0:%.*]] = load i8**
+// CHECK-NEXT: store i8 1, i8* [[T0]],
+// CHECK-NEXT: br label





More information about the cfe-commits mailing list