Home | History | Annotate | Download | only in CodeGenCXX
      1 // RUN: %clang_cc1 -fno-rtti -emit-llvm -fdump-vtable-layouts %s -o - -cxx-abi microsoft -triple=i386-pc-win32 >%t 2>&1
      2 
      3 // RUN: FileCheck --check-prefix=VTABLE-C %s < %t
      4 // RUN: FileCheck --check-prefix=VTABLE-D %s < %t
      5 // RUN: FileCheck --check-prefix=TEST1 %s < %t
      6 // RUN: FileCheck --check-prefix=TEST2 %s < %t
      7 // RUN: FileCheck --check-prefix=TEST3 %s < %t
      8 // RUN: FileCheck --check-prefix=TEST4 %s < %t
      9 // RUN: FileCheck --check-prefix=TEST5 %s < %t
     10 // RUN: FileCheck --check-prefix=TEST6 %s < %t
     11 // RUN: FileCheck --check-prefix=TEST7 %s < %t
     12 // RUN: FileCheck --check-prefix=TEST8 %s < %t
     13 // RUN: FileCheck --check-prefix=TEST9-Y %s < %t
     14 // RUN: FileCheck --check-prefix=TEST9-Z %s < %t
     15 // RUN: FileCheck --check-prefix=TEST9-W %s < %t
     16 // RUN: FileCheck --check-prefix=TEST9-T %s < %t
     17 // RUN: FileCheck --check-prefix=TEST10 %s < %t
     18 // RUN: FileCheck --check-prefix=RET-W %s < %t
     19 // RUN: FileCheck --check-prefix=RET-T %s < %t
     20 
     21 struct Empty { };
     22 
     23 struct A {
     24   virtual void f();
     25   virtual void z();  // Useful to check there are no thunks for f() when appropriate.
     26 };
     27 
     28 struct B {
     29   virtual void g();
     30 };
     31 
     32 struct C: virtual A {
     33   // VTABLE-C: VFTable for 'A' in 'C' (2 entries)
     34   // VTABLE-C-NEXT: 0 | void C::f()
     35   // VTABLE-C-NEXT: 1 | void A::z()
     36 
     37   // VTABLE-C: VFTable indices for 'C' (1 entries)
     38   // VTABLE-C-NEXT: vbtable index 1, vfptr at offset 0
     39   // VTABLE-C-NEXT: 0 | void C::f()
     40 
     41   ~C();  // Currently required to have correct record layout, see PR16406
     42   virtual void f();
     43 };
     44 
     45 C c;
     46 
     47 struct D: virtual A {
     48   // VTABLE-D: VFTable for 'D' (1 entries).
     49   // VTABLE-D-NEXT: 0 | void D::h()
     50 
     51   // VTABLE-D: VFTable for 'A' in 'D' (2 entries).
     52   // VTABLE-D-NEXT: 0 | void D::f()
     53   // VTABLE-D-NEXT: 1 | void A::z()
     54 
     55   // VTABLE-D: VFTable indices for 'D' (2 entries).
     56   // VTABLE-D-NEXT: via vfptr at offset 0
     57   // VTABLE-D-NEXT: 0 | void D::h()
     58   // VTABLE-D-NEXT: via vbtable index 1, vfptr at offset 0
     59   // VTABLE-D-NEXT: 0 | void D::f()
     60 
     61   virtual void f();
     62   virtual void h();
     63 };
     64 
     65 void D::h() {}
     66 D d;
     67 
     68 namespace Test1 {
     69 
     70 struct X { int x; };
     71 
     72 // X and A get reordered in the layout since X doesn't have a vfptr while A has.
     73 struct Y : X, A { };
     74 
     75 struct Z : virtual Y {
     76   // TEST1: VFTable for 'A' in 'Test1::Y' in 'Test1::Z' (2 entries).
     77   // TEST1-NEXT: 0 | void A::f()
     78   // TEST1-NEXT: 1 | void A::z()
     79 
     80   // TEST1-NOT: VFTable indices for 'Test1::Z'
     81 };
     82 
     83 Z z;
     84 }
     85 
     86 namespace Test2 {
     87 
     88 struct X: virtual A, virtual B {
     89   // TEST2: VFTable for 'Test2::X' (1 entries).
     90   // TEST2-NEXT: 0 | void Test2::X::h()
     91 
     92   // TEST2: VFTable for 'A' in 'Test2::X' (2 entries).
     93   // TEST2-NEXT: 0 | void A::f()
     94   // TEST2-NEXT: 1 | void A::z()
     95 
     96   // TEST2: VFTable for 'B' in 'Test2::X' (1 entries).
     97   // TEST2-NEXT: 0 | void B::g()
     98 
     99   // TEST2: VFTable indices for 'Test2::X' (1 entries).
    100   // TEST2-NEXT: 0 | void Test2::X::h()
    101 
    102   virtual void h();
    103 };
    104 
    105 X x;
    106 }
    107 
    108 namespace Test3 {
    109 
    110 struct X : virtual A { };
    111 
    112 struct Y: virtual X {
    113   // TEST3: VFTable for 'A' in 'Test3::X' in 'Test3::Y' (2 entries).
    114   // TEST3-NEXT: 0 | void A::f()
    115   // TEST3-NEXT: 1 | void A::z()
    116 
    117   // TEST3-NOT: VFTable indices for 'Test3::Y'
    118 };
    119 
    120 Y y;
    121 }
    122 
    123 namespace Test4 {
    124 
    125 struct X: virtual C {
    126   // This one's interesting. C::f expects (A*) to be passed as 'this' and does
    127   // ECX-=4 to cast to (C*). In X, C and A vbases are reordered, so the thunk
    128   // should pass a pointer to the end of X in order
    129   // for ECX-=4 to point at the C part.
    130 
    131   // TEST4: VFTable for 'A' in 'C' in 'Test4::X' (2 entries).
    132   // TEST4-NEXT: 0 | void C::f()
    133   // TEST4-NEXT: [this adjustment: 12 non-virtual]
    134   // TEST4-NEXT: 1 | void A::z()
    135 
    136   // TEST4-NOT: VFTable indices for 'Test4::X'
    137 };
    138 
    139 X x;
    140 }
    141 
    142 namespace Test5 {
    143 
    144 // New methods are added to the base's vftable.
    145 struct X : A {
    146   virtual void g();
    147 };
    148 
    149 struct Y : virtual X {
    150   // TEST5: VFTable for 'Test5::Y' (1 entries).
    151   // TEST5-NEXT: 0 | void Test5::Y::h()
    152 
    153   // TEST5: VFTable for 'A' in 'Test5::X' in 'Test5::Y' (3 entries).
    154   // TEST5-NEXT: 0 | void A::f()
    155   // TEST5-NEXT: 1 | void A::z()
    156   // TEST5-NEXT: 2 | void Test5::X::g()
    157 
    158   // TEST5: VFTable indices for 'Test5::Y' (1 entries).
    159   // TEST5-NEXT: 0 | void Test5::Y::h()
    160 
    161   virtual void h();
    162 };
    163 
    164 Y y;
    165 }
    166 
    167 namespace Test6 {
    168 
    169 struct X : A, virtual Empty {
    170   // TEST6: VFTable for 'A' in 'Test6::X' (2 entries).
    171   // TEST6-NEXT: 0 | void A::f()
    172   // TEST6-NEXT: 1 | void A::z()
    173 
    174   // TEST6-NOT: VFTable indices for 'Test6::X'
    175 };
    176 
    177 X x;
    178 }
    179 
    180 namespace Test7 {
    181 
    182 struct X : C { };
    183 
    184 struct Y : virtual X {
    185   // TEST7: VFTable for 'A' in 'C' in 'Test7::X' in 'Test7::Y' (2 entries).
    186   // TEST7-NEXT: 0 | void C::f()
    187   // TEST7-NEXT:     [this adjustment: 12 non-virtual]
    188   // TEST7-NEXT: 1 | void A::z()
    189 
    190   // TEST7: Thunks for 'void C::f()' (1 entry).
    191   // TEST7-NEXT: 0 | this adjustment: 12 non-virtual
    192 
    193   // TEST7-NOT: VFTable indices for 'Test7::Y'
    194 };
    195 
    196 Y y;
    197 }
    198 
    199 namespace Test8 {
    200 
    201 // This is a typical diamond inheritance with a shared 'A' vbase.
    202 struct X : D, C {
    203   // TEST8: VFTable for 'D' in 'Test8::X' (1 entries).
    204   // TEST8-NEXT: 0 | void D::h()
    205 
    206   // TEST8: VFTable for 'A' in 'D' in 'Test8::X' (2 entries).
    207   // TEST8-NEXT: 0 | void Test8::X::f()
    208   // TEST8-NEXT: 1 | void A::z()
    209 
    210   // TEST8: VFTable indices for 'Test8::X' (1 entries).
    211   // TEST8-NEXT: via vbtable index 1, vfptr at offset 0
    212 
    213   virtual void f();
    214 };
    215 
    216 X x;
    217 }
    218 
    219 namespace Test9 {
    220 
    221 struct X : A { };
    222 
    223 struct Y : virtual X {
    224   // TEST9-Y: VFTable for 'Test9::Y' (1 entries).
    225   // TEST9-Y-NEXT: 0 | void Test9::Y::h()
    226 
    227   // TEST9-Y: VFTable for 'A' in 'Test9::X' in 'Test9::Y' (2 entries).
    228   // TEST9-Y-NEXT: 0 | void A::f()
    229   // TEST9-Y-NEXT: 1 | void A::z()
    230 
    231   // TEST9-Y: VFTable indices for 'Test9::Y' (1 entries).
    232   // TEST9-Y-NEXT: 0 | void Test9::Y::h()
    233 
    234   virtual void h();
    235 };
    236 
    237 Y y;
    238 
    239 struct Z : Y, virtual B {
    240   // TEST9-Z: VFTable for 'Test9::Y' in 'Test9::Z' (1 entries).
    241   // TEST9-Z-NEXT: 0 | void Test9::Y::h()
    242 
    243   // TEST9-Z: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' (2 entries).
    244   // TEST9-Z-NEXT: 0 | void A::f()
    245   // TEST9-Z-NEXT: 1 | void A::z()
    246 
    247   // TEST9-Z: VFTable for 'B' in 'Test9::Z' (1 entries).
    248   // TEST9-Z-NEXT: 0 | void B::g()
    249 
    250   // TEST9-Z-NOT: VFTable indices for 'Test9::Z'
    251 };
    252 
    253 Z z;
    254 
    255 struct W : Z, D, virtual A, virtual B {
    256   // TEST9-W: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::W' (1 entries).
    257   // TEST9-W-NEXT: 0 | void Test9::Y::h()
    258 
    259   // TEST9-W: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::W' (2 entries).
    260   // TEST9-W-NEXT: 0 | void A::f()
    261   // TEST9-W-NEXT: 1 | void A::z()
    262 
    263   // TEST9-W: VFTable for 'B' in 'Test9::Z' in 'Test9::W' (1 entries).
    264   // TEST9-W-NEXT: 0 | void B::g()
    265 
    266   // TEST9-W: VFTable for 'D' in 'Test9::W' (1 entries).
    267   // TEST9-W-NEXT: 0 | void D::h()
    268 
    269   // TEST9-W: VFTable for 'A' in 'D' in 'Test9::W' (2 entries).
    270   // TEST9-W-NEXT: 0 | void D::f()
    271   // TEST9-W-NEXT:     [this adjustment: -8 non-virtual]
    272   // TEST9-W-NEXT: 1 | void A::z()
    273 
    274   // TEST9-W: Thunks for 'void D::f()' (1 entry).
    275   // TEST9-W-NEXT: 0 | this adjustment: -8 non-virtual
    276 
    277   // TEST9-W-NOT: VFTable indices for 'Test9::W'
    278 };
    279 
    280 W w;
    281 
    282 struct T : Z, D, virtual A, virtual B {
    283   ~T();  // Currently required to have correct record layout, see PR16406
    284 
    285   // TEST9-T: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::T' (1 entries).
    286   // TEST9-T-NEXT: 0 | void Test9::T::h()
    287 
    288   // TEST9-T: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::T' (2 entries).
    289   // TEST9-T-NEXT: 0 | void Test9::T::f()
    290   // TEST9-T-NEXT: 1 | void Test9::T::z()
    291 
    292   // TEST9-T: VFTable for 'B' in 'Test9::Z' in 'Test9::T' (1 entries).
    293   // TEST9-T-NEXT: 0 | void Test9::T::g()
    294 
    295   // TEST9-T: VFTable for 'D' in 'Test9::T' (1 entries).
    296   // TEST9-T-NEXT: 0 | void Test9::T::h()
    297   // TEST9-T-NEXT:     [this adjustment: -8 non-virtual]
    298 
    299   // TEST9-T: Thunks for 'void Test9::T::h()' (1 entry).
    300   // TEST9-T-NEXT: 0 | this adjustment: -8 non-virtual
    301 
    302   // TEST9-T: VFTable for 'A' in 'D' in 'Test9::T' (2 entries).
    303   // TEST9-T-NEXT: 0 | void Test9::T::f()
    304   // TEST9-T-NEXT:     [this adjustment: -16 non-virtual]
    305   // TEST9-T-NEXT: 1 | void Test9::T::z()
    306   // TEST9-T-NEXT:     [this adjustment: -16 non-virtual]
    307 
    308   // TEST9-T: Thunks for 'void Test9::T::f()' (1 entry).
    309   // TEST9-T-NEXT: 0 | this adjustment: -16 non-virtual
    310 
    311   // TEST9-T: Thunks for 'void Test9::T::z()' (1 entry).
    312   // TEST9-T-NEXT: 0 | this adjustment: -16 non-virtual
    313 
    314   // TEST9-T: VFTable indices for 'Test9::T' (4 entries).
    315   // TEST9-T-NEXT: via vfptr at offset 0
    316   // TEST9-T-NEXT: 0 | void Test9::T::h()
    317   // TEST9-T-NEXT: via vbtable index 1, vfptr at offset 0
    318   // TEST9-T-NEXT: 0 | void Test9::T::f()
    319   // TEST9-T-NEXT: 1 | void Test9::T::z()
    320   // TEST9-T-NEXT: via vbtable index 2, vfptr at offset 0
    321   // TEST9-T-NEXT: 0 | void Test9::T::g()
    322 
    323   virtual void f();
    324   virtual void g();
    325   virtual void h();
    326   virtual void z();
    327 };
    328 
    329 T t;
    330 }
    331 
    332 namespace Test10 {
    333 struct X : virtual C, virtual A {
    334   // TEST10: VFTable for 'A' in 'C' in 'Test10::X' (2 entries).
    335   // TEST10-NEXT: 0 | void Test10::X::f()
    336   // TEST10-NEXT: 1 | void A::z()
    337 
    338   // TEST10: VFTable indices for 'Test10::X' (1 entries).
    339   // TEST10-NEXT: via vbtable index 1, vfptr at offset 0
    340   // TEST10-NEXT: 0 | void Test10::X::f()
    341   virtual void f();
    342 };
    343 
    344 void X::f() {}
    345 X x;
    346 }
    347 
    348 namespace return_adjustment {
    349 
    350 struct X : virtual A {
    351   virtual void f();
    352 };
    353 
    354 struct Y : virtual A, virtual X {
    355   virtual void f();
    356 };
    357 
    358 struct Z {
    359   virtual A* foo();
    360 };
    361 
    362 struct W : Z {
    363   // RET-W: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' (2 entries).
    364   // RET-W-NEXT: 0 | return_adjustment::X *return_adjustment::W::foo()
    365   // RET-W-NEXT:     [return adjustment: vbase #1, 0 non-virtual]
    366   // RET-W-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo()
    367 
    368   // RET-W: VFTable indices for 'return_adjustment::W' (1 entries).
    369   // RET-W-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo()
    370 
    371   virtual X* foo();
    372 };
    373 
    374 W y;
    375 
    376 struct T : W {
    377   // RET-T: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' in 'return_adjustment::T' (3 entries).
    378   // RET-T-NEXT: 0 | return_adjustment::Y *return_adjustment::T::foo()
    379   // RET-T-NEXT:     [return adjustment: vbase #1, 0 non-virtual]
    380   // RET-T-NEXT: 1 | return_adjustment::Y *return_adjustment::T::foo()
    381   // RET-T-NEXT:     [return adjustment: vbase #2, 0 non-virtual]
    382   // RET-T-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo()
    383 
    384   // RET-T: VFTable indices for 'return_adjustment::T' (1 entries).
    385   // RET-T-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo()
    386 
    387   virtual Y* foo();
    388 };
    389 
    390 T t;
    391 }
    392