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

Reply via email to