Clang Project

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