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