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 f();
      8 };
      9 
     10 struct B {
     11   virtual void g();
     12   // Add an extra virtual method so it's easier to check for the absence of thunks.
     13   virtual void h();
     14 };
     15 
     16 struct X : A, B {
     17   // CHECK-LABEL: VFTable for 'test1::A' in 'test1::X' (1 entry)
     18   // CHECK-NEXT:   0 | void test1::X::f()
     19 
     20   // CHECK-LABEL: VFTable for 'test1::B' in 'test1::X' (2 entries)
     21   // CHECK-NEXT:   0 | void test1::B::g()
     22   // CHECK-NEXT:   1 | void test1::B::h()
     23 
     24   // CHECK-LABEL: VFTable indices for 'test1::X' (1 entry)
     25   // CHECK-NEXT:   0 | void test1::X::f()
     26 
     27   // MANGLING-DAG: @"\01??_7X@test1@@6BA@1@@"
     28   // MANGLING-DAG: @"\01??_7X@test1@@6BB@1@@"
     29 
     30   // Overrides only the left child's method (A::f), needs no thunks.
     31   virtual void f();
     32 } x;
     33 
     34 void build_vftable(X *obj) { obj->f(); }
     35 }
     36 
     37 namespace test2 {
     38 struct A {
     39   virtual void f();
     40 };
     41 
     42 struct B {
     43   virtual void g();
     44   virtual void h();
     45 };
     46 
     47 struct X : A, B {
     48   // CHECK-LABEL: VFTable for 'test2::A' in 'test2::X' (1 entry)
     49   // CHECK-NEXT:   0 | void test2::A::f()
     50 
     51   // CHECK-LABEL: VFTable for 'test2::B' in 'test2::X' (2 entries)
     52   // CHECK-NEXT:   0 | void test2::X::g()
     53   // CHECK-NEXT:   1 | void test2::B::h()
     54 
     55   // CHECK-LABEL: VFTable indices for 'test2::X' (1 entry).
     56   // CHECK-NEXT:   via vfptr at offset 4
     57   // CHECK-NEXT:   0 | void test2::X::g()
     58 
     59   // Overrides only the right child's method (B::g), needs this adjustment but
     60   // not thunks.
     61   virtual void g();
     62 };
     63 
     64 void build_vftable(X *obj) { obj->g(); }
     65 }
     66 
     67 namespace test3 {
     68 struct A {
     69   virtual void f();
     70 };
     71 
     72 struct B {
     73   virtual void g();
     74   virtual void h();
     75 };
     76 
     77 struct X : A, B {
     78   // CHECK-LABEL: VFTable for 'test3::A' in 'test3::X' (2 entries)
     79   // CHECK-NEXT:   0 | void test3::A::f()
     80   // CHECK-NEXT:   1 | void test3::X::i()
     81 
     82   // CHECK-LABEL: VFTable for 'test3::B' in 'test3::X' (2 entries)
     83   // CHECK-NEXT:   0 | void test3::B::g()
     84   // CHECK-NEXT:   1 | void test3::B::h()
     85 
     86   // CHECK-LABEL: VFTable indices for 'test3::X' (1 entry).
     87   // CHECK-NEXT:   1 | void test3::X::i()
     88 
     89   // Only adds a new method.
     90   virtual void i();
     91 };
     92 
     93 void build_vftable(X *obj) { obj->i(); }
     94 }
     95 
     96 namespace test4 {
     97 struct A {
     98   virtual void f();
     99 };
    100 
    101 struct Empty { };  // Doesn't have a vftable!
    102 
    103 // Only the right base has a vftable, so it's laid out before the left one!
    104 struct X : Empty, A {
    105   // CHECK-LABEL: VFTable for 'test4::A' in 'test4::X' (1 entry)
    106   // CHECK-NEXT:   0 | void test4::X::f()
    107 
    108   // CHECK-LABEL: VFTable indices for 'test4::X' (1 entry).
    109   // CHECK-NEXT:   0 | void test4::X::f()
    110 
    111   // MANGLING-DAG: @"\01??_7X@test4@@6B@"
    112 
    113   virtual void f();
    114 } x;
    115 
    116 void build_vftable(X *obj) { obj->f(); }
    117 }
    118 
    119 namespace test5 {
    120 struct A {
    121   virtual void f();
    122 };
    123 
    124 struct B {
    125   virtual void g();
    126   virtual void h();
    127 };
    128 
    129 struct C : A, B {
    130   virtual void f();
    131 };
    132 
    133 struct X : C {
    134   // CHECK-LABEL: VFTable for 'test5::A' in 'test5::C' in 'test5::X' (1 entry).
    135   // CHECK-NEXT:   0 | void test5::X::f()
    136 
    137   // CHECK-LABEL: VFTable for 'test5::B' in 'test5::C' in 'test5::X' (2 entries).
    138   // CHECK-NEXT:   0 | void test5::B::g()
    139   // CHECK-NEXT:   1 | void test5::B::h()
    140 
    141   // CHECK-LABEL: VFTable indices for 'test5::X' (1 entry).
    142   // CHECK-NEXT:   0 | void test5::X::f()
    143 
    144   // MANGLING-DAG: @"\01??_7X@test5@@6BA@1@@"
    145   // MANGLING-DAG: @"\01??_7X@test5@@6BB@1@@"
    146 
    147   // Overrides both C::f and A::f.
    148   virtual void f();
    149 } x;
    150 
    151 void build_vftable(X *obj) { obj->f(); }
    152 }
    153 
    154 namespace test6 {
    155 struct A {
    156   virtual void f();
    157 };
    158 
    159 struct B {
    160   virtual void g();
    161   virtual void h();
    162 };
    163 
    164 struct C : A, B {
    165   virtual void g();
    166 };
    167 
    168 struct X : C {
    169   // CHECK-LABEL: VFTable for 'test6::A' in 'test6::C' in 'test6::X' (1 entry).
    170   // CHECK-NEXT:   0 | void test6::A::f()
    171 
    172   // CHECK-LABEL: VFTable for 'test6::B' in 'test6::C' in 'test6::X' (2 entries).
    173   // CHECK-NEXT:   0 | void test6::X::g()
    174   // CHECK-NEXT:   1 | void test6::B::h()
    175 
    176   // CHECK-LABEL: VFTable indices for 'test6::X' (1 entry).
    177   // CHECK-NEXT:   via vfptr at offset 4
    178   // CHECK-NEXT:   0 | void test6::X::g()
    179 
    180   // Overrides both C::g and B::g.
    181   virtual void g();
    182 };
    183 
    184 void build_vftable(X *obj) { obj->g(); }
    185 }
    186 
    187 namespace test7 {
    188 struct A {
    189   virtual void f();
    190 };
    191 
    192 struct B {
    193   virtual void g();
    194   virtual void h();
    195 };
    196 
    197 struct C : A, B {
    198   // Only adds a new method.
    199   virtual void i();
    200 };
    201 
    202 struct X : C {
    203   // CHECK-LABEL: VFTable for 'test7::A' in 'test7::C' in 'test7::X' (2 entries).
    204   // CHECK-NEXT:   0 | void test7::A::f()
    205   // CHECK-NEXT:   1 | void test7::C::i()
    206 
    207   // CHECK-LABEL: VFTable for 'test7::B' in 'test7::C' in 'test7::X' (2 entries).
    208   // CHECK-NEXT:   0 | void test7::X::g()
    209   // CHECK-NEXT:   1 | void test7::B::h()
    210 
    211   // CHECK-LABEL: VFTable indices for 'test7::X' (1 entry).
    212   // CHECK-NEXT:   via vfptr at offset 4
    213   // CHECK-NEXT:   0 | void test7::X::g()
    214 
    215   // Overrides grandparent's B::g.
    216   virtual void g();
    217 };
    218 
    219 void build_vftable(X *obj) { obj->g(); }
    220 }
    221 
    222 namespace test8 {
    223 struct A {
    224   virtual void f();
    225 };
    226 
    227 struct B : A {
    228   virtual void g();
    229 };
    230 
    231 // There are two 'A' subobjects in this class.
    232 struct X : A, B {
    233   // CHECK-LABEL: VFTable for 'test8::A' in 'test8::X' (2 entries).
    234   // CHECK-NEXT:   0 | void test8::A::f()
    235   // CHECK-NEXT:   1 | void test8::X::h()
    236 
    237   // CHECK-LABEL: VFTable for 'test8::A' in 'test8::B' in 'test8::X' (2 entries).
    238   // CHECK-NEXT:   0 | void test8::A::f()
    239   // CHECK-NEXT:   1 | void test8::B::g()
    240 
    241   // CHECK-LABEL: VFTable indices for 'test8::X' (1 entry).
    242   // CHECK-NEXT:   1 | void test8::X::h()
    243 
    244   // MANGLING-DAG: @"\01??_7X@test8@@6BA@1@@"
    245   // MANGLING-DAG: @"\01??_7X@test8@@6BB@1@@"
    246 
    247   virtual void h();
    248 } x;
    249 
    250 void build_vftable(X *obj) { obj->h(); }
    251 }
    252 
    253 namespace test9 {
    254 struct A {
    255   virtual void f();
    256 };
    257 
    258 struct B {
    259   virtual void g();
    260   virtual void h();
    261 };
    262 
    263 struct C : A, B {
    264   // Overrides only the left child's method (A::f).
    265   virtual void f();
    266 };
    267 
    268 struct D : A, B {
    269   // Overrides only the right child's method (B::g).
    270   virtual void g();
    271 };
    272 
    273 // 2-level structure with repeating subobject types, but no thunks needed.
    274 struct X : C, D {
    275   // CHECK-LABEL: VFTable for 'test9::A' in 'test9::C' in 'test9::X' (2 entries)
    276   // CHECK-NEXT:   0 | void test9::C::f()
    277   // CHECK-NEXT:   1 | void test9::X::z()
    278 
    279   // CHECK-LABEL: VFTable for 'test9::B' in 'test9::C' in 'test9::X' (2 entries)
    280   // CHECK-NEXT:   0 | void test9::B::g()
    281   // CHECK-NEXT:   1 | void test9::B::h()
    282 
    283   // CHECK-LABEL: VFTable for 'test9::A' in 'test9::D' in 'test9::X' (1 entry)
    284   // CHECK-NEXT:   0 | void test9::A::f()
    285 
    286   // CHECK-LABEL: VFTable for 'test9::B' in 'test9::D' in 'test9::X' (2 entries)
    287   // CHECK-NEXT:   0 | void test9::D::g()
    288   // CHECK-NEXT:   1 | void test9::B::h()
    289 
    290   // CHECK-LABEL: VFTable indices for 'test9::X' (1 entry).
    291   // CHECK-NEXT:   1 | void test9::X::z()
    292 
    293   // MANGLING-DAG: @"\01??_7X@test9@@6BA@1@C@1@@"
    294   // MANGLING-DAG: @"\01??_7X@test9@@6BA@1@D@1@@"
    295   // MANGLING-DAG: @"\01??_7X@test9@@6BB@1@C@1@@"
    296   // MANGLING-DAG: @"\01??_7X@test9@@6BB@1@D@1@@"
    297 
    298   virtual void z();
    299 } x;
    300 
    301 void build_vftable(test9::X *obj) { obj->z(); }
    302 }
    303