xref: /llvm-project/clang/test/CodeGen/exceptions-seh-finally.c (revision ff08c8e57e39d7970b65637595cdc221901f4ed1)
1 // RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -O1 -disable-llvm-passes -o - | FileCheck %s
2 // RUN: %clang_cc1 %s -triple i686-pc-win32 -fms-extensions -emit-llvm -O1 -disable-llvm-passes -o - | FileCheck %s
3 // RUN: %clang_cc1 %s -triple aarch64-windows -fms-extensions -emit-llvm -O1 -disable-llvm-passes -o - | FileCheck %s
4 // NOTE: we're passing "-O1 -disable-llvm-passes" to avoid adding optnone and noinline everywhere.
5 
6 void abort(void) __attribute__((noreturn));
7 void might_crash(void);
8 void cleanup(void);
9 int check_condition(void);
basic_finally(void)10 void 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 void
26 //
27 // CHECK: [[lpad]]
28 // CHECK-NEXT: %[[pad:[^ ]*]] = cleanuppad
29 // 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 caller
32 
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.
decl_in_finally(void)38 void 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'.
label_in_finally(void)47 void label_in_finally(void) {
48   __try {
49     might_crash();
50   } __finally {
51 l:
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 void
66 
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 {{.*}}, label
75 // CHECK: br label %[[l]]
76 
77 int crashed;
use_abnormal_termination(void)78 void 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 void
94 //
95 // CHECK: [[lpad]]
96 // CHECK-NEXT: %[[pad:[^ ]*]] = cleanuppad
97 // 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 caller
100 
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 i32
104 // CHECK: store i32 %[[abnormal_zext]], ptr @crashed
105 // CHECK-NEXT: ret void
106 
noreturn_noop_finally(void)107 void 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 void
118 
119 // CHECK: define internal void @"?fin$0@0@noreturn_noop_finally@@"({{.*}})
120 // CHECK-SAME: [[finally_attrs]]
121 // CHECK: call void @abort()
122 // CHECK: unreachable
123 
noreturn_finally(void)124 void 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 void
139 //
140 // CHECK: [[lpad]]
141 // CHECK-NEXT: %[[pad:[^ ]*]] = cleanuppad
142 // CHECK: call void @"?fin$0@0@noreturn_finally@@"({{.*}})
143 // CHECK-NEXT: cleanupret from %[[pad]] unwind to caller
144 
145 // CHECK: define internal void @"?fin$0@0@noreturn_finally@@"({{.*}})
146 // CHECK-SAME: [[finally_attrs]]
147 // CHECK: call void @abort()
148 // CHECK: unreachable
149 
finally_with_return(void)150 int 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.slot
158 // CHECK: %cleanup.dest = load i32, ptr %cleanup.dest.slot
159 // CHECK: icmp ne i32 %cleanup.dest
160 // CHECK: call void @"?fin$0@0@finally_with_return@@"({{.*}})
161 // CHECK: ret i32 42
162 
163 // CHECK: define internal void @"?fin$0@0@finally_with_return@@"({{.*}})
164 // CHECK-SAME: [[finally_attrs]]
165 // CHECK-NOT: br i1
166 // CHECK-NOT: br label
167 // CHECK: ret void
168 
nested___finally___finally(void)169 int 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___finally
182 // 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 0
188 //
189 // CHECK: [[lpad]]
190 // CHECK-NEXT: %[[pad:[^ ]*]] = cleanuppad
191 // CHECK: call void @"?fin$0@0@nested___finally___finally@@"({{.*}})
192 // CHECK-NEXT: cleanupret from %[[pad]] unwind to caller
193 
194 // CHECK-LABEL: define internal void @"?fin$0@0@nested___finally___finally@@"({{.*}})
195 // CHECK-SAME: [[finally_attrs]]
196 // CHECK: ret void
197 
198 // CHECK-LABEL: define internal void @"?fin$1@0@nested___finally___finally@@"({{.*}})
199 // CHECK-SAME: [[finally_attrs]]
200 // CHECK: unreachable
201 
202 // FIXME: Our behavior seems suspiciously different.
203 
nested___finally___finally_with_eh_edge(void)204 int 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_edge
217 // 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 912
227 //
228 // CHECK: [[lpad1]]
229 // CHECK-NEXT: %[[innerpad:[^ ]*]] = cleanuppad
230 // 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:[^ ]*]] = cleanuppad
238 // CHECK: call void @"?fin$0@0@nested___finally___finally_with_eh_edge@@"({{.*}})
239 // CHECK-NEXT: cleanupret from %[[outerpad]] unwind to caller
240 
241 // CHECK-LABEL: define internal void @"?fin$0@0@nested___finally___finally_with_eh_edge@@"({{.*}})
242 // CHECK-SAME: [[finally_attrs]]
243 // CHECK: ret void
244 
245 // CHECK-LABEL: define internal void @"?fin$1@0@nested___finally___finally_with_eh_edge@@"({{.*}})
246 // CHECK-SAME: [[finally_attrs]]
247 // CHECK: unreachable
248 
finally_within_finally(void)249 void 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 
276 void cleanup_with_func(const char *);
finally_with_func(void)277 void 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 further
289 // attributes should be string attributes.
290 // CHECK: attributes [[finally_attrs]] = { nounwind "{{.*}}" }
291