291 lines · c
1// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -O1 -disable-llvm-passes -o - | FileCheck %s2// RUN: %clang_cc1 %s -triple i686-pc-win32 -fms-extensions -emit-llvm -O1 -disable-llvm-passes -o - | FileCheck %s3// RUN: %clang_cc1 %s -triple aarch64-windows -fms-extensions -emit-llvm -O1 -disable-llvm-passes -o - | FileCheck %s4// NOTE: we're passing "-O1 -disable-llvm-passes" to avoid adding optnone and noinline everywhere.5 6void abort(void) __attribute__((noreturn));7void might_crash(void);8void cleanup(void);9int check_condition(void);10void basic_finally(void) {11 __try {12 might_crash();13 } __finally {14 cleanup();15 }16}17 18// CHECK-LABEL: define dso_local void @basic_finally()19// CHECK: invoke void @might_crash()20// CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]21//22// CHECK: [[invoke_cont]]23// CHECK: %[[fp:[^ ]*]] = call ptr @llvm.localaddress()24// CHECK: call void @"?fin$0@0@basic_finally@@"({{i8 noundef( zeroext)?}} 0, ptr noundef %[[fp]])25// CHECK-NEXT: ret void26//27// CHECK: [[lpad]]28// CHECK-NEXT: %[[pad:[^ ]*]] = cleanuppad29// CHECK: %[[fp:[^ ]*]] = call ptr @llvm.localaddress()30// CHECK: call void @"?fin$0@0@basic_finally@@"({{i8 noundef( zeroext)?}} 1, ptr noundef %[[fp]])31// CHECK-NEXT: cleanupret from %[[pad]] unwind to caller32 33// CHECK: define internal void @"?fin$0@0@basic_finally@@"({{.*}})34// CHECK-SAME: [[finally_attrs:#[0-9]+]]35// CHECK: call void @cleanup()36 37// Mostly check that we don't double emit 'r' which would crash.38void decl_in_finally(void) {39 __try {40 might_crash();41 } __finally {42 int r;43 }44}45 46// Ditto, don't crash double emitting 'l'.47void label_in_finally(void) {48 __try {49 might_crash();50 } __finally {51l:52 cleanup();53 if (check_condition())54 goto l;55 }56}57 58// CHECK-LABEL: define dso_local void @label_in_finally()59// CHECK: invoke void @might_crash()60// CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]61//62// CHECK: [[invoke_cont]]63// CHECK: %[[fp:[^ ]*]] = call ptr @llvm.localaddress()64// CHECK: call void @"?fin$0@0@label_in_finally@@"({{i8 noundef( zeroext)?}} 0, ptr noundef %[[fp]])65// CHECK: ret void66 67// CHECK: define internal void @"?fin$0@0@label_in_finally@@"({{.*}})68// CHECK-SAME: [[finally_attrs]]69// CHECK: br label %[[l:[^ ]*]]70//71// CHECK: [[l]]72// CHECK: call void @cleanup()73// CHECK: call i32 @check_condition()74// CHECK: br i1 {{.*}}, label75// CHECK: br label %[[l]]76 77int crashed;78void use_abnormal_termination(void) {79 __try {80 might_crash();81 } __finally {82 crashed = __abnormal_termination();83 }84}85 86// CHECK-LABEL: define dso_local void @use_abnormal_termination()87// CHECK: invoke void @might_crash()88// CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]89//90// CHECK: [[invoke_cont]]91// CHECK: %[[fp:[^ ]*]] = call ptr @llvm.localaddress()92// CHECK: call void @"?fin$0@0@use_abnormal_termination@@"({{i8 noundef( zeroext)?}} 0, ptr noundef %[[fp]])93// CHECK: ret void94//95// CHECK: [[lpad]]96// CHECK-NEXT: %[[pad:[^ ]*]] = cleanuppad97// CHECK: %[[fp:[^ ]*]] = call ptr @llvm.localaddress()98// CHECK: call void @"?fin$0@0@use_abnormal_termination@@"({{i8 noundef( zeroext)?}} 1, ptr noundef %[[fp]])99// CHECK-NEXT: cleanupret from %[[pad]] unwind to caller100 101// CHECK: define internal void @"?fin$0@0@use_abnormal_termination@@"({{i8 noundef( zeroext)?}} %[[abnormal:abnormal_termination]], ptr noundef %frame_pointer)102// CHECK-SAME: [[finally_attrs]]103// CHECK: %[[abnormal_zext:[^ ]*]] = zext i8 %[[abnormal]] to i32104// CHECK: store i32 %[[abnormal_zext]], ptr @crashed105// CHECK-NEXT: ret void106 107void noreturn_noop_finally(void) {108 __try {109 __noop();110 } __finally {111 abort();112 }113}114 115// CHECK-LABEL: define dso_local void @noreturn_noop_finally()116// CHECK: call void @"?fin$0@0@noreturn_noop_finally@@"({{.*}})117// CHECK: ret void118 119// CHECK: define internal void @"?fin$0@0@noreturn_noop_finally@@"({{.*}})120// CHECK-SAME: [[finally_attrs]]121// CHECK: call void @abort()122// CHECK: unreachable123 124void noreturn_finally(void) {125 __try {126 might_crash();127 } __finally {128 abort();129 }130}131 132// CHECK-LABEL: define dso_local void @noreturn_finally()133// CHECK: invoke void @might_crash()134// CHECK: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]135//136// CHECK: [[cont]]137// CHECK: call void @"?fin$0@0@noreturn_finally@@"({{.*}})138// CHECK: ret void139//140// CHECK: [[lpad]]141// CHECK-NEXT: %[[pad:[^ ]*]] = cleanuppad142// CHECK: call void @"?fin$0@0@noreturn_finally@@"({{.*}})143// CHECK-NEXT: cleanupret from %[[pad]] unwind to caller144 145// CHECK: define internal void @"?fin$0@0@noreturn_finally@@"({{.*}})146// CHECK-SAME: [[finally_attrs]]147// CHECK: call void @abort()148// CHECK: unreachable149 150int finally_with_return(void) {151 __try {152 return 42;153 } __finally {154 }155}156// CHECK-LABEL: define dso_local i32 @finally_with_return()157// CHECK: store i32 1, ptr %cleanup.dest.slot158// CHECK: %cleanup.dest = load i32, ptr %cleanup.dest.slot159// CHECK: icmp ne i32 %cleanup.dest160// CHECK: call void @"?fin$0@0@finally_with_return@@"({{.*}})161// CHECK: ret i32 42162 163// CHECK: define internal void @"?fin$0@0@finally_with_return@@"({{.*}})164// CHECK-SAME: [[finally_attrs]]165// CHECK-NOT: br i1166// CHECK-NOT: br label167// CHECK: ret void168 169int nested___finally___finally(void) {170 __try {171 __try {172 } __finally {173 return 1;174 }175 } __finally {176 // Intentionally no return here.177 }178 return 0;179}180 181// CHECK-LABEL: define dso_local i32 @nested___finally___finally182// CHECK: invoke void @"?fin$1@0@nested___finally___finally@@"({{.*}})183// CHECK: to label %[[outercont:[^ ]*]] unwind label %[[lpad:[^ ]*]]184//185// CHECK: [[outercont]]186// CHECK: call void @"?fin$0@0@nested___finally___finally@@"({{.*}})187// CHECK-NEXT: ret i32 0188//189// CHECK: [[lpad]]190// CHECK-NEXT: %[[pad:[^ ]*]] = cleanuppad191// CHECK: call void @"?fin$0@0@nested___finally___finally@@"({{.*}})192// CHECK-NEXT: cleanupret from %[[pad]] unwind to caller193 194// CHECK-LABEL: define internal void @"?fin$0@0@nested___finally___finally@@"({{.*}})195// CHECK-SAME: [[finally_attrs]]196// CHECK: ret void197 198// CHECK-LABEL: define internal void @"?fin$1@0@nested___finally___finally@@"({{.*}})199// CHECK-SAME: [[finally_attrs]]200// CHECK: unreachable201 202// FIXME: Our behavior seems suspiciously different.203 204int nested___finally___finally_with_eh_edge(void) {205 __try {206 __try {207 might_crash();208 } __finally {209 return 899;210 }211 } __finally {212 // Intentionally no return here.213 }214 return 912;215}216// CHECK-LABEL: define dso_local i32 @nested___finally___finally_with_eh_edge217// CHECK: invoke void @might_crash()218// CHECK-NEXT: to label %[[invokecont:[^ ]*]] unwind label %[[lpad1:[^ ]*]]219//220// [[invokecont]]221// CHECK: invoke void @"?fin$1@0@nested___finally___finally_with_eh_edge@@"({{.*}})222// CHECK-NEXT: to label %[[outercont:[^ ]*]] unwind label %[[lpad2:[^ ]*]]223//224// CHECK: [[outercont]]225// CHECK: call void @"?fin$0@0@nested___finally___finally_with_eh_edge@@"({{.*}})226// CHECK-NEXT: ret i32 912227//228// CHECK: [[lpad1]]229// CHECK-NEXT: %[[innerpad:[^ ]*]] = cleanuppad230// CHECK: invoke void @"?fin$1@0@nested___finally___finally_with_eh_edge@@"({{.*}})231// CHECK-NEXT: label %[[innercleanupretbb:[^ ]*]] unwind label %[[lpad2:[^ ]*]]232//233// CHECK: [[innercleanupretbb]]234// CHECK-NEXT: cleanupret from %[[innerpad]] unwind label %[[lpad2]]235//236// CHECK: [[lpad2]]237// CHECK-NEXT: %[[outerpad:[^ ]*]] = cleanuppad238// CHECK: call void @"?fin$0@0@nested___finally___finally_with_eh_edge@@"({{.*}})239// CHECK-NEXT: cleanupret from %[[outerpad]] unwind to caller240 241// CHECK-LABEL: define internal void @"?fin$0@0@nested___finally___finally_with_eh_edge@@"({{.*}})242// CHECK-SAME: [[finally_attrs]]243// CHECK: ret void244 245// CHECK-LABEL: define internal void @"?fin$1@0@nested___finally___finally_with_eh_edge@@"({{.*}})246// CHECK-SAME: [[finally_attrs]]247// CHECK: unreachable248 249void finally_within_finally(void) {250 __try {251 might_crash();252 } __finally {253 __try {254 might_crash();255 } __finally {256 }257 }258}259 260// CHECK-LABEL: define dso_local void @finally_within_finally(261// CHECK: invoke void @might_crash(262 263// CHECK: call void @"?fin$0@0@finally_within_finally@@"(264// CHECK: call void @"?fin$0@0@finally_within_finally@@"({{.*}}) [ "funclet"(265 266// CHECK-LABEL: define internal void @"?fin$0@0@finally_within_finally@@"({{[^)]*}})267// CHECK-SAME: [[finally_attrs]]268// CHECK: invoke void @might_crash(269 270// CHECK: call void @"?fin$1@0@finally_within_finally@@"(271// CHECK: call void @"?fin$1@0@finally_within_finally@@"({{.*}}) [ "funclet"(272 273// CHECK-LABEL: define internal void @"?fin$1@0@finally_within_finally@@"({{[^)]*}})274// CHECK-SAME: [[finally_attrs]]275 276void cleanup_with_func(const char *);277void finally_with_func(void) {278 __try {279 might_crash();280 } __finally {281 cleanup_with_func(__func__);282 }283}284 285// CHECK-LABEL: define internal void @"?fin$0@0@finally_with_func@@"({{[^)]*}})286// CHECK: call void @cleanup_with_func(ptr noundef @"??_C@_0BC@COAGBPGM@finally_with_func?$AA@")287 288// Look for the absence of noinline. nounwind is expected; any further289// attributes should be string attributes.290// CHECK: attributes [[finally_attrs]] = { nounwind "{{.*}}" }291