aboutsummaryrefslogtreecommitdiff
path: root/test/CodeGenObjCXX
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2013-04-03 00:56:07 +0000
committerJohn McCall <rjmccall@apple.com>2013-04-03 00:56:07 +0000
commit73c56bb0c8e722f4f0c0a044f13064d381f1ec8d (patch)
treeccfe67d4d674385798cf412f08c0c3d60da3b8cd /test/CodeGenObjCXX
parent7b47adcbea945e31db3e96567e81f14048c7a300 (diff)
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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@178599 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/CodeGenObjCXX')
-rw-r--r--test/CodeGenObjCXX/exceptions-legacy.mm80
1 files changed, 80 insertions, 0 deletions
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