xref: /llvm-project/clang/test/CodeGenCXX/destructors.cpp (revision e6a9b06dc0b974eb16186a71099b88a631afdf52)
1 // RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o - -mconstructor-aliases -fcxx-exceptions -fexceptions -O1 -disable-llvm-passes -std=c++03 > %t
2 // RUN: FileCheck --check-prefix=CHECK1 --input-file=%t %s
3 // RUN: FileCheck --check-prefix=CHECK2 --input-file=%t %s
4 // RUN: FileCheck --check-prefix=CHECK3 --input-file=%t %s
5 // RUN: FileCheck --check-prefixes=CHECK4,CHECK4v03 --input-file=%t %s
6 // RUN: FileCheck --check-prefixes=CHECK5,CHECK5v03 --input-file=%t %s
7 // RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o - -mconstructor-aliases -fcxx-exceptions -fexceptions -O1 -disable-llvm-passes -std=c++11 > %t2
8 // RUN: FileCheck --check-prefix=CHECK1    --input-file=%t2 %s
9 // RUN: FileCheck --check-prefix=CHECK2v11 --input-file=%t2 %s
10 // RUN: FileCheck --check-prefix=CHECK3    --input-file=%t2 %s
11 // RUN: FileCheck --check-prefixes=CHECK4,CHECK4v11 --input-file=%t2 %s
12 // RUN: FileCheck --check-prefixes=CHECK5,CHECK5v11 --input-file=%t2 %s
13 // RUN: FileCheck --check-prefix=CHECK6    --input-file=%t2 %s
14 // REQUIRES: asserts
15 
16 struct A {
17   int a;
18 
19   ~A();
20 };
21 
22 // Base with non-trivial destructor
23 struct B : A {
24   ~B();
25 };
26 
~B()27 B::~B() { }
28 
29 // Field with non-trivial destructor
30 struct C {
31   A a;
32 
33   ~C();
34 };
35 
~C()36 C::~C() { }
37 
38 namespace PR7526 {
39   extern void foo();
40   struct allocator {
41     ~allocator() throw();
42   };
43 
44   struct allocator_derived : allocator { };
45 
46   // CHECK1-LABEL: define{{.*}} void @_ZN6PR75263fooEv()
47   // CHECK1: call void @_ZN6PR75269allocatorD2Ev
48 
49   // CHECK1-LABEL: define{{.*}} void @_ZN6PR75269allocatorD2Ev(ptr {{[^,]*}} %this) unnamed_addr
50   // CHECK1: call void @__cxa_call_unexpected
~allocator()51   allocator::~allocator() throw() { foo(); }
52 
foo()53   void foo() {
54     allocator_derived ad;
55   }
56 }
57 
58 // PR5084
59 template<typename T>
60 class A1 {
61   ~A1();
62 };
63 
64 template<> A1<char>::~A1();
65 
66 // PR5529
67 namespace PR5529 {
68   struct A {
69     ~A();
70   };
71 
~A()72   A::~A() { }
73   struct B : A {
74     virtual ~B();
75   };
76 
~B()77   B::~B()  {}
78 }
79 
80 // FIXME: there's a known problem in the codegen here where, if one
81 // destructor throws, the remaining destructors aren't run.  Fix it,
82 // then make this code check for it.
83 namespace test0 {
84   void foo();
85   struct VBase { ~VBase(); };
86   struct Base { ~Base(); };
87   struct Member { ~Member(); };
88 
89   struct A : Base {
90     Member M;
91     ~A();
92   };
93 
94   // The function-try-block won't suppress -mconstructor-aliases here.
~A()95   A::~A() try { } catch (int i) {}
96 
97 // complete destructor alias tested above
98 
99 // CHECK2-LABEL: @_ZN5test01AD1Ev ={{.*}} unnamed_addr alias {{.*}} @_ZN5test01AD2Ev
100 // CHECK2-LABEL: define{{.*}} void @_ZN5test01AD2Ev(ptr {{[^,]*}} %this) unnamed_addr
101 // CHECK2: invoke void @_ZN5test06MemberD1Ev
102 // CHECK2:   unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]]
103 // CHECK2: invoke void @_ZN5test04BaseD2Ev
104 // CHECK2:   unwind label [[BASE_UNWIND:%[a-zA-Z0-9.]+]]
105 
106 // In C++11, the destructors are often known not to throw.
107 // CHECK2v11-LABEL: @_ZN5test01AD1Ev ={{.*}} unnamed_addr alias {{.*}} @_ZN5test01AD2Ev
108 // CHECK2v11-LABEL: define{{.*}} void @_ZN5test01AD2Ev(ptr {{[^,]*}} %this) unnamed_addr
109 // CHECK2v11: call void @_ZN5test06MemberD1Ev
110 // CHECK2v11: call void @_ZN5test04BaseD2Ev
111 
112   struct B : Base, virtual VBase {
113     Member M;
114     ~B();
115   };
~B()116   B::~B() try { } catch (int i) {}
117   // It will suppress the delegation optimization here, though.
118 
119 // CHECK2-LABEL: define{{.*}} void @_ZN5test01BD2Ev(ptr {{[^,]*}} %this, ptr noundef %vtt) unnamed_addr
120 // CHECK2: invoke void @_ZN5test06MemberD1Ev
121 // CHECK2:   unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]]
122 // CHECK2: invoke void @_ZN5test04BaseD2Ev
123 // CHECK2:   unwind label [[BASE_UNWIND:%[a-zA-Z0-9.]+]]
124 
125 // CHECK2v11-LABEL: define{{.*}} void @_ZN5test01BD2Ev(ptr {{[^,]*}} %this, ptr noundef %vtt) unnamed_addr
126 // CHECK2v11: call void @_ZN5test06MemberD1Ev
127 // CHECK2v11: call void @_ZN5test04BaseD2Ev
128 
129 // CHECK2-LABEL: define{{.*}} void @_ZN5test01BD1Ev(ptr {{[^,]*}} %this) unnamed_addr
130 // CHECK2: invoke void @_ZN5test06MemberD1Ev
131 // CHECK2:   unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]]
132 // CHECK2: invoke void @_ZN5test04BaseD2Ev
133 // CHECK2:   unwind label [[BASE_UNWIND:%[a-zA-Z0-9.]+]]
134 // CHECK2: invoke void @_ZN5test05VBaseD2Ev
135 // CHECK2:   unwind label [[VBASE_UNWIND:%[a-zA-Z0-9.]+]]
136 
137 // CHECK2v11-LABEL: define{{.*}} void @_ZN5test01BD1Ev(ptr {{[^,]*}} %this) unnamed_addr
138 // CHECK2v11: call void @_ZN5test06MemberD1Ev
139 // CHECK2v11: call void @_ZN5test04BaseD2Ev
140 // CHECK2v11: call void @_ZN5test05VBaseD2Ev
141 }
142 
143 // Test base-class aliasing.
144 namespace test1 {
145   struct A { ~A(); char ***m; }; // non-trivial destructor
146   struct B { ~B(); }; // non-trivial destructor
147   struct Empty { }; // trivial destructor, empty
148   struct NonEmpty { int x; }; // trivial destructor, non-empty
149 
150   // There must be a definition in this translation unit for the alias
151   // optimization to apply.
~A()152   A::~A() { delete m; }
153 
154   struct M : A { ~M(); };
~M()155   M::~M() {}
156   // CHECK3: @_ZN5test11MD2Ev ={{.*}} unnamed_addr alias {{.*}} @_ZN5test11AD2Ev
157 
158   struct N : A, Empty { ~N(); };
~N()159   N::~N() {}
160   // CHECK3: @_ZN5test11ND2Ev ={{.*}} unnamed_addr alias {{.*}} @_ZN5test11AD2Ev
161 
162   struct O : Empty, A { ~O(); };
~O()163   O::~O() {}
164   // CHECK3: @_ZN5test11OD2Ev ={{.*}} unnamed_addr alias {{.*}} @_ZN5test11AD2Ev
165 
166   struct P : NonEmpty, A { ~P(); };
~P()167   P::~P() {} // CHECK3-LABEL: define{{.*}} void @_ZN5test11PD2Ev(ptr {{[^,]*}} %this) unnamed_addr
168 
169   struct Q : A, B { ~Q(); };
~Q()170   Q::~Q() {} // CHECK3-LABEL: define{{.*}} void @_ZN5test11QD2Ev(ptr {{[^,]*}} %this) unnamed_addr
171 
172   struct R : A { ~R(); };
~R()173   R::~R() { A a; } // CHECK3-LABEL: define{{.*}} void @_ZN5test11RD2Ev(ptr {{[^,]*}} %this) unnamed_addr
174 
175   struct S : A { ~S(); int x; };
~S()176   S::~S() {}
177   // CHECK4: @_ZN5test11SD2Ev ={{.*}} unnamed_addr alias {{.*}}, ptr @_ZN5test11AD2Ev
178 
179   struct T : A { ~T(); B x; };
~T()180   T::~T() {} // CHECK4-LABEL: define{{.*}} void @_ZN5test11TD2Ev(ptr {{[^,]*}} %this) unnamed_addr
181 
182   // The VTT parameter prevents this.  We could still make this work
183   // for calling conventions that are safe against extra parameters.
184   struct U : A, virtual B { ~U(); };
~U()185   U::~U() {} // CHECK4-LABEL: define{{.*}} void @_ZN5test11UD2Ev(ptr {{[^,]*}} %this, ptr noundef %vtt) unnamed_addr
186 }
187 
188 // PR6471
189 namespace test2 {
190   struct A { ~A(); char ***m; };
191   struct B : A { ~B(); };
192 
~B()193   B::~B() {}
194   // CHECK4-LABEL: define{{.*}} void @_ZN5test21BD2Ev(ptr {{[^,]*}} %this) unnamed_addr
195   // CHECK4: call void @_ZN5test21AD2Ev
196 }
197 
198 // PR7142
199 namespace test3 {
200   struct A { virtual ~A(); };
201   struct B { virtual ~B(); };
202   namespace { // internal linkage => deferred
203     struct C : A, B {}; // ~B() in D requires a this-adjustment thunk
204     struct D : C {};    // D::~D() is an alias to C::~C()
205   }
206 
test()207   void test() {
208     new D; // Force emission of D's vtable
209   }
210 
211   // CHECK4-LABEL: define internal void @_ZN5test312_GLOBAL__N_11CD2Ev(ptr {{[^,]*}} %this) unnamed_addr
212   // CHECK4v03: invoke void @_ZN5test31BD2Ev(
213   // CHECK4v11: call   void @_ZN5test31BD2Ev(
214   // CHECK4: call void @_ZN5test31AD2Ev(
215   // CHECK4: ret void
216 
217   // CHECK4-LABEL: define internal void @_ZN5test312_GLOBAL__N_11DD0Ev(ptr {{[^,]*}} %this) unnamed_addr
218   // CHECK4v03-SAME:  personality ptr @__gxx_personality_v0
219   // CHECK4v03: invoke void @_ZN5test312_GLOBAL__N_11CD2Ev
220   // CHECK4v11: call   void @_ZN5test312_GLOBAL__N_11CD2Ev
221   // CHECK4: call void @_ZdlPv({{.*}}) [[NUW:#[0-9]+]]
222   // CHECK4: ret void
223   // CHECK4v03: landingpad { ptr, i32 }
224   // CHECK4v03-NEXT: cleanup
225   // CHECK4v03: call void @_ZdlPv({{.*}}) [[NUW]]
226   // CHECK4v03: resume { ptr, i32 }
227   // CHECK4v11-NOT: landingpad
228 
229   // CHECK4-LABEL: define internal void @_ZThn8_N5test312_GLOBAL__N_11DD1Ev(
230   // CHECK4: getelementptr inbounds i8, ptr {{.*}}, i64 -8
231   // CHECK4: call void @_ZN5test312_GLOBAL__N_11CD2Ev
232   // CHECK4: ret void
233 
234   // CHECK4-LABEL: define internal void @_ZThn8_N5test312_GLOBAL__N_11DD0Ev(
235   // CHECK4: getelementptr inbounds i8, ptr {{.*}}, i64 -8
236   // CHECK4: call void @_ZN5test312_GLOBAL__N_11DD0Ev(
237   // CHECK4: ret void
238 
239   // CHECK4-LABEL: define internal void @_ZN5test312_GLOBAL__N_11CD0Ev(ptr {{[^,]*}} %this) unnamed_addr
240   // CHECK4v03-SAME:  personality ptr @__gxx_personality_v0
241   // CHECK4v03: invoke void @_ZN5test312_GLOBAL__N_11CD2Ev(
242   // CHECK4v11: call   void @_ZN5test312_GLOBAL__N_11CD2Ev(
243   // CHECK4: call void @_ZdlPv({{.*}}) [[NUW]]
244   // CHECK4: ret void
245   // CHECK4v03: landingpad { ptr, i32 }
246   // CHECK4v03-NEXT: cleanup
247   // CHECK4v03: call void @_ZdlPv({{.*}}) [[NUW]]
248   // CHECK4v03: resume { ptr, i32 }
249 
250   // CHECK4-LABEL: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD1Ev(
251   // CHECK4: getelementptr inbounds i8, ptr {{.*}}, i64 -8
252   // CHECK4: call void @_ZN5test312_GLOBAL__N_11CD2Ev(
253   // CHECK4: ret void
254 
255   // CHECK4-LABEL: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD0Ev(
256   // CHECK4: getelementptr inbounds i8, ptr {{.*}}, i64 -8
257   // CHECK4: call void @_ZN5test312_GLOBAL__N_11CD0Ev(
258   // CHECK4: ret void
259 
260   // CHECK4-LABEL: declare void @_ZN5test31BD2Ev(
261   // CHECK4-LABEL: declare void @_ZN5test31AD2Ev(
262 
263   // CHECK4: attributes [[NUW]] = {{[{].*}} nounwind {{.*[}]}}
264 }
265 
266 namespace test4 {
267   struct A { ~A(); };
268 
269   // CHECK5-LABEL: define{{.*}} void @_ZN5test43fooEv()
270   // CHECK5: call void @_ZN5test41AD1Ev
271   // CHECK5: ret void
foo()272   void foo() {
273     {
274       A a;
275       goto failure;
276     }
277 
278   failure:
279     return;
280   }
281 
282   // CHECK5-LABEL: define{{.*}} void @_ZN5test43barEi(
283   // CHECK5:      [[X:%.*]] = alloca i32
284   // CHECK5-NEXT: [[A:%.*]] = alloca
285   // CHECK5:      br label
286   // CHECK5:      [[TMP:%.*]] = load i32, ptr [[X]]
287   // CHECK5-NEXT: [[CMP:%.*]] = icmp ne i32 [[TMP]], 0
288   // CHECK5-NEXT: br i1
289   // CHECK5:      call void @_ZN5test41AD1Ev(
290   // CHECK5:      br label
291   // CHECK5:      [[TMP:%.*]] = load i32, ptr [[X]]
292   // CHECK5:      [[TMP2:%.*]] = add nsw i32 [[TMP]], -1
293   // CHECK5:      store i32 [[TMP2]], ptr [[X]]
294   // CHECK5:      br label
295   // CHECK5:      ret void
bar(int x)296   void bar(int x) {
297     for (A a; x; ) {
298       x--;
299     }
300   }
301 }
302 
303 // PR7575
304 namespace test5 {
305   struct A { ~A(); };
306 
307   // CHECK5-LABEL: define{{.*}} void @_ZN5test53fooEv()
308   // CHECK5:      [[ELEMS:%.*]] = alloca [5 x [[A:%.*]]], align
309   // CHECK5v03-NEXT: [[EXN:%.*]] = alloca ptr
310   // CHECK5v03-NEXT: [[SEL:%.*]] = alloca i32
311   // CHECK5-NEXT: call void @llvm.lifetime.start.p0(i64 5, ptr [[ELEMS]])
312   // CHECK5-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [5 x [[A]]], ptr [[ELEMS]], i32 0, i32 0
313   // CHECK5-NEXT: [[END:%.*]] = getelementptr inbounds [[A]], ptr [[BEGIN]], i64 5
314   // CHECK5-NEXT: br label
315   // CHECK5:      [[POST:%.*]] = phi ptr [ [[END]], {{%.*}} ], [ [[ELT:%.*]], {{%.*}} ]
316   // CHECK5-NEXT: [[ELT]] = getelementptr inbounds [[A]], ptr [[POST]], i64 -1
317   // CHECK5v03-NEXT: invoke void @_ZN5test51AD1Ev(ptr {{[^,]*}} [[ELT]])
318   // CHECK5v11-NEXT: call   void @_ZN5test51AD1Ev(ptr {{[^,]*}} [[ELT]])
319   // CHECK5:      [[T0:%.*]] = icmp eq ptr [[ELT]], [[BEGIN]]
320   // CHECK5-NEXT: br i1 [[T0]],
321   // CHECK5:      call void @llvm.lifetime.end
322   // CHECK5-NEXT: ret void
323   // lpad
324   // CHECK5v03:      [[EMPTY:%.*]] = icmp eq ptr [[BEGIN]], [[ELT]]
325   // CHECK5v03-NEXT: br i1 [[EMPTY]]
326   // CHECK5v03:      [[AFTER:%.*]] = phi ptr [ [[ELT]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ]
327   // CHECK5v03-NEXT: [[CUR:%.*]] = getelementptr inbounds [[A]], ptr [[AFTER]], i64 -1
328   // CHECK5v03-NEXT: invoke void @_ZN5test51AD1Ev(ptr {{[^,]*}} [[CUR]])
329   // CHECK5v03:      [[DONE:%.*]] = icmp eq ptr [[CUR]], [[BEGIN]]
330   // CHECK5v03-NEXT: br i1 [[DONE]],
331   // CHECK5v11-NOT: landingpad
332   // CHECK5v11:   }
foo()333   void foo() {
334     A elems[5];
335   }
336 }
337 
338 namespace test6 {
339   void opaque();
340 
341   struct A { ~A(); };
342   template <unsigned> struct B { B(); ~B(); int _; };
343   struct C : B<0>, B<1>, virtual B<2>, virtual B<3> {
344     A x, y, z;
345 
346     C();
347     ~C();
348   };
349 
C()350   C::C() { opaque(); }
351   // CHECK5-LABEL: define{{.*}} void @_ZN5test61CC1Ev(ptr {{[^,]*}} %this) unnamed_addr
352   // CHECK5:   call void @_ZN5test61BILj2EEC2Ev
353   // CHECK5:   invoke void @_ZN5test61BILj3EEC2Ev
354   // CHECK5:   invoke void @_ZN5test61BILj0EEC2Ev
355   // CHECK5:   invoke void @_ZN5test61BILj1EEC2Ev
356   // CHECK5:   invoke void @_ZN5test66opaqueEv
357   // CHECK5:   ret void
358   // FIXME: way too much EH cleanup code follows
359 
~C()360   C::~C() { opaque(); }
361   // CHECK5-LABEL: define{{.*}} void @_ZN5test61CD2Ev(ptr {{[^,]*}} %this, ptr noundef %vtt) unnamed_addr
362   // CHECK5:   invoke void @_ZN5test66opaqueEv
363   // CHECK5v03:   invoke void @_ZN5test61AD1Ev
364   // CHECK5v03:   invoke void @_ZN5test61AD1Ev
365   // CHECK5v03:   invoke void @_ZN5test61AD1Ev
366   // CHECK5v03:   invoke void @_ZN5test61BILj1EED2Ev
367   // CHECK5v11:   call   void @_ZN5test61AD1Ev
368   // CHECK5v11:   call   void @_ZN5test61AD1Ev
369   // CHECK5v11:   call   void @_ZN5test61AD1Ev
370   // CHECK5v11:   call   void @_ZN5test61BILj1EED2Ev
371   // CHECK5:   call void @_ZN5test61BILj0EED2Ev
372   // CHECK5:   ret void
373   // CHECK5v03:   invoke void @_ZN5test61AD1Ev
374   // CHECK5v03:   invoke void @_ZN5test61AD1Ev
375   // CHECK5v03:   invoke void @_ZN5test61AD1Ev
376   // CHECK5v03:   invoke void @_ZN5test61BILj1EED2Ev
377   // CHECK5v03:   invoke void @_ZN5test61BILj0EED2Ev
378 
379   // CHECK5-LABEL: define{{.*}} void @_ZN5test61CD1Ev(ptr {{[^,]*}} %this) unnamed_addr
380   // CHECK5v03:   invoke void @_ZN5test61CD2Ev
381   // CHECK5v03:   invoke void @_ZN5test61BILj3EED2Ev
382   // CHECK5v03:   call void @_ZN5test61BILj2EED2Ev
383   // CHECK5v03:   ret void
384   // CHECK5v03:   invoke void @_ZN5test61BILj3EED2Ev
385   // CHECK5v03:   invoke void @_ZN5test61BILj2EED2Ev
386 
387   // CHECK5v11:   call void @_ZN5test61CD2Ev
388   // CHECK5v11:   call void @_ZN5test61BILj3EED2Ev
389   // CHECK5v11:   call void @_ZN5test61BILj2EED2Ev
390   // CHECK5v11:   ret void
391 }
392 
393 // PR 9197
394 namespace test7 {
395   struct D { ~D(); };
396 
397   struct A { ~A(); };
~A()398   A::~A() { }
399 
400   struct B : public A {
401     ~B();
402     D arr[1];
403   };
404 
405   // Verify that this doesn't get emitted as an alias
406   // CHECK5-LABEL: define{{.*}} void @_ZN5test71BD2Ev(
407   // CHECK5v03:   invoke void @_ZN5test71DD1Ev(
408   // CHECK5v11:   call   void @_ZN5test71DD1Ev(
409   // CHECK5:   call void @_ZN5test71AD2Ev(
~B()410   B::~B() {}
411 }
412 
413 // PR10467
414 namespace test8 {
415   struct A { A(); ~A(); };
416 
417   void die() __attribute__((noreturn));
test()418   void test() {
419     A x;
420     while (1) {
421       A y;
422       goto l;
423     }
424   l: die();
425   }
426 
427   // CHECK5-LABEL:    define{{.*}} void @_ZN5test84testEv()
428   // CHECK5:      [[X:%.*]] = alloca [[A:%.*]], align 1
429   // CHECK5-NEXT: [[Y:%.*]] = alloca [[A:%.*]], align 1
430   // CHECK5:      call void @_ZN5test81AC1Ev(ptr {{[^,]*}} [[X]])
431   // CHECK5-NEXT: br label
432   // CHECK5:      invoke void @_ZN5test81AC1Ev(ptr {{[^,]*}} [[Y]])
433   // CHECK5v03:   invoke void @_ZN5test81AD1Ev(ptr {{[^,]*}} [[Y]])
434   // CHECK5v11:   call   void @_ZN5test81AD1Ev(ptr {{[^,]*}} [[Y]])
435   // CHECK5-NOT:  switch
436   // CHECK5:      invoke void @_ZN5test83dieEv()
437   // CHECK5:      unreachable
438 }
439 
440 // PR12710
441 namespace test9 {
442   struct ArgType {
443     ~ArgType();
444   };
445   template<typename T>
446   void f1(const ArgType& = ArgType());
447   void f2();
bar()448   void bar() {
449     f1<int>();
450     f2();
451   }
452   // CHECK5: call void @_ZN5test97ArgTypeD1Ev(ptr {{[^,]*}} %
453   // CHECK5: call void @_ZN5test92f2Ev()
454 }
455 
456 namespace test10 {
457   // We used to crash trying to replace _ZN6test106OptionD1Ev with
458   // _ZN6test106OptionD2Ev twice.
459   struct Option {
~Optiontest10::Option460     virtual ~Option() {}
461   };
462   template <class DataType> class opt : public Option {};
463   template class opt<int>;
464   // CHECK5-LABEL: define{{.*}} zeroext i1 @_ZN6test1016handleOccurrenceEv(
handleOccurrence()465   bool handleOccurrence() {
466     // CHECK5: call void @_ZN6test106OptionD2Ev(
467     Option x;
468     return true;
469   }
470 }
471 
472 #if __cplusplus >= 201103L
473 namespace test11 {
474 
475 // Check that lifetime.end is emitted in the landing pad.
476 
477 // CHECK6-LABEL: define{{.*}} void @_ZN6test1115testLifetimeEndEi(
478 // CHECK6: entry:
479 // CHECK6: [[T1:%[a-z0-9]+]] = alloca %"struct.test11::S1"
480 // CHECK6: [[T2:%[a-z0-9]+]] = alloca %"struct.test11::S1"
481 // CHECK6: [[T3:%[a-z0-9]+]] = alloca %"struct.test11::S1"
482 
483 // CHECK6: {{^}}invoke.cont
484 // CHECK6: call void @_ZN6test112S1D1Ev(ptr {{[^,]*}} [[T1]])
485 // CHECK6: call void @llvm.lifetime.end.p0(i64 32, ptr [[T1]])
486 // CHECK6: {{^}}lpad
487 // CHECK6: call void @_ZN6test112S1D1Ev(ptr {{[^,]*}} [[T1]])
488 // CHECK6: call void @llvm.lifetime.end.p0(i64 32, ptr [[T1]])
489 
490 // CHECK6: {{^}}invoke.cont
491 // CHECK6: call void @_ZN6test112S1D1Ev(ptr {{[^,]*}} [[T2]])
492 // CHECK6: call void @llvm.lifetime.end.p0(i64 32, ptr [[T2]])
493 // CHECK6: {{^}}lpad
494 // CHECK6: call void @_ZN6test112S1D1Ev(ptr {{[^,]*}} [[T2]])
495 // CHECK6: call void @llvm.lifetime.end.p0(i64 32, ptr [[T2]])
496 
497 // CHECK6: {{^}}invoke.cont
498 // CHECK6: call void @_ZN6test112S1D1Ev(ptr {{[^,]*}} [[T3]])
499 // CHECK6: call void @llvm.lifetime.end.p0(i64 32, ptr [[T3]])
500 // CHECK6: {{^}}lpad
501 // CHECK6: call void @_ZN6test112S1D1Ev(ptr {{[^,]*}} [[T3]])
502 // CHECK6: call void @llvm.lifetime.end.p0(i64 32, ptr [[T3]])
503 
504   struct S1 {
505     ~S1();
506     int a[8];
507   };
508 
509   void func1(S1 &) noexcept(false);
510 
testLifetimeEnd(int n)511   void testLifetimeEnd(int n) {
512     if (n < 10) {
513       S1 t1;
514       func1(t1);
515     } else if (n < 100) {
516       S1 t2;
517       func1(t2);
518     } else if (n < 1000) {
519       S1 t3;
520       func1(t3);
521     }
522   }
523 
524 }
525 
526 namespace final_dtor {
527   struct A {
528     virtual void f();
529     // CHECK6-LABEL: define {{.*}} @_ZN10final_dtor1AD2Ev(
530     // CHECK6: store {{.*}} @_ZTV
531     // CHECK6-LABEL: {{^}}}
~Afinal_dtor::A532     virtual ~A() { f(); }
533   };
534   struct B : A {
535     // CHECK6-LABEL: define {{.*}} @_ZN10final_dtor1BD2Ev(
536     // CHECK6: store {{.*}} @_ZTV
537     // CHECK6-LABEL: {{^}}}
~Bfinal_dtor::B538     virtual ~B() { f(); }
539   };
540   struct C final : A {
541     // CHECK6-LABEL: define {{.*}} @_ZN10final_dtor1CD2Ev(
542     // CHECK6-NOT: store {{.*}} @_ZTV
543     // CHECK6-LABEL: {{^}}}
~Cfinal_dtor::C544     virtual ~C() { f(); }
545   };
546   struct D : A {
547     // CHECK6-LABEL: define {{.*}} @_ZN10final_dtor1DD2Ev(
548     // CHECK6-NOT: store {{.*}} @_ZTV
549     // CHECK6-LABEL: {{^}}}
~Dfinal_dtor::D550     virtual ~D() final { f(); }
551   };
use()552   void use() {
553     {A a;}
554     {B b;}
555     {C c;}
556     {D d;}
557   }
558 }
559 #endif
560