|  | // RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s | 
|  |  | 
|  | void g(void); | 
|  |  | 
|  | ////////////////////////////////////////////////////////////////////////////// | 
|  | // __leave with __except | 
|  |  | 
|  | // Nothing in the __try block can trap, so __try.cont isn't created. | 
|  | int __leave_with___except_simple(void) { | 
|  | int myres = 0; | 
|  | __try { | 
|  | myres = 15; | 
|  | __leave; | 
|  | myres = 23; | 
|  | } __except (1) { | 
|  | return 0; | 
|  | } | 
|  | return 1; | 
|  | } | 
|  | // CHECK-LABEL: define dso_local i32 @__leave_with___except_simple() | 
|  | // CHECK: store i32 15, ptr %myres | 
|  | // CHECK-NEXT: br label %[[tryleave:[^ ]*]] | 
|  | // CHECK-NOT: store i32 23 | 
|  | // CHECK: [[tryleave]] | 
|  | // CHECK-NEXT: ret i32 1 | 
|  |  | 
|  |  | 
|  | // The "normal" case. | 
|  | int __leave_with___except(void) { | 
|  | int myres = 0; | 
|  | __try { | 
|  | g(); | 
|  | __leave; | 
|  | myres = 23; | 
|  | } __except (1) { | 
|  | return 0; | 
|  | } | 
|  | return 1; | 
|  | } | 
|  | // CHECK-LABEL: define dso_local i32 @__leave_with___except() | 
|  | // CHECK: invoke void @g() | 
|  | // CHECK-NEXT:       to label %[[cont:.*]] unwind label %{{.*}} | 
|  | // For __excepts, instead of an explicit __try.__leave label, we could use | 
|  | // use invoke.cont as __leave jump target instead.  However, not doing this | 
|  | // keeps the CodeGen code simpler, __leave is very rare, and SimplifyCFG will | 
|  | // simplify this anyways. | 
|  | // CHECK: [[cont]] | 
|  | // CHECK-NEXT: br label %[[tryleave:[^ ]*]] | 
|  | // CHECK-NOT: store i32 23 | 
|  | // CHECK: [[tryleave]] | 
|  | // CHECK-NEXT: br label % | 
|  |  | 
|  |  | 
|  | ////////////////////////////////////////////////////////////////////////////// | 
|  | // __leave with __finally | 
|  |  | 
|  | void abort(void) __attribute__((noreturn)); | 
|  |  | 
|  | // Nothing in the __try block can trap, so __finally.cont and friends aren't | 
|  | // created. | 
|  | int __leave_with___finally_simple(void) { | 
|  | int myres = 0; | 
|  | __try { | 
|  | myres = 15; | 
|  | __leave; | 
|  | myres = 23; | 
|  | } __finally { | 
|  | return 0; | 
|  | } | 
|  | return 1; | 
|  | } | 
|  | // CHECK-LABEL: define dso_local i32 @__leave_with___finally_simple() | 
|  | // CHECK: store i32 15, ptr %myres | 
|  | // CHECK-NEXT: br label %[[tryleave:[^ ]*]] | 
|  | // CHECK-NOT: store i32 23 | 
|  | // CHECK: [[tryleave]] | 
|  | // CHECK-NEXT: %[[fp:[^ ]*]] = call ptr @llvm.localaddress() | 
|  | // CHECK-NEXT: call void @"?fin$0@0@__leave_with___finally_simple@@"(i8 noundef 0, ptr noundef %[[fp]]) | 
|  |  | 
|  | // __finally block doesn't return, __finally.cont doesn't exist. | 
|  | int __leave_with___finally_noreturn(void) { | 
|  | int myres = 0; | 
|  | __try { | 
|  | myres = 15; | 
|  | __leave; | 
|  | myres = 23; | 
|  | } __finally { | 
|  | abort(); | 
|  | } | 
|  | return 1; | 
|  | } | 
|  | // CHECK-LABEL: define dso_local i32 @__leave_with___finally_noreturn() | 
|  | // CHECK: store i32 15, ptr %myres | 
|  | // CHECK-NEXT: br label %[[tryleave:[^ ]*]] | 
|  | // CHECK-NOT: store i32 23 | 
|  | // CHECK: [[tryleave]] | 
|  | // CHECK-NEXT: %[[fp:[^ ]*]] = call ptr @llvm.localaddress() | 
|  | // CHECK-NEXT: call void @"?fin$0@0@__leave_with___finally_noreturn@@"(i8 noundef 0, ptr noundef %[[fp]]) | 
|  |  | 
|  | // The "normal" case. | 
|  | int __leave_with___finally(void) { | 
|  | int myres = 0; | 
|  | __try { | 
|  | g(); | 
|  | __leave; | 
|  | myres = 23; | 
|  | } __finally { | 
|  | return 0; | 
|  | } | 
|  | return 1; | 
|  | } | 
|  | // CHECK-LABEL: define dso_local i32 @__leave_with___finally() | 
|  | // CHECK: invoke void @g() | 
|  | // CHECK-NEXT:       to label %[[cont:.*]] unwind label %{{.*}} | 
|  | // For __finally, there needs to be an explicit __try.__leave, because | 
|  | // abnormal.termination.slot needs to be set there. | 
|  | // CHECK: [[cont]] | 
|  | // CHECK-NEXT: br label %[[tryleave:[^ ]*]] | 
|  | // CHECK-NOT: store i32 23 | 
|  | // CHECK: [[tryleave]] | 
|  | // CHECK-NEXT: %[[fp:[^ ]*]] = call ptr @llvm.localaddress() | 
|  | // CHECK-NEXT: call void @"?fin$0@0@__leave_with___finally@@"(i8 noundef 0, ptr noundef %[[fp]]) | 
|  |  | 
|  |  | 
|  | ////////////////////////////////////////////////////////////////////////////// | 
|  | // Mixed, nested cases. | 
|  |  | 
|  | int nested___except___finally(void) { | 
|  | int myres = 0; | 
|  | __try { | 
|  | __try { | 
|  | g(); | 
|  | } __finally { | 
|  | g(); | 
|  | __leave;  // Refers to the outer __try, not the __finally! | 
|  | myres = 23; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | myres = 51; | 
|  | } __except (1) { | 
|  | } | 
|  | return 1; | 
|  | } | 
|  | // CHECK-LABEL: define dso_local i32 @nested___except___finally() | 
|  |  | 
|  | // CHECK-LABEL: invoke void @g() | 
|  | // CHECK-NEXT:       to label %[[g1_cont1:.*]] unwind label %[[g1_lpad:.*]] | 
|  |  | 
|  | // CHECK: [[g1_cont1]] | 
|  | // CHECK-NEXT: %[[fp:[^ ]*]] = call ptr @llvm.localaddress() | 
|  | // CHECK-NEXT: invoke void @"?fin$0@0@nested___except___finally@@"(i8 noundef 0, ptr noundef %[[fp]]) | 
|  | // CHECK-NEXT:       to label %[[fin_cont:.*]] unwind label %[[g2_lpad:.*]] | 
|  |  | 
|  | // CHECK: [[fin_cont]] | 
|  | // CHECK: store i32 51, ptr % | 
|  | // CHECK-NEXT: br label %[[trycont:[^ ]*]] | 
|  |  | 
|  | // CHECK: [[g1_lpad]] | 
|  | // CHECK-NEXT: cleanuppad | 
|  | // CHECK-NEXT: %[[fp:[^ ]*]] = call ptr @llvm.localaddress() | 
|  | // CHECK-NEXT: invoke void @"?fin$0@0@nested___except___finally@@"(i8 noundef 1, ptr noundef %[[fp]]) | 
|  | // CHECK-NEXT:       to label %[[g1_resume:.*]] unwind label %[[g2_lpad]] | 
|  | // CHECK: cleanupret {{.*}} unwind label %[[g2_lpad]] | 
|  |  | 
|  | // CHECK: [[g2_lpad]] | 
|  | // CHECK: catchpad {{.*}} [ptr null] | 
|  | // CHECK: catchret | 
|  | // CHECK: br label %[[trycont]] | 
|  |  | 
|  | // CHECK: [[trycont]] | 
|  | // CHECK-NEXT: ret i32 1 | 
|  |  | 
|  | // CHECK-LABEL: define internal void @"?fin$0@0@nested___except___finally@@"(i8 noundef %abnormal_termination, ptr noundef %frame_pointer) | 
|  | // CHECK: call void @g() | 
|  | // CHECK: unreachable | 
|  |  | 
|  | int nested___except___except(void) { | 
|  | int myres = 0; | 
|  | __try { | 
|  | __try { | 
|  | g(); | 
|  | myres = 16; | 
|  | } __except (1) { | 
|  | g(); | 
|  | __leave;  // Refers to the outer __try, not the __except we're in! | 
|  | myres = 23; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | myres = 51; | 
|  | } __except (1) { | 
|  | } | 
|  | return 1; | 
|  | } | 
|  | // The order of basic blocks in the below doesn't matter. | 
|  | // CHECK-LABEL: define dso_local i32 @nested___except___except() | 
|  |  | 
|  | // CHECK-LABEL: invoke void @g() | 
|  | // CHECK-NEXT:       to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]] | 
|  |  | 
|  | // CHECK: [[g1_lpad]] | 
|  | // CHECK: catchpad {{.*}} [ptr null] | 
|  | // CHECK: catchret {{.*}} to label %[[except:[^ ]*]] | 
|  | // CHECK: [[except]] | 
|  | // CHECK: invoke void @g() | 
|  | // CHECK-NEXT:       to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]] | 
|  |  | 
|  | // CHECK: [[g2_lpad]] | 
|  | // CHECK: catchpad {{.*}} [ptr null] | 
|  | // CHECK: catchret | 
|  | // CHECK: br label %[[trycont4:[^ ]*]] | 
|  |  | 
|  | // CHECK: [[trycont4]] | 
|  | // CHECK-NEXT: ret i32 1 | 
|  |  | 
|  | // CHECK: [[g2_cont]] | 
|  | // CHECK-NEXT: br label %[[tryleave:[^ ]*]] | 
|  | // CHECK-NOT: store i32 23 | 
|  |  | 
|  | // CHECK: [[g1_cont]] | 
|  | // CHECK: store i32 16, ptr %myres | 
|  | // CHECK-NEXT: br label %[[trycont:[^ ]*]] | 
|  |  | 
|  | // CHECK: [[trycont]] | 
|  | // CHECK-NEXT: store i32 51, ptr %myres | 
|  | // CHECK-NEXT: br label %[[tryleave]] | 
|  |  | 
|  | // CHECK: [[tryleave]] | 
|  | // CHECK-NEXT: br label %[[trycont4]] | 
|  |  | 
|  | int nested___finally___except(void) { | 
|  | int myres = 0; | 
|  | __try { | 
|  | __try { | 
|  | g(); | 
|  | } __except (1) { | 
|  | g(); | 
|  | __leave;  // Refers to the outer __try, not the __except! | 
|  | myres = 23; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | myres = 51; | 
|  | } __finally { | 
|  | } | 
|  | return 1; | 
|  | } | 
|  | // The order of basic blocks in the below doesn't matter. | 
|  | // CHECK-LABEL: define dso_local i32 @nested___finally___except() | 
|  |  | 
|  | // CHECK-LABEL: invoke void @g() | 
|  | // CHECK-NEXT:       to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]] | 
|  |  | 
|  | // CHECK: [[g1_lpad]] | 
|  | // CHECK: catchpad | 
|  | // CHECK: catchret | 
|  | // CHECK: invoke void @g() | 
|  | // CHECK-NEXT:       to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]] | 
|  |  | 
|  | // CHECK: [[g2_cont]] | 
|  | // CHECK: br label %[[tryleave:[^ ]*]] | 
|  | // CHECK-NOT: 23 | 
|  |  | 
|  | // CHECK: [[g1_cont]] | 
|  | // CHECK-NEXT: br label %[[trycont:[^ ]*]] | 
|  |  | 
|  | // CHECK: [[trycont]] | 
|  | // CHECK: store i32 51, ptr % | 
|  | // CHECK-NEXT: br label %[[tryleave]] | 
|  |  | 
|  | // CHECK: [[tryleave]] | 
|  | // CHECK: %[[fp:[^ ]*]] = call ptr @llvm.localaddress() | 
|  | // CHECK-NEXT: call void @"?fin$0@0@nested___finally___except@@"(i8 noundef 0, ptr noundef %[[fp]]) | 
|  | // CHECK-NEXT: ret i32 1 | 
|  |  | 
|  | // CHECK: [[g2_lpad]] | 
|  | // CHECK: cleanuppad | 
|  | // CHECK: %[[fp:[^ ]*]] = call ptr @llvm.localaddress() | 
|  | // CHECK-NEXT: call void @"?fin$0@0@nested___finally___except@@"(i8 noundef 1, ptr noundef %[[fp]]) | 
|  | // CHECK: cleanupret {{.*}} unwind to caller | 
|  |  | 
|  | // CHECK-LABEL: define internal void @"?fin$0@0@nested___finally___except@@"(i8 noundef %abnormal_termination, ptr noundef %frame_pointer) | 
|  | // CHECK: ret void | 
|  |  | 
|  | int nested___finally___finally(void) { | 
|  | int myres = 0; | 
|  | __try { | 
|  | __try { | 
|  | g(); | 
|  | myres = 16; | 
|  | } __finally { | 
|  | g(); | 
|  | __leave;  // Refers to the outer __try, not the __finally we're in! | 
|  | myres = 23; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | myres = 51; | 
|  | } __finally { | 
|  | } | 
|  | return 1; | 
|  | } | 
|  | // The order of basic blocks in the below doesn't matter. | 
|  | // CHECK-LABEL: define dso_local i32 @nested___finally___finally() | 
|  |  | 
|  | // CHECK: invoke void @g() | 
|  | // CHECK-NEXT:       to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]] | 
|  |  | 
|  | // CHECK: [[g1_cont]] | 
|  | // CHECK: store i32 16, ptr %[[myres:[^ ]*]], | 
|  | // CHECK: %[[fp:[^ ]*]] = call ptr @llvm.localaddress() | 
|  | // CHECK-NEXT: invoke void @"?fin$1@0@nested___finally___finally@@"(i8 noundef 0, ptr noundef %[[fp]]) | 
|  | // CHECK-NEXT:       to label %[[finally_cont:.*]] unwind label %[[g2_lpad:.*]] | 
|  |  | 
|  | // CHECK: [[finally_cont]] | 
|  | // CHECK: store i32 51, ptr %[[myres]] | 
|  | // CHECK: %[[fp:[^ ]*]] = call ptr @llvm.localaddress() | 
|  | // CHECK-NEXT: call void @"?fin$0@0@nested___finally___finally@@"(i8 noundef 0, ptr noundef %[[fp]]) | 
|  | // CHECK-NEXT: ret i32 1 | 
|  |  | 
|  | // CHECK: [[g1_lpad]] | 
|  | // CHECK-NEXT: %[[padtoken:[^ ]*]] = cleanuppad within none [] | 
|  | // CHECK-NEXT: %[[fp:[^ ]*]] = call ptr @llvm.localaddress() | 
|  | // CHECK-NEXT: invoke void @"?fin$1@0@nested___finally___finally@@"(i8 noundef 1, ptr noundef %[[fp]]) | 
|  | // CHECK-NEXT:       to label %[[finally_cont2:.*]] unwind label %[[g2_lpad]] | 
|  | // CHECK: [[finally_cont2]] | 
|  | // CHECK: cleanupret from %[[padtoken]] unwind label %[[g2_lpad]] | 
|  |  | 
|  | // CHECK: [[g2_lpad]] | 
|  | // CHECK-NEXT: %[[padtoken:[^ ]*]] = cleanuppad within none [] | 
|  | // CHECK-NEXT: %[[fp:[^ ]*]] = call ptr @llvm.localaddress() | 
|  | // CHECK-NEXT: call void @"?fin$0@0@nested___finally___finally@@"(i8 noundef 1, ptr noundef %[[fp]]) | 
|  | // CHECK: cleanupret from %[[padtoken]] unwind to caller | 
|  |  | 
|  | // CHECK-LABEL: define internal void @"?fin$0@0@nested___finally___finally@@"(i8 noundef %abnormal_termination, ptr noundef %frame_pointer) | 
|  | // CHECK: ret void | 
|  |  | 
|  | // CHECK-LABEL: define internal void @"?fin$1@0@nested___finally___finally@@"(i8 noundef %abnormal_termination, ptr noundef %frame_pointer) | 
|  | // CHECK: call void @g() | 
|  | // CHECK: unreachable |