|  | // RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s | 
|  | // RUN: %clang_cc1 %s -triple i686-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s | 
|  | // RUN: %clang_cc1 %s -triple aarch64-windows -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 dso_local void @basic_finally() | 
|  | // CHECK: invoke void @might_crash() | 
|  | // CHECK:     to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] | 
|  | // | 
|  | // CHECK: [[invoke_cont]] | 
|  | // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() | 
|  | // CHECK: call void @"?fin$0@0@basic_finally@@"({{i8( zeroext)?}} 0, i8* %[[fp]]) | 
|  | // CHECK-NEXT: ret void | 
|  | // | 
|  | // CHECK: [[lpad]] | 
|  | // CHECK-NEXT: %[[pad:[^ ]*]] = cleanuppad | 
|  | // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() | 
|  | // CHECK: call void @"?fin$0@0@basic_finally@@"({{i8( zeroext)?}} 1, i8* %[[fp]]) | 
|  | // CHECK-NEXT: cleanupret from %[[pad]] unwind to caller | 
|  |  | 
|  | // CHECK: define internal void @"?fin$0@0@basic_finally@@"({{.*}}) | 
|  | // CHECK-SAME: [[finally_attrs:#[0-9]+]] | 
|  | // 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 dso_local 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.localaddress() | 
|  | // CHECK: call void @"?fin$0@0@label_in_finally@@"({{i8( zeroext)?}} 0, i8* %[[fp]]) | 
|  | // CHECK: ret void | 
|  |  | 
|  | // CHECK: define internal void @"?fin$0@0@label_in_finally@@"({{.*}}) | 
|  | // CHECK-SAME: [[finally_attrs]] | 
|  | // 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 dso_local 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.localaddress() | 
|  | // CHECK: call void @"?fin$0@0@use_abnormal_termination@@"({{i8( zeroext)?}} 0, i8* %[[fp]]) | 
|  | // CHECK: ret void | 
|  | // | 
|  | // CHECK: [[lpad]] | 
|  | // CHECK-NEXT: %[[pad:[^ ]*]] = cleanuppad | 
|  | // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress() | 
|  | // CHECK: call void @"?fin$0@0@use_abnormal_termination@@"({{i8( zeroext)?}} 1, i8* %[[fp]]) | 
|  | // CHECK-NEXT: cleanupret from %[[pad]] unwind to caller | 
|  |  | 
|  | // CHECK: define internal void @"?fin$0@0@use_abnormal_termination@@"({{i8( zeroext)?}} %[[abnormal:abnormal_termination]], i8* %frame_pointer) | 
|  | // CHECK-SAME: [[finally_attrs]] | 
|  | // CHECK: %[[abnormal_zext:[^ ]*]] = zext i8 %[[abnormal]] to i32 | 
|  | // CHECK: store i32 %[[abnormal_zext]], i32* @crashed | 
|  | // CHECK-NEXT: ret void | 
|  |  | 
|  | void noreturn_noop_finally() { | 
|  | __try { | 
|  | __noop(); | 
|  | } __finally { | 
|  | abort(); | 
|  | } | 
|  | } | 
|  |  | 
|  | // CHECK-LABEL: define dso_local void @noreturn_noop_finally() | 
|  | // CHECK: call void @"?fin$0@0@noreturn_noop_finally@@"({{.*}}) | 
|  | // CHECK: ret void | 
|  |  | 
|  | // CHECK: define internal void @"?fin$0@0@noreturn_noop_finally@@"({{.*}}) | 
|  | // CHECK-SAME: [[finally_attrs]] | 
|  | // CHECK: call void @abort() | 
|  | // CHECK: unreachable | 
|  |  | 
|  | void noreturn_finally() { | 
|  | __try { | 
|  | might_crash(); | 
|  | } __finally { | 
|  | abort(); | 
|  | } | 
|  | } | 
|  |  | 
|  | // CHECK-LABEL: define dso_local void @noreturn_finally() | 
|  | // CHECK: invoke void @might_crash() | 
|  | // CHECK:     to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]] | 
|  | // | 
|  | // CHECK: [[cont]] | 
|  | // CHECK: call void @"?fin$0@0@noreturn_finally@@"({{.*}}) | 
|  | // CHECK: ret void | 
|  | // | 
|  | // CHECK: [[lpad]] | 
|  | // CHECK-NEXT: %[[pad:[^ ]*]] = cleanuppad | 
|  | // CHECK: call void @"?fin$0@0@noreturn_finally@@"({{.*}}) | 
|  | // CHECK-NEXT: cleanupret from %[[pad]] unwind to caller | 
|  |  | 
|  | // CHECK: define internal void @"?fin$0@0@noreturn_finally@@"({{.*}}) | 
|  | // CHECK-SAME: [[finally_attrs]] | 
|  | // CHECK: call void @abort() | 
|  | // CHECK: unreachable | 
|  |  | 
|  | int finally_with_return() { | 
|  | __try { | 
|  | return 42; | 
|  | } __finally { | 
|  | } | 
|  | } | 
|  | // CHECK-LABEL: define dso_local i32 @finally_with_return() | 
|  | // CHECK: call void @"?fin$0@0@finally_with_return@@"({{.*}}) | 
|  | // CHECK-NEXT: ret i32 42 | 
|  |  | 
|  | // CHECK: define internal void @"?fin$0@0@finally_with_return@@"({{.*}}) | 
|  | // CHECK-SAME: [[finally_attrs]] | 
|  | // 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 dso_local i32 @nested___finally___finally | 
|  | // CHECK: invoke void @"?fin$1@0@nested___finally___finally@@"({{.*}}) | 
|  | // CHECK:          to label %[[outercont:[^ ]*]] unwind label %[[lpad:[^ ]*]] | 
|  | // | 
|  | // CHECK: [[outercont]] | 
|  | // CHECK: call void @"?fin$0@0@nested___finally___finally@@"({{.*}}) | 
|  | // CHECK-NEXT: ret i32 0 | 
|  | // | 
|  | // CHECK: [[lpad]] | 
|  | // CHECK-NEXT: %[[pad:[^ ]*]] = cleanuppad | 
|  | // CHECK: call void @"?fin$0@0@nested___finally___finally@@"({{.*}}) | 
|  | // CHECK-NEXT: cleanupret from %[[pad]] unwind to caller | 
|  |  | 
|  | // CHECK-LABEL: define internal void @"?fin$0@0@nested___finally___finally@@"({{.*}}) | 
|  | // CHECK-SAME: [[finally_attrs]] | 
|  | // CHECK: ret void | 
|  |  | 
|  | // CHECK-LABEL: define internal void @"?fin$1@0@nested___finally___finally@@"({{.*}}) | 
|  | // CHECK-SAME: [[finally_attrs]] | 
|  | // CHECK: unreachable | 
|  |  | 
|  | // FIXME: Our behavior seems suspiciously different. | 
|  |  | 
|  | int nested___finally___finally_with_eh_edge() { | 
|  | __try { | 
|  | __try { | 
|  | might_crash(); | 
|  | } __finally { | 
|  | return 899; | 
|  | } | 
|  | } __finally { | 
|  | // Intentionally no return here. | 
|  | } | 
|  | return 912; | 
|  | } | 
|  | // CHECK-LABEL: define dso_local i32 @nested___finally___finally_with_eh_edge | 
|  | // CHECK: invoke void @might_crash() | 
|  | // CHECK-NEXT: to label %[[invokecont:[^ ]*]] unwind label %[[lpad1:[^ ]*]] | 
|  | // | 
|  | // [[invokecont]] | 
|  | // CHECK: invoke void @"?fin$1@0@nested___finally___finally_with_eh_edge@@"({{.*}}) | 
|  | // CHECK-NEXT:       to label %[[outercont:[^ ]*]] unwind label %[[lpad2:[^ ]*]] | 
|  | // | 
|  | // CHECK: [[outercont]] | 
|  | // CHECK: call void @"?fin$0@0@nested___finally___finally_with_eh_edge@@"({{.*}}) | 
|  | // CHECK-NEXT: ret i32 912 | 
|  | // | 
|  | // CHECK: [[lpad1]] | 
|  | // CHECK-NEXT: %[[innerpad:[^ ]*]] = cleanuppad | 
|  | // CHECK: invoke void @"?fin$1@0@nested___finally___finally_with_eh_edge@@"({{.*}}) | 
|  | // CHECK-NEXT:    label %[[innercleanupretbb:[^ ]*]] unwind label %[[lpad2:[^ ]*]] | 
|  | // | 
|  | // CHECK: [[innercleanupretbb]] | 
|  | // CHECK-NEXT: cleanupret from %[[innerpad]] unwind label %[[lpad2]] | 
|  | // | 
|  | // CHECK: [[lpad2]] | 
|  | // CHECK-NEXT: %[[outerpad:[^ ]*]] = cleanuppad | 
|  | // CHECK: call void @"?fin$0@0@nested___finally___finally_with_eh_edge@@"({{.*}}) | 
|  | // CHECK-NEXT: cleanupret from %[[outerpad]] unwind to caller | 
|  |  | 
|  | // CHECK-LABEL: define internal void @"?fin$0@0@nested___finally___finally_with_eh_edge@@"({{.*}}) | 
|  | // CHECK-SAME: [[finally_attrs]] | 
|  | // CHECK: ret void | 
|  |  | 
|  | // CHECK-LABEL: define internal void @"?fin$1@0@nested___finally___finally_with_eh_edge@@"({{.*}}) | 
|  | // CHECK-SAME: [[finally_attrs]] | 
|  | // CHECK: unreachable | 
|  |  | 
|  | void finally_within_finally() { | 
|  | __try { | 
|  | might_crash(); | 
|  | } __finally { | 
|  | __try { | 
|  | might_crash(); | 
|  | } __finally { | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // CHECK-LABEL: define dso_local void @finally_within_finally( | 
|  | // CHECK: invoke void @might_crash( | 
|  |  | 
|  | // CHECK: call void @"?fin$0@0@finally_within_finally@@"( | 
|  | // CHECK: call void @"?fin$0@0@finally_within_finally@@"({{.*}}) [ "funclet"( | 
|  |  | 
|  | // CHECK-LABEL: define internal void @"?fin$0@0@finally_within_finally@@"({{[^)]*}}) | 
|  | // CHECK-SAME: [[finally_attrs]] | 
|  | // CHECK: invoke void @might_crash( | 
|  |  | 
|  | // CHECK: call void @"?fin$1@0@finally_within_finally@@"( | 
|  | // CHECK: call void @"?fin$1@0@finally_within_finally@@"({{.*}}) [ "funclet"( | 
|  |  | 
|  | // CHECK-LABEL: define internal void @"?fin$1@0@finally_within_finally@@"({{[^)]*}}) | 
|  | // CHECK-SAME: [[finally_attrs]] | 
|  |  | 
|  | void cleanup_with_func(const char *); | 
|  | void finally_with_func() { | 
|  | __try { | 
|  | might_crash(); | 
|  | } __finally { | 
|  | cleanup_with_func(__func__); | 
|  | } | 
|  | } | 
|  |  | 
|  | // CHECK-LABEL: define internal void @"?fin$0@0@finally_with_func@@"({{[^)]*}}) | 
|  | // CHECK: call void @cleanup_with_func(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @"??_C@_0BC@COAGBPGM@finally_with_func?$AA@", i{{32|64}} 0, i{{32|64}} 0)) | 
|  |  | 
|  | // Look for the absence of noinline. Enum attributes come first, so check that | 
|  | // a string attribute is the first to verify that no enum attributes are | 
|  | // present. | 
|  | // CHECK: attributes [[finally_attrs]] = { "{{.*}}" } |