xref: /llvm-project/clang/test/Layout/no-unique-address.cpp (revision aee49255074fd4ef38d97e6e70cbfbf2f9fd0fa7)
1 // RUN: %clang_cc1 -std=c++2a -fsyntax-only -triple x86_64-linux-gnu -fdump-record-layouts %s | FileCheck %s
2 
3 namespace Empty {
4   struct A {};
5   struct B { [[no_unique_address]] A a; char b; };
6   static_assert(sizeof(B) == 1);
7 
8   // CHECK:*** Dumping AST Record Layout
9   // CHECK:          0 | struct Empty::B
10   // CHECK-NEXT:     0 |   struct Empty::A a (empty)
11   // CHECK-NEXT:     0 |   char b
12   // CHECK-NEXT:       | [sizeof=1, dsize=1, align=1,
13   // CHECK-NEXT:       |  nvsize=1, nvalign=1]
14 
15   struct C {};
16   struct D {
17     [[no_unique_address]] A a;
18     [[no_unique_address]] C c;
19     char d;
20   };
21   static_assert(sizeof(D) == 1);
22 
23   // CHECK:*** Dumping AST Record Layout
24   // CHECK:          0 | struct Empty::D
25   // CHECK-NEXT:     0 |   struct Empty::A a (empty)
26   // CHECK-NEXT:     0 |   struct Empty::C c (empty)
27   // CHECK-NEXT:     0 |   char d
28   // CHECK-NEXT:       | [sizeof=1, dsize=1, align=1,
29   // CHECK-NEXT:       |  nvsize=1, nvalign=1]
30 
31   struct E {
32     [[no_unique_address]] A a1;
33     [[no_unique_address]] A a2;
34     char e;
35   };
36   static_assert(sizeof(E) == 2);
37 
38   // CHECK:*** Dumping AST Record Layout
39   // CHECK:          0 | struct Empty::E
40   // CHECK-NEXT:     0 |   struct Empty::A a1 (empty)
41   // CHECK-NEXT:     1 |   struct Empty::A a2 (empty)
42   // CHECK-NEXT:     0 |   char e
43   // CHECK-NEXT:       | [sizeof=2, dsize=2, align=1,
44   // CHECK-NEXT:       |  nvsize=2, nvalign=1]
45 
46   struct F {
47     ~F();
48     [[no_unique_address]] A a1;
49     [[no_unique_address]] A a2;
50     char f;
51   };
52   static_assert(sizeof(F) == 2);
53 
54   // CHECK:*** Dumping AST Record Layout
55   // CHECK:          0 | struct Empty::F
56   // CHECK-NEXT:     0 |   struct Empty::A a1 (empty)
57   // CHECK-NEXT:     1 |   struct Empty::A a2 (empty)
58   // CHECK-NEXT:     0 |   char f
59   // CHECK-NEXT:       | [sizeof=2, dsize=1, align=1,
60   // CHECK-NEXT:       |  nvsize=2, nvalign=1]
61 
62   struct G { [[no_unique_address]] A a; ~G(); };
63   static_assert(sizeof(G) == 1);
64 
65   // CHECK:*** Dumping AST Record Layout
66   // CHECK:          0 | struct Empty::G
67   // CHECK-NEXT:     0 |   struct Empty::A a (empty)
68   // CHECK-NEXT:       | [sizeof=1, dsize=0, align=1,
69   // CHECK-NEXT:       |  nvsize=1, nvalign=1]
70 
71   struct H { [[no_unique_address]] A a, b; ~H(); };
72   static_assert(sizeof(H) == 2);
73 
74   // CHECK:*** Dumping AST Record Layout
75   // CHECK:          0 | struct Empty::H
76   // CHECK-NEXT:     0 |   struct Empty::A a (empty)
77   // CHECK-NEXT:     1 |   struct Empty::A b (empty)
78   // CHECK-NEXT:       | [sizeof=2, dsize=0, align=1,
79   // CHECK-NEXT:       |  nvsize=2, nvalign=1]
80 
81   struct OversizedEmpty : A {
82     ~OversizedEmpty();
83     [[no_unique_address]] A a;
84   };
85   static_assert(sizeof(OversizedEmpty) == 2);
86 
87   // CHECK:*** Dumping AST Record Layout
88   // CHECK:          0 | struct Empty::OversizedEmpty
89   // CHECK-NEXT:     0 |   struct Empty::A (base) (empty)
90   // CHECK-NEXT:     1 |   struct Empty::A a (empty)
91   // CHECK-NEXT:       | [sizeof=2, dsize=0, align=1,
92   // CHECK-NEXT:       |  nvsize=2, nvalign=1]
93 
94   struct HasOversizedEmpty {
95     [[no_unique_address]] OversizedEmpty m;
96   };
97   static_assert(sizeof(HasOversizedEmpty) == 2);
98 
99   // CHECK:*** Dumping AST Record Layout
100   // CHECK:          0 | struct Empty::HasOversizedEmpty
101   // CHECK-NEXT:     0 |   struct Empty::OversizedEmpty m (empty)
102   // CHECK-NEXT:     0 |     struct Empty::A (base) (empty)
103   // CHECK-NEXT:     1 |     struct Empty::A a (empty)
104   // CHECK-NEXT:       | [sizeof=2, dsize=0, align=1,
105   // CHECK-NEXT:       |  nvsize=2, nvalign=1]
106 
107   struct EmptyWithNonzeroDSize {
108     [[no_unique_address]] A a;
109     int x;
110     [[no_unique_address]] A b;
111     int y;
112     [[no_unique_address]] A c;
113   };
114   static_assert(sizeof(EmptyWithNonzeroDSize) == 12);
115 
116   // CHECK:*** Dumping AST Record Layout
117   // CHECK:          0 | struct Empty::EmptyWithNonzeroDSize
118   // CHECK-NEXT:     0 |   struct Empty::A a (empty)
119   // CHECK-NEXT:     0 |   int x
120   // CHECK-NEXT:     4 |   struct Empty::A b (empty)
121   // CHECK-NEXT:     4 |   int y
122   // CHECK-NEXT:     8 |   struct Empty::A c (empty)
123   // CHECK-NEXT:       | [sizeof=12, dsize=12, align=4,
124   // CHECK-NEXT:       |  nvsize=12, nvalign=4]
125 
126   struct EmptyWithNonzeroDSizeNonPOD {
127     ~EmptyWithNonzeroDSizeNonPOD();
128     [[no_unique_address]] A a;
129     int x;
130     [[no_unique_address]] A b;
131     int y;
132     [[no_unique_address]] A c;
133   };
134   static_assert(sizeof(EmptyWithNonzeroDSizeNonPOD) == 12);
135 
136   // CHECK:*** Dumping AST Record Layout
137   // CHECK:          0 | struct Empty::EmptyWithNonzeroDSizeNonPOD
138   // CHECK-NEXT:     0 |   struct Empty::A a (empty)
139   // CHECK-NEXT:     0 |   int x
140   // CHECK-NEXT:     4 |   struct Empty::A b (empty)
141   // CHECK-NEXT:     4 |   int y
142   // CHECK-NEXT:     8 |   struct Empty::A c (empty)
143   // CHECK-NEXT:       | [sizeof=12, dsize=8, align=4,
144   // CHECK-NEXT:       |  nvsize=9, nvalign=4]
145 }
146 
147 namespace POD {
148   // Cannot reuse tail padding of a PDO type.
149   struct A { int n; char c[3]; };
150   struct B { [[no_unique_address]] A a; char d; };
151   static_assert(sizeof(B) == 12);
152 
153   // CHECK:*** Dumping AST Record Layout
154   // CHECK:          0 | struct POD::B
155   // CHECK-NEXT:     0 |   struct POD::A a
156   // CHECK-NEXT:     0 |     int n
157   // CHECK-NEXT:     4 |     char[3] c
158   // CHECK-NEXT:     8 |   char d
159   // CHECK-NEXT:       | [sizeof=12, dsize=12, align=4,
160   // CHECK-NEXT:       |  nvsize=12, nvalign=4]
161 }
162 
163 namespace NonPOD {
164   struct A { int n; char c[3]; ~A(); };
165   struct B { [[no_unique_address]] A a; char d; };
166   static_assert(sizeof(B) == 8);
167 
168   // CHECK:*** Dumping AST Record Layout
169   // CHECK:          0 | struct NonPOD::B
170   // CHECK-NEXT:     0 |   struct NonPOD::A a
171   // CHECK-NEXT:     0 |     int n
172   // CHECK-NEXT:     4 |     char[3] c
173   // CHECK-NEXT:     7 |   char d
174   // CHECK-NEXT:       | [sizeof=8, dsize=8, align=4,
175   // CHECK-NEXT:       |  nvsize=8, nvalign=4]
176 }
177 
178 namespace NVSizeGreaterThanDSize {
179   // The nvsize of an object includes the complete size of its empty subobjects
180   // (although it's unclear why). Ensure this corner case is handled properly.
181   struct alignas(8) A { ~A(); }; // dsize 0, nvsize 0, size 8
182   struct B : A { char c; }; // dsize 1, nvsize 8, size 8
183   static_assert(sizeof(B) == 8);
184 
185   // CHECK:*** Dumping AST Record Layout
186   // CHECK:          0 | struct NVSizeGreaterThanDSize::B
187   // CHECK-NEXT:     0 |   struct NVSizeGreaterThanDSize::A (base) (empty)
188   // CHECK-NEXT:     0 |   char c
189   // CHECK-NEXT:       | [sizeof=8, dsize=1, align=8,
190   // CHECK-NEXT:       |  nvsize=8, nvalign=8]
191 
192   struct V { int n; };
193 
194   // V is at offset 16, not offset 12, because B's tail padding is strangely not
195   // usable for virtual bases.
196   struct C : B, virtual V {};
197   static_assert(sizeof(C) == 24);
198 
199   // CHECK:*** Dumping AST Record Layout
200   // CHECK:          0 | struct NVSizeGreaterThanDSize::C
201   // CHECK-NEXT:     0 |   (C vtable pointer)
202   // CHECK-NEXT:     8 |   struct NVSizeGreaterThanDSize::B (base)
203   // CHECK-NEXT:     8 |     struct NVSizeGreaterThanDSize::A (base) (empty)
204   // CHECK-NEXT:     8 |     char c
205   // CHECK-NEXT:    16 |   struct NVSizeGreaterThanDSize::V (virtual base)
206   // CHECK-NEXT:    16 |     int n
207   // CHECK-NEXT:       | [sizeof=24, dsize=20, align=8,
208   // CHECK-NEXT:       |  nvsize=16, nvalign=8]
209 
210   struct D : virtual V {
211     [[no_unique_address]] B b;
212   };
213   static_assert(sizeof(D) == 24);
214 
215   // CHECK:*** Dumping AST Record Layout
216   // CHECK:          0 | struct NVSizeGreaterThanDSize::D
217   // CHECK-NEXT:     0 |   (D vtable pointer)
218   // CHECK-NEXT:     8 |   struct NVSizeGreaterThanDSize::B b
219   // CHECK-NEXT:     8 |     struct NVSizeGreaterThanDSize::A (base) (empty)
220   // CHECK-NEXT:     8 |     char c
221   // CHECK-NEXT:    16 |   struct NVSizeGreaterThanDSize::V (virtual base)
222   // CHECK-NEXT:    16 |     int n
223   // CHECK-NEXT:       | [sizeof=24, dsize=20, align=8,
224   // CHECK-NEXT:       |  nvsize=16, nvalign=8]
225 
226   struct X : virtual A { [[no_unique_address]] A a; };
227   struct E : virtual A {
228     [[no_unique_address]] A a;
229     // Here, we arrange for X to hang over the end of the nvsize of E. This
230     // should force the A vbase to be laid out at offset 24, not 16.
231     [[no_unique_address]] X x;
232   };
233   static_assert(sizeof(E) == 32);
234 
235   // CHECK:*** Dumping AST Record Layout
236   // CHECK:          0 | struct NVSizeGreaterThanDSize::E
237   // CHECK-NEXT:     0 |   (E vtable pointer)
238   // CHECK-NEXT:     0 |   struct NVSizeGreaterThanDSize::A a (empty)
239   // CHECK-NEXT:     8 |   struct NVSizeGreaterThanDSize::X x
240   // CHECK-NEXT:     8 |     (X vtable pointer)
241   // CHECK-NEXT:     8 |     struct NVSizeGreaterThanDSize::A a (empty)
242   // CHECK-NEXT:    16 |     struct NVSizeGreaterThanDSize::A (virtual base) (empty)
243   // CHECK-NEXT:    24 |   struct NVSizeGreaterThanDSize::A (virtual base) (empty)
244   // CHECK-NEXT:       | [sizeof=32, dsize=16, align=8,
245   // CHECK-NEXT:       |  nvsize=16, nvalign=8]
246 }
247 
248 namespace RepeatedVBase {
249   struct alignas(16) A { ~A(); };
250   struct B : A {};
251   struct X : virtual A, virtual B {};
252   struct Y { [[no_unique_address]] X x; char c; };
253   static_assert(sizeof(Y) == 32);
254 
255   // CHECK:*** Dumping AST Record Layout
256   // CHECK:          0 | struct RepeatedVBase::Y
257   // CHECK-NEXT:     0 |   struct RepeatedVBase::X x
258   // CHECK-NEXT:     0 |     (X vtable pointer)
259   // CHECK-NEXT:     0 |     struct RepeatedVBase::A (virtual base) (empty)
260   // CHECK-NEXT:    16 |     struct RepeatedVBase::B (virtual base) (empty)
261   // CHECK-NEXT:    16 |       struct RepeatedVBase::A (base) (empty)
262   // CHECK-NEXT:     8 |     char c
263   // CHECK-NEXT:       | [sizeof=32, dsize=9, align=16,
264   // CHECK-NEXT:       |  nvsize=9, nvalign=16]
265 }
266