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