xref: /llvm-project/clang/test/Layout/ms-x86-vtordisp.cpp (revision 7c1d9b15eee3a34678addab2bab66f3020ac0753)
1 // RUN: %clang_cc1 -std=c++14 -fno-rtti -fms-extensions -triple i686-pc-win32 -fdump-record-layouts -fsyntax-only %s 2>&1 \
2 // RUN:            | FileCheck %s
3 // RUN: %clang_cc1 -std=c++14 -fno-rtti -fms-extensions -triple x86_64-pc-win32 -fdump-record-layouts -fsyntax-only %s 2>/dev/null \
4 // RUN:            | FileCheck %s -check-prefix CHECK-X64
5 
6 extern "C" int printf(const char *fmt, ...);
7 
8 struct B0 {
9 	int a;
B0B010 	B0() : a(0xf00000B0) {}
fB011 	virtual void f() { printf("B0"); }
12 };
13 
14 struct __declspec(align(16)) B1 {
15 	int a;
B1B116 	B1() : a(0xf00000B1) {}
fB117 	virtual void f() { printf("B1"); }
18 };
19 
20 struct __declspec(align(16)) Align16 {};
21 struct __declspec(align(32)) Align32 {};
22 struct VAlign16 : virtual Align16 {};
23 struct VAlign32 : virtual Align32 {};
24 
25 struct A : virtual B0, virtual B1 {
26 	int a;
AA27 	A() : a(0xf000000A) {}
fA28 	virtual void f() { printf("A"); }
gA29 	virtual void g() { printf("A"); }
30 };
31 
32 // CHECK-LABEL:   0 | struct A{{$}}
33 // CHECK-NEXT:    0 |   (A vftable pointer)
34 // CHECK-NEXT:    4 |   (A vbtable pointer)
35 // CHECK-NEXT:    8 |   int a
36 // CHECK-NEXT:   16 |   (vtordisp for vbase B0)
37 // CHECK-NEXT:   20 |   struct B0 (virtual base)
38 // CHECK-NEXT:   20 |     (B0 vftable pointer)
39 // CHECK-NEXT:   24 |     int a
40 // CHECK-NEXT:   44 |   (vtordisp for vbase B1)
41 // CHECK-NEXT:   48 |   struct B1 (virtual base)
42 // CHECK-NEXT:   48 |     (B1 vftable pointer)
43 // CHECK-NEXT:   52 |     int a
44 // CHECK-NEXT:      | [sizeof=64, align=16
45 // CHECK-NEXT:      |  nvsize=12, nvalign=16]
46 // CHECK-X64-LABEL:   0 | struct A{{$}}
47 // CHECK-X64-NEXT:    0 |   (A vftable pointer)
48 // CHECK-X64-NEXT:    8 |   (A vbtable pointer)
49 // CHECK-X64-NEXT:   16 |   int a
50 // CHECK-X64-NEXT:   36 |   (vtordisp for vbase B0)
51 // CHECK-X64-NEXT:   40 |   struct B0 (virtual base)
52 // CHECK-X64-NEXT:   40 |     (B0 vftable pointer)
53 // CHECK-X64-NEXT:   48 |     int a
54 // CHECK-X64-NEXT:   76 |   (vtordisp for vbase B1)
55 // CHECK-X64-NEXT:   80 |   struct B1 (virtual base)
56 // CHECK-X64-NEXT:   80 |     (B1 vftable pointer)
57 // CHECK-X64-NEXT:   88 |     int a
58 // CHECK-X64-NEXT:      | [sizeof=96, align=16
59 // CHECK-X64-NEXT:      |  nvsize=24, nvalign=16]
60 
61 struct C : virtual B0, virtual B1, VAlign32 {
62 	int a;
CC63 	C() : a(0xf000000C) {}
fC64 	virtual void f() { printf("C"); }
gC65 	virtual void g() { printf("C"); }
66 };
67 
68 // CHECK-LABEL:   0 | struct C{{$}}
69 // CHECK-NEXT:    0 |   (C vftable pointer)
70 // CHECK-NEXT:   32 |   struct VAlign32 (base)
71 // CHECK-NEXT:   32 |     (VAlign32 vbtable pointer)
72 // CHECK-NEXT:   36 |   int a
73 // CHECK-NEXT:   64 |   (vtordisp for vbase B0)
74 // CHECK-NEXT:   68 |   struct B0 (virtual base)
75 // CHECK-NEXT:   68 |     (B0 vftable pointer)
76 // CHECK-NEXT:   72 |     int a
77 // CHECK-NEXT:  108 |   (vtordisp for vbase B1)
78 // CHECK-NEXT:  112 |   struct B1 (virtual base)
79 // CHECK-NEXT:  112 |     (B1 vftable pointer)
80 // CHECK-NEXT:  116 |     int a
81 // CHECK-NEXT:  128 |   struct Align32 (virtual base) (empty)
82 // CHECK-NEXT:      | [sizeof=128, align=32
83 // CHECK-NEXT:      |  nvsize=64, nvalign=32]
84 // CHECK-X64-LABEL:   0 | struct C{{$}}
85 // CHECK-X64-NEXT:    0 |   (C vftable pointer)
86 // CHECK-X64-NEXT:   32 |   struct VAlign32 (base)
87 // CHECK-X64-NEXT:   32 |     (VAlign32 vbtable pointer)
88 // CHECK-X64-NEXT:   40 |   int a
89 // CHECK-X64-NEXT:   68 |   (vtordisp for vbase B0)
90 // CHECK-X64-NEXT:   72 |   struct B0 (virtual base)
91 // CHECK-X64-NEXT:   72 |     (B0 vftable pointer)
92 // CHECK-X64-NEXT:   80 |     int a
93 // CHECK-X64-NEXT:  108 |   (vtordisp for vbase B1)
94 // CHECK-X64-NEXT:  112 |   struct B1 (virtual base)
95 // CHECK-X64-NEXT:  112 |     (B1 vftable pointer)
96 // CHECK-X64-NEXT:  120 |     int a
97 // CHECK-X64-NEXT:  128 |   struct Align32 (virtual base) (empty)
98 // CHECK-X64-NEXT:      | [sizeof=128, align=32
99 // CHECK-X64-NEXT:      |  nvsize=64, nvalign=32]
100 
101 struct __declspec(align(32)) D : virtual B0, virtual B1  {
102 	int a;
DD103 	D() : a(0xf000000D) {}
fD104 	virtual void f() { printf("D"); }
gD105 	virtual void g() { printf("D"); }
106 };
107 
108 // CHECK-LABEL:   0 | struct D{{$}}
109 // CHECK-NEXT:    0 |   (D vftable pointer)
110 // CHECK-NEXT:    4 |   (D vbtable pointer)
111 // CHECK-NEXT:    8 |   int a
112 // CHECK-NEXT:   32 |   (vtordisp for vbase B0)
113 // CHECK-NEXT:   36 |   struct B0 (virtual base)
114 // CHECK-NEXT:   36 |     (B0 vftable pointer)
115 // CHECK-NEXT:   40 |     int a
116 // CHECK-NEXT:   76 |   (vtordisp for vbase B1)
117 // CHECK-NEXT:   80 |   struct B1 (virtual base)
118 // CHECK-NEXT:   80 |     (B1 vftable pointer)
119 // CHECK-NEXT:   84 |     int a
120 // CHECK-NEXT:      | [sizeof=96, align=32
121 // CHECK-NEXT:      |  nvsize=12, nvalign=32]
122 // CHECK-X64-LABEL:   0 | struct D{{$}}
123 // CHECK-X64-NEXT:    0 |   (D vftable pointer)
124 // CHECK-X64-NEXT:    8 |   (D vbtable pointer)
125 // CHECK-X64-NEXT:   16 |   int a
126 // CHECK-X64-NEXT:   36 |   (vtordisp for vbase B0)
127 // CHECK-X64-NEXT:   40 |   struct B0 (virtual base)
128 // CHECK-X64-NEXT:   40 |     (B0 vftable pointer)
129 // CHECK-X64-NEXT:   48 |     int a
130 // CHECK-X64-NEXT:   76 |   (vtordisp for vbase B1)
131 // CHECK-X64-NEXT:   80 |   struct B1 (virtual base)
132 // CHECK-X64-NEXT:   80 |     (B1 vftable pointer)
133 // CHECK-X64-NEXT:   88 |     int a
134 // CHECK-X64-NEXT:      | [sizeof=96, align=32
135 // CHECK-X64-NEXT:      |  nvsize=24, nvalign=32]
136 
137 struct AT {
~ATAT138 	virtual ~AT(){}
139 };
140 struct CT : virtual AT {
141 	virtual ~CT();
142 };
~CT()143 CT::~CT(){}
144 
145 // CHECK-LABEL:   0 | struct CT{{$}}
146 // CHECK-NEXT:    0 |   (CT vbtable pointer)
147 // CHECK-NEXT:    4 |   struct AT (virtual base)
148 // CHECK-NEXT:    4 |     (AT vftable pointer)
149 // CHECK-NEXT:      | [sizeof=8, align=4
150 // CHECK-NEXT:      |  nvsize=4, nvalign=4]
151 // CHECK-X64-LABEL:   0 | struct CT{{$}}
152 // CHECK-X64-NEXT:    0 |   (CT vbtable pointer)
153 // CHECK-X64-NEXT:    8 |   struct AT (virtual base)
154 // CHECK-X64-NEXT:    8 |     (AT vftable pointer)
155 // CHECK-X64-NEXT:      | [sizeof=16, align=8
156 // CHECK-X64-NEXT:      |  nvsize=8, nvalign=8]
157 
158 struct XA {
XAXA159 	XA() { printf("XA"); }
160 	long long ll;
161 };
162 struct XB : XA {
XBXB163 	XB() { printf("XB"); }
fooXB164 	virtual void foo() {}
165 	int b;
166 };
167 struct XC : virtual XB {
XCXC168 	XC() { printf("XC"); }
fooXC169 	virtual void foo() {}
170 };
171 
172 // CHECK-LABEL:   0 | struct XC{{$}}
173 // CHECK-NEXT:    0 |   (XC vbtable pointer)
174 // CHECK-NEXT:    4 |   (vtordisp for vbase XB)
175 // CHECK-NEXT:    8 |   struct XB (virtual base)
176 // CHECK-NEXT:    8 |     (XB vftable pointer)
177 // CHECK-NEXT:   16 |     struct XA (base)
178 // CHECK-NEXT:   16 |       long long ll
179 // CHECK-NEXT:   24 |     int b
180 // CHECK-NEXT:      | [sizeof=32, align=8
181 // CHECK-NEXT:      |  nvsize=4, nvalign=8]
182 // CHECK-X64-LABEL:   0 | struct XC{{$}}
183 // CHECK-X64-NEXT:    0 |   (XC vbtable pointer)
184 // CHECK-X64-NEXT:   12 |   (vtordisp for vbase XB)
185 // CHECK-X64-NEXT:   16 |   struct XB (virtual base)
186 // CHECK-X64-NEXT:   16 |     (XB vftable pointer)
187 // CHECK-X64-NEXT:   24 |     struct XA (base)
188 // CHECK-X64-NEXT:   24 |       long long ll
189 // CHECK-X64-NEXT:   32 |     int b
190 // CHECK-X64-NEXT:      | [sizeof=40, align=8
191 // CHECK-X64-NEXT:      |  nvsize=8, nvalign=8]
192 
193 namespace pragma_test1 {
194 // No overrides means no vtordisps by default.
195 struct A { virtual ~A(); virtual void foo(); int a; };
196 struct B : virtual A { virtual ~B(); virtual void bar(); int b; };
197 struct C : virtual B { int c; };
198 // CHECK-LABEL:   0 | struct pragma_test1::C{{$}}
199 // CHECK-NEXT:    0 |   (C vbtable pointer)
200 // CHECK-NEXT:    4 |   int c
201 // CHECK-NEXT:    8 |   struct pragma_test1::A (virtual base)
202 // CHECK-NEXT:    8 |     (A vftable pointer)
203 // CHECK-NEXT:   12 |     int a
204 // CHECK-NEXT:   16 |   struct pragma_test1::B (virtual base)
205 // CHECK-NEXT:   16 |     (B vftable pointer)
206 // CHECK-NEXT:   20 |     (B vbtable pointer)
207 // CHECK-NEXT:   24 |     int b
208 // CHECK-NEXT:      | [sizeof=28, align=4
209 // CHECK-NEXT:      |  nvsize=8, nvalign=4]
210 }
211 
212 namespace pragma_test2 {
213 struct A { virtual ~A(); virtual void foo(); int a; };
214 #pragma vtordisp(push,2)
215 struct B : virtual A { virtual ~B(); virtual void bar(); int b; };
216 struct C : virtual B { int c; };
217 #pragma vtordisp(pop)
218 // CHECK-LABEL:   0 | struct pragma_test2::C{{$}}
219 // CHECK-NEXT:    0 |   (C vbtable pointer)
220 // CHECK-NEXT:    4 |   int c
221 // CHECK-NEXT:    8 |   (vtordisp for vbase A)
222 // CHECK-NEXT:   12 |   struct pragma_test2::A (virtual base)
223 // CHECK-NEXT:   12 |     (A vftable pointer)
224 // CHECK-NEXT:   16 |     int a
225 //   By adding a virtual method and vftable to B, now we need a vtordisp.
226 // CHECK-NEXT:   20 |   (vtordisp for vbase B)
227 // CHECK-NEXT:   24 |   struct pragma_test2::B (virtual base)
228 // CHECK-NEXT:   24 |     (B vftable pointer)
229 // CHECK-NEXT:   28 |     (B vbtable pointer)
230 // CHECK-NEXT:   32 |     int b
231 // CHECK-NEXT:      | [sizeof=36, align=4
232 // CHECK-NEXT:      |  nvsize=8, nvalign=4]
233 }
234 
235 namespace pragma_test3 {
236 struct A { virtual ~A(); virtual void foo(); int a; };
237 #pragma vtordisp(push,2)
238 struct B : virtual A { virtual ~B(); virtual void foo(); int b; };
239 struct C : virtual B { int c; };
240 #pragma vtordisp(pop)
241 // CHECK-LABEL:   0 | struct pragma_test3::C{{$}}
242 // CHECK-NEXT:    0 |   (C vbtable pointer)
243 // CHECK-NEXT:    4 |   int c
244 // CHECK-NEXT:    8 |   (vtordisp for vbase A)
245 // CHECK-NEXT:   12 |   struct pragma_test3::A (virtual base)
246 // CHECK-NEXT:   12 |     (A vftable pointer)
247 // CHECK-NEXT:   16 |     int a
248 //   No vtordisp before B!  It doesn't have its own vftable.
249 // CHECK-NEXT:   20 |   struct pragma_test3::B (virtual base)
250 // CHECK-NEXT:   20 |     (B vbtable pointer)
251 // CHECK-NEXT:   24 |     int b
252 // CHECK-NEXT:      | [sizeof=28, align=4
253 // CHECK-NEXT:      |  nvsize=8, nvalign=4]
254 }
255 
256 namespace pragma_test4 {
257 struct A {
258   A();
259   virtual void foo();
260   int a;
261 };
262 
263 // Make sure the pragma applies to class template decls before they've been
264 // instantiated.
265 #pragma vtordisp(push,2)
266 template <typename T>
267 struct B : virtual A {
268   B();
269   virtual ~B();
270   virtual void bar();
271   T b;
272 };
273 #pragma vtordisp(pop)
274 
275 struct C : virtual B<int> { int c; };
276 // CHECK-LABEL:   0 | struct pragma_test4::C{{$}}
277 // CHECK-NEXT:    0 |   (C vbtable pointer)
278 // CHECK-NEXT:    4 |   int c
279 //   Pragma applies to B, which has vbase A.
280 // CHECK-NEXT:    8 |   (vtordisp for vbase A)
281 // CHECK-NEXT:   12 |   struct pragma_test4::A (virtual base)
282 // CHECK-NEXT:   12 |     (A vftable pointer)
283 // CHECK-NEXT:   16 |     int a
284 //   Pragma does not apply to C, and B doesn't usually need a vtordisp in C.
285 // CHECK-NEXT:   20 |   struct pragma_test4::B<int> (virtual base)
286 // CHECK-NEXT:   20 |     (B vftable pointer)
287 // CHECK-NEXT:   24 |     (B vbtable pointer)
288 // CHECK-NEXT:   28 |     int b
289 // CHECK-NEXT:      | [sizeof=32, align=4
290 // CHECK-NEXT:      |  nvsize=8, nvalign=4]
291 }
292 
293 struct GA {
funGA294 	virtual void fun() {}
295 };
296 struct GB: public GA {};
297 struct GC: public virtual GA {
funGC298 	virtual void fun() {}
GCGC299 	GC() {}
300 };
301 struct GD: public virtual GC, public virtual GB {};
302 
303 // CHECK-LABEL:   0 | struct GD{{$}}
304 // CHECK-NEXT:    0 |   (GD vbtable pointer)
305 // CHECK-NEXT:    4 |   (vtordisp for vbase GA)
306 // CHECK-NEXT:    8 |   struct GA (virtual base)
307 // CHECK-NEXT:    8 |     (GA vftable pointer)
308 // CHECK-NEXT:   12 |   struct GC (virtual base)
309 // CHECK-NEXT:   12 |     (GC vbtable pointer)
310 // CHECK-NEXT:   16 |   struct GB (virtual base)
311 // CHECK-NEXT:   16 |     struct GA (primary base)
312 // CHECK-NEXT:   16 |       (GA vftable pointer)
313 // CHECK-NEXT:      | [sizeof=20, align=4
314 // CHECK-NEXT:      |  nvsize=4, nvalign=4]
315 // CHECK-X64-LABEL:   0 | struct GD{{$}}
316 // CHECK-X64-NEXT:    0 |   (GD vbtable pointer)
317 // CHECK-X64-NEXT:   12 |   (vtordisp for vbase GA)
318 // CHECK-X64-NEXT:   16 |   struct GA (virtual base)
319 // CHECK-X64-NEXT:   16 |     (GA vftable pointer)
320 // CHECK-X64-NEXT:   24 |   struct GC (virtual base)
321 // CHECK-X64-NEXT:   24 |     (GC vbtable pointer)
322 // CHECK-X64-NEXT:   32 |   struct GB (virtual base)
323 // CHECK-X64-NEXT:   32 |     struct GA (primary base)
324 // CHECK-X64-NEXT:   32 |       (GA vftable pointer)
325 // CHECK-X64-NEXT:      | [sizeof=40, align=8
326 // CHECK-X64-NEXT:      |  nvsize=8, nvalign=8]
327 
328 struct HA {
funHA329   virtual void fun() {}
330 };
331 #pragma vtordisp(push, 2)
332 struct HB : virtual HA {};
333 #pragma vtordisp(pop)
334 #pragma vtordisp(push, 0)
335 struct HC : virtual HB {};
336 #pragma vtordisp(pop)
337 
338 // CHECK-LABEL:   0 | struct HC{{$}}
339 // CHECK-NEXT:    0 |   (HC vbtable pointer)
340 // CHECK-NEXT:    4 |   (vtordisp for vbase HA)
341 // CHECK-NEXT:    8 |   struct HA (virtual base)
342 // CHECK-NEXT:    8 |     (HA vftable pointer)
343 // CHECK-NEXT:   12 |   struct HB (virtual base)
344 // CHECK-NEXT:   12 |     (HB vbtable pointer)
345 // CHECK-NEXT:      | [sizeof=16, align=4
346 // CHECK-NEXT:      |  nvsize=4, nvalign=4]
347 // CHECK-X64-LABEL:   0 | struct HC{{$}}
348 // CHECK-X64-NEXT:    0 |   (HC vbtable pointer)
349 // CHECK-X64-NEXT:   12 |   (vtordisp for vbase HA)
350 // CHECK-X64-NEXT:   16 |   struct HA (virtual base)
351 // CHECK-X64-NEXT:   16 |     (HA vftable pointer)
352 // CHECK-X64-NEXT:   24 |   struct HB (virtual base)
353 // CHECK-X64-NEXT:   24 |     (HB vbtable pointer)
354 // CHECK-X64-NEXT:      | [sizeof=32, align=8
355 // CHECK-X64-NEXT:      |  nvsize=8, nvalign=8]
356 
357 struct IA {
358   virtual void f();
359 };
360 struct __declspec(dllexport) IB : virtual IA {
361   virtual void f() = 0;
IBIB362   IB() {}
363 };
364 
365 // CHECK-LABEL:   0 | struct IB{{$}}
366 // CHECK-NEXT:    0 |   (IB vbtable pointer)
367 // CHECK-NEXT:    4 |   struct IA (virtual base)
368 // CHECK-NEXT:    4 |     (IA vftable pointer)
369 // CHECK-NEXT:      | [sizeof=8, align=4
370 // CHECK-NEXT:      |  nvsize=4, nvalign=4]
371 // CHECK-X64-LABEL:   0 | struct IB{{$}}
372 // CHECK-X64-NEXT:    0 |   (IB vbtable pointer)
373 // CHECK-X64-NEXT:    8 |   struct IA (virtual base)
374 // CHECK-X64-NEXT:    8 |     (IA vftable pointer)
375 // CHECK-X64-NEXT:      | [sizeof=16, align=8
376 // CHECK-X64-NEXT:      |  nvsize=8, nvalign=8]
377 
378 int a[
379 sizeof(A)+
380 sizeof(C)+
381 sizeof(D)+
382 sizeof(CT)+
383 sizeof(XC)+
384 sizeof(pragma_test1::C)+
385 sizeof(pragma_test2::C)+
386 sizeof(pragma_test3::C)+
387 sizeof(pragma_test4::C)+
388 sizeof(GD)+
389 sizeof(HC)+
390 sizeof(IB)+
391 0];
392