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 5namespace test1 { 6struct A { 7 virtual void f(); 8}; 9 10struct 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 16struct 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 34void build_vftable(X *obj) { obj->f(); } 35} 36 37namespace test2 { 38struct A { 39 virtual void f(); 40}; 41 42struct B { 43 virtual void g(); 44 virtual void h(); 45}; 46 47struct 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 64void build_vftable(X *obj) { obj->g(); } 65} 66 67namespace test3 { 68struct A { 69 virtual void f(); 70}; 71 72struct B { 73 virtual void g(); 74 virtual void h(); 75}; 76 77struct 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 93void build_vftable(X *obj) { obj->i(); } 94} 95 96namespace test4 { 97struct A { 98 virtual void f(); 99}; 100 101struct Empty { }; // Doesn't have a vftable! 102 103// Only the right base has a vftable, so it's laid out before the left one! 104struct 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 116void build_vftable(X *obj) { obj->f(); } 117} 118 119namespace test5 { 120struct A { 121 virtual void f(); 122}; 123 124struct B { 125 virtual void g(); 126 virtual void h(); 127}; 128 129struct C : A, B { 130 virtual void f(); 131}; 132 133struct 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 151void build_vftable(X *obj) { obj->f(); } 152} 153 154namespace test6 { 155struct A { 156 virtual void f(); 157}; 158 159struct B { 160 virtual void g(); 161 virtual void h(); 162}; 163 164struct C : A, B { 165 virtual void g(); 166}; 167 168struct 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 184void build_vftable(X *obj) { obj->g(); } 185} 186 187namespace test7 { 188struct A { 189 virtual void f(); 190}; 191 192struct B { 193 virtual void g(); 194 virtual void h(); 195}; 196 197struct C : A, B { 198 // Only adds a new method. 199 virtual void i(); 200}; 201 202struct 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 219void build_vftable(X *obj) { obj->g(); } 220} 221 222namespace test8 { 223struct A { 224 virtual void f(); 225}; 226 227struct B : A { 228 virtual void g(); 229}; 230 231// There are two 'A' subobjects in this class. 232struct 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 250void build_vftable(X *obj) { obj->h(); } 251} 252 253namespace test9 { 254struct A { 255 virtual void f(); 256}; 257 258struct B { 259 virtual void g(); 260 virtual void h(); 261}; 262 263struct C : A, B { 264 // Overrides only the left child's method (A::f). 265 virtual void f(); 266}; 267 268struct 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. 274struct 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 301void build_vftable(test9::X *obj) { obj->z(); } 302} 303