1 // RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple=x86_64-pc-windows-msvc \ 2 // RUN: -mconstructor-aliases -fexceptions -fcxx-exceptions -fnew-ms-eh \ 3 // RUN: -O1 -disable-llvm-optzns \ 4 // RUN: | FileCheck -check-prefix WIN64 %s 5 6 extern "C" void might_throw(); 7 8 // Simplify the generated IR with noexcept. 9 extern "C" void recover() noexcept(true); 10 extern "C" void handle_exception(void *e) noexcept(true); 11 12 extern "C" void catch_all() { 13 try { 14 might_throw(); 15 } catch (...) { 16 recover(); 17 } 18 } 19 20 // WIN64-LABEL: define void @catch_all() 21 // WIN64: invoke void @might_throw() 22 // WIN64-NEXT: to label %[[cont:[^ ]*]] unwind label %[[catchswitch_lpad:[^ ]*]] 23 // 24 // WIN64: [[catchswitch_lpad]] 25 // WIN64: %[[catchswitch:[^ ]*]] = catchswitch within none [label %[[catchpad_lpad:[^ ]*]]] unwind to caller 26 // 27 // WIN64: [[catchpad_lpad]] 28 // WIN64: catchpad within %[[catchswitch]] [i8* null, i32 64, i8* null] 29 // WIN64: call void @recover() 30 // WIN64: catchret from %{{.*}} to label %[[catchret:[^ ]*]] 31 // 32 // WIN64: [[catchret]] 33 // WIN64-NEXT: br label %[[ret:[^ ]*]] 34 // 35 // WIN64: [[ret]] 36 // WIN64: ret void 37 // 38 // WIN64: [[cont]] 39 // WIN64: br label %[[ret]] 40 41 extern "C" void catch_int() { 42 try { 43 might_throw(); 44 } catch (int e) { 45 handle_exception(&e); 46 } 47 } 48 49 // WIN64-LABEL: define void @catch_int() 50 // WIN64: catchpad within %{{[^ ]*}} [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i32* %[[e_addr:[^\]]*]]] 51 // 52 // The catchpad instruction starts the lifetime of 'e'. Unfortunately, that 53 // leaves us with nowhere to put lifetime.start, so we don't emit lifetime 54 // markers for now. 55 // WIN64-NOT: lifetime.start 56 // 57 // WIN64: %[[e_i8:[^ ]*]] = bitcast i32* %[[e_addr]] to i8* 58 // WIN64-NOT: lifetime.start 59 // WIN64: call void @handle_exception 60 // WIN64-SAME: (i8* %[[e_i8]]) 61 // WIN64-NOT: lifetime.end 62 // WIN64: catchret 63 64 extern "C" void catch_int_unnamed() { 65 try { 66 might_throw(); 67 } catch (int) { 68 } 69 } 70 71 // WIN64-LABEL: define void @catch_int_unnamed() 72 // WIN64: catchpad within %{{.*}} [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null] 73 // WIN64: catchret 74 75 struct A { 76 A(); 77 A(const A &o); 78 ~A(); 79 int a; 80 }; 81 82 struct B : A { 83 B(); 84 B(const B &o); 85 ~B(); 86 int b; 87 }; 88 89 extern "C" void catch_a_byval() { 90 try { 91 might_throw(); 92 } catch (A e) { 93 handle_exception(&e); 94 } 95 } 96 97 // WIN64-LABEL: define void @catch_a_byval() 98 // WIN64: %[[e_addr:[^ ]*]] = alloca %struct.A 99 // WIN64: catchpad within %{{[^ ]*}} [%rtti.TypeDescriptor7* @"\01??_R0?AUA@@@8", i32 0, %struct.A* %[[e_addr]]] 100 // WIN64: %[[e_i8:[^ ]*]] = bitcast %struct.A* %[[e_addr]] to i8* 101 // WIN64: call void @handle_exception(i8* %[[e_i8]]) 102 // WIN64: catchret 103 104 extern "C" void catch_a_ref() { 105 try { 106 might_throw(); 107 } catch (A &e) { 108 handle_exception(&e); 109 } 110 } 111 112 // WIN64-LABEL: define void @catch_a_ref() 113 // WIN64: %[[e_addr:[^ ]*]] = alloca %struct.A* 114 // WIN64: catchpad within %{{[^ ]*}} [%rtti.TypeDescriptor7* @"\01??_R0?AUA@@@8", i32 8, %struct.A** %[[e_addr]]] 115 // WIN64: %[[eptr:[^ ]*]] = load %struct.A*, %struct.A** %[[e_addr]] 116 // WIN64: %[[eptr_i8:[^ ]*]] = bitcast %struct.A* %[[eptr]] to i8* 117 // WIN64: call void @handle_exception(i8* %[[eptr_i8]]) 118 // WIN64: catchret 119 120 extern "C" void fn_with_exc_spec() throw(int) { 121 might_throw(); 122 } 123 124 // WIN64-LABEL: define void @fn_with_exc_spec() 125 // WIN64: call void @might_throw() 126 // WIN64-NEXT: ret void 127 128 extern "C" void catch_nested() { 129 try { 130 might_throw(); 131 } catch (int) { 132 try { 133 might_throw(); 134 } catch (int) { 135 might_throw(); 136 } 137 } 138 } 139 140 // WIN64-LABEL: define void @catch_nested() 141 // WIN64: invoke void @might_throw() 142 // WIN64-NEXT: to label %{{.*}} unwind label %[[catchswitch_outer:[^ ]*]] 143 // 144 // WIN64: [[catchswitch_outer]] 145 // WIN64: %[[catchswitch_outer_scope:[^ ]*]] = catchswitch within none [label %[[catch_int_outer:[^ ]*]]] unwind to caller 146 // 147 // WIN64: [[catch_int_outer]] 148 // WIN64: %[[catchpad:[^ ]*]] = catchpad within %[[catchswitch_outer_scope]] [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null] 149 // WIN64: invoke void @might_throw() 150 // WIN64-NEXT: to label %[[cont2:[^ ]*]] unwind label %[[catchswitch_inner:[^ ]*]] 151 // 152 // WIN64: [[catchswitch_inner]] 153 // WIN64: %[[catchswitch_inner_scope:[^ ]*]] = catchswitch within %[[catchpad]] [label %[[catch_int_inner:[^ ]*]]] unwind to caller 154 // 155 // WIN64: [[catch_int_inner]] 156 // WIN64: catchpad within %[[catchswitch_inner_scope]] [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i8* null] 157 // WIN64-NEXT: call void @might_throw() 158 // WIN64: catchret {{.*}} to label %[[catchret2:[^ ]*]] 159 // 160 // WIN64: [[catchret2]] 161 // WIN64: catchret {{.*}} to label %[[mainret:[^ ]*]] 162 // 163 // WIN64: [[mainret]] 164 // WIN64: ret void 165