blob: bd0666b7d6b354a45a71d3fb2b113acc7d0e6e13 [file] [log] [blame]
Timur Iskhodzhanov635de282013-07-30 09:46:19 +00001// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -fdump-vtable-layouts -o - >%t 2>&1
2
3// RUN: FileCheck --check-prefix=NO-THUNKS-Test1 %s < %t
4// RUN: FileCheck --check-prefix=NO-THUNKS-Test2 %s < %t
5// RUN: FileCheck --check-prefix=NO-THUNKS-Test3 %s < %t
6// RUN: FileCheck --check-prefix=NO-THUNKS-Test4 %s < %t
7// RUN: FileCheck --check-prefix=NO-THUNKS-Test5 %s < %t
8// RUN: FileCheck --check-prefix=NO-THUNKS-Test6 %s < %t
9// RUN: FileCheck --check-prefix=NO-THUNKS-Test7 %s < %t
10// RUN: FileCheck --check-prefix=NO-THUNKS-Test8 %s < %t
11// RUN: FileCheck --check-prefix=NO-THUNKS-Test9 %s < %t
12// RUN: FileCheck --check-prefix=PURE-VIRTUAL-Test1 %s < %t
13// RUN: FileCheck --check-prefix=THIS-THUNKS-Test1 %s < %t
14// RUN: FileCheck --check-prefix=THIS-THUNKS-Test2 %s < %t
15// RUN: FileCheck --check-prefix=THIS-THUNKS-Test3 %s < %t
16// RUN: FileCheck --check-prefix=RET-THUNKS-Test1 %s < %t
17// RUN: FileCheck --check-prefix=RET-THUNKS-Test2 %s < %t
18// RUN: FileCheck --check-prefix=RET-THUNKS-Test3 %s < %t
19// RUN: FileCheck --check-prefix=RET-THUNKS-Test4 %s < %t
20// RUN: FileCheck --check-prefix=RET-THUNKS-Test5 %s < %t
21
22struct Empty {
23 // Doesn't have a vftable!
24};
25
26struct A {
27 virtual void f();
28};
29
30struct B {
31 virtual void g();
32 // Add an extra virtual method so it's easier to check for the absence of thunks.
33 virtual void h();
34};
35
36struct C {
37 virtual void g(); // Might "collide" with B::g if both are bases of some class.
38};
39
40
41namespace no_thunks {
42
43struct Test1: A, B {
44 // NO-THUNKS-Test1: VFTable for 'A' in 'no_thunks::Test1' (1 entries)
45 // NO-THUNKS-Test1-NEXT: 0 | void no_thunks::Test1::f()
46
47 // NO-THUNKS-Test1: VFTable for 'B' in 'no_thunks::Test1' (2 entries)
48 // NO-THUNKS-Test1-NEXT: 0 | void B::g()
49 // NO-THUNKS-Test1-NEXT: 1 | void B::h()
50
51 // NO-THUNKS-Test1: VFTable indices for 'no_thunks::Test1' (1 entries)
52 // NO-THUNKS-Test1-NEXT: 0 | void no_thunks::Test1::f()
53
54 // Overrides only the left child's method (A::f), needs no thunks.
55 virtual void f();
56};
57
58Test1 t1;
59
60struct Test2: A, B {
61 // NO-THUNKS-Test2: VFTable for 'A' in 'no_thunks::Test2' (1 entries)
62 // NO-THUNKS-Test2-NEXT: 0 | void A::f()
63
64 // NO-THUNKS-Test2: VFTable for 'B' in 'no_thunks::Test2' (2 entries)
65 // NO-THUNKS-Test2-NEXT: 0 | void no_thunks::Test2::g()
66 // NO-THUNKS-Test2-NEXT: 1 | void B::h()
67
68 // NO-THUNKS-Test2: VFTable indices for 'no_thunks::Test2' (1 entries).
69 // NO-THUNKS-Test2-NEXT: via vfptr at offset 4
70 // NO-THUNKS-Test2-NEXT: 0 | void no_thunks::Test2::g()
71
72 // Overrides only the right child's method (B::g), needs this adjustment but
73 // not thunks.
74 virtual void g();
75};
76
77Test2 t2;
78
79struct Test3: A, B {
80 // NO-THUNKS-Test3: VFTable for 'A' in 'no_thunks::Test3' (2 entries)
81 // NO-THUNKS-Test3-NEXT: 0 | void A::f()
82 // NO-THUNKS-Test3-NEXT: 1 | void no_thunks::Test3::i()
83
84 // NO-THUNKS-Test3: VFTable for 'B' in 'no_thunks::Test3' (2 entries)
85 // NO-THUNKS-Test3-NEXT: 0 | void B::g()
86 // NO-THUNKS-Test3-NEXT: 1 | void B::h()
87
88 // NO-THUNKS-Test3: VFTable indices for 'no_thunks::Test3' (1 entries).
89 // NO-THUNKS-Test3-NEXT: 1 | void no_thunks::Test3::i()
90
91 // Only adds a new method.
92 virtual void i();
93};
94
95Test3 t3;
96
97// Only the right base has a vftable, so it's laid out before the left one!
98struct Test4 : Empty, A {
99 // NO-THUNKS-Test4: VFTable for 'A' in 'no_thunks::Test4' (1 entries)
100 // NO-THUNKS-Test4-NEXT: 0 | void no_thunks::Test4::f()
101
102 // NO-THUNKS-Test4: VFTable indices for 'no_thunks::Test4' (1 entries).
103 // NO-THUNKS-Test4-NEXT: 0 | void no_thunks::Test4::f()
104
105 virtual void f();
106};
107
108Test4 t4;
109
110// 2-level structure with repeating subobject types, but no thunks needed.
111struct Test5: Test1, Test2 {
112 // NO-THUNKS-Test5: VFTable for 'A' in 'no_thunks::Test1' in 'no_thunks::Test5' (2 entries)
113 // NO-THUNKS-Test5-NEXT: 0 | void no_thunks::Test1::f()
114 // NO-THUNKS-Test5-NEXT: 1 | void no_thunks::Test5::z()
115
116 // NO-THUNKS-Test5: VFTable for 'B' in 'no_thunks::Test1' in 'no_thunks::Test5' (2 entries)
117 // NO-THUNKS-Test5-NEXT: 0 | void B::g()
118 // NO-THUNKS-Test5-NEXT: 1 | void B::h()
119
120 // NO-THUNKS-Test5: VFTable for 'A' in 'no_thunks::Test2' in 'no_thunks::Test5' (1 entries)
121 // NO-THUNKS-Test5-NEXT: 0 | void A::f()
122
123 // NO-THUNKS-Test5: VFTable for 'B' in 'no_thunks::Test2' in 'no_thunks::Test5' (2 entries)
124 // NO-THUNKS-Test5-NEXT: 0 | void no_thunks::Test2::g()
125 // NO-THUNKS-Test5-NEXT: 1 | void B::h()
126
127 // NO-THUNKS-Test5: VFTable indices for 'no_thunks::Test5' (1 entries).
128 // NO-THUNKS-Test5-NEXT: 1 | void no_thunks::Test5::z()
129
130 virtual void z();
131};
132
133Test5 t5;
134
135struct Test6: Test1 {
136 // NO-THUNKS-Test6: VFTable for 'A' in 'no_thunks::Test1' in 'no_thunks::Test6' (1 entries).
137 // NO-THUNKS-Test6-NEXT: 0 | void no_thunks::Test6::f()
138
139 // NO-THUNKS-Test6: VFTable for 'B' in 'no_thunks::Test1' in 'no_thunks::Test6' (2 entries).
140 // NO-THUNKS-Test6-NEXT: 0 | void B::g()
141 // NO-THUNKS-Test6-NEXT: 1 | void B::h()
142
143 // NO-THUNKS-Test6: VFTable indices for 'no_thunks::Test6' (1 entries).
144 // NO-THUNKS-Test6-NEXT: 0 | void no_thunks::Test6::f()
145
146 // Overrides both no_thunks::Test1::f and A::f.
147 virtual void f();
148};
149
150Test6 t6;
151
152struct Test7: Test2 {
153 // NO-THUNKS-Test7: VFTable for 'A' in 'no_thunks::Test2' in 'no_thunks::Test7' (1 entries).
154 // NO-THUNKS-Test7-NEXT: 0 | void A::f()
155
156 // NO-THUNKS-Test7: VFTable for 'B' in 'no_thunks::Test2' in 'no_thunks::Test7' (2 entries).
157 // NO-THUNKS-Test7-NEXT: 0 | void no_thunks::Test7::g()
158 // NO-THUNKS-Test7-NEXT: 1 | void B::h()
159
160 // NO-THUNKS-Test7: VFTable indices for 'no_thunks::Test7' (1 entries).
161 // NO-THUNKS-Test7-NEXT: via vfptr at offset 4
162 // NO-THUNKS-Test7-NEXT: 0 | void no_thunks::Test7::g()
163
164 // Overrides both no_thunks::Test2::g and B::g.
165 virtual void g();
166};
167
168Test7 t7;
169
170struct Test8: Test3 {
171 // NO-THUNKS-Test8: VFTable for 'A' in 'no_thunks::Test3' in 'no_thunks::Test8' (2 entries).
172 // NO-THUNKS-Test8-NEXT: 0 | void A::f()
173 // NO-THUNKS-Test8-NEXT: 1 | void no_thunks::Test3::i()
174
175 // NO-THUNKS-Test8: VFTable for 'B' in 'no_thunks::Test3' in 'no_thunks::Test8' (2 entries).
176 // NO-THUNKS-Test8-NEXT: 0 | void no_thunks::Test8::g()
177 // NO-THUNKS-Test8-NEXT: 1 | void B::h()
178
179 // NO-THUNKS-Test8: VFTable indices for 'no_thunks::Test8' (1 entries).
180 // NO-THUNKS-Test8-NEXT: via vfptr at offset 4
181 // NO-THUNKS-Test8-NEXT: 0 | void no_thunks::Test8::g()
182
183 // Overrides grandparent's B::g.
184 virtual void g();
185};
186
187Test8 t8;
188
189struct D : A {
190 virtual void g();
191};
192
193// Repeating subobject.
194struct Test9: A, D {
195 // NO-THUNKS-Test9: VFTable for 'A' in 'no_thunks::Test9' (2 entries).
196 // NO-THUNKS-Test9-NEXT: 0 | void A::f()
197 // NO-THUNKS-Test9-NEXT: 1 | void no_thunks::Test9::h()
198
199 // NO-THUNKS-Test9: VFTable for 'A' in 'no_thunks::D' in 'no_thunks::Test9' (2 entries).
200 // NO-THUNKS-Test9-NEXT: 0 | void A::f()
201 // NO-THUNKS-Test9-NEXT: 1 | void no_thunks::D::g()
202
203 // NO-THUNKS-Test9: VFTable indices for 'no_thunks::Test9' (1 entries).
204 // NO-THUNKS-Test9-NEXT: 1 | void no_thunks::Test9::h()
205
206 virtual void h();
207};
208
209Test9 t9;
210}
211
212namespace pure_virtual {
213struct D {
214 virtual void g() = 0;
215 virtual void h();
216};
217
218
219struct Test1: A, D {
220 // PURE-VIRTUAL-Test1: VFTable for 'A' in 'pure_virtual::Test1' (1 entries)
221 // PURE-VIRTUAL-Test1-NEXT: 0 | void A::f()
222
223 // PURE-VIRTUAL-Test1: VFTable for 'pure_virtual::D' in 'pure_virtual::Test1' (2 entries)
224 // PURE-VIRTUAL-Test1-NEXT: 0 | void pure_virtual::Test1::g()
225 // PURE-VIRTUAL-Test1-NEXT: 1 | void pure_virtual::D::h()
226
227 // PURE-VIRTUAL-Test1: VFTable indices for 'pure_virtual::Test1' (1 entries).
228 // PURE-VIRTUAL-Test1-NEXT: via vfptr at offset 4
229 // PURE-VIRTUAL-Test1-NEXT: 0 | void pure_virtual::Test1::g()
230
231 // Overrides only the right child's method (pure_virtual::D::g), needs this adjustment but
232 // not thunks.
233 virtual void g();
234};
235
236Test1 t1;
237}
238
239namespace this_adjustment {
240
241// Overrides methods of two bases at the same time, thus needing thunks.
242struct Test1 : B, C {
243 // THIS-THUNKS-Test1: VFTable for 'B' in 'this_adjustment::Test1' (2 entries).
244 // THIS-THUNKS-Test1-NEXT: 0 | void this_adjustment::Test1::g()
245 // THIS-THUNKS-Test1-NEXT: 1 | void B::h()
246
247 // THIS-THUNKS-Test1: VFTable for 'C' in 'this_adjustment::Test1' (1 entries).
248 // THIS-THUNKS-Test1-NEXT: 0 | void this_adjustment::Test1::g()
249 // THIS-THUNKS-Test1-NEXT: [this adjustment: -4 non-virtual]
250
251 // THIS-THUNKS-Test1: Thunks for 'void this_adjustment::Test1::g()' (1 entry).
252 // THIS-THUNKS-Test1-NEXT: 0 | this adjustment: -4 non-virtual
253
254 // THIS-THUNKS-Test1: VFTable indices for 'this_adjustment::Test1' (1 entries).
255 // THIS-THUNKS-Test1-NEXT: 0 | void this_adjustment::Test1::g()
256
257 virtual void g();
258};
259
260Test1 t1;
261
262struct Test2 : A, B, C {
263 // THIS-THUNKS-Test2: VFTable for 'A' in 'this_adjustment::Test2' (1 entries).
264 // THIS-THUNKS-Test2-NEXT: 0 | void A::f()
265
266 // THIS-THUNKS-Test2: VFTable for 'B' in 'this_adjustment::Test2' (2 entries).
267 // THIS-THUNKS-Test2-NEXT: 0 | void this_adjustment::Test2::g()
268 // THIS-THUNKS-Test2-NEXT: 1 | void B::h()
269
270 // THIS-THUNKS-Test2: VFTable for 'C' in 'this_adjustment::Test2' (1 entries).
271 // THIS-THUNKS-Test2-NEXT: 0 | void this_adjustment::Test2::g()
272 // THIS-THUNKS-Test2-NEXT: [this adjustment: -4 non-virtual]
273
274 // THIS-THUNKS-Test2: Thunks for 'void this_adjustment::Test2::g()' (1 entry).
275 // THIS-THUNKS-Test2-NEXT: 0 | this adjustment: -4 non-virtual
276
277 // THIS-THUNKS-Test2: VFTable indices for 'this_adjustment::Test2' (1 entries).
278 // THIS-THUNKS-Test2-NEXT: via vfptr at offset 4
279 // THIS-THUNKS-Test2-NEXT: 0 | void this_adjustment::Test2::g()
280
281 virtual void g();
282};
283
284Test2 t2;
285
286// Overrides methods of two bases at the same time, thus needing thunks.
287struct Test3: no_thunks::Test1, no_thunks::Test2 {
288 // THIS-THUNKS-Test3: VFTable for 'A' in 'no_thunks::Test1' in 'this_adjustment::Test3' (1 entries).
289 // THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::f()
290
291 // THIS-THUNKS-Test3: VFTable for 'B' in 'no_thunks::Test1' in 'this_adjustment::Test3' (2 entries).
292 // THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::g()
293 // THIS-THUNKS-Test3-NEXT: 1 | void B::h()
294
295 // THIS-THUNKS-Test3: VFTable for 'A' in 'no_thunks::Test2' in 'this_adjustment::Test3' (1 entries).
296 // THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::f()
297 // THIS-THUNKS-Test3-NEXT: [this adjustment: -8 non-virtual]
298
299 // THIS-THUNKS-Test3: Thunks for 'void this_adjustment::Test3::f()' (1 entry).
300 // THIS-THUNKS-Test3-NEXT: 0 | this adjustment: -8 non-virtual
301
302 // THIS-THUNKS-Test3: VFTable for 'B' in 'no_thunks::Test2' in 'this_adjustment::Test3' (2 entries).
303 // THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::g()
304 // THIS-THUNKS-Test3-NEXT: [this adjustment: -8 non-virtual]
305 // THIS-THUNKS-Test3-NEXT: 1 | void B::h()
306
307 // THIS-THUNKS-Test3: Thunks for 'void this_adjustment::Test3::g()' (1 entry).
308 // THIS-THUNKS-Test3-NEXT: 0 | this adjustment: -8 non-virtual
309
310 // THIS-THUNKS-Test3: VFTable indices for 'this_adjustment::Test3' (2 entries).
311 // THIS-THUNKS-Test3-NEXT: via vfptr at offset 0
312 // THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::f()
313 // THIS-THUNKS-Test3-NEXT: via vfptr at offset 4
314 // THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::g()
315
316 virtual void f();
317 virtual void g();
318};
319
320Test3 t3;
321}
322
323namespace return_adjustment {
324
325struct Ret1 {
326 virtual C* foo();
327 virtual void z();
328};
329
330struct Test1 : Ret1 {
331 // RET-THUNKS-Test1: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test1' (3 entries).
332 // RET-THUNKS-Test1-NEXT: 0 | this_adjustment::Test1 *return_adjustment::Test1::foo()
333 // RET-THUNKS-Test1-NEXT: [return adjustment: 4 non-virtual]
334 // RET-THUNKS-Test1-NEXT: 1 | void return_adjustment::Ret1::z()
335 // RET-THUNKS-Test1-NEXT: 2 | this_adjustment::Test1 *return_adjustment::Test1::foo()
336
337 // RET-THUNKS-Test1: VFTable indices for 'return_adjustment::Test1' (1 entries).
338 // RET-THUNKS-Test1-NEXT: 2 | this_adjustment::Test1 *return_adjustment::Test1::foo()
339
340 virtual this_adjustment::Test1* foo();
341};
342
343Test1 t1;
344
345struct Ret2 : B, this_adjustment::Test1 { };
346
347struct Test2 : Test1 {
348 // RET-THUNKS-Test2: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test1' in 'return_adjustment::Test2' (4 entries).
349 // RET-THUNKS-Test2-NEXT: 0 | return_adjustment::Ret2 *return_adjustment::Test2::foo()
350 // RET-THUNKS-Test2-NEXT: [return adjustment: 8 non-virtual]
351 // RET-THUNKS-Test2-NEXT: 1 | void return_adjustment::Ret1::z()
352 // RET-THUNKS-Test2-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test2::foo()
353 // RET-THUNKS-Test2-NEXT: [return adjustment: 4 non-virtual]
354 // RET-THUNKS-Test2-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test2::foo()
355
356 // RET-THUNKS-Test2: VFTable indices for 'return_adjustment::Test2' (1 entries).
357 // RET-THUNKS-Test2-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test2::foo()
358
359 virtual Ret2* foo();
360};
361
362Test2 t2;
363
364struct Test3: B, Ret1 {
365 // RET-THUNKS-Test3: VFTable for 'B' in 'return_adjustment::Test3' (2 entries).
366 // RET-THUNKS-Test3-NEXT: 0 | void B::g()
367 // RET-THUNKS-Test3-NEXT: 1 | void B::h()
368
369 // RET-THUNKS-Test3: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test3' (3 entries).
370 // RET-THUNKS-Test3-NEXT: 0 | this_adjustment::Test1 *return_adjustment::Test3::foo()
371 // RET-THUNKS-Test3-NEXT: [return adjustment: 4 non-virtual]
372 // RET-THUNKS-Test3-NEXT: 1 | void return_adjustment::Ret1::z()
373 // RET-THUNKS-Test3-NEXT: 2 | this_adjustment::Test1 *return_adjustment::Test3::foo()
374
375 // RET-THUNKS-Test3: VFTable indices for 'return_adjustment::Test3' (1 entries).
376 // RET-THUNKS-Test3-NEXT: via vfptr at offset 4
377 // RET-THUNKS-Test3-NEXT: 2 | this_adjustment::Test1 *return_adjustment::Test3::foo()
378
379 virtual this_adjustment::Test1* foo();
380};
381
382Test3 t3;
383
384struct Test4 : Test3 {
385 // RET-THUNKS-Test4: VFTable for 'B' in 'return_adjustment::Test3' in 'return_adjustment::Test4' (2 entries).
386 // RET-THUNKS-Test4-NEXT: 0 | void B::g()
387 // RET-THUNKS-Test4-NEXT: 1 | void B::h()
388
389 // RET-THUNKS-Test4: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test3' in 'return_adjustment::Test4' (4 entries).
390 // RET-THUNKS-Test4-NEXT: 0 | return_adjustment::Ret2 *return_adjustment::Test4::foo()
391 // RET-THUNKS-Test4-NEXT: [return adjustment: 8 non-virtual]
392 // RET-THUNKS-Test4-NEXT: 1 | void return_adjustment::Ret1::z()
393 // RET-THUNKS-Test4-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test4::foo()
394 // RET-THUNKS-Test4-NEXT: [return adjustment: 4 non-virtual]
395 // RET-THUNKS-Test4-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test4::foo()
396
397 // RET-THUNKS-Test4: VFTable indices for 'return_adjustment::Test4' (1 entries).
398 // RET-THUNKS-Test4-NEXT: -- accessible via vfptr at offset 4 --
399 // RET-THUNKS-Test4-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test4::foo()
400
401 virtual Ret2* foo();
402};
403
404Test4 t4;
405
406struct Test5 : Ret1, Test1 {
407 // RET-THUNKS-Test5: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test5' (3 entries).
408 // RET-THUNKS-Test5-NEXT: 0 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
409 // RET-THUNKS-Test5-NEXT: [return adjustment: 8 non-virtual]
410 // RET-THUNKS-Test5-NEXT: 1 | void return_adjustment::Ret1::z()
411 // RET-THUNKS-Test5-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
412
413 // RET-THUNKS-Test5: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test1' in 'return_adjustment::Test5' (4 entries).
414 // RET-THUNKS-Test5-NEXT: 0 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
415 // RET-THUNKS-Test5-NEXT: [return adjustment: 8 non-virtual]
416 // RET-THUNKS-Test5-NEXT: [this adjustment: -4 non-virtual]
417 // RET-THUNKS-Test5-NEXT: 1 | void return_adjustment::Ret1::z()
418 // RET-THUNKS-Test5-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
419 // RET-THUNKS-Test5-NEXT: [return adjustment: 4 non-virtual]
420 // RET-THUNKS-Test5-NEXT: [this adjustment: -4 non-virtual]
421 // RET-THUNKS-Test5-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
422 // RET-THUNKS-Test5-NEXT: [this adjustment: -4 non-virtual]
423
424 // RET-THUNKS-Test5: VFTable indices for 'return_adjustment::Test5' (1 entries).
425 // RET-THUNKS-Test5-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
426
427 virtual Ret2* foo();
428};
429
430Test5 t5;
431}