diff options
Diffstat (limited to 'test/CodeGen/exceptions-seh-finally.c')
-rw-r--r-- | test/CodeGen/exceptions-seh-finally.c | 242 |
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 0000000..345d514 --- /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 |