Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / clang / test / CodeGenCXX / strict-vtable-pointers.cpp
blob34e50b39a5daa4afee44bb48761bccef97463850
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
7 typedef __typeof__(sizeof(0)) size_t;
8 void *operator new(size_t, void *) throw();
9 using uintptr_t = unsigned long long;
11 struct NotTrivialDtor {
12 ~NotTrivialDtor();
15 struct DynamicBase1 {
16 NotTrivialDtor obj;
17 virtual void foo();
20 struct DynamicDerived : DynamicBase1 {
21 void foo() override;
24 struct DynamicBase2 {
25 virtual void bar();
26 ~DynamicBase2() {
27 bar();
31 struct DynamicDerivedMultiple : DynamicBase1, DynamicBase2 {
32 void foo() override;
33 void bar() override;
36 struct StaticBase {
37 NotTrivialDtor obj;
38 void bar();
41 struct DynamicFromStatic : StaticBase {
42 virtual void bar();
45 struct DynamicFromVirtualStatic1 : virtual StaticBase {
48 struct DynamicFromVirtualStatic2 : virtual StaticBase {
51 struct DynamicFrom2Virtuals : DynamicFromVirtualStatic1,
52 DynamicFromVirtualStatic2 {
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();
64 DynamicBase2 DB2;
65 DB2.bar();
67 StaticBase SB;
68 SB.bar();
70 DynamicDerivedMultiple DDM;
71 DDM.foo();
72 DDM.bar();
74 DynamicFromStatic DFS;
75 DFS.bar();
76 DynamicFromVirtualStatic1 DFVS1;
77 DFVS1.bar();
78 DynamicFrom2Virtuals DF2V;
79 DF2V.bar();
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: {{^}}}
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: {{^}}}
92 // CHECK-NEW-LABEL: define{{.*}} void @_Z9Pointers1v()
93 // CHECK-NEW-NOT: @llvm.launder.invariant.group.p0(
94 // CHECK-NEW-LABEL: call void @_ZN12DynamicBase1C1Ev(
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();
103 DynamicDerived *DD = new (DB) DynamicDerived;
104 DD->foo();
105 DD->~DynamicDerived();
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();
119 DynamicDerived *DB2 = new (&DB) DynamicDerived;
120 // Using DB now is prohibited.
121 DB2->foo();
122 DB2->~DynamicDerived();
124 // We have to get back to the previous type to avoid calling wrong destructor
125 new (&DB) DynamicBase1;
126 DB.foo();
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: {{^}}}
135 struct DynamicDerived;
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]])
142 // CHECK-CTORS: store {{.*}} %[[THIS0]]
143 // CHECK-CTORS-LABEL: {{^}}}
145 struct DynamicDerivedMultiple;
146 // CHECK-CTORS-LABEL: define linkonce_odr void @_ZN22DynamicDerivedMultipleC2Ev(
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]])
152 // CHECK-CTORS: call ptr @llvm.launder.invariant.group.p0(
154 // CHECK-CTORS: call void @_ZN12DynamicBase2C2Ev(
155 // CHECK-CTORS-NOT: @llvm.launder.invariant.group.p0
157 // CHECK-CTORS: store {{.*}} @_ZTV22DynamicDerivedMultiple, i32 0, inrange i32 0, i32 2), {{.*}} %[[THIS0]]
158 // CHECK-CTORS: %[[THIS_ADD:.*]] = getelementptr inbounds i8, ptr %[[THIS0]], i64 16
160 // CHECK-CTORS: store {{.*}} @_ZTV22DynamicDerivedMultiple, i32 0, inrange i32 1, i32 2), {{.*}} %[[THIS_ADD]]
161 // CHECK-CTORS-LABEL: {{^}}}
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: {{^}}}
168 struct A {
169 virtual void foo();
170 int m;
172 struct B : A {
173 void foo() override;
176 union U {
177 A a;
178 B b;
181 void changeToB(U *u);
182 void changeToA(U *u);
184 void g2(A *a) {
185 a->foo();
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
206 struct HoldingVirtuals {
207 A a;
210 struct Empty {};
211 struct AnotherEmpty {
212 Empty e;
214 union NoVptrs {
215 int a;
216 AnotherEmpty empty;
218 void take(AnotherEmpty &);
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);
230 union U2 {
231 HoldingVirtuals h;
232 int z;
234 void take(HoldingVirtuals &);
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);
246 struct VirtualInBase : HoldingVirtuals, Empty {
249 struct VirtualInVBase : virtual Empty, virtual HoldingVirtuals {
252 // It has vtable by virtual inheritance.
253 struct VirtualInheritance : virtual Empty {
256 union U3 {
257 VirtualInBase v1;
258 VirtualInBase v2;
259 VirtualInheritance v3;
260 int z;
263 void take(VirtualInBase &);
264 void take(VirtualInVBase &);
265 void take(VirtualInheritance &);
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);
278 // CHECK-NEW: call ptr @llvm.launder.invariant.group.p0(ptr
279 // CHECK-NEW: call void @_Z4takeR18VirtualInheritance(
280 take(u.v3);
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;
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();
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;
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;
310 struct HoldingOtherVirtuals {
311 B b;
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;
321 // CHECK-NEW-LABEL: compareNull
322 bool compareNull(A *a) {
323 // CHECK-NEW-NOT: call ptr @llvm.strip.invariant.group
325 if (a != nullptr)
326 return false;
327 if (!a)
328 return false;
329 return a == nullptr;
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;
343 // CHECK-NEW-LABEL: define{{.*}} void @_Z7member1P20HoldingOtherVirtuals(
344 void member1(HoldingOtherVirtuals *p) {
346 // CHECK-NEW-NOT: call ptr @llvm.strip.invariant.group.p0(
347 (void)p->b;
350 // CHECK-NEW-LABEL: member2
351 void member2(A *a) {
352 // CHECK-NEW: call ptr @llvm.strip.invariant.group.p0
353 (void)a->m;
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
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 [[STRUCT_A:%.*]], ptr [[TMP9]], i32 0, i32 1
371 // CHECK-NEW: store ptr [[M]], ptr [[APM]]
372 int *const apm = &ap->m;
374 B *bp = new (ap) B;
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 [[STRUCT_A]], ptr [[TMP23]], i32 0, i32 1
379 // CHECK-NEW: store ptr [[M4]], ptr [[BPM]]
380 int *const bpm = &bp->m;
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();
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;
398 // CHECK-NEW: call ptr @llvm.strip.invariant.group
399 auto i2 = (uintptr_t)a;
400 (void)i2;
402 // CHECK-NEW-NOT: @llvm.strip.invariant.group
403 // CHECK-NEW-NOT: @llvm.launder.invariant.group
405 // The information is already stripped
406 auto i = (uintptr_t)v;
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;
416 // CHECK-NEW: call ptr @llvm.strip.invariant.group
417 auto i2 = (uintptr_t)I;
418 (void)i2;
420 // CHECK-NEW-NOT: @llvm.strip.invariant.group
421 // CHECK-NEW-NOT: @llvm.launder.invariant.group
423 // The information is already stripped
424 auto i = (uintptr_t)v;
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;
434 auto *v2 = (void *)i;
436 // CHECK-NEW: @llvm.launder.invariant.group
437 A *a2 = (A *)v2;
438 (void)a2;
440 // CHECK-NEW-NOT: @llvm.launder.invariant.group
441 auto *v3 = (void *)i;
442 (void)v3;
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;
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;
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;
466 auto *b2 = (B *)a;
467 (void)b2;
470 // CHECK-NEW-LABEL: define{{.*}} void @_Z9testCast6P1A(
471 void testCast6(A *a) {
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;
480 // CHECK-NEW: @llvm.strip.invariant.group
481 auto *E = (Empty *)a;
482 (void)E;
484 // CHECK-NEW: @llvm.launder.invariant.group
485 auto *a3 = (A *)E;
486 (void)a3;
488 // CHECK-NEW-NOT: @llvm.strip.invariant.group
489 auto i = (uintptr_t)E;
490 (void)i;
493 class Incomplete2;
494 // CHECK-NEW-LABEL: define{{.*}} void @_Z9testCast7P10Incomplete(
495 void testCast7(Incomplete *I) {
496 // CHECK-NEW-NOT: @llvm.strip.invariant.group
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.
501 // CHECK-NEW: @llvm.launder.invariant.group
502 auto *I2 = (Incomplete2 *)I;
503 (void)I2;
504 // CHECK-NEW-LABEL: ret void
507 template <typename Base>
508 struct PossiblyDerivingFromDynamicBase : Base {
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;
518 // CHECK-NEW: @llvm.launder.invariant.group
519 auto *P2 = (PossiblyDerivingFromDynamicBase<Empty> *)I;
520 (void)P2;
522 // CHECK-NEW: @llvm.launder.invariant.group
523 auto *P3 = (PossiblyDerivingFromDynamicBase<A> *)I;
524 (void)P3;
526 // CHECK-NEW-NOT: @llvm.launder.invariant.group
527 auto *a3 = (A *)P3;
529 // CHECK-NEW-LABEL: ret void
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;
537 // CHECK-NEW-LABEL: ret void
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: {{^}}}
545 // CHECK-DTORS-LABEL: define linkonce_odr void @_ZN25DynamicFromVirtualStatic2D2Ev(
546 // CHECK-DTORS-NOT: invariant.barrier
547 // CHECK-DTORS-LABEL: {{^}}}
549 // CHECK-DTORS-LABEL: define linkonce_odr void @_ZN17DynamicFromStaticD2Ev
550 // CHECK-DTORS-NOT: call ptr @llvm.launder.invariant.group.p0(
551 // CHECK-DTORS-LABEL: {{^}}}
553 // CHECK-DTORS-LABEL: define linkonce_odr void @_ZN22DynamicDerivedMultipleD2Ev(
555 // CHECK-DTORS-LABEL: define linkonce_odr void @_ZN12DynamicBase2D2Ev(
556 // CHECK-DTORS: call ptr @llvm.launder.invariant.group.p0(
557 // CHECK-DTORS-LABEL: {{^}}}
559 // CHECK-DTORS-LABEL: define linkonce_odr void @_ZN12DynamicBase1D2Ev
560 // CHECK-DTORS: call ptr @llvm.launder.invariant.group.p0(
561 // CHECK-DTORS-LABEL: {{^}}}
563 // CHECK-DTORS-LABEL: define linkonce_odr void @_ZN14DynamicDerivedD2Ev
564 // CHECK-DTORS-NOT: call ptr @llvm.launder.invariant.group.p0(
565 // CHECK-DTORS-LABEL: {{^}}}
567 // CHECK-LINK-REQ: !llvm.module.flags = !{![[FIRST:[0-9]+]], ![[SEC:[0-9]+]]{{.*}}}
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}