1 // RUN: %clang_cc1 -std=c++2a -fsyntax-only -triple x86_64-windows-msvc -fms-compatibility -fdump-record-layouts %s | FileCheck %s
6 struct A3
{ [[msvc::no_unique_address
]] A a
; };
7 struct alignas(8) A4
{};
10 [[msvc::no_unique_address
]] A a
;
13 static_assert(sizeof(B
) == 1);
15 // CHECK:*** Dumping AST Record Layout
16 // CHECK: 0 | struct Empty::B
17 // CHECK-NEXT: 0 | struct Empty::A a (empty)
18 // CHECK-NEXT: 0 | char b
19 // CHECK-NEXT: | [sizeof=1, align=1,
20 // CHECK-NEXT: | nvsize=1, nvalign=1]
23 [[msvc::no_unique_address
]] A a
;
24 [[msvc::no_unique_address
]] A2 a2
;
27 static_assert(sizeof(C
) == 1);
29 // CHECK:*** Dumping AST Record Layout
30 // CHECK: 0 | struct Empty::C
31 // CHECK-NEXT: 0 | struct Empty::A a (empty)
32 // CHECK-NEXT: 0 | struct Empty::A2 a2 (empty)
33 // CHECK-NEXT: 0 | char c
34 // CHECK-NEXT: | [sizeof=1, align=1,
35 // CHECK-NEXT: | nvsize=1, nvalign=1]
38 [[msvc::no_unique_address
]] A3 a
;
41 static_assert(sizeof(D
) == 8);
43 // CHECK:*** Dumping AST Record Layout
44 // CHECK: 0 | struct Empty::D
45 // CHECK-NEXT: 0 | struct Empty::A3 a (empty)
46 // CHECK-NEXT: 0 | struct Empty::A a (empty)
47 // CHECK-NEXT: 4 | int i
48 // CHECK-NEXT: | [sizeof=8, align=4,
49 // CHECK-NEXT: | nvsize=8, nvalign=4]
52 [[msvc::no_unique_address
]] A a1
;
53 [[msvc::no_unique_address
]] A a2
;
56 static_assert(sizeof(E
) == 2);
58 // CHECK:*** Dumping AST Record Layout
59 // CHECK: 0 | struct Empty::E
60 // CHECK-NEXT: 0 | struct Empty::A a1 (empty)
61 // CHECK-NEXT: 1 | struct Empty::A a2 (empty)
62 // CHECK-NEXT: 0 | char e
63 // CHECK-NEXT: | [sizeof=2, align=1,
64 // CHECK-NEXT: | nvsize=2, nvalign=1]
68 [[msvc::no_unique_address
]] A a1
;
69 [[msvc::no_unique_address
]] A a2
;
72 static_assert(sizeof(F
) == 2);
74 // CHECK:*** Dumping AST Record Layout
75 // CHECK: 0 | struct Empty::F
76 // CHECK-NEXT: 0 | struct Empty::A a1 (empty)
77 // CHECK-NEXT: 1 | struct Empty::A a2 (empty)
78 // CHECK-NEXT: 0 | char f
79 // CHECK-NEXT: | [sizeof=2, align=1,
80 // CHECK-NEXT: | nvsize=2, nvalign=1]
82 struct G
{ [[msvc::no_unique_address
]] A a
; ~G(); };
83 static_assert(sizeof(G
) == 1);
85 // CHECK:*** Dumping AST Record Layout
86 // CHECK: 0 | struct Empty::G
87 // CHECK-NEXT: 0 | struct Empty::A a (empty)
88 // CHECK-NEXT: | [sizeof=1, align=1,
89 // CHECK-NEXT: | nvsize=1, nvalign=1]
92 [[msvc::no_unique_address
]] A a
;
93 [[msvc::no_unique_address
]] A b
;
96 static_assert(sizeof(H
) == 2);
98 // CHECK:*** Dumping AST Record Layout
99 // CHECK: 0 | struct Empty::H
100 // CHECK-NEXT: 0 | struct Empty::A a (empty)
101 // CHECK-NEXT: 1 | struct Empty::A b (empty)
102 // CHECK-NEXT: | [sizeof=2, align=1,
103 // CHECK-NEXT: | nvsize=2, nvalign=1]
106 [[msvc::no_unique_address
]] A4 a
;
107 [[msvc::no_unique_address
]] A4 b
;
109 static_assert(sizeof(I
) == 16);
111 // CHECK:*** Dumping AST Record Layout
112 // CHECK: 0 | struct Empty::I
113 // CHECK-NEXT: 0 | struct Empty::A4 a (empty)
114 // CHECK-NEXT: 8 | struct Empty::A4 b (empty)
115 // CHECK-NEXT: | [sizeof=16, align=8,
116 // CHECK-NEXT: | nvsize=16, nvalign=8]
119 [[msvc::no_unique_address
]] A4 a
;
122 static_assert(sizeof(J
) == 16);
124 // MSVC puts a and b at the same offset.
125 // CHECK:*** Dumping AST Record Layout
126 // CHECK: 0 | struct Empty::J
127 // CHECK-NEXT: 0 | struct Empty::A4 a (empty)
128 // CHECK-NEXT: 8 | struct Empty::A4 b (empty)
129 // CHECK-NEXT: | [sizeof=16, align=8,
130 // CHECK-NEXT: | nvsize=16, nvalign=8]
133 [[msvc::no_unique_address
]] A4 a
;
134 [[msvc::no_unique_address
]] char c
;
135 [[msvc::no_unique_address
]] A4 b
;
137 static_assert(sizeof(K
) == 16);
139 // CHECK:*** Dumping AST Record Layout
140 // CHECK: 0 | struct Empty::K
141 // CHECK-NEXT: 0 | struct Empty::A4 a (empty)
142 // CHECK-NEXT: 0 | char c
143 // CHECK-NEXT: 8 | struct Empty::A4 b (empty)
144 // CHECK-NEXT: | [sizeof=16, align=8,
145 // CHECK-NEXT: | nvsize=16, nvalign=8]
147 struct OversizedEmpty
: A
{
149 [[msvc::no_unique_address
]] A a
;
151 static_assert(sizeof(OversizedEmpty
) == 1);
153 // CHECK:*** Dumping AST Record Layout
154 // CHECK: 0 | struct Empty::OversizedEmpty
155 // CHECK-NEXT: 0 | struct Empty::A (base) (empty)
156 // CHECK-NEXT: 0 | struct Empty::A a (empty)
157 // CHECK-NEXT: | [sizeof=1, align=1,
158 // CHECK-NEXT: | nvsize=1, nvalign=1]
160 struct HasOversizedEmpty
{
161 [[msvc::no_unique_address
]] OversizedEmpty m
;
163 static_assert(sizeof(HasOversizedEmpty
) == 1);
165 // CHECK:*** Dumping AST Record Layout
166 // CHECK: 0 | struct Empty::HasOversizedEmpty
167 // CHECK-NEXT: 0 | struct Empty::OversizedEmpty m (empty)
168 // CHECK-NEXT: 0 | struct Empty::A (base) (empty)
169 // CHECK-NEXT: 0 | struct Empty::A a (empty)
170 // CHECK-NEXT: | [sizeof=1, align=1,
171 // CHECK-NEXT: | nvsize=1, nvalign=1]
173 struct EmptyWithNonzeroDSize
{
174 [[msvc::no_unique_address
]] A a
;
176 [[msvc::no_unique_address
]] A b
;
178 [[msvc::no_unique_address
]] A c
;
180 static_assert(sizeof(EmptyWithNonzeroDSize
) == 8);
182 // CHECK:*** Dumping AST Record Layout
183 // CHECK: 0 | struct Empty::EmptyWithNonzeroDSize
184 // CHECK-NEXT: 0 | struct Empty::A a (empty)
185 // CHECK-NEXT: 0 | int x
186 // CHECK-NEXT: 1 | struct Empty::A b (empty)
187 // CHECK-NEXT: 4 | int y
188 // CHECK-NEXT: 2 | struct Empty::A c (empty)
189 // CHECK-NEXT: | [sizeof=8, align=4,
190 // CHECK-NEXT: | nvsize=8, nvalign=4]
192 struct EmptyWithNonzeroDSizeNonPOD
{
193 ~EmptyWithNonzeroDSizeNonPOD();
194 [[msvc::no_unique_address
]] A a
;
196 [[msvc::no_unique_address
]] A b
;
198 [[msvc::no_unique_address
]] A c
;
200 static_assert(sizeof(EmptyWithNonzeroDSizeNonPOD
) == 8);
202 // CHECK:*** Dumping AST Record Layout
203 // CHECK: 0 | struct Empty::EmptyWithNonzeroDSizeNonPOD
204 // CHECK-NEXT: 0 | struct Empty::A a (empty)
205 // CHECK-NEXT: 0 | int x
206 // CHECK-NEXT: 1 | struct Empty::A b (empty)
207 // CHECK-NEXT: 4 | int y
208 // CHECK-NEXT: 2 | struct Empty::A c (empty)
209 // CHECK-NEXT: | [sizeof=8, align=4,
210 // CHECK-NEXT: | nvsize=8, nvalign=4]
214 struct A
{ int n
; char c
[3]; };
215 struct B
{ [[msvc::no_unique_address
]] A a
; char d
; };
216 static_assert(sizeof(B
) == 12);
218 // CHECK:*** Dumping AST Record Layout
219 // CHECK: 0 | struct POD::B
220 // CHECK-NEXT: 0 | struct POD::A a
221 // CHECK-NEXT: 0 | int n
222 // CHECK-NEXT: 4 | char[3] c
223 // CHECK-NEXT: 8 | char d
224 // CHECK-NEXT: | [sizeof=12, align=4,
225 // CHECK-NEXT: | nvsize=12, nvalign=4]
229 struct A
{ int n
; char c
[3]; ~A(); };
230 struct B
{ [[msvc::no_unique_address
]] A a
; char d
; };
231 static_assert(sizeof(B
) == 12);
233 // CHECK:*** Dumping AST Record Layout
234 // CHECK: 0 | struct NonPOD::B
235 // CHECK-NEXT: 0 | struct NonPOD::A a
236 // CHECK-NEXT: 0 | int n
237 // CHECK-NEXT: 4 | char[3] c
238 // CHECK-NEXT: 8 | char d
239 // CHECK-NEXT: | [sizeof=12, align=4,
240 // CHECK-NEXT: | nvsize=12, nvalign=4]
244 // The nvsize of an object includes the complete size of its empty subobjects
245 // (although it's unclear why). Ensure this corner case is handled properly.
247 struct alignas(8) A
{}; // dsize 0, nvsize 0, size 8
248 struct B
: A
{ char c
; }; // dsize 1, nvsize 8, size 8
249 static_assert(sizeof(B
) == 8);
251 // CHECK:*** Dumping AST Record Layout
252 // CHECK: 0 | struct VBases::B
253 // CHECK-NEXT: 0 | struct VBases::A (base) (empty)
254 // CHECK-NEXT: 0 | char c
255 // CHECK-NEXT: | [sizeof=8, align=8,
256 // CHECK-NEXT: | nvsize=8, nvalign=8]
260 struct C
: B
, virtual V
{};
261 static_assert(sizeof(C
) == 24);
263 // CHECK:*** Dumping AST Record Layout
264 // CHECK: 0 | struct VBases::C
265 // CHECK-NEXT: 0 | struct VBases::B (base)
266 // CHECK-NEXT: 0 | struct VBases::A (base) (empty)
267 // CHECK-NEXT: 0 | char c
268 // CHECK-NEXT: 8 | (C vbtable pointer)
269 // CHECK-NEXT: 16 | struct VBases::V (virtual base)
270 // CHECK-NEXT: 16 | int n
271 // CHECK-NEXT: | [sizeof=24, align=8,
272 // CHECK-NEXT: | nvsize=16, nvalign=8]
274 struct D
: virtual Empty
{
275 [[msvc::no_unique_address
]] Empty a
;
277 static_assert(sizeof(D
) == 16);
279 // CHECK:*** Dumping AST Record Layout
280 // CHECK: 0 | struct VBases::D
281 // CHECK-NEXT: 0 | (D vbtable pointer)
282 // CHECK-NEXT: 8 | struct VBases::Empty a
283 // CHECK-NEXT: 16 | struct VBases::Empty (virtual base) (empty)
284 // CHECK-NEXT: | [sizeof=16, align=8,
285 // CHECK-NEXT: | nvsize=16, nvalign=8]
287 struct E
: virtual V
{
288 [[msvc::no_unique_address
]] B b
;
290 static_assert(sizeof(E
) == 24);
292 // CHECK:*** Dumping AST Record Layout
293 // CHECK: 0 | struct VBases::E
294 // CHECK-NEXT: 0 | (E vbtable pointer)
295 // CHECK-NEXT: 8 | struct VBases::B b
296 // CHECK-NEXT: 8 | struct VBases::A (base) (empty)
297 // CHECK-NEXT: 8 | char c
298 // CHECK-NEXT: 16 | struct VBases::V (virtual base)
299 // CHECK-NEXT: 16 | int n
300 // CHECK-NEXT: | [sizeof=24, align=8,
301 // CHECK-NEXT: | nvsize=16, nvalign=8]
303 struct X
: virtual A
{ [[msvc::no_unique_address
]] A a
; };
304 struct F
: virtual A
{
305 [[msvc::no_unique_address
]] A a
;
306 [[msvc::no_unique_address
]] X x
;
308 static_assert(sizeof(F
) == 24);
310 // MSVC places x after a and the total size is 48.
311 // CHECK:*** Dumping AST Record Layout
312 // CHECK: 0 | struct VBases::F
313 // CHECK-NEXT: 0 | (F vbtable pointer)
314 // CHECK-NEXT: 8 | struct VBases::A a (empty)
315 // CHECK-NEXT: 8 | struct VBases::X x
316 // CHECK-NEXT: 8 | (X vbtable pointer)
317 // CHECK-NEXT: 16 | struct VBases::A a (empty)
318 // CHECK-NEXT: 24 | struct VBases::A (virtual base) (empty)
319 // CHECK-NEXT: 24 | struct VBases::A (virtual base) (empty)
320 // CHECK-NEXT: | [sizeof=24, align=8,
321 // CHECK-NEXT: | nvsize=24, nvalign=8]
323 struct G
: virtual Empty
{
325 [[msvc::no_unique_address
]] A a
;
327 static_assert(sizeof(G
) == 16);
329 // MSVC places a at offset 12.
330 // CHECK:*** Dumping AST Record Layout
331 // CHECK: 0 | struct VBases::G
332 // CHECK-NEXT: 0 | (G vbtable pointer)
333 // CHECK-NEXT: 8 | int i
334 // CHECK-NEXT: 8 | struct VBases::A a (empty)
335 // CHECK-NEXT: 16 | struct VBases::Empty (virtual base) (empty)
336 // CHECK-NEXT: | [sizeof=16, align=8,
337 // CHECK-NEXT: | nvsize=16, nvalign=8]
343 union empty_union
{};
345 struct empty_union_container
{
346 [[msvc::no_unique_address
]] empty_union x
;
349 union union_of_empty
{
350 [[msvc::no_unique_address
]] empty x
;
353 struct struct_of_empty
{
354 [[msvc::no_unique_address
]] empty x
;
357 struct union_of_empty_container
{
358 [[msvc::no_unique_address
]] union_of_empty x
;
360 static_assert(sizeof(union_of_empty_container
) == 1);
361 // CHECK:*** Dumping AST Record Layout
362 // CHECK: 0 | struct ZeroSize::union_of_empty_container
363 // CHECK-NOT: (empty)
364 // CHECK: 0 | union ZeroSize::union_of_empty x (empty)
365 // CHECK: 0 | struct ZeroSize::empty x (empty)
366 // CHECK: | [sizeof=1, align=1,
367 // CHECK: | nvsize=1, nvalign=1]
369 struct struct_of_empty_container
{
370 [[msvc::no_unique_address
]] struct_of_empty x
;
372 static_assert(sizeof(struct_of_empty_container
) == 1);
373 // CHECK:*** Dumping AST Record Layout
374 // CHECK: 0 | struct ZeroSize::struct_of_empty_container
375 // CHECK-NOT: (empty)
376 // CHECK: 0 | struct ZeroSize::struct_of_empty x (empty)
377 // CHECK: 0 | struct ZeroSize::empty x (empty)
378 // CHECK: | [sizeof=1, align=1,
379 // CHECK: | nvsize=1, nvalign=1]