xref: /llvm-project/clang/test/Layout/ms-no-unique-address.cpp (revision 0faee97a924adec76d5c7cd680c289ced51e6b5a)
1 // RUN: %clang_cc1 -std=c++2a -fsyntax-only -triple x86_64-windows-msvc -fms-compatibility -fdump-record-layouts %s | FileCheck %s
2 
3 namespace Empty {
4   struct A {};
5   struct A2 {};
6   struct A3 { [[msvc::no_unique_address]] A a; };
7   struct alignas(8) A4 {};
8 
9   struct B {
10     [[msvc::no_unique_address]] A a;
11     char b;
12   };
13   static_assert(sizeof(B) == 1);
14 
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]
21 
22   struct C {
23     [[msvc::no_unique_address]] A a;
24     [[msvc::no_unique_address]] A2 a2;
25     char c;
26   };
27   static_assert(sizeof(C) == 1);
28 
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]
36 
37   struct D {
38     [[msvc::no_unique_address]] A3 a;
39     int i;
40   };
41   static_assert(sizeof(D) == 8);
42 
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]
50 
51   struct E {
52     [[msvc::no_unique_address]] A a1;
53     [[msvc::no_unique_address]] A a2;
54     char e;
55   };
56   static_assert(sizeof(E) == 2);
57 
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]
65 
66   struct F {
67     ~F();
68     [[msvc::no_unique_address]] A a1;
69     [[msvc::no_unique_address]] A a2;
70     char f;
71   };
72   static_assert(sizeof(F) == 2);
73 
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]
81 
82   struct G { [[msvc::no_unique_address]] A a; ~G(); };
83   static_assert(sizeof(G) == 1);
84 
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]
90 
91   struct H {
92     [[msvc::no_unique_address]] A a;
93     [[msvc::no_unique_address]] A b;
94     ~H();
95   };
96   static_assert(sizeof(H) == 2);
97 
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]
104 
105   struct I {
106     [[msvc::no_unique_address]] A4 a;
107     [[msvc::no_unique_address]] A4 b;
108   };
109   static_assert(sizeof(I) == 16);
110 
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]
117 
118   struct J {
119     [[msvc::no_unique_address]] A4 a;
120     A4 b;
121   };
122   static_assert(sizeof(J) == 16);
123 
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]
131 
132   struct K {
133     [[msvc::no_unique_address]] A4 a;
134     [[msvc::no_unique_address]] char c;
135     [[msvc::no_unique_address]] A4 b;
136   };
137   static_assert(sizeof(K) == 16);
138 
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]
146 
147   struct OversizedEmpty : A {
148     ~OversizedEmpty();
149     [[msvc::no_unique_address]] A a;
150   };
151   static_assert(sizeof(OversizedEmpty) == 1);
152 
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]
159 
160   struct HasOversizedEmpty {
161     [[msvc::no_unique_address]] OversizedEmpty m;
162   };
163   static_assert(sizeof(HasOversizedEmpty) == 1);
164 
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]
172 
173   struct EmptyWithNonzeroDSize {
174     [[msvc::no_unique_address]] A a;
175     int x;
176     [[msvc::no_unique_address]] A b;
177     int y;
178     [[msvc::no_unique_address]] A c;
179   };
180   static_assert(sizeof(EmptyWithNonzeroDSize) == 8);
181 
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]
191 
192   struct EmptyWithNonzeroDSizeNonPOD {
193     ~EmptyWithNonzeroDSizeNonPOD();
194     [[msvc::no_unique_address]] A a;
195     int x;
196     [[msvc::no_unique_address]] A b;
197     int y;
198     [[msvc::no_unique_address]] A c;
199   };
200   static_assert(sizeof(EmptyWithNonzeroDSizeNonPOD) == 8);
201 
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]
211 }
212 
213 namespace POD {
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);
217 
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]
226 }
227 
228 namespace NonPOD {
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);
232 
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]
241 }
242 
243 namespace VBases {
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.
246   struct Empty {};
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);
250 
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]
257 
258   struct V { int n; };
259 
260   struct C : B, virtual V {};
261   static_assert(sizeof(C) == 24);
262 
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]
273 
274   struct D : virtual Empty {
275     [[msvc::no_unique_address]] Empty a;
276   };
277   static_assert(sizeof(D) == 16);
278 
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]
286 
287   struct E : virtual V {
288     [[msvc::no_unique_address]] B b;
289   };
290   static_assert(sizeof(E) == 24);
291 
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]
302 
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;
307   };
308   static_assert(sizeof(F) == 24);
309 
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]
322 
323   struct G : virtual Empty {
324     int i;
325     [[msvc::no_unique_address]] A a;
326   };
327   static_assert(sizeof(G) == 16);
328 
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]
338 }
339 
340 namespace ZeroSize {
341   struct empty {};
342 
343   union empty_union {};
344 
345   struct empty_union_container {
346     [[msvc::no_unique_address]] empty_union x;
347   };
348 
349   union union_of_empty {
350     [[msvc::no_unique_address]] empty x;
351   };
352 
353   struct struct_of_empty {
354     [[msvc::no_unique_address]] empty x;
355   };
356 
357   struct union_of_empty_container {
358     [[msvc::no_unique_address]] union_of_empty x;
359   };
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]
368 
369   struct struct_of_empty_container {
370     [[msvc::no_unique_address]] struct_of_empty x;
371   };
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]
380 
381 }
382