xref: /llvm-project/clang/test/AST/ByteCode/unions.cpp (revision ac857f9bdd500d274d7996e0fa14aaf8b765d745)
1 // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=expected,both %s
2 // RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter -verify=expected,both %s
3 // RUN: %clang_cc1 -verify=ref,both %s
4 // RUN: %clang_cc1 -std=c++20 -verify=ref,both %s
5 
6 union U {
7   int a;
8   int b;
9 };
10 
11 constexpr U a = {12};
12 static_assert(a.a == 12, "");
13 static_assert(a.b == 0, ""); // both-error {{not an integral constant expression}} \
14                              // both-note {{read of member 'b' of union with active member 'a'}}
15 union U1 {
16   int i;
17   float f = 3.0f;
18 };
19 constexpr U1 u1{};
20 static_assert(u1.f == 3.0, "");
21 static_assert(u1.i == 1, ""); // both-error {{not an integral constant expression}} \
22                               // both-note {{read of member 'i' of union with active member 'f'}}
23 
24 
25 
26 union A {
27   int a;
28   double d;
29 };
30 constexpr A aa = {1, 2.0}; // both-error {{excess elements in union initializer}}
31 constexpr A ab = {.d = 1.0};
32 static_assert(ab.d == 1.0, "");
33 static_assert(ab.a == 1, ""); // both-error {{not an integral constant expression}} \
34                               // both-note {{read of member 'a' of union with active member 'd'}}
35 
36 
37 namespace Empty {
38   union E {};
39   constexpr E e{};
40 }
41 
42 namespace SimpleStore {
43   union A {
44     int a;
45     int b;
46   };
47   constexpr int foo() {
48     A a{.b = 4};
49     a.b = 10;
50     return a.b;
51   }
52   static_assert(foo() == 10, "");
53 
54   constexpr int empty() {
55     A a{}; /// Just test that this works.
56     return 10;
57   }
58   static_assert(empty() == 10, "");
59 }
60 
61 namespace ZeroInit {
62   struct S { int m; };
63   union Z {
64     float f;
65   };
66 
67   constexpr Z z{};
68   static_assert(z.f == 0.0, "");
69 }
70 
71 namespace DefaultInit {
72   union U1 {
73     constexpr U1() {}
74     int a, b = 42;
75   };
76 
77   constexpr U1 u1; /// OK.
78 
79   constexpr int foo() {
80     U1 u;
81     return u.a; // both-note {{read of member 'a' of union with active member 'b'}}
82   }
83   static_assert(foo() == 42); // both-error {{not an integral constant expression}} \
84                               // both-note {{in call to}}
85 }
86 
87 #if __cplusplus >= 202002L
88 namespace SimpleActivate {
89   constexpr int foo() { // both-error {{never produces a constant expression}}
90     union {
91       int a;
92       int b;
93     } Z;
94 
95     Z.a = 10;
96     Z.b = 20;
97     return Z.a; // both-note 2{{read of member 'a' of union with active member 'b'}}
98   }
99   static_assert(foo() == 20); // both-error {{not an integral constant expression}} \
100                               // both-note {{in call to}}
101 
102   constexpr int foo2() {
103     union {
104       int a;
105       int b;
106     } Z;
107 
108     Z.a = 10;
109     Z.b = 20;
110     return Z.b;
111   }
112   static_assert(foo2() == 20);
113 
114 
115   constexpr int foo3() {
116     union {
117       struct {
118         float x,y;
119       } a;
120       int b;
121     } Z;
122 
123     Z.a.y = 10;
124 
125     return Z.a.x; // both-note {{read of uninitialized object}}
126   }
127   static_assert(foo3() == 10); // both-error {{not an integral constant expression}} \
128                                // both-note {{in call to}}
129 
130   constexpr int foo4() {
131     union {
132       struct {
133         float x,y;
134       } a;
135       int b;
136     } Z;
137 
138     Z.a.x = 100;
139     Z.a.y = 10;
140 
141     return Z.a.x;
142   }
143   static_assert(foo4() == 100);
144 }
145 
146 namespace IndirectFieldDecl {
147   struct C {
148     union { int a, b = 2, c; };
149     union { int d, e = 5, f; };
150     constexpr C() : a(1) {}
151   };
152   static_assert(C().a == 1, "");
153 }
154 
155 namespace UnionDtor {
156 
157   union U {
158     int *I;
159     constexpr U(int *I) : I(I) {}
160     constexpr ~U() {
161       *I = 10;
162     }
163   };
164 
165   constexpr int foo() {
166     int a = 100;
167     {
168       U u(&a);
169     }
170     return a;
171   }
172   static_assert(foo() == 10);
173 }
174 
175 namespace UnionMemberDtor {
176   class UM {
177   public:
178     int &I;
179     constexpr UM(int &I) : I(I) {}
180     constexpr ~UM() { I = 200; }
181   };
182 
183   union U {
184     UM um;
185     constexpr U(int &I) : um(I) {}
186     constexpr ~U() {
187     }
188   };
189 
190   constexpr int foo() {
191     int a = 100;
192     {
193       U u(a);
194     }
195 
196     return a;
197   }
198   static_assert(foo() == 100);
199 }
200 
201 namespace Nested {
202   union U {
203     int a;
204     int b;
205   };
206 
207   union U2 {
208     U u;
209     U u2;
210     int x;
211     int y;
212   };
213 
214  constexpr int foo() { // both-error {{constexpr function never produces a constant expression}}
215     U2 u;
216     u.u.a = 10;
217     int a = u.y; // both-note 2{{read of member 'y' of union with active member 'u' is not allowed in a constant expression}}
218 
219     return 1;
220   }
221   static_assert(foo() == 1); // both-error {{not an integral constant expression}} \
222                              // both-note {{in call to}}
223 
224  constexpr int foo2() {
225     U2 u;
226     u.u.a = 10;
227     return u.u.a;
228   }
229   static_assert(foo2() == 10);
230 
231  constexpr int foo3() { // both-error {{constexpr function never produces a constant expression}}
232     U2 u;
233     u.u.a = 10;
234     int a = u.u.b; // both-note 2{{read of member 'b' of union with active member 'a' is not allowed in a constant expression}}
235 
236     return 1;
237   }
238   static_assert(foo3() == 1); // both-error {{not an integral constant expression}} \
239                               // both-note {{in call to}}
240 
241   constexpr int foo4() { // both-error {{constexpr function never produces a constant expression}}
242     U2 u;
243 
244     u.x = 10;
245 
246     return u.u.a; // both-note 2{{read of member 'u' of union with active member 'x' is not allowed in a constant expression}}
247   }
248   static_assert(foo4() == 1); // both-error {{not an integral constant expression}} \
249                               // both-note {{in call to}}
250 
251 }
252 
253 
254 namespace Zeroing {
255   struct non_trivial_constructor {
256       constexpr non_trivial_constructor() : x(100) {}
257       int x;
258   };
259   union U2 {
260       int a{1000};
261       non_trivial_constructor b;
262   };
263 
264   static_assert(U2().b.x == 100, ""); // both-error {{not an integral constant expression}} \
265                                       // both-note {{read of member 'b' of union with active member 'a'}}
266 
267   union { int a; int b; } constexpr u1{};
268   static_assert(u1.a == 0, "");
269   static_assert(u1.b == 0, ""); // both-error {{not an integral constant expression}} \
270                                 // both-note {{read of member 'b' of union with active member 'a'}}
271 
272   union U { int a; int b; } constexpr u2 = U();
273   static_assert(u2.a == 0, "");
274   static_assert(u2.b == 0, ""); // both-error {{not an integral constant expression}} \
275                                 // both-note {{read of member 'b' of union with active member 'a'}}
276 
277 
278   struct F {int x; int y; };
279   union { F a; int b; } constexpr u3{};
280   static_assert(u3.a.x == 0, "");
281 
282   union U4 { F a; int b; } constexpr u4 = U4();
283   static_assert(u4.a.x == 0, "");
284 
285   union { int a[5]; int b; } constexpr u5{};
286   static_assert(u5.a[0] == 0, "");
287   static_assert(u5.a[4] == 0, "");
288   static_assert(u5.b == 0, ""); // both-error {{not an integral constant expression}} \
289                                 // both-note {{read of member 'b' of union with active member 'a'}}
290 
291   union U6 { int a[5]; int b; } constexpr u6 = U6();
292   static_assert(u6.a[0] == 0, "");
293   static_assert(u6.a[4] == 0, "");
294   static_assert(u6.b == 0, ""); // both-error {{not an integral constant expression}} \
295                                 // both-note {{read of member 'b' of union with active member 'a'}}
296 
297   union UnionWithUnnamedBitfield {
298     int : 3;
299     int n;
300   };
301   static_assert(UnionWithUnnamedBitfield().n == 0, "");
302   static_assert(UnionWithUnnamedBitfield{}.n == 0, "");
303   static_assert(UnionWithUnnamedBitfield{1}.n == 1, "");
304 }
305 
306 namespace IndirectField {
307   struct S {
308     struct {
309       union {
310         struct {
311           int a;
312           int b;
313         };
314         int c;
315       };
316       int d;
317     };
318     union {
319       int e;
320       int f;
321     };
322     constexpr S(int a, int b, int d, int e) : a(a), b(b), d(d), e(e) {}
323     constexpr S(int c, int d, int f) : c(c), d(d), f(f) {}
324   };
325 
326   constexpr S s1(1,2,3,4);
327   constexpr S s2(5, 6, 7);
328 
329   static_assert(s1.a == 1, "");
330   static_assert(s1.b == 2, "");
331 
332   static_assert(s1.c == 0, ""); // both-error {{constant expression}} both-note {{union with active member}}
333   static_assert(s1.d == 3, "");
334   static_assert(s1.e == 4, "");
335   static_assert(s1.f == 0, ""); // both-error {{constant expression}} both-note {{union with active member}}
336 
337   static_assert(s2.a == 0, ""); // both-error {{constant expression}} both-note {{union with active member}}
338   static_assert(s2.b == 0, ""); // both-error {{constant expression}} both-note {{union with active member}}
339   static_assert(s2.c == 5, "");
340   static_assert(s2.d == 6, "");
341   static_assert(s2.e == 0, ""); // both-error {{constant expression}} both-note {{union with active member}}
342   static_assert(s2.f == 7, "");
343 }
344 
345 namespace CopyCtor {
346   union U {
347     int a;
348     int b;
349   };
350 
351   constexpr U x = {42};
352   constexpr U y = x;
353   static_assert(y.a == 42, "");
354   static_assert(y.b == 42, ""); // both-error {{constant expression}} \
355                                 // both-note {{'b' of union with active member 'a'}}
356 }
357 
358 namespace UnionInBase {
359   struct Base {
360     int y; // both-note {{subobject declared here}}
361   };
362   struct A : Base {
363     int x;
364     int arr[3];
365     union { int p, q; };
366   };
367   union B {
368     A a;
369     int b;
370   };
371   constexpr int read_wrong_member_indirect() { // both-error {{never produces a constant}}
372     B b = {.b = 1};
373     int *p = &b.a.y;
374     return *p; // both-note 2{{read of member 'a' of union with active member 'b'}}
375 
376   }
377   static_assert(read_wrong_member_indirect() == 1); // both-error {{not an integral constant expression}} \
378                                                     // both-note {{in call to}}
379   constexpr int read_uninitialized() {
380     B b = {.b = 1};
381     int *p = &b.a.y;
382     b.a.x = 1;
383     return *p; // both-note {{read of uninitialized object}}
384   }
385   static_assert(read_uninitialized() == 0); // both-error {{constant}} \
386                                             // both-note {{in call}}
387   constexpr int write_uninitialized() {
388     B b = {.b = 1};
389     int *p = &b.a.y;
390     b.a.x = 1;
391     *p = 1;
392     return *p;
393   }
394 
395   constexpr B return_uninit() {
396     B b = {.b = 1};
397     b.a.x = 2;
398     return b;
399   }
400   constexpr B uninit = return_uninit(); // both-error {{constant expression}} \
401                                         // both-note {{subobject 'y' is not initialized}}
402   static_assert(return_uninit().a.x == 2);
403 }
404 
405 /// FIXME: Our diagnostic here is a little off.
406 namespace One {
407   struct A { long x; };
408 
409   union U;
410   constexpr A foo(U *up);
411   union U {
412     A a = foo(this); // both-note {{in call to 'foo(&u)'}}
413     int y;
414   };
415 
416   constexpr A foo(U *up) {
417     return {up->y}; // both-note {{read of member 'y' of union}}
418   }
419 
420   constinit U u = {}; // both-error {{constant init}} \
421                       // both-note {{constinit}}
422 }
423 
424 #endif
425