572 lines · cpp
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.ll2// RUN: FileCheck --check-prefix=CHECK-CTORS %s < %t.ll3// RUN: FileCheck --check-prefix=CHECK-NEW %s < %t.ll4// RUN: FileCheck --check-prefix=CHECK-DTORS %s < %t.ll5// RUN: FileCheck --check-prefix=CHECK-LINK-REQ %s < %t.ll6 7typedef __typeof__(sizeof(0)) size_t;8void *operator new(size_t, void *) throw();9using uintptr_t = unsigned long long;10 11struct NotTrivialDtor {12 ~NotTrivialDtor();13};14 15struct DynamicBase1 {16 NotTrivialDtor obj;17 virtual void foo();18};19 20struct DynamicDerived : DynamicBase1 {21 void foo() override;22};23 24struct DynamicBase2 {25 virtual void bar();26 ~DynamicBase2() {27 bar();28 }29};30 31struct DynamicDerivedMultiple : DynamicBase1, DynamicBase2 {32 void foo() override;33 void bar() override;34};35 36struct StaticBase {37 NotTrivialDtor obj;38 void bar();39};40 41struct DynamicFromStatic : StaticBase {42 virtual void bar();43};44 45struct DynamicFromVirtualStatic1 : virtual StaticBase {46};47 48struct DynamicFromVirtualStatic2 : virtual StaticBase {49};50 51struct 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: {{^}}}58void 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 82struct DynamicFromVirtualStatic1;83// CHECK-CTORS-LABEL: define linkonce_odr void @_ZN25DynamicFromVirtualStatic1C1Ev84// CHECK-CTORS-NOT: @llvm.launder.invariant.group.p0(85// CHECK-CTORS-LABEL: {{^}}}86 87struct DynamicFrom2Virtuals;88// CHECK-CTORS-LABEL: define linkonce_odr void @_ZN20DynamicFrom2VirtualsC1Ev89// 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: {{^}}}99void 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 @_ZN12DynamicBase1C1Ev110// 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: {{^}}}115void 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 destructor125 new (&DB) DynamicBase1;126 DB.foo();127}128 129/*** Testing Constructors ***/130struct 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 135struct 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 145struct 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.p0156 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 16159 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 163struct DynamicFromStatic;164// CHECK-CTORS-LABEL: define linkonce_odr void @_ZN17DynamicFromStaticC2Ev(165// CHECK-CTORS-NOT: @llvm.launder.invariant.group.p0(166// CHECK-CTORS-LABEL: {{^}}}167 168struct A {169 virtual void foo();170 int m;171};172struct B : A {173 void foo() override;174};175 176union U {177 A a;178 B b;179};180 181void changeToB(U *u);182void changeToA(U *u);183 184void g2(A *a) {185 a->foo();186}187// We have to guard access to union fields with invariant.group, because188// it is very easy to skip the barrier with unions. In this example the inlined189// g2 will produce loads with the same !invariant.group metadata, and190// u->a and u->b would use the same pointer.191// CHECK-NEW-LABEL: define{{.*}} void @_Z14UnionsBarriersP1U192void UnionsBarriers(U *u) {193 // CHECK-NEW: call void @_Z9changeToBP1U(194 changeToB(u);195 // CHECK-NEW: call ptr @llvm.launder.invariant.group.p0(ptr196 // CHECK-NEW: call void @_Z2g2P1A(ptr197 g2(&u->b);198 // CHECK-NEW: call void @_Z9changeToAP1U(ptr199 changeToA(u);200 // CHECK-NEW: call ptr @llvm.launder.invariant.group.p0(ptr201 // call void @_Z2g2P1A(ptr %a)202 g2(&u->a);203 // CHECK-NEW-NOT: call ptr @llvm.launder.invariant.group.p0(ptr204}205 206struct HoldingVirtuals {207 A a;208};209 210struct Empty {};211struct AnotherEmpty {212 Empty e;213};214union NoVptrs {215 int a;216 AnotherEmpty empty;217};218void take(AnotherEmpty &);219 220// CHECK-NEW-LABEL: noBarriers221void noBarriers(NoVptrs &noVptrs) {222 // CHECK-NEW-NOT: call ptr @llvm.launder.invariant.group.p0(ptr223 // CHECK-NEW: 42224 noVptrs.a += 42;225 // CHECK-NEW-NOT: call ptr @llvm.launder.invariant.group.p0(ptr226 // CHECK-NEW: call void @_Z4takeR12AnotherEmpty(227 take(noVptrs.empty);228}229 230union U2 {231 HoldingVirtuals h;232 int z;233};234void take(HoldingVirtuals &);235 236// CHECK-NEW-LABEL: define{{.*}} void @_Z15UnionsBarriers2R2U2237void UnionsBarriers2(U2 &u) {238 // CHECK-NEW-NOT: call ptr @llvm.launder.invariant.group.p0(ptr239 // CHECK-NEW: 42240 u.z += 42;241 // CHECK-NEW: call ptr @llvm.launder.invariant.group.p0(ptr242 // CHECK-NEW: call void @_Z4takeR15HoldingVirtuals(243 take(u.h);244}245 246struct VirtualInBase : HoldingVirtuals, Empty {247};248 249struct VirtualInVBase : virtual Empty, virtual HoldingVirtuals {250};251 252// It has vtable by virtual inheritance.253struct VirtualInheritance : virtual Empty {254};255 256union U3 {257 VirtualInBase v1;258 VirtualInBase v2;259 VirtualInheritance v3;260 int z;261};262 263void take(VirtualInBase &);264void take(VirtualInVBase &);265void take(VirtualInheritance &);266 267void UnionsBarrier3(U3 &u) {268 // CHECK-NEW-NOT: call ptr @llvm.launder.invariant.group.p0(ptr269 // CHECK-NEW: 42270 u.z += 42;271 // CHECK-NEW: call ptr @llvm.launder.invariant.group.p0(ptr272 // CHECK-NEW: call void @_Z4takeR13VirtualInBase(273 take(u.v1);274 // CHECK-NEW: call ptr @llvm.launder.invariant.group.p0(ptr275 // CHECK-NEW: call void @_Z4takeR13VirtualInBase(276 take(u.v2);277 278 // CHECK-NEW: call ptr @llvm.launder.invariant.group.p0(ptr279 // CHECK-NEW: call void @_Z4takeR18VirtualInheritance(280 take(u.v3);281}282 283// CHECK-NEW-LABEL: define{{.*}} void @_Z7comparev()284void compare() {285 A *a = new A;286 a->foo();287 // CHECK-NEW: call ptr @llvm.launder.invariant.group.p0(ptr288 A *b = new (a) B;289 290 // CHECK-NEW: %[[a:.*]] = call ptr @llvm.strip.invariant.group.p0(ptr291 // CHECK-NEW: %[[b:.*]] = call ptr @llvm.strip.invariant.group.p0(ptr292 // CHECK-NEW: %cmp = icmp eq ptr %[[a]], %[[b]]293 if (a == b)294 b->foo();295}296 297// CHECK-NEW-LABEL: compare2298bool compare2(A *a, A *a2) {299 // CHECK-NEW: %[[a:.*]] = call ptr @llvm.strip.invariant.group.p0(ptr300 // CHECK-NEW: %[[b:.*]] = call ptr @llvm.strip.invariant.group.p0(ptr301 // CHECK-NEW: %cmp = icmp ult ptr %[[a]], %[[b]]302 return a < a2;303}304// CHECK-NEW-LABEL: compareIntPointers305bool compareIntPointers(int *a, int *b) {306 // CHECK-NEW-NOT: call ptr @llvm.strip.invariant.group307 return a == b;308}309 310struct HoldingOtherVirtuals {311 B b;312};313 314// There is no need to add barriers for comparision of pointer to classes315// that are not dynamic.316// CHECK-NEW-LABEL: compare5317bool compare5(HoldingOtherVirtuals *a, HoldingOtherVirtuals *b) {318 // CHECK-NEW-NOT: call ptr @llvm.strip.invariant.group319 return a == b;320}321// CHECK-NEW-LABEL: compareNull322bool compareNull(A *a) {323 // CHECK-NEW-NOT: call ptr @llvm.strip.invariant.group324 325 if (a != nullptr)326 return false;327 if (!a)328 return false;329 return a == nullptr;330}331 332struct X;333// We have to also introduce the barriers if comparing pointers to incomplete334// objects335// CHECK-NEW-LABEL: define{{.*}} zeroext i1 @_Z8compare4P1XS0_336bool compare4(X *x, X *x2) {337 // CHECK-NEW: %[[x:.*]] = call ptr @llvm.strip.invariant.group.p0(ptr338 // CHECK-NEW: %[[x2:.*]] = call ptr @llvm.strip.invariant.group.p0(ptr339 // CHECK-NEW: %cmp = icmp eq ptr %[[x]], %[[x2]]340 return x == x2;341}342 343// CHECK-NEW-LABEL: define{{.*}} void @_Z7member1P20HoldingOtherVirtuals(344void 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: member2351void member2(A *a) {352 // CHECK-NEW: call ptr @llvm.strip.invariant.group.p0353 (void)a->m;354}355 356// Check if from comparison of addresses of member we can't infer the equality357// of ap and bp.358// CHECK-NEW-LABEL: @_Z18testCompareMembersv(359void testCompareMembers() {360 // CHECK-NEW: [[AP:%.*]] = alloca ptr361 // CHECK-NEW: [[APM:%.*]] = alloca ptr362 // CHECK-NEW: [[BP:%.*]] = alloca ptr363 // CHECK-NEW: [[BPM:%.*]] = alloca ptr364 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 1371 // 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 1379 // 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.group385 // CHECK-NEW-NOT: launder.invariant.group386 // 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(ptr393void testCast1(A *a) {394 // Here we get rid of dynamic info395 // CHECK-NEW: call ptr @llvm.strip.invariant.group396 auto *v = (void *)a;397 398 // CHECK-NEW: call ptr @llvm.strip.invariant.group399 auto i2 = (uintptr_t)a;400 (void)i2;401 402 // CHECK-NEW-NOT: @llvm.strip.invariant.group403 // CHECK-NEW-NOT: @llvm.launder.invariant.group404 405 // The information is already stripped406 auto i = (uintptr_t)v;407}408 409struct Incomplete;410// CHECK-NEW-LABEL: define{{.*}} void @_Z9testCast2P10Incomplete(ptr411void testCast2(Incomplete *I) {412 // Here we get rid of potential dynamic info413 // CHECK-NEW: call ptr @llvm.strip.invariant.group414 auto *v = (void *)I;415 416 // CHECK-NEW: call ptr @llvm.strip.invariant.group417 auto i2 = (uintptr_t)I;418 (void)i2;419 420 // CHECK-NEW-NOT: @llvm.strip.invariant.group421 // CHECK-NEW-NOT: @llvm.launder.invariant.group422 423 // The information is already stripped424 auto i = (uintptr_t)v;425}426 427// CHECK-NEW-LABEL: define{{.*}} void @_Z9testCast3y(428void testCast3(uintptr_t i) {429 // CHECK-NEW-NOT: @llvm.strip.invariant.group430 // CHECK-NEW: @llvm.launder.invariant.group431 A *a3 = (A *)i;432 (void)a3;433 434 auto *v2 = (void *)i;435 436 // CHECK-NEW: @llvm.launder.invariant.group437 A *a2 = (A *)v2;438 (void)a2;439 440 // CHECK-NEW-NOT: @llvm.launder.invariant.group441 auto *v3 = (void *)i;442 (void)v3;443}444 445// CHECK-NEW-LABEL: define{{.*}} void @_Z9testCast4y(446void testCast4(uintptr_t i) {447 // CHECK-NEW-NOT: @llvm.strip.invariant.group448 // CHECK-NEW: @llvm.launder.invariant.group449 auto *a3 = (Incomplete *)i;450 (void)a3;451 452 // CHECK-NEW: @llvm.launder.invariant.group453 auto *v2 = (void *)i;454 // CHECK-NEW-NOT: @llvm.launder.invariant.group455 auto *a2 = (Incomplete *)v2;456 (void)a2;457}458 459// CHECK-NEW-LABEL: define{{.*}} void @_Z9testCast5P1B(460void testCast5(B *b) {461 // CHECK-NEW-NOT: @llvm.strip.invariant.group462 // CHECK-NEW-NOT: @llvm.launder.invariant.group463 A *a = b;464 (void)a;465 466 auto *b2 = (B *)a;467 (void)b2;468}469 470// CHECK-NEW-LABEL: define{{.*}} void @_Z9testCast6P1A(471void testCast6(A *a) {472 473 // CHECK-NEW: @llvm.strip.invariant.group474 auto *I = (Incomplete *)a;475 (void)I;476 // CHECK-NEW: @llvm.launder.invariant.group477 auto *a2 = (A *)I;478 (void)a2;479 480 // CHECK-NEW: @llvm.strip.invariant.group481 auto *E = (Empty *)a;482 (void)E;483 484 // CHECK-NEW: @llvm.launder.invariant.group485 auto *a3 = (A *)E;486 (void)a3;487 488 // CHECK-NEW-NOT: @llvm.strip.invariant.group489 auto i = (uintptr_t)E;490 (void)i;491}492 493class Incomplete2;494// CHECK-NEW-LABEL: define{{.*}} void @_Z9testCast7P10Incomplete(495void testCast7(Incomplete *I) {496 // CHECK-NEW-NOT: @llvm.strip.invariant.group497 498 // Incomplete2 could be dynamic where Incomplete may not be dynamic, thus499 // launder is needed. We don't strip firstly because launder is sufficient.500 501 // CHECK-NEW: @llvm.launder.invariant.group502 auto *I2 = (Incomplete2 *)I;503 (void)I2;504 // CHECK-NEW-LABEL: ret void505}506 507template <typename Base>508struct PossiblyDerivingFromDynamicBase : Base {509};510 511// CHECK-NEW-LABEL: define{{.*}} void @_Z9testCast8P10Incomplete(512void testCast8(Incomplete *I) {513 // CHECK-NEW-NOT: @llvm.strip.invariant.group514 // CHECK-NEW: @llvm.launder.invariant.group515 auto *P = (PossiblyDerivingFromDynamicBase<Incomplete> *)I;516 (void)P;517 518 // CHECK-NEW: @llvm.launder.invariant.group519 auto *P2 = (PossiblyDerivingFromDynamicBase<Empty> *)I;520 (void)P2;521 522 // CHECK-NEW: @llvm.launder.invariant.group523 auto *P3 = (PossiblyDerivingFromDynamicBase<A> *)I;524 (void)P3;525 526 // CHECK-NEW-NOT: @llvm.launder.invariant.group527 auto *a3 = (A *)P3;528 529 // CHECK-NEW-LABEL: ret void530}531 532// CHECK-NEW-LABEL: define{{.*}} void @_Z9testCast9533void testCast9(PossiblyDerivingFromDynamicBase<Incomplete> *P) {534 // CHECK-NEW: @llvm.strip.invariant.group535 auto *V = (void *)P;536 537 // CHECK-NEW-LABEL: ret void538}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.barrier547// CHECK-DTORS-LABEL: {{^}}}548 549// CHECK-DTORS-LABEL: define linkonce_odr void @_ZN17DynamicFromStaticD2Ev550// 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 @_ZN12DynamicBase1D2Ev560// CHECK-DTORS: call ptr @llvm.launder.invariant.group.p0(561// CHECK-DTORS-LABEL: {{^}}}562 563// CHECK-DTORS-LABEL: define linkonce_odr void @_ZN14DynamicDerivedD2Ev564// 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