brintos

brintos / llvm-project-archived public Read only

0
0
Text · 21.8 KiB · 257ba27 Raw
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