xref: /llvm-project/clang/test/CodeGenCXX/strict-vtable-pointers.cpp (revision 94473f4db6a6f5f12d7c4081455b5b596094eac5)
1 // RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -fstrict-vtable-pointers -std=c++11 -disable-llvm-passes -O2 -emit-llvm -o %t.ll
2 // RUN: FileCheck --check-prefix=CHECK-CTORS %s < %t.ll
3 // RUN: FileCheck --check-prefix=CHECK-NEW %s < %t.ll
4 // RUN: FileCheck --check-prefix=CHECK-DTORS %s < %t.ll
5 // RUN: FileCheck --check-prefix=CHECK-LINK-REQ %s < %t.ll
6 
7 typedef __typeof__(sizeof(0)) size_t;
8 void *operator new(size_t, void *) throw();
9 using uintptr_t = unsigned long long;
10 
11 struct NotTrivialDtor {
12   ~NotTrivialDtor();
13 };
14 
15 struct DynamicBase1 {
16   NotTrivialDtor obj;
17   virtual void foo();
18 };
19 
20 struct DynamicDerived : DynamicBase1 {
21   void foo() override;
22 };
23 
24 struct DynamicBase2 {
25   virtual void bar();
26   ~DynamicBase2() {
27     bar();
28   }
29 };
30 
31 struct DynamicDerivedMultiple : DynamicBase1, DynamicBase2 {
32   void foo() override;
33   void bar() override;
34 };
35 
36 struct StaticBase {
37   NotTrivialDtor obj;
38   void bar();
39 };
40 
41 struct DynamicFromStatic : StaticBase {
42   virtual void bar();
43 };
44 
45 struct DynamicFromVirtualStatic1 : virtual StaticBase {
46 };
47 
48 struct DynamicFromVirtualStatic2 : virtual StaticBase {
49 };
50 
51 struct DynamicFrom2Virtuals : DynamicFromVirtualStatic1,
52                               DynamicFromVirtualStatic2 {
53 };
54 
55 // CHECK-NEW-LABEL: define{{.*}} void @_Z12LocalObjectsv()
56 // CHECK-NEW-NOT: @llvm.launder.invariant.group.p0(
57 // CHECK-NEW-LABEL: {{^}}}
58 void LocalObjects() {
59   DynamicBase1 DB;
60   DB.foo();
61   DynamicDerived DD;
62   DD.foo();
63 
64   DynamicBase2 DB2;
65   DB2.bar();
66 
67   StaticBase SB;
68   SB.bar();
69 
70   DynamicDerivedMultiple DDM;
71   DDM.foo();
72   DDM.bar();
73 
74   DynamicFromStatic DFS;
75   DFS.bar();
76   DynamicFromVirtualStatic1 DFVS1;
77   DFVS1.bar();
78   DynamicFrom2Virtuals DF2V;
79   DF2V.bar();
80 }
81 
82 struct DynamicFromVirtualStatic1;
83 // CHECK-CTORS-LABEL: define linkonce_odr void @_ZN25DynamicFromVirtualStatic1C1Ev
84 // CHECK-CTORS-NOT: @llvm.launder.invariant.group.p0(
85 // CHECK-CTORS-LABEL: {{^}}}
86 
87 struct DynamicFrom2Virtuals;
88 // CHECK-CTORS-LABEL: define linkonce_odr void @_ZN20DynamicFrom2VirtualsC1Ev
89 // CHECK-CTORS: call ptr @llvm.launder.invariant.group.p0(
90 // CHECK-CTORS-LABEL: {{^}}}
91 
92 // CHECK-NEW-LABEL: define{{.*}} void @_Z9Pointers1v()
93 // CHECK-NEW-NOT: @llvm.launder.invariant.group.p0(
94 // CHECK-NEW-LABEL: call void @_ZN12DynamicBase1C1Ev(
95 
96 // CHECK-NEW: %[[THIS3:.*]] = call ptr @llvm.launder.invariant.group.p0(ptr %[[THIS2:.*]])
97 // CHECK-NEW: call void @_ZN14DynamicDerivedC1Ev(ptr {{[^,]*}} %[[THIS3]])
98 // CHECK-NEW-LABEL: {{^}}}
99 void Pointers1() {
100   DynamicBase1 *DB = new DynamicBase1;
101   DB->foo();
102 
103   DynamicDerived *DD = new (DB) DynamicDerived;
104   DD->foo();
105   DD->~DynamicDerived();
106 }
107 
108 // CHECK-NEW-LABEL: define{{.*}} void @_Z14HackingObjectsv()
109 // CHECK-NEW:  call void @_ZN12DynamicBase1C1Ev
110 // CHECK-NEW:  call ptr @llvm.launder.invariant.group.p0(
111 // CHECK-NEW:  call void @_ZN14DynamicDerivedC1Ev(
112 // CHECK-NEW:  call ptr @llvm.launder.invariant.group.p0(
113 // CHECK-NEW: call void @_ZN12DynamicBase1C1Ev(
114 // CHECK-NEW-LABEL: {{^}}}
115 void HackingObjects() {
116   DynamicBase1 DB;
117   DB.foo();
118 
119   DynamicDerived *DB2 = new (&DB) DynamicDerived;
120   // Using DB now is prohibited.
121   DB2->foo();
122   DB2->~DynamicDerived();
123 
124   // We have to get back to the previous type to avoid calling wrong destructor
125   new (&DB) DynamicBase1;
126   DB.foo();
127 }
128 
129 /*** Testing Constructors ***/
130 struct DynamicBase1;
131 // CHECK-CTORS-LABEL: define linkonce_odr void @_ZN12DynamicBase1C2Ev(
132 // CHECK-CTORS-NOT: call ptr @llvm.launder.invariant.group.p0(
133 // CHECK-CTORS-LABEL: {{^}}}
134 
135 struct DynamicDerived;
136 
137 // CHECK-CTORS-LABEL: define linkonce_odr void @_ZN14DynamicDerivedC2Ev(
138 // CHECK-CTORS: %[[THIS0:.*]] = load ptr, ptr {{.*}}
139 // CHECK-CTORS: %[[THIS2:.*]] = call ptr @llvm.launder.invariant.group.p0(ptr %[[THIS1:.*]])
140 // CHECK-CTORS: call void @_ZN12DynamicBase1C2Ev(ptr {{[^,]*}} %[[THIS2]])
141 
142 // CHECK-CTORS: store {{.*}} %[[THIS0]]
143 // CHECK-CTORS-LABEL: {{^}}}
144 
145 struct DynamicDerivedMultiple;
146 // CHECK-CTORS-LABEL: define linkonce_odr void @_ZN22DynamicDerivedMultipleC2Ev(
147 
148 // CHECK-CTORS: %[[THIS0:.*]] = load ptr, ptr {{.*}}
149 // CHECK-CTORS: %[[THIS2:.*]] = call ptr @llvm.launder.invariant.group.p0(ptr %[[THIS0]])
150 // CHECK-CTORS: call void @_ZN12DynamicBase1C2Ev(ptr {{[^,]*}} %[[THIS2]])
151 
152 // CHECK-CTORS: call ptr @llvm.launder.invariant.group.p0(
153 
154 // CHECK-CTORS: call void @_ZN12DynamicBase2C2Ev(
155 // CHECK-CTORS-NOT: @llvm.launder.invariant.group.p0
156 
157 // CHECK-CTORS: store ptr getelementptr inbounds inrange(-16, 16) ({ [4 x ptr], [3 x ptr] }, ptr @_ZTV22DynamicDerivedMultiple, i32 0, i32 0, i32 2), ptr %[[THIS0]]
158 // CHECK-CTORS: %[[THIS_ADD:.*]] = getelementptr inbounds i8, ptr %[[THIS0]], i64 16
159 
160 // CHECK-CTORS: store ptr getelementptr inbounds inrange(-16, 8) ({ [4 x ptr], [3 x ptr] }, ptr @_ZTV22DynamicDerivedMultiple, i32 0, i32 1, i32 2), ptr %[[THIS_ADD]]
161 // CHECK-CTORS-LABEL: {{^}}}
162 
163 struct DynamicFromStatic;
164 // CHECK-CTORS-LABEL: define linkonce_odr void @_ZN17DynamicFromStaticC2Ev(
165 // CHECK-CTORS-NOT: @llvm.launder.invariant.group.p0(
166 // CHECK-CTORS-LABEL: {{^}}}
167 
168 struct A {
169   virtual void foo();
170   int m;
171 };
172 struct B : A {
173   void foo() override;
174 };
175 
176 union U {
177   A a;
178   B b;
179 };
180 
181 void changeToB(U *u);
182 void changeToA(U *u);
183 
184 void g2(A *a) {
185   a->foo();
186 }
187 // We have to guard access to union fields with invariant.group, because
188 // it is very easy to skip the barrier with unions. In this example the inlined
189 // g2 will produce loads with the same !invariant.group metadata, and
190 // u->a and u->b would use the same pointer.
191 // CHECK-NEW-LABEL: define{{.*}} void @_Z14UnionsBarriersP1U
192 void UnionsBarriers(U *u) {
193   // CHECK-NEW: call void @_Z9changeToBP1U(
194   changeToB(u);
195   // CHECK-NEW: call ptr @llvm.launder.invariant.group.p0(ptr
196   // CHECK-NEW: call void @_Z2g2P1A(ptr
197   g2(&u->b);
198   // CHECK-NEW: call void @_Z9changeToAP1U(ptr
199   changeToA(u);
200   // CHECK-NEW: call ptr @llvm.launder.invariant.group.p0(ptr
201   // call void @_Z2g2P1A(ptr %a)
202   g2(&u->a);
203   // CHECK-NEW-NOT: call ptr @llvm.launder.invariant.group.p0(ptr
204 }
205 
206 struct HoldingVirtuals {
207   A a;
208 };
209 
210 struct Empty {};
211 struct AnotherEmpty {
212   Empty e;
213 };
214 union NoVptrs {
215   int a;
216   AnotherEmpty empty;
217 };
218 void take(AnotherEmpty &);
219 
220 // CHECK-NEW-LABEL: noBarriers
221 void noBarriers(NoVptrs &noVptrs) {
222   // CHECK-NEW-NOT: call ptr @llvm.launder.invariant.group.p0(ptr
223   // CHECK-NEW: 42
224   noVptrs.a += 42;
225   // CHECK-NEW-NOT: call ptr @llvm.launder.invariant.group.p0(ptr
226   // CHECK-NEW: call void @_Z4takeR12AnotherEmpty(
227   take(noVptrs.empty);
228 }
229 
230 union U2 {
231   HoldingVirtuals h;
232   int z;
233 };
234 void take(HoldingVirtuals &);
235 
236 // CHECK-NEW-LABEL: define{{.*}} void @_Z15UnionsBarriers2R2U2
237 void UnionsBarriers2(U2 &u) {
238   // CHECK-NEW-NOT: call ptr @llvm.launder.invariant.group.p0(ptr
239   // CHECK-NEW: 42
240   u.z += 42;
241   // CHECK-NEW: call ptr @llvm.launder.invariant.group.p0(ptr
242   // CHECK-NEW: call void @_Z4takeR15HoldingVirtuals(
243   take(u.h);
244 }
245 
246 struct VirtualInBase : HoldingVirtuals, Empty {
247 };
248 
249 struct VirtualInVBase : virtual Empty, virtual HoldingVirtuals {
250 };
251 
252 // It has vtable by virtual inheritance.
253 struct VirtualInheritance : virtual Empty {
254 };
255 
256 union U3 {
257   VirtualInBase v1;
258   VirtualInBase v2;
259   VirtualInheritance v3;
260   int z;
261 };
262 
263 void take(VirtualInBase &);
264 void take(VirtualInVBase &);
265 void take(VirtualInheritance &);
266 
267 void UnionsBarrier3(U3 &u) {
268   // CHECK-NEW-NOT: call ptr @llvm.launder.invariant.group.p0(ptr
269   // CHECK-NEW: 42
270   u.z += 42;
271   // CHECK-NEW: call ptr @llvm.launder.invariant.group.p0(ptr
272   // CHECK-NEW: call void @_Z4takeR13VirtualInBase(
273   take(u.v1);
274   // CHECK-NEW: call ptr @llvm.launder.invariant.group.p0(ptr
275   // CHECK-NEW: call void @_Z4takeR13VirtualInBase(
276   take(u.v2);
277 
278   // CHECK-NEW: call ptr @llvm.launder.invariant.group.p0(ptr
279   // CHECK-NEW: call void @_Z4takeR18VirtualInheritance(
280   take(u.v3);
281 }
282 
283 // CHECK-NEW-LABEL: define{{.*}} void @_Z7comparev()
284 void compare() {
285   A *a = new A;
286   a->foo();
287   // CHECK-NEW: call ptr @llvm.launder.invariant.group.p0(ptr
288   A *b = new (a) B;
289 
290   // CHECK-NEW: %[[a:.*]] = call ptr @llvm.strip.invariant.group.p0(ptr
291   // CHECK-NEW: %[[b:.*]] = call ptr @llvm.strip.invariant.group.p0(ptr
292   // CHECK-NEW: %cmp = icmp eq ptr %[[a]], %[[b]]
293   if (a == b)
294     b->foo();
295 }
296 
297 // CHECK-NEW-LABEL: compare2
298 bool compare2(A *a, A *a2) {
299   // CHECK-NEW: %[[a:.*]] = call ptr @llvm.strip.invariant.group.p0(ptr
300   // CHECK-NEW: %[[b:.*]] = call ptr @llvm.strip.invariant.group.p0(ptr
301   // CHECK-NEW: %cmp = icmp ult ptr %[[a]], %[[b]]
302   return a < a2;
303 }
304 // CHECK-NEW-LABEL: compareIntPointers
305 bool compareIntPointers(int *a, int *b) {
306   // CHECK-NEW-NOT: call ptr @llvm.strip.invariant.group
307   return a == b;
308 }
309 
310 struct HoldingOtherVirtuals {
311   B b;
312 };
313 
314 // There is no need to add barriers for comparision of pointer to classes
315 // that are not dynamic.
316 // CHECK-NEW-LABEL: compare5
317 bool compare5(HoldingOtherVirtuals *a, HoldingOtherVirtuals *b) {
318   // CHECK-NEW-NOT: call ptr @llvm.strip.invariant.group
319   return a == b;
320 }
321 // CHECK-NEW-LABEL: compareNull
322 bool compareNull(A *a) {
323   // CHECK-NEW-NOT: call ptr @llvm.strip.invariant.group
324 
325   if (a != nullptr)
326     return false;
327   if (!a)
328     return false;
329   return a == nullptr;
330 }
331 
332 struct X;
333 // We have to also introduce the barriers if comparing pointers to incomplete
334 // objects
335 // CHECK-NEW-LABEL: define{{.*}} zeroext i1 @_Z8compare4P1XS0_
336 bool compare4(X *x, X *x2) {
337   // CHECK-NEW: %[[x:.*]] = call ptr @llvm.strip.invariant.group.p0(ptr
338   // CHECK-NEW: %[[x2:.*]] = call ptr @llvm.strip.invariant.group.p0(ptr
339   // CHECK-NEW: %cmp = icmp eq ptr %[[x]], %[[x2]]
340   return x == x2;
341 }
342 
343 // CHECK-NEW-LABEL: define{{.*}} void @_Z7member1P20HoldingOtherVirtuals(
344 void member1(HoldingOtherVirtuals *p) {
345 
346   // CHECK-NEW-NOT: call ptr @llvm.strip.invariant.group.p0(
347   (void)p->b;
348 }
349 
350 // CHECK-NEW-LABEL: member2
351 void member2(A *a) {
352   // CHECK-NEW: call ptr @llvm.strip.invariant.group.p0
353   (void)a->m;
354 }
355 
356 // Check if from comparison of addresses of member we can't infer the equality
357 // of ap and bp.
358 // CHECK-NEW-LABEL: @_Z18testCompareMembersv(
359 void testCompareMembers() {
360   // CHECK-NEW:    [[AP:%.*]] = alloca ptr
361   // CHECK-NEW:    [[APM:%.*]] = alloca ptr
362   // CHECK-NEW:    [[BP:%.*]] = alloca ptr
363   // CHECK-NEW:    [[BPM:%.*]] = alloca ptr
364 
365   A *ap = new A;
366   // CHECK-NEW:   call void %{{.*}}(ptr {{[^,]*}} %{{.*}})
367   ap->foo();
368   // CHECK-NEW:    [[TMP7:%.*]] = load ptr, ptr [[AP]]
369   // CHECK-NEW:    [[TMP9:%.*]] = call ptr @llvm.strip.invariant.group.p0(ptr [[TMP7]])
370   // CHECK-NEW:    [[M:%.*]] = getelementptr inbounds nuw [[STRUCT_A:%.*]], ptr [[TMP9]], i32 0, i32 1
371   // CHECK-NEW:    store ptr [[M]], ptr [[APM]]
372   int *const apm = &ap->m;
373 
374   B *bp = new (ap) B;
375 
376   // CHECK-NEW:    [[TMP20:%.*]] = load ptr, ptr [[BP]]
377   // CHECK-NEW:    [[TMP23:%.*]] = call ptr @llvm.strip.invariant.group.p0(ptr [[TMP20]])
378   // CHECK-NEW:    [[M4:%.*]] = getelementptr inbounds nuw [[STRUCT_A]], ptr [[TMP23]], i32 0, i32 1
379   // CHECK-NEW:    store ptr [[M4]], ptr [[BPM]]
380   int *const bpm = &bp->m;
381 
382   // CHECK-NEW:    [[TMP25:%.*]] = load ptr, ptr [[APM]]
383   // CHECK-NEW:    [[TMP26:%.*]] = load ptr, ptr [[BPM]]
384   // CHECK-NEW-NOT: strip.invariant.group
385   // CHECK-NEW-NOT: launder.invariant.group
386   // CHECK-NEW:    [[CMP:%.*]] = icmp eq ptr [[TMP25]], [[TMP26]]
387   if (apm == bpm) {
388     bp->foo();
389   }
390 }
391 
392 // CHECK-NEW-LABEL: define{{.*}} void @_Z9testCast1P1A(ptr
393 void testCast1(A *a) {
394   // Here we get rid of dynamic info
395   // CHECK-NEW: call ptr @llvm.strip.invariant.group
396   auto *v = (void *)a;
397 
398   // CHECK-NEW: call ptr @llvm.strip.invariant.group
399   auto i2 = (uintptr_t)a;
400   (void)i2;
401 
402   // CHECK-NEW-NOT: @llvm.strip.invariant.group
403   // CHECK-NEW-NOT: @llvm.launder.invariant.group
404 
405   // The information is already stripped
406   auto i = (uintptr_t)v;
407 }
408 
409 struct Incomplete;
410 // CHECK-NEW-LABEL: define{{.*}} void @_Z9testCast2P10Incomplete(ptr
411 void testCast2(Incomplete *I) {
412   // Here we get rid of potential dynamic info
413   // CHECK-NEW: call ptr @llvm.strip.invariant.group
414   auto *v = (void *)I;
415 
416   // CHECK-NEW: call ptr @llvm.strip.invariant.group
417   auto i2 = (uintptr_t)I;
418   (void)i2;
419 
420   // CHECK-NEW-NOT: @llvm.strip.invariant.group
421   // CHECK-NEW-NOT: @llvm.launder.invariant.group
422 
423   // The information is already stripped
424   auto i = (uintptr_t)v;
425 }
426 
427 // CHECK-NEW-LABEL: define{{.*}} void @_Z9testCast3y(
428 void testCast3(uintptr_t i) {
429   // CHECK-NEW-NOT: @llvm.strip.invariant.group
430   // CHECK-NEW: @llvm.launder.invariant.group
431   A *a3 = (A *)i;
432   (void)a3;
433 
434   auto *v2 = (void *)i;
435 
436   // CHECK-NEW: @llvm.launder.invariant.group
437   A *a2 = (A *)v2;
438   (void)a2;
439 
440   // CHECK-NEW-NOT: @llvm.launder.invariant.group
441   auto *v3 = (void *)i;
442   (void)v3;
443 }
444 
445 // CHECK-NEW-LABEL: define{{.*}} void @_Z9testCast4y(
446 void testCast4(uintptr_t i) {
447   // CHECK-NEW-NOT: @llvm.strip.invariant.group
448   // CHECK-NEW: @llvm.launder.invariant.group
449   auto *a3 = (Incomplete *)i;
450   (void)a3;
451 
452   // CHECK-NEW: @llvm.launder.invariant.group
453   auto *v2 = (void *)i;
454   // CHECK-NEW-NOT: @llvm.launder.invariant.group
455   auto *a2 = (Incomplete *)v2;
456   (void)a2;
457 }
458 
459 // CHECK-NEW-LABEL: define{{.*}} void @_Z9testCast5P1B(
460 void testCast5(B *b) {
461   // CHECK-NEW-NOT: @llvm.strip.invariant.group
462   // CHECK-NEW-NOT: @llvm.launder.invariant.group
463   A *a = b;
464   (void)a;
465 
466   auto *b2 = (B *)a;
467   (void)b2;
468 }
469 
470 // CHECK-NEW-LABEL: define{{.*}} void @_Z9testCast6P1A(
471 void testCast6(A *a) {
472 
473   // CHECK-NEW: @llvm.strip.invariant.group
474   auto *I = (Incomplete *)a;
475   (void)I;
476   // CHECK-NEW: @llvm.launder.invariant.group
477   auto *a2 = (A *)I;
478   (void)a2;
479 
480   // CHECK-NEW: @llvm.strip.invariant.group
481   auto *E = (Empty *)a;
482   (void)E;
483 
484   // CHECK-NEW: @llvm.launder.invariant.group
485   auto *a3 = (A *)E;
486   (void)a3;
487 
488   // CHECK-NEW-NOT: @llvm.strip.invariant.group
489   auto i = (uintptr_t)E;
490   (void)i;
491 }
492 
493 class Incomplete2;
494 // CHECK-NEW-LABEL: define{{.*}} void @_Z9testCast7P10Incomplete(
495 void testCast7(Incomplete *I) {
496   // CHECK-NEW-NOT: @llvm.strip.invariant.group
497 
498   // Incomplete2 could be dynamic where Incomplete may not be dynamic, thus
499   // launder is needed.  We don't strip firstly because launder is sufficient.
500 
501   // CHECK-NEW: @llvm.launder.invariant.group
502   auto *I2 = (Incomplete2 *)I;
503   (void)I2;
504   // CHECK-NEW-LABEL: ret void
505 }
506 
507 template <typename Base>
508 struct PossiblyDerivingFromDynamicBase : Base {
509 };
510 
511 // CHECK-NEW-LABEL: define{{.*}} void @_Z9testCast8P10Incomplete(
512 void testCast8(Incomplete *I) {
513   // CHECK-NEW-NOT: @llvm.strip.invariant.group
514   // CHECK-NEW: @llvm.launder.invariant.group
515   auto *P = (PossiblyDerivingFromDynamicBase<Incomplete> *)I;
516   (void)P;
517 
518   // CHECK-NEW: @llvm.launder.invariant.group
519   auto *P2 = (PossiblyDerivingFromDynamicBase<Empty> *)I;
520   (void)P2;
521 
522   // CHECK-NEW: @llvm.launder.invariant.group
523   auto *P3 = (PossiblyDerivingFromDynamicBase<A> *)I;
524   (void)P3;
525 
526   // CHECK-NEW-NOT: @llvm.launder.invariant.group
527   auto *a3 = (A *)P3;
528 
529   // CHECK-NEW-LABEL: ret void
530 }
531 
532 // CHECK-NEW-LABEL: define{{.*}} void @_Z9testCast9
533 void testCast9(PossiblyDerivingFromDynamicBase<Incomplete> *P) {
534   // CHECK-NEW: @llvm.strip.invariant.group
535   auto *V = (void *)P;
536 
537   // CHECK-NEW-LABEL: ret void
538 }
539 
540 /** DTORS **/
541 // CHECK-DTORS-LABEL: define linkonce_odr void @_ZN10StaticBaseD2Ev(
542 // CHECK-DTORS-NOT: call ptr @llvm.launder.invariant.group.p0(
543 // CHECK-DTORS-LABEL: {{^}}}
544 
545 // CHECK-DTORS-LABEL: define linkonce_odr void @_ZN25DynamicFromVirtualStatic2D2Ev(
546 // CHECK-DTORS-NOT: invariant.barrier
547 // CHECK-DTORS-LABEL: {{^}}}
548 
549 // CHECK-DTORS-LABEL: define linkonce_odr void @_ZN17DynamicFromStaticD2Ev
550 // CHECK-DTORS-NOT: call ptr @llvm.launder.invariant.group.p0(
551 // CHECK-DTORS-LABEL: {{^}}}
552 
553 // CHECK-DTORS-LABEL: define linkonce_odr void @_ZN22DynamicDerivedMultipleD2Ev(
554 
555 // CHECK-DTORS-LABEL: define linkonce_odr void @_ZN12DynamicBase2D2Ev(
556 // CHECK-DTORS: call ptr @llvm.launder.invariant.group.p0(
557 // CHECK-DTORS-LABEL: {{^}}}
558 
559 // CHECK-DTORS-LABEL: define linkonce_odr void @_ZN12DynamicBase1D2Ev
560 // CHECK-DTORS: call ptr @llvm.launder.invariant.group.p0(
561 // CHECK-DTORS-LABEL: {{^}}}
562 
563 // CHECK-DTORS-LABEL: define linkonce_odr void @_ZN14DynamicDerivedD2Ev
564 // CHECK-DTORS-NOT: call ptr @llvm.launder.invariant.group.p0(
565 // CHECK-DTORS-LABEL: {{^}}}
566 
567 // CHECK-LINK-REQ: !llvm.module.flags = !{![[FIRST:[0-9]+]], ![[SEC:[0-9]+]]{{.*}}}
568 
569 // CHECK-LINK-REQ: ![[FIRST]] = !{i32 1, !"StrictVTablePointers", i32 1}
570 // CHECK-LINK-REQ: ![[SEC]] = !{i32 3, !"StrictVTablePointersRequirement", ![[META:.*]]}
571 // CHECK-LINK-REQ: ![[META]] = !{!"StrictVTablePointers", i32 1}
572