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 
5 namespace test1 {
6 struct 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 
12 struct B {
13   virtual void g();
14 };
15 
16 // Overrides a method of two bases at the same time, thus needing thunks.
17 struct C : A, B {
18   virtual void g();
19 };
20 
21 struct D {
22   virtual B* foo();
23   virtual void z();
24 };
25 
26 struct 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 
build_vftable(X * obj)44 void build_vftable(X *obj) { obj->foo(); }
45 }
46 
47 namespace test2 {
48 struct A {
49   virtual void g();
50   virtual void h();
51 };
52 
53 struct B {
54   virtual void g();
55 };
56 
57 struct C : A, B {
58   virtual void g();
59 };
60 
61 struct D {
62   virtual B* foo();
63   virtual void z();
64 };
65 
66 struct E : D {
67   virtual C* foo();
68 };
69 
70 struct F : C { };
71 
72 struct 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 
build_vftable(X * obj)90 void build_vftable(X *obj) { obj->foo(); }
91 }
92 
93 namespace test3 {
94 struct A {
95   virtual void g();
96   virtual void h();
97 };
98 
99 struct B {
100   virtual void g();
101 };
102 
103 struct C : A, B {
104   virtual void g();
105 };
106 
107 struct D {
108   virtual B* foo();
109   virtual void z();
110 };
111 
112 struct E : D {
113   virtual C* foo();
114 };
115 
116 struct F : A, C { };
117 
118 struct 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 
build_vftable(X * obj)137 void build_vftable(X *obj) { obj->foo(); }
138 }
139 
140 namespace test4 {
141 struct A {
142   virtual void g();
143   virtual void h();
144 };
145 
146 struct B {
147   virtual void g();
148 };
149 
150 struct C : A, B {
151   virtual void g();
152 };
153 
154 struct D {
155   virtual B* foo();
156   virtual void z();
157 };
158 
159 struct E : D {
160   virtual C* foo();
161 };
162 
163 struct F : A, C { };
164 
165 struct 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 
build_vftable(X * obj)201 void build_vftable(X *obj) { obj->foo(); }
202 }
203 
204 namespace test5 {
205 struct A {
206   virtual void g();
207   virtual void h();
208 };
209 
210 struct B {
211   virtual void g();
212 };
213 
214 struct C : A, B {
215   virtual void g();
216 };
217 
218 struct D {
219   virtual B* foo();
220   virtual void z();
221 };
222 
223 struct 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 
build_vftable(X * obj)244 void build_vftable(X *obj) { obj->foo(); }
245 }
246 
247 namespace test6 {
248 struct A {
249   virtual void g();
250   virtual void h();
251 };
252 
253 struct B {
254   virtual void g();
255 };
256 
257 struct C : A, B {
258   virtual void g();
259 };
260 
261 struct D {
262   virtual B* foo();
263   virtual void z();
264 };
265 
266 struct E : A, D {
267   virtual C* foo();
268 };
269 
270 struct F : A, C { };
271 
272 struct 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 
build_vftable(X * obj)296 void build_vftable(X *obj) { obj->foo(); }
297 }
298 
299 namespace test7 {
300 struct A {
301   virtual A *f() = 0;
302 };
303 struct B {
304   virtual void g();
305 };
306 struct 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 
build_vftable(C * obj)320 void build_vftable(C *obj) { obj->g(); }
321 }
322 
323 namespace pr20444 {
324 struct A {
325   virtual A* f();
326 };
327 struct B {
328   virtual B* f();
329 };
330 struct 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 
build_vftable(C * obj)344 void build_vftable(C *obj) { obj->f(); }
345 
346 struct 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 
build_vftable(D * obj)363 void build_vftable(D *obj) { obj->f(); }
364 }
365