848 lines · cpp
1// RUN: %clang_cc1 -std=c++11 -fms-extensions -fno-rtti -emit-llvm -o %t.ll -fdump-vtable-layouts %s -triple=i386-pc-win32 >%t2// RUN: FileCheck %s < %t3// RUN: FileCheck --check-prefix=MANGLING %s < %t.ll4 5struct Empty { };6 7struct A {8 virtual void f();9 virtual void z(); // Useful to check there are no thunks for f() when appropriate.10};11 12struct B {13 virtual void g();14};15 16struct 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 023 // CHECK-NEXT: 0 | void C::f()24 25 // MANGLING-DAG: @"??_7C@@6B@"26 27 virtual void f() {}28};29 30C c;31void use(C *obj) { obj->f(); }32 33struct 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 043 // CHECK-NEXT: 0 | void D::h()44 // CHECK-NEXT: via vbtable index 1, vfptr at offset 045 // CHECK-NEXT: 0 | void D::f()46 47 // MANGLING-DAG: @"??_7D@@6B0@@"48 // MANGLING-DAG: @"??_7D@@6BA@@@"49 50 virtual void f();51 virtual void h();52};53 54D d;55void use(D *obj) { obj->h(); }56 57namespace Test1 {58 59struct X { int x; };60 61// X and A get reordered in the layout since X doesn't have a vfptr while A has.62struct Y : X, A { };63// MANGLING-DAG: @"??_7Y@Test1@@6B@"64 65struct 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: @"??_7Z@Test1@@6B@"74};75 76Z::Z() {}77}78 79namespace Test2 {80 81struct 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: @"??_7X@Test2@@6B01@@"96 // MANGLING-DAG: @"??_7X@Test2@@6BA@@@"97 // MANGLING-DAG: @"??_7X@Test2@@6BB@@@"98 99 virtual void h();100};101 102X x;103void use(X *obj) { obj->h(); }104}105 106namespace Test3 {107 108struct X : virtual A {109 // MANGLING-DAG: @"??_7X@Test3@@6B@"110};111 112struct 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: @"??_7Y@Test3@@6B@"121};122 123Y::Y() {}124}125 126namespace Test4 {127 128struct X: virtual C {129 X();130 // This one's interesting. C::f expects (A*) to be passed as 'this' and does131 // ECX-=4 to cast to (C*). In X, C and A vbases are reordered, so the thunk132 // should pass a pointer to the end of X in order133 // 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: @"??_7X@Test4@@6B@"146 147 // Also check the mangling of the thunk.148 // MANGLING-DAG: define linkonce_odr dso_local x86_thiscallcc void @"?f@C@@WPPPPPPPI@AEXXZ"149};150 151X::X() {}152}153 154namespace Test5 {155 156// New methods are added to the base's vftable.157struct X : A {158 // MANGLING-DAG: @"??_7X@Test5@@6B@"159 virtual void g();160};161 162struct 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: @"??_7Y@Test5@@6B01@@"175 // MANGLING-DAG: @"??_7Y@Test5@@6BX@1@@"176 177 virtual void h();178};179 180Y y;181void use(Y *obj) { obj->h(); }182}183 184namespace Test6 {185 186struct 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: @"??_7X@Test6@@6B@"195};196 197X::X() {}198}199 200namespace Test7 {201 202struct X : C {203 // MANGLING-DAG: @"??_7X@Test7@@6B@"204};205 206struct 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: @"??_7Y@Test7@@6B@"219};220 221Y::Y() {}222}223 224namespace Test8 {225 226// This is a typical diamond inheritance with a shared 'A' vbase.227struct 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 0237 // CHECK-NEXT: 0 | void Test8::X::f()238 239 // MANGLING-DAG: @"??_7X@Test8@@6BA@@@"240 // MANGLING-DAG: @"??_7X@Test8@@6BD@@@"241 242 virtual void f();243};244 245X x;246void use(X *obj) { obj->f(); }247 248// Another diamond inheritance which led to AST crashes.249struct Y : virtual A {};250 251struct 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 0258 // CHECK-NEXT: 0 | void Test8::Z::f()259 virtual void f();260};261Z z;262void use(Z *obj) { obj->f(); }263 264// Another diamond inheritance which we miscompiled (PR18967).265struct W : virtual A {266 virtual void bar();267};268 269struct 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};283T t;284void use(T *obj) { obj->bar(); }285}286 287namespace Test9 {288 289struct X : A { };290 291struct 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: @"??_7Y@Test9@@6B01@@"303 // MANGLING-DAG: @"??_7Y@Test9@@6BX@1@@"304 305 virtual void h();306};307 308Y y;309void use(Y *obj) { obj->h(); }310 311struct 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: @"??_7Z@Test9@@6BX@1@@"326 // MANGLING-DAG: @"??_7Z@Test9@@6BY@1@@"327 328 // MANGLING-DAG: @"??_7Z@Test9@@6B@"329};330 331Z::Z() {}332 333struct 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: @"??_7W@Test9@@6BA@@@"359 // MANGLING-DAG: @"??_7W@Test9@@6BD@@@"360 // MANGLING-DAG: @"??_7W@Test9@@6BX@1@@"361 362 // MANGLING-DAG: @"??_7W@Test9@@6B@"363 // MANGLING-DAG: @"??_7W@Test9@@6BY@1@@"364};365 366W::W() {}367 368struct 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 0400 // CHECK-NEXT: 0 | void Test9::T::h()401 // CHECK-NEXT: via vbtable index 1, vfptr at offset 0402 // 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 0405 // CHECK-NEXT: 0 | void Test9::T::g()406 407 // MANGLING-DAG: @"??_7T@Test9@@6BA@@@"408 // MANGLING-DAG: @"??_7T@Test9@@6BD@@@"409 // MANGLING-DAG: @"??_7T@Test9@@6BX@1@@"410 411 // MANGLING-DAG: @"??_7T@Test9@@6B@"412 // MANGLING-DAG: @"??_7T@Test9@@6BY@1@@"413 414 virtual void f();415 virtual void g();416 virtual void h();417 virtual void z();418};419 420T t;421void use(T *obj) { obj->f(); }422}423 424namespace Test10 {425struct 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 0432 // CHECK-NEXT: 0 | void Test10::X::f()433 virtual void f();434};435 436void X::f() {}437X x;438void use(X *obj) { obj->f(); }439}440 441namespace Test11 {442struct X : virtual A {};443struct Y { virtual void g(); };444 445struct Z : virtual X, Y {446 // MANGLING-DAG: @"??_7Z@Test11@@6BY@1@@"447 // MANGLING-DAG: @"??_7Z@Test11@@6BX@1@@"448};449 450Z z;451 452struct W : virtual X, A {};453 454// Used to crash, PR17748.455W w;456}457 458namespace Test12 {459struct X : B, A { };460 461struct Y : X {462 virtual void f(); // Overrides A::f.463};464 465struct 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: @"??_7Z@Test12@@6BA@@@" = {{.*}}@"?f@Y@Test12@@UAEXXZ"472};473 474struct 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: @"??_7W@Test12@@6BA@@@" = {{.*}}@"?f@Y@Test12@@UAEXXZ"482};483 484W::W() {}485}486 487namespace vdtors {488struct X {489 virtual ~X();490 virtual void zzz();491};492 493struct 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 502Y y;503void use(Y *obj) { delete obj; }504 505struct Z {506 virtual void z();507};508 509struct W : Z, X {510 // Implicit virtual dtor.511};512 513struct 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 531U u;532void use(U *obj) { delete obj; }533 534struct 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 551V v;552void use(V *obj) { delete obj; }553 554struct T : virtual X {555 virtual ~T();556};557 558struct 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 567P p;568void use(P *obj) { delete obj; }569 570struct Q {571 virtual ~Q();572};573 574// PR19172: Yet another diamond we miscompiled.575struct 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 592R r;593void use(R *obj) { delete obj; }594}595 596namespace return_adjustment {597 598struct X : virtual A {599 virtual void f();600};601 602struct Y : virtual A, virtual X {603 virtual void f();604};605 606struct Z {607 virtual A* foo();608};609 610struct W : Z {611 // CHECK-LABEL: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' (2 entries).612 // CHECK-NEXT: 0 | X *return_adjustment::W::foo()613 // CHECK-NEXT: [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual]614 // CHECK-NEXT: 1 | X *return_adjustment::W::foo()615 616 // CHECK-LABEL: Thunks for '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 | X *return_adjustment::W::foo()621 622 virtual X* foo();623};624 625W w;626void use(W *obj) { obj->foo(); }627 628struct T : W {629 // CHECK-LABEL: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' in 'return_adjustment::T' (3 entries).630 // CHECK-NEXT: 0 | Y *return_adjustment::T::foo()631 // CHECK-NEXT: [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual]632 // CHECK-NEXT: 1 | 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 | Y *return_adjustment::T::foo()635 636 // CHECK-LABEL: Thunks for '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 | Y *return_adjustment::T::foo()642 643 virtual Y* foo();644};645 646T t;647void use(T *obj) { obj->foo(); }648 649struct U : virtual A {650 virtual void g(); // adds a vfptr651};652 653struct V : Z {654 // CHECK-LABEL: VFTable for 'return_adjustment::Z' in 'return_adjustment::V' (2 entries).655 // CHECK-NEXT: 0 | 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 | U *return_adjustment::V::foo()658 659 // CHECK-LABEL: Thunks for '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 | U *return_adjustment::V::foo()664 665 virtual U* foo();666};667 668V v;669void use(V *obj) { obj->foo(); }670}671 672namespace pr17748 {673struct A {674 virtual void f() {}675};676 677struct B : virtual A {678 B() {}679};680 681struct C : virtual B, A {682 C() {}683};684C c;685 686// MANGLING-DAG: @"??_7A@pr17748@@6B@"687// MANGLING-DAG: @"??_7B@pr17748@@6B@"688// MANGLING-DAG: @"??_7C@pr17748@@6BA@1@@"689// MANGLING-DAG: @"??_7C@pr17748@@6BB@1@@"690}691 692namespace pr19066 {693struct X : virtual B {};694 695struct 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 704Y::Y() {}705}706 707namespace pr19240 {708struct A {709 virtual void c();710};711 712struct B : virtual A {713 virtual void c();714};715 716struct C { };717 718struct D : virtual A, virtual C, B {};719 720D obj;721 722// Each MDC only has one vftable.723 724// MANGLING-DAG: @"??_7D@pr19240@@6B@"725// MANGLING-DAG: @"??_7A@pr19240@@6B@"726// MANGLING-DAG: @"??_7B@pr19240@@6B@"727 728}729 730namespace pr19408 {731// This test is a non-vtordisp version of the reproducer for PR19408.732struct X : virtual A {733 int x;734};735 736struct Y : X {737 virtual void f();738 int y;739};740 741struct 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: @"??_7Z@pr19408@@6B@" = {{.*}}@"?f@Y@pr19408@@W3AEXXZ"750};751 752Z::Z() {}753 754struct 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: @"??_7W@pr19408@@6BY@1@@" = {{.*}}@"?f@Y@pr19408@@W3AEXXZ"763};764 765W::W() {}766}767 768namespace Test13 {769struct A {770 virtual void f();771};772struct __declspec(dllexport) B : virtual A {773 virtual void f() = 0;774 // MANGLING-DAG: @"??_7B@Test13@@6B@" = weak_odr dllexport unnamed_addr constant { [1 x ptr] } { [1 x ptr] [ptr @_purecall] }775};776}777 778namespace pr21031_1 {779// This ordering of base specifiers regressed in r202425.780struct A { virtual void f(void); };781struct B : virtual A { virtual void g(void); };782struct C : virtual A, B { C(); };783C::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: @"??_7C@pr21031_1@@6BB@1@@" = {{.*}} constant { [1 x ptr] }792// MANGLING-DAG: @"??_7C@pr21031_1@@6B@" = {{.*}} constant { [1 x ptr] }793}794 795namespace pr21031_2 {796struct A { virtual void f(void); };797struct B : virtual A { virtual void g(void); };798struct C : B, virtual A { C(); };799C::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: @"??_7C@pr21031_2@@6BA@1@@" = {{.*}} constant { [1 x ptr] }808// MANGLING-DAG: @"??_7C@pr21031_2@@6BB@1@@" = {{.*}} constant { [1 x ptr] }809}810 811namespace pr21062_1 {812struct A { virtual void f(); };813struct B {};814struct C : virtual B {};815struct D : virtual C, virtual B, virtual A { D();};816D::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: @"??_7D@pr21062_1@@6B@" = {{.*}} constant { [1 x ptr] }822}823 824namespace pr21062_2 {825struct A { virtual void f(); };826struct B {};827struct C : virtual B {};828struct D : C, virtual B, virtual A { D(); };829D::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: @"??_7D@pr21062_2@@6B@" = {{.*}} constant { [1 x ptr] }835}836 837namespace pr21064 {838struct A {};839struct B { virtual void f(); };840struct C : virtual A, virtual B {};841struct D : virtual A, virtual C { D(); };842D::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: @"??_7D@pr21064@@6B@" = {{.*}} constant { [1 x ptr] }847}848