1 // RUN: %clang_cc1 -fno-rtti -emit-llvm -o %t.ll -fdump-vtable-layouts %s -triple=i386-pc-win32 >%t 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-X %s < %t 13 // RUN: FileCheck --check-prefix=TEST8-Z %s < %t 14 // RUN: FileCheck --check-prefix=TEST8-T %s < %t 15 // RUN: FileCheck --check-prefix=TEST9-Y %s < %t 16 // RUN: FileCheck --check-prefix=TEST9-Z %s < %t 17 // RUN: FileCheck --check-prefix=TEST9-W %s < %t 18 // RUN: FileCheck --check-prefix=TEST9-T %s < %t 19 // RUN: FileCheck --check-prefix=TEST10 %s < %t 20 // RUN: FileCheck --check-prefix=VDTORS-Y %s < %t 21 // RUN: FileCheck --check-prefix=VDTORS-U %s < %t 22 // RUN: FileCheck --check-prefix=VDTORS-V %s < %t 23 // RUN: FileCheck --check-prefix=VDTORS-P %s < %t 24 // RUN: FileCheck --check-prefix=RET-W %s < %t 25 // RUN: FileCheck --check-prefix=RET-T %s < %t 26 // RUN: FileCheck --check-prefix=RET-V %s < %t 27 28 // RUN: FileCheck --check-prefix=MANGLING %s < %t.ll 29 30 struct Empty { }; 31 32 struct A { 33 virtual void f(); 34 virtual void z(); // Useful to check there are no thunks for f() when appropriate. 35 }; 36 37 struct B { 38 virtual void g(); 39 }; 40 41 struct C: virtual A { 42 // VTABLE-C: VFTable for 'A' in 'C' (2 entries) 43 // VTABLE-C-NEXT: 0 | void C::f() 44 // VTABLE-C-NEXT: 1 | void A::z() 45 46 // VTABLE-C: VFTable indices for 'C' (1 entry) 47 // VTABLE-C-NEXT: vbtable index 1, vfptr at offset 0 48 // VTABLE-C-NEXT: 0 | void C::f() 49 50 // MANGLING-DAG: @"\01??_7C@@6B@" 51 52 virtual void f() {} 53 }; 54 55 C c; 56 57 struct D: virtual A { 58 // VTABLE-D: VFTable for 'D' (1 entry). 59 // VTABLE-D-NEXT: 0 | void D::h() 60 61 // VTABLE-D: VFTable for 'A' in 'D' (2 entries). 62 // VTABLE-D-NEXT: 0 | void D::f() 63 // VTABLE-D-NEXT: 1 | void A::z() 64 65 // VTABLE-D: VFTable indices for 'D' (2 entries). 66 // VTABLE-D-NEXT: via vfptr at offset 0 67 // VTABLE-D-NEXT: 0 | void D::h() 68 // VTABLE-D-NEXT: via vbtable index 1, vfptr at offset 0 69 // VTABLE-D-NEXT: 0 | void D::f() 70 71 // MANGLING-DAG: @"\01??_7D@@6B0@@" 72 // MANGLING-DAG: @"\01??_7D@@6BA@@@" 73 74 virtual void f(); 75 virtual void h(); 76 }; 77 78 void D::h() {} 79 D d; 80 81 namespace Test1 { 82 83 struct X { int x; }; 84 85 // X and A get reordered in the layout since X doesn't have a vfptr while A has. 86 struct Y : X, A { }; 87 // MANGLING-DAG: @"\01??_7Y@Test1@@6B@" 88 89 struct Z : virtual Y { 90 // TEST1: VFTable for 'A' in 'Test1::Y' in 'Test1::Z' (2 entries). 91 // TEST1-NEXT: 0 | void A::f() 92 // TEST1-NEXT: 1 | void A::z() 93 94 // TEST1-NOT: VFTable indices for 'Test1::Z' 95 96 // MANGLING-DAG: @"\01??_7Z@Test1@@6B@" 97 }; 98 99 Z z; 100 } 101 102 namespace Test2 { 103 104 struct X: virtual A, virtual B { 105 // TEST2: VFTable for 'Test2::X' (1 entry). 106 // TEST2-NEXT: 0 | void Test2::X::h() 107 108 // TEST2: VFTable for 'A' in 'Test2::X' (2 entries). 109 // TEST2-NEXT: 0 | void A::f() 110 // TEST2-NEXT: 1 | void A::z() 111 112 // TEST2: VFTable for 'B' in 'Test2::X' (1 entry). 113 // TEST2-NEXT: 0 | void B::g() 114 115 // TEST2: VFTable indices for 'Test2::X' (1 entry). 116 // TEST2-NEXT: 0 | void Test2::X::h() 117 118 // MANGLING-DAG: @"\01??_7X@Test2@@6B01@@" 119 // MANGLING-DAG: @"\01??_7X@Test2@@6BA@@@" 120 // MANGLING-DAG: @"\01??_7X@Test2@@6BB@@@" 121 122 virtual void h(); 123 }; 124 125 X x; 126 } 127 128 namespace Test3 { 129 130 struct X : virtual A { 131 // MANGLING-DAG: @"\01??_7X@Test3@@6B@" 132 }; 133 134 struct Y: virtual X { 135 // TEST3: VFTable for 'A' in 'Test3::X' in 'Test3::Y' (2 entries). 136 // TEST3-NEXT: 0 | void A::f() 137 // TEST3-NEXT: 1 | void A::z() 138 139 // TEST3-NOT: VFTable indices for 'Test3::Y' 140 141 // MANGLING-DAG: @"\01??_7Y@Test3@@6B@" 142 }; 143 144 Y y; 145 } 146 147 namespace Test4 { 148 149 struct X: virtual C { 150 // This one's interesting. C::f expects (A*) to be passed as 'this' and does 151 // ECX-=4 to cast to (C*). In X, C and A vbases are reordered, so the thunk 152 // should pass a pointer to the end of X in order 153 // for ECX-=4 to point at the C part. 154 155 // TEST4: VFTable for 'A' in 'C' in 'Test4::X' (2 entries). 156 // TEST4-NEXT: 0 | void C::f() 157 // TEST4-NEXT: [this adjustment: 8 non-virtual] 158 // TEST4-NEXT: 1 | void A::z() 159 160 // TEST4: Thunks for 'void C::f()' (1 entry). 161 // TEST4-NEXT: 0 | [this adjustment: 8 non-virtual] 162 163 // TEST4-NOT: VFTable indices for 'Test4::X' 164 165 // MANGLING-DAG: @"\01??_7X@Test4@@6B@" 166 167 // Also check the mangling of the thunk. 168 // MANGLING-DAG: define weak x86_thiscallcc void @"\01?f@C@@WPPPPPPPI@AEXXZ" 169 }; 170 171 X x; 172 } 173 174 namespace Test5 { 175 176 // New methods are added to the base's vftable. 177 struct X : A { 178 // MANGLING-DAG: @"\01??_7X@Test5@@6B@" 179 virtual void g(); 180 }; 181 182 struct Y : virtual X { 183 // TEST5: VFTable for 'Test5::Y' (1 entry). 184 // TEST5-NEXT: 0 | void Test5::Y::h() 185 186 // TEST5: VFTable for 'A' in 'Test5::X' in 'Test5::Y' (3 entries). 187 // TEST5-NEXT: 0 | void A::f() 188 // TEST5-NEXT: 1 | void A::z() 189 // TEST5-NEXT: 2 | void Test5::X::g() 190 191 // TEST5: VFTable indices for 'Test5::Y' (1 entry). 192 // TEST5-NEXT: 0 | void Test5::Y::h() 193 194 // MANGLING-DAG: @"\01??_7Y@Test5@@6B01@@" 195 // MANGLING-DAG: @"\01??_7Y@Test5@@6BX@1@@" 196 197 virtual void h(); 198 }; 199 200 Y y; 201 } 202 203 namespace Test6 { 204 205 struct X : A, virtual Empty { 206 // TEST6: VFTable for 'A' in 'Test6::X' (2 entries). 207 // TEST6-NEXT: 0 | void A::f() 208 // TEST6-NEXT: 1 | void A::z() 209 210 // TEST6-NOT: VFTable indices for 'Test6::X' 211 212 // MANGLING-DAG: @"\01??_7X@Test6@@6B@" 213 }; 214 215 X x; 216 } 217 218 namespace Test7 { 219 220 struct X : C { 221 // MANGLING-DAG: @"\01??_7X@Test7@@6B@" 222 }; 223 224 struct Y : virtual X { 225 // TEST7: VFTable for 'A' in 'C' in 'Test7::X' in 'Test7::Y' (2 entries). 226 // TEST7-NEXT: 0 | void C::f() 227 // TEST7-NEXT: [this adjustment: 8 non-virtual] 228 // TEST7-NEXT: 1 | void A::z() 229 230 // TEST7: Thunks for 'void C::f()' (1 entry). 231 // TEST7-NEXT: 0 | [this adjustment: 8 non-virtual] 232 233 // TEST7-NOT: VFTable indices for 'Test7::Y' 234 235 // MANGLING-DAG: @"\01??_7Y@Test7@@6B@" 236 }; 237 238 Y y; 239 } 240 241 namespace Test8 { 242 243 // This is a typical diamond inheritance with a shared 'A' vbase. 244 struct X : D, C { 245 // TEST8-X: VFTable for 'D' in 'Test8::X' (1 entry). 246 // TEST8-X-NEXT: 0 | void D::h() 247 248 // TEST8-X: VFTable for 'A' in 'D' in 'Test8::X' (2 entries). 249 // TEST8-X-NEXT: 0 | void Test8::X::f() 250 // TEST8-X-NEXT: 1 | void A::z() 251 252 // TEST8-X: VFTable indices for 'Test8::X' (1 entry). 253 // TEST8-X-NEXT: via vbtable index 1, vfptr at offset 0 254 // TEST8-X-NEXT: 0 | void Test8::X::f() 255 256 // MANGLING-DAG: @"\01??_7X@Test8@@6BA@@@" 257 // MANGLING-DAG: @"\01??_7X@Test8@@6BD@@@" 258 259 virtual void f(); 260 }; 261 262 X x; 263 264 // Another diamond inheritance which led to AST crashes. 265 struct Y : virtual A {}; 266 267 struct Z : Y, C { 268 // TEST8-Z: VFTable for 'A' in 'Test8::Y' in 'Test8::Z' (2 entries). 269 // TEST8-Z-NEXT: 0 | void Test8::Z::f() 270 // TEST8-Z-NEXT: 1 | void A::z() 271 272 // TEST8-Z: VFTable indices for 'Test8::Z' (1 entry). 273 // TEST8-Z-NEXT: via vbtable index 1, vfptr at offset 0 274 // TEST8-Z-NEXT: 0 | void Test8::Z::f() 275 virtual void f(); 276 }; 277 Z z; 278 279 // Another diamond inheritance which we miscompiled (PR18967). 280 struct W : virtual A { 281 virtual void bar(); 282 }; 283 284 struct T : W, C { 285 // TEST8-T: VFTable for 'Test8::W' in 'Test8::T' (1 entry) 286 // TEST8-T-NEXT: 0 | void Test8::T::bar() 287 288 // TEST8-T: VFTable for 'A' in 'Test8::W' in 'Test8::T' (2 entries) 289 // TEST8-T-NEXT: 0 | void C::f() 290 // TEST8-T-NEXT: [this adjustment: -4 non-virtual] 291 // TEST8-T-NEXT: 1 | void A::z() 292 293 // TEST8-T: Thunks for 'void C::f()' (1 entry). 294 // TEST8-T-NEXT: 0 | [this adjustment: -4 non-virtual] 295 virtual void bar(); 296 int field; 297 }; 298 T t; 299 } 300 301 namespace Test9 { 302 303 struct X : A { }; 304 305 struct Y : virtual X { 306 // TEST9-Y: VFTable for 'Test9::Y' (1 entry). 307 // TEST9-Y-NEXT: 0 | void Test9::Y::h() 308 309 // TEST9-Y: VFTable for 'A' in 'Test9::X' in 'Test9::Y' (2 entries). 310 // TEST9-Y-NEXT: 0 | void A::f() 311 // TEST9-Y-NEXT: 1 | void A::z() 312 313 // TEST9-Y: VFTable indices for 'Test9::Y' (1 entry). 314 // TEST9-Y-NEXT: 0 | void Test9::Y::h() 315 316 // MANGLING-DAG: @"\01??_7Y@Test9@@6B01@@" 317 // MANGLING-DAG: @"\01??_7Y@Test9@@6BX@1@@" 318 319 virtual void h(); 320 }; 321 322 Y y; 323 324 struct Z : Y, virtual B { 325 // TEST9-Z: VFTable for 'Test9::Y' in 'Test9::Z' (1 entry). 326 // TEST9-Z-NEXT: 0 | void Test9::Y::h() 327 328 // TEST9-Z: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' (2 entries). 329 // TEST9-Z-NEXT: 0 | void A::f() 330 // TEST9-Z-NEXT: 1 | void A::z() 331 332 // TEST9-Z: VFTable for 'B' in 'Test9::Z' (1 entry). 333 // TEST9-Z-NEXT: 0 | void B::g() 334 335 // TEST9-Z-NOT: VFTable indices for 'Test9::Z' 336 337 // MANGLING-DAG: @"\01??_7Z@Test9@@6BX@1@@" 338 // MANGLING-DAG: @"\01??_7Z@Test9@@6BY@1@@" 339 340 // MANGLING-DAG: @"\01??_7Z@Test9@@6B@" 341 }; 342 343 Z z; 344 345 struct W : Z, D, virtual A, virtual B { 346 // TEST9-W: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::W' (1 entry). 347 // TEST9-W-NEXT: 0 | void Test9::Y::h() 348 349 // TEST9-W: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::W' (2 entries). 350 // TEST9-W-NEXT: 0 | void A::f() 351 // TEST9-W-NEXT: 1 | void A::z() 352 353 // TEST9-W: VFTable for 'B' in 'Test9::Z' in 'Test9::W' (1 entry). 354 // TEST9-W-NEXT: 0 | void B::g() 355 356 // TEST9-W: VFTable for 'D' in 'Test9::W' (1 entry). 357 // TEST9-W-NEXT: 0 | void D::h() 358 359 // TEST9-W: VFTable for 'A' in 'D' in 'Test9::W' (2 entries). 360 // TEST9-W-NEXT: 0 | void D::f() 361 // TEST9-W-NEXT: [this adjustment: -8 non-virtual] 362 // TEST9-W-NEXT: 1 | void A::z() 363 364 // TEST9-W: Thunks for 'void D::f()' (1 entry). 365 // TEST9-W-NEXT: 0 | [this adjustment: -8 non-virtual] 366 367 // TEST9-W-NOT: VFTable indices for 'Test9::W' 368 369 // MANGLING-DAG: @"\01??_7W@Test9@@6BA@@@" 370 // MANGLING-DAG: @"\01??_7W@Test9@@6BD@@@" 371 // MANGLING-DAG: @"\01??_7W@Test9@@6BX@1@@" 372 373 // MANGLING-DAG: @"\01??_7W@Test9@@6B@" 374 // MANGLING-DAG: @"\01??_7W@Test9@@6BY@1@@" 375 }; 376 377 W w; 378 379 struct T : Z, D, virtual A, virtual B { 380 // TEST9-T: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::T' (1 entry). 381 // TEST9-T-NEXT: 0 | void Test9::T::h() 382 383 // TEST9-T: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::T' (2 entries). 384 // TEST9-T-NEXT: 0 | void Test9::T::f() 385 // TEST9-T-NEXT: 1 | void Test9::T::z() 386 387 // TEST9-T: VFTable for 'B' in 'Test9::Z' in 'Test9::T' (1 entry). 388 // TEST9-T-NEXT: 0 | void Test9::T::g() 389 390 // TEST9-T: VFTable for 'D' in 'Test9::T' (1 entry). 391 // TEST9-T-NEXT: 0 | void Test9::T::h() 392 // TEST9-T-NEXT: [this adjustment: -8 non-virtual] 393 394 // TEST9-T: Thunks for 'void Test9::T::h()' (1 entry). 395 // TEST9-T-NEXT: 0 | [this adjustment: -8 non-virtual] 396 397 // TEST9-T: VFTable for 'A' in 'D' in 'Test9::T' (2 entries). 398 // TEST9-T-NEXT: 0 | void Test9::T::f() 399 // TEST9-T-NEXT: [this adjustment: -8 non-virtual] 400 // TEST9-T-NEXT: 1 | void Test9::T::z() 401 // TEST9-T-NEXT: [this adjustment: -8 non-virtual] 402 403 // TEST9-T: Thunks for 'void Test9::T::f()' (1 entry). 404 // TEST9-T-NEXT: 0 | [this adjustment: -8 non-virtual] 405 406 // TEST9-T: Thunks for 'void Test9::T::z()' (1 entry). 407 // TEST9-T-NEXT: 0 | [this adjustment: -8 non-virtual] 408 409 // TEST9-T: VFTable indices for 'Test9::T' (4 entries). 410 // TEST9-T-NEXT: via vfptr at offset 0 411 // TEST9-T-NEXT: 0 | void Test9::T::h() 412 // TEST9-T-NEXT: via vbtable index 1, vfptr at offset 0 413 // TEST9-T-NEXT: 0 | void Test9::T::f() 414 // TEST9-T-NEXT: 1 | void Test9::T::z() 415 // TEST9-T-NEXT: via vbtable index 2, vfptr at offset 0 416 // TEST9-T-NEXT: 0 | void Test9::T::g() 417 418 // MANGLING-DAG: @"\01??_7T@Test9@@6BA@@@" 419 // MANGLING-DAG: @"\01??_7T@Test9@@6BD@@@" 420 // MANGLING-DAG: @"\01??_7T@Test9@@6BX@1@@" 421 422 // MANGLING-DAG: @"\01??_7T@Test9@@6B@" 423 // MANGLING-DAG: @"\01??_7T@Test9@@6BY@1@@" 424 425 virtual void f(); 426 virtual void g(); 427 virtual void h(); 428 virtual void z(); 429 }; 430 431 T t; 432 } 433 434 namespace Test10 { 435 struct X : virtual C, virtual A { 436 // TEST10: VFTable for 'A' in 'C' in 'Test10::X' (2 entries). 437 // TEST10-NEXT: 0 | void Test10::X::f() 438 // TEST10-NEXT: 1 | void A::z() 439 440 // TEST10: VFTable indices for 'Test10::X' (1 entry). 441 // TEST10-NEXT: via vbtable index 1, vfptr at offset 0 442 // TEST10-NEXT: 0 | void Test10::X::f() 443 virtual void f(); 444 }; 445 446 void X::f() {} 447 X x; 448 } 449 450 namespace Test11 { 451 struct X : virtual A {}; 452 struct Y { virtual void g(); }; 453 454 struct Z : virtual X, Y { 455 // MANGLING-DAG: @"\01??_7Z@Test11@@6BY@1@@" 456 // MANGLING-DAG: @"\01??_7Z@Test11@@6BX@1@@" 457 }; 458 459 Z z; 460 461 struct W : virtual X, A {}; 462 463 // PR17748 FIXME this one hits UNREACHABLE: 464 // W w; 465 } 466 467 namespace vdtors { 468 struct X { 469 virtual ~X(); 470 virtual void zzz(); 471 }; 472 473 struct Y : virtual X { 474 // VDTORS-Y: VFTable for 'vdtors::X' in 'vdtors::Y' (2 entries). 475 // VDTORS-Y-NEXT: 0 | vdtors::Y::~Y() [scalar deleting] 476 // VDTORS-Y-NEXT: 1 | void vdtors::X::zzz() 477 478 // VDTORS-Y-NOT: Thunks for 'vdtors::Y::~Y()' 479 virtual ~Y(); 480 }; 481 482 Y y; 483 484 struct Z { 485 virtual void z(); 486 }; 487 488 struct W : Z, X { 489 // Implicit virtual dtor. 490 }; 491 492 struct U : virtual W { 493 // VDTORS-U: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::U' (1 entry). 494 // VDTORS-U-NEXT: 0 | void vdtors::Z::z() 495 496 // VDTORS-U: VFTable for 'vdtors::X' in 'vdtors::W' in 'vdtors::U' (2 entries). 497 // VDTORS-U-NEXT: 0 | vdtors::U::~U() [scalar deleting] 498 // VDTORS-U-NEXT: [this adjustment: -4 non-virtual] 499 // VDTORS-U-NEXT: 1 | void vdtors::X::zzz() 500 501 // VDTORS-U: Thunks for 'vdtors::U::~U()' (1 entry). 502 // VDTORS-U-NEXT: 0 | [this adjustment: -4 non-virtual] 503 504 // VDTORS-U: VFTable indices for 'vdtors::U' (1 entry). 505 // VDTORS-U-NEXT: -- accessible via vbtable index 1, vfptr at offset 4 -- 506 // VDTORS-U-NEXT: 0 | vdtors::U::~U() [scalar deleting] 507 virtual ~U(); 508 }; 509 510 U u; 511 512 struct V : virtual W { 513 // VDTORS-V: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::V' (1 entry). 514 // VDTORS-V-NEXT: 0 | void vdtors::Z::z() 515 516 // VDTORS-V: VFTable for 'vdtors::X' in 'vdtors::W' in 'vdtors::V' (2 entries). 517 // VDTORS-V-NEXT: 0 | vdtors::V::~V() [scalar deleting] 518 // VDTORS-V-NEXT: [this adjustment: -4 non-virtual] 519 // VDTORS-V-NEXT: 1 | void vdtors::X::zzz() 520 521 // VDTORS-V: Thunks for 'vdtors::V::~V()' (1 entry). 522 // VDTORS-V-NEXT: 0 | [this adjustment: -4 non-virtual] 523 524 // VDTORS-V: VFTable indices for 'vdtors::V' (1 entry). 525 // VDTORS-V-NEXT: -- accessible via vbtable index 1, vfptr at offset 4 -- 526 // VDTORS-V-NEXT: 0 | vdtors::V::~V() [scalar deleting] 527 }; 528 529 V v; 530 531 struct T : virtual X { 532 virtual ~T(); 533 }; 534 535 struct P : T, Y { 536 // VDTORS-P: VFTable for 'vdtors::X' in 'vdtors::T' in 'vdtors::P' (2 entries). 537 // VDTORS-P-NEXT: 0 | vdtors::P::~P() [scalar deleting] 538 // VDTORS-P-NEXT: 1 | void vdtors::X::zzz() 539 540 // VDTORS-P-NOT: Thunks for 'vdtors::P::~P()' 541 virtual ~P(); 542 }; 543 544 P p; 545 546 } 547 548 namespace return_adjustment { 549 550 struct X : virtual A { 551 virtual void f(); 552 }; 553 554 struct Y : virtual A, virtual X { 555 virtual void f(); 556 }; 557 558 struct Z { 559 virtual A* foo(); 560 }; 561 562 struct W : Z { 563 // RET-W: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' (2 entries). 564 // RET-W-NEXT: 0 | return_adjustment::X *return_adjustment::W::foo() 565 // RET-W-NEXT: [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual] 566 // RET-W-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo() 567 568 // RET-W: Thunks for 'return_adjustment::X *return_adjustment::W::foo()' (1 entry). 569 // RET-W-NEXT: 0 | [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual] 570 571 // RET-W: VFTable indices for 'return_adjustment::W' (1 entry). 572 // RET-W-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo() 573 574 virtual X* foo(); 575 }; 576 577 W y; 578 579 struct T : W { 580 // RET-T: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' in 'return_adjustment::T' (3 entries). 581 // RET-T-NEXT: 0 | return_adjustment::Y *return_adjustment::T::foo() 582 // RET-T-NEXT: [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual] 583 // RET-T-NEXT: 1 | return_adjustment::Y *return_adjustment::T::foo() 584 // RET-T-NEXT: [return adjustment (to type 'struct return_adjustment::X *'): vbase #2, 0 non-virtual] 585 // RET-T-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo() 586 587 // RET-T: Thunks for 'return_adjustment::Y *return_adjustment::T::foo()' (2 entries). 588 // RET-T-NEXT: 0 | [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual] 589 // RET-T-NEXT: 1 | [return adjustment (to type 'struct return_adjustment::X *'): vbase #2, 0 non-virtual] 590 591 // RET-T: VFTable indices for 'return_adjustment::T' (1 entry). 592 // RET-T-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo() 593 594 virtual Y* foo(); 595 }; 596 597 T t; 598 599 struct U : virtual A { 600 virtual void g(); // adds a vfptr 601 }; 602 603 struct V : Z { 604 // RET-V: VFTable for 'return_adjustment::Z' in 'return_adjustment::V' (2 entries). 605 // RET-V-NEXT: 0 | return_adjustment::U *return_adjustment::V::foo() 606 // RET-V-NEXT: [return adjustment (to type 'struct A *'): vbptr at offset 4, vbase #1, 0 non-virtual] 607 // RET-V-NEXT: 1 | return_adjustment::U *return_adjustment::V::foo() 608 609 // RET-V: Thunks for 'return_adjustment::U *return_adjustment::V::foo()' (1 entry). 610 // RET-V-NEXT: 0 | [return adjustment (to type 'struct A *'): vbptr at offset 4, vbase #1, 0 non-virtual] 611 612 // RET-V: VFTable indices for 'return_adjustment::V' (1 entry). 613 // RET-V-NEXT: 1 | return_adjustment::U *return_adjustment::V::foo() 614 615 virtual U* foo(); 616 }; 617 618 V v; 619 } 620 621 namespace pr17748 { 622 struct A { 623 virtual void f() {} 624 }; 625 626 struct B : virtual A { 627 B() {} 628 }; 629 630 struct C : virtual B, A { 631 C() {} 632 }; 633 C c; 634 635 // MANGLING-DAG: @"\01??_7A@pr17748@@6B@" 636 // MANGLING-DAG: @"\01??_7B@pr17748@@6B@" 637 // MANGLING-DAG: @"\01??_7C@pr17748@@6BA@1@@" 638 // MANGLING-DAG: @"\01??_7C@pr17748@@6BB@1@@" 639 } 640