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

Reply via email to