1// RUN: %clang_cc1 %s -fno-rtti -triple=i386-pc-win32 -emit-llvm -o %t.ll -fdump-vtable-layouts >%t
2// RUN: FileCheck %s < %t
3// RUN: FileCheck --check-prefix=MANGLING %s < %t.ll
4
5namespace test1 {
6struct A {
7  virtual void f();
8};
9
10struct B {
11  virtual void g();
12  // Add an extra virtual method so it's easier to check for the absence of thunks.
13  virtual void h();
14};
15
16struct X : A, B {
17  // CHECK-LABEL: VFTable for 'test1::A' in 'test1::X' (1 entry)
18  // CHECK-NEXT:   0 | void test1::X::f()
19
20  // CHECK-LABEL: VFTable for 'test1::B' in 'test1::X' (2 entries)
21  // CHECK-NEXT:   0 | void test1::B::g()
22  // CHECK-NEXT:   1 | void test1::B::h()
23
24  // CHECK-LABEL: VFTable indices for 'test1::X' (1 entry)
25  // CHECK-NEXT:   0 | void test1::X::f()
26
27  // MANGLING-DAG: @"\01??_7X@test1@@6BA@1@@"
28  // MANGLING-DAG: @"\01??_7X@test1@@6BB@1@@"
29
30  // Overrides only the left child's method (A::f), needs no thunks.
31  virtual void f();
32} x;
33
34void build_vftable(X *obj) { obj->f(); }
35}
36
37namespace test2 {
38struct A {
39  virtual void f();
40};
41
42struct B {
43  virtual void g();
44  virtual void h();
45};
46
47struct X : A, B {
48  // CHECK-LABEL: VFTable for 'test2::A' in 'test2::X' (1 entry)
49  // CHECK-NEXT:   0 | void test2::A::f()
50
51  // CHECK-LABEL: VFTable for 'test2::B' in 'test2::X' (2 entries)
52  // CHECK-NEXT:   0 | void test2::X::g()
53  // CHECK-NEXT:   1 | void test2::B::h()
54
55  // CHECK-LABEL: VFTable indices for 'test2::X' (1 entry).
56  // CHECK-NEXT:   via vfptr at offset 4
57  // CHECK-NEXT:   0 | void test2::X::g()
58
59  // Overrides only the right child's method (B::g), needs this adjustment but
60  // not thunks.
61  virtual void g();
62};
63
64void build_vftable(X *obj) { obj->g(); }
65}
66
67namespace test3 {
68struct A {
69  virtual void f();
70};
71
72struct B {
73  virtual void g();
74  virtual void h();
75};
76
77struct X : A, B {
78  // CHECK-LABEL: VFTable for 'test3::A' in 'test3::X' (2 entries)
79  // CHECK-NEXT:   0 | void test3::A::f()
80  // CHECK-NEXT:   1 | void test3::X::i()
81
82  // CHECK-LABEL: VFTable for 'test3::B' in 'test3::X' (2 entries)
83  // CHECK-NEXT:   0 | void test3::B::g()
84  // CHECK-NEXT:   1 | void test3::B::h()
85
86  // CHECK-LABEL: VFTable indices for 'test3::X' (1 entry).
87  // CHECK-NEXT:   1 | void test3::X::i()
88
89  // Only adds a new method.
90  virtual void i();
91};
92
93void build_vftable(X *obj) { obj->i(); }
94}
95
96namespace test4 {
97struct A {
98  virtual void f();
99};
100
101struct Empty { };  // Doesn't have a vftable!
102
103// Only the right base has a vftable, so it's laid out before the left one!
104struct X : Empty, A {
105  // CHECK-LABEL: VFTable for 'test4::A' in 'test4::X' (1 entry)
106  // CHECK-NEXT:   0 | void test4::X::f()
107
108  // CHECK-LABEL: VFTable indices for 'test4::X' (1 entry).
109  // CHECK-NEXT:   0 | void test4::X::f()
110
111  // MANGLING-DAG: @"\01??_7X@test4@@6B@"
112
113  virtual void f();
114} x;
115
116void build_vftable(X *obj) { obj->f(); }
117}
118
119namespace test5 {
120struct A {
121  virtual void f();
122};
123
124struct B {
125  virtual void g();
126  virtual void h();
127};
128
129struct C : A, B {
130  virtual void f();
131};
132
133struct X : C {
134  // CHECK-LABEL: VFTable for 'test5::A' in 'test5::C' in 'test5::X' (1 entry).
135  // CHECK-NEXT:   0 | void test5::X::f()
136
137  // CHECK-LABEL: VFTable for 'test5::B' in 'test5::C' in 'test5::X' (2 entries).
138  // CHECK-NEXT:   0 | void test5::B::g()
139  // CHECK-NEXT:   1 | void test5::B::h()
140
141  // CHECK-LABEL: VFTable indices for 'test5::X' (1 entry).
142  // CHECK-NEXT:   0 | void test5::X::f()
143
144  // MANGLING-DAG: @"\01??_7X@test5@@6BA@1@@"
145  // MANGLING-DAG: @"\01??_7X@test5@@6BB@1@@"
146
147  // Overrides both C::f and A::f.
148  virtual void f();
149} x;
150
151void build_vftable(X *obj) { obj->f(); }
152}
153
154namespace test6 {
155struct A {
156  virtual void f();
157};
158
159struct B {
160  virtual void g();
161  virtual void h();
162};
163
164struct C : A, B {
165  virtual void g();
166};
167
168struct X : C {
169  // CHECK-LABEL: VFTable for 'test6::A' in 'test6::C' in 'test6::X' (1 entry).
170  // CHECK-NEXT:   0 | void test6::A::f()
171
172  // CHECK-LABEL: VFTable for 'test6::B' in 'test6::C' in 'test6::X' (2 entries).
173  // CHECK-NEXT:   0 | void test6::X::g()
174  // CHECK-NEXT:   1 | void test6::B::h()
175
176  // CHECK-LABEL: VFTable indices for 'test6::X' (1 entry).
177  // CHECK-NEXT:   via vfptr at offset 4
178  // CHECK-NEXT:   0 | void test6::X::g()
179
180  // Overrides both C::g and B::g.
181  virtual void g();
182};
183
184void build_vftable(X *obj) { obj->g(); }
185}
186
187namespace test7 {
188struct A {
189  virtual void f();
190};
191
192struct B {
193  virtual void g();
194  virtual void h();
195};
196
197struct C : A, B {
198  // Only adds a new method.
199  virtual void i();
200};
201
202struct X : C {
203  // CHECK-LABEL: VFTable for 'test7::A' in 'test7::C' in 'test7::X' (2 entries).
204  // CHECK-NEXT:   0 | void test7::A::f()
205  // CHECK-NEXT:   1 | void test7::C::i()
206
207  // CHECK-LABEL: VFTable for 'test7::B' in 'test7::C' in 'test7::X' (2 entries).
208  // CHECK-NEXT:   0 | void test7::X::g()
209  // CHECK-NEXT:   1 | void test7::B::h()
210
211  // CHECK-LABEL: VFTable indices for 'test7::X' (1 entry).
212  // CHECK-NEXT:   via vfptr at offset 4
213  // CHECK-NEXT:   0 | void test7::X::g()
214
215  // Overrides grandparent's B::g.
216  virtual void g();
217};
218
219void build_vftable(X *obj) { obj->g(); }
220}
221
222namespace test8 {
223struct A {
224  virtual void f();
225};
226
227struct B : A {
228  virtual void g();
229};
230
231// There are two 'A' subobjects in this class.
232struct X : A, B {
233  // CHECK-LABEL: VFTable for 'test8::A' in 'test8::X' (2 entries).
234  // CHECK-NEXT:   0 | void test8::A::f()
235  // CHECK-NEXT:   1 | void test8::X::h()
236
237  // CHECK-LABEL: VFTable for 'test8::A' in 'test8::B' in 'test8::X' (2 entries).
238  // CHECK-NEXT:   0 | void test8::A::f()
239  // CHECK-NEXT:   1 | void test8::B::g()
240
241  // CHECK-LABEL: VFTable indices for 'test8::X' (1 entry).
242  // CHECK-NEXT:   1 | void test8::X::h()
243
244  // MANGLING-DAG: @"\01??_7X@test8@@6BA@1@@"
245  // MANGLING-DAG: @"\01??_7X@test8@@6BB@1@@"
246
247  virtual void h();
248} x;
249
250void build_vftable(X *obj) { obj->h(); }
251}
252
253namespace test9 {
254struct A {
255  virtual void f();
256};
257
258struct B {
259  virtual void g();
260  virtual void h();
261};
262
263struct C : A, B {
264  // Overrides only the left child's method (A::f).
265  virtual void f();
266};
267
268struct D : A, B {
269  // Overrides only the right child's method (B::g).
270  virtual void g();
271};
272
273// 2-level structure with repeating subobject types, but no thunks needed.
274struct X : C, D {
275  // CHECK-LABEL: VFTable for 'test9::A' in 'test9::C' in 'test9::X' (2 entries)
276  // CHECK-NEXT:   0 | void test9::C::f()
277  // CHECK-NEXT:   1 | void test9::X::z()
278
279  // CHECK-LABEL: VFTable for 'test9::B' in 'test9::C' in 'test9::X' (2 entries)
280  // CHECK-NEXT:   0 | void test9::B::g()
281  // CHECK-NEXT:   1 | void test9::B::h()
282
283  // CHECK-LABEL: VFTable for 'test9::A' in 'test9::D' in 'test9::X' (1 entry)
284  // CHECK-NEXT:   0 | void test9::A::f()
285
286  // CHECK-LABEL: VFTable for 'test9::B' in 'test9::D' in 'test9::X' (2 entries)
287  // CHECK-NEXT:   0 | void test9::D::g()
288  // CHECK-NEXT:   1 | void test9::B::h()
289
290  // CHECK-LABEL: VFTable indices for 'test9::X' (1 entry).
291  // CHECK-NEXT:   1 | void test9::X::z()
292
293  // MANGLING-DAG: @"\01??_7X@test9@@6BA@1@C@1@@"
294  // MANGLING-DAG: @"\01??_7X@test9@@6BA@1@D@1@@"
295  // MANGLING-DAG: @"\01??_7X@test9@@6BB@1@C@1@@"
296  // MANGLING-DAG: @"\01??_7X@test9@@6BB@1@D@1@@"
297
298  virtual void z();
299} x;
300
301void build_vftable(test9::X *obj) { obj->z(); }
302}
303