1 // RUN: %clang_cc1 -std=c++11 -fms-extensions -fno-rtti -emit-llvm -o %t.ll -fdump-vtable-layouts %s -triple=i386-pc-win32 >%t 2 // RUN: FileCheck %s < %t 3 // RUN: FileCheck --check-prefix=MANGLING %s < %t.ll 4 5 struct Empty { }; 6 7 struct A { 8 virtual void f(); 9 virtual void z(); // Useful to check there are no thunks for f() when appropriate. 10 }; 11 12 struct B { 13 virtual void g(); 14 }; 15 16 struct C: virtual A { 17 // CHECK-LABEL: VFTable for 'A' in 'C' (2 entries) 18 // CHECK-NEXT: 0 | void C::f() 19 // CHECK-NEXT: 1 | void A::z() 20 21 // CHECK-LABEL: VFTable indices for 'C' (1 entry) 22 // CHECK-NEXT: vbtable index 1, vfptr at offset 0 23 // CHECK-NEXT: 0 | void C::f() 24 25 // MANGLING-DAG: @"\01??_7C@@6B@" 26 27 virtual void f() {} 28 }; 29 30 C c; 31 void use(C *obj) { obj->f(); } 32 33 struct D: virtual A { 34 // CHECK-LABEL: VFTable for 'D' (1 entry). 35 // CHECK-NEXT: 0 | void D::h() 36 37 // CHECK-LABEL: VFTable for 'A' in 'D' (2 entries). 38 // CHECK-NEXT: 0 | void D::f() 39 // CHECK-NEXT: 1 | void A::z() 40 41 // CHECK-LABEL: VFTable indices for 'D' (2 entries). 42 // CHECK-NEXT: via vfptr at offset 0 43 // CHECK-NEXT: 0 | void D::h() 44 // CHECK-NEXT: via vbtable index 1, vfptr at offset 0 45 // CHECK-NEXT: 0 | void D::f() 46 47 // MANGLING-DAG: @"\01??_7D@@6B0@@" 48 // MANGLING-DAG: @"\01??_7D@@6BA@@@" 49 50 virtual void f(); 51 virtual void h(); 52 }; 53 54 D d; 55 void use(D *obj) { obj->h(); } 56 57 namespace Test1 { 58 59 struct X { int x; }; 60 61 // X and A get reordered in the layout since X doesn't have a vfptr while A has. 62 struct Y : X, A { }; 63 // MANGLING-DAG: @"\01??_7Y@Test1@@6B@" 64 65 struct Z : virtual Y { 66 Z(); 67 // CHECK-LABEL: VFTable for 'A' in 'Test1::Y' in 'Test1::Z' (2 entries). 68 // CHECK-NEXT: 0 | void A::f() 69 // CHECK-NEXT: 1 | void A::z() 70 71 // CHECK-NOT: VFTable indices for 'Test1::Z' 72 73 // MANGLING-DAG: @"\01??_7Z@Test1@@6B@" 74 }; 75 76 Z::Z() {} 77 } 78 79 namespace Test2 { 80 81 struct X: virtual A, virtual B { 82 // CHECK-LABEL: VFTable for 'Test2::X' (1 entry). 83 // CHECK-NEXT: 0 | void Test2::X::h() 84 85 // CHECK-LABEL: VFTable for 'A' in 'Test2::X' (2 entries). 86 // CHECK-NEXT: 0 | void A::f() 87 // CHECK-NEXT: 1 | void A::z() 88 89 // CHECK-LABEL: VFTable for 'B' in 'Test2::X' (1 entry). 90 // CHECK-NEXT: 0 | void B::g() 91 92 // CHECK-LABEL: VFTable indices for 'Test2::X' (1 entry). 93 // CHECK-NEXT: 0 | void Test2::X::h() 94 95 // MANGLING-DAG: @"\01??_7X@Test2@@6B01@@" 96 // MANGLING-DAG: @"\01??_7X@Test2@@6BA@@@" 97 // MANGLING-DAG: @"\01??_7X@Test2@@6BB@@@" 98 99 virtual void h(); 100 }; 101 102 X x; 103 void use(X *obj) { obj->h(); } 104 } 105 106 namespace Test3 { 107 108 struct X : virtual A { 109 // MANGLING-DAG: @"\01??_7X@Test3@@6B@" 110 }; 111 112 struct Y: virtual X { 113 Y(); 114 // CHECK-LABEL: VFTable for 'A' in 'Test3::X' in 'Test3::Y' (2 entries). 115 // CHECK-NEXT: 0 | void A::f() 116 // CHECK-NEXT: 1 | void A::z() 117 118 // CHECK-NOT: VFTable indices for 'Test3::Y' 119 120 // MANGLING-DAG: @"\01??_7Y@Test3@@6B@" 121 }; 122 123 Y::Y() {} 124 } 125 126 namespace Test4 { 127 128 struct X: virtual C { 129 X(); 130 // This one's interesting. C::f expects (A*) to be passed as 'this' and does 131 // ECX-=4 to cast to (C*). In X, C and A vbases are reordered, so the thunk 132 // should pass a pointer to the end of X in order 133 // for ECX-=4 to point at the C part. 134 135 // CHECK-LABEL: VFTable for 'A' in 'C' in 'Test4::X' (2 entries). 136 // CHECK-NEXT: 0 | void C::f() 137 // CHECK-NEXT: [this adjustment: 8 non-virtual] 138 // CHECK-NEXT: 1 | void A::z() 139 140 // CHECK-LABEL: Thunks for 'void C::f()' (1 entry). 141 // CHECK-NEXT: 0 | [this adjustment: 8 non-virtual] 142 143 // CHECK-NOT: VFTable indices for 'Test4::X' 144 145 // MANGLING-DAG: @"\01??_7X@Test4@@6B@" 146 147 // Also check the mangling of the thunk. 148 // MANGLING-DAG: define linkonce_odr x86_thiscallcc void @"\01?f@C@@WPPPPPPPI@AEXXZ" 149 }; 150 151 X::X() {} 152 } 153 154 namespace Test5 { 155 156 // New methods are added to the base's vftable. 157 struct X : A { 158 // MANGLING-DAG: @"\01??_7X@Test5@@6B@" 159 virtual void g(); 160 }; 161 162 struct Y : virtual X { 163 // CHECK-LABEL: VFTable for 'Test5::Y' (1 entry). 164 // CHECK-NEXT: 0 | void Test5::Y::h() 165 166 // CHECK-LABEL: VFTable for 'A' in 'Test5::X' in 'Test5::Y' (3 entries). 167 // CHECK-NEXT: 0 | void A::f() 168 // CHECK-NEXT: 1 | void A::z() 169 // CHECK-NEXT: 2 | void Test5::X::g() 170 171 // CHECK-LABEL: VFTable indices for 'Test5::Y' (1 entry). 172 // CHECK-NEXT: 0 | void Test5::Y::h() 173 174 // MANGLING-DAG: @"\01??_7Y@Test5@@6B01@@" 175 // MANGLING-DAG: @"\01??_7Y@Test5@@6BX@1@@" 176 177 virtual void h(); 178 }; 179 180 Y y; 181 void use(Y *obj) { obj->h(); } 182 } 183 184 namespace Test6 { 185 186 struct X : A, virtual Empty { 187 X(); 188 // CHECK-LABEL: VFTable for 'A' in 'Test6::X' (2 entries). 189 // CHECK-NEXT: 0 | void A::f() 190 // CHECK-NEXT: 1 | void A::z() 191 192 // CHECK-NOT: VFTable indices for 'Test6::X' 193 194 // MANGLING-DAG: @"\01??_7X@Test6@@6B@" 195 }; 196 197 X::X() {} 198 } 199 200 namespace Test7 { 201 202 struct X : C { 203 // MANGLING-DAG: @"\01??_7X@Test7@@6B@" 204 }; 205 206 struct Y : virtual X { 207 Y(); 208 // CHECK-LABEL: VFTable for 'A' in 'C' in 'Test7::X' in 'Test7::Y' (2 entries). 209 // CHECK-NEXT: 0 | void C::f() 210 // CHECK-NEXT: [this adjustment: 8 non-virtual] 211 // CHECK-NEXT: 1 | void A::z() 212 213 // CHECK-LABEL: Thunks for 'void C::f()' (1 entry). 214 // CHECK-NEXT: 0 | [this adjustment: 8 non-virtual] 215 216 // CHECK-NOT: VFTable indices for 'Test7::Y' 217 218 // MANGLING-DAG: @"\01??_7Y@Test7@@6B@" 219 }; 220 221 Y::Y() {} 222 } 223 224 namespace Test8 { 225 226 // This is a typical diamond inheritance with a shared 'A' vbase. 227 struct X : D, C { 228 // CHECK-LABEL: VFTable for 'D' in 'Test8::X' (1 entry). 229 // CHECK-NEXT: 0 | void D::h() 230 231 // CHECK-LABEL: VFTable for 'A' in 'D' in 'Test8::X' (2 entries). 232 // CHECK-NEXT: 0 | void Test8::X::f() 233 // CHECK-NEXT: 1 | void A::z() 234 235 // CHECK-LABEL: VFTable indices for 'Test8::X' (1 entry). 236 // CHECK-NEXT: via vbtable index 1, vfptr at offset 0 237 // CHECK-NEXT: 0 | void Test8::X::f() 238 239 // MANGLING-DAG: @"\01??_7X@Test8@@6BA@@@" 240 // MANGLING-DAG: @"\01??_7X@Test8@@6BD@@@" 241 242 virtual void f(); 243 }; 244 245 X x; 246 void use(X *obj) { obj->f(); } 247 248 // Another diamond inheritance which led to AST crashes. 249 struct Y : virtual A {}; 250 251 struct Z : Y, C { 252 // CHECK-LABEL: VFTable for 'A' in 'Test8::Y' in 'Test8::Z' (2 entries). 253 // CHECK-NEXT: 0 | void Test8::Z::f() 254 // CHECK-NEXT: 1 | void A::z() 255 256 // CHECK-LABEL: VFTable indices for 'Test8::Z' (1 entry). 257 // CHECK-NEXT: via vbtable index 1, vfptr at offset 0 258 // CHECK-NEXT: 0 | void Test8::Z::f() 259 virtual void f(); 260 }; 261 Z z; 262 void use(Z *obj) { obj->f(); } 263 264 // Another diamond inheritance which we miscompiled (PR18967). 265 struct W : virtual A { 266 virtual void bar(); 267 }; 268 269 struct T : W, C { 270 // CHECK-LABEL: VFTable for 'Test8::W' in 'Test8::T' (1 entry) 271 // CHECK-NEXT: 0 | void Test8::T::bar() 272 273 // CHECK-LABEL: VFTable for 'A' in 'Test8::W' in 'Test8::T' (2 entries) 274 // CHECK-NEXT: 0 | void C::f() 275 // CHECK-NEXT: [this adjustment: -4 non-virtual] 276 // CHECK-NEXT: 1 | void A::z() 277 278 // CHECK-LABEL: Thunks for 'void C::f()' (1 entry). 279 // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual] 280 virtual void bar(); 281 int field; 282 }; 283 T t; 284 void use(T *obj) { obj->bar(); } 285 } 286 287 namespace Test9 { 288 289 struct X : A { }; 290 291 struct Y : virtual X { 292 // CHECK-LABEL: VFTable for 'Test9::Y' (1 entry). 293 // CHECK-NEXT: 0 | void Test9::Y::h() 294 295 // CHECK-LABEL: VFTable for 'A' in 'Test9::X' in 'Test9::Y' (2 entries). 296 // CHECK-NEXT: 0 | void A::f() 297 // CHECK-NEXT: 1 | void A::z() 298 299 // CHECK-LABEL: VFTable indices for 'Test9::Y' (1 entry). 300 // CHECK-NEXT: 0 | void Test9::Y::h() 301 302 // MANGLING-DAG: @"\01??_7Y@Test9@@6B01@@" 303 // MANGLING-DAG: @"\01??_7Y@Test9@@6BX@1@@" 304 305 virtual void h(); 306 }; 307 308 Y y; 309 void use(Y *obj) { obj->h(); } 310 311 struct Z : Y, virtual B { 312 Z(); 313 // CHECK-LABEL: VFTable for 'Test9::Y' in 'Test9::Z' (1 entry). 314 // CHECK-NEXT: 0 | void Test9::Y::h() 315 316 // CHECK-LABEL: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' (2 entries). 317 // CHECK-NEXT: 0 | void A::f() 318 // CHECK-NEXT: 1 | void A::z() 319 320 // CHECK-LABEL: VFTable for 'B' in 'Test9::Z' (1 entry). 321 // CHECK-NEXT: 0 | void B::g() 322 323 // CHECK-NOT: VFTable indices for 'Test9::Z' 324 325 // MANGLING-DAG: @"\01??_7Z@Test9@@6BX@1@@" 326 // MANGLING-DAG: @"\01??_7Z@Test9@@6BY@1@@" 327 328 // MANGLING-DAG: @"\01??_7Z@Test9@@6B@" 329 }; 330 331 Z::Z() {} 332 333 struct W : Z, D, virtual A, virtual B { 334 W(); 335 // CHECK-LABEL: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::W' (1 entry). 336 // CHECK-NEXT: 0 | void Test9::Y::h() 337 338 // CHECK-LABEL: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::W' (2 entries). 339 // CHECK-NEXT: 0 | void A::f() 340 // CHECK-NEXT: 1 | void A::z() 341 342 // CHECK-LABEL: VFTable for 'B' in 'Test9::Z' in 'Test9::W' (1 entry). 343 // CHECK-NEXT: 0 | void B::g() 344 345 // CHECK-LABEL: VFTable for 'D' in 'Test9::W' (1 entry). 346 // CHECK-NEXT: 0 | void D::h() 347 348 // CHECK-LABEL: VFTable for 'A' in 'D' in 'Test9::W' (2 entries). 349 // CHECK-NEXT: 0 | void D::f() 350 // CHECK-NEXT: [this adjustment: -8 non-virtual] 351 // CHECK-NEXT: 1 | void A::z() 352 353 // CHECK-LABEL: Thunks for 'void D::f()' (1 entry). 354 // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual] 355 356 // CHECK-NOT: VFTable indices for 'Test9::W' 357 358 // MANGLING-DAG: @"\01??_7W@Test9@@6BA@@@" 359 // MANGLING-DAG: @"\01??_7W@Test9@@6BD@@@" 360 // MANGLING-DAG: @"\01??_7W@Test9@@6BX@1@@" 361 362 // MANGLING-DAG: @"\01??_7W@Test9@@6B@" 363 // MANGLING-DAG: @"\01??_7W@Test9@@6BY@1@@" 364 }; 365 366 W::W() {} 367 368 struct T : Z, D, virtual A, virtual B { 369 // CHECK-LABEL: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::T' (1 entry). 370 // CHECK-NEXT: 0 | void Test9::T::h() 371 372 // CHECK-LABEL: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::T' (2 entries). 373 // CHECK-NEXT: 0 | void Test9::T::f() 374 // CHECK-NEXT: 1 | void Test9::T::z() 375 376 // CHECK-LABEL: VFTable for 'B' in 'Test9::Z' in 'Test9::T' (1 entry). 377 // CHECK-NEXT: 0 | void Test9::T::g() 378 379 // CHECK-LABEL: VFTable for 'D' in 'Test9::T' (1 entry). 380 // CHECK-NEXT: 0 | void Test9::T::h() 381 // CHECK-NEXT: [this adjustment: -8 non-virtual] 382 383 // CHECK-LABEL: Thunks for 'void Test9::T::h()' (1 entry). 384 // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual] 385 386 // CHECK-LABEL: VFTable for 'A' in 'D' in 'Test9::T' (2 entries). 387 // CHECK-NEXT: 0 | void Test9::T::f() 388 // CHECK-NEXT: [this adjustment: -8 non-virtual] 389 // CHECK-NEXT: 1 | void Test9::T::z() 390 // CHECK-NEXT: [this adjustment: -8 non-virtual] 391 392 // CHECK-LABEL: Thunks for 'void Test9::T::f()' (1 entry). 393 // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual] 394 395 // CHECK-LABEL: Thunks for 'void Test9::T::z()' (1 entry). 396 // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual] 397 398 // CHECK-LABEL: VFTable indices for 'Test9::T' (4 entries). 399 // CHECK-NEXT: via vfptr at offset 0 400 // CHECK-NEXT: 0 | void Test9::T::h() 401 // CHECK-NEXT: via vbtable index 1, vfptr at offset 0 402 // CHECK-NEXT: 0 | void Test9::T::f() 403 // CHECK-NEXT: 1 | void Test9::T::z() 404 // CHECK-NEXT: via vbtable index 2, vfptr at offset 0 405 // CHECK-NEXT: 0 | void Test9::T::g() 406 407 // MANGLING-DAG: @"\01??_7T@Test9@@6BA@@@" 408 // MANGLING-DAG: @"\01??_7T@Test9@@6BD@@@" 409 // MANGLING-DAG: @"\01??_7T@Test9@@6BX@1@@" 410 411 // MANGLING-DAG: @"\01??_7T@Test9@@6B@" 412 // MANGLING-DAG: @"\01??_7T@Test9@@6BY@1@@" 413 414 virtual void f(); 415 virtual void g(); 416 virtual void h(); 417 virtual void z(); 418 }; 419 420 T t; 421 void use(T *obj) { obj->f(); } 422 } 423 424 namespace Test10 { 425 struct X : virtual C, virtual A { 426 // CHECK-LABEL: VFTable for 'A' in 'C' in 'Test10::X' (2 entries). 427 // CHECK-NEXT: 0 | void Test10::X::f() 428 // CHECK-NEXT: 1 | void A::z() 429 430 // CHECK-LABEL: VFTable indices for 'Test10::X' (1 entry). 431 // CHECK-NEXT: via vbtable index 1, vfptr at offset 0 432 // CHECK-NEXT: 0 | void Test10::X::f() 433 virtual void f(); 434 }; 435 436 void X::f() {} 437 X x; 438 void use(X *obj) { obj->f(); } 439 } 440 441 namespace Test11 { 442 struct X : virtual A {}; 443 struct Y { virtual void g(); }; 444 445 struct Z : virtual X, Y { 446 // MANGLING-DAG: @"\01??_7Z@Test11@@6BY@1@@" 447 // MANGLING-DAG: @"\01??_7Z@Test11@@6BX@1@@" 448 }; 449 450 Z z; 451 452 struct W : virtual X, A {}; 453 454 // Used to crash, PR17748. 455 W w; 456 } 457 458 namespace Test12 { 459 struct X : B, A { }; 460 461 struct Y : X { 462 virtual void f(); // Overrides A::f. 463 }; 464 465 struct Z : virtual Y { 466 // CHECK-LABEL: VFTable for 'A' in 'Test12::X' in 'Test12::Y' in 'Test12::Z' (2 entries). 467 // CHECK-NEXT: 0 | void Test12::Y::f() 468 // CHECK-NEXT: 1 | void A::z() 469 470 int z; 471 // MANGLING-DAG: @"\01??_7Z@Test12@@6BA@@@" = {{.*}}@"\01?f@Y@Test12@@UAEXXZ" 472 }; 473 474 struct W : Z { 475 // CHECK-LABEL: VFTable for 'A' in 'Test12::X' in 'Test12::Y' in 'Test12::Z' in 'Test12::W' (2 entries). 476 // CHECK-NEXT: 0 | void Test12::Y::f() 477 // CHECK-NEXT: 1 | void A::z() 478 W(); 479 480 int w; 481 // MANGLING-DAG: @"\01??_7W@Test12@@6BA@@@" = {{.*}}@"\01?f@Y@Test12@@UAEXXZ" 482 }; 483 484 W::W() {} 485 } 486 487 namespace vdtors { 488 struct X { 489 virtual ~X(); 490 virtual void zzz(); 491 }; 492 493 struct Y : virtual X { 494 // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::Y' (2 entries). 495 // CHECK-NEXT: 0 | vdtors::Y::~Y() [scalar deleting] 496 // CHECK-NEXT: 1 | void vdtors::X::zzz() 497 498 // CHECK-NOT: Thunks for 'vdtors::Y::~Y()' 499 virtual ~Y(); 500 }; 501 502 Y y; 503 void use(Y *obj) { delete obj; } 504 505 struct Z { 506 virtual void z(); 507 }; 508 509 struct W : Z, X { 510 // Implicit virtual dtor. 511 }; 512 513 struct U : virtual W { 514 // CHECK-LABEL: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::U' (1 entry). 515 // CHECK-NEXT: 0 | void vdtors::Z::z() 516 517 // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::W' in 'vdtors::U' (2 entries). 518 // CHECK-NEXT: 0 | vdtors::U::~U() [scalar deleting] 519 // CHECK-NEXT: [this adjustment: -4 non-virtual] 520 // CHECK-NEXT: 1 | void vdtors::X::zzz() 521 522 // CHECK-LABEL: Thunks for 'vdtors::U::~U()' (1 entry). 523 // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual] 524 525 // CHECK-LABEL: VFTable indices for 'vdtors::U' (1 entry). 526 // CHECK-NEXT: -- accessible via vbtable index 1, vfptr at offset 4 -- 527 // CHECK-NEXT: 0 | vdtors::U::~U() [scalar deleting] 528 virtual ~U(); 529 }; 530 531 U u; 532 void use(U *obj) { delete obj; } 533 534 struct V : virtual W { 535 // CHECK-LABEL: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::V' (1 entry). 536 // CHECK-NEXT: 0 | void vdtors::Z::z() 537 538 // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::W' in 'vdtors::V' (2 entries). 539 // CHECK-NEXT: 0 | vdtors::V::~V() [scalar deleting] 540 // CHECK-NEXT: [this adjustment: -4 non-virtual] 541 // CHECK-NEXT: 1 | void vdtors::X::zzz() 542 543 // CHECK-LABEL: Thunks for 'vdtors::V::~V()' (1 entry). 544 // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual] 545 546 // CHECK-LABEL: VFTable indices for 'vdtors::V' (1 entry). 547 // CHECK-NEXT: -- accessible via vbtable index 1, vfptr at offset 4 -- 548 // CHECK-NEXT: 0 | vdtors::V::~V() [scalar deleting] 549 }; 550 551 V v; 552 void use(V *obj) { delete obj; } 553 554 struct T : virtual X { 555 virtual ~T(); 556 }; 557 558 struct P : T, Y { 559 // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::T' in 'vdtors::P' (2 entries). 560 // CHECK-NEXT: 0 | vdtors::P::~P() [scalar deleting] 561 // CHECK-NEXT: 1 | void vdtors::X::zzz() 562 563 // CHECK-NOT: Thunks for 'vdtors::P::~P()' 564 virtual ~P(); 565 }; 566 567 P p; 568 void use(P *obj) { delete obj; } 569 570 struct Q { 571 virtual ~Q(); 572 }; 573 574 // PR19172: Yet another diamond we miscompiled. 575 struct R : virtual Q, X { 576 // CHECK-LABEL: VFTable for 'vdtors::Q' in 'vdtors::R' (1 entry). 577 // CHECK-NEXT: 0 | vdtors::R::~R() [scalar deleting] 578 // CHECK-NEXT: [this adjustment: -8 non-virtual] 579 580 // CHECK-LABEL: Thunks for 'vdtors::R::~R()' (1 entry). 581 // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual] 582 583 // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::R' (2 entries). 584 // CHECK-NEXT: 0 | vdtors::R::~R() [scalar deleting] 585 // CHECK-NEXT: 1 | void vdtors::X::zzz() 586 587 // CHECK-LABEL: VFTable indices for 'vdtors::R' (1 entry). 588 // CHECK-NEXT: 0 | vdtors::R::~R() [scalar deleting] 589 virtual ~R(); 590 }; 591 592 R r; 593 void use(R *obj) { delete obj; } 594 } 595 596 namespace return_adjustment { 597 598 struct X : virtual A { 599 virtual void f(); 600 }; 601 602 struct Y : virtual A, virtual X { 603 virtual void f(); 604 }; 605 606 struct Z { 607 virtual A* foo(); 608 }; 609 610 struct W : Z { 611 // CHECK-LABEL: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' (2 entries). 612 // CHECK-NEXT: 0 | return_adjustment::X *return_adjustment::W::foo() 613 // CHECK-NEXT: [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual] 614 // CHECK-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo() 615 616 // CHECK-LABEL: Thunks for 'return_adjustment::X *return_adjustment::W::foo()' (1 entry). 617 // CHECK-NEXT: 0 | [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual] 618 619 // CHECK-LABEL: VFTable indices for 'return_adjustment::W' (1 entry). 620 // CHECK-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo() 621 622 virtual X* foo(); 623 }; 624 625 W w; 626 void use(W *obj) { obj->foo(); } 627 628 struct T : W { 629 // CHECK-LABEL: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' in 'return_adjustment::T' (3 entries). 630 // CHECK-NEXT: 0 | return_adjustment::Y *return_adjustment::T::foo() 631 // CHECK-NEXT: [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual] 632 // CHECK-NEXT: 1 | return_adjustment::Y *return_adjustment::T::foo() 633 // CHECK-NEXT: [return adjustment (to type 'struct return_adjustment::X *'): vbase #2, 0 non-virtual] 634 // CHECK-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo() 635 636 // CHECK-LABEL: Thunks for 'return_adjustment::Y *return_adjustment::T::foo()' (2 entries). 637 // CHECK-NEXT: 0 | [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual] 638 // CHECK-NEXT: 1 | [return adjustment (to type 'struct return_adjustment::X *'): vbase #2, 0 non-virtual] 639 640 // CHECK-LABEL: VFTable indices for 'return_adjustment::T' (1 entry). 641 // CHECK-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo() 642 643 virtual Y* foo(); 644 }; 645 646 T t; 647 void use(T *obj) { obj->foo(); } 648 649 struct U : virtual A { 650 virtual void g(); // adds a vfptr 651 }; 652 653 struct V : Z { 654 // CHECK-LABEL: VFTable for 'return_adjustment::Z' in 'return_adjustment::V' (2 entries). 655 // CHECK-NEXT: 0 | return_adjustment::U *return_adjustment::V::foo() 656 // CHECK-NEXT: [return adjustment (to type 'struct A *'): vbptr at offset 4, vbase #1, 0 non-virtual] 657 // CHECK-NEXT: 1 | return_adjustment::U *return_adjustment::V::foo() 658 659 // CHECK-LABEL: Thunks for 'return_adjustment::U *return_adjustment::V::foo()' (1 entry). 660 // CHECK-NEXT: 0 | [return adjustment (to type 'struct A *'): vbptr at offset 4, vbase #1, 0 non-virtual] 661 662 // CHECK-LABEL: VFTable indices for 'return_adjustment::V' (1 entry). 663 // CHECK-NEXT: 1 | return_adjustment::U *return_adjustment::V::foo() 664 665 virtual U* foo(); 666 }; 667 668 V v; 669 void use(V *obj) { obj->foo(); } 670 } 671 672 namespace pr17748 { 673 struct A { 674 virtual void f() {} 675 }; 676 677 struct B : virtual A { 678 B() {} 679 }; 680 681 struct C : virtual B, A { 682 C() {} 683 }; 684 C c; 685 686 // MANGLING-DAG: @"\01??_7A@pr17748@@6B@" 687 // MANGLING-DAG: @"\01??_7B@pr17748@@6B@" 688 // MANGLING-DAG: @"\01??_7C@pr17748@@6BA@1@@" 689 // MANGLING-DAG: @"\01??_7C@pr17748@@6BB@1@@" 690 } 691 692 namespace pr19066 { 693 struct X : virtual B {}; 694 695 struct Y : virtual X, B { 696 Y(); 697 // CHECK-LABEL: VFTable for 'B' in 'pr19066::X' in 'pr19066::Y' (1 entry). 698 // CHECK-NEXT: 0 | void B::g() 699 700 // CHECK-LABEL: VFTable for 'B' in 'pr19066::Y' (1 entry). 701 // CHECK-NEXT: 0 | void B::g() 702 }; 703 704 Y::Y() {} 705 } 706 707 namespace pr19240 { 708 struct A { 709 virtual void c(); 710 }; 711 712 struct B : virtual A { 713 virtual void c(); 714 }; 715 716 struct C { }; 717 718 struct D : virtual A, virtual C, B {}; 719 720 D obj; 721 722 // Each MDC only has one vftable. 723 724 // MANGLING-DAG: @"\01??_7D@pr19240@@6B@" 725 // MANGLING-DAG: @"\01??_7A@pr19240@@6B@" 726 // MANGLING-DAG: @"\01??_7B@pr19240@@6B@" 727 728 } 729 730 namespace pr19408 { 731 // This test is a non-vtordisp version of the reproducer for PR19408. 732 struct X : virtual A { 733 int x; 734 }; 735 736 struct Y : X { 737 virtual void f(); 738 int y; 739 }; 740 741 struct Z : Y { 742 // CHECK-LABEL: VFTable for 'A' in 'pr19408::X' in 'pr19408::Y' in 'pr19408::Z' (2 entries). 743 // CHECK-NEXT: 0 | void pr19408::Y::f() 744 // CHECK-NEXT: [this adjustment: -4 non-virtual] 745 // CHECK-NEXT: 1 | void A::z() 746 747 Z(); 748 int z; 749 // MANGLING-DAG: @"\01??_7Z@pr19408@@6B@" = {{.*}}@"\01?f@Y@pr19408@@W3AEXXZ" 750 }; 751 752 Z::Z() {} 753 754 struct W : B, Y { 755 // CHECK-LABEL: VFTable for 'A' in 'pr19408::X' in 'pr19408::Y' in 'pr19408::W' (2 entries). 756 // CHECK-NEXT: 0 | void pr19408::Y::f() 757 // CHECK-NEXT: [this adjustment: -4 non-virtual] 758 // CHECK-NEXT: 1 | void A::z() 759 760 W(); 761 int w; 762 // MANGLING-DAG: @"\01??_7W@pr19408@@6BY@1@@" = {{.*}}@"\01?f@Y@pr19408@@W3AEXXZ" 763 }; 764 765 W::W() {} 766 } 767 768 namespace Test13 { 769 struct A { 770 virtual void f(); 771 }; 772 struct __declspec(dllexport) B : virtual A { 773 virtual void f() = 0; 774 // MANGLING-DAG: @"\01??_7B@Test13@@6B@" = weak_odr dllexport unnamed_addr constant [1 x i8*] [i8* bitcast (void ()* @_purecall to i8*)] 775 }; 776 } 777 778 namespace pr21031_1 { 779 // This ordering of base specifiers regressed in r202425. 780 struct A { virtual void f(void); }; 781 struct B : virtual A { virtual void g(void); }; 782 struct C : virtual A, B { C(); }; 783 C::C() {} 784 785 // CHECK-LABEL: VFTable for 'pr21031_1::A' in 'pr21031_1::B' in 'pr21031_1::C' (1 entry) 786 // CHECK-NEXT: 0 | void pr21031_1::A::f() 787 788 // CHECK-LABEL: VFTable for 'pr21031_1::B' in 'pr21031_1::C' (1 entry) 789 // CHECK-NEXT: 0 | void pr21031_1::B::g() 790 791 // MANGLING-DAG: @"\01??_7C@pr21031_1@@6BB@1@@" = {{.*}} constant [1 x i8*] 792 // MANGLING-DAG: @"\01??_7C@pr21031_1@@6B@" = {{.*}} constant [1 x i8*] 793 } 794 795 namespace pr21031_2 { 796 struct A { virtual void f(void); }; 797 struct B : virtual A { virtual void g(void); }; 798 struct C : B, virtual A { C(); }; 799 C::C() {} 800 801 // CHECK-LABEL: VFTable for 'pr21031_2::B' in 'pr21031_2::C' (1 entry) 802 // CHECK-NEXT: 0 | void pr21031_2::B::g() 803 804 // CHECK-LABEL: VFTable for 'pr21031_2::A' in 'pr21031_2::B' in 'pr21031_2::C' (1 entry) 805 // CHECK-NEXT: 0 | void pr21031_2::A::f() 806 807 // MANGLING-DAG: @"\01??_7C@pr21031_2@@6BA@1@@" = {{.*}} constant [1 x i8*] 808 // MANGLING-DAG: @"\01??_7C@pr21031_2@@6BB@1@@" = {{.*}} constant [1 x i8*] 809 } 810 811 namespace pr21062_1 { 812 struct A { virtual void f(); }; 813 struct B {}; 814 struct C : virtual B {}; 815 struct D : virtual C, virtual B, virtual A { D();}; 816 D::D() {} 817 818 // CHECK-LABEL: VFTable for 'pr21062_1::A' in 'pr21062_1::D' (1 entry) 819 // CHECK-NEXT: 0 | void pr21062_1::A::f() 820 821 // MANGLING-DAG: @"\01??_7D@pr21062_1@@6B@" = {{.*}} constant [1 x i8*] 822 } 823 824 namespace pr21062_2 { 825 struct A { virtual void f(); }; 826 struct B {}; 827 struct C : virtual B {}; 828 struct D : C, virtual B, virtual A { D(); }; 829 D::D() {} 830 831 // CHECK-LABEL: VFTable for 'pr21062_2::A' in 'pr21062_2::D' (1 entry) 832 // CHECK-NEXT: 0 | void pr21062_2::A::f() 833 834 // MANGLING-DAG: @"\01??_7D@pr21062_2@@6B@" = {{.*}} constant [1 x i8*] 835 } 836 837 namespace pr21064 { 838 struct A {}; 839 struct B { virtual void f(); }; 840 struct C : virtual A, virtual B {}; 841 struct D : virtual A, virtual C { D(); }; 842 D::D() {} 843 // CHECK-LABEL: VFTable for 'pr21064::B' in 'pr21064::C' in 'pr21064::D' (1 entry) 844 // CHECK-NEXT: 0 | void pr21064::B::f() 845 846 // MANGLING-DAG: @"\01??_7D@pr21064@@6B@" = {{.*}} constant [1 x i8*] 847 } 848