Home | History | Annotate | Download | only in CodeGenCXX
      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