aboutsummaryrefslogtreecommitdiff
path: root/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp')
-rw-r--r--test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp667
1 files changed, 429 insertions, 238 deletions
diff --git a/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp
index b58a0b14cdcd..4ce4e9c2e17e 100644
--- a/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp
+++ b/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp
@@ -1,29 +1,5 @@
-// 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: %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 { };
@@ -38,34 +14,35 @@ struct B {
};
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()
+ // CHECK-LABEL: VFTable for 'A' in 'C' (2 entries)
+ // CHECK-NEXT: 0 | void C::f()
+ // CHECK-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()
+ // 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();
+ virtual void f() {}
};
C c;
+void use(C *obj) { obj->f(); }
struct D: virtual A {
- // VTABLE-D: VFTable for 'D' (1 entries).
- // VTABLE-D-NEXT: 0 | void D::h()
+ // CHECK-LABEL: VFTable for 'D' (1 entry).
+ // CHECK-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()
+ // CHECK-LABEL: VFTable for 'A' in 'D' (2 entries).
+ // CHECK-NEXT: 0 | void D::f()
+ // CHECK-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()
+ // 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@@@"
@@ -74,8 +51,8 @@ struct D: virtual A {
virtual void h();
};
-void D::h() {}
D d;
+void use(D *obj) { obj->h(); }
namespace Test1 {
@@ -86,33 +63,34 @@ 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()
+ 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()
- // TEST1-NOT: VFTable indices for 'Test1::Z'
+ // CHECK-NOT: VFTable indices for 'Test1::Z'
// MANGLING-DAG: @"\01??_7Z@Test1@@6B@"
};
-Z z;
+Z::Z() {}
}
namespace Test2 {
struct X: virtual A, virtual B {
- // TEST2: VFTable for 'Test2::X' (1 entries).
- // TEST2-NEXT: 0 | void Test2::X::h()
+ // CHECK-LABEL: VFTable for 'Test2::X' (1 entry).
+ // CHECK-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()
+ // CHECK-LABEL: VFTable for 'A' in 'Test2::X' (2 entries).
+ // CHECK-NEXT: 0 | void A::f()
+ // CHECK-NEXT: 1 | void A::z()
- // TEST2: VFTable for 'B' in 'Test2::X' (1 entries).
- // TEST2-NEXT: 0 | void B::g()
+ // CHECK-LABEL: VFTable for 'B' in 'Test2::X' (1 entry).
+ // CHECK-NEXT: 0 | void B::g()
- // TEST2: VFTable indices for 'Test2::X' (1 entries).
- // TEST2-NEXT: 0 | void Test2::X::h()
+ // 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@@@"
@@ -122,6 +100,7 @@ struct X: virtual A, virtual B {
};
X x;
+void use(X *obj) { obj->h(); }
}
namespace Test3 {
@@ -131,40 +110,45 @@ struct X : virtual A {
};
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()
+ 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()
- // TEST3-NOT: VFTable indices for 'Test3::Y'
+ // CHECK-NOT: VFTable indices for 'Test3::Y'
// MANGLING-DAG: @"\01??_7Y@Test3@@6B@"
};
-Y y;
+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.
- // 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()
+ // 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]
- // TEST4-NOT: VFTable indices for 'Test4::X'
+ // CHECK-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"
+ // MANGLING-DAG: define linkonce_odr x86_thiscallcc void @"\01?f@C@@WPPPPPPPI@AEXXZ"
};
-X x;
+X::X() {}
}
namespace Test5 {
@@ -176,16 +160,16 @@ struct X : A {
};
struct Y : virtual X {
- // TEST5: VFTable for 'Test5::Y' (1 entries).
- // TEST5-NEXT: 0 | void Test5::Y::h()
+ // CHECK-LABEL: VFTable for 'Test5::Y' (1 entry).
+ // CHECK-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()
+ // 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()
- // TEST5: VFTable indices for 'Test5::Y' (1 entries).
- // TEST5-NEXT: 0 | void Test5::Y::h()
+ // 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@@"
@@ -194,21 +178,23 @@ struct Y : virtual X {
};
Y y;
+void use(Y *obj) { obj->h(); }
}
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()
+ X();
+ // CHECK-LABEL: VFTable for 'A' in 'Test6::X' (2 entries).
+ // CHECK-NEXT: 0 | void A::f()
+ // CHECK-NEXT: 1 | void A::z()
- // TEST6-NOT: VFTable indices for 'Test6::X'
+ // CHECK-NOT: VFTable indices for 'Test6::X'
// MANGLING-DAG: @"\01??_7X@Test6@@6B@"
};
-X x;
+X::X() {}
}
namespace Test7 {
@@ -218,36 +204,37 @@ struct X : C {
};
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()
+ 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()
- // TEST7: Thunks for 'void C::f()' (1 entry).
- // TEST7-NEXT: 0 | [this adjustment: 8 non-virtual]
+ // CHECK-LABEL: Thunks for 'void C::f()' (1 entry).
+ // CHECK-NEXT: 0 | [this adjustment: 8 non-virtual]
- // TEST7-NOT: VFTable indices for 'Test7::Y'
+ // CHECK-NOT: VFTable indices for 'Test7::Y'
// MANGLING-DAG: @"\01??_7Y@Test7@@6B@"
};
-Y y;
+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()
+ // CHECK-LABEL: VFTable for 'D' in 'Test8::X' (1 entry).
+ // CHECK-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()
+ // 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()
- // 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()
+ // 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@@@"
@@ -256,21 +243,45 @@ struct X : D, C {
};
X x;
+void use(X *obj) { obj->f(); }
// 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()
+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()
- // 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()
+ // 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 {
@@ -278,15 +289,15 @@ 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()
+ // CHECK-LABEL: VFTable for 'Test9::Y' (1 entry).
+ // CHECK-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()
+ // 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()
- // TEST9-Y: VFTable indices for 'Test9::Y' (1 entries).
- // TEST9-Y-NEXT: 0 | void Test9::Y::h()
+ // 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@@"
@@ -295,115 +306,110 @@ struct Y : virtual X {
};
Y y;
+void use(Y *obj) { obj->h(); }
struct Z : Y, virtual B {
- // TEST9-Z: VFTable for 'Test9::Y' in 'Test9::Z' (1 entries).
- // TEST9-Z-NEXT: 0 | void Test9::Y::h()
+ Z();
+ // CHECK-LABEL: VFTable for 'Test9::Y' in 'Test9::Z' (1 entry).
+ // CHECK-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()
+ // 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()
- // TEST9-Z: VFTable for 'B' in 'Test9::Z' (1 entries).
- // TEST9-Z-NEXT: 0 | void B::g()
+ // CHECK-LABEL: VFTable for 'B' in 'Test9::Z' (1 entry).
+ // CHECK-NEXT: 0 | void B::g()
- // TEST9-Z-NOT: VFTable indices for 'Test9::Z'
+ // CHECK-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@"
+ // MANGLING-DAG: @"\01??_7Z@Test9@@6B@"
};
-Z z;
+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()
+ W();
+ // CHECK-LABEL: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::W' (1 entry).
+ // CHECK-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()
+ // 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()
- // TEST9-W: VFTable for 'B' in 'Test9::Z' in 'Test9::W' (1 entries).
- // TEST9-W-NEXT: 0 | void B::g()
+ // CHECK-LABEL: VFTable for 'B' in 'Test9::Z' in 'Test9::W' (1 entry).
+ // CHECK-NEXT: 0 | void B::g()
- // TEST9-W: VFTable for 'D' in 'Test9::W' (1 entries).
- // TEST9-W-NEXT: 0 | void D::h()
+ // CHECK-LABEL: VFTable for 'D' in 'Test9::W' (1 entry).
+ // CHECK-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()
+ // 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()
- // TEST9-W: Thunks for 'void D::f()' (1 entry).
- // TEST9-W-NEXT: 0 | [this adjustment: -8 non-virtual]
+ // CHECK-LABEL: Thunks for 'void D::f()' (1 entry).
+ // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual]
- // TEST9-W-NOT: VFTable indices for 'Test9::W'
+ // 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@@"
- // 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@@"
+ // MANGLING-DAG: @"\01??_7W@Test9@@6B@"
+ // MANGLING-DAG: @"\01??_7W@Test9@@6BY@1@@"
};
-W w;
+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()
+ // CHECK-LABEL: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::T' (1 entry).
+ // CHECK-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()
+ // 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()
- // TEST9-T: VFTable for 'B' in 'Test9::Z' in 'Test9::T' (1 entries).
- // TEST9-T-NEXT: 0 | void Test9::T::g()
+ // CHECK-LABEL: VFTable for 'B' in 'Test9::Z' in 'Test9::T' (1 entry).
+ // CHECK-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]
+ // CHECK-LABEL: VFTable for 'D' in 'Test9::T' (1 entry).
+ // CHECK-NEXT: 0 | void Test9::T::h()
+ // CHECK-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]
+ // CHECK-LABEL: Thunks for 'void Test9::T::h()' (1 entry).
+ // CHECK-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]
+ // 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]
- // TEST9-T: Thunks for 'void Test9::T::f()' (1 entry).
- // TEST9-T-NEXT: 0 | [this adjustment: -8 non-virtual]
+ // CHECK-LABEL: Thunks for 'void Test9::T::f()' (1 entry).
+ // CHECK-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]
+ // CHECK-LABEL: Thunks for 'void Test9::T::z()' (1 entry).
+ // CHECK-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()
+ // 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@@"
- // 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@@"
+ // MANGLING-DAG: @"\01??_7T@Test9@@6B@"
+ // MANGLING-DAG: @"\01??_7T@Test9@@6BY@1@@"
virtual void f();
virtual void g();
@@ -412,22 +418,70 @@ struct T : Z, D, virtual A, virtual B {
};
T t;
+void use(T *obj) { obj->f(); }
}
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()
+ // 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()
- // 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()
+ // 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 {
@@ -437,15 +491,16 @@ struct X {
};
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()
+ // 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()
- // VDTORS-Y-NOT: Thunks for 'vdtors::Y::~Y()'
+ // CHECK-NOT: Thunks for 'vdtors::Y::~Y()'
virtual ~Y();
};
Y y;
+void use(Y *obj) { delete obj; }
struct Z {
virtual void z();
@@ -456,59 +511,86 @@ struct W : Z, X {
};
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()
+ // CHECK-LABEL: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::U' (1 entry).
+ // CHECK-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()
+ // 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()
- // VDTORS-U: Thunks for 'vdtors::W::~W()' (1 entry).
- // VDTORS-U-NEXT: 0 | [this adjustment: -4 non-virtual]
+ // CHECK-LABEL: Thunks for 'vdtors::U::~U()' (1 entry).
+ // CHECK-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]
+ // 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 {
- // VDTORS-V: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::V' (1 entries).
- // VDTORS-V-NEXT: 0 | void vdtors::Z::z()
+ // CHECK-LABEL: VFTable for 'vdtors::Z' in 'vdtors::W' in 'vdtors::V' (1 entry).
+ // CHECK-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()
+ // 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()
- // VDTORS-V: Thunks for 'vdtors::W::~W()' (1 entry).
- // VDTORS-V-NEXT: 0 | [this adjustment: -4 non-virtual]
+ // CHECK-LABEL: Thunks for 'vdtors::V::~V()' (1 entry).
+ // CHECK-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]
+ // 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 {
- // 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()
+ // 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()
- // VDTORS-P-NOT: Thunks for 'vdtors::P::~P()'
+ // 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::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();
+};
+
+R r;
+void use(R *obj) { delete obj; }
}
namespace return_adjustment {
@@ -526,50 +608,159 @@ struct Z {
};
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()
+ // 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]
- // RET-W: VFTable indices for 'return_adjustment::W' (1 entries).
- // RET-W-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo()
+ // CHECK-LABEL: VFTable indices for 'return_adjustment::W' (1 entry).
+ // CHECK-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo()
virtual X* foo();
};
-W y;
+W w;
+void use(W *obj) { obj->foo(); }
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()
+ // 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]
- // RET-T: VFTable indices for 'return_adjustment::T' (1 entries).
- // RET-T-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo()
+ // 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 {
- // 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()
+ // 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]
- // RET-V: VFTable indices for 'return_adjustment::V' (1 entries).
- // RET-V-NEXT: 1 | return_adjustment::U *return_adjustment::V::foo()
+ // 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::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() {}
}