Clang Project

clang_source_code/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-return-adjustment.cpp
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 g();
8  // Add an extra virtual method so it's easier to check for the absence of thunks.
9  virtual void h();
10};
11
12struct B {
13  virtual void g();
14};
15
16// Overrides a method of two bases at the same time, thus needing thunks.
17struct C : A, B {
18  virtual void g();
19};
20
21struct D {
22  virtual B* foo();
23  virtual void z();
24};
25
26struct X : D {
27  // CHECK-LABEL: VFTable for 'test1::D' in 'test1::X' (3 entries).
28  // CHECK-NEXT:   0 | test1::C *test1::X::foo()
29  // CHECK-NEXT:       [return adjustment (to type 'struct test1::B *'): 4 non-virtual]
30  // CHECK-NEXT:   1 | void test1::D::z()
31  // CHECK-NEXT:   2 | test1::C *test1::X::foo()
32
33  // CHECK-LABEL: Thunks for 'test1::C *test1::X::foo()' (1 entry).
34  // CHECK-NEXT:   0 | [return adjustment (to type 'struct test1::B *'): 4 non-virtual]
35
36  // CHECK-LABEL: VFTable indices for 'test1::X' (1 entry).
37  // CHECK-NEXT:   2 | test1::C *test1::X::foo()
38
39  // MANGLING-DAG: @"??_7X@test1@@6B@"
40
41  virtual C* foo();
42} x;
43
44void build_vftable(X *obj) { obj->foo(); }
45}
46
47namespace test2 {
48struct A {
49  virtual void g();
50  virtual void h();
51};
52
53struct B {
54  virtual void g();
55};
56
57struct C : A, B {
58  virtual void g();
59};
60
61struct D {
62  virtual B* foo();
63  virtual void z();
64};
65
66struct E : D {
67  virtual C* foo();
68};
69
70struct F : C { };
71
72struct X : E {
73  virtual F* foo();
74  // CHECK-LABEL: VFTable for 'test2::D' in 'test2::E' in 'test2::X' (4 entries).
75  // CHECK-NEXT:   0 | test2::F *test2::X::foo()
76  // CHECK-NEXT:       [return adjustment (to type 'struct test2::B *'): 4 non-virtual]
77  // CHECK-NEXT:   1 | void test2::D::z()
78  // CHECK-NEXT:   2 | test2::F *test2::X::foo()
79  // CHECK-NEXT:       [return adjustment (to type 'struct test2::C *'): 0 non-virtual]
80  // CHECK-NEXT:   3 | test2::F *test2::X::foo()
81
82  // CHECK-LABEL: Thunks for 'test2::F *test2::X::foo()' (2 entries).
83  // CHECK-NEXT:   0 | [return adjustment (to type 'struct test2::C *'): 0 non-virtual]
84  // CHECK-NEXT:   1 | [return adjustment (to type 'struct test2::B *'): 4 non-virtual]
85
86  // CHECK-LABEL: VFTable indices for 'test2::X' (1 entry).
87  // CHECK-NEXT:   3 | test2::F *test2::X::foo()
88};
89
90void build_vftable(X *obj) { obj->foo(); }
91}
92
93namespace test3 {
94struct A {
95  virtual void g();
96  virtual void h();
97};
98
99struct B {
100  virtual void g();
101};
102
103struct C : A, B {
104  virtual void g();
105};
106
107struct D {
108  virtual B* foo();
109  virtual void z();
110};
111
112struct E : D {
113  virtual C* foo();
114};
115
116struct F : A, C { };
117
118struct X : E {
119  // CHECK-LABEL: VFTable for 'test3::D' in 'test3::E' in 'test3::X' (4 entries).
120  // CHECK-NEXT:   0 | test3::F *test3::X::foo()
121  // CHECK-NEXT:       [return adjustment (to type 'struct test3::B *'): 8 non-virtual]
122  // CHECK-NEXT:   1 | void test3::D::z()
123  // CHECK-NEXT:   2 | test3::F *test3::X::foo()
124  // CHECK-NEXT:       [return adjustment (to type 'struct test3::C *'): 4 non-virtual]
125  // CHECK-NEXT:   3 | test3::F *test3::X::foo()
126
127  // CHECK-LABEL: Thunks for 'test3::F *test3::X::foo()' (2 entries).
128  // CHECK-NEXT:   0 | [return adjustment (to type 'struct test3::C *'): 4 non-virtual]
129  // CHECK-NEXT:   1 | [return adjustment (to type 'struct test3::B *'): 8 non-virtual]
130
131  // CHECK-LABEL: VFTable indices for 'test3::X' (1 entry).
132  // CHECK-NEXT:   3 | test3::F *test3::X::foo()
133
134  virtual F* foo();
135};
136
137void build_vftable(X *obj) { obj->foo(); }
138}
139
140namespace test4 {
141struct A {
142  virtual void g();
143  virtual void h();
144};
145
146struct B {
147  virtual void g();
148};
149
150struct C : A, B {
151  virtual void g();
152};
153
154struct D {
155  virtual B* foo();
156  virtual void z();
157};
158
159struct E : D {
160  virtual C* foo();
161};
162
163struct F : A, C { };
164
165struct X : D, E {
166  // CHECK-LABEL: VFTable for 'test4::D' in 'test4::X' (3 entries).
167  // CHECK-NEXT:   0 | test4::F *test4::X::foo()
168  // CHECK-NEXT:       [return adjustment (to type 'struct test4::B *'): 8 non-virtual]
169  // CHECK-NEXT:   1 | void test4::D::z()
170  // CHECK-NEXT:   2 | test4::F *test4::X::foo()
171
172  // CHECK-LABEL: Thunks for 'test4::F *test4::X::foo()' (1 entry).
173  // CHECK-NEXT:   0 | [return adjustment (to type 'struct test4::B *'): 8 non-virtual]
174
175  // CHECK-LABEL: VFTable for 'test4::D' in 'test4::E' in 'test4::X' (4 entries).
176  // CHECK-NEXT:   0 | test4::F *test4::X::foo()
177  // CHECK-NEXT:       [return adjustment (to type 'struct test4::B *'): 8 non-virtual]
178  // CHECK-NEXT:       [this adjustment: -4 non-virtual]
179  // CHECK-NEXT:   1 | void test4::D::z()
180  // CHECK-NEXT:   2 | test4::F *test4::X::foo()
181  // CHECK-NEXT:       [return adjustment (to type 'struct test4::C *'): 4 non-virtual]
182  // CHECK-NEXT:       [this adjustment: -4 non-virtual]
183  // CHECK-NEXT:   3 | test4::F *test4::X::foo()
184  // CHECK-NEXT:       [return adjustment (to type 'struct test4::F *'): 0 non-virtual]
185  // CHECK-NEXT:       [this adjustment: -4 non-virtual]
186
187  // CHECK-LABEL: Thunks for 'test4::F *test4::X::foo()' (3 entries).
188  // CHECK-NEXT:   0 | [return adjustment (to type 'struct test4::F *'): 0 non-virtual]
189  // CHECK-NEXT:       [this adjustment: -4 non-virtual]
190  // CHECK-NEXT:   1 | [return adjustment (to type 'struct test4::C *'): 4 non-virtual]
191  // CHECK-NEXT:       [this adjustment: -4 non-virtual]
192  // CHECK-NEXT:   2 | [return adjustment (to type 'struct test4::B *'): 8 non-virtual]
193  // CHECK-NEXT:       [this adjustment: -4 non-virtual]
194
195  // CHECK-LABEL: VFTable indices for 'test4::X' (1 entry).
196  // CHECK-NEXT:   2 | test4::F *test4::X::foo()
197
198  virtual F* foo();
199};
200
201void build_vftable(X *obj) { obj->foo(); }
202}
203
204namespace test5 {
205struct A {
206  virtual void g();
207  virtual void h();
208};
209
210struct B {
211  virtual void g();
212};
213
214struct C : A, B {
215  virtual void g();
216};
217
218struct D {
219  virtual B* foo();
220  virtual void z();
221};
222
223struct X : A, D {
224  // CHECK-LABEL: VFTable for 'test5::A' in 'test5::X' (2 entries).
225  // CHECK-NEXT:   0 | void test5::A::g()
226  // CHECK-NEXT:   1 | void test5::A::h()
227
228  // CHECK-LABEL: VFTable for 'test5::D' in 'test5::X' (3 entries).
229  // CHECK-NEXT:   0 | test5::C *test5::X::foo()
230  // CHECK-NEXT:       [return adjustment (to type 'struct test5::B *'): 4 non-virtual]
231  // CHECK-NEXT:   1 | void test5::D::z()
232  // CHECK-NEXT:   2 | test5::C *test5::X::foo()
233
234  // CHECK-LABEL: Thunks for 'test5::C *test5::X::foo()' (1 entry).
235  // CHECK-NEXT:   0 | [return adjustment (to type 'struct test5::B *'): 4 non-virtual]
236
237  // CHECK-LABEL: VFTable indices for 'test5::X' (1 entry).
238  // CHECK-NEXT:   via vfptr at offset 4
239  // CHECK-NEXT:   2 | test5::C *test5::X::foo()
240
241  virtual C* foo();
242};
243
244void build_vftable(X *obj) { obj->foo(); }
245}
246
247namespace test6 {
248struct A {
249  virtual void g();
250  virtual void h();
251};
252
253struct B {
254  virtual void g();
255};
256
257struct C : A, B {
258  virtual void g();
259};
260
261struct D {
262  virtual B* foo();
263  virtual void z();
264};
265
266struct E : A, D {
267  virtual C* foo();
268};
269
270struct F : A, C { };
271
272struct X : E {
273  // CHECK-LABEL: VFTable for 'test6::A' in 'test6::E' in 'test6::X' (2 entries).
274  // CHECK-NEXT:   0 | void test6::A::g()
275  // CHECK-NEXT:   1 | void test6::A::h()
276
277  // CHECK-LABEL: VFTable for 'test6::D' in 'test6::E' in 'test6::X' (4 entries).
278  // CHECK-NEXT:   0 | test6::F *test6::X::foo()
279  // CHECK-NEXT:       [return adjustment (to type 'struct test6::B *'): 8 non-virtual]
280  // CHECK-NEXT:   1 | void test6::D::z()
281  // CHECK-NEXT:   2 | test6::F *test6::X::foo()
282  // CHECK-NEXT:       [return adjustment (to type 'struct test6::C *'): 4 non-virtual]
283  // CHECK-NEXT:   3 | test6::F *test6::X::foo()
284
285  // CHECK-LABEL: Thunks for 'test6::F *test6::X::foo()' (2 entries).
286  // CHECK-NEXT:   0 | [return adjustment (to type 'struct test6::C *'): 4 non-virtual]
287  // CHECK-NEXT:   1 | [return adjustment (to type 'struct test6::B *'): 8 non-virtual]
288
289  // CHECK-LABEL: VFTable indices for 'test6::X' (1 entry).
290  // CHECK-NEXT:   -- accessible via vfptr at offset 4 --
291  // CHECK-NEXT:   3 | test6::F *test6::X::foo()
292
293  virtual F* foo();
294};
295
296void build_vftable(X *obj) { obj->foo(); }
297}
298
299namespace test7 {
300struct A {
301  virtual A *f() = 0;
302};
303struct B {
304  virtual void g();
305};
306struct C : B, A {
307  virtual void g();
308  virtual C *f() = 0;
309  // CHECK-LABEL: VFTable for 'test7::B' in 'test7::C' (1 entry).
310  // CHECK-NEXT:   0 | void test7::C::g()
311
312  // CHECK-LABEL: VFTable for 'test7::A' in 'test7::C' (2 entries).
313  // CHECK-NEXT:   0 | test7::C *test7::C::f() [pure]
314  // CHECK-NEXT:   1 | test7::C *test7::C::f() [pure]
315
316  // No return adjusting thunks needed for pure virtual methods.
317  // CHECK-NOT: Thunks for 'test7::C *test7::C::f()'
318};
319
320void build_vftable(C *obj) { obj->g(); }
321}
322
323namespace pr20444 {
324struct A {
325  virtual A* f();
326};
327struct B {
328  virtual B* f();
329};
330struct C : A, B {
331  virtual C* f();
332  // CHECK-LABEL: VFTable for 'pr20444::A' in 'pr20444::C' (1 entry).
333  // CHECK-NEXT:   0 | pr20444::C *pr20444::C::f()
334
335  // CHECK-LABEL: VFTable for 'pr20444::B' in 'pr20444::C' (2 entries).
336  // CHECK-NEXT:   0 | pr20444::C *pr20444::C::f()
337  // CHECK-NEXT:       [return adjustment (to type 'struct pr20444::B *'): 4 non-virtual]
338  // CHECK-NEXT:       [this adjustment: -4 non-virtual]
339  // CHECK-NEXT:   1 | pr20444::C *pr20444::C::f()
340  // CHECK-NEXT:       [return adjustment (to type 'struct pr20444::C *'): 0 non-virtual]
341  // CHECK-NEXT:       [this adjustment: -4 non-virtual]
342};
343
344void build_vftable(C *obj) { obj->f(); }
345
346struct D : C {
347  virtual D* f();
348  // CHECK-LABEL: VFTable for 'pr20444::A' in 'pr20444::C' in 'pr20444::D' (1 entry).
349  // CHECK-NEXT:   0 | pr20444::D *pr20444::D::f()
350
351  // CHECK-LABEL: VFTable for 'pr20444::B' in 'pr20444::C' in 'pr20444::D' (3 entries).
352  // CHECK-NEXT:   0 | pr20444::D *pr20444::D::f()
353  // CHECK-NEXT:       [return adjustment (to type 'struct pr20444::B *'): 4 non-virtual]
354  // CHECK-NEXT:       [this adjustment: -4 non-virtual]
355  // CHECK-NEXT:   1 | pr20444::D *pr20444::D::f()
356  // CHECK-NEXT:       [return adjustment (to type 'struct pr20444::C *'): 0 non-virtual]
357  // CHECK-NEXT:       [this adjustment: -4 non-virtual]
358  // CHECK-NEXT:   2 | pr20444::D *pr20444::D::f()
359  // CHECK-NEXT:       [return adjustment (to type 'struct pr20444::D *'): 0 non-virtual]
360  // CHECK-NEXT:       [this adjustment: -4 non-virtual]
361};
362
363void build_vftable(D *obj) { obj->f(); }
364}
365