aboutsummaryrefslogtreecommitdiff
path: root/test/CodeGen/exceptions-seh-finally.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/CodeGen/exceptions-seh-finally.c')
-rw-r--r--test/CodeGen/exceptions-seh-finally.c242
1 files changed, 242 insertions, 0 deletions
diff --git a/test/CodeGen/exceptions-seh-finally.c b/test/CodeGen/exceptions-seh-finally.c
new file mode 100644
index 000000000000..345d514611e3
--- /dev/null
+++ b/test/CodeGen/exceptions-seh-finally.c
@@ -0,0 +1,242 @@
+// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s
+
+void abort(void) __attribute__((noreturn));
+void might_crash(void);
+void cleanup(void);
+int check_condition(void);
+void basic_finally(void) {
+ __try {
+ might_crash();
+ } __finally {
+ cleanup();
+ }
+}
+
+// CHECK-LABEL: define void @basic_finally()
+// CHECK: invoke void @might_crash()
+// CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
+//
+// CHECK: [[invoke_cont]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@basic_finally@@"(i8 0, i8* %[[fp]])
+// CHECK-NEXT: ret void
+//
+// CHECK: [[lpad]]
+// CHECK-NEXT: landingpad
+// CHECK-NEXT: cleanup
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@basic_finally@@"(i8 1, i8* %[[fp]])
+// CHECK: resume { i8*, i32 }
+
+// CHECK: define internal void @"\01?fin$0@0@basic_finally@@"(i8 %abnormal_termination, i8* %frame_pointer)
+// CHECK: call void @cleanup()
+
+// Mostly check that we don't double emit 'r' which would crash.
+void decl_in_finally(void) {
+ __try {
+ might_crash();
+ } __finally {
+ int r;
+ }
+}
+
+// Ditto, don't crash double emitting 'l'.
+void label_in_finally(void) {
+ __try {
+ might_crash();
+ } __finally {
+l:
+ cleanup();
+ if (check_condition())
+ goto l;
+ }
+}
+
+// CHECK-LABEL: define void @label_in_finally()
+// CHECK: invoke void @might_crash()
+// CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
+//
+// CHECK: [[invoke_cont]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@label_in_finally@@"(i8 0, i8* %[[fp]])
+// CHECK: ret void
+
+// CHECK: define internal void @"\01?fin$0@0@label_in_finally@@"(i8 %abnormal_termination, i8* %frame_pointer)
+// CHECK: br label %[[l:[^ ]*]]
+//
+// CHECK: [[l]]
+// CHECK: call void @cleanup()
+// CHECK: call i32 @check_condition()
+// CHECK: br i1 {{.*}}, label
+// CHECK: br label %[[l]]
+
+int crashed;
+void use_abnormal_termination(void) {
+ __try {
+ might_crash();
+ } __finally {
+ crashed = __abnormal_termination();
+ }
+}
+
+// CHECK-LABEL: define void @use_abnormal_termination()
+// CHECK: invoke void @might_crash()
+// CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
+//
+// CHECK: [[invoke_cont]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"(i8 0, i8* %[[fp]])
+// CHECK: ret void
+//
+// CHECK: [[lpad]]
+// CHECK-NEXT: landingpad
+// CHECK-NEXT: cleanup
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"(i8 1, i8* %[[fp]])
+// CHECK: resume { i8*, i32 }
+
+// CHECK: define internal void @"\01?fin$0@0@use_abnormal_termination@@"(i8 %abnormal_termination, i8* %frame_pointer)
+// CHECK: %[[abnormal_zext:[^ ]*]] = zext i8 %abnormal_termination to i32
+// CHECK: store i32 %[[abnormal_zext]], i32* @crashed
+// CHECK-NEXT: ret void
+
+void noreturn_noop_finally() {
+ __try {
+ __noop();
+ } __finally {
+ abort();
+ }
+}
+
+// CHECK-LABEL: define void @noreturn_noop_finally()
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@noreturn_noop_finally@@"(i8 0, i8* %[[fp]])
+// CHECK: ret void
+
+// CHECK: define internal void @"\01?fin$0@0@noreturn_noop_finally@@"(i8 %abnormal_termination, i8* %frame_pointer)
+// CHECK: call void @abort()
+// CHECK: unreachable
+
+void noreturn_finally() {
+ __try {
+ might_crash();
+ } __finally {
+ abort();
+ }
+}
+
+// CHECK-LABEL: define void @noreturn_finally()
+// CHECK: invoke void @might_crash()
+// CHECK: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
+//
+// CHECK: [[cont]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@noreturn_finally@@"(i8 0, i8* %[[fp]])
+// CHECK: ret void
+//
+// CHECK: [[lpad]]
+// CHECK: landingpad
+// CHECK-NEXT: cleanup
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@noreturn_finally@@"(i8 1, i8* %[[fp]])
+// CHECK: resume { i8*, i32 }
+
+// CHECK: define internal void @"\01?fin$0@0@noreturn_finally@@"(i8 %abnormal_termination, i8* %frame_pointer)
+// CHECK: call void @abort()
+// CHECK: unreachable
+
+int finally_with_return() {
+ __try {
+ return 42;
+ } __finally {
+ }
+}
+// CHECK-LABEL: define i32 @finally_with_return()
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0@0@finally_with_return@@"(i8 0, i8* %[[fp]])
+// CHECK-NEXT: ret i32 42
+
+// CHECK: define internal void @"\01?fin$0@0@finally_with_return@@"(i8 %abnormal_termination, i8* %frame_pointer)
+// CHECK-NOT: br i1
+// CHECK-NOT: br label
+// CHECK: ret void
+
+int nested___finally___finally() {
+ __try {
+ __try {
+ } __finally {
+ return 1;
+ }
+ } __finally {
+ // Intentionally no return here.
+ }
+ return 0;
+}
+
+// CHECK-LABEL: define i32 @nested___finally___finally
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally@@"(i8 0, i8* %[[fp]])
+// CHECK: to label %[[outercont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
+//
+// CHECK: [[outercont]]
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i8 0, i8* %[[fp]])
+// CHECK-NEXT: ret i32 0
+//
+// CHECK: [[lpad]]
+// CHECK-NEXT: landingpad
+// CHECK-NEXT: cleanup
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i8 1, i8* %[[fp]])
+
+// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally@@"(i8 %abnormal_termination, i8* %frame_pointer)
+// CHECK: ret void
+
+// CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally@@"(i8 %abnormal_termination, i8* %frame_pointer)
+// CHECK: unreachable
+
+int nested___finally___finally_with_eh_edge() {
+ __try {
+ __try {
+ might_crash();
+ } __finally {
+ return 899;
+ }
+ } __finally {
+ // Intentionally no return here.
+ }
+ return 912;
+}
+// CHECK-LABEL: define i32 @nested___finally___finally_with_eh_edge
+// CHECK: invoke void @might_crash()
+// CHECK-NEXT: to label %[[invokecont:[^ ]*]] unwind label %[[lpad1:[^ ]*]]
+//
+// [[invokecont]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"(i8 0, i8* %[[fp]])
+// CHECK: to label %[[outercont:[^ ]*]] unwind label %[[lpad2:[^ ]*]]
+//
+// CHECK: [[outercont]]
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"(i8 0, i8* %[[fp]])
+// CHECK-NEXT: ret i32 912
+//
+// CHECK: [[lpad1]]
+// CHECK-NEXT: landingpad
+// CHECK-NEXT: cleanup
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"(i8 1, i8* %[[fp]])
+// CHECK: to label %[[outercont:[^ ]*]] unwind label %[[lpad2]]
+//
+// CHECK: [[lpad2]]
+// CHECK-NEXT: landingpad
+// CHECK-NEXT: cleanup
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"(i8 1, i8* %[[fp]])
+// CHECK: resume
+
+// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"(i8 %abnormal_termination, i8* %frame_pointer)
+// CHECK: ret void
+
+// CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"(i8 %abnormal_termination, i8* %frame_pointer)
+// CHECK: unreachable