Add MicrosoftVFTableContext to AST

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@187409 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp
new file mode 100644
index 0000000..cf9e4c0
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp
@@ -0,0 +1,391 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm -fdump-vtable-layouts %s -o - -cxx-abi microsoft -triple=i386-pc-win32 >%t 2>&1
+
+// 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 %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=RET-W %s < %t
+// RUN: FileCheck --check-prefix=RET-T %s < %t
+
+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()
+
+  ~C();  // Currently required to have correct record layout, see PR16406
+  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()
+
+  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 { };
+
+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'
+};
+
+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()
+
+  virtual void h();
+};
+
+X x;
+}
+
+namespace Test3 {
+
+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()
+
+  // TEST3-NOT: VFTable indices for 'Test3::Y'
+};
+
+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: 12 non-virtual]
+  // TEST4-NEXT: 1 | void A::z()
+
+  // TEST4-NOT: VFTable indices for 'Test4::X'
+};
+
+X x;
+}
+
+namespace Test5 {
+
+// New methods are added to the base's vftable.
+struct X : A {
+  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()
+
+  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'
+};
+
+X x;
+}
+
+namespace Test7 {
+
+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: 12 non-virtual]
+  // TEST7-NEXT: 1 | void A::z()
+
+  // TEST7: Thunks for 'void C::f()' (1 entry).
+  // TEST7-NEXT: 0 | this adjustment: 12 non-virtual
+
+  // TEST7-NOT: VFTable indices for 'Test7::Y'
+};
+
+Y y;
+}
+
+namespace Test8 {
+
+// This is a typical diamond inheritance with a shared 'A' vbase.
+struct X : D, C {
+  // TEST8: VFTable for 'D' in 'Test8::X' (1 entries).
+  // TEST8-NEXT: 0 | void D::h()
+
+  // TEST8: VFTable for 'A' in 'D' in 'Test8::X' (2 entries).
+  // TEST8-NEXT: 0 | void Test8::X::f()
+  // TEST8-NEXT: 1 | void A::z()
+
+  // TEST8: VFTable indices for 'Test8::X' (1 entries).
+  // TEST8-NEXT: via vbtable index 1, vfptr at offset 0
+
+  virtual void f();
+};
+
+X x;
+}
+
+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()
+
+  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'
+};
+
+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'
+};
+
+W w;
+
+struct T : Z, D, virtual A, virtual B {
+  ~T();  // Currently required to have correct record layout, see PR16406
+
+  // 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: -16 non-virtual]
+  // TEST9-T-NEXT: 1 | void Test9::T::z()
+  // TEST9-T-NEXT:     [this adjustment: -16 non-virtual]
+
+  // TEST9-T: Thunks for 'void Test9::T::f()' (1 entry).
+  // TEST9-T-NEXT: 0 | this adjustment: -16 non-virtual
+
+  // TEST9-T: Thunks for 'void Test9::T::z()' (1 entry).
+  // TEST9-T-NEXT: 0 | this adjustment: -16 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()
+
+  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 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;
+}