// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=expected,both %s // RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter -verify=expected,both %s // RUN: %clang_cc1 -verify=ref,both %s // RUN: %clang_cc1 -std=c++20 -verify=ref,both %s union U { int a; int b; }; constexpr U a = {12}; static_assert(a.a == 12, ""); static_assert(a.b == 0, ""); // both-error {{not an integral constant expression}} \ // both-note {{read of member 'b' of union with active member 'a'}} union U1 { int i; float f = 3.0f; }; constexpr U1 u1{}; static_assert(u1.f == 3.0, ""); static_assert(u1.i == 1, ""); // both-error {{not an integral constant expression}} \ // both-note {{read of member 'i' of union with active member 'f'}} union A { int a; double d; }; constexpr A aa = {1, 2.0}; // both-error {{excess elements in union initializer}} constexpr A ab = {.d = 1.0}; static_assert(ab.d == 1.0, ""); static_assert(ab.a == 1, ""); // both-error {{not an integral constant expression}} \ // both-note {{read of member 'a' of union with active member 'd'}} namespace Empty { union E {}; constexpr E e{}; } namespace SimpleStore { union A { int a; int b; }; constexpr int foo() { A a{.b = 4}; a.b = 10; return a.b; } static_assert(foo() == 10, ""); constexpr int empty() { A a{}; /// Just test that this works. return 10; } static_assert(empty() == 10, ""); } namespace ZeroInit { struct S { int m; }; union Z { float f; }; constexpr Z z{}; static_assert(z.f == 0.0, ""); } namespace DefaultInit { union U1 { constexpr U1() {} int a, b = 42; }; constexpr U1 u1; /// OK. constexpr int foo() { U1 u; return u.a; // both-note {{read of member 'a' of union with active member 'b'}} } static_assert(foo() == 42); // both-error {{not an integral constant expression}} \ // both-note {{in call to}} } #if __cplusplus >= 202002L namespace SimpleActivate { constexpr int foo() { // both-error {{never produces a constant expression}} union { int a; int b; } Z; Z.a = 10; Z.b = 20; return Z.a; // both-note 2{{read of member 'a' of union with active member 'b'}} } static_assert(foo() == 20); // both-error {{not an integral constant expression}} \ // both-note {{in call to}} constexpr int foo2() { union { int a; int b; } Z; Z.a = 10; Z.b = 20; return Z.b; } static_assert(foo2() == 20); constexpr int foo3() { union { struct { float x,y; } a; int b; } Z; Z.a.y = 10; return Z.a.x; // both-note {{read of uninitialized object}} } static_assert(foo3() == 10); // both-error {{not an integral constant expression}} \ // both-note {{in call to}} constexpr int foo4() { union { struct { float x,y; } a; int b; } Z; Z.a.x = 100; Z.a.y = 10; return Z.a.x; } static_assert(foo4() == 100); } namespace IndirectFieldDecl { struct C { union { int a, b = 2, c; }; union { int d, e = 5, f; }; constexpr C() : a(1) {} }; static_assert(C().a == 1, ""); } namespace UnionDtor { union U { int *I; constexpr U(int *I) : I(I) {} constexpr ~U() { *I = 10; } }; constexpr int foo() { int a = 100; { U u(&a); } return a; } static_assert(foo() == 10); } namespace UnionMemberDtor { class UM { public: int &I; constexpr UM(int &I) : I(I) {} constexpr ~UM() { I = 200; } }; union U { UM um; constexpr U(int &I) : um(I) {} constexpr ~U() { } }; constexpr int foo() { int a = 100; { U u(a); } return a; } static_assert(foo() == 100); } namespace Nested { union U { int a; int b; }; union U2 { U u; U u2; int x; int y; }; constexpr int foo() { // both-error {{constexpr function never produces a constant expression}} U2 u; u.u.a = 10; int a = u.y; // both-note 2{{read of member 'y' of union with active member 'u' is not allowed in a constant expression}} return 1; } static_assert(foo() == 1); // both-error {{not an integral constant expression}} \ // both-note {{in call to}} constexpr int foo2() { U2 u; u.u.a = 10; return u.u.a; } static_assert(foo2() == 10); constexpr int foo3() { // both-error {{constexpr function never produces a constant expression}} U2 u; u.u.a = 10; 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}} return 1; } static_assert(foo3() == 1); // both-error {{not an integral constant expression}} \ // both-note {{in call to}} constexpr int foo4() { // both-error {{constexpr function never produces a constant expression}} U2 u; u.x = 10; return u.u.a; // both-note 2{{read of member 'u' of union with active member 'x' is not allowed in a constant expression}} } static_assert(foo4() == 1); // both-error {{not an integral constant expression}} \ // both-note {{in call to}} } namespace Zeroing { struct non_trivial_constructor { constexpr non_trivial_constructor() : x(100) {} int x; }; union U2 { int a{1000}; non_trivial_constructor b; }; static_assert(U2().b.x == 100, ""); // both-error {{not an integral constant expression}} \ // both-note {{read of member 'b' of union with active member 'a'}} union { int a; int b; } constexpr u1{}; static_assert(u1.a == 0, ""); static_assert(u1.b == 0, ""); // both-error {{not an integral constant expression}} \ // both-note {{read of member 'b' of union with active member 'a'}} union U { int a; int b; } constexpr u2 = U(); static_assert(u2.a == 0, ""); static_assert(u2.b == 0, ""); // both-error {{not an integral constant expression}} \ // both-note {{read of member 'b' of union with active member 'a'}} struct F {int x; int y; }; union { F a; int b; } constexpr u3{}; static_assert(u3.a.x == 0, ""); union U4 { F a; int b; } constexpr u4 = U4(); static_assert(u4.a.x == 0, ""); union { int a[5]; int b; } constexpr u5{}; static_assert(u5.a[0] == 0, ""); static_assert(u5.a[4] == 0, ""); static_assert(u5.b == 0, ""); // both-error {{not an integral constant expression}} \ // both-note {{read of member 'b' of union with active member 'a'}} union U6 { int a[5]; int b; } constexpr u6 = U6(); static_assert(u6.a[0] == 0, ""); static_assert(u6.a[4] == 0, ""); static_assert(u6.b == 0, ""); // both-error {{not an integral constant expression}} \ // both-note {{read of member 'b' of union with active member 'a'}} union UnionWithUnnamedBitfield { int : 3; int n; }; static_assert(UnionWithUnnamedBitfield().n == 0, ""); static_assert(UnionWithUnnamedBitfield{}.n == 0, ""); static_assert(UnionWithUnnamedBitfield{1}.n == 1, ""); } namespace IndirectField { struct S { struct { union { struct { int a; int b; }; int c; }; int d; }; union { int e; int f; }; constexpr S(int a, int b, int d, int e) : a(a), b(b), d(d), e(e) {} constexpr S(int c, int d, int f) : c(c), d(d), f(f) {} }; constexpr S s1(1,2,3,4); constexpr S s2(5, 6, 7); static_assert(s1.a == 1, ""); static_assert(s1.b == 2, ""); static_assert(s1.c == 0, ""); // both-error {{constant expression}} both-note {{union with active member}} static_assert(s1.d == 3, ""); static_assert(s1.e == 4, ""); static_assert(s1.f == 0, ""); // both-error {{constant expression}} both-note {{union with active member}} static_assert(s2.a == 0, ""); // both-error {{constant expression}} both-note {{union with active member}} static_assert(s2.b == 0, ""); // both-error {{constant expression}} both-note {{union with active member}} static_assert(s2.c == 5, ""); static_assert(s2.d == 6, ""); static_assert(s2.e == 0, ""); // both-error {{constant expression}} both-note {{union with active member}} static_assert(s2.f == 7, ""); } namespace CopyCtor { union U { int a; int b; }; constexpr U x = {42}; constexpr U y = x; static_assert(y.a == 42, ""); static_assert(y.b == 42, ""); // both-error {{constant expression}} \ // both-note {{'b' of union with active member 'a'}} } namespace UnionInBase { struct Base { int y; // both-note {{subobject declared here}} }; struct A : Base { int x; int arr[3]; union { int p, q; }; }; union B { A a; int b; }; constexpr int read_wrong_member_indirect() { // both-error {{never produces a constant}} B b = {.b = 1}; int *p = &b.a.y; return *p; // both-note 2{{read of member 'a' of union with active member 'b'}} } static_assert(read_wrong_member_indirect() == 1); // both-error {{not an integral constant expression}} \ // both-note {{in call to}} constexpr int read_uninitialized() { B b = {.b = 1}; int *p = &b.a.y; b.a.x = 1; return *p; // both-note {{read of uninitialized object}} } static_assert(read_uninitialized() == 0); // both-error {{constant}} \ // both-note {{in call}} constexpr int write_uninitialized() { B b = {.b = 1}; int *p = &b.a.y; b.a.x = 1; *p = 1; return *p; } constexpr B return_uninit() { B b = {.b = 1}; b.a.x = 2; return b; } constexpr B uninit = return_uninit(); // both-error {{constant expression}} \ // both-note {{subobject 'y' is not initialized}} static_assert(return_uninit().a.x == 2); } namespace One { struct A { long x; }; union U; constexpr A foo(U *up); union U { A a = foo(this); // both-note {{in call to 'foo(&u)'}} int y; }; constexpr A foo(U *up) { return {up->y}; // both-note {{read of member 'y' of union}} } constinit U u = {}; // both-error {{constant init}} \ // both-note {{constinit}} } namespace CopyAssign { union A { int a; int b; }; constexpr int f() { A a{12}; A b{13}; b.b = 32; b = a ; return b.a; } static_assert(f()== 12); constexpr int f2() { A a{12}; A b{13}; b.b = 32; b = a ; return b.b; // both-note {{read of member 'b' of union with active member 'a'}} } static_assert(f2() == 12); // both-error {{not an integral constant expression}} \ // both-note {{in call to}} } namespace MoveAssign { union A { int a; int b; }; constexpr int f() { A b{13}; b = A{12} ; return b.a; } static_assert(f()== 12); } namespace IFD { template struct Optional { struct { union { char null_state; T val; }; }; constexpr Optional() : null_state(){} }; constexpr bool test() { Optional opt{}; Optional opt2{}; opt = opt2; return true; } static_assert(test()); } namespace AnonymousUnion { struct A { int x; union { int p, q; }; }; union B { A a; int bb; }; constexpr B return_init_all() { B b = {.bb = 1}; b.a.x = 2; return b; } static_assert(return_init_all().a.p == 7); // both-error {{}} \ // both-note {{read of member 'p' of union with no active member}} } namespace MemberCalls { struct S { constexpr bool foo() const { return true; } }; constexpr bool foo() { // both-error {{never produces a constant expression}} union { int a; S s; } u; u.a = 10; return u.s.foo(); // both-note 2{{member call on member 's' of union with active member 'a'}} } static_assert(foo()); // both-error {{not an integral constant expression}} \ // both-note {{in call to}} } namespace InactiveDestroy { struct A { constexpr ~A() {} }; union U { A a; constexpr ~U() { } }; constexpr bool foo() { // both-error {{never produces a constant expression}} U u; u.a.~A(); // both-note 2{{destruction of member 'a' of union with no active member}} return true; } static_assert(foo()); // both-error {{not an integral constant expression}} \ // both-note {{in call to}} } namespace InactiveTrivialDestroy { struct A {}; union U { A a; }; constexpr bool foo() { // both-error {{never produces a constant expression}} U u; u.a.~A(); // both-note 2{{destruction of member 'a' of union with no active member}} return true; } static_assert(foo()); // both-error {{not an integral constant expression}} \ // both-note {{in call to}} } namespace ActiveDestroy { struct A {}; union U { A a; }; constexpr bool foo2() { U u{}; u.a.~A(); return true; } static_assert(foo2()); } namespace MoveOrAssignOp { struct min_pointer { int *ptr_; constexpr min_pointer(int *p) : ptr_(p) {} min_pointer() = default; }; class F { struct __long { min_pointer __data_; }; union __rep { int __s; __long __l; } __rep_; public: constexpr F() { __rep_ = __rep(); __rep_.__l.__data_ = nullptr; } }; constexpr bool foo() { F f{}; return true; } static_assert(foo()); } #endif namespace AddressComparison { union { int a; int c; } U; static_assert(__builtin_addressof(U.a) == (void*)__builtin_addressof(U.c)); static_assert(&U.a == &U.c); struct { union { struct { int a; int b; } a; struct { int b; int a; }b; } u; int b; } S; static_assert(&S.u.a.a == &S.u.b.b); static_assert(&S.u.a.b != &S.u.b.b); static_assert(&S.u.a.b == &S.u.b.b); // both-error {{failed}} union { int a[2]; int b[2]; } U2; static_assert(&U2.a[0] == &U2.b[0]); static_assert(&U2.a[0] != &U2.b[1]); static_assert(&U2.a[0] == &U2.b[1]); // both-error {{failed}} }