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