1 // RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s
2
3 void abort(void) __attribute__((noreturn));
4 void might_crash(void);
5 void cleanup(void);
6 int check_condition(void);
basic_finally(void)7 void basic_finally(void) {
8 __try {
9 might_crash();
10 } __finally {
11 cleanup();
12 }
13 }
14
15 // CHECK-LABEL: define void @basic_finally()
16 // CHECK: invoke void @might_crash()
17 // CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
18 //
19 // CHECK: [[invoke_cont]]
20 // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
21 // CHECK: call void @"\01?fin$0@0@basic_finally@@"(i1 zeroext false, i8* %[[fp]])
22 // CHECK-NEXT: ret void
23 //
24 // CHECK: [[lpad]]
25 // CHECK-NEXT: landingpad
26 // CHECK-NEXT: cleanup
27 // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
28 // CHECK: call void @"\01?fin$0@0@basic_finally@@"(i1 zeroext true, i8* %[[fp]])
29 // CHECK: resume { i8*, i32 }
30
31 // CHECK: define internal void @"\01?fin$0@0@basic_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
32 // CHECK: call void @cleanup()
33
34 // Mostly check that we don't double emit 'r' which would crash.
decl_in_finally(void)35 void decl_in_finally(void) {
36 __try {
37 might_crash();
38 } __finally {
39 int r;
40 }
41 }
42
43 // Ditto, don't crash double emitting 'l'.
label_in_finally(void)44 void label_in_finally(void) {
45 __try {
46 might_crash();
47 } __finally {
48 l:
49 cleanup();
50 if (check_condition())
51 goto l;
52 }
53 }
54
55 // CHECK-LABEL: define void @label_in_finally()
56 // CHECK: invoke void @might_crash()
57 // CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
58 //
59 // CHECK: [[invoke_cont]]
60 // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
61 // CHECK: call void @"\01?fin$0@0@label_in_finally@@"(i1 zeroext false, i8* %[[fp]])
62 // CHECK: ret void
63
64 // CHECK: define internal void @"\01?fin$0@0@label_in_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
65 // CHECK: br label %[[l:[^ ]*]]
66 //
67 // CHECK: [[l]]
68 // CHECK: call void @cleanup()
69 // CHECK: call i32 @check_condition()
70 // CHECK: br i1 {{.*}}, label
71 // CHECK: br label %[[l]]
72
73 int crashed;
use_abnormal_termination(void)74 void use_abnormal_termination(void) {
75 __try {
76 might_crash();
77 } __finally {
78 crashed = __abnormal_termination();
79 }
80 }
81
82 // CHECK-LABEL: define void @use_abnormal_termination()
83 // CHECK: invoke void @might_crash()
84 // CHECK: to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
85 //
86 // CHECK: [[invoke_cont]]
87 // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
88 // CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"(i1 zeroext false, i8* %[[fp]])
89 // CHECK: ret void
90 //
91 // CHECK: [[lpad]]
92 // CHECK-NEXT: landingpad
93 // CHECK-NEXT: cleanup
94 // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
95 // CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"(i1 zeroext true, i8* %[[fp]])
96 // CHECK: resume { i8*, i32 }
97
98 // CHECK: define internal void @"\01?fin$0@0@use_abnormal_termination@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
99 // CHECK: %[[abnormal_zext:[^ ]*]] = zext i1 %abnormal_termination to i32
100 // CHECK: store i32 %[[abnormal_zext]], i32* @crashed
101 // CHECK-NEXT: ret void
102
noreturn_noop_finally()103 void noreturn_noop_finally() {
104 __try {
105 __noop();
106 } __finally {
107 abort();
108 }
109 }
110
111 // CHECK-LABEL: define void @noreturn_noop_finally()
112 // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
113 // CHECK: call void @"\01?fin$0@0@noreturn_noop_finally@@"(i1 zeroext false, i8* %[[fp]])
114 // CHECK: ret void
115
116 // CHECK: define internal void @"\01?fin$0@0@noreturn_noop_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
117 // CHECK: call void @abort()
118 // CHECK: unreachable
119
noreturn_finally()120 void noreturn_finally() {
121 __try {
122 might_crash();
123 } __finally {
124 abort();
125 }
126 }
127
128 // CHECK-LABEL: define void @noreturn_finally()
129 // CHECK: invoke void @might_crash()
130 // CHECK: to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
131 //
132 // CHECK: [[cont]]
133 // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
134 // CHECK: call void @"\01?fin$0@0@noreturn_finally@@"(i1 zeroext false, i8* %[[fp]])
135 // CHECK: ret void
136 //
137 // CHECK: [[lpad]]
138 // CHECK: landingpad
139 // CHECK-NEXT: cleanup
140 // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
141 // CHECK: call void @"\01?fin$0@0@noreturn_finally@@"(i1 zeroext true, i8* %[[fp]])
142 // CHECK: resume { i8*, i32 }
143
144 // CHECK: define internal void @"\01?fin$0@0@noreturn_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
145 // CHECK: call void @abort()
146 // CHECK: unreachable
147
finally_with_return()148 int finally_with_return() {
149 __try {
150 return 42;
151 } __finally {
152 }
153 }
154 // CHECK-LABEL: define i32 @finally_with_return()
155 // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
156 // CHECK-NEXT: call void @"\01?fin$0@0@finally_with_return@@"(i1 zeroext false, i8* %[[fp]])
157 // CHECK-NEXT: ret i32 42
158
159 // CHECK: define internal void @"\01?fin$0@0@finally_with_return@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
160 // CHECK-NOT: br i1
161 // CHECK-NOT: br label
162 // CHECK: ret void
163
nested___finally___finally()164 int nested___finally___finally() {
165 __try {
166 __try {
167 } __finally {
168 return 1;
169 }
170 } __finally {
171 // Intentionally no return here.
172 }
173 return 0;
174 }
175
176 // CHECK-LABEL: define i32 @nested___finally___finally
177 // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
178 // CHECK: invoke void @"\01?fin$1@0@nested___finally___finally@@"(i1 zeroext false, i8* %[[fp]])
179 // CHECK: to label %[[outercont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
180 //
181 // CHECK: [[outercont]]
182 // CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
183 // CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i1 zeroext false, i8* %[[fp]])
184 // CHECK-NEXT: ret i32 0
185 //
186 // CHECK: [[lpad]]
187 // CHECK-NEXT: landingpad
188 // CHECK-NEXT: cleanup
189 // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
190 // CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i1 zeroext true, i8* %[[fp]])
191
192 // CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
193 // CHECK: ret void
194
195 // CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
196 // CHECK: unreachable
197
nested___finally___finally_with_eh_edge()198 int nested___finally___finally_with_eh_edge() {
199 __try {
200 __try {
201 might_crash();
202 } __finally {
203 return 899;
204 }
205 } __finally {
206 // Intentionally no return here.
207 }
208 return 912;
209 }
210 // CHECK-LABEL: define i32 @nested___finally___finally_with_eh_edge
211 // CHECK: invoke void @might_crash()
212 // CHECK-NEXT: to label %[[invokecont:[^ ]*]] unwind label %[[lpad1:[^ ]*]]
213 //
214 // [[invokecont]]
215 // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
216 // CHECK: invoke void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext false, i8* %[[fp]])
217 // CHECK: to label %[[outercont:[^ ]*]] unwind label %[[lpad2:[^ ]*]]
218 //
219 // CHECK: [[outercont]]
220 // CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
221 // CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext false, i8* %[[fp]])
222 // CHECK-NEXT: ret i32 912
223 //
224 // CHECK: [[lpad1]]
225 // CHECK-NEXT: landingpad
226 // CHECK-NEXT: cleanup
227 // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
228 // CHECK: invoke void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext true, i8* %[[fp]])
229 // CHECK: to label %[[outercont:[^ ]*]] unwind label %[[lpad2]]
230 //
231 // CHECK: [[lpad2]]
232 // CHECK-NEXT: landingpad
233 // CHECK-NEXT: cleanup
234 // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
235 // CHECK: call void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext true, i8* %[[fp]])
236 // CHECK: resume
237
238 // CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
239 // CHECK: ret void
240
241 // CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
242 // CHECK: unreachable
243