head 1.1; branch 1.1.1; access; symbols netbsd-11-0-RC5:1.1.1.11 netbsd-11-0-RC4:1.1.1.11 netbsd-11-0-RC3:1.1.1.11 netbsd-11-0-RC2:1.1.1.11 netbsd-11-0-RC1:1.1.1.11 perseant-exfatfs-base-20250801:1.1.1.11 netbsd-11:1.1.1.11.0.10 netbsd-11-base:1.1.1.11 netbsd-10-1-RELEASE:1.1.1.11 perseant-exfatfs-base-20240630:1.1.1.11 perseant-exfatfs:1.1.1.11.0.8 perseant-exfatfs-base:1.1.1.11 netbsd-8-3-RELEASE:1.1.1.9 netbsd-9-4-RELEASE:1.1.1.10 netbsd-10-0-RELEASE:1.1.1.11 netbsd-10-0-RC6:1.1.1.11 netbsd-10-0-RC5:1.1.1.11 netbsd-10-0-RC4:1.1.1.11 netbsd-10-0-RC3:1.1.1.11 netbsd-10-0-RC2:1.1.1.11 netbsd-10-0-RC1:1.1.1.11 netbsd-10:1.1.1.11.0.6 netbsd-10-base:1.1.1.11 netbsd-9-3-RELEASE:1.1.1.10 cjep_sun2x:1.1.1.11.0.4 cjep_sun2x-base:1.1.1.11 cjep_staticlib_x-base1:1.1.1.11 netbsd-9-2-RELEASE:1.1.1.10 cjep_staticlib_x:1.1.1.11.0.2 cjep_staticlib_x-base:1.1.1.11 netbsd-9-1-RELEASE:1.1.1.10 phil-wifi-20200421:1.1.1.11 phil-wifi-20200411:1.1.1.11 phil-wifi-20200406:1.1.1.11 netbsd-8-2-RELEASE:1.1.1.9 netbsd-9-0-RELEASE:1.1.1.10 netbsd-9-0-RC2:1.1.1.10 netbsd-9-0-RC1:1.1.1.10 netbsd-9:1.1.1.10.0.2 netbsd-9-base:1.1.1.10 phil-wifi-20190609:1.1.1.10 netbsd-8-1-RELEASE:1.1.1.9 netbsd-8-1-RC1:1.1.1.9 pgoyette-compat-merge-20190127:1.1.1.9.12.1 pgoyette-compat-20190127:1.1.1.10 pgoyette-compat-20190118:1.1.1.10 pgoyette-compat-1226:1.1.1.10 pgoyette-compat-1126:1.1.1.10 pgoyette-compat-1020:1.1.1.10 pgoyette-compat-0930:1.1.1.10 pgoyette-compat-0906:1.1.1.10 netbsd-7-2-RELEASE:1.1.1.6.2.1 pgoyette-compat-0728:1.1.1.10 clang-337282:1.1.1.10 netbsd-8-0-RELEASE:1.1.1.9 phil-wifi:1.1.1.9.0.14 phil-wifi-base:1.1.1.9 pgoyette-compat-0625:1.1.1.9 netbsd-8-0-RC2:1.1.1.9 pgoyette-compat-0521:1.1.1.9 pgoyette-compat-0502:1.1.1.9 pgoyette-compat-0422:1.1.1.9 netbsd-8-0-RC1:1.1.1.9 pgoyette-compat-0415:1.1.1.9 pgoyette-compat-0407:1.1.1.9 pgoyette-compat-0330:1.1.1.9 pgoyette-compat-0322:1.1.1.9 pgoyette-compat-0315:1.1.1.9 netbsd-7-1-2-RELEASE:1.1.1.6.2.1 pgoyette-compat:1.1.1.9.0.12 pgoyette-compat-base:1.1.1.9 netbsd-7-1-1-RELEASE:1.1.1.6.2.1 clang-319952:1.1.1.9 matt-nb8-mediatek:1.1.1.9.0.10 matt-nb8-mediatek-base:1.1.1.9 clang-309604:1.1.1.9 perseant-stdc-iso10646:1.1.1.9.0.8 perseant-stdc-iso10646-base:1.1.1.9 netbsd-8:1.1.1.9.0.6 netbsd-8-base:1.1.1.9 prg-localcount2-base3:1.1.1.9 prg-localcount2-base2:1.1.1.9 prg-localcount2-base1:1.1.1.9 prg-localcount2:1.1.1.9.0.4 prg-localcount2-base:1.1.1.9 pgoyette-localcount-20170426:1.1.1.9 bouyer-socketcan-base1:1.1.1.9 pgoyette-localcount-20170320:1.1.1.9 netbsd-7-1:1.1.1.6.2.1.0.6 netbsd-7-1-RELEASE:1.1.1.6.2.1 netbsd-7-1-RC2:1.1.1.6.2.1 clang-294123:1.1.1.9 netbsd-7-nhusb-base-20170116:1.1.1.6.2.1 bouyer-socketcan:1.1.1.9.0.2 bouyer-socketcan-base:1.1.1.9 clang-291444:1.1.1.9 pgoyette-localcount-20170107:1.1.1.8 netbsd-7-1-RC1:1.1.1.6.2.1 pgoyette-localcount-20161104:1.1.1.8 netbsd-7-0-2-RELEASE:1.1.1.6.2.1 localcount-20160914:1.1.1.8 netbsd-7-nhusb:1.1.1.6.2.1.0.4 netbsd-7-nhusb-base:1.1.1.6.2.1 clang-280599:1.1.1.8 pgoyette-localcount-20160806:1.1.1.8 pgoyette-localcount-20160726:1.1.1.8 pgoyette-localcount:1.1.1.8.0.2 pgoyette-localcount-base:1.1.1.8 netbsd-7-0-1-RELEASE:1.1.1.6.2.1 clang-261930:1.1.1.8 netbsd-7-0:1.1.1.6.2.1.0.2 netbsd-7-0-RELEASE:1.1.1.6.2.1 netbsd-7-0-RC3:1.1.1.6.2.1 netbsd-7-0-RC2:1.1.1.6.2.1 netbsd-7-0-RC1:1.1.1.6.2.1 clang-237755:1.1.1.7 clang-232565:1.1.1.7 clang-227398:1.1.1.7 tls-maxphys-base:1.1.1.6 tls-maxphys:1.1.1.6.0.4 netbsd-7:1.1.1.6.0.2 netbsd-7-base:1.1.1.6 clang-215315:1.1.1.6 clang-209886:1.1.1.5 yamt-pagecache:1.1.1.4.0.4 yamt-pagecache-base9:1.1.1.4 tls-earlyentropy:1.1.1.4.0.2 tls-earlyentropy-base:1.1.1.5 riastradh-xf86-video-intel-2-7-1-pre-2-21-15:1.1.1.4 riastradh-drm2-base3:1.1.1.4 clang-202566:1.1.1.4 clang-201163:1.1.1.3 clang-199312:1.1.1.3 clang-198450:1.1.1.2 clang-196603:1.1.1.1 clang-195771:1.1.1.1 LLVM:1.1.1; locks; strict; comment @// @; 1.1 date 2013.11.28.14.14.58; author joerg; state Exp; branches 1.1.1.1; next ; commitid ow8OybrawrB1f3fx; 1.1.1.1 date 2013.11.28.14.14.58; author joerg; state Exp; branches; next 1.1.1.2; commitid ow8OybrawrB1f3fx; 1.1.1.2 date 2014.01.05.15.40.09; author joerg; state Exp; branches; next 1.1.1.3; commitid wh3aCSIWykURqWjx; 1.1.1.3 date 2014.01.15.21.26.09; author joerg; state Exp; branches; next 1.1.1.4; commitid NQXlzzA0SPkc5glx; 1.1.1.4 date 2014.03.04.19.55.42; author joerg; state Exp; branches 1.1.1.4.2.1 1.1.1.4.4.1; next 1.1.1.5; commitid 29z1hJonZISIXprx; 1.1.1.5 date 2014.05.30.18.14.47; author joerg; state Exp; branches; next 1.1.1.6; commitid 8q0kdlBlCn09GACx; 1.1.1.6 date 2014.08.10.17.08.40; author joerg; state Exp; branches 1.1.1.6.2.1 1.1.1.6.4.1; next 1.1.1.7; commitid N85tXAN6Ex9VZPLx; 1.1.1.7 date 2015.01.29.19.57.35; author joerg; state Exp; branches; next 1.1.1.8; commitid mlISSizlPKvepX7y; 1.1.1.8 date 2016.02.27.22.10.23; author joerg; state Exp; branches 1.1.1.8.2.1; next 1.1.1.9; commitid tIimz3oDlh1NpBWy; 1.1.1.9 date 2017.01.11.10.40.06; author joerg; state Exp; branches 1.1.1.9.12.1 1.1.1.9.14.1; next 1.1.1.10; commitid CNnUNfII1jgNmxBz; 1.1.1.10 date 2018.07.17.18.31.27; author joerg; state Exp; branches; next 1.1.1.11; commitid wDzL46ALjrCZgwKA; 1.1.1.11 date 2019.11.13.22.20.15; author joerg; state dead; branches; next ; commitid QD8YATxuNG34YJKB; 1.1.1.4.2.1 date 2014.08.10.07.08.14; author tls; state Exp; branches; next ; commitid t01A1TLTYxkpGMLx; 1.1.1.4.4.1 date 2014.03.04.19.55.42; author yamt; state dead; branches; next 1.1.1.4.4.2; commitid WSrDtL5nYAUyiyBx; 1.1.1.4.4.2 date 2014.05.22.16.18.57; author yamt; state Exp; branches; next ; commitid WSrDtL5nYAUyiyBx; 1.1.1.6.2.1 date 2015.06.04.20.04.34; author snj; state Exp; branches; next ; commitid yRnjq9fueSo6n9oy; 1.1.1.6.4.1 date 2014.08.10.17.08.40; author tls; state dead; branches; next 1.1.1.6.4.2; commitid jTnpym9Qu0o4R1Nx; 1.1.1.6.4.2 date 2014.08.19.23.47.58; author tls; state Exp; branches; next ; commitid jTnpym9Qu0o4R1Nx; 1.1.1.8.2.1 date 2017.03.20.06.52.59; author pgoyette; state Exp; branches; next ; commitid jjw7cAwgyKq7RfKz; 1.1.1.9.12.1 date 2018.07.28.04.33.42; author pgoyette; state Exp; branches; next ; commitid 1UP1xAIUxv1ZgRLA; 1.1.1.9.14.1 date 2019.06.10.21.45.52; author christos; state Exp; branches; next 1.1.1.9.14.2; commitid jtc8rnCzWiEEHGqB; 1.1.1.9.14.2 date 2020.04.13.07.47.29; author martin; state dead; branches; next ; commitid X01YhRUPVUDaec4C; desc @@ 1.1 log @Initial revision @ text @// RUN: %clang_cc1 -fno-rtti -emit-llvm -o %t.ll -fdump-vtable-layouts %s -cxx-abi microsoft -triple=i386-pc-win32 >%t // RUN: FileCheck --check-prefix=VTABLE-C %s < %t // RUN: FileCheck --check-prefix=VTABLE-D %s < %t // RUN: FileCheck --check-prefix=TEST1 %s < %t // RUN: FileCheck --check-prefix=TEST2 %s < %t // RUN: FileCheck --check-prefix=TEST3 %s < %t // RUN: FileCheck --check-prefix=TEST4 %s < %t // RUN: FileCheck --check-prefix=TEST5 %s < %t // RUN: FileCheck --check-prefix=TEST6 %s < %t // RUN: FileCheck --check-prefix=TEST7 %s < %t // RUN: FileCheck --check-prefix=TEST8-X %s < %t // RUN: FileCheck --check-prefix=TEST8-Z %s < %t // RUN: FileCheck --check-prefix=TEST9-Y %s < %t // RUN: FileCheck --check-prefix=TEST9-Z %s < %t // RUN: FileCheck --check-prefix=TEST9-W %s < %t // RUN: FileCheck --check-prefix=TEST9-T %s < %t // RUN: FileCheck --check-prefix=TEST10 %s < %t // RUN: FileCheck --check-prefix=VDTORS-Y %s < %t // RUN: FileCheck --check-prefix=VDTORS-U %s < %t // RUN: FileCheck --check-prefix=VDTORS-V %s < %t // RUN: FileCheck --check-prefix=VDTORS-P %s < %t // RUN: FileCheck --check-prefix=RET-W %s < %t // RUN: FileCheck --check-prefix=RET-T %s < %t // RUN: FileCheck --check-prefix=RET-V %s < %t // RUN: FileCheck --check-prefix=MANGLING %s < %t.ll struct Empty { }; struct A { virtual void f(); virtual void z(); // Useful to check there are no thunks for f() when appropriate. }; struct B { virtual void g(); }; struct C: virtual A { // VTABLE-C: VFTable for 'A' in 'C' (2 entries) // VTABLE-C-NEXT: 0 | void C::f() // VTABLE-C-NEXT: 1 | void A::z() // VTABLE-C: VFTable indices for 'C' (1 entries) // VTABLE-C-NEXT: vbtable index 1, vfptr at offset 0 // VTABLE-C-NEXT: 0 | void C::f() // MANGLING-DAG: @@"\01??_7C@@@@6B@@" virtual void f(); }; C c; struct D: virtual A { // VTABLE-D: VFTable for 'D' (1 entries). // VTABLE-D-NEXT: 0 | void D::h() // VTABLE-D: VFTable for 'A' in 'D' (2 entries). // VTABLE-D-NEXT: 0 | void D::f() // VTABLE-D-NEXT: 1 | void A::z() // VTABLE-D: VFTable indices for 'D' (2 entries). // VTABLE-D-NEXT: via vfptr at offset 0 // VTABLE-D-NEXT: 0 | void D::h() // VTABLE-D-NEXT: via vbtable index 1, vfptr at offset 0 // VTABLE-D-NEXT: 0 | void D::f() // MANGLING-DAG: @@"\01??_7D@@@@6B0@@@@" // MANGLING-DAG: @@"\01??_7D@@@@6BA@@@@@@" virtual void f(); virtual void h(); }; void D::h() {} D d; namespace Test1 { struct X { int x; }; // X and A get reordered in the layout since X doesn't have a vfptr while A has. struct Y : X, A { }; // MANGLING-DAG: @@"\01??_7Y@@Test1@@@@6B@@" struct Z : virtual Y { // TEST1: VFTable for 'A' in 'Test1::Y' in 'Test1::Z' (2 entries). // TEST1-NEXT: 0 | void A::f() // TEST1-NEXT: 1 | void A::z() // TEST1-NOT: VFTable indices for 'Test1::Z' // MANGLING-DAG: @@"\01??_7Z@@Test1@@@@6B@@" }; Z z; } namespace Test2 { struct X: virtual A, virtual B { // TEST2: VFTable for 'Test2::X' (1 entries). // TEST2-NEXT: 0 | void Test2::X::h() // TEST2: VFTable for 'A' in 'Test2::X' (2 entries). // TEST2-NEXT: 0 | void A::f() // TEST2-NEXT: 1 | void A::z() // TEST2: VFTable for 'B' in 'Test2::X' (1 entries). // TEST2-NEXT: 0 | void B::g() // TEST2: VFTable indices for 'Test2::X' (1 entries). // TEST2-NEXT: 0 | void Test2::X::h() // MANGLING-DAG: @@"\01??_7X@@Test2@@@@6B01@@@@" // MANGLING-DAG: @@"\01??_7X@@Test2@@@@6BA@@@@@@" // MANGLING-DAG: @@"\01??_7X@@Test2@@@@6BB@@@@@@" virtual void h(); }; X x; } namespace Test3 { struct X : virtual A { // MANGLING-DAG: @@"\01??_7X@@Test3@@@@6B@@" }; struct Y: virtual X { // TEST3: VFTable for 'A' in 'Test3::X' in 'Test3::Y' (2 entries). // TEST3-NEXT: 0 | void A::f() // TEST3-NEXT: 1 | void A::z() // TEST3-NOT: VFTable indices for 'Test3::Y' // MANGLING-DAG: @@"\01??_7Y@@Test3@@@@6B@@" }; Y y; } namespace Test4 { struct X: virtual C { // This one's interesting. C::f expects (A*) to be passed as 'this' and does // ECX-=4 to cast to (C*). In X, C and A vbases are reordered, so the thunk // should pass a pointer to the end of X in order // for ECX-=4 to point at the C part. // TEST4: VFTable for 'A' in 'C' in 'Test4::X' (2 entries). // TEST4-NEXT: 0 | void C::f() // TEST4-NEXT: [this adjustment: 8 non-virtual] // TEST4-NEXT: 1 | void A::z() // TEST4-NOT: VFTable indices for 'Test4::X' // MANGLING-DAG: @@"\01??_7X@@Test4@@@@6B@@" // Also check the mangling of the thunk. // MANGLING-DAG: define weak x86_thiscallcc void @@"\01?f@@C@@@@WPPPPPPPI@@AEXXZ" }; X x; } namespace Test5 { // New methods are added to the base's vftable. struct X : A { // MANGLING-DAG: @@"\01??_7X@@Test5@@@@6B@@" virtual void g(); }; struct Y : virtual X { // TEST5: VFTable for 'Test5::Y' (1 entries). // TEST5-NEXT: 0 | void Test5::Y::h() // TEST5: VFTable for 'A' in 'Test5::X' in 'Test5::Y' (3 entries). // TEST5-NEXT: 0 | void A::f() // TEST5-NEXT: 1 | void A::z() // TEST5-NEXT: 2 | void Test5::X::g() // TEST5: VFTable indices for 'Test5::Y' (1 entries). // TEST5-NEXT: 0 | void Test5::Y::h() // MANGLING-DAG: @@"\01??_7Y@@Test5@@@@6B01@@@@" // MANGLING-DAG: @@"\01??_7Y@@Test5@@@@6BX@@1@@@@" virtual void h(); }; Y y; } namespace Test6 { struct X : A, virtual Empty { // TEST6: VFTable for 'A' in 'Test6::X' (2 entries). // TEST6-NEXT: 0 | void A::f() // TEST6-NEXT: 1 | void A::z() // TEST6-NOT: VFTable indices for 'Test6::X' // MANGLING-DAG: @@"\01??_7X@@Test6@@@@6B@@" }; X x; } namespace Test7 { struct X : C { // MANGLING-DAG: @@"\01??_7X@@Test7@@@@6B@@" }; struct Y : virtual X { // TEST7: VFTable for 'A' in 'C' in 'Test7::X' in 'Test7::Y' (2 entries). // TEST7-NEXT: 0 | void C::f() // TEST7-NEXT: [this adjustment: 8 non-virtual] // TEST7-NEXT: 1 | void A::z() // TEST7: Thunks for 'void C::f()' (1 entry). // TEST7-NEXT: 0 | [this adjustment: 8 non-virtual] // TEST7-NOT: VFTable indices for 'Test7::Y' // MANGLING-DAG: @@"\01??_7Y@@Test7@@@@6B@@" }; Y y; } namespace Test8 { // This is a typical diamond inheritance with a shared 'A' vbase. struct X : D, C { // TEST8-X: VFTable for 'D' in 'Test8::X' (1 entries). // TEST8-X-NEXT: 0 | void D::h() // TEST8-X: VFTable for 'A' in 'D' in 'Test8::X' (2 entries). // TEST8-X-NEXT: 0 | void Test8::X::f() // TEST8-X-NEXT: 1 | void A::z() // TEST8-X: VFTable indices for 'Test8::X' (1 entries). // TEST8-X-NEXT: via vbtable index 1, vfptr at offset 0 // TEST8-X-NEXT: 0 | void Test8::X::f() // MANGLING-DAG: @@"\01??_7X@@Test8@@@@6BA@@@@@@" // MANGLING-DAG: @@"\01??_7X@@Test8@@@@6BD@@@@@@" virtual void f(); }; X x; // Another diamond inheritance which led to AST crashes. struct Y : virtual A {}; class Z : Y, C { // TEST8-Z: VFTable for 'A' in 'Test8::Y' in 'Test8::Z' (2 entries). // TEST8-Z-NEXT: 0 | void Test8::Z::f() // TEST8-Z-NEXT: 1 | void A::z() // TEST8-Z: VFTable indices for 'Test8::Z' (1 entries). // TEST8-Z-NEXT: via vbtable index 1, vfptr at offset 0 // TEST8-Z-NEXT: 0 | void Test8::Z::f() virtual void f(); }; Z z; } namespace Test9 { struct X : A { }; struct Y : virtual X { // TEST9-Y: VFTable for 'Test9::Y' (1 entries). // TEST9-Y-NEXT: 0 | void Test9::Y::h() // TEST9-Y: VFTable for 'A' in 'Test9::X' in 'Test9::Y' (2 entries). // TEST9-Y-NEXT: 0 | void A::f() // TEST9-Y-NEXT: 1 | void A::z() // TEST9-Y: VFTable indices for 'Test9::Y' (1 entries). // TEST9-Y-NEXT: 0 | void Test9::Y::h() // MANGLING-DAG: @@"\01??_7Y@@Test9@@@@6B01@@@@" // MANGLING-DAG: @@"\01??_7Y@@Test9@@@@6BX@@1@@@@" virtual void h(); }; Y y; struct Z : Y, virtual B { // TEST9-Z: VFTable for 'Test9::Y' in 'Test9::Z' (1 entries). // TEST9-Z-NEXT: 0 | void Test9::Y::h() // TEST9-Z: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' (2 entries). // TEST9-Z-NEXT: 0 | void A::f() // TEST9-Z-NEXT: 1 | void A::z() // TEST9-Z: VFTable for 'B' in 'Test9::Z' (1 entries). // TEST9-Z-NEXT: 0 | void B::g() // TEST9-Z-NOT: VFTable indices for 'Test9::Z' // MANGLING-DAG: @@"\01??_7Z@@Test9@@@@6BX@@1@@@@" // MANGLING-DAG: @@"\01??_7Z@@Test9@@@@6BY@@1@@@@" // FIXME this one is wrong: // INCORRECT MANGLING-DAG: @@"\01??_7Z@@Test9@@@@6BB@@@@@@" // MANGLING-DAG-SHOULD-BE: @@"\01??_7Z@@Test9@@@@6B@@" }; Z z; struct W : Z, D, virtual A, virtual B { // TEST9-W: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::W' (1 entries). // TEST9-W-NEXT: 0 | void Test9::Y::h() // TEST9-W: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::W' (2 entries). // TEST9-W-NEXT: 0 | void A::f() // TEST9-W-NEXT: 1 | void A::z() // TEST9-W: VFTable for 'B' in 'Test9::Z' in 'Test9::W' (1 entries). // TEST9-W-NEXT: 0 | void B::g() // TEST9-W: VFTable for 'D' in 'Test9::W' (1 entries). // TEST9-W-NEXT: 0 | void D::h() // TEST9-W: VFTable for 'A' in 'D' in 'Test9::W' (2 entries). // TEST9-W-NEXT: 0 | void D::f() // TEST9-W-NEXT: [this adjustment: -8 non-virtual] // TEST9-W-NEXT: 1 | void A::z() // TEST9-W: Thunks for 'void D::f()' (1 entry). // TEST9-W-NEXT: 0 | [this adjustment: -8 non-virtual] // TEST9-W-NOT: VFTable indices for 'Test9::W' // MANGLING-DAG: @@"\01??_7W@@Test9@@@@6BA@@@@@@" // MANGLING-DAG: @@"\01??_7W@@Test9@@@@6BD@@@@@@" // MANGLING-DAG: @@"\01??_7W@@Test9@@@@6BX@@1@@@@" // FIXME: these two are wrong: // INCORRECT MANGLING-DAG: @@"\01??_7W@@Test9@@@@6BB@@@@@@" // MANGLING-DAG-SHOULD-BE: @@"\01??_7W@@Test9@@@@6B@@" // INCORRECT MANGLING-DAG: @@"\01??_7W@@Test9@@@@6BY@@1@@Z@@1@@@@" // MANGLING-DAG-SHOULD-BE: @@"\01??_7W@@Test9@@@@6BY@@1@@@@" }; W w; struct T : Z, D, virtual A, virtual B { // TEST9-T: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::T' (1 entries). // TEST9-T-NEXT: 0 | void Test9::T::h() // TEST9-T: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::T' (2 entries). // TEST9-T-NEXT: 0 | void Test9::T::f() // TEST9-T-NEXT: 1 | void Test9::T::z() // TEST9-T: VFTable for 'B' in 'Test9::Z' in 'Test9::T' (1 entries). // TEST9-T-NEXT: 0 | void Test9::T::g() // TEST9-T: VFTable for 'D' in 'Test9::T' (1 entries). // TEST9-T-NEXT: 0 | void Test9::T::h() // TEST9-T-NEXT: [this adjustment: -8 non-virtual] // TEST9-T: Thunks for 'void Test9::T::h()' (1 entry). // TEST9-T-NEXT: 0 | [this adjustment: -8 non-virtual] // TEST9-T: VFTable for 'A' in 'D' in 'Test9::T' (2 entries). // TEST9-T-NEXT: 0 | void Test9::T::f() // TEST9-T-NEXT: [this adjustment: -8 non-virtual] // TEST9-T-NEXT: 1 | void Test9::T::z() // TEST9-T-NEXT: [this adjustment: -8 non-virtual] // TEST9-T: Thunks for 'void Test9::T::f()' (1 entry). // TEST9-T-NEXT: 0 | [this adjustment: -8 non-virtual] // TEST9-T: Thunks for 'void Test9::T::z()' (1 entry). // TEST9-T-NEXT: 0 | [this adjustment: -8 non-virtual] // TEST9-T: VFTable indices for 'Test9::T' (4 entries). // TEST9-T-NEXT: via vfptr at offset 0 // TEST9-T-NEXT: 0 | void Test9::T::h() // TEST9-T-NEXT: via vbtable index 1, vfptr at offset 0 // TEST9-T-NEXT: 0 | void Test9::T::f() // TEST9-T-NEXT: 1 | void Test9::T::z() // TEST9-T-NEXT: via vbtable index 2, vfptr at offset 0 // TEST9-T-NEXT: 0 | void Test9::T::g() // MANGLING-DAG: @@"\01??_7T@@Test9@@@@6BA@@@@@@" // MANGLING-DAG: @@"\01??_7T@@Test9@@@@6BD@@@@@@" // MANGLING-DAG: @@"\01??_7T@@Test9@@@@6BX@@1@@@@" // FIXME: these two are wrong: // INCORRECT MANGLING-DAG: @@"\01??_7T@@Test9@@@@6BB@@@@@@" // MANGLING-DAG-SHOULD-BE: @@"\01??_7T@@Test9@@@@6B@@" // INCORRECT MANGLING-DAG: @@"\01??_7T@@Test9@@@@6BY@@1@@Z@@1@@@@" // MANGLING-DAG-SHOULD-BE: @@"\01??_7T@@Test9@@@@6BY@@1@@@@" virtual void f(); virtual void g(); virtual void h(); virtual void z(); }; T t; } namespace Test10 { struct X : virtual C, virtual A { // TEST10: VFTable for 'A' in 'C' in 'Test10::X' (2 entries). // TEST10-NEXT: 0 | void Test10::X::f() // TEST10-NEXT: 1 | void A::z() // TEST10: VFTable indices for 'Test10::X' (1 entries). // TEST10-NEXT: via vbtable index 1, vfptr at offset 0 // TEST10-NEXT: 0 | void Test10::X::f() virtual void f(); }; void X::f() {} X x; } namespace vdtors { struct X { virtual ~X(); virtual void zzz(); }; struct Y : virtual X { // VDTORS-Y: VFTable for 'vdtors::X' in 'vdtors::Y' (2 entries). // VDTORS-Y-NEXT: 0 | vdtors::Y::~Y() [scalar deleting] // VDTORS-Y-NEXT: 1 | void vdtors::X::zzz() // VDTORS-Y-NOT: Thunks for 'vdtors::Y::~Y()' virtual ~Y(); }; Y y; struct Z { virtual void z(); }; struct W : Z, X { // Implicit virtual dtor. }; struct U : virtual W { // VDTORS-U: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::U' (1 entries). // VDTORS-U-NEXT: 0 | void vdtors::Z::z() // VDTORS-U: VFTable for 'vdtors::X' in 'vdtors::W' in 'vdtors::U' (2 entries). // VDTORS-U-NEXT: 0 | vdtors::U::~U() [scalar deleting] // VDTORS-U-NEXT: [this adjustment: -4 non-virtual] // VDTORS-U-NEXT: 1 | void vdtors::X::zzz() // VDTORS-U: Thunks for 'vdtors::W::~W()' (1 entry). // VDTORS-U-NEXT: 0 | [this adjustment: -4 non-virtual] // VDTORS-U: VFTable indices for 'vdtors::U' (1 entries). // VDTORS-U-NEXT: -- accessible via vbtable index 1, vfptr at offset 4 -- // VDTORS-U-NEXT: 0 | vdtors::U::~U() [scalar deleting] virtual ~U(); }; U u; struct V : virtual W { // VDTORS-V: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::V' (1 entries). // VDTORS-V-NEXT: 0 | void vdtors::Z::z() // VDTORS-V: VFTable for 'vdtors::X' in 'vdtors::W' in 'vdtors::V' (2 entries). // VDTORS-V-NEXT: 0 | vdtors::V::~V() [scalar deleting] // VDTORS-V-NEXT: [this adjustment: -4 non-virtual] // VDTORS-V-NEXT: 1 | void vdtors::X::zzz() // VDTORS-V: Thunks for 'vdtors::W::~W()' (1 entry). // VDTORS-V-NEXT: 0 | [this adjustment: -4 non-virtual] // VDTORS-V: VFTable indices for 'vdtors::V' (1 entries). // VDTORS-V-NEXT: -- accessible via vbtable index 1, vfptr at offset 4 -- // VDTORS-V-NEXT: 0 | vdtors::V::~V() [scalar deleting] }; V v; struct T : virtual X { virtual ~T(); }; struct P : T, Y { // VDTORS-P: VFTable for 'vdtors::X' in 'vdtors::T' in 'vdtors::P' (2 entries). // VDTORS-P-NEXT: 0 | vdtors::P::~P() [scalar deleting] // VDTORS-P-NEXT: 1 | void vdtors::X::zzz() // VDTORS-P-NOT: Thunks for 'vdtors::P::~P()' virtual ~P(); }; P p; } namespace return_adjustment { struct X : virtual A { virtual void f(); }; struct Y : virtual A, virtual X { virtual void f(); }; struct Z { virtual A* foo(); }; struct W : Z { // RET-W: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' (2 entries). // RET-W-NEXT: 0 | return_adjustment::X *return_adjustment::W::foo() // RET-W-NEXT: [return adjustment: vbase #1, 0 non-virtual] // RET-W-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo() // RET-W: VFTable indices for 'return_adjustment::W' (1 entries). // RET-W-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo() virtual X* foo(); }; W y; struct T : W { // RET-T: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' in 'return_adjustment::T' (3 entries). // RET-T-NEXT: 0 | return_adjustment::Y *return_adjustment::T::foo() // RET-T-NEXT: [return adjustment: vbase #1, 0 non-virtual] // RET-T-NEXT: 1 | return_adjustment::Y *return_adjustment::T::foo() // RET-T-NEXT: [return adjustment: vbase #2, 0 non-virtual] // RET-T-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo() // RET-T: VFTable indices for 'return_adjustment::T' (1 entries). // RET-T-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo() virtual Y* foo(); }; T t; struct U : virtual A { virtual void g(); // adds a vfptr }; struct V : Z { // RET-V: VFTable for 'return_adjustment::Z' in 'return_adjustment::V' (2 entries). // RET-V-NEXT: 0 | return_adjustment::U *return_adjustment::V::foo() // RET-V-NEXT: [return adjustment: vbptr at offset 4, vbase #1, 0 non-virtual] // RET-V-NEXT: 1 | return_adjustment::U *return_adjustment::V::foo() // RET-V: VFTable indices for 'return_adjustment::V' (1 entries). // RET-V-NEXT: 1 | return_adjustment::U *return_adjustment::V::foo() virtual U* foo(); }; V v; } @ 1.1.1.1 log @Import Clang 3.4rc1 r195771. @ text @@ 1.1.1.2 log @Import clang 3.5svn r198450. @ text @a432 20 namespace Test11 { struct X : virtual A {}; struct Y { virtual void g(); }; struct Z : virtual X, Y { // MANGLING-DAG: @@"\01??_7Z@@Test11@@@@6BY@@1@@@@" // FIXME this one is wrong: // MANGLING-DAG-SHOULD-BE: @@"\01??_7Z@@Test11@@@@6BX@@1@@@@" // INCORRECT MANGLING-DAG: @@"\01??_7Z@@Test11@@@@6BA@@@@@@" }; Z z; struct W : virtual X, A {}; // PR17748 FIXME this one hits UNREACHABLE: // W w; } @ 1.1.1.3 log @Import Clang 3.5svn r199312 @ text @d1 1 a1 1 // RUN: %clang_cc1 -fno-rtti -emit-llvm -o %t.ll -fdump-vtable-layouts %s -triple=i386-pc-win32 >%t @ 1.1.1.4 log @Import Clang 3.5svn r202566. @ text @d315 3 a317 1 // MANGLING-DAG: @@"\01??_7Z@@Test9@@@@6B@@" d350 5 a354 2 // MANGLING-DAG: @@"\01??_7W@@Test9@@@@6B@@" // MANGLING-DAG: @@"\01??_7W@@Test9@@@@6BY@@1@@@@" d402 5 a406 2 // MANGLING-DAG: @@"\01??_7T@@Test9@@@@6B@@" // MANGLING-DAG: @@"\01??_7T@@Test9@@@@6BY@@1@@@@" d439 4 a442 1 // MANGLING-DAG: @@"\01??_7Z@@Test11@@@@6BX@@1@@@@" a595 20 namespace pr17748 { struct A { virtual void f() {} }; struct B : virtual A { B() {} }; struct C : virtual B, A { C() {} }; C c; // MANGLING-DAG: @@"\01??_7A@@pr17748@@@@6B@@" // MANGLING-DAG: @@"\01??_7B@@pr17748@@@@6B@@" // MANGLING-DAG: @@"\01??_7C@@pr17748@@@@6BA@@1@@@@" // MANGLING-DAG: @@"\01??_7C@@pr17748@@@@6BB@@1@@@@" } @ 1.1.1.4.2.1 log @Rebase. @ text @d2 25 a26 1 // RUN: FileCheck %s < %t d41 7 a47 7 // CHECK-LABEL: VFTable for 'A' in 'C' (2 entries) // CHECK-NEXT: 0 | void C::f() // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: VFTable indices for 'C' (1 entry) // CHECK-NEXT: vbtable index 1, vfptr at offset 0 // CHECK-NEXT: 0 | void C::f() d51 1 a51 1 virtual void f() {} a54 1 void use(C *obj) { obj->f(); } d57 2 a58 2 // CHECK-LABEL: VFTable for 'D' (1 entry). // CHECK-NEXT: 0 | void D::h() d60 9 a68 9 // CHECK-LABEL: VFTable for 'A' in 'D' (2 entries). // CHECK-NEXT: 0 | void D::f() // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: VFTable indices for 'D' (2 entries). // CHECK-NEXT: via vfptr at offset 0 // CHECK-NEXT: 0 | void D::h() // CHECK-NEXT: via vbtable index 1, vfptr at offset 0 // CHECK-NEXT: 0 | void D::f() d77 1 a78 1 void use(D *obj) { obj->h(); } d89 3 a91 4 Z(); // CHECK-LABEL: VFTable for 'A' in 'Test1::Y' in 'Test1::Z' (2 entries). // CHECK-NEXT: 0 | void A::f() // CHECK-NEXT: 1 | void A::z() d93 1 a93 1 // CHECK-NOT: VFTable indices for 'Test1::Z' d98 1 a98 1 Z::Z() {} d104 2 a105 2 // CHECK-LABEL: VFTable for 'Test2::X' (1 entry). // CHECK-NEXT: 0 | void Test2::X::h() d107 3 a109 3 // CHECK-LABEL: VFTable for 'A' in 'Test2::X' (2 entries). // CHECK-NEXT: 0 | void A::f() // CHECK-NEXT: 1 | void A::z() d111 2 a112 2 // CHECK-LABEL: VFTable for 'B' in 'Test2::X' (1 entry). // CHECK-NEXT: 0 | void B::g() d114 2 a115 2 // CHECK-LABEL: VFTable indices for 'Test2::X' (1 entry). // CHECK-NEXT: 0 | void Test2::X::h() a124 1 void use(X *obj) { obj->h(); } d134 3 a136 4 Y(); // CHECK-LABEL: VFTable for 'A' in 'Test3::X' in 'Test3::Y' (2 entries). // CHECK-NEXT: 0 | void A::f() // CHECK-NEXT: 1 | void A::z() d138 1 a138 1 // CHECK-NOT: VFTable indices for 'Test3::Y' d143 1 a143 1 Y::Y() {} a148 1 X(); d154 4 a157 7 // CHECK-LABEL: VFTable for 'A' in 'C' in 'Test4::X' (2 entries). // CHECK-NEXT: 0 | void C::f() // CHECK-NEXT: [this adjustment: 8 non-virtual] // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: Thunks for 'void C::f()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: 8 non-virtual] d159 1 a159 1 // CHECK-NOT: VFTable indices for 'Test4::X' d167 1 a167 1 X::X() {} d179 2 a180 2 // CHECK-LABEL: VFTable for 'Test5::Y' (1 entry). // CHECK-NEXT: 0 | void Test5::Y::h() d182 4 a185 4 // CHECK-LABEL: VFTable for 'A' in 'Test5::X' in 'Test5::Y' (3 entries). // CHECK-NEXT: 0 | void A::f() // CHECK-NEXT: 1 | void A::z() // CHECK-NEXT: 2 | void Test5::X::g() d187 2 a188 2 // CHECK-LABEL: VFTable indices for 'Test5::Y' (1 entry). // CHECK-NEXT: 0 | void Test5::Y::h() a196 1 void use(Y *obj) { obj->h(); } d202 3 a204 4 X(); // CHECK-LABEL: VFTable for 'A' in 'Test6::X' (2 entries). // CHECK-NEXT: 0 | void A::f() // CHECK-NEXT: 1 | void A::z() d206 1 a206 1 // CHECK-NOT: VFTable indices for 'Test6::X' d211 1 a211 1 X::X() {} d221 4 a224 5 Y(); // CHECK-LABEL: VFTable for 'A' in 'C' in 'Test7::X' in 'Test7::Y' (2 entries). // CHECK-NEXT: 0 | void C::f() // CHECK-NEXT: [this adjustment: 8 non-virtual] // CHECK-NEXT: 1 | void A::z() d226 2 a227 2 // CHECK-LABEL: Thunks for 'void C::f()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: 8 non-virtual] d229 1 a229 1 // CHECK-NOT: VFTable indices for 'Test7::Y' d234 1 a234 1 Y::Y() {} d241 2 a242 2 // CHECK-LABEL: VFTable for 'D' in 'Test8::X' (1 entry). // CHECK-NEXT: 0 | void D::h() d244 7 a250 7 // CHECK-LABEL: VFTable for 'A' in 'D' in 'Test8::X' (2 entries). // CHECK-NEXT: 0 | void Test8::X::f() // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: VFTable indices for 'Test8::X' (1 entry). // CHECK-NEXT: via vbtable index 1, vfptr at offset 0 // CHECK-NEXT: 0 | void Test8::X::f() a258 1 void use(X *obj) { obj->f(); } d263 8 a270 8 struct Z : Y, C { // CHECK-LABEL: VFTable for 'A' in 'Test8::Y' in 'Test8::Z' (2 entries). // CHECK-NEXT: 0 | void Test8::Z::f() // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: VFTable indices for 'Test8::Z' (1 entry). // CHECK-NEXT: via vbtable index 1, vfptr at offset 0 // CHECK-NEXT: 0 | void Test8::Z::f() a273 23 void use(Z *obj) { obj->f(); } // Another diamond inheritance which we miscompiled (PR18967). struct W : virtual A { virtual void bar(); }; struct T : W, C { // CHECK-LABEL: VFTable for 'Test8::W' in 'Test8::T' (1 entry) // CHECK-NEXT: 0 | void Test8::T::bar() // CHECK-LABEL: VFTable for 'A' in 'Test8::W' in 'Test8::T' (2 entries) // CHECK-NEXT: 0 | void C::f() // CHECK-NEXT: [this adjustment: -4 non-virtual] // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: Thunks for 'void C::f()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual] virtual void bar(); int field; }; T t; void use(T *obj) { obj->bar(); } d281 2 a282 2 // CHECK-LABEL: VFTable for 'Test9::Y' (1 entry). // CHECK-NEXT: 0 | void Test9::Y::h() d284 3 a286 3 // CHECK-LABEL: VFTable for 'A' in 'Test9::X' in 'Test9::Y' (2 entries). // CHECK-NEXT: 0 | void A::f() // CHECK-NEXT: 1 | void A::z() d288 2 a289 2 // CHECK-LABEL: VFTable indices for 'Test9::Y' (1 entry). // CHECK-NEXT: 0 | void Test9::Y::h() a297 1 void use(Y *obj) { obj->h(); } d300 2 a301 7 Z(); // CHECK-LABEL: VFTable for 'Test9::Y' in 'Test9::Z' (1 entry). // CHECK-NEXT: 0 | void Test9::Y::h() // CHECK-LABEL: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' (2 entries). // CHECK-NEXT: 0 | void A::f() // CHECK-NEXT: 1 | void A::z() d303 3 a305 2 // CHECK-LABEL: VFTable for 'B' in 'Test9::Z' (1 entry). // CHECK-NEXT: 0 | void B::g() d307 4 a310 1 // CHECK-NOT: VFTable indices for 'Test9::Z' d318 1 a318 1 Z::Z() {} d321 2 a322 3 W(); // CHECK-LABEL: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::W' (1 entry). // CHECK-NEXT: 0 | void Test9::Y::h() d324 3 a326 3 // CHECK-LABEL: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::W' (2 entries). // CHECK-NEXT: 0 | void A::f() // CHECK-NEXT: 1 | void A::z() d328 2 a329 2 // CHECK-LABEL: VFTable for 'B' in 'Test9::Z' in 'Test9::W' (1 entry). // CHECK-NEXT: 0 | void B::g() d331 2 a332 2 // CHECK-LABEL: VFTable for 'D' in 'Test9::W' (1 entry). // CHECK-NEXT: 0 | void D::h() d334 4 a337 4 // CHECK-LABEL: VFTable for 'A' in 'D' in 'Test9::W' (2 entries). // CHECK-NEXT: 0 | void D::f() // CHECK-NEXT: [this adjustment: -8 non-virtual] // CHECK-NEXT: 1 | void A::z() d339 2 a340 2 // CHECK-LABEL: Thunks for 'void D::f()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual] d342 1 a342 1 // CHECK-NOT: VFTable indices for 'Test9::W' d352 1 a352 1 W::W() {} d355 2 a356 2 // CHECK-LABEL: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::T' (1 entry). // CHECK-NEXT: 0 | void Test9::T::h() d358 34 a391 34 // CHECK-LABEL: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::T' (2 entries). // CHECK-NEXT: 0 | void Test9::T::f() // CHECK-NEXT: 1 | void Test9::T::z() // CHECK-LABEL: VFTable for 'B' in 'Test9::Z' in 'Test9::T' (1 entry). // CHECK-NEXT: 0 | void Test9::T::g() // CHECK-LABEL: VFTable for 'D' in 'Test9::T' (1 entry). // CHECK-NEXT: 0 | void Test9::T::h() // CHECK-NEXT: [this adjustment: -8 non-virtual] // CHECK-LABEL: Thunks for 'void Test9::T::h()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual] // CHECK-LABEL: VFTable for 'A' in 'D' in 'Test9::T' (2 entries). // CHECK-NEXT: 0 | void Test9::T::f() // CHECK-NEXT: [this adjustment: -8 non-virtual] // CHECK-NEXT: 1 | void Test9::T::z() // CHECK-NEXT: [this adjustment: -8 non-virtual] // CHECK-LABEL: Thunks for 'void Test9::T::f()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual] // CHECK-LABEL: Thunks for 'void Test9::T::z()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual] // CHECK-LABEL: VFTable indices for 'Test9::T' (4 entries). // CHECK-NEXT: via vfptr at offset 0 // CHECK-NEXT: 0 | void Test9::T::h() // CHECK-NEXT: via vbtable index 1, vfptr at offset 0 // CHECK-NEXT: 0 | void Test9::T::f() // CHECK-NEXT: 1 | void Test9::T::z() // CHECK-NEXT: via vbtable index 2, vfptr at offset 0 // CHECK-NEXT: 0 | void Test9::T::g() a406 1 void use(T *obj) { obj->f(); } d411 7 a417 7 // CHECK-LABEL: VFTable for 'A' in 'C' in 'Test10::X' (2 entries). // CHECK-NEXT: 0 | void Test10::X::f() // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: VFTable indices for 'Test10::X' (1 entry). // CHECK-NEXT: via vbtable index 1, vfptr at offset 0 // CHECK-NEXT: 0 | void Test10::X::f() a422 1 void use(X *obj) { obj->f(); } d438 2 a439 31 // Used to crash, PR17748. W w; } namespace Test12 { struct X : B, A { }; struct Y : X { virtual void f(); // Overrides A::f. }; struct Z : virtual Y { // CHECK-LABEL: VFTable for 'A' in 'Test12::X' in 'Test12::Y' in 'Test12::Z' (2 entries). // CHECK-NEXT: 0 | void Test12::Y::f() // CHECK-NEXT: 1 | void A::z() int z; // MANGLING-DAG: @@"\01??_7Z@@Test12@@@@6BA@@@@@@" = {{.*}}@@"\01?f@@Y@@Test12@@@@UAEXXZ" }; struct W : Z { // CHECK-LABEL: VFTable for 'A' in 'Test12::X' in 'Test12::Y' in 'Test12::Z' in 'Test12::W' (2 entries). // CHECK-NEXT: 0 | void Test12::Y::f() // CHECK-NEXT: 1 | void A::z() W(); int w; // MANGLING-DAG: @@"\01??_7W@@Test12@@@@6BA@@@@@@" = {{.*}}@@"\01?f@@Y@@Test12@@@@UAEXXZ" }; W::W() {} d449 3 a451 3 // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::Y' (2 entries). // CHECK-NEXT: 0 | vdtors::Y::~Y() [scalar deleting] // CHECK-NEXT: 1 | void vdtors::X::zzz() d453 1 a453 1 // CHECK-NOT: Thunks for 'vdtors::Y::~Y()' a457 1 void use(Y *obj) { delete obj; } d468 2 a469 2 // CHECK-LABEL: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::U' (1 entry). // CHECK-NEXT: 0 | void vdtors::Z::z() d471 11 a481 11 // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::W' in 'vdtors::U' (2 entries). // CHECK-NEXT: 0 | vdtors::U::~U() [scalar deleting] // CHECK-NEXT: [this adjustment: -4 non-virtual] // CHECK-NEXT: 1 | void vdtors::X::zzz() // CHECK-LABEL: Thunks for 'vdtors::U::~U()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual] // CHECK-LABEL: VFTable indices for 'vdtors::U' (1 entry). // CHECK-NEXT: -- accessible via vbtable index 1, vfptr at offset 4 -- // CHECK-NEXT: 0 | vdtors::U::~U() [scalar deleting] a485 1 void use(U *obj) { delete obj; } d488 2 a489 2 // CHECK-LABEL: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::V' (1 entry). // CHECK-NEXT: 0 | void vdtors::Z::z() d491 11 a501 11 // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::W' in 'vdtors::V' (2 entries). // CHECK-NEXT: 0 | vdtors::V::~V() [scalar deleting] // CHECK-NEXT: [this adjustment: -4 non-virtual] // CHECK-NEXT: 1 | void vdtors::X::zzz() // CHECK-LABEL: Thunks for 'vdtors::V::~V()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual] // CHECK-LABEL: VFTable indices for 'vdtors::V' (1 entry). // CHECK-NEXT: -- accessible via vbtable index 1, vfptr at offset 4 -- // CHECK-NEXT: 0 | vdtors::V::~V() [scalar deleting] a504 1 void use(V *obj) { delete obj; } d511 3 a513 3 // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::T' in 'vdtors::P' (2 entries). // CHECK-NEXT: 0 | vdtors::P::~P() [scalar deleting] // CHECK-NEXT: 1 | void vdtors::X::zzz() d515 1 a515 1 // CHECK-NOT: Thunks for 'vdtors::P::~P()' a519 23 void use(P *obj) { delete obj; } struct Q { virtual ~Q(); }; // PR19172: Yet another diamond we miscompiled. struct R : virtual Q, X { // CHECK-LABEL: VFTable for 'vdtors::Q' in 'vdtors::R' (1 entry). // CHECK-NEXT: 0 | vdtors::R::~R() [scalar deleting] // CHECK-NEXT: [this adjustment: -8 non-virtual] // CHECK-LABEL: Thunks for 'vdtors::R::~R()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual] // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::R' (2 entries). // CHECK-NEXT: 0 | vdtors::R::~R() [scalar deleting] // CHECK-NEXT: 1 | void vdtors::X::zzz() // CHECK-LABEL: VFTable indices for 'vdtors::R' (1 entry). // CHECK-NEXT: 0 | vdtors::R::~R() [scalar deleting] virtual ~R(); }; a520 2 R r; void use(R *obj) { delete obj; } d538 4 a541 4 // CHECK-LABEL: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' (2 entries). // CHECK-NEXT: 0 | return_adjustment::X *return_adjustment::W::foo() // CHECK-NEXT: [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual] // CHECK-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo() d543 2 a544 5 // CHECK-LABEL: Thunks for 'return_adjustment::X *return_adjustment::W::foo()' (1 entry). // CHECK-NEXT: 0 | [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual] // CHECK-LABEL: VFTable indices for 'return_adjustment::W' (1 entry). // CHECK-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo() d549 1 a549 2 W w; void use(W *obj) { obj->foo(); } d552 6 a557 10 // CHECK-LABEL: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' in 'return_adjustment::T' (3 entries). // CHECK-NEXT: 0 | return_adjustment::Y *return_adjustment::T::foo() // CHECK-NEXT: [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual] // CHECK-NEXT: 1 | return_adjustment::Y *return_adjustment::T::foo() // CHECK-NEXT: [return adjustment (to type 'struct return_adjustment::X *'): vbase #2, 0 non-virtual] // CHECK-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo() // CHECK-LABEL: Thunks for 'return_adjustment::Y *return_adjustment::T::foo()' (2 entries). // CHECK-NEXT: 0 | [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual] // CHECK-NEXT: 1 | [return adjustment (to type 'struct return_adjustment::X *'): vbase #2, 0 non-virtual] d559 2 a560 2 // CHECK-LABEL: VFTable indices for 'return_adjustment::T' (1 entry). // CHECK-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo() a565 1 void use(T *obj) { obj->foo(); } d572 4 a575 7 // CHECK-LABEL: VFTable for 'return_adjustment::Z' in 'return_adjustment::V' (2 entries). // CHECK-NEXT: 0 | return_adjustment::U *return_adjustment::V::foo() // CHECK-NEXT: [return adjustment (to type 'struct A *'): vbptr at offset 4, vbase #1, 0 non-virtual] // CHECK-NEXT: 1 | return_adjustment::U *return_adjustment::V::foo() // CHECK-LABEL: Thunks for 'return_adjustment::U *return_adjustment::V::foo()' (1 entry). // CHECK-NEXT: 0 | [return adjustment (to type 'struct A *'): vbptr at offset 4, vbase #1, 0 non-virtual] d577 2 a578 2 // CHECK-LABEL: VFTable indices for 'return_adjustment::V' (1 entry). // CHECK-NEXT: 1 | return_adjustment::U *return_adjustment::V::foo() a583 1 void use(V *obj) { obj->foo(); } a604 76 namespace pr19066 { struct X : virtual B {}; struct Y : virtual X, B { Y(); // CHECK-LABEL: VFTable for 'B' in 'pr19066::X' in 'pr19066::Y' (1 entry). // CHECK-NEXT: 0 | void B::g() // CHECK-LABEL: VFTable for 'B' in 'pr19066::Y' (1 entry). // CHECK-NEXT: 0 | void B::g() }; Y::Y() {} } namespace pr19240 { struct A { virtual void c(); }; struct B : virtual A { virtual void c(); }; struct C { }; struct D : virtual A, virtual C, B {}; D obj; // Each MDC only has one vftable. // MANGLING-DAG: @@"\01??_7D@@pr19240@@@@6B@@" // MANGLING-DAG: @@"\01??_7A@@pr19240@@@@6B@@" // MANGLING-DAG: @@"\01??_7B@@pr19240@@@@6B@@" } namespace pr19408 { // This test is a non-vtordisp version of the reproducer for PR19408. struct X : virtual A { int x; }; struct Y : X { virtual void f(); int y; }; struct Z : Y { // CHECK-LABEL: VFTable for 'A' in 'pr19408::X' in 'pr19408::Y' in 'pr19408::Z' (2 entries). // CHECK-NEXT: 0 | void pr19408::Y::f() // CHECK-NEXT: [this adjustment: -4 non-virtual] // CHECK-NEXT: 1 | void A::z() Z(); int z; // MANGLING-DAG: @@"\01??_7Z@@pr19408@@@@6B@@" = {{.*}}@@"\01?f@@Y@@pr19408@@@@W3AEXXZ" }; Z::Z() {} struct W : B, Y { // CHECK-LABEL: VFTable for 'A' in 'pr19408::X' in 'pr19408::Y' in 'pr19408::W' (2 entries). // CHECK-NEXT: 0 | void pr19408::Y::f() // CHECK-NEXT: [this adjustment: -4 non-virtual] // CHECK-NEXT: 1 | void A::z() W(); int w; // MANGLING-DAG: @@"\01??_7W@@pr19408@@@@6BY@@1@@@@" = {{.*}}@@"\01?f@@Y@@pr19408@@@@W3AEXXZ" }; W::W() {} } @ 1.1.1.5 log @Import Clang 3.5svn r209886. @ text @d2 25 a26 1 // RUN: FileCheck %s < %t d41 7 a47 7 // CHECK-LABEL: VFTable for 'A' in 'C' (2 entries) // CHECK-NEXT: 0 | void C::f() // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: VFTable indices for 'C' (1 entry) // CHECK-NEXT: vbtable index 1, vfptr at offset 0 // CHECK-NEXT: 0 | void C::f() d51 1 a51 1 virtual void f() {} a54 1 void use(C *obj) { obj->f(); } d57 2 a58 2 // CHECK-LABEL: VFTable for 'D' (1 entry). // CHECK-NEXT: 0 | void D::h() d60 9 a68 9 // CHECK-LABEL: VFTable for 'A' in 'D' (2 entries). // CHECK-NEXT: 0 | void D::f() // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: VFTable indices for 'D' (2 entries). // CHECK-NEXT: via vfptr at offset 0 // CHECK-NEXT: 0 | void D::h() // CHECK-NEXT: via vbtable index 1, vfptr at offset 0 // CHECK-NEXT: 0 | void D::f() d77 1 a78 1 void use(D *obj) { obj->h(); } d89 3 a91 4 Z(); // CHECK-LABEL: VFTable for 'A' in 'Test1::Y' in 'Test1::Z' (2 entries). // CHECK-NEXT: 0 | void A::f() // CHECK-NEXT: 1 | void A::z() d93 1 a93 1 // CHECK-NOT: VFTable indices for 'Test1::Z' d98 1 a98 1 Z::Z() {} d104 2 a105 2 // CHECK-LABEL: VFTable for 'Test2::X' (1 entry). // CHECK-NEXT: 0 | void Test2::X::h() d107 3 a109 3 // CHECK-LABEL: VFTable for 'A' in 'Test2::X' (2 entries). // CHECK-NEXT: 0 | void A::f() // CHECK-NEXT: 1 | void A::z() d111 2 a112 2 // CHECK-LABEL: VFTable for 'B' in 'Test2::X' (1 entry). // CHECK-NEXT: 0 | void B::g() d114 2 a115 2 // CHECK-LABEL: VFTable indices for 'Test2::X' (1 entry). // CHECK-NEXT: 0 | void Test2::X::h() a124 1 void use(X *obj) { obj->h(); } d134 3 a136 4 Y(); // CHECK-LABEL: VFTable for 'A' in 'Test3::X' in 'Test3::Y' (2 entries). // CHECK-NEXT: 0 | void A::f() // CHECK-NEXT: 1 | void A::z() d138 1 a138 1 // CHECK-NOT: VFTable indices for 'Test3::Y' d143 1 a143 1 Y::Y() {} a148 1 X(); d154 4 a157 7 // CHECK-LABEL: VFTable for 'A' in 'C' in 'Test4::X' (2 entries). // CHECK-NEXT: 0 | void C::f() // CHECK-NEXT: [this adjustment: 8 non-virtual] // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: Thunks for 'void C::f()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: 8 non-virtual] d159 1 a159 1 // CHECK-NOT: VFTable indices for 'Test4::X' d167 1 a167 1 X::X() {} d179 2 a180 2 // CHECK-LABEL: VFTable for 'Test5::Y' (1 entry). // CHECK-NEXT: 0 | void Test5::Y::h() d182 4 a185 4 // CHECK-LABEL: VFTable for 'A' in 'Test5::X' in 'Test5::Y' (3 entries). // CHECK-NEXT: 0 | void A::f() // CHECK-NEXT: 1 | void A::z() // CHECK-NEXT: 2 | void Test5::X::g() d187 2 a188 2 // CHECK-LABEL: VFTable indices for 'Test5::Y' (1 entry). // CHECK-NEXT: 0 | void Test5::Y::h() a196 1 void use(Y *obj) { obj->h(); } d202 3 a204 4 X(); // CHECK-LABEL: VFTable for 'A' in 'Test6::X' (2 entries). // CHECK-NEXT: 0 | void A::f() // CHECK-NEXT: 1 | void A::z() d206 1 a206 1 // CHECK-NOT: VFTable indices for 'Test6::X' d211 1 a211 1 X::X() {} d221 4 a224 5 Y(); // CHECK-LABEL: VFTable for 'A' in 'C' in 'Test7::X' in 'Test7::Y' (2 entries). // CHECK-NEXT: 0 | void C::f() // CHECK-NEXT: [this adjustment: 8 non-virtual] // CHECK-NEXT: 1 | void A::z() d226 2 a227 2 // CHECK-LABEL: Thunks for 'void C::f()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: 8 non-virtual] d229 1 a229 1 // CHECK-NOT: VFTable indices for 'Test7::Y' d234 1 a234 1 Y::Y() {} d241 2 a242 2 // CHECK-LABEL: VFTable for 'D' in 'Test8::X' (1 entry). // CHECK-NEXT: 0 | void D::h() d244 7 a250 7 // CHECK-LABEL: VFTable for 'A' in 'D' in 'Test8::X' (2 entries). // CHECK-NEXT: 0 | void Test8::X::f() // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: VFTable indices for 'Test8::X' (1 entry). // CHECK-NEXT: via vbtable index 1, vfptr at offset 0 // CHECK-NEXT: 0 | void Test8::X::f() a258 1 void use(X *obj) { obj->f(); } d263 8 a270 8 struct Z : Y, C { // CHECK-LABEL: VFTable for 'A' in 'Test8::Y' in 'Test8::Z' (2 entries). // CHECK-NEXT: 0 | void Test8::Z::f() // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: VFTable indices for 'Test8::Z' (1 entry). // CHECK-NEXT: via vbtable index 1, vfptr at offset 0 // CHECK-NEXT: 0 | void Test8::Z::f() a273 23 void use(Z *obj) { obj->f(); } // Another diamond inheritance which we miscompiled (PR18967). struct W : virtual A { virtual void bar(); }; struct T : W, C { // CHECK-LABEL: VFTable for 'Test8::W' in 'Test8::T' (1 entry) // CHECK-NEXT: 0 | void Test8::T::bar() // CHECK-LABEL: VFTable for 'A' in 'Test8::W' in 'Test8::T' (2 entries) // CHECK-NEXT: 0 | void C::f() // CHECK-NEXT: [this adjustment: -4 non-virtual] // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: Thunks for 'void C::f()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual] virtual void bar(); int field; }; T t; void use(T *obj) { obj->bar(); } d281 2 a282 2 // CHECK-LABEL: VFTable for 'Test9::Y' (1 entry). // CHECK-NEXT: 0 | void Test9::Y::h() d284 3 a286 3 // CHECK-LABEL: VFTable for 'A' in 'Test9::X' in 'Test9::Y' (2 entries). // CHECK-NEXT: 0 | void A::f() // CHECK-NEXT: 1 | void A::z() d288 2 a289 2 // CHECK-LABEL: VFTable indices for 'Test9::Y' (1 entry). // CHECK-NEXT: 0 | void Test9::Y::h() a297 1 void use(Y *obj) { obj->h(); } d300 2 a301 7 Z(); // CHECK-LABEL: VFTable for 'Test9::Y' in 'Test9::Z' (1 entry). // CHECK-NEXT: 0 | void Test9::Y::h() // CHECK-LABEL: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' (2 entries). // CHECK-NEXT: 0 | void A::f() // CHECK-NEXT: 1 | void A::z() d303 3 a305 2 // CHECK-LABEL: VFTable for 'B' in 'Test9::Z' (1 entry). // CHECK-NEXT: 0 | void B::g() d307 4 a310 1 // CHECK-NOT: VFTable indices for 'Test9::Z' d318 1 a318 1 Z::Z() {} d321 2 a322 3 W(); // CHECK-LABEL: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::W' (1 entry). // CHECK-NEXT: 0 | void Test9::Y::h() d324 3 a326 3 // CHECK-LABEL: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::W' (2 entries). // CHECK-NEXT: 0 | void A::f() // CHECK-NEXT: 1 | void A::z() d328 2 a329 2 // CHECK-LABEL: VFTable for 'B' in 'Test9::Z' in 'Test9::W' (1 entry). // CHECK-NEXT: 0 | void B::g() d331 2 a332 2 // CHECK-LABEL: VFTable for 'D' in 'Test9::W' (1 entry). // CHECK-NEXT: 0 | void D::h() d334 4 a337 4 // CHECK-LABEL: VFTable for 'A' in 'D' in 'Test9::W' (2 entries). // CHECK-NEXT: 0 | void D::f() // CHECK-NEXT: [this adjustment: -8 non-virtual] // CHECK-NEXT: 1 | void A::z() d339 2 a340 2 // CHECK-LABEL: Thunks for 'void D::f()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual] d342 1 a342 1 // CHECK-NOT: VFTable indices for 'Test9::W' d352 1 a352 1 W::W() {} d355 2 a356 2 // CHECK-LABEL: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::T' (1 entry). // CHECK-NEXT: 0 | void Test9::T::h() d358 34 a391 34 // CHECK-LABEL: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::T' (2 entries). // CHECK-NEXT: 0 | void Test9::T::f() // CHECK-NEXT: 1 | void Test9::T::z() // CHECK-LABEL: VFTable for 'B' in 'Test9::Z' in 'Test9::T' (1 entry). // CHECK-NEXT: 0 | void Test9::T::g() // CHECK-LABEL: VFTable for 'D' in 'Test9::T' (1 entry). // CHECK-NEXT: 0 | void Test9::T::h() // CHECK-NEXT: [this adjustment: -8 non-virtual] // CHECK-LABEL: Thunks for 'void Test9::T::h()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual] // CHECK-LABEL: VFTable for 'A' in 'D' in 'Test9::T' (2 entries). // CHECK-NEXT: 0 | void Test9::T::f() // CHECK-NEXT: [this adjustment: -8 non-virtual] // CHECK-NEXT: 1 | void Test9::T::z() // CHECK-NEXT: [this adjustment: -8 non-virtual] // CHECK-LABEL: Thunks for 'void Test9::T::f()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual] // CHECK-LABEL: Thunks for 'void Test9::T::z()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual] // CHECK-LABEL: VFTable indices for 'Test9::T' (4 entries). // CHECK-NEXT: via vfptr at offset 0 // CHECK-NEXT: 0 | void Test9::T::h() // CHECK-NEXT: via vbtable index 1, vfptr at offset 0 // CHECK-NEXT: 0 | void Test9::T::f() // CHECK-NEXT: 1 | void Test9::T::z() // CHECK-NEXT: via vbtable index 2, vfptr at offset 0 // CHECK-NEXT: 0 | void Test9::T::g() a406 1 void use(T *obj) { obj->f(); } d411 7 a417 7 // CHECK-LABEL: VFTable for 'A' in 'C' in 'Test10::X' (2 entries). // CHECK-NEXT: 0 | void Test10::X::f() // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: VFTable indices for 'Test10::X' (1 entry). // CHECK-NEXT: via vbtable index 1, vfptr at offset 0 // CHECK-NEXT: 0 | void Test10::X::f() a422 1 void use(X *obj) { obj->f(); } d438 2 a439 31 // Used to crash, PR17748. W w; } namespace Test12 { struct X : B, A { }; struct Y : X { virtual void f(); // Overrides A::f. }; struct Z : virtual Y { // CHECK-LABEL: VFTable for 'A' in 'Test12::X' in 'Test12::Y' in 'Test12::Z' (2 entries). // CHECK-NEXT: 0 | void Test12::Y::f() // CHECK-NEXT: 1 | void A::z() int z; // MANGLING-DAG: @@"\01??_7Z@@Test12@@@@6BA@@@@@@" = {{.*}}@@"\01?f@@Y@@Test12@@@@UAEXXZ" }; struct W : Z { // CHECK-LABEL: VFTable for 'A' in 'Test12::X' in 'Test12::Y' in 'Test12::Z' in 'Test12::W' (2 entries). // CHECK-NEXT: 0 | void Test12::Y::f() // CHECK-NEXT: 1 | void A::z() W(); int w; // MANGLING-DAG: @@"\01??_7W@@Test12@@@@6BA@@@@@@" = {{.*}}@@"\01?f@@Y@@Test12@@@@UAEXXZ" }; W::W() {} d449 3 a451 3 // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::Y' (2 entries). // CHECK-NEXT: 0 | vdtors::Y::~Y() [scalar deleting] // CHECK-NEXT: 1 | void vdtors::X::zzz() d453 1 a453 1 // CHECK-NOT: Thunks for 'vdtors::Y::~Y()' a457 1 void use(Y *obj) { delete obj; } d468 2 a469 2 // CHECK-LABEL: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::U' (1 entry). // CHECK-NEXT: 0 | void vdtors::Z::z() d471 11 a481 11 // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::W' in 'vdtors::U' (2 entries). // CHECK-NEXT: 0 | vdtors::U::~U() [scalar deleting] // CHECK-NEXT: [this adjustment: -4 non-virtual] // CHECK-NEXT: 1 | void vdtors::X::zzz() // CHECK-LABEL: Thunks for 'vdtors::U::~U()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual] // CHECK-LABEL: VFTable indices for 'vdtors::U' (1 entry). // CHECK-NEXT: -- accessible via vbtable index 1, vfptr at offset 4 -- // CHECK-NEXT: 0 | vdtors::U::~U() [scalar deleting] a485 1 void use(U *obj) { delete obj; } d488 2 a489 2 // CHECK-LABEL: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::V' (1 entry). // CHECK-NEXT: 0 | void vdtors::Z::z() d491 11 a501 11 // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::W' in 'vdtors::V' (2 entries). // CHECK-NEXT: 0 | vdtors::V::~V() [scalar deleting] // CHECK-NEXT: [this adjustment: -4 non-virtual] // CHECK-NEXT: 1 | void vdtors::X::zzz() // CHECK-LABEL: Thunks for 'vdtors::V::~V()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual] // CHECK-LABEL: VFTable indices for 'vdtors::V' (1 entry). // CHECK-NEXT: -- accessible via vbtable index 1, vfptr at offset 4 -- // CHECK-NEXT: 0 | vdtors::V::~V() [scalar deleting] a504 1 void use(V *obj) { delete obj; } d511 3 a513 3 // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::T' in 'vdtors::P' (2 entries). // CHECK-NEXT: 0 | vdtors::P::~P() [scalar deleting] // CHECK-NEXT: 1 | void vdtors::X::zzz() d515 1 a515 1 // CHECK-NOT: Thunks for 'vdtors::P::~P()' a519 23 void use(P *obj) { delete obj; } struct Q { virtual ~Q(); }; // PR19172: Yet another diamond we miscompiled. struct R : virtual Q, X { // CHECK-LABEL: VFTable for 'vdtors::Q' in 'vdtors::R' (1 entry). // CHECK-NEXT: 0 | vdtors::R::~R() [scalar deleting] // CHECK-NEXT: [this adjustment: -8 non-virtual] // CHECK-LABEL: Thunks for 'vdtors::R::~R()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual] // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::R' (2 entries). // CHECK-NEXT: 0 | vdtors::R::~R() [scalar deleting] // CHECK-NEXT: 1 | void vdtors::X::zzz() // CHECK-LABEL: VFTable indices for 'vdtors::R' (1 entry). // CHECK-NEXT: 0 | vdtors::R::~R() [scalar deleting] virtual ~R(); }; a520 2 R r; void use(R *obj) { delete obj; } d538 4 a541 4 // CHECK-LABEL: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' (2 entries). // CHECK-NEXT: 0 | return_adjustment::X *return_adjustment::W::foo() // CHECK-NEXT: [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual] // CHECK-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo() d543 2 a544 5 // CHECK-LABEL: Thunks for 'return_adjustment::X *return_adjustment::W::foo()' (1 entry). // CHECK-NEXT: 0 | [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual] // CHECK-LABEL: VFTable indices for 'return_adjustment::W' (1 entry). // CHECK-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo() d549 1 a549 2 W w; void use(W *obj) { obj->foo(); } d552 6 a557 10 // CHECK-LABEL: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' in 'return_adjustment::T' (3 entries). // CHECK-NEXT: 0 | return_adjustment::Y *return_adjustment::T::foo() // CHECK-NEXT: [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual] // CHECK-NEXT: 1 | return_adjustment::Y *return_adjustment::T::foo() // CHECK-NEXT: [return adjustment (to type 'struct return_adjustment::X *'): vbase #2, 0 non-virtual] // CHECK-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo() // CHECK-LABEL: Thunks for 'return_adjustment::Y *return_adjustment::T::foo()' (2 entries). // CHECK-NEXT: 0 | [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual] // CHECK-NEXT: 1 | [return adjustment (to type 'struct return_adjustment::X *'): vbase #2, 0 non-virtual] d559 2 a560 2 // CHECK-LABEL: VFTable indices for 'return_adjustment::T' (1 entry). // CHECK-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo() a565 1 void use(T *obj) { obj->foo(); } d572 4 a575 7 // CHECK-LABEL: VFTable for 'return_adjustment::Z' in 'return_adjustment::V' (2 entries). // CHECK-NEXT: 0 | return_adjustment::U *return_adjustment::V::foo() // CHECK-NEXT: [return adjustment (to type 'struct A *'): vbptr at offset 4, vbase #1, 0 non-virtual] // CHECK-NEXT: 1 | return_adjustment::U *return_adjustment::V::foo() // CHECK-LABEL: Thunks for 'return_adjustment::U *return_adjustment::V::foo()' (1 entry). // CHECK-NEXT: 0 | [return adjustment (to type 'struct A *'): vbptr at offset 4, vbase #1, 0 non-virtual] d577 2 a578 2 // CHECK-LABEL: VFTable indices for 'return_adjustment::V' (1 entry). // CHECK-NEXT: 1 | return_adjustment::U *return_adjustment::V::foo() a583 1 void use(V *obj) { obj->foo(); } a604 76 namespace pr19066 { struct X : virtual B {}; struct Y : virtual X, B { Y(); // CHECK-LABEL: VFTable for 'B' in 'pr19066::X' in 'pr19066::Y' (1 entry). // CHECK-NEXT: 0 | void B::g() // CHECK-LABEL: VFTable for 'B' in 'pr19066::Y' (1 entry). // CHECK-NEXT: 0 | void B::g() }; Y::Y() {} } namespace pr19240 { struct A { virtual void c(); }; struct B : virtual A { virtual void c(); }; struct C { }; struct D : virtual A, virtual C, B {}; D obj; // Each MDC only has one vftable. // MANGLING-DAG: @@"\01??_7D@@pr19240@@@@6B@@" // MANGLING-DAG: @@"\01??_7A@@pr19240@@@@6B@@" // MANGLING-DAG: @@"\01??_7B@@pr19240@@@@6B@@" } namespace pr19408 { // This test is a non-vtordisp version of the reproducer for PR19408. struct X : virtual A { int x; }; struct Y : X { virtual void f(); int y; }; struct Z : Y { // CHECK-LABEL: VFTable for 'A' in 'pr19408::X' in 'pr19408::Y' in 'pr19408::Z' (2 entries). // CHECK-NEXT: 0 | void pr19408::Y::f() // CHECK-NEXT: [this adjustment: -4 non-virtual] // CHECK-NEXT: 1 | void A::z() Z(); int z; // MANGLING-DAG: @@"\01??_7Z@@pr19408@@@@6B@@" = {{.*}}@@"\01?f@@Y@@pr19408@@@@W3AEXXZ" }; Z::Z() {} struct W : B, Y { // CHECK-LABEL: VFTable for 'A' in 'pr19408::X' in 'pr19408::Y' in 'pr19408::W' (2 entries). // CHECK-NEXT: 0 | void pr19408::Y::f() // CHECK-NEXT: [this adjustment: -4 non-virtual] // CHECK-NEXT: 1 | void A::z() W(); int w; // MANGLING-DAG: @@"\01??_7W@@pr19408@@@@6BY@@1@@@@" = {{.*}}@@"\01?f@@Y@@pr19408@@@@W3AEXXZ" }; W::W() {} } @ 1.1.1.6 log @Import clang 3.6svn r215315. @ text @d148 1 a148 1 // MANGLING-DAG: define linkonce_odr x86_thiscallcc void @@"\01?f@@C@@@@WPPPPPPPI@@AEXXZ" a575 4 // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::R' (2 entries). // CHECK-NEXT: 0 | vdtors::R::~R() [scalar deleting] // CHECK-NEXT: 1 | void vdtors::X::zzz() d583 4 d697 1 a697 1 // CHECK-LABEL: VFTable for 'B' in 'pr19066::Y' (1 entry). d700 1 a700 1 // CHECK-LABEL: VFTable for 'B' in 'pr19066::X' in 'pr19066::Y' (1 entry). @ 1.1.1.6.2.1 log @Update LLVM to 3.6.1, requested by joerg in ticket 824. @ text @d1 1 a1 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 d576 4 a586 4 // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::R' (2 entries). // CHECK-NEXT: 0 | vdtors::R::~R() [scalar deleting] // CHECK-NEXT: 1 | void vdtors::X::zzz() d697 1 a697 1 // CHECK-LABEL: VFTable for 'B' in 'pr19066::X' in 'pr19066::Y' (1 entry). d700 1 a700 1 // CHECK-LABEL: VFTable for 'B' in 'pr19066::Y' (1 entry). a766 43 namespace Test13 { struct A { virtual void f(); }; struct __declspec(dllexport) B : virtual A { virtual void f() = 0; // MANGLING-DAG: @@"\01??_7B@@Test13@@@@6B@@" = weak_odr dllexport unnamed_addr constant [1 x i8*] [i8* bitcast (void ()* @@_purecall to i8*)] }; } namespace pr21031_1 { // This ordering of base specifiers regressed in r202425. struct A { virtual void f(void); }; struct B : virtual A { virtual void g(void); }; struct C : virtual A, B { C(); }; C::C() {} // CHECK-LABEL: VFTable for 'pr21031_1::A' in 'pr21031_1::B' in 'pr21031_1::C' (1 entry) // CHECK-NEXT: 0 | void pr21031_1::A::f() // CHECK-LABEL: VFTable for 'pr21031_1::B' in 'pr21031_1::C' (1 entry) // CHECK-NEXT: 0 | void pr21031_1::B::g() // MANGLING-DAG: @@"\01??_7C@@pr21031_1@@@@6BB@@1@@@@" = {{.*}} constant [1 x i8*] // MANGLING-DAG: @@"\01??_7C@@pr21031_1@@@@6B@@" = {{.*}} constant [1 x i8*] } namespace pr21031_2 { struct A { virtual void f(void); }; struct B : virtual A { virtual void g(void); }; struct C : B, virtual A { C(); }; C::C() {} // CHECK-LABEL: VFTable for 'pr21031_2::B' in 'pr21031_2::C' (1 entry) // CHECK-NEXT: 0 | void pr21031_2::B::g() // CHECK-LABEL: VFTable for 'pr21031_2::A' in 'pr21031_2::B' in 'pr21031_2::C' (1 entry) // CHECK-NEXT: 0 | void pr21031_2::A::f() // MANGLING-DAG: @@"\01??_7C@@pr21031_2@@@@6BA@@1@@@@" = {{.*}} constant [1 x i8*] // MANGLING-DAG: @@"\01??_7C@@pr21031_2@@@@6BB@@1@@@@" = {{.*}} constant [1 x i8*] } @ 1.1.1.7 log @Import Clang 3.6RC1 r227398. @ text @d1 1 a1 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 d576 4 a586 4 // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::R' (2 entries). // CHECK-NEXT: 0 | vdtors::R::~R() [scalar deleting] // CHECK-NEXT: 1 | void vdtors::X::zzz() d697 1 a697 1 // CHECK-LABEL: VFTable for 'B' in 'pr19066::X' in 'pr19066::Y' (1 entry). d700 1 a700 1 // CHECK-LABEL: VFTable for 'B' in 'pr19066::Y' (1 entry). a766 43 namespace Test13 { struct A { virtual void f(); }; struct __declspec(dllexport) B : virtual A { virtual void f() = 0; // MANGLING-DAG: @@"\01??_7B@@Test13@@@@6B@@" = weak_odr dllexport unnamed_addr constant [1 x i8*] [i8* bitcast (void ()* @@_purecall to i8*)] }; } namespace pr21031_1 { // This ordering of base specifiers regressed in r202425. struct A { virtual void f(void); }; struct B : virtual A { virtual void g(void); }; struct C : virtual A, B { C(); }; C::C() {} // CHECK-LABEL: VFTable for 'pr21031_1::A' in 'pr21031_1::B' in 'pr21031_1::C' (1 entry) // CHECK-NEXT: 0 | void pr21031_1::A::f() // CHECK-LABEL: VFTable for 'pr21031_1::B' in 'pr21031_1::C' (1 entry) // CHECK-NEXT: 0 | void pr21031_1::B::g() // MANGLING-DAG: @@"\01??_7C@@pr21031_1@@@@6BB@@1@@@@" = {{.*}} constant [1 x i8*] // MANGLING-DAG: @@"\01??_7C@@pr21031_1@@@@6B@@" = {{.*}} constant [1 x i8*] } namespace pr21031_2 { struct A { virtual void f(void); }; struct B : virtual A { virtual void g(void); }; struct C : B, virtual A { C(); }; C::C() {} // CHECK-LABEL: VFTable for 'pr21031_2::B' in 'pr21031_2::C' (1 entry) // CHECK-NEXT: 0 | void pr21031_2::B::g() // CHECK-LABEL: VFTable for 'pr21031_2::A' in 'pr21031_2::B' in 'pr21031_2::C' (1 entry) // CHECK-NEXT: 0 | void pr21031_2::A::f() // MANGLING-DAG: @@"\01??_7C@@pr21031_2@@@@6BA@@1@@@@" = {{.*}} constant [1 x i8*] // MANGLING-DAG: @@"\01??_7C@@pr21031_2@@@@6BB@@1@@@@" = {{.*}} constant [1 x i8*] } @ 1.1.1.8 log @Import Clang 3.8.0rc3 r261930. @ text @a809 38 namespace pr21062_1 { struct A { virtual void f(); }; struct B {}; struct C : virtual B {}; struct D : virtual C, virtual B, virtual A { D();}; D::D() {} // CHECK-LABEL: VFTable for 'pr21062_1::A' in 'pr21062_1::D' (1 entry) // CHECK-NEXT: 0 | void pr21062_1::A::f() // MANGLING-DAG: @@"\01??_7D@@pr21062_1@@@@6B@@" = {{.*}} constant [1 x i8*] } namespace pr21062_2 { struct A { virtual void f(); }; struct B {}; struct C : virtual B {}; struct D : C, virtual B, virtual A { D(); }; D::D() {} // CHECK-LABEL: VFTable for 'pr21062_2::A' in 'pr21062_2::D' (1 entry) // CHECK-NEXT: 0 | void pr21062_2::A::f() // MANGLING-DAG: @@"\01??_7D@@pr21062_2@@@@6B@@" = {{.*}} constant [1 x i8*] } namespace pr21064 { struct A {}; struct B { virtual void f(); }; struct C : virtual A, virtual B {}; struct D : virtual A, virtual C { D(); }; D::D() {} // CHECK-LABEL: VFTable for 'pr21064::B' in 'pr21064::C' in 'pr21064::D' (1 entry) // CHECK-NEXT: 0 | void pr21064::B::f() // MANGLING-DAG: @@"\01??_7D@@pr21064@@@@6B@@" = {{.*}} constant [1 x i8*] } @ 1.1.1.8.2.1 log @Sync with HEAD @ text @d774 1 a774 1 // MANGLING-DAG: @@"\01??_7B@@Test13@@@@6B@@" = weak_odr dllexport unnamed_addr constant { [1 x i8*] } { [1 x i8*] [i8* bitcast (void ()* @@_purecall to i8*)] } d791 2 a792 2 // MANGLING-DAG: @@"\01??_7C@@pr21031_1@@@@6BB@@1@@@@" = {{.*}} constant { [1 x i8*] } // MANGLING-DAG: @@"\01??_7C@@pr21031_1@@@@6B@@" = {{.*}} constant { [1 x i8*] } d807 2 a808 2 // MANGLING-DAG: @@"\01??_7C@@pr21031_2@@@@6BA@@1@@@@" = {{.*}} constant { [1 x i8*] } // MANGLING-DAG: @@"\01??_7C@@pr21031_2@@@@6BB@@1@@@@" = {{.*}} constant { [1 x i8*] } d821 1 a821 1 // MANGLING-DAG: @@"\01??_7D@@pr21062_1@@@@6B@@" = {{.*}} constant { [1 x i8*] } d834 1 a834 1 // MANGLING-DAG: @@"\01??_7D@@pr21062_2@@@@6B@@" = {{.*}} constant { [1 x i8*] } d846 1 a846 1 // MANGLING-DAG: @@"\01??_7D@@pr21064@@@@6B@@" = {{.*}} constant { [1 x i8*] } @ 1.1.1.9 log @Import Clang pre-4.0.0 r291444. @ text @d774 1 a774 1 // MANGLING-DAG: @@"\01??_7B@@Test13@@@@6B@@" = weak_odr dllexport unnamed_addr constant { [1 x i8*] } { [1 x i8*] [i8* bitcast (void ()* @@_purecall to i8*)] } d791 2 a792 2 // MANGLING-DAG: @@"\01??_7C@@pr21031_1@@@@6BB@@1@@@@" = {{.*}} constant { [1 x i8*] } // MANGLING-DAG: @@"\01??_7C@@pr21031_1@@@@6B@@" = {{.*}} constant { [1 x i8*] } d807 2 a808 2 // MANGLING-DAG: @@"\01??_7C@@pr21031_2@@@@6BA@@1@@@@" = {{.*}} constant { [1 x i8*] } // MANGLING-DAG: @@"\01??_7C@@pr21031_2@@@@6BB@@1@@@@" = {{.*}} constant { [1 x i8*] } d821 1 a821 1 // MANGLING-DAG: @@"\01??_7D@@pr21062_1@@@@6B@@" = {{.*}} constant { [1 x i8*] } d834 1 a834 1 // MANGLING-DAG: @@"\01??_7D@@pr21062_2@@@@6B@@" = {{.*}} constant { [1 x i8*] } d846 1 a846 1 // MANGLING-DAG: @@"\01??_7D@@pr21064@@@@6B@@" = {{.*}} constant { [1 x i8*] } @ 1.1.1.9.14.1 log @Sync with HEAD @ text @d25 1 a25 1 // MANGLING-DAG: @@"??_7C@@@@6B@@" d47 2 a48 2 // MANGLING-DAG: @@"??_7D@@@@6B0@@@@" // MANGLING-DAG: @@"??_7D@@@@6BA@@@@@@" d63 1 a63 1 // MANGLING-DAG: @@"??_7Y@@Test1@@@@6B@@" d73 1 a73 1 // MANGLING-DAG: @@"??_7Z@@Test1@@@@6B@@" d95 3 a97 3 // MANGLING-DAG: @@"??_7X@@Test2@@@@6B01@@@@" // MANGLING-DAG: @@"??_7X@@Test2@@@@6BA@@@@@@" // MANGLING-DAG: @@"??_7X@@Test2@@@@6BB@@@@@@" d109 1 a109 1 // MANGLING-DAG: @@"??_7X@@Test3@@@@6B@@" d120 1 a120 1 // MANGLING-DAG: @@"??_7Y@@Test3@@@@6B@@" d145 1 a145 1 // MANGLING-DAG: @@"??_7X@@Test4@@@@6B@@" d148 1 a148 1 // MANGLING-DAG: define linkonce_odr dso_local x86_thiscallcc void @@"?f@@C@@@@WPPPPPPPI@@AEXXZ" d158 1 a158 1 // MANGLING-DAG: @@"??_7X@@Test5@@@@6B@@" d174 2 a175 2 // MANGLING-DAG: @@"??_7Y@@Test5@@@@6B01@@@@" // MANGLING-DAG: @@"??_7Y@@Test5@@@@6BX@@1@@@@" d194 1 a194 1 // MANGLING-DAG: @@"??_7X@@Test6@@@@6B@@" d203 1 a203 1 // MANGLING-DAG: @@"??_7X@@Test7@@@@6B@@" d218 1 a218 1 // MANGLING-DAG: @@"??_7Y@@Test7@@@@6B@@" d239 2 a240 2 // MANGLING-DAG: @@"??_7X@@Test8@@@@6BA@@@@@@" // MANGLING-DAG: @@"??_7X@@Test8@@@@6BD@@@@@@" d302 2 a303 2 // MANGLING-DAG: @@"??_7Y@@Test9@@@@6B01@@@@" // MANGLING-DAG: @@"??_7Y@@Test9@@@@6BX@@1@@@@" d325 2 a326 2 // MANGLING-DAG: @@"??_7Z@@Test9@@@@6BX@@1@@@@" // MANGLING-DAG: @@"??_7Z@@Test9@@@@6BY@@1@@@@" d328 1 a328 1 // MANGLING-DAG: @@"??_7Z@@Test9@@@@6B@@" d358 3 a360 3 // MANGLING-DAG: @@"??_7W@@Test9@@@@6BA@@@@@@" // MANGLING-DAG: @@"??_7W@@Test9@@@@6BD@@@@@@" // MANGLING-DAG: @@"??_7W@@Test9@@@@6BX@@1@@@@" d362 2 a363 2 // MANGLING-DAG: @@"??_7W@@Test9@@@@6B@@" // MANGLING-DAG: @@"??_7W@@Test9@@@@6BY@@1@@@@" d407 3 a409 3 // MANGLING-DAG: @@"??_7T@@Test9@@@@6BA@@@@@@" // MANGLING-DAG: @@"??_7T@@Test9@@@@6BD@@@@@@" // MANGLING-DAG: @@"??_7T@@Test9@@@@6BX@@1@@@@" d411 2 a412 2 // MANGLING-DAG: @@"??_7T@@Test9@@@@6B@@" // MANGLING-DAG: @@"??_7T@@Test9@@@@6BY@@1@@@@" d446 2 a447 2 // MANGLING-DAG: @@"??_7Z@@Test11@@@@6BY@@1@@@@" // MANGLING-DAG: @@"??_7Z@@Test11@@@@6BX@@1@@@@" d471 1 a471 1 // MANGLING-DAG: @@"??_7Z@@Test12@@@@6BA@@@@@@" = {{.*}}@@"?f@@Y@@Test12@@@@UAEXXZ" d481 1 a481 1 // MANGLING-DAG: @@"??_7W@@Test12@@@@6BA@@@@@@" = {{.*}}@@"?f@@Y@@Test12@@@@UAEXXZ" d686 4 a689 4 // MANGLING-DAG: @@"??_7A@@pr17748@@@@6B@@" // MANGLING-DAG: @@"??_7B@@pr17748@@@@6B@@" // MANGLING-DAG: @@"??_7C@@pr17748@@@@6BA@@1@@@@" // MANGLING-DAG: @@"??_7C@@pr17748@@@@6BB@@1@@@@" d724 3 a726 3 // MANGLING-DAG: @@"??_7D@@pr19240@@@@6B@@" // MANGLING-DAG: @@"??_7A@@pr19240@@@@6B@@" // MANGLING-DAG: @@"??_7B@@pr19240@@@@6B@@" d749 1 a749 1 // MANGLING-DAG: @@"??_7Z@@pr19408@@@@6B@@" = {{.*}}@@"?f@@Y@@pr19408@@@@W3AEXXZ" d762 1 a762 1 // MANGLING-DAG: @@"??_7W@@pr19408@@@@6BY@@1@@@@" = {{.*}}@@"?f@@Y@@pr19408@@@@W3AEXXZ" d774 1 a774 1 // MANGLING-DAG: @@"??_7B@@Test13@@@@6B@@" = weak_odr dllexport unnamed_addr constant { [1 x i8*] } { [1 x i8*] [i8* bitcast (void ()* @@_purecall to i8*)] } d791 2 a792 2 // MANGLING-DAG: @@"??_7C@@pr21031_1@@@@6BB@@1@@@@" = {{.*}} constant { [1 x i8*] } // MANGLING-DAG: @@"??_7C@@pr21031_1@@@@6B@@" = {{.*}} constant { [1 x i8*] } d807 2 a808 2 // MANGLING-DAG: @@"??_7C@@pr21031_2@@@@6BA@@1@@@@" = {{.*}} constant { [1 x i8*] } // MANGLING-DAG: @@"??_7C@@pr21031_2@@@@6BB@@1@@@@" = {{.*}} constant { [1 x i8*] } d821 1 a821 1 // MANGLING-DAG: @@"??_7D@@pr21062_1@@@@6B@@" = {{.*}} constant { [1 x i8*] } d834 1 a834 1 // MANGLING-DAG: @@"??_7D@@pr21062_2@@@@6B@@" = {{.*}} constant { [1 x i8*] } d846 1 a846 1 // MANGLING-DAG: @@"??_7D@@pr21064@@@@6B@@" = {{.*}} constant { [1 x i8*] } @ 1.1.1.9.14.2 log @Mostly merge changes from HEAD upto 20200411 @ text @@ 1.1.1.9.12.1 log @Sync with HEAD @ text @d25 1 a25 1 // MANGLING-DAG: @@"??_7C@@@@6B@@" d47 2 a48 2 // MANGLING-DAG: @@"??_7D@@@@6B0@@@@" // MANGLING-DAG: @@"??_7D@@@@6BA@@@@@@" d63 1 a63 1 // MANGLING-DAG: @@"??_7Y@@Test1@@@@6B@@" d73 1 a73 1 // MANGLING-DAG: @@"??_7Z@@Test1@@@@6B@@" d95 3 a97 3 // MANGLING-DAG: @@"??_7X@@Test2@@@@6B01@@@@" // MANGLING-DAG: @@"??_7X@@Test2@@@@6BA@@@@@@" // MANGLING-DAG: @@"??_7X@@Test2@@@@6BB@@@@@@" d109 1 a109 1 // MANGLING-DAG: @@"??_7X@@Test3@@@@6B@@" d120 1 a120 1 // MANGLING-DAG: @@"??_7Y@@Test3@@@@6B@@" d145 1 a145 1 // MANGLING-DAG: @@"??_7X@@Test4@@@@6B@@" d148 1 a148 1 // MANGLING-DAG: define linkonce_odr dso_local x86_thiscallcc void @@"?f@@C@@@@WPPPPPPPI@@AEXXZ" d158 1 a158 1 // MANGLING-DAG: @@"??_7X@@Test5@@@@6B@@" d174 2 a175 2 // MANGLING-DAG: @@"??_7Y@@Test5@@@@6B01@@@@" // MANGLING-DAG: @@"??_7Y@@Test5@@@@6BX@@1@@@@" d194 1 a194 1 // MANGLING-DAG: @@"??_7X@@Test6@@@@6B@@" d203 1 a203 1 // MANGLING-DAG: @@"??_7X@@Test7@@@@6B@@" d218 1 a218 1 // MANGLING-DAG: @@"??_7Y@@Test7@@@@6B@@" d239 2 a240 2 // MANGLING-DAG: @@"??_7X@@Test8@@@@6BA@@@@@@" // MANGLING-DAG: @@"??_7X@@Test8@@@@6BD@@@@@@" d302 2 a303 2 // MANGLING-DAG: @@"??_7Y@@Test9@@@@6B01@@@@" // MANGLING-DAG: @@"??_7Y@@Test9@@@@6BX@@1@@@@" d325 2 a326 2 // MANGLING-DAG: @@"??_7Z@@Test9@@@@6BX@@1@@@@" // MANGLING-DAG: @@"??_7Z@@Test9@@@@6BY@@1@@@@" d328 1 a328 1 // MANGLING-DAG: @@"??_7Z@@Test9@@@@6B@@" d358 3 a360 3 // MANGLING-DAG: @@"??_7W@@Test9@@@@6BA@@@@@@" // MANGLING-DAG: @@"??_7W@@Test9@@@@6BD@@@@@@" // MANGLING-DAG: @@"??_7W@@Test9@@@@6BX@@1@@@@" d362 2 a363 2 // MANGLING-DAG: @@"??_7W@@Test9@@@@6B@@" // MANGLING-DAG: @@"??_7W@@Test9@@@@6BY@@1@@@@" d407 3 a409 3 // MANGLING-DAG: @@"??_7T@@Test9@@@@6BA@@@@@@" // MANGLING-DAG: @@"??_7T@@Test9@@@@6BD@@@@@@" // MANGLING-DAG: @@"??_7T@@Test9@@@@6BX@@1@@@@" d411 2 a412 2 // MANGLING-DAG: @@"??_7T@@Test9@@@@6B@@" // MANGLING-DAG: @@"??_7T@@Test9@@@@6BY@@1@@@@" d446 2 a447 2 // MANGLING-DAG: @@"??_7Z@@Test11@@@@6BY@@1@@@@" // MANGLING-DAG: @@"??_7Z@@Test11@@@@6BX@@1@@@@" d471 1 a471 1 // MANGLING-DAG: @@"??_7Z@@Test12@@@@6BA@@@@@@" = {{.*}}@@"?f@@Y@@Test12@@@@UAEXXZ" d481 1 a481 1 // MANGLING-DAG: @@"??_7W@@Test12@@@@6BA@@@@@@" = {{.*}}@@"?f@@Y@@Test12@@@@UAEXXZ" d686 4 a689 4 // MANGLING-DAG: @@"??_7A@@pr17748@@@@6B@@" // MANGLING-DAG: @@"??_7B@@pr17748@@@@6B@@" // MANGLING-DAG: @@"??_7C@@pr17748@@@@6BA@@1@@@@" // MANGLING-DAG: @@"??_7C@@pr17748@@@@6BB@@1@@@@" d724 3 a726 3 // MANGLING-DAG: @@"??_7D@@pr19240@@@@6B@@" // MANGLING-DAG: @@"??_7A@@pr19240@@@@6B@@" // MANGLING-DAG: @@"??_7B@@pr19240@@@@6B@@" d749 1 a749 1 // MANGLING-DAG: @@"??_7Z@@pr19408@@@@6B@@" = {{.*}}@@"?f@@Y@@pr19408@@@@W3AEXXZ" d762 1 a762 1 // MANGLING-DAG: @@"??_7W@@pr19408@@@@6BY@@1@@@@" = {{.*}}@@"?f@@Y@@pr19408@@@@W3AEXXZ" d774 1 a774 1 // MANGLING-DAG: @@"??_7B@@Test13@@@@6B@@" = weak_odr dllexport unnamed_addr constant { [1 x i8*] } { [1 x i8*] [i8* bitcast (void ()* @@_purecall to i8*)] } d791 2 a792 2 // MANGLING-DAG: @@"??_7C@@pr21031_1@@@@6BB@@1@@@@" = {{.*}} constant { [1 x i8*] } // MANGLING-DAG: @@"??_7C@@pr21031_1@@@@6B@@" = {{.*}} constant { [1 x i8*] } d807 2 a808 2 // MANGLING-DAG: @@"??_7C@@pr21031_2@@@@6BA@@1@@@@" = {{.*}} constant { [1 x i8*] } // MANGLING-DAG: @@"??_7C@@pr21031_2@@@@6BB@@1@@@@" = {{.*}} constant { [1 x i8*] } d821 1 a821 1 // MANGLING-DAG: @@"??_7D@@pr21062_1@@@@6B@@" = {{.*}} constant { [1 x i8*] } d834 1 a834 1 // MANGLING-DAG: @@"??_7D@@pr21062_2@@@@6B@@" = {{.*}} constant { [1 x i8*] } d846 1 a846 1 // MANGLING-DAG: @@"??_7D@@pr21064@@@@6B@@" = {{.*}} constant { [1 x i8*] } @ 1.1.1.10 log @Import clang r337282 from trunk @ text @d25 1 a25 1 // MANGLING-DAG: @@"??_7C@@@@6B@@" d47 2 a48 2 // MANGLING-DAG: @@"??_7D@@@@6B0@@@@" // MANGLING-DAG: @@"??_7D@@@@6BA@@@@@@" d63 1 a63 1 // MANGLING-DAG: @@"??_7Y@@Test1@@@@6B@@" d73 1 a73 1 // MANGLING-DAG: @@"??_7Z@@Test1@@@@6B@@" d95 3 a97 3 // MANGLING-DAG: @@"??_7X@@Test2@@@@6B01@@@@" // MANGLING-DAG: @@"??_7X@@Test2@@@@6BA@@@@@@" // MANGLING-DAG: @@"??_7X@@Test2@@@@6BB@@@@@@" d109 1 a109 1 // MANGLING-DAG: @@"??_7X@@Test3@@@@6B@@" d120 1 a120 1 // MANGLING-DAG: @@"??_7Y@@Test3@@@@6B@@" d145 1 a145 1 // MANGLING-DAG: @@"??_7X@@Test4@@@@6B@@" d148 1 a148 1 // MANGLING-DAG: define linkonce_odr dso_local x86_thiscallcc void @@"?f@@C@@@@WPPPPPPPI@@AEXXZ" d158 1 a158 1 // MANGLING-DAG: @@"??_7X@@Test5@@@@6B@@" d174 2 a175 2 // MANGLING-DAG: @@"??_7Y@@Test5@@@@6B01@@@@" // MANGLING-DAG: @@"??_7Y@@Test5@@@@6BX@@1@@@@" d194 1 a194 1 // MANGLING-DAG: @@"??_7X@@Test6@@@@6B@@" d203 1 a203 1 // MANGLING-DAG: @@"??_7X@@Test7@@@@6B@@" d218 1 a218 1 // MANGLING-DAG: @@"??_7Y@@Test7@@@@6B@@" d239 2 a240 2 // MANGLING-DAG: @@"??_7X@@Test8@@@@6BA@@@@@@" // MANGLING-DAG: @@"??_7X@@Test8@@@@6BD@@@@@@" d302 2 a303 2 // MANGLING-DAG: @@"??_7Y@@Test9@@@@6B01@@@@" // MANGLING-DAG: @@"??_7Y@@Test9@@@@6BX@@1@@@@" d325 2 a326 2 // MANGLING-DAG: @@"??_7Z@@Test9@@@@6BX@@1@@@@" // MANGLING-DAG: @@"??_7Z@@Test9@@@@6BY@@1@@@@" d328 1 a328 1 // MANGLING-DAG: @@"??_7Z@@Test9@@@@6B@@" d358 3 a360 3 // MANGLING-DAG: @@"??_7W@@Test9@@@@6BA@@@@@@" // MANGLING-DAG: @@"??_7W@@Test9@@@@6BD@@@@@@" // MANGLING-DAG: @@"??_7W@@Test9@@@@6BX@@1@@@@" d362 2 a363 2 // MANGLING-DAG: @@"??_7W@@Test9@@@@6B@@" // MANGLING-DAG: @@"??_7W@@Test9@@@@6BY@@1@@@@" d407 3 a409 3 // MANGLING-DAG: @@"??_7T@@Test9@@@@6BA@@@@@@" // MANGLING-DAG: @@"??_7T@@Test9@@@@6BD@@@@@@" // MANGLING-DAG: @@"??_7T@@Test9@@@@6BX@@1@@@@" d411 2 a412 2 // MANGLING-DAG: @@"??_7T@@Test9@@@@6B@@" // MANGLING-DAG: @@"??_7T@@Test9@@@@6BY@@1@@@@" d446 2 a447 2 // MANGLING-DAG: @@"??_7Z@@Test11@@@@6BY@@1@@@@" // MANGLING-DAG: @@"??_7Z@@Test11@@@@6BX@@1@@@@" d471 1 a471 1 // MANGLING-DAG: @@"??_7Z@@Test12@@@@6BA@@@@@@" = {{.*}}@@"?f@@Y@@Test12@@@@UAEXXZ" d481 1 a481 1 // MANGLING-DAG: @@"??_7W@@Test12@@@@6BA@@@@@@" = {{.*}}@@"?f@@Y@@Test12@@@@UAEXXZ" d686 4 a689 4 // MANGLING-DAG: @@"??_7A@@pr17748@@@@6B@@" // MANGLING-DAG: @@"??_7B@@pr17748@@@@6B@@" // MANGLING-DAG: @@"??_7C@@pr17748@@@@6BA@@1@@@@" // MANGLING-DAG: @@"??_7C@@pr17748@@@@6BB@@1@@@@" d724 3 a726 3 // MANGLING-DAG: @@"??_7D@@pr19240@@@@6B@@" // MANGLING-DAG: @@"??_7A@@pr19240@@@@6B@@" // MANGLING-DAG: @@"??_7B@@pr19240@@@@6B@@" d749 1 a749 1 // MANGLING-DAG: @@"??_7Z@@pr19408@@@@6B@@" = {{.*}}@@"?f@@Y@@pr19408@@@@W3AEXXZ" d762 1 a762 1 // MANGLING-DAG: @@"??_7W@@pr19408@@@@6BY@@1@@@@" = {{.*}}@@"?f@@Y@@pr19408@@@@W3AEXXZ" d774 1 a774 1 // MANGLING-DAG: @@"??_7B@@Test13@@@@6B@@" = weak_odr dllexport unnamed_addr constant { [1 x i8*] } { [1 x i8*] [i8* bitcast (void ()* @@_purecall to i8*)] } d791 2 a792 2 // MANGLING-DAG: @@"??_7C@@pr21031_1@@@@6BB@@1@@@@" = {{.*}} constant { [1 x i8*] } // MANGLING-DAG: @@"??_7C@@pr21031_1@@@@6B@@" = {{.*}} constant { [1 x i8*] } d807 2 a808 2 // MANGLING-DAG: @@"??_7C@@pr21031_2@@@@6BA@@1@@@@" = {{.*}} constant { [1 x i8*] } // MANGLING-DAG: @@"??_7C@@pr21031_2@@@@6BB@@1@@@@" = {{.*}} constant { [1 x i8*] } d821 1 a821 1 // MANGLING-DAG: @@"??_7D@@pr21062_1@@@@6B@@" = {{.*}} constant { [1 x i8*] } d834 1 a834 1 // MANGLING-DAG: @@"??_7D@@pr21062_2@@@@6B@@" = {{.*}} constant { [1 x i8*] } d846 1 a846 1 // MANGLING-DAG: @@"??_7D@@pr21064@@@@6B@@" = {{.*}} constant { [1 x i8*] } @ 1.1.1.11 log @Mark old LLVM instance as dead. @ text @@ 1.1.1.6.4.1 log @file microsoft-abi-vtables-virtual-inheritance.cpp was added on branch tls-maxphys on 2014-08-19 23:47:58 +0000 @ text @d1 766 @ 1.1.1.6.4.2 log @Rebase to HEAD as of a few days ago. @ text @a0 766 // RUN: %clang_cc1 -fno-rtti -emit-llvm -o %t.ll -fdump-vtable-layouts %s -triple=i386-pc-win32 >%t // RUN: FileCheck %s < %t // RUN: FileCheck --check-prefix=MANGLING %s < %t.ll struct Empty { }; struct A { virtual void f(); virtual void z(); // Useful to check there are no thunks for f() when appropriate. }; struct B { virtual void g(); }; struct C: virtual A { // CHECK-LABEL: VFTable for 'A' in 'C' (2 entries) // CHECK-NEXT: 0 | void C::f() // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: VFTable indices for 'C' (1 entry) // CHECK-NEXT: vbtable index 1, vfptr at offset 0 // CHECK-NEXT: 0 | void C::f() // MANGLING-DAG: @@"\01??_7C@@@@6B@@" virtual void f() {} }; C c; void use(C *obj) { obj->f(); } struct D: virtual A { // CHECK-LABEL: VFTable for 'D' (1 entry). // CHECK-NEXT: 0 | void D::h() // CHECK-LABEL: VFTable for 'A' in 'D' (2 entries). // CHECK-NEXT: 0 | void D::f() // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: VFTable indices for 'D' (2 entries). // CHECK-NEXT: via vfptr at offset 0 // CHECK-NEXT: 0 | void D::h() // CHECK-NEXT: via vbtable index 1, vfptr at offset 0 // CHECK-NEXT: 0 | void D::f() // MANGLING-DAG: @@"\01??_7D@@@@6B0@@@@" // MANGLING-DAG: @@"\01??_7D@@@@6BA@@@@@@" virtual void f(); virtual void h(); }; D d; void use(D *obj) { obj->h(); } namespace Test1 { struct X { int x; }; // X and A get reordered in the layout since X doesn't have a vfptr while A has. struct Y : X, A { }; // MANGLING-DAG: @@"\01??_7Y@@Test1@@@@6B@@" struct Z : virtual Y { Z(); // CHECK-LABEL: VFTable for 'A' in 'Test1::Y' in 'Test1::Z' (2 entries). // CHECK-NEXT: 0 | void A::f() // CHECK-NEXT: 1 | void A::z() // CHECK-NOT: VFTable indices for 'Test1::Z' // MANGLING-DAG: @@"\01??_7Z@@Test1@@@@6B@@" }; Z::Z() {} } namespace Test2 { struct X: virtual A, virtual B { // CHECK-LABEL: VFTable for 'Test2::X' (1 entry). // CHECK-NEXT: 0 | void Test2::X::h() // CHECK-LABEL: VFTable for 'A' in 'Test2::X' (2 entries). // CHECK-NEXT: 0 | void A::f() // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: VFTable for 'B' in 'Test2::X' (1 entry). // CHECK-NEXT: 0 | void B::g() // CHECK-LABEL: VFTable indices for 'Test2::X' (1 entry). // CHECK-NEXT: 0 | void Test2::X::h() // MANGLING-DAG: @@"\01??_7X@@Test2@@@@6B01@@@@" // MANGLING-DAG: @@"\01??_7X@@Test2@@@@6BA@@@@@@" // MANGLING-DAG: @@"\01??_7X@@Test2@@@@6BB@@@@@@" virtual void h(); }; X x; void use(X *obj) { obj->h(); } } namespace Test3 { struct X : virtual A { // MANGLING-DAG: @@"\01??_7X@@Test3@@@@6B@@" }; struct Y: virtual X { Y(); // CHECK-LABEL: VFTable for 'A' in 'Test3::X' in 'Test3::Y' (2 entries). // CHECK-NEXT: 0 | void A::f() // CHECK-NEXT: 1 | void A::z() // CHECK-NOT: VFTable indices for 'Test3::Y' // MANGLING-DAG: @@"\01??_7Y@@Test3@@@@6B@@" }; Y::Y() {} } namespace Test4 { struct X: virtual C { X(); // This one's interesting. C::f expects (A*) to be passed as 'this' and does // ECX-=4 to cast to (C*). In X, C and A vbases are reordered, so the thunk // should pass a pointer to the end of X in order // for ECX-=4 to point at the C part. // CHECK-LABEL: VFTable for 'A' in 'C' in 'Test4::X' (2 entries). // CHECK-NEXT: 0 | void C::f() // CHECK-NEXT: [this adjustment: 8 non-virtual] // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: Thunks for 'void C::f()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: 8 non-virtual] // CHECK-NOT: VFTable indices for 'Test4::X' // MANGLING-DAG: @@"\01??_7X@@Test4@@@@6B@@" // Also check the mangling of the thunk. // MANGLING-DAG: define linkonce_odr x86_thiscallcc void @@"\01?f@@C@@@@WPPPPPPPI@@AEXXZ" }; X::X() {} } namespace Test5 { // New methods are added to the base's vftable. struct X : A { // MANGLING-DAG: @@"\01??_7X@@Test5@@@@6B@@" virtual void g(); }; struct Y : virtual X { // CHECK-LABEL: VFTable for 'Test5::Y' (1 entry). // CHECK-NEXT: 0 | void Test5::Y::h() // CHECK-LABEL: VFTable for 'A' in 'Test5::X' in 'Test5::Y' (3 entries). // CHECK-NEXT: 0 | void A::f() // CHECK-NEXT: 1 | void A::z() // CHECK-NEXT: 2 | void Test5::X::g() // CHECK-LABEL: VFTable indices for 'Test5::Y' (1 entry). // CHECK-NEXT: 0 | void Test5::Y::h() // MANGLING-DAG: @@"\01??_7Y@@Test5@@@@6B01@@@@" // MANGLING-DAG: @@"\01??_7Y@@Test5@@@@6BX@@1@@@@" virtual void h(); }; Y y; void use(Y *obj) { obj->h(); } } namespace Test6 { struct X : A, virtual Empty { X(); // CHECK-LABEL: VFTable for 'A' in 'Test6::X' (2 entries). // CHECK-NEXT: 0 | void A::f() // CHECK-NEXT: 1 | void A::z() // CHECK-NOT: VFTable indices for 'Test6::X' // MANGLING-DAG: @@"\01??_7X@@Test6@@@@6B@@" }; X::X() {} } namespace Test7 { struct X : C { // MANGLING-DAG: @@"\01??_7X@@Test7@@@@6B@@" }; struct Y : virtual X { Y(); // CHECK-LABEL: VFTable for 'A' in 'C' in 'Test7::X' in 'Test7::Y' (2 entries). // CHECK-NEXT: 0 | void C::f() // CHECK-NEXT: [this adjustment: 8 non-virtual] // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: Thunks for 'void C::f()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: 8 non-virtual] // CHECK-NOT: VFTable indices for 'Test7::Y' // MANGLING-DAG: @@"\01??_7Y@@Test7@@@@6B@@" }; Y::Y() {} } namespace Test8 { // This is a typical diamond inheritance with a shared 'A' vbase. struct X : D, C { // CHECK-LABEL: VFTable for 'D' in 'Test8::X' (1 entry). // CHECK-NEXT: 0 | void D::h() // CHECK-LABEL: VFTable for 'A' in 'D' in 'Test8::X' (2 entries). // CHECK-NEXT: 0 | void Test8::X::f() // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: VFTable indices for 'Test8::X' (1 entry). // CHECK-NEXT: via vbtable index 1, vfptr at offset 0 // CHECK-NEXT: 0 | void Test8::X::f() // MANGLING-DAG: @@"\01??_7X@@Test8@@@@6BA@@@@@@" // MANGLING-DAG: @@"\01??_7X@@Test8@@@@6BD@@@@@@" virtual void f(); }; X x; void use(X *obj) { obj->f(); } // Another diamond inheritance which led to AST crashes. struct Y : virtual A {}; struct Z : Y, C { // CHECK-LABEL: VFTable for 'A' in 'Test8::Y' in 'Test8::Z' (2 entries). // CHECK-NEXT: 0 | void Test8::Z::f() // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: VFTable indices for 'Test8::Z' (1 entry). // CHECK-NEXT: via vbtable index 1, vfptr at offset 0 // CHECK-NEXT: 0 | void Test8::Z::f() virtual void f(); }; Z z; void use(Z *obj) { obj->f(); } // Another diamond inheritance which we miscompiled (PR18967). struct W : virtual A { virtual void bar(); }; struct T : W, C { // CHECK-LABEL: VFTable for 'Test8::W' in 'Test8::T' (1 entry) // CHECK-NEXT: 0 | void Test8::T::bar() // CHECK-LABEL: VFTable for 'A' in 'Test8::W' in 'Test8::T' (2 entries) // CHECK-NEXT: 0 | void C::f() // CHECK-NEXT: [this adjustment: -4 non-virtual] // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: Thunks for 'void C::f()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual] virtual void bar(); int field; }; T t; void use(T *obj) { obj->bar(); } } namespace Test9 { struct X : A { }; struct Y : virtual X { // CHECK-LABEL: VFTable for 'Test9::Y' (1 entry). // CHECK-NEXT: 0 | void Test9::Y::h() // CHECK-LABEL: VFTable for 'A' in 'Test9::X' in 'Test9::Y' (2 entries). // CHECK-NEXT: 0 | void A::f() // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: VFTable indices for 'Test9::Y' (1 entry). // CHECK-NEXT: 0 | void Test9::Y::h() // MANGLING-DAG: @@"\01??_7Y@@Test9@@@@6B01@@@@" // MANGLING-DAG: @@"\01??_7Y@@Test9@@@@6BX@@1@@@@" virtual void h(); }; Y y; void use(Y *obj) { obj->h(); } struct Z : Y, virtual B { Z(); // CHECK-LABEL: VFTable for 'Test9::Y' in 'Test9::Z' (1 entry). // CHECK-NEXT: 0 | void Test9::Y::h() // CHECK-LABEL: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' (2 entries). // CHECK-NEXT: 0 | void A::f() // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: VFTable for 'B' in 'Test9::Z' (1 entry). // CHECK-NEXT: 0 | void B::g() // CHECK-NOT: VFTable indices for 'Test9::Z' // MANGLING-DAG: @@"\01??_7Z@@Test9@@@@6BX@@1@@@@" // MANGLING-DAG: @@"\01??_7Z@@Test9@@@@6BY@@1@@@@" // MANGLING-DAG: @@"\01??_7Z@@Test9@@@@6B@@" }; Z::Z() {} struct W : Z, D, virtual A, virtual B { W(); // CHECK-LABEL: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::W' (1 entry). // CHECK-NEXT: 0 | void Test9::Y::h() // CHECK-LABEL: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::W' (2 entries). // CHECK-NEXT: 0 | void A::f() // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: VFTable for 'B' in 'Test9::Z' in 'Test9::W' (1 entry). // CHECK-NEXT: 0 | void B::g() // CHECK-LABEL: VFTable for 'D' in 'Test9::W' (1 entry). // CHECK-NEXT: 0 | void D::h() // CHECK-LABEL: VFTable for 'A' in 'D' in 'Test9::W' (2 entries). // CHECK-NEXT: 0 | void D::f() // CHECK-NEXT: [this adjustment: -8 non-virtual] // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: Thunks for 'void D::f()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual] // CHECK-NOT: VFTable indices for 'Test9::W' // MANGLING-DAG: @@"\01??_7W@@Test9@@@@6BA@@@@@@" // MANGLING-DAG: @@"\01??_7W@@Test9@@@@6BD@@@@@@" // MANGLING-DAG: @@"\01??_7W@@Test9@@@@6BX@@1@@@@" // MANGLING-DAG: @@"\01??_7W@@Test9@@@@6B@@" // MANGLING-DAG: @@"\01??_7W@@Test9@@@@6BY@@1@@@@" }; W::W() {} struct T : Z, D, virtual A, virtual B { // CHECK-LABEL: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::T' (1 entry). // CHECK-NEXT: 0 | void Test9::T::h() // CHECK-LABEL: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::T' (2 entries). // CHECK-NEXT: 0 | void Test9::T::f() // CHECK-NEXT: 1 | void Test9::T::z() // CHECK-LABEL: VFTable for 'B' in 'Test9::Z' in 'Test9::T' (1 entry). // CHECK-NEXT: 0 | void Test9::T::g() // CHECK-LABEL: VFTable for 'D' in 'Test9::T' (1 entry). // CHECK-NEXT: 0 | void Test9::T::h() // CHECK-NEXT: [this adjustment: -8 non-virtual] // CHECK-LABEL: Thunks for 'void Test9::T::h()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual] // CHECK-LABEL: VFTable for 'A' in 'D' in 'Test9::T' (2 entries). // CHECK-NEXT: 0 | void Test9::T::f() // CHECK-NEXT: [this adjustment: -8 non-virtual] // CHECK-NEXT: 1 | void Test9::T::z() // CHECK-NEXT: [this adjustment: -8 non-virtual] // CHECK-LABEL: Thunks for 'void Test9::T::f()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual] // CHECK-LABEL: Thunks for 'void Test9::T::z()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual] // CHECK-LABEL: VFTable indices for 'Test9::T' (4 entries). // CHECK-NEXT: via vfptr at offset 0 // CHECK-NEXT: 0 | void Test9::T::h() // CHECK-NEXT: via vbtable index 1, vfptr at offset 0 // CHECK-NEXT: 0 | void Test9::T::f() // CHECK-NEXT: 1 | void Test9::T::z() // CHECK-NEXT: via vbtable index 2, vfptr at offset 0 // CHECK-NEXT: 0 | void Test9::T::g() // MANGLING-DAG: @@"\01??_7T@@Test9@@@@6BA@@@@@@" // MANGLING-DAG: @@"\01??_7T@@Test9@@@@6BD@@@@@@" // MANGLING-DAG: @@"\01??_7T@@Test9@@@@6BX@@1@@@@" // MANGLING-DAG: @@"\01??_7T@@Test9@@@@6B@@" // MANGLING-DAG: @@"\01??_7T@@Test9@@@@6BY@@1@@@@" virtual void f(); virtual void g(); virtual void h(); virtual void z(); }; T t; void use(T *obj) { obj->f(); } } namespace Test10 { struct X : virtual C, virtual A { // CHECK-LABEL: VFTable for 'A' in 'C' in 'Test10::X' (2 entries). // CHECK-NEXT: 0 | void Test10::X::f() // CHECK-NEXT: 1 | void A::z() // CHECK-LABEL: VFTable indices for 'Test10::X' (1 entry). // CHECK-NEXT: via vbtable index 1, vfptr at offset 0 // CHECK-NEXT: 0 | void Test10::X::f() virtual void f(); }; void X::f() {} X x; void use(X *obj) { obj->f(); } } namespace Test11 { struct X : virtual A {}; struct Y { virtual void g(); }; struct Z : virtual X, Y { // MANGLING-DAG: @@"\01??_7Z@@Test11@@@@6BY@@1@@@@" // MANGLING-DAG: @@"\01??_7Z@@Test11@@@@6BX@@1@@@@" }; Z z; struct W : virtual X, A {}; // Used to crash, PR17748. W w; } namespace Test12 { struct X : B, A { }; struct Y : X { virtual void f(); // Overrides A::f. }; struct Z : virtual Y { // CHECK-LABEL: VFTable for 'A' in 'Test12::X' in 'Test12::Y' in 'Test12::Z' (2 entries). // CHECK-NEXT: 0 | void Test12::Y::f() // CHECK-NEXT: 1 | void A::z() int z; // MANGLING-DAG: @@"\01??_7Z@@Test12@@@@6BA@@@@@@" = {{.*}}@@"\01?f@@Y@@Test12@@@@UAEXXZ" }; struct W : Z { // CHECK-LABEL: VFTable for 'A' in 'Test12::X' in 'Test12::Y' in 'Test12::Z' in 'Test12::W' (2 entries). // CHECK-NEXT: 0 | void Test12::Y::f() // CHECK-NEXT: 1 | void A::z() W(); int w; // MANGLING-DAG: @@"\01??_7W@@Test12@@@@6BA@@@@@@" = {{.*}}@@"\01?f@@Y@@Test12@@@@UAEXXZ" }; W::W() {} } namespace vdtors { struct X { virtual ~X(); virtual void zzz(); }; struct Y : virtual X { // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::Y' (2 entries). // CHECK-NEXT: 0 | vdtors::Y::~Y() [scalar deleting] // CHECK-NEXT: 1 | void vdtors::X::zzz() // CHECK-NOT: Thunks for 'vdtors::Y::~Y()' virtual ~Y(); }; Y y; void use(Y *obj) { delete obj; } struct Z { virtual void z(); }; struct W : Z, X { // Implicit virtual dtor. }; struct U : virtual W { // CHECK-LABEL: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::U' (1 entry). // CHECK-NEXT: 0 | void vdtors::Z::z() // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::W' in 'vdtors::U' (2 entries). // CHECK-NEXT: 0 | vdtors::U::~U() [scalar deleting] // CHECK-NEXT: [this adjustment: -4 non-virtual] // CHECK-NEXT: 1 | void vdtors::X::zzz() // CHECK-LABEL: Thunks for 'vdtors::U::~U()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual] // CHECK-LABEL: VFTable indices for 'vdtors::U' (1 entry). // CHECK-NEXT: -- accessible via vbtable index 1, vfptr at offset 4 -- // CHECK-NEXT: 0 | vdtors::U::~U() [scalar deleting] virtual ~U(); }; U u; void use(U *obj) { delete obj; } struct V : virtual W { // CHECK-LABEL: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::V' (1 entry). // CHECK-NEXT: 0 | void vdtors::Z::z() // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::W' in 'vdtors::V' (2 entries). // CHECK-NEXT: 0 | vdtors::V::~V() [scalar deleting] // CHECK-NEXT: [this adjustment: -4 non-virtual] // CHECK-NEXT: 1 | void vdtors::X::zzz() // CHECK-LABEL: Thunks for 'vdtors::V::~V()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual] // CHECK-LABEL: VFTable indices for 'vdtors::V' (1 entry). // CHECK-NEXT: -- accessible via vbtable index 1, vfptr at offset 4 -- // CHECK-NEXT: 0 | vdtors::V::~V() [scalar deleting] }; V v; void use(V *obj) { delete obj; } struct T : virtual X { virtual ~T(); }; struct P : T, Y { // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::T' in 'vdtors::P' (2 entries). // CHECK-NEXT: 0 | vdtors::P::~P() [scalar deleting] // CHECK-NEXT: 1 | void vdtors::X::zzz() // CHECK-NOT: Thunks for 'vdtors::P::~P()' virtual ~P(); }; P p; void use(P *obj) { delete obj; } struct Q { virtual ~Q(); }; // PR19172: Yet another diamond we miscompiled. struct R : virtual Q, X { // CHECK-LABEL: VFTable for 'vdtors::X' in 'vdtors::R' (2 entries). // CHECK-NEXT: 0 | vdtors::R::~R() [scalar deleting] // CHECK-NEXT: 1 | void vdtors::X::zzz() // CHECK-LABEL: VFTable for 'vdtors::Q' in 'vdtors::R' (1 entry). // CHECK-NEXT: 0 | vdtors::R::~R() [scalar deleting] // CHECK-NEXT: [this adjustment: -8 non-virtual] // CHECK-LABEL: Thunks for 'vdtors::R::~R()' (1 entry). // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual] // CHECK-LABEL: VFTable indices for 'vdtors::R' (1 entry). // CHECK-NEXT: 0 | vdtors::R::~R() [scalar deleting] virtual ~R(); }; R r; void use(R *obj) { delete obj; } } namespace return_adjustment { struct X : virtual A { virtual void f(); }; struct Y : virtual A, virtual X { virtual void f(); }; struct Z { virtual A* foo(); }; struct W : Z { // CHECK-LABEL: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' (2 entries). // CHECK-NEXT: 0 | return_adjustment::X *return_adjustment::W::foo() // CHECK-NEXT: [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual] // CHECK-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo() // CHECK-LABEL: Thunks for 'return_adjustment::X *return_adjustment::W::foo()' (1 entry). // CHECK-NEXT: 0 | [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual] // CHECK-LABEL: VFTable indices for 'return_adjustment::W' (1 entry). // CHECK-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo() virtual X* foo(); }; W w; void use(W *obj) { obj->foo(); } struct T : W { // CHECK-LABEL: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' in 'return_adjustment::T' (3 entries). // CHECK-NEXT: 0 | return_adjustment::Y *return_adjustment::T::foo() // CHECK-NEXT: [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual] // CHECK-NEXT: 1 | return_adjustment::Y *return_adjustment::T::foo() // CHECK-NEXT: [return adjustment (to type 'struct return_adjustment::X *'): vbase #2, 0 non-virtual] // CHECK-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo() // CHECK-LABEL: Thunks for 'return_adjustment::Y *return_adjustment::T::foo()' (2 entries). // CHECK-NEXT: 0 | [return adjustment (to type 'struct A *'): vbase #1, 0 non-virtual] // CHECK-NEXT: 1 | [return adjustment (to type 'struct return_adjustment::X *'): vbase #2, 0 non-virtual] // CHECK-LABEL: VFTable indices for 'return_adjustment::T' (1 entry). // CHECK-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo() virtual Y* foo(); }; T t; void use(T *obj) { obj->foo(); } struct U : virtual A { virtual void g(); // adds a vfptr }; struct V : Z { // CHECK-LABEL: VFTable for 'return_adjustment::Z' in 'return_adjustment::V' (2 entries). // CHECK-NEXT: 0 | return_adjustment::U *return_adjustment::V::foo() // CHECK-NEXT: [return adjustment (to type 'struct A *'): vbptr at offset 4, vbase #1, 0 non-virtual] // CHECK-NEXT: 1 | return_adjustment::U *return_adjustment::V::foo() // CHECK-LABEL: Thunks for 'return_adjustment::U *return_adjustment::V::foo()' (1 entry). // CHECK-NEXT: 0 | [return adjustment (to type 'struct A *'): vbptr at offset 4, vbase #1, 0 non-virtual] // CHECK-LABEL: VFTable indices for 'return_adjustment::V' (1 entry). // CHECK-NEXT: 1 | return_adjustment::U *return_adjustment::V::foo() virtual U* foo(); }; V v; void use(V *obj) { obj->foo(); } } namespace pr17748 { struct A { virtual void f() {} }; struct B : virtual A { B() {} }; struct C : virtual B, A { C() {} }; C c; // MANGLING-DAG: @@"\01??_7A@@pr17748@@@@6B@@" // MANGLING-DAG: @@"\01??_7B@@pr17748@@@@6B@@" // MANGLING-DAG: @@"\01??_7C@@pr17748@@@@6BA@@1@@@@" // MANGLING-DAG: @@"\01??_7C@@pr17748@@@@6BB@@1@@@@" } namespace pr19066 { struct X : virtual B {}; struct Y : virtual X, B { Y(); // CHECK-LABEL: VFTable for 'B' in 'pr19066::Y' (1 entry). // CHECK-NEXT: 0 | void B::g() // CHECK-LABEL: VFTable for 'B' in 'pr19066::X' in 'pr19066::Y' (1 entry). // CHECK-NEXT: 0 | void B::g() }; Y::Y() {} } namespace pr19240 { struct A { virtual void c(); }; struct B : virtual A { virtual void c(); }; struct C { }; struct D : virtual A, virtual C, B {}; D obj; // Each MDC only has one vftable. // MANGLING-DAG: @@"\01??_7D@@pr19240@@@@6B@@" // MANGLING-DAG: @@"\01??_7A@@pr19240@@@@6B@@" // MANGLING-DAG: @@"\01??_7B@@pr19240@@@@6B@@" } namespace pr19408 { // This test is a non-vtordisp version of the reproducer for PR19408. struct X : virtual A { int x; }; struct Y : X { virtual void f(); int y; }; struct Z : Y { // CHECK-LABEL: VFTable for 'A' in 'pr19408::X' in 'pr19408::Y' in 'pr19408::Z' (2 entries). // CHECK-NEXT: 0 | void pr19408::Y::f() // CHECK-NEXT: [this adjustment: -4 non-virtual] // CHECK-NEXT: 1 | void A::z() Z(); int z; // MANGLING-DAG: @@"\01??_7Z@@pr19408@@@@6B@@" = {{.*}}@@"\01?f@@Y@@pr19408@@@@W3AEXXZ" }; Z::Z() {} struct W : B, Y { // CHECK-LABEL: VFTable for 'A' in 'pr19408::X' in 'pr19408::Y' in 'pr19408::W' (2 entries). // CHECK-NEXT: 0 | void pr19408::Y::f() // CHECK-NEXT: [this adjustment: -4 non-virtual] // CHECK-NEXT: 1 | void A::z() W(); int w; // MANGLING-DAG: @@"\01??_7W@@pr19408@@@@6BY@@1@@@@" = {{.*}}@@"\01?f@@Y@@pr19408@@@@W3AEXXZ" }; W::W() {} } @ 1.1.1.4.4.1 log @file microsoft-abi-vtables-virtual-inheritance.cpp was added on branch yamt-pagecache on 2014-05-22 16:18:57 +0000 @ text @d1 604 @ 1.1.1.4.4.2 log @sync with head. for a reference, the tree before this commit was tagged as yamt-pagecache-tag8. this commit was splitted into small chunks to avoid a limitation of cvs. ("Protocol error: too many arguments") @ text @a0 604 // RUN: %clang_cc1 -fno-rtti -emit-llvm -o %t.ll -fdump-vtable-layouts %s -triple=i386-pc-win32 >%t // RUN: FileCheck --check-prefix=VTABLE-C %s < %t // RUN: FileCheck --check-prefix=VTABLE-D %s < %t // RUN: FileCheck --check-prefix=TEST1 %s < %t // RUN: FileCheck --check-prefix=TEST2 %s < %t // RUN: FileCheck --check-prefix=TEST3 %s < %t // RUN: FileCheck --check-prefix=TEST4 %s < %t // RUN: FileCheck --check-prefix=TEST5 %s < %t // RUN: FileCheck --check-prefix=TEST6 %s < %t // RUN: FileCheck --check-prefix=TEST7 %s < %t // RUN: FileCheck --check-prefix=TEST8-X %s < %t // RUN: FileCheck --check-prefix=TEST8-Z %s < %t // RUN: FileCheck --check-prefix=TEST9-Y %s < %t // RUN: FileCheck --check-prefix=TEST9-Z %s < %t // RUN: FileCheck --check-prefix=TEST9-W %s < %t // RUN: FileCheck --check-prefix=TEST9-T %s < %t // RUN: FileCheck --check-prefix=TEST10 %s < %t // RUN: FileCheck --check-prefix=VDTORS-Y %s < %t // RUN: FileCheck --check-prefix=VDTORS-U %s < %t // RUN: FileCheck --check-prefix=VDTORS-V %s < %t // RUN: FileCheck --check-prefix=VDTORS-P %s < %t // RUN: FileCheck --check-prefix=RET-W %s < %t // RUN: FileCheck --check-prefix=RET-T %s < %t // RUN: FileCheck --check-prefix=RET-V %s < %t // RUN: FileCheck --check-prefix=MANGLING %s < %t.ll struct Empty { }; struct A { virtual void f(); virtual void z(); // Useful to check there are no thunks for f() when appropriate. }; struct B { virtual void g(); }; struct C: virtual A { // VTABLE-C: VFTable for 'A' in 'C' (2 entries) // VTABLE-C-NEXT: 0 | void C::f() // VTABLE-C-NEXT: 1 | void A::z() // VTABLE-C: VFTable indices for 'C' (1 entries) // VTABLE-C-NEXT: vbtable index 1, vfptr at offset 0 // VTABLE-C-NEXT: 0 | void C::f() // MANGLING-DAG: @@"\01??_7C@@@@6B@@" virtual void f(); }; C c; struct D: virtual A { // VTABLE-D: VFTable for 'D' (1 entries). // VTABLE-D-NEXT: 0 | void D::h() // VTABLE-D: VFTable for 'A' in 'D' (2 entries). // VTABLE-D-NEXT: 0 | void D::f() // VTABLE-D-NEXT: 1 | void A::z() // VTABLE-D: VFTable indices for 'D' (2 entries). // VTABLE-D-NEXT: via vfptr at offset 0 // VTABLE-D-NEXT: 0 | void D::h() // VTABLE-D-NEXT: via vbtable index 1, vfptr at offset 0 // VTABLE-D-NEXT: 0 | void D::f() // MANGLING-DAG: @@"\01??_7D@@@@6B0@@@@" // MANGLING-DAG: @@"\01??_7D@@@@6BA@@@@@@" virtual void f(); virtual void h(); }; void D::h() {} D d; namespace Test1 { struct X { int x; }; // X and A get reordered in the layout since X doesn't have a vfptr while A has. struct Y : X, A { }; // MANGLING-DAG: @@"\01??_7Y@@Test1@@@@6B@@" struct Z : virtual Y { // TEST1: VFTable for 'A' in 'Test1::Y' in 'Test1::Z' (2 entries). // TEST1-NEXT: 0 | void A::f() // TEST1-NEXT: 1 | void A::z() // TEST1-NOT: VFTable indices for 'Test1::Z' // MANGLING-DAG: @@"\01??_7Z@@Test1@@@@6B@@" }; Z z; } namespace Test2 { struct X: virtual A, virtual B { // TEST2: VFTable for 'Test2::X' (1 entries). // TEST2-NEXT: 0 | void Test2::X::h() // TEST2: VFTable for 'A' in 'Test2::X' (2 entries). // TEST2-NEXT: 0 | void A::f() // TEST2-NEXT: 1 | void A::z() // TEST2: VFTable for 'B' in 'Test2::X' (1 entries). // TEST2-NEXT: 0 | void B::g() // TEST2: VFTable indices for 'Test2::X' (1 entries). // TEST2-NEXT: 0 | void Test2::X::h() // MANGLING-DAG: @@"\01??_7X@@Test2@@@@6B01@@@@" // MANGLING-DAG: @@"\01??_7X@@Test2@@@@6BA@@@@@@" // MANGLING-DAG: @@"\01??_7X@@Test2@@@@6BB@@@@@@" virtual void h(); }; X x; } namespace Test3 { struct X : virtual A { // MANGLING-DAG: @@"\01??_7X@@Test3@@@@6B@@" }; struct Y: virtual X { // TEST3: VFTable for 'A' in 'Test3::X' in 'Test3::Y' (2 entries). // TEST3-NEXT: 0 | void A::f() // TEST3-NEXT: 1 | void A::z() // TEST3-NOT: VFTable indices for 'Test3::Y' // MANGLING-DAG: @@"\01??_7Y@@Test3@@@@6B@@" }; Y y; } namespace Test4 { struct X: virtual C { // This one's interesting. C::f expects (A*) to be passed as 'this' and does // ECX-=4 to cast to (C*). In X, C and A vbases are reordered, so the thunk // should pass a pointer to the end of X in order // for ECX-=4 to point at the C part. // TEST4: VFTable for 'A' in 'C' in 'Test4::X' (2 entries). // TEST4-NEXT: 0 | void C::f() // TEST4-NEXT: [this adjustment: 8 non-virtual] // TEST4-NEXT: 1 | void A::z() // TEST4-NOT: VFTable indices for 'Test4::X' // MANGLING-DAG: @@"\01??_7X@@Test4@@@@6B@@" // Also check the mangling of the thunk. // MANGLING-DAG: define weak x86_thiscallcc void @@"\01?f@@C@@@@WPPPPPPPI@@AEXXZ" }; X x; } namespace Test5 { // New methods are added to the base's vftable. struct X : A { // MANGLING-DAG: @@"\01??_7X@@Test5@@@@6B@@" virtual void g(); }; struct Y : virtual X { // TEST5: VFTable for 'Test5::Y' (1 entries). // TEST5-NEXT: 0 | void Test5::Y::h() // TEST5: VFTable for 'A' in 'Test5::X' in 'Test5::Y' (3 entries). // TEST5-NEXT: 0 | void A::f() // TEST5-NEXT: 1 | void A::z() // TEST5-NEXT: 2 | void Test5::X::g() // TEST5: VFTable indices for 'Test5::Y' (1 entries). // TEST5-NEXT: 0 | void Test5::Y::h() // MANGLING-DAG: @@"\01??_7Y@@Test5@@@@6B01@@@@" // MANGLING-DAG: @@"\01??_7Y@@Test5@@@@6BX@@1@@@@" virtual void h(); }; Y y; } namespace Test6 { struct X : A, virtual Empty { // TEST6: VFTable for 'A' in 'Test6::X' (2 entries). // TEST6-NEXT: 0 | void A::f() // TEST6-NEXT: 1 | void A::z() // TEST6-NOT: VFTable indices for 'Test6::X' // MANGLING-DAG: @@"\01??_7X@@Test6@@@@6B@@" }; X x; } namespace Test7 { struct X : C { // MANGLING-DAG: @@"\01??_7X@@Test7@@@@6B@@" }; struct Y : virtual X { // TEST7: VFTable for 'A' in 'C' in 'Test7::X' in 'Test7::Y' (2 entries). // TEST7-NEXT: 0 | void C::f() // TEST7-NEXT: [this adjustment: 8 non-virtual] // TEST7-NEXT: 1 | void A::z() // TEST7: Thunks for 'void C::f()' (1 entry). // TEST7-NEXT: 0 | [this adjustment: 8 non-virtual] // TEST7-NOT: VFTable indices for 'Test7::Y' // MANGLING-DAG: @@"\01??_7Y@@Test7@@@@6B@@" }; Y y; } namespace Test8 { // This is a typical diamond inheritance with a shared 'A' vbase. struct X : D, C { // TEST8-X: VFTable for 'D' in 'Test8::X' (1 entries). // TEST8-X-NEXT: 0 | void D::h() // TEST8-X: VFTable for 'A' in 'D' in 'Test8::X' (2 entries). // TEST8-X-NEXT: 0 | void Test8::X::f() // TEST8-X-NEXT: 1 | void A::z() // TEST8-X: VFTable indices for 'Test8::X' (1 entries). // TEST8-X-NEXT: via vbtable index 1, vfptr at offset 0 // TEST8-X-NEXT: 0 | void Test8::X::f() // MANGLING-DAG: @@"\01??_7X@@Test8@@@@6BA@@@@@@" // MANGLING-DAG: @@"\01??_7X@@Test8@@@@6BD@@@@@@" virtual void f(); }; X x; // Another diamond inheritance which led to AST crashes. struct Y : virtual A {}; class Z : Y, C { // TEST8-Z: VFTable for 'A' in 'Test8::Y' in 'Test8::Z' (2 entries). // TEST8-Z-NEXT: 0 | void Test8::Z::f() // TEST8-Z-NEXT: 1 | void A::z() // TEST8-Z: VFTable indices for 'Test8::Z' (1 entries). // TEST8-Z-NEXT: via vbtable index 1, vfptr at offset 0 // TEST8-Z-NEXT: 0 | void Test8::Z::f() virtual void f(); }; Z z; } namespace Test9 { struct X : A { }; struct Y : virtual X { // TEST9-Y: VFTable for 'Test9::Y' (1 entries). // TEST9-Y-NEXT: 0 | void Test9::Y::h() // TEST9-Y: VFTable for 'A' in 'Test9::X' in 'Test9::Y' (2 entries). // TEST9-Y-NEXT: 0 | void A::f() // TEST9-Y-NEXT: 1 | void A::z() // TEST9-Y: VFTable indices for 'Test9::Y' (1 entries). // TEST9-Y-NEXT: 0 | void Test9::Y::h() // MANGLING-DAG: @@"\01??_7Y@@Test9@@@@6B01@@@@" // MANGLING-DAG: @@"\01??_7Y@@Test9@@@@6BX@@1@@@@" virtual void h(); }; Y y; struct Z : Y, virtual B { // TEST9-Z: VFTable for 'Test9::Y' in 'Test9::Z' (1 entries). // TEST9-Z-NEXT: 0 | void Test9::Y::h() // TEST9-Z: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' (2 entries). // TEST9-Z-NEXT: 0 | void A::f() // TEST9-Z-NEXT: 1 | void A::z() // TEST9-Z: VFTable for 'B' in 'Test9::Z' (1 entries). // TEST9-Z-NEXT: 0 | void B::g() // TEST9-Z-NOT: VFTable indices for 'Test9::Z' // MANGLING-DAG: @@"\01??_7Z@@Test9@@@@6BX@@1@@@@" // MANGLING-DAG: @@"\01??_7Z@@Test9@@@@6BY@@1@@@@" // MANGLING-DAG: @@"\01??_7Z@@Test9@@@@6B@@" }; Z z; struct W : Z, D, virtual A, virtual B { // TEST9-W: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::W' (1 entries). // TEST9-W-NEXT: 0 | void Test9::Y::h() // TEST9-W: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::W' (2 entries). // TEST9-W-NEXT: 0 | void A::f() // TEST9-W-NEXT: 1 | void A::z() // TEST9-W: VFTable for 'B' in 'Test9::Z' in 'Test9::W' (1 entries). // TEST9-W-NEXT: 0 | void B::g() // TEST9-W: VFTable for 'D' in 'Test9::W' (1 entries). // TEST9-W-NEXT: 0 | void D::h() // TEST9-W: VFTable for 'A' in 'D' in 'Test9::W' (2 entries). // TEST9-W-NEXT: 0 | void D::f() // TEST9-W-NEXT: [this adjustment: -8 non-virtual] // TEST9-W-NEXT: 1 | void A::z() // TEST9-W: Thunks for 'void D::f()' (1 entry). // TEST9-W-NEXT: 0 | [this adjustment: -8 non-virtual] // TEST9-W-NOT: VFTable indices for 'Test9::W' // MANGLING-DAG: @@"\01??_7W@@Test9@@@@6BA@@@@@@" // MANGLING-DAG: @@"\01??_7W@@Test9@@@@6BD@@@@@@" // MANGLING-DAG: @@"\01??_7W@@Test9@@@@6BX@@1@@@@" // MANGLING-DAG: @@"\01??_7W@@Test9@@@@6B@@" // MANGLING-DAG: @@"\01??_7W@@Test9@@@@6BY@@1@@@@" }; W w; struct T : Z, D, virtual A, virtual B { // TEST9-T: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::T' (1 entries). // TEST9-T-NEXT: 0 | void Test9::T::h() // TEST9-T: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::T' (2 entries). // TEST9-T-NEXT: 0 | void Test9::T::f() // TEST9-T-NEXT: 1 | void Test9::T::z() // TEST9-T: VFTable for 'B' in 'Test9::Z' in 'Test9::T' (1 entries). // TEST9-T-NEXT: 0 | void Test9::T::g() // TEST9-T: VFTable for 'D' in 'Test9::T' (1 entries). // TEST9-T-NEXT: 0 | void Test9::T::h() // TEST9-T-NEXT: [this adjustment: -8 non-virtual] // TEST9-T: Thunks for 'void Test9::T::h()' (1 entry). // TEST9-T-NEXT: 0 | [this adjustment: -8 non-virtual] // TEST9-T: VFTable for 'A' in 'D' in 'Test9::T' (2 entries). // TEST9-T-NEXT: 0 | void Test9::T::f() // TEST9-T-NEXT: [this adjustment: -8 non-virtual] // TEST9-T-NEXT: 1 | void Test9::T::z() // TEST9-T-NEXT: [this adjustment: -8 non-virtual] // TEST9-T: Thunks for 'void Test9::T::f()' (1 entry). // TEST9-T-NEXT: 0 | [this adjustment: -8 non-virtual] // TEST9-T: Thunks for 'void Test9::T::z()' (1 entry). // TEST9-T-NEXT: 0 | [this adjustment: -8 non-virtual] // TEST9-T: VFTable indices for 'Test9::T' (4 entries). // TEST9-T-NEXT: via vfptr at offset 0 // TEST9-T-NEXT: 0 | void Test9::T::h() // TEST9-T-NEXT: via vbtable index 1, vfptr at offset 0 // TEST9-T-NEXT: 0 | void Test9::T::f() // TEST9-T-NEXT: 1 | void Test9::T::z() // TEST9-T-NEXT: via vbtable index 2, vfptr at offset 0 // TEST9-T-NEXT: 0 | void Test9::T::g() // MANGLING-DAG: @@"\01??_7T@@Test9@@@@6BA@@@@@@" // MANGLING-DAG: @@"\01??_7T@@Test9@@@@6BD@@@@@@" // MANGLING-DAG: @@"\01??_7T@@Test9@@@@6BX@@1@@@@" // MANGLING-DAG: @@"\01??_7T@@Test9@@@@6B@@" // MANGLING-DAG: @@"\01??_7T@@Test9@@@@6BY@@1@@@@" virtual void f(); virtual void g(); virtual void h(); virtual void z(); }; T t; } namespace Test10 { struct X : virtual C, virtual A { // TEST10: VFTable for 'A' in 'C' in 'Test10::X' (2 entries). // TEST10-NEXT: 0 | void Test10::X::f() // TEST10-NEXT: 1 | void A::z() // TEST10: VFTable indices for 'Test10::X' (1 entries). // TEST10-NEXT: via vbtable index 1, vfptr at offset 0 // TEST10-NEXT: 0 | void Test10::X::f() virtual void f(); }; void X::f() {} X x; } namespace Test11 { struct X : virtual A {}; struct Y { virtual void g(); }; struct Z : virtual X, Y { // MANGLING-DAG: @@"\01??_7Z@@Test11@@@@6BY@@1@@@@" // MANGLING-DAG: @@"\01??_7Z@@Test11@@@@6BX@@1@@@@" }; Z z; struct W : virtual X, A {}; // PR17748 FIXME this one hits UNREACHABLE: // W w; } namespace vdtors { struct X { virtual ~X(); virtual void zzz(); }; struct Y : virtual X { // VDTORS-Y: VFTable for 'vdtors::X' in 'vdtors::Y' (2 entries). // VDTORS-Y-NEXT: 0 | vdtors::Y::~Y() [scalar deleting] // VDTORS-Y-NEXT: 1 | void vdtors::X::zzz() // VDTORS-Y-NOT: Thunks for 'vdtors::Y::~Y()' virtual ~Y(); }; Y y; struct Z { virtual void z(); }; struct W : Z, X { // Implicit virtual dtor. }; struct U : virtual W { // VDTORS-U: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::U' (1 entries). // VDTORS-U-NEXT: 0 | void vdtors::Z::z() // VDTORS-U: VFTable for 'vdtors::X' in 'vdtors::W' in 'vdtors::U' (2 entries). // VDTORS-U-NEXT: 0 | vdtors::U::~U() [scalar deleting] // VDTORS-U-NEXT: [this adjustment: -4 non-virtual] // VDTORS-U-NEXT: 1 | void vdtors::X::zzz() // VDTORS-U: Thunks for 'vdtors::W::~W()' (1 entry). // VDTORS-U-NEXT: 0 | [this adjustment: -4 non-virtual] // VDTORS-U: VFTable indices for 'vdtors::U' (1 entries). // VDTORS-U-NEXT: -- accessible via vbtable index 1, vfptr at offset 4 -- // VDTORS-U-NEXT: 0 | vdtors::U::~U() [scalar deleting] virtual ~U(); }; U u; struct V : virtual W { // VDTORS-V: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::V' (1 entries). // VDTORS-V-NEXT: 0 | void vdtors::Z::z() // VDTORS-V: VFTable for 'vdtors::X' in 'vdtors::W' in 'vdtors::V' (2 entries). // VDTORS-V-NEXT: 0 | vdtors::V::~V() [scalar deleting] // VDTORS-V-NEXT: [this adjustment: -4 non-virtual] // VDTORS-V-NEXT: 1 | void vdtors::X::zzz() // VDTORS-V: Thunks for 'vdtors::W::~W()' (1 entry). // VDTORS-V-NEXT: 0 | [this adjustment: -4 non-virtual] // VDTORS-V: VFTable indices for 'vdtors::V' (1 entries). // VDTORS-V-NEXT: -- accessible via vbtable index 1, vfptr at offset 4 -- // VDTORS-V-NEXT: 0 | vdtors::V::~V() [scalar deleting] }; V v; struct T : virtual X { virtual ~T(); }; struct P : T, Y { // VDTORS-P: VFTable for 'vdtors::X' in 'vdtors::T' in 'vdtors::P' (2 entries). // VDTORS-P-NEXT: 0 | vdtors::P::~P() [scalar deleting] // VDTORS-P-NEXT: 1 | void vdtors::X::zzz() // VDTORS-P-NOT: Thunks for 'vdtors::P::~P()' virtual ~P(); }; P p; } namespace return_adjustment { struct X : virtual A { virtual void f(); }; struct Y : virtual A, virtual X { virtual void f(); }; struct Z { virtual A* foo(); }; struct W : Z { // RET-W: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' (2 entries). // RET-W-NEXT: 0 | return_adjustment::X *return_adjustment::W::foo() // RET-W-NEXT: [return adjustment: vbase #1, 0 non-virtual] // RET-W-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo() // RET-W: VFTable indices for 'return_adjustment::W' (1 entries). // RET-W-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo() virtual X* foo(); }; W y; struct T : W { // RET-T: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' in 'return_adjustment::T' (3 entries). // RET-T-NEXT: 0 | return_adjustment::Y *return_adjustment::T::foo() // RET-T-NEXT: [return adjustment: vbase #1, 0 non-virtual] // RET-T-NEXT: 1 | return_adjustment::Y *return_adjustment::T::foo() // RET-T-NEXT: [return adjustment: vbase #2, 0 non-virtual] // RET-T-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo() // RET-T: VFTable indices for 'return_adjustment::T' (1 entries). // RET-T-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo() virtual Y* foo(); }; T t; struct U : virtual A { virtual void g(); // adds a vfptr }; struct V : Z { // RET-V: VFTable for 'return_adjustment::Z' in 'return_adjustment::V' (2 entries). // RET-V-NEXT: 0 | return_adjustment::U *return_adjustment::V::foo() // RET-V-NEXT: [return adjustment: vbptr at offset 4, vbase #1, 0 non-virtual] // RET-V-NEXT: 1 | return_adjustment::U *return_adjustment::V::foo() // RET-V: VFTable indices for 'return_adjustment::V' (1 entries). // RET-V-NEXT: 1 | return_adjustment::U *return_adjustment::V::foo() virtual U* foo(); }; V v; } namespace pr17748 { struct A { virtual void f() {} }; struct B : virtual A { B() {} }; struct C : virtual B, A { C() {} }; C c; // MANGLING-DAG: @@"\01??_7A@@pr17748@@@@6B@@" // MANGLING-DAG: @@"\01??_7B@@pr17748@@@@6B@@" // MANGLING-DAG: @@"\01??_7C@@pr17748@@@@6BA@@1@@@@" // MANGLING-DAG: @@"\01??_7C@@pr17748@@@@6BB@@1@@@@" } @