On Tue, Feb 19, 2019 at 11:28:22AM -1000, Jason Merrill wrote: > On Tue, Feb 19, 2019 at 4:00 AM Jakub Jelinek <ja...@redhat.com> wrote: > > On Mon, Feb 18, 2019 at 03:01:14PM -1000, Jason Merrill wrote: > > > But it's not clear to me that the standard actually allows this. I don't > > > think changing the active member of a union in the mem-initializer for > > > another member is reasonable. > > > > There is in [expr.const]/2: > > > > an lvalue-to-rvalue conversion (7.1) that is applied to a glvalue that > > refers to a non-active member of a > > union or a subobject thereof; > > > > an assignment expression (8.18) or invocation of an assignment operator > > (15.8) that would change the > > active member of a union; > > > > in C++17 it seems, so maybe my union testcases are accepts-invalid. > > This has been introduced in P0137R1 and removed again in P1330R0. Does that > > mean e.g. following is valid in C++14, invalid in C++17 and valid again in > > C++20? Or has one of the above papers changed retroactively previous > > standards? > > Before P0137 I believe foo and bar were arguably undefined.
I see, before that it was: "an lvalue-to-rvalue conversion (4.1) or modification (5.18, 5.2.6, 5.3.2) that is applied to a glvalue that refers to a non-active member of a union or a subobject thereof;" So, do we want something like this then (or free all vectors immediately there and return immediately)? 2019-02-19 Jakub Jelinek <ja...@redhat.com> PR c++/89336 * constexpr.c (cxx_eval_store_expression): Diagnose changing of active union member for -std=c++17 and earlier. * g++.dg/cpp1y/constexpr-89336-3.C: New test. --- gcc/cp/constexpr.c.jj 2019-02-19 10:26:09.567962395 +0100 +++ gcc/cp/constexpr.c 2019-02-19 22:53:45.702983814 +0100 @@ -3890,8 +3890,20 @@ cxx_eval_store_expression (const constex if (code == UNION_TYPE && CONSTRUCTOR_NELTS (*valp) && CONSTRUCTOR_ELT (*valp, 0)->index != index) - /* Changing active member. */ - vec_safe_truncate (CONSTRUCTOR_ELTS (*valp), 0); + { + if (cxx_dialect < cxx2a) + { + if (!ctx->quiet) + error_at (cp_expr_loc_or_loc (t, input_location), + "change of the active member of a union " + "from %qD to %qD", + CONSTRUCTOR_ELT (*valp, 0)->index, + index); + *non_constant_p = true; + } + /* Changing active member. */ + vec_safe_truncate (CONSTRUCTOR_ELTS (*valp), 0); + } for (idx = 0; vec_safe_iterate (CONSTRUCTOR_ELTS (*valp), idx, &cep); --- gcc/testsuite/g++.dg/cpp1y/constexpr-89336-3.C.jj 2019-02-19 14:13:19.990627715 +0100 +++ gcc/testsuite/g++.dg/cpp1y/constexpr-89336-3.C 2019-02-19 22:59:02.294799026 +0100 @@ -0,0 +1,46 @@ +// PR c++/89336 +// { dg-do compile { target c++14 } } + +constexpr int +foo () +{ + union U { int a; long b; }; + union V { union U u; short v; }; + V w {}; + w.u.a = w.v = w.u.b = 5L; // { dg-error "change of the active member of a union from" "" { target c++17_down } } + return w.u.a; +} + +static_assert (foo () == 5, ""); // { dg-error "non-constant condition for static assertion" "" { target c++17_down } } + // { dg-message "expansion of" "" { target c++17_down } .-1 } + +constexpr int +bar () +{ + union U { int a[5]; long b; }; + union V { union U u; short v; }; + V w {}; + w.v = 5; + w.u.a[3] = w.u.a[1] = w.v; // { dg-error "change of the active member of a union from" "" { target c++17_down } } + return w.u.a[1] + w.u.a[3]; +} + +static_assert (bar () == 10, ""); // { dg-error "non-constant condition for static assertion" "" { target c++17_down } } + // { dg-message "expansion of" "" { target c++17_down } .-1 } + +struct Z { int x, y; }; + +constexpr Z +baz () +{ + union W { Z a; long long w; }; + W w {}; + w.a = { 5, 0 }; + w.a = { (int) (w.w = 17LL + w.a.x), 2 }; // { dg-error "change of the active member of a union from" "" { target c++17_down } } + return w.a; +} + +static_assert (baz ().x == 22, ""); // { dg-error "non-constant condition for static assertion" "" { target c++17_down } } + // { dg-message "expansion of" "" { target c++17_down } .-1 } +static_assert (baz ().y == 2, ""); // { dg-error "non-constant condition for static assertion" "" { target c++17_down } } + // { dg-message "expansion of" "" { target c++17_down } .-1 } Jakub