1 | // RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-darwin -std=c++11 -emit-llvm %s -o - \ |
2 | // RUN: | FileCheck %s |
3 | |
4 | struct test1_D { |
5 | double d; |
6 | } d1; |
7 | |
8 | void test1() { |
9 | throw d1; |
10 | } |
11 | |
12 | // CHECK-LABEL: define void @_Z5test1v() |
13 | // CHECK: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 8) |
14 | // CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[DSTAR:%[^*]*\*]] |
15 | // CHECK-NEXT: [[EXN2:%.*]] = bitcast [[DSTAR]] [[EXN]] to i8* |
16 | // CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[EXN2]], i8* align 8 bitcast ([[DSTAR]] @d1 to i8*), i64 8, i1 false) |
17 | // CHECK-NEXT: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({ i8*, i8* }* @_ZTI7test1_D to i8*), i8* null) [[NR:#[0-9]+]] |
18 | // CHECK-NEXT: unreachable |
19 | |
20 | |
21 | struct test2_D { |
22 | test2_D(const test2_D&o); |
23 | test2_D(); |
24 | virtual void bar() { } |
25 | int i; int j; |
26 | } d2; |
27 | |
28 | void test2() { |
29 | throw d2; |
30 | } |
31 | |
32 | // CHECK-LABEL: define void @_Z5test2v() |
33 | // CHECK: [[EXNVAR:%.*]] = alloca i8* |
34 | // CHECK-NEXT: [[SELECTORVAR:%.*]] = alloca i32 |
35 | // CHECK-NEXT: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 16) |
36 | // CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[DSTAR:%[^*]*\*]] |
37 | // CHECK-NEXT: invoke void @_ZN7test2_DC1ERKS_([[DSTAR]] [[EXN]], [[DSTAR]] dereferenceable({{[0-9]+}}) @d2) |
38 | // CHECK-NEXT: to label %[[CONT:.*]] unwind label %{{.*}} |
39 | // : [[CONT]]: (can't check this in Release-Asserts builds) |
40 | // CHECK: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({{.*}}* @_ZTI7test2_D to i8*), i8* null) [[NR]] |
41 | // CHECK-NEXT: unreachable |
42 | |
43 | |
44 | struct test3_D { |
45 | test3_D() { } |
46 | test3_D(volatile test3_D&o); |
47 | virtual void bar(); |
48 | }; |
49 | |
50 | void test3() { |
51 | throw (volatile test3_D *)0; |
52 | } |
53 | |
54 | // CHECK-LABEL: define void @_Z5test3v() |
55 | // CHECK: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 8) |
56 | // CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[D:%[^*]+]]** |
57 | // CHECK-NEXT: store [[D]]* null, [[D]]** [[EXN]] |
58 | // CHECK-NEXT: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({ i8*, i8*, i32, i8* }* @_ZTIPV7test3_D to i8*), i8* null) [[NR]] |
59 | // CHECK-NEXT: unreachable |
60 | |
61 | |
62 | void test4() { |
63 | throw; |
64 | } |
65 | |
66 | // CHECK-LABEL: define void @_Z5test4v() |
67 | // CHECK: call void @__cxa_rethrow() [[NR]] |
68 | // CHECK-NEXT: unreachable |
69 | |
70 | |
71 | // rdar://problem/7696549 |
72 | namespace test5 { |
73 | struct A { |
74 | A(); |
75 | A(const A&); |
76 | ~A(); |
77 | }; |
78 | |
79 | void test() { |
80 | try { throw A(); } catch (A &x) {} |
81 | } |
82 | // CHECK-LABEL: define void @_ZN5test54testEv() |
83 | // CHECK: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 1) |
84 | // CHECK: [[EXNCAST:%.*]] = bitcast i8* [[EXNOBJ]] to [[A:%[^*]*]]* |
85 | // CHECK-NEXT: invoke void @_ZN5test51AC1Ev([[A]]* [[EXNCAST]]) |
86 | // CHECK: invoke void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({{.*}}* @_ZTIN5test51AE to i8*), i8* bitcast (void ([[A]]*)* @_ZN5test51AD1Ev to i8*)) [[NR]] |
87 | // CHECK-NEXT: to label {{%.*}} unwind label %[[HANDLER:[^ ]*]] |
88 | // : [[HANDLER]]: (can't check this in Release-Asserts builds) |
89 | // CHECK: {{%.*}} = call i32 @llvm.eh.typeid.for(i8* bitcast ({{.*}}* @_ZTIN5test51AE to i8*)) |
90 | } |
91 | |
92 | namespace test6 { |
93 | template <class T> struct allocator { |
94 | ~allocator() throw() { } |
95 | }; |
96 | |
97 | void foo() { |
98 | allocator<int> a; |
99 | } |
100 | } |
101 | |
102 | // PR7127 |
103 | namespace test7 { |
104 | // CHECK-LABEL: define i32 @_ZN5test73fooEv() |
105 | // CHECK-SAME: personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) |
106 | int foo() { |
107 | // CHECK: [[CAUGHTEXNVAR:%.*]] = alloca i8* |
108 | // CHECK-NEXT: [[SELECTORVAR:%.*]] = alloca i32 |
109 | // CHECK-NEXT: [[INTCATCHVAR:%.*]] = alloca i32 |
110 | try { |
111 | try { |
112 | // CHECK-NEXT: [[EXNALLOC:%.*]] = call i8* @__cxa_allocate_exception |
113 | // CHECK-NEXT: bitcast i8* [[EXNALLOC]] to i32* |
114 | // CHECK-NEXT: store i32 1, i32* |
115 | // CHECK-NEXT: invoke void @__cxa_throw(i8* [[EXNALLOC]], i8* bitcast (i8** @_ZTIi to i8*), i8* null |
116 | throw 1; |
117 | } |
118 | |
119 | // CHECK: [[CAUGHTVAL:%.*]] = landingpad { i8*, i32 } |
120 | // CHECK-NEXT: catch i8* bitcast (i8** @_ZTIi to i8*) |
121 | // CHECK-NEXT: catch i8* null |
122 | // CHECK-NEXT: [[CAUGHTEXN:%.*]] = extractvalue { i8*, i32 } [[CAUGHTVAL]], 0 |
123 | // CHECK-NEXT: store i8* [[CAUGHTEXN]], i8** [[CAUGHTEXNVAR]] |
124 | // CHECK-NEXT: [[SELECTOR:%.*]] = extractvalue { i8*, i32 } [[CAUGHTVAL]], 1 |
125 | // CHECK-NEXT: store i32 [[SELECTOR]], i32* [[SELECTORVAR]] |
126 | // CHECK-NEXT: br label |
127 | // CHECK: [[SELECTOR:%.*]] = load i32, i32* [[SELECTORVAR]] |
128 | // CHECK-NEXT: [[T0:%.*]] = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) |
129 | // CHECK-NEXT: icmp eq i32 [[SELECTOR]], [[T0]] |
130 | // CHECK-NEXT: br i1 |
131 | // CHECK: [[T0:%.*]] = load i8*, i8** [[CAUGHTEXNVAR]] |
132 | // CHECK-NEXT: [[T1:%.*]] = call i8* @__cxa_begin_catch(i8* [[T0]]) |
133 | // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to i32* |
134 | // CHECK-NEXT: [[T3:%.*]] = load i32, i32* [[T2]] |
135 | // CHECK-NEXT: store i32 [[T3]], i32* {{%.*}}, align 4 |
136 | // CHECK-NEXT: invoke void @__cxa_rethrow |
137 | catch (int) { |
138 | throw; |
139 | } |
140 | } |
141 | // CHECK: [[CAUGHTVAL:%.*]] = landingpad { i8*, i32 } |
142 | // CHECK-NEXT: catch i8* null |
143 | // CHECK-NEXT: [[CAUGHTEXN:%.*]] = extractvalue { i8*, i32 } [[CAUGHTVAL]], 0 |
144 | // CHECK-NEXT: store i8* [[CAUGHTEXN]], i8** [[CAUGHTEXNVAR]] |
145 | // CHECK-NEXT: [[SELECTOR:%.*]] = extractvalue { i8*, i32 } [[CAUGHTVAL]], 1 |
146 | // CHECK-NEXT: store i32 [[SELECTOR]], i32* [[SELECTORVAR]] |
147 | // CHECK-NEXT: call void @__cxa_end_catch() |
148 | // CHECK-NEXT: br label |
149 | // CHECK: load i8*, i8** [[CAUGHTEXNVAR]] |
150 | // CHECK-NEXT: call i8* @__cxa_begin_catch |
151 | // CHECK-NEXT: call void @__cxa_end_catch |
152 | catch (...) { |
153 | } |
154 | // CHECK: ret i32 0 |
155 | return 0; |
156 | } |
157 | } |
158 | |
159 | // Ordering of destructors in a catch handler. |
160 | namespace test8 { |
161 | struct A { A(const A&); ~A(); }; |
162 | void bar(); |
163 | |
164 | // CHECK-LABEL: define void @_ZN5test83fooEv() |
165 | void foo() { |
166 | try { |
167 | // CHECK: invoke void @_ZN5test83barEv() |
168 | bar(); |
169 | } catch (A a) { |
170 | // CHECK: call i8* @__cxa_get_exception_ptr |
171 | // CHECK-NEXT: bitcast |
172 | // CHECK-NEXT: invoke void @_ZN5test81AC1ERKS0_( |
173 | // CHECK: call i8* @__cxa_begin_catch |
174 | // CHECK-NEXT: call void @_ZN5test81AD1Ev( |
175 | // CHECK: call void @__cxa_end_catch() |
176 | // CHECK: ret void |
177 | } |
178 | } |
179 | } |
180 | |
181 | // Constructor function-try-block must rethrow on fallthrough. |
182 | // rdar://problem/7696603 |
183 | namespace test9 { |
184 | void opaque(); |
185 | |
186 | struct A { A(); }; |
187 | |
188 | |
189 | // CHECK-LABEL: define void @_ZN5test91AC2Ev(%"struct.test9::A"* %this) unnamed_addr |
190 | // CHECK-SAME: personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) |
191 | A::A() try { |
192 | // CHECK: invoke void @_ZN5test96opaqueEv() |
193 | opaque(); |
194 | } catch (int x) { |
195 | // CHECK: landingpad { i8*, i32 } |
196 | // CHECK-NEXT: catch i8* bitcast (i8** @_ZTIi to i8*) |
197 | |
198 | // CHECK: call i8* @__cxa_begin_catch |
199 | // CHECK: invoke void @_ZN5test96opaqueEv() |
200 | // CHECK: invoke void @__cxa_rethrow() |
201 | |
202 | // CHECK-LABEL: define void @_ZN5test91AC1Ev(%"struct.test9::A"* %this) unnamed_addr |
203 | // CHECK: call void @_ZN5test91AC2Ev |
204 | // CHECK-NEXT: ret void |
205 | opaque(); |
206 | } |
207 | } |
208 | |
209 | // __cxa_end_catch can throw for some kinds of caught exceptions. |
210 | namespace test10 { |
211 | void opaque(); |
212 | |
213 | struct A { ~A(); }; |
214 | struct B { int x; }; |
215 | |
216 | // CHECK-LABEL: define void @_ZN6test103fooEv() |
217 | void foo() { |
218 | A a; // force a cleanup context |
219 | |
220 | try { |
221 | // CHECK: invoke void @_ZN6test106opaqueEv() |
222 | opaque(); |
223 | } catch (int i) { |
224 | // CHECK: call i8* @__cxa_begin_catch |
225 | // CHECK-NEXT: bitcast |
226 | // CHECK-NEXT: load i32, i32* |
227 | // CHECK-NEXT: store i32 |
228 | // CHECK-NEXT: call void @__cxa_end_catch() [[NUW:#[0-9]+]] |
229 | } catch (B a) { |
230 | // CHECK: call i8* @__cxa_begin_catch |
231 | // CHECK-NEXT: bitcast |
232 | // CHECK-NEXT: bitcast |
233 | // CHECK-NEXT: bitcast |
234 | // CHECK-NEXT: call void @llvm.memcpy |
235 | // CHECK-NEXT: invoke void @__cxa_end_catch() |
236 | } catch (...) { |
237 | // CHECK: call i8* @__cxa_begin_catch |
238 | // CHECK-NEXT: invoke void @__cxa_end_catch() |
239 | } |
240 | |
241 | // CHECK: call void @_ZN6test101AD1Ev( |
242 | } |
243 | } |
244 | |
245 | // __cxa_begin_catch returns pointers by value, even when catching by reference |
246 | // <rdar://problem/8212123> |
247 | namespace test11 { |
248 | void opaque(); |
249 | |
250 | // CHECK-LABEL: define void @_ZN6test113fooEv() |
251 | void foo() { |
252 | try { |
253 | // CHECK: invoke void @_ZN6test116opaqueEv() |
254 | opaque(); |
255 | } catch (int**&p) { |
256 | // CHECK: [[EXN:%.*]] = load i8*, i8** |
257 | // CHECK-NEXT: call i8* @__cxa_begin_catch(i8* [[EXN]]) [[NUW]] |
258 | // CHECK-NEXT: [[ADJ1:%.*]] = getelementptr i8, i8* [[EXN]], i32 32 |
259 | // CHECK-NEXT: [[ADJ2:%.*]] = bitcast i8* [[ADJ1]] to i32*** |
260 | // CHECK-NEXT: store i32*** [[ADJ2]], i32**** [[P:%.*]] |
261 | // CHECK-NEXT: call void @__cxa_end_catch() [[NUW]] |
262 | } |
263 | } |
264 | |
265 | struct A {}; |
266 | |
267 | // CHECK-LABEL: define void @_ZN6test113barEv() |
268 | void bar() { |
269 | try { |
270 | // CHECK: [[EXNSLOT:%.*]] = alloca i8* |
271 | // CHECK-NEXT: [[SELECTORSLOT:%.*]] = alloca i32 |
272 | // CHECK-NEXT: [[P:%.*]] = alloca [[A:%.*]]**, |
273 | // CHECK-NEXT: [[TMP:%.*]] = alloca [[A]]* |
274 | // CHECK-NEXT: invoke void @_ZN6test116opaqueEv() |
275 | opaque(); |
276 | } catch (A*&p) { |
277 | // CHECK: [[EXN:%.*]] = load i8*, i8** [[EXNSLOT]] |
278 | // CHECK-NEXT: [[ADJ1:%.*]] = call i8* @__cxa_begin_catch(i8* [[EXN]]) [[NUW]] |
279 | // CHECK-NEXT: [[ADJ2:%.*]] = bitcast i8* [[ADJ1]] to [[A]]* |
280 | // CHECK-NEXT: store [[A]]* [[ADJ2]], [[A]]** [[TMP]] |
281 | // CHECK-NEXT: store [[A]]** [[TMP]], [[A]]*** [[P]] |
282 | // CHECK-NEXT: call void @__cxa_end_catch() [[NUW]] |
283 | } |
284 | } |
285 | } |
286 | |
287 | // PR7686 |
288 | namespace test12 { |
289 | struct A { ~A() noexcept(false); }; |
290 | bool opaque(const A&); |
291 | |
292 | // CHECK-LABEL: define void @_ZN6test124testEv() |
293 | void test() { |
294 | // CHECK: [[X:%.*]] = alloca [[A:%.*]], |
295 | // CHECK: [[EHCLEANUPDEST:%.*]] = alloca i32 |
296 | // CHECK: [[Y:%.*]] = alloca [[A]] |
297 | // CHECK: [[Z:%.*]] = alloca [[A]] |
298 | // CHECK: [[CLEANUPDEST:%.*]] = alloca i32 |
299 | |
300 | A x; |
301 | // CHECK: invoke zeroext i1 @_ZN6test126opaqueERKNS_1AE( |
302 | if (opaque(x)) { |
303 | A y; |
304 | A z; |
305 | |
306 | // CHECK: invoke void @_ZN6test121AD1Ev([[A]]* [[Z]]) |
307 | // CHECK: invoke void @_ZN6test121AD1Ev([[A]]* [[Y]]) |
308 | // CHECK-NOT: switch |
309 | goto success; |
310 | } |
311 | |
312 | success: |
313 | bool _ = true; |
314 | |
315 | // CHECK: call void @_ZN6test121AD1Ev([[A]]* [[X]]) |
316 | // CHECK-NEXT: ret void |
317 | } |
318 | } |
319 | |
320 | // Reduced from some TableGen code that was causing a self-host crash. |
321 | namespace test13 { |
322 | struct A { ~A(); }; |
323 | |
324 | void test0(int x) { |
325 | try { |
326 | switch (x) { |
327 | case 0: |
328 | break; |
329 | case 1:{ |
330 | A a; |
331 | break; |
332 | } |
333 | default: |
334 | return; |
335 | } |
336 | return; |
337 | } catch (int x) { |
338 | } |
339 | return; |
340 | } |
341 | |
342 | void test1(int x) { |
343 | A y; |
344 | try { |
345 | switch (x) { |
346 | default: break; |
347 | } |
348 | } catch (int x) {} |
349 | } |
350 | } |
351 | |
352 | // rdar://problem/8231514 |
353 | namespace test14 { |
354 | struct A { ~A(); }; |
355 | struct B { ~B(); }; |
356 | |
357 | B b(); |
358 | void opaque(); |
359 | |
360 | void foo() { |
361 | A a; |
362 | try { |
363 | B str = b(); |
364 | opaque(); |
365 | } catch (int x) { |
366 | } |
367 | } |
368 | } |
369 | |
370 | // rdar://problem/8231514 |
371 | // JumpDests shouldn't get confused by scopes that aren't normal cleanups. |
372 | namespace test15 { |
373 | struct A { ~A(); }; |
374 | |
375 | bool opaque(int); |
376 | |
377 | // CHECK-LABEL: define void @_ZN6test153fooEv() |
378 | void foo() { |
379 | A a; |
380 | |
381 | try { |
382 | // CHECK: [[X:%.*]] = alloca i32 |
383 | // CHECK: store i32 10, i32* [[X]] |
384 | // CHECK-NEXT: br label |
385 | // -> while.cond |
386 | int x = 10; |
387 | |
388 | while (true) { |
389 | // CHECK: load i32, i32* [[X]] |
390 | // CHECK-NEXT: [[COND:%.*]] = invoke zeroext i1 @_ZN6test156opaqueEi |
391 | // CHECK: br i1 [[COND]] |
392 | if (opaque(x)) |
393 | // CHECK: br label |
394 | break; |
395 | |
396 | // CHECK: br label |
397 | } |
398 | // CHECK: br label |
399 | } catch (int x) { } |
400 | |
401 | // CHECK: call void @_ZN6test151AD1Ev |
402 | } |
403 | } |
404 | |
405 | namespace test16 { |
406 | struct A { A(); ~A() noexcept(false); }; |
407 | struct B { int x; B(const A &); ~B() noexcept(false); }; |
408 | void foo(); |
409 | bool cond(); |
410 | |
411 | // CHECK-LABEL: define void @_ZN6test163barEv() |
412 | void bar() { |
413 | // CHECK: [[EXN_SAVE:%.*]] = alloca i8* |
414 | // CHECK-NEXT: [[EXN_ACTIVE:%.*]] = alloca i1 |
415 | // CHECK-NEXT: [[TEMP:%.*]] = alloca [[A:%.*]], |
416 | // CHECK-NEXT: [[EXNSLOT:%.*]] = alloca i8* |
417 | // CHECK-NEXT: [[SELECTORSLOT:%.*]] = alloca i32 |
418 | // CHECK-NEXT: [[TEMP_ACTIVE:%.*]] = alloca i1 |
419 | |
420 | cond() ? throw B(A()) : foo(); |
421 | |
422 | // CHECK-NEXT: [[COND:%.*]] = call zeroext i1 @_ZN6test164condEv() |
423 | // CHECK-NEXT: store i1 false, i1* [[EXN_ACTIVE]] |
424 | // CHECK-NEXT: store i1 false, i1* [[TEMP_ACTIVE]] |
425 | // CHECK-NEXT: br i1 [[COND]], |
426 | |
427 | // CHECK: [[EXN:%.*]] = call i8* @__cxa_allocate_exception(i64 4) |
428 | // CHECK-NEXT: store i8* [[EXN]], i8** [[EXN_SAVE]] |
429 | // CHECK-NEXT: store i1 true, i1* [[EXN_ACTIVE]] |
430 | // CHECK-NEXT: [[T0:%.*]] = bitcast i8* [[EXN]] to [[B:%.*]]* |
431 | // CHECK-NEXT: invoke void @_ZN6test161AC1Ev([[A]]* [[TEMP]]) |
432 | // CHECK: store i1 true, i1* [[TEMP_ACTIVE]] |
433 | // CHECK-NEXT: invoke void @_ZN6test161BC1ERKNS_1AE([[B]]* [[T0]], [[A]]* dereferenceable({{[0-9]+}}) [[TEMP]]) |
434 | // CHECK: store i1 false, i1* [[EXN_ACTIVE]] |
435 | // CHECK-NEXT: invoke void @__cxa_throw(i8* [[EXN]], |
436 | |
437 | // CHECK: invoke void @_ZN6test163fooEv() |
438 | // CHECK: br label |
439 | |
440 | // CHECK: invoke void @_ZN6test161AD1Ev([[A]]* [[TEMP]]) |
441 | // CHECK: ret void |
442 | |
443 | // CHECK: [[T0:%.*]] = load i1, i1* [[EXN_ACTIVE]] |
444 | // CHECK-NEXT: br i1 [[T0]] |
445 | // CHECK: [[T1:%.*]] = load i8*, i8** [[EXN_SAVE]] |
446 | // CHECK-NEXT: call void @__cxa_free_exception(i8* [[T1]]) |
447 | // CHECK-NEXT: br label |
448 | } |
449 | } |
450 | |
451 | namespace test17 { |
452 | class BaseException { |
453 | private: |
454 | int a[4]; |
455 | public: |
456 | BaseException() {}; |
457 | }; |
458 | |
459 | class DerivedException: public BaseException { |
460 | }; |
461 | |
462 | int foo() { |
463 | throw DerivedException(); |
464 | // The alignment passed to memset is 16 on Darwin. |
465 | |
466 | // CHECK: [[T0:%.*]] = call i8* @__cxa_allocate_exception(i64 16) |
467 | // CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to %"class.test17::DerivedException"* |
468 | // CHECK-NEXT: [[T2:%.*]] = bitcast %"class.test17::DerivedException"* [[T1]] to i8* |
469 | // CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 16 [[T2]], i8 0, i64 16, i1 false) |
470 | } |
471 | } |
472 | |
473 | // CHECK: attributes [[NUW]] = { nounwind } |
474 | // CHECK: attributes [[NR]] = { noreturn } |
475 | |