blob: cf9e4c012c5537999bcaa780a641e2cd535e9ec1 [file] [log] [blame]
Timur Iskhodzhanov635de282013-07-30 09:46:19 +00001// RUN: %clang_cc1 -fno-rtti -emit-llvm -fdump-vtable-layouts %s -o - -cxx-abi microsoft -triple=i386-pc-win32 >%t 2>&1
2
3// RUN: FileCheck --check-prefix=VTABLE-C %s < %t
4// RUN: FileCheck --check-prefix=VTABLE-D %s < %t
5// RUN: FileCheck --check-prefix=TEST1 %s < %t
6// RUN: FileCheck --check-prefix=TEST2 %s < %t
7// RUN: FileCheck --check-prefix=TEST3 %s < %t
8// RUN: FileCheck --check-prefix=TEST4 %s < %t
9// RUN: FileCheck --check-prefix=TEST5 %s < %t
10// RUN: FileCheck --check-prefix=TEST6 %s < %t
11// RUN: FileCheck --check-prefix=TEST7 %s < %t
12// RUN: FileCheck --check-prefix=TEST8 %s < %t
13// RUN: FileCheck --check-prefix=TEST9-Y %s < %t
14// RUN: FileCheck --check-prefix=TEST9-Z %s < %t
15// RUN: FileCheck --check-prefix=TEST9-W %s < %t
16// RUN: FileCheck --check-prefix=TEST9-T %s < %t
17// RUN: FileCheck --check-prefix=TEST10 %s < %t
18// RUN: FileCheck --check-prefix=RET-W %s < %t
19// RUN: FileCheck --check-prefix=RET-T %s < %t
20
21struct Empty { };
22
23struct A {
24 virtual void f();
25 virtual void z(); // Useful to check there are no thunks for f() when appropriate.
26};
27
28struct B {
29 virtual void g();
30};
31
32struct C: virtual A {
33 // VTABLE-C: VFTable for 'A' in 'C' (2 entries)
34 // VTABLE-C-NEXT: 0 | void C::f()
35 // VTABLE-C-NEXT: 1 | void A::z()
36
37 // VTABLE-C: VFTable indices for 'C' (1 entries)
38 // VTABLE-C-NEXT: vbtable index 1, vfptr at offset 0
39 // VTABLE-C-NEXT: 0 | void C::f()
40
41 ~C(); // Currently required to have correct record layout, see PR16406
42 virtual void f();
43};
44
45C c;
46
47struct D: virtual A {
48 // VTABLE-D: VFTable for 'D' (1 entries).
49 // VTABLE-D-NEXT: 0 | void D::h()
50
51 // VTABLE-D: VFTable for 'A' in 'D' (2 entries).
52 // VTABLE-D-NEXT: 0 | void D::f()
53 // VTABLE-D-NEXT: 1 | void A::z()
54
55 // VTABLE-D: VFTable indices for 'D' (2 entries).
56 // VTABLE-D-NEXT: via vfptr at offset 0
57 // VTABLE-D-NEXT: 0 | void D::h()
58 // VTABLE-D-NEXT: via vbtable index 1, vfptr at offset 0
59 // VTABLE-D-NEXT: 0 | void D::f()
60
61 virtual void f();
62 virtual void h();
63};
64
65void D::h() {}
66D d;
67
68namespace Test1 {
69
70struct X { int x; };
71
72// X and A get reordered in the layout since X doesn't have a vfptr while A has.
73struct Y : X, A { };
74
75struct Z : virtual Y {
76 // TEST1: VFTable for 'A' in 'Test1::Y' in 'Test1::Z' (2 entries).
77 // TEST1-NEXT: 0 | void A::f()
78 // TEST1-NEXT: 1 | void A::z()
79
80 // TEST1-NOT: VFTable indices for 'Test1::Z'
81};
82
83Z z;
84}
85
86namespace Test2 {
87
88struct X: virtual A, virtual B {
89 // TEST2: VFTable for 'Test2::X' (1 entries).
90 // TEST2-NEXT: 0 | void Test2::X::h()
91
92 // TEST2: VFTable for 'A' in 'Test2::X' (2 entries).
93 // TEST2-NEXT: 0 | void A::f()
94 // TEST2-NEXT: 1 | void A::z()
95
96 // TEST2: VFTable for 'B' in 'Test2::X' (1 entries).
97 // TEST2-NEXT: 0 | void B::g()
98
99 // TEST2: VFTable indices for 'Test2::X' (1 entries).
100 // TEST2-NEXT: 0 | void Test2::X::h()
101
102 virtual void h();
103};
104
105X x;
106}
107
108namespace Test3 {
109
110struct X : virtual A { };
111
112struct Y: virtual X {
113 // TEST3: VFTable for 'A' in 'Test3::X' in 'Test3::Y' (2 entries).
114 // TEST3-NEXT: 0 | void A::f()
115 // TEST3-NEXT: 1 | void A::z()
116
117 // TEST3-NOT: VFTable indices for 'Test3::Y'
118};
119
120Y y;
121}
122
123namespace Test4 {
124
125struct X: virtual C {
126 // This one's interesting. C::f expects (A*) to be passed as 'this' and does
127 // ECX-=4 to cast to (C*). In X, C and A vbases are reordered, so the thunk
128 // should pass a pointer to the end of X in order
129 // for ECX-=4 to point at the C part.
130
131 // TEST4: VFTable for 'A' in 'C' in 'Test4::X' (2 entries).
132 // TEST4-NEXT: 0 | void C::f()
133 // TEST4-NEXT: [this adjustment: 12 non-virtual]
134 // TEST4-NEXT: 1 | void A::z()
135
136 // TEST4-NOT: VFTable indices for 'Test4::X'
137};
138
139X x;
140}
141
142namespace Test5 {
143
144// New methods are added to the base's vftable.
145struct X : A {
146 virtual void g();
147};
148
149struct Y : virtual X {
150 // TEST5: VFTable for 'Test5::Y' (1 entries).
151 // TEST5-NEXT: 0 | void Test5::Y::h()
152
153 // TEST5: VFTable for 'A' in 'Test5::X' in 'Test5::Y' (3 entries).
154 // TEST5-NEXT: 0 | void A::f()
155 // TEST5-NEXT: 1 | void A::z()
156 // TEST5-NEXT: 2 | void Test5::X::g()
157
158 // TEST5: VFTable indices for 'Test5::Y' (1 entries).
159 // TEST5-NEXT: 0 | void Test5::Y::h()
160
161 virtual void h();
162};
163
164Y y;
165}
166
167namespace Test6 {
168
169struct X : A, virtual Empty {
170 // TEST6: VFTable for 'A' in 'Test6::X' (2 entries).
171 // TEST6-NEXT: 0 | void A::f()
172 // TEST6-NEXT: 1 | void A::z()
173
174 // TEST6-NOT: VFTable indices for 'Test6::X'
175};
176
177X x;
178}
179
180namespace Test7 {
181
182struct X : C { };
183
184struct Y : virtual X {
185 // TEST7: VFTable for 'A' in 'C' in 'Test7::X' in 'Test7::Y' (2 entries).
186 // TEST7-NEXT: 0 | void C::f()
187 // TEST7-NEXT: [this adjustment: 12 non-virtual]
188 // TEST7-NEXT: 1 | void A::z()
189
190 // TEST7: Thunks for 'void C::f()' (1 entry).
191 // TEST7-NEXT: 0 | this adjustment: 12 non-virtual
192
193 // TEST7-NOT: VFTable indices for 'Test7::Y'
194};
195
196Y y;
197}
198
199namespace Test8 {
200
201// This is a typical diamond inheritance with a shared 'A' vbase.
202struct X : D, C {
203 // TEST8: VFTable for 'D' in 'Test8::X' (1 entries).
204 // TEST8-NEXT: 0 | void D::h()
205
206 // TEST8: VFTable for 'A' in 'D' in 'Test8::X' (2 entries).
207 // TEST8-NEXT: 0 | void Test8::X::f()
208 // TEST8-NEXT: 1 | void A::z()
209
210 // TEST8: VFTable indices for 'Test8::X' (1 entries).
211 // TEST8-NEXT: via vbtable index 1, vfptr at offset 0
212
213 virtual void f();
214};
215
216X x;
217}
218
219namespace Test9 {
220
221struct X : A { };
222
223struct Y : virtual X {
224 // TEST9-Y: VFTable for 'Test9::Y' (1 entries).
225 // TEST9-Y-NEXT: 0 | void Test9::Y::h()
226
227 // TEST9-Y: VFTable for 'A' in 'Test9::X' in 'Test9::Y' (2 entries).
228 // TEST9-Y-NEXT: 0 | void A::f()
229 // TEST9-Y-NEXT: 1 | void A::z()
230
231 // TEST9-Y: VFTable indices for 'Test9::Y' (1 entries).
232 // TEST9-Y-NEXT: 0 | void Test9::Y::h()
233
234 virtual void h();
235};
236
237Y y;
238
239struct Z : Y, virtual B {
240 // TEST9-Z: VFTable for 'Test9::Y' in 'Test9::Z' (1 entries).
241 // TEST9-Z-NEXT: 0 | void Test9::Y::h()
242
243 // TEST9-Z: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' (2 entries).
244 // TEST9-Z-NEXT: 0 | void A::f()
245 // TEST9-Z-NEXT: 1 | void A::z()
246
247 // TEST9-Z: VFTable for 'B' in 'Test9::Z' (1 entries).
248 // TEST9-Z-NEXT: 0 | void B::g()
249
250 // TEST9-Z-NOT: VFTable indices for 'Test9::Z'
251};
252
253Z z;
254
255struct W : Z, D, virtual A, virtual B {
256 // TEST9-W: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::W' (1 entries).
257 // TEST9-W-NEXT: 0 | void Test9::Y::h()
258
259 // TEST9-W: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::W' (2 entries).
260 // TEST9-W-NEXT: 0 | void A::f()
261 // TEST9-W-NEXT: 1 | void A::z()
262
263 // TEST9-W: VFTable for 'B' in 'Test9::Z' in 'Test9::W' (1 entries).
264 // TEST9-W-NEXT: 0 | void B::g()
265
266 // TEST9-W: VFTable for 'D' in 'Test9::W' (1 entries).
267 // TEST9-W-NEXT: 0 | void D::h()
268
269 // TEST9-W: VFTable for 'A' in 'D' in 'Test9::W' (2 entries).
270 // TEST9-W-NEXT: 0 | void D::f()
271 // TEST9-W-NEXT: [this adjustment: -8 non-virtual]
272 // TEST9-W-NEXT: 1 | void A::z()
273
274 // TEST9-W: Thunks for 'void D::f()' (1 entry).
275 // TEST9-W-NEXT: 0 | this adjustment: -8 non-virtual
276
277 // TEST9-W-NOT: VFTable indices for 'Test9::W'
278};
279
280W w;
281
282struct T : Z, D, virtual A, virtual B {
283 ~T(); // Currently required to have correct record layout, see PR16406
284
285 // TEST9-T: VFTable for 'Test9::Y' in 'Test9::Z' in 'Test9::T' (1 entries).
286 // TEST9-T-NEXT: 0 | void Test9::T::h()
287
288 // TEST9-T: VFTable for 'A' in 'Test9::X' in 'Test9::Y' in 'Test9::Z' in 'Test9::T' (2 entries).
289 // TEST9-T-NEXT: 0 | void Test9::T::f()
290 // TEST9-T-NEXT: 1 | void Test9::T::z()
291
292 // TEST9-T: VFTable for 'B' in 'Test9::Z' in 'Test9::T' (1 entries).
293 // TEST9-T-NEXT: 0 | void Test9::T::g()
294
295 // TEST9-T: VFTable for 'D' in 'Test9::T' (1 entries).
296 // TEST9-T-NEXT: 0 | void Test9::T::h()
297 // TEST9-T-NEXT: [this adjustment: -8 non-virtual]
298
299 // TEST9-T: Thunks for 'void Test9::T::h()' (1 entry).
300 // TEST9-T-NEXT: 0 | this adjustment: -8 non-virtual
301
302 // TEST9-T: VFTable for 'A' in 'D' in 'Test9::T' (2 entries).
303 // TEST9-T-NEXT: 0 | void Test9::T::f()
304 // TEST9-T-NEXT: [this adjustment: -16 non-virtual]
305 // TEST9-T-NEXT: 1 | void Test9::T::z()
306 // TEST9-T-NEXT: [this adjustment: -16 non-virtual]
307
308 // TEST9-T: Thunks for 'void Test9::T::f()' (1 entry).
309 // TEST9-T-NEXT: 0 | this adjustment: -16 non-virtual
310
311 // TEST9-T: Thunks for 'void Test9::T::z()' (1 entry).
312 // TEST9-T-NEXT: 0 | this adjustment: -16 non-virtual
313
314 // TEST9-T: VFTable indices for 'Test9::T' (4 entries).
315 // TEST9-T-NEXT: via vfptr at offset 0
316 // TEST9-T-NEXT: 0 | void Test9::T::h()
317 // TEST9-T-NEXT: via vbtable index 1, vfptr at offset 0
318 // TEST9-T-NEXT: 0 | void Test9::T::f()
319 // TEST9-T-NEXT: 1 | void Test9::T::z()
320 // TEST9-T-NEXT: via vbtable index 2, vfptr at offset 0
321 // TEST9-T-NEXT: 0 | void Test9::T::g()
322
323 virtual void f();
324 virtual void g();
325 virtual void h();
326 virtual void z();
327};
328
329T t;
330}
331
332namespace Test10 {
333struct X : virtual C, virtual A {
334 // TEST10: VFTable for 'A' in 'C' in 'Test10::X' (2 entries).
335 // TEST10-NEXT: 0 | void Test10::X::f()
336 // TEST10-NEXT: 1 | void A::z()
337
338 // TEST10: VFTable indices for 'Test10::X' (1 entries).
339 // TEST10-NEXT: via vbtable index 1, vfptr at offset 0
340 // TEST10-NEXT: 0 | void Test10::X::f()
341 virtual void f();
342};
343
344void X::f() {}
345X x;
346}
347
348namespace return_adjustment {
349
350struct X : virtual A {
351 virtual void f();
352};
353
354struct Y : virtual A, virtual X {
355 virtual void f();
356};
357
358struct Z {
359 virtual A* foo();
360};
361
362struct W : Z {
363 // RET-W: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' (2 entries).
364 // RET-W-NEXT: 0 | return_adjustment::X *return_adjustment::W::foo()
365 // RET-W-NEXT: [return adjustment: vbase #1, 0 non-virtual]
366 // RET-W-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo()
367
368 // RET-W: VFTable indices for 'return_adjustment::W' (1 entries).
369 // RET-W-NEXT: 1 | return_adjustment::X *return_adjustment::W::foo()
370
371 virtual X* foo();
372};
373
374W y;
375
376struct T : W {
377 // RET-T: VFTable for 'return_adjustment::Z' in 'return_adjustment::W' in 'return_adjustment::T' (3 entries).
378 // RET-T-NEXT: 0 | return_adjustment::Y *return_adjustment::T::foo()
379 // RET-T-NEXT: [return adjustment: vbase #1, 0 non-virtual]
380 // RET-T-NEXT: 1 | return_adjustment::Y *return_adjustment::T::foo()
381 // RET-T-NEXT: [return adjustment: vbase #2, 0 non-virtual]
382 // RET-T-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo()
383
384 // RET-T: VFTable indices for 'return_adjustment::T' (1 entries).
385 // RET-T-NEXT: 2 | return_adjustment::Y *return_adjustment::T::foo()
386
387 virtual Y* foo();
388};
389
390T t;
391}