On Tue, Feb 19, 2019 at 11:03:05PM +0100, Jakub Jelinek wrote: > > 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)?
Bootstrapped/regtested now on x86_64-linux and i686-linux. > 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