On Sun, Apr 17, 2022 at 6:24 PM Jason Merrill <ja...@redhat.com> wrote:
>
> On 4/15/22 07:22, Jakub Jelinek wrote:
> > Hi!
> >
> > The CONSTRUCTOR_PLACEHOLDER_BOUNDARY bit is supposed to separate
> > PLACEHOLDER_EXPRs that should be replaced by one object or subobjects of it
> > (variable, TARGET_EXPR slot, ...) from other PLACEHOLDER_EXPRs that should
> > be replaced by different objects or subobjects.
> > The bit is set when finding PLACEHOLDER_EXPRs inside of a CONSTRUCTOR, not
> > looking into nested CONSTRUCTOR_PLACEHOLDER_BOUNDARY ctors, and we prevent
> > elision of TARGET_EXPRs (through TARGET_EXPR_NO_ELIDE) whose initializer
> > is a CONSTRUCTOR_PLACEHOLDER_BOUNDARY ctor.  The following testcase ICEs
> > though, we don't replace the placeholders in there at all, because
> > CONSTRUCTOR_PLACEHOLDER_BOUNDARY isn't set on the TARGET_EXPR_INITIAL
> > ctor, but on a ctor nested in such a ctor.  replace_placeholders should be
> > run on the whole TARGET_EXPR slot.
> >
> > So, the following patch fixes it by moving the 
> > CONSTRUCTOR_PLACEHOLDER_BOUNDARY
> > bit from nested CONSTRUCTORs to the CONSTRUCTOR containing those (but only
> > if it is closely nested, if there is some other tree sandwiched in between,
> > it doesn't do it).
>
> Hmm, Patrick made a similar change and then reverted it for PR90996.
> But it makes sense to me; when we replace placeholders, it's appropriate
> to look at the whole aggregate initialization rather than the innermost
> CONSTRUCTOR that has DMIs.  Patrick, was there a reason that change
> seemed wrong to you, or was it just unnecessary for the bug you were
> working on?

That change was just not strictly necessary for PR90996 I think.  For
that testcase:

struct S {
  int &&a = 2;
  int b[1] {a};
};

S c[] {{2}};

we first call replace_placeholders from store_init_value for the
overall initiializer for c

  {{.a=(int &) &_ZGR1c_, .b={*(&<PLACEHOLDER_EXPR struct S>)->a}}

but CONSTRUCTOR_PLACEHOLDER_BOUNDARY set on the middle pair of {}
prevents the placeholder from being resolved to c[0].  The reverted
change would have allowed us to resolve the placeholder at this point,
since the flag would have been moved to the outermost {} IIUC.

But fortunately split_nonconstant_init then factors out the
initialization of c[0].b into an INIT_EXPR:

  c[0].b[0] = *(&<PLACEHOLDER_EXPR struct S>)->a;

during gimplification of which we attempt replace_placeholders again
which succeeds this time at resolving the placeholder, due to the
other change in r10-7587 that made replace_placeholders look through
all handled components, not just COMPONENT_REF (mirroring
replace_placeholders_r).

So I reverted the rest of r10-7587 after Martin noticed it had no
effect: https://gcc.gnu.org/pipermail/gcc-patches/2020-April/543918.html

The reverted change and Jakub's more general patch seem right/safe to
me FWIW, I just couldn't come up with a testcase that demonstrated its
need at the time unfortunately.



>
> > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> >
> > 2022-04-15  Jakub Jelinek  <ja...@redhat.com>
> >
> >       PR c++/105256
> >       * typeck2.cc (process_init_constructor_array,
> >       process_init_constructor_record, process_init_constructor_union): Move
> >       CONSTRUCTOR_PLACEHOLDER_BOUNDARY flag from CONSTRUCTOR elements to the
> >       containing CONSTRUCTOR.
> >
> >       * g++.dg/cpp0x/pr105256.C: New test.
> >
> > --- gcc/cp/typeck2.cc.jj      2022-04-07 09:09:54.432995137 +0200
> > +++ gcc/cp/typeck2.cc 2022-04-14 16:02:12.438432494 +0200
> > @@ -1515,6 +1515,14 @@ process_init_constructor_array (tree typ
> >             strip_array_types (TREE_TYPE (ce->value)))));
> >
> >         picflags |= picflag_from_initializer (ce->value);
> > +      /* Propagate CONSTRUCTOR_PLACEHOLDER_BOUNDARY to outer
> > +      CONSTRUCTOR.  */
> > +      if (TREE_CODE (ce->value) == CONSTRUCTOR
> > +       && CONSTRUCTOR_PLACEHOLDER_BOUNDARY (ce->value))
> > +     {
> > +       CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = 1;
> > +       CONSTRUCTOR_PLACEHOLDER_BOUNDARY (ce->value) = 0;
> > +     }
> >       }
> >
> >     /* No more initializers. If the array is unbounded, we are done. 
> > Otherwise,
> > @@ -1560,6 +1568,14 @@ process_init_constructor_array (tree typ
> >             }
> >
> >           picflags |= picflag_from_initializer (next);
> > +         /* Propagate CONSTRUCTOR_PLACEHOLDER_BOUNDARY to outer
> > +            CONSTRUCTOR.  */
> > +         if (TREE_CODE (next) == CONSTRUCTOR
> > +             && CONSTRUCTOR_PLACEHOLDER_BOUNDARY (next))
> > +           {
> > +             CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = 1;
> > +             CONSTRUCTOR_PLACEHOLDER_BOUNDARY (next) = 0;
> > +           }
> >           if (len > i+1)
> >             {
> >               tree range = build2 (RANGE_EXPR, size_type_node,
> > @@ -1754,6 +1770,13 @@ process_init_constructor_record (tree ty
> >         if (fldtype != TREE_TYPE (field))
> >       next = cp_convert_and_check (TREE_TYPE (field), next, complain);
> >         picflags |= picflag_from_initializer (next);
> > +      /* Propagate CONSTRUCTOR_PLACEHOLDER_BOUNDARY to outer CONSTRUCTOR.  
> > */
> > +      if (TREE_CODE (next) == CONSTRUCTOR
> > +       && CONSTRUCTOR_PLACEHOLDER_BOUNDARY (next))
> > +     {
> > +       CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = 1;
> > +       CONSTRUCTOR_PLACEHOLDER_BOUNDARY (next) = 0;
> > +     }
> >         CONSTRUCTOR_APPEND_ELT (v, field, next);
> >       }
> >
> > @@ -1894,6 +1917,14 @@ process_init_constructor_union (tree typ
> >       ce->value = massage_init_elt (TREE_TYPE (ce->index), ce->value, 
> > nested,
> >                                 flags, complain);
> >
> > +  /* Propagate CONSTRUCTOR_PLACEHOLDER_BOUNDARY to outer CONSTRUCTOR.  */
> > +  if (ce->value
> > +      && TREE_CODE (ce->value) == CONSTRUCTOR
> > +      && CONSTRUCTOR_PLACEHOLDER_BOUNDARY (ce->value))
> > +    {
> > +      CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = 1;
> > +      CONSTRUCTOR_PLACEHOLDER_BOUNDARY (ce->value) = 0;
> > +    }
> >     return picflag_from_initializer (ce->value);
> >   }
> >
> > --- gcc/testsuite/g++.dg/cpp0x/pr105256.C.jj  2022-04-14 16:04:30.518518875 
> > +0200
> > +++ gcc/testsuite/g++.dg/cpp0x/pr105256.C     2022-04-14 16:03:53.264035175 
> > +0200
> > @@ -0,0 +1,18 @@
> > +// PR c++/105256
> > +// { dg-do compile { target c++11 } }
> > +
> > +int bar (int &);
> > +
> > +struct S {
> > +  struct T {
> > +    struct U {
> > +      int i = bar (i);
> > +    } u;
> > +  };
> > +};
> > +
> > +void
> > +foo (S::T *p)
> > +{
> > +  *p = {};
> > +};
> >
> >       Jakub
> >
>

Reply via email to