Home | History | Annotate | Download | only in CodeGenCXX
      1 // RUN: %clang_cc1 %s -fno-rtti -triple=i386-pc-win32 -emit-llvm -o %t.ll -fdump-vtable-layouts >%t
      2 // RUN: FileCheck %s < %t
      3 // RUN: FileCheck --check-prefix=MANGLING %s < %t.ll
      4 
      5 namespace test1 {
      6 struct A {
      7   virtual void g();
      8   // Add an extra virtual method so it's easier to check for the absence of thunks.
      9   virtual void h();
     10 };
     11 
     12 struct B {
     13   virtual void g();
     14 };
     15 
     16 // Overrides a method of two bases at the same time, thus needing thunks.
     17 struct C : A, B {
     18   virtual void g();
     19 };
     20 
     21 struct D {
     22   virtual B* foo();
     23   virtual void z();
     24 };
     25 
     26 struct X : D {
     27   // CHECK-LABEL: VFTable for 'test1::D' in 'test1::X' (3 entries).
     28   // CHECK-NEXT:   0 | test1::C *test1::X::foo()
     29   // CHECK-NEXT:       [return adjustment (to type 'struct test1::B *'): 4 non-virtual]
     30   // CHECK-NEXT:   1 | void test1::D::z()
     31   // CHECK-NEXT:   2 | test1::C *test1::X::foo()
     32 
     33   // CHECK-LABEL: Thunks for 'test1::C *test1::X::foo()' (1 entry).
     34   // CHECK-NEXT:   0 | [return adjustment (to type 'struct test1::B *'): 4 non-virtual]
     35 
     36   // CHECK-LABEL: VFTable indices for 'test1::X' (1 entry).
     37   // CHECK-NEXT:   2 | test1::C *test1::X::foo()
     38 
     39   // MANGLING-DAG: @"\01??_7X@test1@@6B@"
     40 
     41   virtual C* foo();
     42 } x;
     43 
     44 void build_vftable(X *obj) { obj->foo(); }
     45 }
     46 
     47 namespace test2 {
     48 struct A {
     49   virtual void g();
     50   virtual void h();
     51 };
     52 
     53 struct B {
     54   virtual void g();
     55 };
     56 
     57 struct C : A, B {
     58   virtual void g();
     59 };
     60 
     61 struct D {
     62   virtual B* foo();
     63   virtual void z();
     64 };
     65 
     66 struct E : D {
     67   virtual C* foo();
     68 };
     69 
     70 struct F : C { };
     71 
     72 struct X : E {
     73   virtual F* foo();
     74   // CHECK-LABEL: VFTable for 'test2::D' in 'test2::E' in 'test2::X' (4 entries).
     75   // CHECK-NEXT:   0 | test2::F *test2::X::foo()
     76   // CHECK-NEXT:       [return adjustment (to type 'struct test2::B *'): 4 non-virtual]
     77   // CHECK-NEXT:   1 | void test2::D::z()
     78   // CHECK-NEXT:   2 | test2::F *test2::X::foo()
     79   // CHECK-NEXT:       [return adjustment (to type 'struct test2::C *'): 0 non-virtual]
     80   // CHECK-NEXT:   3 | test2::F *test2::X::foo()
     81 
     82   // CHECK-LABEL: Thunks for 'test2::F *test2::X::foo()' (2 entries).
     83   // CHECK-NEXT:   0 | [return adjustment (to type 'struct test2::C *'): 0 non-virtual]
     84   // CHECK-NEXT:   1 | [return adjustment (to type 'struct test2::B *'): 4 non-virtual]
     85 
     86   // CHECK-LABEL: VFTable indices for 'test2::X' (1 entry).
     87   // CHECK-NEXT:   3 | test2::F *test2::X::foo()
     88 };
     89 
     90 void build_vftable(X *obj) { obj->foo(); }
     91 }
     92 
     93 namespace test3 {
     94 struct A {
     95   virtual void g();
     96   virtual void h();
     97 };
     98 
     99 struct B {
    100   virtual void g();
    101 };
    102 
    103 struct C : A, B {
    104   virtual void g();
    105 };
    106 
    107 struct D {
    108   virtual B* foo();
    109   virtual void z();
    110 };
    111 
    112 struct E : D {
    113   virtual C* foo();
    114 };
    115 
    116 struct F : A, C { };
    117 
    118 struct X : E {
    119   // CHECK-LABEL: VFTable for 'test3::D' in 'test3::E' in 'test3::X' (4 entries).
    120   // CHECK-NEXT:   0 | test3::F *test3::X::foo()
    121   // CHECK-NEXT:       [return adjustment (to type 'struct test3::B *'): 8 non-virtual]
    122   // CHECK-NEXT:   1 | void test3::D::z()
    123   // CHECK-NEXT:   2 | test3::F *test3::X::foo()
    124   // CHECK-NEXT:       [return adjustment (to type 'struct test3::C *'): 4 non-virtual]
    125   // CHECK-NEXT:   3 | test3::F *test3::X::foo()
    126 
    127   // CHECK-LABEL: Thunks for 'test3::F *test3::X::foo()' (2 entries).
    128   // CHECK-NEXT:   0 | [return adjustment (to type 'struct test3::C *'): 4 non-virtual]
    129   // CHECK-NEXT:   1 | [return adjustment (to type 'struct test3::B *'): 8 non-virtual]
    130 
    131   // CHECK-LABEL: VFTable indices for 'test3::X' (1 entry).
    132   // CHECK-NEXT:   3 | test3::F *test3::X::foo()
    133 
    134   virtual F* foo();
    135 };
    136 
    137 void build_vftable(X *obj) { obj->foo(); }
    138 }
    139 
    140 namespace test4 {
    141 struct A {
    142   virtual void g();
    143   virtual void h();
    144 };
    145 
    146 struct B {
    147   virtual void g();
    148 };
    149 
    150 struct C : A, B {
    151   virtual void g();
    152 };
    153 
    154 struct D {
    155   virtual B* foo();
    156   virtual void z();
    157 };
    158 
    159 struct E : D {
    160   virtual C* foo();
    161 };
    162 
    163 struct F : A, C { };
    164 
    165 struct X : D, E {
    166   // CHECK-LABEL: VFTable for 'test4::D' in 'test4::X' (3 entries).
    167   // CHECK-NEXT:   0 | test4::F *test4::X::foo()
    168   // CHECK-NEXT:       [return adjustment (to type 'struct test4::B *'): 8 non-virtual]
    169   // CHECK-NEXT:   1 | void test4::D::z()
    170   // CHECK-NEXT:   2 | test4::F *test4::X::foo()
    171 
    172   // CHECK-LABEL: Thunks for 'test4::F *test4::X::foo()' (1 entry).
    173   // CHECK-NEXT:   0 | [return adjustment (to type 'struct test4::B *'): 8 non-virtual]
    174 
    175   // CHECK-LABEL: VFTable for 'test4::D' in 'test4::E' in 'test4::X' (4 entries).
    176   // CHECK-NEXT:   0 | test4::F *test4::X::foo()
    177   // CHECK-NEXT:       [return adjustment (to type 'struct test4::B *'): 8 non-virtual]
    178   // CHECK-NEXT:       [this adjustment: -4 non-virtual]
    179   // CHECK-NEXT:   1 | void test4::D::z()
    180   // CHECK-NEXT:   2 | test4::F *test4::X::foo()
    181   // CHECK-NEXT:       [return adjustment (to type 'struct test4::C *'): 4 non-virtual]
    182   // CHECK-NEXT:       [this adjustment: -4 non-virtual]
    183   // CHECK-NEXT:   3 | test4::F *test4::X::foo()
    184   // CHECK-NEXT:       [return adjustment (to type 'struct test4::F *'): 0 non-virtual]
    185   // CHECK-NEXT:       [this adjustment: -4 non-virtual]
    186 
    187   // CHECK-LABEL: Thunks for 'test4::F *test4::X::foo()' (3 entries).
    188   // CHECK-NEXT:   0 | [return adjustment (to type 'struct test4::F *'): 0 non-virtual]
    189   // CHECK-NEXT:       [this adjustment: -4 non-virtual]
    190   // CHECK-NEXT:   1 | [return adjustment (to type 'struct test4::C *'): 4 non-virtual]
    191   // CHECK-NEXT:       [this adjustment: -4 non-virtual]
    192   // CHECK-NEXT:   2 | [return adjustment (to type 'struct test4::B *'): 8 non-virtual]
    193   // CHECK-NEXT:       [this adjustment: -4 non-virtual]
    194 
    195   // CHECK-LABEL: VFTable indices for 'test4::X' (1 entry).
    196   // CHECK-NEXT:   2 | test4::F *test4::X::foo()
    197 
    198   virtual F* foo();
    199 };
    200 
    201 void build_vftable(X *obj) { obj->foo(); }
    202 }
    203 
    204 namespace test5 {
    205 struct A {
    206   virtual void g();
    207   virtual void h();
    208 };
    209 
    210 struct B {
    211   virtual void g();
    212 };
    213 
    214 struct C : A, B {
    215   virtual void g();
    216 };
    217 
    218 struct D {
    219   virtual B* foo();
    220   virtual void z();
    221 };
    222 
    223 struct X : A, D {
    224   // CHECK-LABEL: VFTable for 'test5::A' in 'test5::X' (2 entries).
    225   // CHECK-NEXT:   0 | void test5::A::g()
    226   // CHECK-NEXT:   1 | void test5::A::h()
    227 
    228   // CHECK-LABEL: VFTable for 'test5::D' in 'test5::X' (3 entries).
    229   // CHECK-NEXT:   0 | test5::C *test5::X::foo()
    230   // CHECK-NEXT:       [return adjustment (to type 'struct test5::B *'): 4 non-virtual]
    231   // CHECK-NEXT:   1 | void test5::D::z()
    232   // CHECK-NEXT:   2 | test5::C *test5::X::foo()
    233 
    234   // CHECK-LABEL: Thunks for 'test5::C *test5::X::foo()' (1 entry).
    235   // CHECK-NEXT:   0 | [return adjustment (to type 'struct test5::B *'): 4 non-virtual]
    236 
    237   // CHECK-LABEL: VFTable indices for 'test5::X' (1 entry).
    238   // CHECK-NEXT:   via vfptr at offset 4
    239   // CHECK-NEXT:   2 | test5::C *test5::X::foo()
    240 
    241   virtual C* foo();
    242 };
    243 
    244 void build_vftable(X *obj) { obj->foo(); }
    245 }
    246 
    247 namespace test6 {
    248 struct A {
    249   virtual void g();
    250   virtual void h();
    251 };
    252 
    253 struct B {
    254   virtual void g();
    255 };
    256 
    257 struct C : A, B {
    258   virtual void g();
    259 };
    260 
    261 struct D {
    262   virtual B* foo();
    263   virtual void z();
    264 };
    265 
    266 struct E : A, D {
    267   virtual C* foo();
    268 };
    269 
    270 struct F : A, C { };
    271 
    272 struct X : E {
    273   // CHECK-LABEL: VFTable for 'test6::A' in 'test6::E' in 'test6::X' (2 entries).
    274   // CHECK-NEXT:   0 | void test6::A::g()
    275   // CHECK-NEXT:   1 | void test6::A::h()
    276 
    277   // CHECK-LABEL: VFTable for 'test6::D' in 'test6::E' in 'test6::X' (4 entries).
    278   // CHECK-NEXT:   0 | test6::F *test6::X::foo()
    279   // CHECK-NEXT:       [return adjustment (to type 'struct test6::B *'): 8 non-virtual]
    280   // CHECK-NEXT:   1 | void test6::D::z()
    281   // CHECK-NEXT:   2 | test6::F *test6::X::foo()
    282   // CHECK-NEXT:       [return adjustment (to type 'struct test6::C *'): 4 non-virtual]
    283   // CHECK-NEXT:   3 | test6::F *test6::X::foo()
    284 
    285   // CHECK-LABEL: Thunks for 'test6::F *test6::X::foo()' (2 entries).
    286   // CHECK-NEXT:   0 | [return adjustment (to type 'struct test6::C *'): 4 non-virtual]
    287   // CHECK-NEXT:   1 | [return adjustment (to type 'struct test6::B *'): 8 non-virtual]
    288 
    289   // CHECK-LABEL: VFTable indices for 'test6::X' (1 entry).
    290   // CHECK-NEXT:   -- accessible via vfptr at offset 4 --
    291   // CHECK-NEXT:   3 | test6::F *test6::X::foo()
    292 
    293   virtual F* foo();
    294 };
    295 
    296 void build_vftable(X *obj) { obj->foo(); }
    297 }
    298 
    299 namespace test7 {
    300 struct A {
    301   virtual A *f() = 0;
    302 };
    303 struct B {
    304   virtual void g();
    305 };
    306 struct C : B, A {
    307   virtual void g();
    308   virtual C *f() = 0;
    309   // CHECK-LABEL: VFTable for 'test7::B' in 'test7::C' (1 entry).
    310   // CHECK-NEXT:   0 | void test7::C::g()
    311 
    312   // CHECK-LABEL: VFTable for 'test7::A' in 'test7::C' (2 entries).
    313   // CHECK-NEXT:   0 | test7::C *test7::C::f() [pure]
    314   // CHECK-NEXT:   1 | test7::C *test7::C::f() [pure]
    315 
    316   // No return adjusting thunks needed for pure virtual methods.
    317   // CHECK-NOT: Thunks for 'test7::C *test7::C::f()'
    318 };
    319 
    320 void build_vftable(C *obj) { obj->g(); }
    321 }
    322 
    323 namespace pr20444 {
    324 struct A {
    325   virtual A* f();
    326 };
    327 struct B {
    328   virtual B* f();
    329 };
    330 struct C : A, B {
    331   virtual C* f();
    332   // CHECK-LABEL: VFTable for 'pr20444::A' in 'pr20444::C' (1 entry).
    333   // CHECK-NEXT:   0 | pr20444::C *pr20444::C::f()
    334 
    335   // CHECK-LABEL: VFTable for 'pr20444::B' in 'pr20444::C' (2 entries).
    336   // CHECK-NEXT:   0 | pr20444::C *pr20444::C::f()
    337   // CHECK-NEXT:       [return adjustment (to type 'struct pr20444::B *'): 4 non-virtual]
    338   // CHECK-NEXT:       [this adjustment: -4 non-virtual]
    339   // CHECK-NEXT:   1 | pr20444::C *pr20444::C::f()
    340   // CHECK-NEXT:       [return adjustment (to type 'struct pr20444::C *'): 0 non-virtual]
    341   // CHECK-NEXT:       [this adjustment: -4 non-virtual]
    342 };
    343 
    344 void build_vftable(C *obj) { obj->f(); }
    345 
    346 struct D : C {
    347   virtual D* f();
    348   // CHECK-LABEL: VFTable for 'pr20444::A' in 'pr20444::C' in 'pr20444::D' (1 entry).
    349   // CHECK-NEXT:   0 | pr20444::D *pr20444::D::f()
    350 
    351   // CHECK-LABEL: VFTable for 'pr20444::B' in 'pr20444::C' in 'pr20444::D' (3 entries).
    352   // CHECK-NEXT:   0 | pr20444::D *pr20444::D::f()
    353   // CHECK-NEXT:       [return adjustment (to type 'struct pr20444::B *'): 4 non-virtual]
    354   // CHECK-NEXT:       [this adjustment: -4 non-virtual]
    355   // CHECK-NEXT:   1 | pr20444::D *pr20444::D::f()
    356   // CHECK-NEXT:       [return adjustment (to type 'struct pr20444::C *'): 0 non-virtual]
    357   // CHECK-NEXT:       [this adjustment: -4 non-virtual]
    358   // CHECK-NEXT:   2 | pr20444::D *pr20444::D::f()
    359   // CHECK-NEXT:       [return adjustment (to type 'struct pr20444::D *'): 0 non-virtual]
    360   // CHECK-NEXT:       [this adjustment: -4 non-virtual]
    361 };
    362 
    363 void build_vftable(D *obj) { obj->f(); }
    364 }
    365