1 // RUN: %clang_cc1 -std=c++11 -fms-extensions -fno-rtti -emit-llvm -o %t.ll -fdump-vtable-layouts %s -triple=i386-pc-win32 >%t
2 // RUN: FileCheck %s < %t
3 // RUN: FileCheck --check-prefix=MANGLING %s < %t.ll
9 virtual void z(); // Useful to check there are no thunks for f() when appropriate.
17 // CHECK-LABEL: VFTable for 'A' in 'C' (2 entries)
18 // CHECK-NEXT: 0 | void C::f()
19 // CHECK-NEXT: 1 | void A::z()
21 // CHECK-LABEL: VFTable indices for 'C' (1 entry)
22 // CHECK-NEXT: vbtable index 1, vfptr at offset 0
23 // CHECK-NEXT: 0 | void C::f()
25 // MANGLING-DAG: @"??_7C@@6B@"
31 void use(C
*obj
) { obj
->f(); }
34 // CHECK-LABEL: VFTable for 'D' (1 entry).
35 // CHECK-NEXT: 0 | void D::h()
37 // CHECK-LABEL: VFTable for 'A' in 'D' (2 entries).
38 // CHECK-NEXT: 0 | void D::f()
39 // CHECK-NEXT: 1 | void A::z()
41 // CHECK-LABEL: VFTable indices for 'D' (2 entries).
42 // CHECK-NEXT: via vfptr at offset 0
43 // CHECK-NEXT: 0 | void D::h()
44 // CHECK-NEXT: via vbtable index 1, vfptr at offset 0
45 // CHECK-NEXT: 0 | void D::f()
47 // MANGLING-DAG: @"??_7D@@6B0@@"
48 // MANGLING-DAG: @"??_7D@@6BA@@@"
55 void use(D
*obj
) { obj
->h(); }
61 // X and A get reordered in the layout since X doesn't have a vfptr while A has.
63 // MANGLING-DAG: @"??_7Y@Test1@@6B@"
65 struct Z
: virtual Y
{
67 // CHECK-LABEL: VFTable for 'A' in 'Test1::Y' in 'Test1::Z' (2 entries).
68 // CHECK-NEXT: 0 | void A::f()
69 // CHECK-NEXT: 1 | void A::z()
71 // CHECK-NOT: VFTable indices for 'Test1::Z'
73 // MANGLING-DAG: @"??_7Z@Test1@@6B@"
81 struct X
: virtual A
, virtual B
{
82 // CHECK-LABEL: VFTable for 'Test2::X' (1 entry).
83 // CHECK-NEXT: 0 | void Test2::X::h()
85 // CHECK-LABEL: VFTable for 'A' in 'Test2::X' (2 entries).
86 // CHECK-NEXT: 0 | void A::f()
87 // CHECK-NEXT: 1 | void A::z()
89 // CHECK-LABEL: VFTable for 'B' in 'Test2::X' (1 entry).
90 // CHECK-NEXT: 0 | void B::g()
92 // CHECK-LABEL: VFTable indices for 'Test2::X' (1 entry).
93 // CHECK-NEXT: 0 | void Test2::X::h()
95 // MANGLING-DAG: @"??_7X@Test2@@6B01@@"
96 // MANGLING-DAG: @"??_7X@Test2@@6BA@@@"
97 // MANGLING-DAG: @"??_7X@Test2@@6BB@@@"
103 void use(X
*obj
) { obj
->h(); }
108 struct X
: virtual A
{
109 // MANGLING-DAG: @"??_7X@Test3@@6B@"
112 struct Y
: virtual X
{
114 // CHECK-LABEL: VFTable for 'A' in 'Test3::X' in 'Test3::Y' (2 entries).
115 // CHECK-NEXT: 0 | void A::f()
116 // CHECK-NEXT: 1 | void A::z()
118 // CHECK-NOT: VFTable indices for 'Test3::Y'
120 // MANGLING-DAG: @"??_7Y@Test3@@6B@"
128 struct X
: virtual C
{
130 // This one's interesting. C::f expects (A*) to be passed as 'this' and does
131 // ECX-=4 to cast to (C*). In X, C and A vbases are reordered, so the thunk
132 // should pass a pointer to the end of X in order
133 // for ECX-=4 to point at the C part.
135 // CHECK-LABEL: VFTable for 'A' in 'C' in 'Test4::X' (2 entries).
136 // CHECK-NEXT: 0 | void C::f()
137 // CHECK-NEXT: [this adjustment: 8 non-virtual]
138 // CHECK-NEXT: 1 | void A::z()
140 // CHECK-LABEL: Thunks for 'void C::f()' (1 entry).
141 // CHECK-NEXT: 0 | [this adjustment: 8 non-virtual]
143 // CHECK-NOT: VFTable indices for 'Test4::X'
145 // MANGLING-DAG: @"??_7X@Test4@@6B@"
147 // Also check the mangling of the thunk.
148 // MANGLING-DAG: define linkonce_odr dso_local x86_thiscallcc void @"?f@C@@WPPPPPPPI@AEXXZ"
156 // New methods are added to the base's vftable.
158 // MANGLING-DAG: @"??_7X@Test5@@6B@"
162 struct Y
: virtual X
{
163 // CHECK-LABEL: VFTable for 'Test5::Y' (1 entry).
164 // CHECK-NEXT: 0 | void Test5::Y::h()
166 // CHECK-LABEL: VFTable for 'A' in 'Test5::X' in 'Test5::Y' (3 entries).
167 // CHECK-NEXT: 0 | void A::f()
168 // CHECK-NEXT: 1 | void A::z()
169 // CHECK-NEXT: 2 | void Test5::X::g()
171 // CHECK-LABEL: VFTable indices for 'Test5::Y' (1 entry).
172 // CHECK-NEXT: 0 | void Test5::Y::h()
174 // MANGLING-DAG: @"??_7Y@Test5@@6B01@@"
175 // MANGLING-DAG: @"??_7Y@Test5@@6BX@1@@"
181 void use(Y
*obj
) { obj
->h(); }
186 struct X
: A
, virtual Empty
{
188 // CHECK-LABEL: VFTable for 'A' in 'Test6::X' (2 entries).
189 // CHECK-NEXT: 0 | void A::f()
190 // CHECK-NEXT: 1 | void A::z()
192 // CHECK-NOT: VFTable indices for 'Test6::X'
194 // MANGLING-DAG: @"??_7X@Test6@@6B@"
203 // MANGLING-DAG: @"??_7X@Test7@@6B@"
206 struct Y
: virtual X
{
208 // CHECK-LABEL: VFTable for 'A' in 'C' in 'Test7::X' in 'Test7::Y' (2 entries).
209 // CHECK-NEXT: 0 | void C::f()
210 // CHECK-NEXT: [this adjustment: 8 non-virtual]
211 // CHECK-NEXT: 1 | void A::z()
213 // CHECK-LABEL: Thunks for 'void C::f()' (1 entry).
214 // CHECK-NEXT: 0 | [this adjustment: 8 non-virtual]
216 // CHECK-NOT: VFTable indices for 'Test7::Y'
218 // MANGLING-DAG: @"??_7Y@Test7@@6B@"
226 // This is a typical diamond inheritance with a shared 'A' vbase.
228 // CHECK-LABEL: VFTable for 'D' in 'Test8::X' (1 entry).
229 // CHECK-NEXT: 0 | void D::h()
231 // CHECK-LABEL: VFTable for 'A' in 'D' in 'Test8::X' (2 entries).
232 // CHECK-NEXT: 0 | void Test8::X::f()
233 // CHECK-NEXT: 1 | void A::z()
235 // CHECK-LABEL: VFTable indices for 'Test8::X' (1 entry).
236 // CHECK-NEXT: via vbtable index 1, vfptr at offset 0
237 // CHECK-NEXT: 0 | void Test8::X::f()
239 // MANGLING-DAG: @"??_7X@Test8@@6BA@@@"
240 // MANGLING-DAG: @"??_7X@Test8@@6BD@@@"
246 void use(X
*obj
) { obj
->f(); }
248 // Another diamond inheritance which led to AST crashes.
249 struct Y
: virtual A
{};
252 // CHECK-LABEL: VFTable for 'A' in 'Test8::Y' in 'Test8::Z' (2 entries).
253 // CHECK-NEXT: 0 | void Test8::Z::f()
254 // CHECK-NEXT: 1 | void A::z()
256 // CHECK-LABEL: VFTable indices for 'Test8::Z' (1 entry).
257 // CHECK-NEXT: via vbtable index 1, vfptr at offset 0
258 // CHECK-NEXT: 0 | void Test8::Z::f()
262 void use(Z
*obj
) { obj
->f(); }
264 // Another diamond inheritance which we miscompiled (PR18967).
265 struct W
: virtual A
{
270 // CHECK-LABEL: VFTable for 'Test8::W' in 'Test8::T' (1 entry)
271 // CHECK-NEXT: 0 | void Test8::T::bar()
273 // CHECK-LABEL: VFTable for 'A' in 'Test8::W' in 'Test8::T' (2 entries)
274 // CHECK-NEXT: 0 | void C::f()
275 // CHECK-NEXT: [this adjustment: -4 non-virtual]
276 // CHECK-NEXT: 1 | void A::z()
278 // CHECK-LABEL: Thunks for 'void C::f()' (1 entry).
279 // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual]
284 void use(T
*obj
) { obj
->bar(); }
291 struct Y
: virtual X
{
292 // CHECK-LABEL: VFTable for 'Test9::Y' (1 entry).
293 // CHECK-NEXT: 0 | void Test9::Y::h()
295 // CHECK-LABEL: VFTable for 'A' in 'Test9::X' in 'Test9::Y' (2 entries).
296 // CHECK-NEXT: 0 | void A::f()
297 // CHECK-NEXT: 1 | void A::z()
299 // CHECK-LABEL: VFTable indices for 'Test9::Y' (1 entry).
300 // CHECK-NEXT: 0 | void Test9::Y::h()
302 // MANGLING-DAG: @"??_7Y@Test9@@6B01@@"
303 // MANGLING-DAG: @"??_7Y@Test9@@6BX@1@@"
309 void use(Y
*obj
) { obj
->h(); }
311 struct Z
: Y
, virtual B
{
313 // CHECK-LABEL: VFTable for 'Test9::Y' in 'Test9::Z' (1 entry).
314 // CHECK-NEXT: 0 | void Test9::Y::h()
316 // CHECK-LABEL: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' (2 entries).
317 // CHECK-NEXT: 0 | void A::f()
318 // CHECK-NEXT: 1 | void A::z()
320 // CHECK-LABEL: VFTable for 'B' in 'Test9::Z' (1 entry).
321 // CHECK-NEXT: 0 | void B::g()
323 // CHECK-NOT: VFTable indices for 'Test9::Z'
325 // MANGLING-DAG: @"??_7Z@Test9@@6BX@1@@"
326 // MANGLING-DAG: @"??_7Z@Test9@@6BY@1@@"
328 // MANGLING-DAG: @"??_7Z@Test9@@6B@"
333 struct W
: Z
, D
, virtual A
, virtual B
{
335 // CHECK-LABEL: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::W' (1 entry).
336 // CHECK-NEXT: 0 | void Test9::Y::h()
338 // CHECK-LABEL: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::W' (2 entries).
339 // CHECK-NEXT: 0 | void A::f()
340 // CHECK-NEXT: 1 | void A::z()
342 // CHECK-LABEL: VFTable for 'B' in 'Test9::Z' in 'Test9::W' (1 entry).
343 // CHECK-NEXT: 0 | void B::g()
345 // CHECK-LABEL: VFTable for 'D' in 'Test9::W' (1 entry).
346 // CHECK-NEXT: 0 | void D::h()
348 // CHECK-LABEL: VFTable for 'A' in 'D' in 'Test9::W' (2 entries).
349 // CHECK-NEXT: 0 | void D::f()
350 // CHECK-NEXT: [this adjustment: -8 non-virtual]
351 // CHECK-NEXT: 1 | void A::z()
353 // CHECK-LABEL: Thunks for 'void D::f()' (1 entry).
354 // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual]
356 // CHECK-NOT: VFTable indices for 'Test9::W'
358 // MANGLING-DAG: @"??_7W@Test9@@6BA@@@"
359 // MANGLING-DAG: @"??_7W@Test9@@6BD@@@"
360 // MANGLING-DAG: @"??_7W@Test9@@6BX@1@@"
362 // MANGLING-DAG: @"??_7W@Test9@@6B@"
363 // MANGLING-DAG: @"??_7W@Test9@@6BY@1@@"
368 struct T
: Z
, D
, virtual A
, virtual B
{
369 // CHECK-LABEL: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::T' (1 entry).
370 // CHECK-NEXT: 0 | void Test9::T::h()
372 // CHECK-LABEL: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::T' (2 entries).
373 // CHECK-NEXT: 0 | void Test9::T::f()
374 // CHECK-NEXT: 1 | void Test9::T::z()
376 // CHECK-LABEL: VFTable for 'B' in 'Test9::Z' in 'Test9::T' (1 entry).
377 // CHECK-NEXT: 0 | void Test9::T::g()
379 // CHECK-LABEL: VFTable for 'D' in 'Test9::T' (1 entry).
380 // CHECK-NEXT: 0 | void Test9::T::h()
381 // CHECK-NEXT: [this adjustment: -8 non-virtual]
383 // CHECK-LABEL: Thunks for 'void Test9::T::h()' (1 entry).
384 // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual]
386 // CHECK-LABEL: VFTable for 'A' in 'D' in 'Test9::T' (2 entries).
387 // CHECK-NEXT: 0 | void Test9::T::f()
388 // CHECK-NEXT: [this adjustment: -8 non-virtual]
389 // CHECK-NEXT: 1 | void Test9::T::z()
390 // CHECK-NEXT: [this adjustment: -8 non-virtual]
392 // CHECK-LABEL: Thunks for 'void Test9::T::f()' (1 entry).
393 // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual]
395 // CHECK-LABEL: Thunks for 'void Test9::T::z()' (1 entry).
396 // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual]
398 // CHECK-LABEL: VFTable indices for 'Test9::T' (4 entries).
399 // CHECK-NEXT: via vfptr at offset 0
400 // CHECK-NEXT: 0 | void Test9::T::h()
401 // CHECK-NEXT: via vbtable index 1, vfptr at offset 0
402 // CHECK-NEXT: 0 | void Test9::T::f()
403 // CHECK-NEXT: 1 | void Test9::T::z()
404 // CHECK-NEXT: via vbtable index 2, vfptr at offset 0
405 // CHECK-NEXT: 0 | void Test9::T::g()
407 // MANGLING-DAG: @"??_7T@Test9@@6BA@@@"
408 // MANGLING-DAG: @"??_7T@Test9@@6BD@@@"
409 // MANGLING-DAG: @"??_7T@Test9@@6BX@1@@"
411 // MANGLING-DAG: @"??_7T@Test9@@6B@"
412 // MANGLING-DAG: @"??_7T@Test9@@6BY@1@@"
421 void use(T
*obj
) { obj
->f(); }
425 struct X
: virtual C
, virtual A
{
426 // CHECK-LABEL: VFTable for 'A' in 'C' in 'Test10::X' (2 entries).
427 // CHECK-NEXT: 0 | void Test10::X::f()
428 // CHECK-NEXT: 1 | void A::z()
430 // CHECK-LABEL: VFTable indices for 'Test10::X' (1 entry).
431 // CHECK-NEXT: via vbtable index 1, vfptr at offset 0
432 // CHECK-NEXT: 0 | void Test10::X::f()
438 void use(X
*obj
) { obj
->f(); }
442 struct X
: virtual A
{};
443 struct Y
{ virtual void g(); };
445 struct Z
: virtual X
, Y
{
446 // MANGLING-DAG: @"??_7Z@Test11@@6BY@1@@"
447 // MANGLING-DAG: @"??_7Z@Test11@@6BX@1@@"
452 struct W
: virtual X
, A
{};
454 // Used to crash, PR17748.
462 virtual void f(); // Overrides A::f.
465 struct Z
: virtual Y
{
466 // CHECK-LABEL: VFTable for 'A' in 'Test12::X' in 'Test12::Y' in 'Test12::Z' (2 entries).
467 // CHECK-NEXT: 0 | void Test12::Y::f()
468 // CHECK-NEXT: 1 | void A::z()
471 // MANGLING-DAG: @"??_7Z@Test12@@6BA@@@" = {{.*}}@"?f@Y@Test12@@UAEXXZ"
475 // CHECK-LABEL: VFTable for 'A' in 'Test12::X' in 'Test12::Y' in 'Test12::Z' in 'Test12::W' (2 entries).
476 // CHECK-NEXT: 0 | void Test12::Y::f()
477 // CHECK-NEXT: 1 | void A::z()
481 // MANGLING-DAG: @"??_7W@Test12@@6BA@@@" = {{.*}}@"?f@Y@Test12@@UAEXXZ"
493 struct Y
: virtual X
{
494 // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::Y' (2 entries).
495 // CHECK-NEXT: 0 | vdtors::Y::~Y() [scalar deleting]
496 // CHECK-NEXT: 1 | void vdtors::X::zzz()
498 // CHECK-NOT: Thunks for 'vdtors::Y::~Y()'
503 void use(Y
*obj
) { delete obj
; }
510 // Implicit virtual dtor.
513 struct U
: virtual W
{
514 // CHECK-LABEL: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::U' (1 entry).
515 // CHECK-NEXT: 0 | void vdtors::Z::z()
517 // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::W' in 'vdtors::U' (2 entries).
518 // CHECK-NEXT: 0 | vdtors::U::~U() [scalar deleting]
519 // CHECK-NEXT: [this adjustment: -4 non-virtual]
520 // CHECK-NEXT: 1 | void vdtors::X::zzz()
522 // CHECK-LABEL: Thunks for 'vdtors::U::~U()' (1 entry).
523 // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual]
525 // CHECK-LABEL: VFTable indices for 'vdtors::U' (1 entry).
526 // CHECK-NEXT: -- accessible via vbtable index 1, vfptr at offset 4 --
527 // CHECK-NEXT: 0 | vdtors::U::~U() [scalar deleting]
532 void use(U
*obj
) { delete obj
; }
534 struct V
: virtual W
{
535 // CHECK-LABEL: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::V' (1 entry).
536 // CHECK-NEXT: 0 | void vdtors::Z::z()
538 // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::W' in 'vdtors::V' (2 entries).
539 // CHECK-NEXT: 0 | vdtors::V::~V() [scalar deleting]
540 // CHECK-NEXT: [this adjustment: -4 non-virtual]
541 // CHECK-NEXT: 1 | void vdtors::X::zzz()
543 // CHECK-LABEL: Thunks for 'vdtors::V::~V()' (1 entry).
544 // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual]
546 // CHECK-LABEL: VFTable indices for 'vdtors::V' (1 entry).
547 // CHECK-NEXT: -- accessible via vbtable index 1, vfptr at offset 4 --
548 // CHECK-NEXT: 0 | vdtors::V::~V() [scalar deleting]
552 void use(V
*obj
) { delete obj
; }
554 struct T
: virtual X
{
559 // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::T' in 'vdtors::P' (2 entries).
560 // CHECK-NEXT: 0 | vdtors::P::~P() [scalar deleting]
561 // CHECK-NEXT: 1 | void vdtors::X::zzz()
563 // CHECK-NOT: Thunks for 'vdtors::P::~P()'
568 void use(P
*obj
) { delete obj
; }
574 // PR19172: Yet another diamond we miscompiled.
575 struct R
: virtual Q
, X
{
576 // CHECK-LABEL: VFTable for 'vdtors::Q' in 'vdtors::R' (1 entry).
577 // CHECK-NEXT: 0 | vdtors::R::~R() [scalar deleting]
578 // CHECK-NEXT: [this adjustment: -8 non-virtual]
580 // CHECK-LABEL: Thunks for 'vdtors::R::~R()' (1 entry).
581 // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual]
583 // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::R' (2 entries).
584 // CHECK-NEXT: 0 | vdtors::R::~R() [scalar deleting]
585 // CHECK-NEXT: 1 | void vdtors::X::zzz()
587 // CHECK-LABEL: VFTable indices for 'vdtors::R' (1 entry).
588 // CHECK-NEXT: 0 | vdtors::R::~R() [scalar deleting]
593 void use(R
*obj
) { delete obj
; }
596 namespace return_adjustment
{
598 struct X
: virtual A
{
602 struct Y
: virtual A
, virtual X
{
611 // CHECK-LABEL: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' (2 entries).
612 // CHECK-NEXT: 0 | X *return_adjustment::W::foo()
613 // CHECK-NEXT: [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual]
614 // CHECK-NEXT: 1 | X *return_adjustment::W::foo()
616 // CHECK-LABEL: Thunks for 'X *return_adjustment::W::foo()' (1 entry).
617 // CHECK-NEXT: 0 | [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual]
619 // CHECK-LABEL: VFTable indices for 'return_adjustment::W' (1 entry).
620 // CHECK-NEXT: 1 | X *return_adjustment::W::foo()
626 void use(W
*obj
) { obj
->foo(); }
629 // CHECK-LABEL: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' in 'return_adjustment::T' (3 entries).
630 // CHECK-NEXT: 0 | Y *return_adjustment::T::foo()
631 // CHECK-NEXT: [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual]
632 // CHECK-NEXT: 1 | Y *return_adjustment::T::foo()
633 // CHECK-NEXT: [return adjustment (to type 'struct return_adjustment::X *'): vbase #2, 0 non-virtual]
634 // CHECK-NEXT: 2 | Y *return_adjustment::T::foo()
636 // CHECK-LABEL: Thunks for 'Y *return_adjustment::T::foo()' (2 entries).
637 // CHECK-NEXT: 0 | [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual]
638 // CHECK-NEXT: 1 | [return adjustment (to type 'struct return_adjustment::X *'): vbase #2, 0 non-virtual]
640 // CHECK-LABEL: VFTable indices for 'return_adjustment::T' (1 entry).
641 // CHECK-NEXT: 2 | Y *return_adjustment::T::foo()
647 void use(T
*obj
) { obj
->foo(); }
649 struct U
: virtual A
{
650 virtual void g(); // adds a vfptr
654 // CHECK-LABEL: VFTable for 'return_adjustment::Z' in 'return_adjustment::V' (2 entries).
655 // CHECK-NEXT: 0 | U *return_adjustment::V::foo()
656 // CHECK-NEXT: [return adjustment (to type 'struct A *'): vbptr at offset 4, vbase #1, 0 non-virtual]
657 // CHECK-NEXT: 1 | U *return_adjustment::V::foo()
659 // CHECK-LABEL: Thunks for 'U *return_adjustment::V::foo()' (1 entry).
660 // CHECK-NEXT: 0 | [return adjustment (to type 'struct A *'): vbptr at offset 4, vbase #1, 0 non-virtual]
662 // CHECK-LABEL: VFTable indices for 'return_adjustment::V' (1 entry).
663 // CHECK-NEXT: 1 | U *return_adjustment::V::foo()
669 void use(V
*obj
) { obj
->foo(); }
677 struct B
: virtual A
{
681 struct C
: virtual B
, A
{
686 // MANGLING-DAG: @"??_7A@pr17748@@6B@"
687 // MANGLING-DAG: @"??_7B@pr17748@@6B@"
688 // MANGLING-DAG: @"??_7C@pr17748@@6BA@1@@"
689 // MANGLING-DAG: @"??_7C@pr17748@@6BB@1@@"
693 struct X
: virtual B
{};
695 struct Y
: virtual X
, B
{
697 // CHECK-LABEL: VFTable for 'B' in 'pr19066::X' in 'pr19066::Y' (1 entry).
698 // CHECK-NEXT: 0 | void B::g()
700 // CHECK-LABEL: VFTable for 'B' in 'pr19066::Y' (1 entry).
701 // CHECK-NEXT: 0 | void B::g()
712 struct B
: virtual A
{
718 struct D
: virtual A
, virtual C
, B
{};
722 // Each MDC only has one vftable.
724 // MANGLING-DAG: @"??_7D@pr19240@@6B@"
725 // MANGLING-DAG: @"??_7A@pr19240@@6B@"
726 // MANGLING-DAG: @"??_7B@pr19240@@6B@"
731 // This test is a non-vtordisp version of the reproducer for PR19408.
732 struct X
: virtual A
{
742 // CHECK-LABEL: VFTable for 'A' in 'pr19408::X' in 'pr19408::Y' in 'pr19408::Z' (2 entries).
743 // CHECK-NEXT: 0 | void pr19408::Y::f()
744 // CHECK-NEXT: [this adjustment: -4 non-virtual]
745 // CHECK-NEXT: 1 | void A::z()
749 // MANGLING-DAG: @"??_7Z@pr19408@@6B@" = {{.*}}@"?f@Y@pr19408@@W3AEXXZ"
755 // CHECK-LABEL: VFTable for 'A' in 'pr19408::X' in 'pr19408::Y' in 'pr19408::W' (2 entries).
756 // CHECK-NEXT: 0 | void pr19408::Y::f()
757 // CHECK-NEXT: [this adjustment: -4 non-virtual]
758 // CHECK-NEXT: 1 | void A::z()
762 // MANGLING-DAG: @"??_7W@pr19408@@6BY@1@@" = {{.*}}@"?f@Y@pr19408@@W3AEXXZ"
772 struct __declspec(dllexport
) B
: virtual A
{
773 virtual void f() = 0;
774 // MANGLING-DAG: @"??_7B@Test13@@6B@" = weak_odr dllexport unnamed_addr constant { [1 x ptr] } { [1 x ptr] [ptr @_purecall] }
778 namespace pr21031_1
{
779 // This ordering of base specifiers regressed in r202425.
780 struct A
{ virtual void f(void); };
781 struct B
: virtual A
{ virtual void g(void); };
782 struct C
: virtual A
, B
{ C(); };
785 // CHECK-LABEL: VFTable for 'pr21031_1::A' in 'pr21031_1::B' in 'pr21031_1::C' (1 entry)
786 // CHECK-NEXT: 0 | void pr21031_1::A::f()
788 // CHECK-LABEL: VFTable for 'pr21031_1::B' in 'pr21031_1::C' (1 entry)
789 // CHECK-NEXT: 0 | void pr21031_1::B::g()
791 // MANGLING-DAG: @"??_7C@pr21031_1@@6BB@1@@" = {{.*}} constant { [1 x ptr] }
792 // MANGLING-DAG: @"??_7C@pr21031_1@@6B@" = {{.*}} constant { [1 x ptr] }
795 namespace pr21031_2
{
796 struct A
{ virtual void f(void); };
797 struct B
: virtual A
{ virtual void g(void); };
798 struct C
: B
, virtual A
{ C(); };
801 // CHECK-LABEL: VFTable for 'pr21031_2::B' in 'pr21031_2::C' (1 entry)
802 // CHECK-NEXT: 0 | void pr21031_2::B::g()
804 // CHECK-LABEL: VFTable for 'pr21031_2::A' in 'pr21031_2::B' in 'pr21031_2::C' (1 entry)
805 // CHECK-NEXT: 0 | void pr21031_2::A::f()
807 // MANGLING-DAG: @"??_7C@pr21031_2@@6BA@1@@" = {{.*}} constant { [1 x ptr] }
808 // MANGLING-DAG: @"??_7C@pr21031_2@@6BB@1@@" = {{.*}} constant { [1 x ptr] }
811 namespace pr21062_1
{
812 struct A
{ virtual void f(); };
814 struct C
: virtual B
{};
815 struct D
: virtual C
, virtual B
, virtual A
{ D();};
818 // CHECK-LABEL: VFTable for 'pr21062_1::A' in 'pr21062_1::D' (1 entry)
819 // CHECK-NEXT: 0 | void pr21062_1::A::f()
821 // MANGLING-DAG: @"??_7D@pr21062_1@@6B@" = {{.*}} constant { [1 x ptr] }
824 namespace pr21062_2
{
825 struct A
{ virtual void f(); };
827 struct C
: virtual B
{};
828 struct D
: C
, virtual B
, virtual A
{ D(); };
831 // CHECK-LABEL: VFTable for 'pr21062_2::A' in 'pr21062_2::D' (1 entry)
832 // CHECK-NEXT: 0 | void pr21062_2::A::f()
834 // MANGLING-DAG: @"??_7D@pr21062_2@@6B@" = {{.*}} constant { [1 x ptr] }
839 struct B
{ virtual void f(); };
840 struct C
: virtual A
, virtual B
{};
841 struct D
: virtual A
, virtual C
{ D(); };
843 // CHECK-LABEL: VFTable for 'pr21064::B' in 'pr21064::C' in 'pr21064::D' (1 entry)
844 // CHECK-NEXT: 0 | void pr21064::B::f()
846 // MANGLING-DAG: @"??_7D@pr21064@@6B@" = {{.*}} constant { [1 x ptr] }