diff options
-rw-r--r-- | lib/CodeGen/CGObjCMac.cpp | 5 | ||||
-rw-r--r-- | test/CodeGenObjC/exceptions.m | 4 | ||||
-rw-r--r-- | test/CodeGenObjCXX/exceptions-legacy.mm | 80 |
3 files changed, 86 insertions, 3 deletions
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 019c32ea3d..6274e1bfe3 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -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::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, 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, diff --git a/test/CodeGenObjC/exceptions.m b/test/CodeGenObjC/exceptions.m index 551e67c2e6..408b94d385 100644 --- a/test/CodeGenObjC/exceptions.m +++ b/test/CodeGenObjC/exceptions.m @@ -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 { diff --git a/test/CodeGenObjCXX/exceptions-legacy.mm b/test/CodeGenObjCXX/exceptions-legacy.mm new file mode 100644 index 0000000000..a31ba36660 --- /dev/null +++ b/test/CodeGenObjCXX/exceptions-legacy.mm @@ -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 |