1// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -fdump-vtable-layouts -o - > %t 2>&1
2// RUN: FileCheck --check-prefix=EMITS-VTABLE %s < %t
3// RUN: FileCheck --check-prefix=NO-VTABLE %s < %t
4// RUN: FileCheck --check-prefix=CHECK-A %s < %t
5// RUN: FileCheck --check-prefix=CHECK-B %s < %t
6// RUN: FileCheck --check-prefix=CHECK-C %s < %t
7// RUN: FileCheck --check-prefix=CHECK-D %s < %t
8// RUN: FileCheck --check-prefix=CHECK-E %s < %t
9// RUN: FileCheck --check-prefix=CHECK-F %s < %t
10// RUN: FileCheck --check-prefix=CHECK-G %s < %t
11// RUN: FileCheck --check-prefix=CHECK-I %s < %t
12
13// FIXME: Currently, we only test VFTableContext in the AST, but still use
14// VTableContext for CodeGen. We should remove the "Vtable" checks below when we
15// completely switch from VTableContext to VFTableContext.
16// Currently, the order of Vtable vs VFTable output depends on whether the
17// v*table info was required by a constructor or a method definition.
18
19struct A {
20  // CHECK-A: Vtable for 'A' (3 entries)
21  // CHECK-A-NEXT: 0 | void A::f()
22  // CHECK-A-NEXT: 1 | void A::g()
23  // CHECK-A-NEXT: 2 | void A::h()
24
25  // CHECK-A: VFTable for 'A' (3 entries)
26  // CHECK-A-NEXT: 0 | void A::f()
27  // CHECK-A-NEXT: 1 | void A::g()
28  // CHECK-A-NEXT: 2 | void A::h()
29
30  virtual void f();
31  virtual void g();
32  virtual void h();
33  int ia;
34};
35A a;
36// EMITS-VTABLE-DAG: @"\01??_7A@@6B@" = linkonce_odr unnamed_addr constant [3 x i8*]
37
38struct B : A {
39  // CHECK-B: Vtable for 'B' (5 entries)
40  // CHECK-B-NEXT: 0 | void B::f()
41  // CHECK-B-NEXT: 1 | void A::g()
42  // CHECK-B-NEXT: 2 | void A::h()
43  // CHECK-B-NEXT: 3 | void B::i()
44  // CHECK-B-NEXT: 4 | void B::j()
45
46  // CHECK-B: VFTable for 'A' in 'B' (5 entries)
47  // CHECK-B-NEXT: 0 | void B::f()
48  // CHECK-B-NEXT: 1 | void A::g()
49  // CHECK-B-NEXT: 2 | void A::h()
50  // CHECK-B-NEXT: 3 | void B::i()
51  // CHECK-B-NEXT: 4 | void B::j()
52
53  virtual void f();  // overrides A::f()
54  virtual void i();
55  virtual void j();
56};
57B b;
58// EMITS-VTABLE-DAG: @"\01??_7B@@6B@" = linkonce_odr unnamed_addr constant [5 x i8*]
59
60struct C {
61  // CHECK-C: VFTable for 'C' (2 entries)
62  // CHECK-C-NEXT: 0 | C::~C() [scalar deleting]
63  // CHECK-C-NEXT: 1 | void C::f()
64  // CHECK-C: VFTable indices for 'C' (2 entries).
65  // CHECK-C-NEXT: 0 | C::~C() [scalar deleting]
66  // CHECK-C-NEXT: 1 | void C::f()
67
68  // CHECK-C: Vtable for 'C' (2 entries)
69  // CHECK-C-NEXT: 0 | C::~C() [scalar deleting]
70  // CHECK-C-NEXT: 1 | void C::f()
71  // CHECK-C: VTable indices for 'C' (2 entries).
72  // CHECK-C-NEXT: 0 | C::~C() [scalar deleting]
73  // CHECK-C-NEXT: 1 | void C::f()
74
75  virtual ~C();
76  virtual void f();
77};
78void C::f() {}
79// NO-VTABLE-NOT: @"\01??_7C@@6B@"
80
81struct D {
82  // CHECK-D: Vtable for 'D' (2 entries)
83  // CHECK-D-NEXT: 0 | void D::f()
84  // CHECK-D-NEXT: 1 | D::~D() [scalar deleting]
85
86  // CHECK-D: VFTable for 'D' (2 entries)
87  // CHECK-D-NEXT: 0 | void D::f()
88  // CHECK-D-NEXT: 1 | D::~D() [scalar deleting]
89
90  virtual void f();
91  virtual ~D();
92};
93D d;
94// EMITS-VTABLE-DAG: @"\01??_7D@@6B@" = linkonce_odr unnamed_addr constant [2 x i8*]
95
96struct E : A {
97  // CHECK-E: VFTable for 'A' in 'E' (5 entries)
98  // CHECK-E-NEXT: 0 | void A::f()
99  // CHECK-E-NEXT: 1 | void A::g()
100  // CHECK-E-NEXT: 2 | void A::h()
101  // CHECK-E-NEXT: 3 | E::~E() [scalar deleting]
102  // CHECK-E-NEXT: 4 | void E::i()
103  // CHECK-E: VFTable indices for 'E' (2 entries).
104  // CHECK-E-NEXT: 3 | E::~E() [scalar deleting]
105  // CHECK-E-NEXT: 4 | void E::i()
106
107  // CHECK-E: Vtable for 'E' (5 entries)
108  // CHECK-E-NEXT: 0 | void A::f()
109  // CHECK-E-NEXT: 1 | void A::g()
110  // CHECK-E-NEXT: 2 | void A::h()
111  // CHECK-E-NEXT: 3 | E::~E() [scalar deleting]
112  // CHECK-E-NEXT: 4 | void E::i()
113  // CHECK-E: VTable indices for 'E' (2 entries).
114  // CHECK-E-NEXT: 3 | E::~E() [scalar deleting]
115  // CHECK-E-NEXT: 4 | void E::i()
116
117  // ~E would be the key method, but it isn't used, and MS ABI has no key
118  // methods.
119  virtual ~E();
120  virtual void i();
121};
122void E::i() {}
123// NO-VTABLE-NOT: @"\01??_7E@@6B@"
124
125struct F : A {
126  // CHECK-F: Vtable for 'F' (5 entries)
127  // CHECK-F-NEXT: 0 | void A::f()
128  // CHECK-F-NEXT: 1 | void A::g()
129  // CHECK-F-NEXT: 2 | void A::h()
130  // CHECK-F-NEXT: 3 | void F::i()
131  // CHECK-F-NEXT: 4 | F::~F() [scalar deleting]
132  // CHECK-F: VTable indices for 'F' (2 entries).
133  // CHECK-F-NEXT: 3 | void F::i()
134  // CHECK-F-NEXT: 4 | F::~F() [scalar deleting]
135
136  // CHECK-F: VFTable for 'A' in 'F' (5 entries)
137  // CHECK-F-NEXT: 0 | void A::f()
138  // CHECK-F-NEXT: 1 | void A::g()
139  // CHECK-F-NEXT: 2 | void A::h()
140  // CHECK-F-NEXT: 3 | void F::i()
141  // CHECK-F-NEXT: 4 | F::~F() [scalar deleting]
142  // CHECK-F: VFTable indices for 'F' (2 entries).
143  // CHECK-F-NEXT: 3 | void F::i()
144  // CHECK-F-NEXT: 4 | F::~F() [scalar deleting]
145
146  virtual void i();
147  virtual ~F();
148};
149F f;
150// EMITS-VTABLE-DAG: @"\01??_7F@@6B@" = linkonce_odr unnamed_addr constant [5 x i8*]
151
152struct G : E {
153  // CHECK-G: VFTable for 'A' in 'E' in 'G' (6 entries)
154  // CHECK-G-NEXT: 0 | void G::f()
155  // CHECK-G-NEXT: 1 | void A::g()
156  // CHECK-G-NEXT: 2 | void A::h()
157  // CHECK-G-NEXT: 3 | G::~G() [scalar deleting]
158  // CHECK-G-NEXT: 4 | void E::i()
159  // CHECK-G-NEXT: 5 | void G::j()
160  // CHECK-G: VFTable indices for 'G' (3 entries).
161  // CHECK-G-NEXT: 0 | void G::f()
162  // CHECK-G-NEXT: 3 | G::~G() [scalar deleting]
163  // CHECK-G-NEXT: 5 | void G::j()
164
165  // CHECK-G: Vtable for 'G' (6 entries)
166  // CHECK-G-NEXT: 0 | void G::f()
167  // CHECK-G-NEXT: 1 | void A::g()
168  // CHECK-G-NEXT: 2 | void A::h()
169  // CHECK-G-NEXT: 3 | G::~G() [scalar deleting]
170  // CHECK-G-NEXT: 4 | void E::i()
171  // CHECK-G-NEXT: 5 | void G::j()
172  // CHECK-G: VTable indices for 'G' (3 entries).
173  // CHECK-G-NEXT: 0 | void G::f()
174  // CHECK-G-NEXT: 3 | G::~G() [scalar deleting]
175  // CHECK-G-NEXT: 5 | void G::j()
176
177  virtual void f();  // overrides A::f()
178  virtual ~G();
179  virtual void j();
180};
181void G::j() {}
182// NO-VTABLE-NOT: @"\01??_7G@@6B@"
183
184// Test that the usual Itanium-style key method does not emit a vtable.
185struct H {
186  virtual void f();
187};
188void H::f() {}
189// NO-VTABLE-NOT: @"\01??_7H@@6B@"
190
191struct Empty { };
192
193struct I : Empty {
194  // CHECK-I: VFTable for 'I' (2 entries)
195  // CHECK-I-NEXT: 0 | void I::f()
196  // CHECK-I-NEXT: 1 | void I::g()
197  virtual void f();
198  virtual void g();
199};
200
201I i;
202