On Thu, 19 Mar 2020, Jason Merrill wrote:

> On 3/19/20 12:35 PM, Patrick Palka wrote:
> > This patch adds a check to detect changing the active union member during
> > initialization of the union.  It uses the CONSTRUCTOR_NO_CLEARING flag as a
> > proxy for whether the non-empty CONSTRUCTOR of UNION_TYPE we're assigning to
> > in
> > cxx_eval_store_expression is in the process of being initialized, which
> > seems to
> > work well.
> 
> > In order for this check to work reliably, we also have to adjust
> > cxx_eval_bare_aggregate to set the active union member before processing the
> > initializer.
> > 
> > Does this look OK to commit after testing?
> 
> That makes sense.  OK.

Thanks.  The issue Marek points out unfortunately makes this approach of
using CONSTRUCTOR_NO_CLEARING unreliable and regresses other testcases,
and I'm afraid I don't know how to salvage this approach...

> 
> > gcc/cp/ChangeLog:
> > 
> >     PR c++/94066
> >     * constexpr.c (cxx_eval_bare_aggregate): When constructing a union,
> >     always set the active union member before evaluating the initializer.
> >     Relax assertion that verifies the index of the constructor element
> > we're
> >     initializing hasn't been changed.
> >     (cxx_eval_store_expression): Diagnose changing the active union member
> >     while the union is in the process of being initialized.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> >     PR c++/94066
> >     * g++.dg/cpp1y/pr94066.C: New test.
> >     * g++.dg/cpp1y/pr94066-2.C: New test.
> >     * g++.dg/cpp1y/pr94066-3.C: New test.
> > ---
> >   gcc/cp/constexpr.c                     | 25 ++++++++++++++++++++++++-
> >   gcc/testsuite/g++.dg/cpp1y/pr94066-2.C | 19 +++++++++++++++++++
> >   gcc/testsuite/g++.dg/cpp1y/pr94066-3.C | 18 ++++++++++++++++++
> >   gcc/testsuite/g++.dg/cpp1y/pr94066.C   | 18 ++++++++++++++++++
> >   4 files changed, 79 insertions(+), 1 deletion(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr94066-2.C
> >   create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr94066-3.C
> >   create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr94066.C
> > 
> > diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
> > index 192face9a3a..97fe5572f71 100644
> > --- a/gcc/cp/constexpr.c
> > +++ b/gcc/cp/constexpr.c
> > @@ -3751,6 +3751,11 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx,
> > tree t,
> >     /* If we built a new CONSTRUCTOR, attach it now so that other
> >        initializers can refer to it.  */
> >     CONSTRUCTOR_APPEND_ELT (*p, index, new_ctx.ctor);
> > +      else if (TREE_CODE (type) == UNION_TYPE)
> > +   /* If we're constructing a union, set the active union member now so
> > +      that we can later detect if the initializer attempts to activate
> > +      another member.  */
> > +   CONSTRUCTOR_APPEND_ELT (*p, index, NULL_TREE);
> >         tree elt = cxx_eval_constant_expression (&new_ctx, value,
> >                                            lval,
> >                                            non_constant_p, overflow_p);
> > @@ -3784,7 +3789,12 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx,
> > tree t,
> >     }
> >         else
> >     {
> > -     if (new_ctx.ctor != ctx->ctor)
> > +     if (TREE_CODE (type) == UNION_TYPE
> > +         && (*p)->last().index != index)
> > +       /* The initializer may have erroneously changed the active union
> > +          member we were initializing.  */
> > +       gcc_assert (*non_constant_p);
> > +     else if (new_ctx.ctor != ctx->ctor)
> >         {
> >           /* We appended this element above; update the value.  */
> >           gcc_assert ((*p)->last().index == index);
> > @@ -4647,6 +4657,19 @@ cxx_eval_store_expression (const constexpr_ctx *ctx,
> > tree t,
> >                           index);
> >               *non_constant_p = true;
> >             }
> > +         else if (TREE_CODE (t) == MODIFY_EXPR
> > +                  && CONSTRUCTOR_NO_CLEARING (*valp))
> > +           {
> > +             /* Diagnose changing the active union member while the union
> > +                is in the process of being initialized.  */
> > +             if (!ctx->quiet)
> > +               error_at (cp_expr_loc_or_input_loc (t),
> > +                         "change of the active member of a union "
> > +                         "from %qD to %qD during initialization",
> > +                         CONSTRUCTOR_ELT (*valp, 0)->index,
> > +                         index);
> > +             *non_constant_p = true;
> > +           }
> >           /* Changing active member.  */
> >           vec_safe_truncate (CONSTRUCTOR_ELTS (*valp), 0);
> >           no_zero_init = true;
> > diff --git a/gcc/testsuite/g++.dg/cpp1y/pr94066-2.C
> > b/gcc/testsuite/g++.dg/cpp1y/pr94066-2.C
> > new file mode 100644
> > index 00000000000..1c00b650961
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp1y/pr94066-2.C
> > @@ -0,0 +1,19 @@
> > +// PR c++/94066
> > +// { dg-do compile { target c++14 } }
> > +
> > +struct A { long x; };
> > +
> > +union U;
> > +constexpr A foo(U *up);
> > +
> > +union U {
> > +  U() = default;
> > +  A a = foo(this); int y;
> > +};
> > +
> > +constexpr A foo(U *up) {
> > +  up->y = 11;  // { dg-error "'U::a' to 'U::y'" }
> > +  return {42};
> > +}
> > +
> > +extern constexpr U u = {};
> > diff --git a/gcc/testsuite/g++.dg/cpp1y/pr94066-3.C
> > b/gcc/testsuite/g++.dg/cpp1y/pr94066-3.C
> > new file mode 100644
> > index 00000000000..6bf1ec81885
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp1y/pr94066-3.C
> > @@ -0,0 +1,18 @@
> > +// PR c++/94066
> > +// { dg-do compile { target c++14 } }
> > +
> > +struct A { long x; };
> > +
> > +union U;
> > +constexpr int foo(U *up);
> > +
> > +union U {
> > +  int a = foo(this); int y;
> > +};
> > +
> > +constexpr int foo(U *up) {
> > +  up->y = 11; // { dg-error "'U::a' to 'U::y'" }
> > +  return {42};
> > +}
> > +
> > +extern constexpr U u = {};
> > diff --git a/gcc/testsuite/g++.dg/cpp1y/pr94066.C
> > b/gcc/testsuite/g++.dg/cpp1y/pr94066.C
> > new file mode 100644
> > index 00000000000..6725c8c737f
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp1y/pr94066.C
> > @@ -0,0 +1,18 @@
> > +// PR c++/94066
> > +// { dg-do compile { target c++14 } }
> > +
> > +struct A { long x; };
> > +
> > +union U;
> > +constexpr A foo(U *up);
> > +
> > +union U {
> > +  A a = foo(this); int y;
> > +};
> > +
> > +constexpr A foo(U *up) {
> > +  up->y = 11;  // { dg-error "'U::a' to 'U::y'" }
> > +  return {42};
> > +}
> > +
> > +extern constexpr U u = {};
> > 
> 
> 

Reply via email to