xref: /aosp_15_r20/external/clang/test/CodeGen/exceptions-seh-finally.c (revision 67e74705e28f6214e480b399dd47ea732279e315)
1*67e74705SXin Li // RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s
2*67e74705SXin Li // RUN: %clang_cc1 %s -triple i686-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s
3*67e74705SXin Li 
4*67e74705SXin Li void abort(void) __attribute__((noreturn));
5*67e74705SXin Li void might_crash(void);
6*67e74705SXin Li void cleanup(void);
7*67e74705SXin Li int check_condition(void);
basic_finally(void)8*67e74705SXin Li void basic_finally(void) {
9*67e74705SXin Li   __try {
10*67e74705SXin Li     might_crash();
11*67e74705SXin Li   } __finally {
12*67e74705SXin Li     cleanup();
13*67e74705SXin Li   }
14*67e74705SXin Li }
15*67e74705SXin Li 
16*67e74705SXin Li // CHECK-LABEL: define void @basic_finally()
17*67e74705SXin Li // CHECK: invoke void @might_crash()
18*67e74705SXin Li // CHECK:     to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
19*67e74705SXin Li //
20*67e74705SXin Li // CHECK: [[invoke_cont]]
21*67e74705SXin Li // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
22*67e74705SXin Li // CHECK: call void @"\01?fin$0@0@basic_finally@@"({{i8( zeroext)?}} 0, i8* %[[fp]])
23*67e74705SXin Li // CHECK-NEXT: ret void
24*67e74705SXin Li //
25*67e74705SXin Li // CHECK: [[lpad]]
26*67e74705SXin Li // CHECK-NEXT: %[[pad:[^ ]*]] = cleanuppad
27*67e74705SXin Li // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
28*67e74705SXin Li // CHECK: call void @"\01?fin$0@0@basic_finally@@"({{i8( zeroext)?}} 1, i8* %[[fp]])
29*67e74705SXin Li // CHECK-NEXT: cleanupret from %[[pad]] unwind to caller
30*67e74705SXin Li 
31*67e74705SXin Li // CHECK: define internal void @"\01?fin$0@0@basic_finally@@"({{.*}})
32*67e74705SXin Li // CHECK-SAME: [[finally_attrs:#[0-9]+]]
33*67e74705SXin Li // CHECK: call void @cleanup()
34*67e74705SXin Li 
35*67e74705SXin Li // Mostly check that we don't double emit 'r' which would crash.
decl_in_finally(void)36*67e74705SXin Li void decl_in_finally(void) {
37*67e74705SXin Li   __try {
38*67e74705SXin Li     might_crash();
39*67e74705SXin Li   } __finally {
40*67e74705SXin Li     int r;
41*67e74705SXin Li   }
42*67e74705SXin Li }
43*67e74705SXin Li 
44*67e74705SXin Li // Ditto, don't crash double emitting 'l'.
label_in_finally(void)45*67e74705SXin Li void label_in_finally(void) {
46*67e74705SXin Li   __try {
47*67e74705SXin Li     might_crash();
48*67e74705SXin Li   } __finally {
49*67e74705SXin Li l:
50*67e74705SXin Li     cleanup();
51*67e74705SXin Li     if (check_condition())
52*67e74705SXin Li       goto l;
53*67e74705SXin Li   }
54*67e74705SXin Li }
55*67e74705SXin Li 
56*67e74705SXin Li // CHECK-LABEL: define void @label_in_finally()
57*67e74705SXin Li // CHECK: invoke void @might_crash()
58*67e74705SXin Li // CHECK:     to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
59*67e74705SXin Li //
60*67e74705SXin Li // CHECK: [[invoke_cont]]
61*67e74705SXin Li // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
62*67e74705SXin Li // CHECK: call void @"\01?fin$0@0@label_in_finally@@"({{i8( zeroext)?}} 0, i8* %[[fp]])
63*67e74705SXin Li // CHECK: ret void
64*67e74705SXin Li 
65*67e74705SXin Li // CHECK: define internal void @"\01?fin$0@0@label_in_finally@@"({{.*}})
66*67e74705SXin Li // CHECK-SAME: [[finally_attrs]]
67*67e74705SXin Li // CHECK: br label %[[l:[^ ]*]]
68*67e74705SXin Li //
69*67e74705SXin Li // CHECK: [[l]]
70*67e74705SXin Li // CHECK: call void @cleanup()
71*67e74705SXin Li // CHECK: call i32 @check_condition()
72*67e74705SXin Li // CHECK: br i1 {{.*}}, label
73*67e74705SXin Li // CHECK: br label %[[l]]
74*67e74705SXin Li 
75*67e74705SXin Li int crashed;
use_abnormal_termination(void)76*67e74705SXin Li void use_abnormal_termination(void) {
77*67e74705SXin Li   __try {
78*67e74705SXin Li     might_crash();
79*67e74705SXin Li   } __finally {
80*67e74705SXin Li     crashed = __abnormal_termination();
81*67e74705SXin Li   }
82*67e74705SXin Li }
83*67e74705SXin Li 
84*67e74705SXin Li // CHECK-LABEL: define void @use_abnormal_termination()
85*67e74705SXin Li // CHECK: invoke void @might_crash()
86*67e74705SXin Li // CHECK:     to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
87*67e74705SXin Li //
88*67e74705SXin Li // CHECK: [[invoke_cont]]
89*67e74705SXin Li // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
90*67e74705SXin Li // CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"({{i8( zeroext)?}} 0, i8* %[[fp]])
91*67e74705SXin Li // CHECK: ret void
92*67e74705SXin Li //
93*67e74705SXin Li // CHECK: [[lpad]]
94*67e74705SXin Li // CHECK-NEXT: %[[pad:[^ ]*]] = cleanuppad
95*67e74705SXin Li // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.localaddress()
96*67e74705SXin Li // CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"({{i8( zeroext)?}} 1, i8* %[[fp]])
97*67e74705SXin Li // CHECK-NEXT: cleanupret from %[[pad]] unwind to caller
98*67e74705SXin Li 
99*67e74705SXin Li // CHECK: define internal void @"\01?fin$0@0@use_abnormal_termination@@"({{i8( zeroext)?}} %[[abnormal:abnormal_termination]], i8* %frame_pointer)
100*67e74705SXin Li // CHECK-SAME: [[finally_attrs]]
101*67e74705SXin Li // CHECK: %[[abnormal_zext:[^ ]*]] = zext i8 %[[abnormal]] to i32
102*67e74705SXin Li // CHECK: store i32 %[[abnormal_zext]], i32* @crashed
103*67e74705SXin Li // CHECK-NEXT: ret void
104*67e74705SXin Li 
noreturn_noop_finally()105*67e74705SXin Li void noreturn_noop_finally() {
106*67e74705SXin Li   __try {
107*67e74705SXin Li     __noop();
108*67e74705SXin Li   } __finally {
109*67e74705SXin Li     abort();
110*67e74705SXin Li   }
111*67e74705SXin Li }
112*67e74705SXin Li 
113*67e74705SXin Li // CHECK-LABEL: define void @noreturn_noop_finally()
114*67e74705SXin Li // CHECK: call void @"\01?fin$0@0@noreturn_noop_finally@@"({{.*}})
115*67e74705SXin Li // CHECK: ret void
116*67e74705SXin Li 
117*67e74705SXin Li // CHECK: define internal void @"\01?fin$0@0@noreturn_noop_finally@@"({{.*}})
118*67e74705SXin Li // CHECK-SAME: [[finally_attrs]]
119*67e74705SXin Li // CHECK: call void @abort()
120*67e74705SXin Li // CHECK: unreachable
121*67e74705SXin Li 
noreturn_finally()122*67e74705SXin Li void noreturn_finally() {
123*67e74705SXin Li   __try {
124*67e74705SXin Li     might_crash();
125*67e74705SXin Li   } __finally {
126*67e74705SXin Li     abort();
127*67e74705SXin Li   }
128*67e74705SXin Li }
129*67e74705SXin Li 
130*67e74705SXin Li // CHECK-LABEL: define void @noreturn_finally()
131*67e74705SXin Li // CHECK: invoke void @might_crash()
132*67e74705SXin Li // CHECK:     to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
133*67e74705SXin Li //
134*67e74705SXin Li // CHECK: [[cont]]
135*67e74705SXin Li // CHECK: call void @"\01?fin$0@0@noreturn_finally@@"({{.*}})
136*67e74705SXin Li // CHECK: ret void
137*67e74705SXin Li //
138*67e74705SXin Li // CHECK: [[lpad]]
139*67e74705SXin Li // CHECK-NEXT: %[[pad:[^ ]*]] = cleanuppad
140*67e74705SXin Li // CHECK: call void @"\01?fin$0@0@noreturn_finally@@"({{.*}})
141*67e74705SXin Li // CHECK-NEXT: cleanupret from %[[pad]] unwind to caller
142*67e74705SXin Li 
143*67e74705SXin Li // CHECK: define internal void @"\01?fin$0@0@noreturn_finally@@"({{.*}})
144*67e74705SXin Li // CHECK-SAME: [[finally_attrs]]
145*67e74705SXin Li // CHECK: call void @abort()
146*67e74705SXin Li // CHECK: unreachable
147*67e74705SXin Li 
finally_with_return()148*67e74705SXin Li int finally_with_return() {
149*67e74705SXin Li   __try {
150*67e74705SXin Li     return 42;
151*67e74705SXin Li   } __finally {
152*67e74705SXin Li   }
153*67e74705SXin Li }
154*67e74705SXin Li // CHECK-LABEL: define i32 @finally_with_return()
155*67e74705SXin Li // CHECK: call void @"\01?fin$0@0@finally_with_return@@"({{.*}})
156*67e74705SXin Li // CHECK-NEXT: ret i32 42
157*67e74705SXin Li 
158*67e74705SXin Li // CHECK: define internal void @"\01?fin$0@0@finally_with_return@@"({{.*}})
159*67e74705SXin Li // CHECK-SAME: [[finally_attrs]]
160*67e74705SXin Li // CHECK-NOT: br i1
161*67e74705SXin Li // CHECK-NOT: br label
162*67e74705SXin Li // CHECK: ret void
163*67e74705SXin Li 
nested___finally___finally()164*67e74705SXin Li int nested___finally___finally() {
165*67e74705SXin Li   __try {
166*67e74705SXin Li     __try {
167*67e74705SXin Li     } __finally {
168*67e74705SXin Li       return 1;
169*67e74705SXin Li     }
170*67e74705SXin Li   } __finally {
171*67e74705SXin Li     // Intentionally no return here.
172*67e74705SXin Li   }
173*67e74705SXin Li   return 0;
174*67e74705SXin Li }
175*67e74705SXin Li 
176*67e74705SXin Li // CHECK-LABEL: define i32 @nested___finally___finally
177*67e74705SXin Li // CHECK: invoke void @"\01?fin$1@0@nested___finally___finally@@"({{.*}})
178*67e74705SXin Li // CHECK:          to label %[[outercont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
179*67e74705SXin Li //
180*67e74705SXin Li // CHECK: [[outercont]]
181*67e74705SXin Li // CHECK: call void @"\01?fin$0@0@nested___finally___finally@@"({{.*}})
182*67e74705SXin Li // CHECK-NEXT: ret i32 0
183*67e74705SXin Li //
184*67e74705SXin Li // CHECK: [[lpad]]
185*67e74705SXin Li // CHECK-NEXT: %[[pad:[^ ]*]] = cleanuppad
186*67e74705SXin Li // CHECK: call void @"\01?fin$0@0@nested___finally___finally@@"({{.*}})
187*67e74705SXin Li // CHECK-NEXT: cleanupret from %[[pad]] unwind to caller
188*67e74705SXin Li 
189*67e74705SXin Li // CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally@@"({{.*}})
190*67e74705SXin Li // CHECK-SAME: [[finally_attrs]]
191*67e74705SXin Li // CHECK: ret void
192*67e74705SXin Li 
193*67e74705SXin Li // CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally@@"({{.*}})
194*67e74705SXin Li // CHECK-SAME: [[finally_attrs]]
195*67e74705SXin Li // CHECK: unreachable
196*67e74705SXin Li 
197*67e74705SXin Li // FIXME: Our behavior seems suspiciously different.
198*67e74705SXin Li 
nested___finally___finally_with_eh_edge()199*67e74705SXin Li int nested___finally___finally_with_eh_edge() {
200*67e74705SXin Li   __try {
201*67e74705SXin Li     __try {
202*67e74705SXin Li       might_crash();
203*67e74705SXin Li     } __finally {
204*67e74705SXin Li       return 899;
205*67e74705SXin Li     }
206*67e74705SXin Li   } __finally {
207*67e74705SXin Li     // Intentionally no return here.
208*67e74705SXin Li   }
209*67e74705SXin Li   return 912;
210*67e74705SXin Li }
211*67e74705SXin Li // CHECK-LABEL: define i32 @nested___finally___finally_with_eh_edge
212*67e74705SXin Li // CHECK: invoke void @might_crash()
213*67e74705SXin Li // CHECK-NEXT: to label %[[invokecont:[^ ]*]] unwind label %[[lpad1:[^ ]*]]
214*67e74705SXin Li //
215*67e74705SXin Li // [[invokecont]]
216*67e74705SXin Li // CHECK: invoke void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"({{.*}})
217*67e74705SXin Li // CHECK-NEXT:       to label %[[outercont:[^ ]*]] unwind label %[[lpad2:[^ ]*]]
218*67e74705SXin Li //
219*67e74705SXin Li // CHECK: [[outercont]]
220*67e74705SXin Li // CHECK: call void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"({{.*}})
221*67e74705SXin Li // CHECK-NEXT: ret i32 912
222*67e74705SXin Li //
223*67e74705SXin Li // CHECK: [[lpad1]]
224*67e74705SXin Li // CHECK-NEXT: %[[innerpad:[^ ]*]] = cleanuppad
225*67e74705SXin Li // CHECK: invoke void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"({{.*}})
226*67e74705SXin Li // CHECK-NEXT:    label %[[innercleanupretbb:[^ ]*]] unwind label %[[lpad2:[^ ]*]]
227*67e74705SXin Li //
228*67e74705SXin Li // CHECK: [[innercleanupretbb]]
229*67e74705SXin Li // CHECK-NEXT: cleanupret from %[[innerpad]] unwind label %[[lpad2]]
230*67e74705SXin Li //
231*67e74705SXin Li // CHECK: [[lpad2]]
232*67e74705SXin Li // CHECK-NEXT: %[[outerpad:[^ ]*]] = cleanuppad
233*67e74705SXin Li // CHECK: call void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"({{.*}})
234*67e74705SXin Li // CHECK-NEXT: cleanupret from %[[outerpad]] unwind to caller
235*67e74705SXin Li 
236*67e74705SXin Li // CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"({{.*}})
237*67e74705SXin Li // CHECK-SAME: [[finally_attrs]]
238*67e74705SXin Li // CHECK: ret void
239*67e74705SXin Li 
240*67e74705SXin Li // CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"({{.*}})
241*67e74705SXin Li // CHECK-SAME: [[finally_attrs]]
242*67e74705SXin Li // CHECK: unreachable
243*67e74705SXin Li 
finally_within_finally()244*67e74705SXin Li void finally_within_finally() {
245*67e74705SXin Li   __try {
246*67e74705SXin Li     might_crash();
247*67e74705SXin Li   } __finally {
248*67e74705SXin Li     __try {
249*67e74705SXin Li       might_crash();
250*67e74705SXin Li     } __finally {
251*67e74705SXin Li     }
252*67e74705SXin Li   }
253*67e74705SXin Li }
254*67e74705SXin Li 
255*67e74705SXin Li // CHECK-LABEL: define void @finally_within_finally(
256*67e74705SXin Li // CHECK: invoke void @might_crash(
257*67e74705SXin Li 
258*67e74705SXin Li // CHECK: call void @"\01?fin$0@0@finally_within_finally@@"(
259*67e74705SXin Li // CHECK: call void @"\01?fin$0@0@finally_within_finally@@"({{.*}}) [ "funclet"(
260*67e74705SXin Li 
261*67e74705SXin Li // CHECK-LABEL: define internal void @"\01?fin$0@0@finally_within_finally@@"({{[^)]*}})
262*67e74705SXin Li // CHECK-SAME: [[finally_attrs]]
263*67e74705SXin Li // CHECK: invoke void @might_crash(
264*67e74705SXin Li 
265*67e74705SXin Li // CHECK: call void @"\01?fin$1@0@finally_within_finally@@"(
266*67e74705SXin Li // CHECK: call void @"\01?fin$1@0@finally_within_finally@@"({{.*}}) [ "funclet"(
267*67e74705SXin Li 
268*67e74705SXin Li // CHECK-LABEL: define internal void @"\01?fin$1@0@finally_within_finally@@"({{[^)]*}})
269*67e74705SXin Li // CHECK-SAME: [[finally_attrs]]
270*67e74705SXin Li 
271*67e74705SXin Li // Look for the absence of noinline. Enum attributes come first, so check that
272*67e74705SXin Li // a string attribute is the first to verify that no enum attributes are
273*67e74705SXin Li // present.
274*67e74705SXin Li // CHECK: attributes [[finally_attrs]] = { "{{.*}}" }
275