On Wed, Sep 09, 2020 at 05:02:24PM -0400, Jason Merrill wrote:
> On 9/8/20 10:34 PM, Marek Polacek wrote:
> > On Tue, Sep 08, 2020 at 04:19:42PM -0400, Jason Merrill wrote:
> > > On 9/8/20 4:06 PM, Marek Polacek wrote:
> > > > On Mon, Sep 07, 2020 at 11:19:47PM -0400, Jason Merrill wrote:
> > > > > On 9/6/20 11:34 AM, Marek Polacek wrote:
> > > > > > @@ -3944,9 +3935,9 @@ build_new (location_t loc, vec<tree, va_gc> 
> > > > > > **placement, tree type,
> > > > > >         }
> > > > > >       /* P1009: Array size deduction in new-expressions.  */
> > > > > > -  if (TREE_CODE (type) == ARRAY_TYPE
> > > > > > -      && !TYPE_DOMAIN (type)
> > > > > > -      && *init)
> > > > > > +  const bool deduce_array_p = (TREE_CODE (type) == ARRAY_TYPE
> > > > > > +                          && !TYPE_DOMAIN (type));
> > > > > > +  if (*init && (deduce_array_p || (nelts && cxx_dialect >= cxx20)))
> > > > > 
> > > > > Looks like this won't handle new (char[4]), for which we also get an
> > > > > ARRAY_TYPE.
> > > > 
> > > > Good catch.  Fixed & paren-init37.C added.
> > > > 
> > > > > >         {
> > > > > >           /* This means we have 'new T[]()'.  */
> > > > > >           if ((*init)->is_empty ())
> > > > > > @@ -3955,16 +3946,20 @@ build_new (location_t loc, vec<tree, va_gc> 
> > > > > > **placement, tree type,
> > > > > >               CONSTRUCTOR_IS_DIRECT_INIT (ctor) = true;
> > > > > >               vec_safe_push (*init, ctor);
> > > > > >             }
> > > > > > +      tree array_type = deduce_array_p ? TREE_TYPE (type) : type;
> > > > > 
> > > > > I'd call this variable elt_type.
> > > > 
> > > > Right, and it should be inside the block below.
> > > > 
> > > > > >           tree &elt = (**init)[0];
> > > > > >           /* The C++20 'new T[](e_0, ..., e_k)' case allowed by 
> > > > > > P0960.  */
> > > > > >           if (!DIRECT_LIST_INIT_P (elt) && cxx_dialect >= cxx20)
> > > > > >             {
> > > > > > -     /* Handle new char[]("foo").  */
> > > > > > +     /* Handle new char[]("foo"): turn it into new char[]{"foo"}.  
> > > > > > */
> > > > > >               if (vec_safe_length (*init) == 1
> > > > > > -         && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type)))
> > > > > > +         && char_type_p (TYPE_MAIN_VARIANT (array_type))
> > > > > >                   && TREE_CODE (tree_strip_any_location_wrapper 
> > > > > > (elt))
> > > > > >                      == STRING_CST)
> > > > > > -       /* Leave it alone: the string should not be wrapped in {}.  
> > > > > > */;
> > > > > > +       {
> > > > > > +         elt = build_constructor_single (init_list_type_node, 
> > > > > > NULL_TREE, elt);
> > > > > > +         CONSTRUCTOR_IS_DIRECT_INIT (elt) = true;
> > > > > > +       }
> > > > > >               else
> > > > > >                 {
> > > > > >                   tree ctor = build_constructor_from_vec 
> > > > > > (init_list_type_node, *init);
> > > > > 
> > > > > With this change, doesn't the string special case produce the same 
> > > > > result as
> > > > > the general case?
> > > > 
> > > > The problem is that reshape_init won't do anything for 
> > > > CONSTRUCTOR_IS_PAREN_INIT.
> > > 
> > > Ah, yes, that flag is the difference.
> > > 
> > > > So the reshape_init in build_new_1 wouldn't unwrap the outermost { } 
> > > > around
> > > > a STRING_CST.
> > > 
> > > > Perhaps reshape_init should be adjusted to do that unwrapping even when 
> > > > it gets
> > > > a CONSTRUCTOR_IS_PAREN_INIT CONSTRUCTOR.  But I'm not sure if it should 
> > > > also do
> > > > the reference_related_p unwrapping in reshape_init_r in that case.
> > > 
> > > That would make sense to me.
> > 
> > Done (but only for the outermost CONSTRUCTOR) in the below.  It allowed me 
> > to...
> > 
> > > > > > @@ -3977,9 +3972,15 @@ build_new (location_t loc, vec<tree, va_gc> 
> > > > > > **placement, tree type,
> > > > > >                 }
> > > > > >             }
> > > > > >           /* Otherwise we should have 'new T[]{e_0, ..., e_k}'.  */
> > > > > > -      if (BRACE_ENCLOSED_INITIALIZER_P (elt))
> > > > > > -   elt = reshape_init (type, elt, complain);
> > > > > > -      cp_complete_array_type (&type, elt, /*do_default*/false);
> > > > > > +      if (deduce_array_p)
> > > > > > +   {
> > > > > > +     /* Don't reshape ELT itself: we want to pass a 
> > > > > > list-initializer to
> > > > > > +        build_new_1, even for STRING_CSTs.  */
> > > > > > +     tree e = elt;
> > > > > > +     if (BRACE_ENCLOSED_INITIALIZER_P (e))
> > > > > > +       e = reshape_init (type, e, complain);
> > > > > 
> > > > > The comment is unclear; this call does reshape the CONSTRUCTOR ELT 
> > > > > points
> > > > > to, it just doesn't change ELT if the reshape call returns something 
> > > > > else.
> > > > 
> > > > Yea, I've amended the comment.
> > > > 
> > > > > Why are we reshaping here, anyway?  Won't that lead to undesired brace
> > > > > elision?
> > > > 
> > > > We have to reshape before deducing the array, otherwise we could deduce 
> > > > the
> > > > wrong number of elements when certain braces were omitted.  E.g. in
> > > > 
> > > >     struct S { int x, y; };
> > > >     new S[]{1, 2, 3, 4}; // braces elided, is { {1, 2}, {3, 4} }
> > > 
> > > Ah, right, we also get here for initializers written with actual braces.
> > > 
> > > > we want S[2], not S[4].  A way to test it would be
> > > > 
> > > >     struct S { int x, y; };
> > > >     S *p = new S[]{1, 2, 3, 4};
> > > > 
> > > >     void* operator new (unsigned long int size)
> > > >     {
> > > >         if (size != sizeof (S) * 2)
> > > >         __builtin_abort ();
> > > >         return __builtin_malloc (size);
> > > >     }
> > > > 
> > > >     int main () { }
> > > > 
> > > > I can add that too, if you want.  (It'd be safer if 
> > > > cp_complete_array_type
> > > > always reshaped but that's not trivial, as the original patch mentions.)
> > > > ()-init-list wouldn't be reshaped because CONSTRUCTOR_IS_PAREN_INIT is 
> > > > set.
> > > > 
> > > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> > > > 
> > > > Thanks,
> > > > 
> > > > -- >8 --
> > > > This patch corrects our handling of array new-expression with ()-init:
> > > > 
> > > >     new int[4](1, 2, 3, 4);
> > > > 
> > > > should work even with the explicit array bound, and
> > > > 
> > > >     new char[3]("so_sad");
> > > > 
> > > > should cause an error, but we weren't giving any.
> > > > 
> > > > Fixed by handling array new-expressions with ()-init in the same spot
> > > > where we deduce the array bound in array new-expression.  I'm now
> > > > always passing STRING_CSTs to build_new_1 wrapped in { } which allowed
> > > > me to remove the special handling of STRING_CSTs in build_new_1.  And
> > > > since the DIRECT_LIST_INIT_P block in build_new_1 calls digest_init, we
> > > > report errors about too short arrays.
> > > > 
> > > > I took a stab at cp_complete_array_type's "FIXME: this code is 
> > > > duplicated
> > > > from reshape_init", but calling reshape_init there, I ran into issues
> > > > with has_designator_problem: when we reshape an already reshaped
> > > > CONSTRUCTOR again, d.cur.index has been filled, so we think that we
> > > > have a user-provided designator (though there was no designator in the
> > > > source code), and report an error.
> > > > 
> > > > gcc/cp/ChangeLog:
> > > > 
> > > >         PR c++/77841
> > > >         * init.c (build_new_1): Don't handle string-initializers here.
> > > >         (build_new): Handle new-expression with paren-init when the
> > > >         array bound is known.  Always pass string constants to 
> > > > build_new_1
> > > >         enclosed in braces.
> > > > 
> > > > gcc/testsuite/ChangeLog:
> > > > 
> > > >         PR c++/77841
> > > >         * g++.old-deja/g++.ext/arrnew2.C: Expect the error only in C++17
> > > >         and less.
> > > >         * g++.old-deja/g++.robertl/eb58.C: Adjust dg-error.
> > > >         * g++.old-deja/g++.robertl/eb63.C: Expect the error only in 
> > > > C++17
> > > >         and less.
> > > >         * g++.dg/cpp2a/paren-init36.C: New test.
> > > >         * g++.dg/cpp2a/paren-init37.C: New test.
> > > >         * g++.dg/pr84729.C: Adjust dg-error.
> > > > ---
> > > >    gcc/cp/init.c                                 | 41 
> > > > +++++++++++--------
> > > >    gcc/testsuite/g++.dg/cpp2a/paren-init36.C     | 14 +++++++
> > > >    gcc/testsuite/g++.dg/cpp2a/paren-init37.C     | 14 +++++++
> > > >    gcc/testsuite/g++.dg/pr84729.C                |  2 +-
> > > >    gcc/testsuite/g++.old-deja/g++.ext/arrnew2.C  |  2 +-
> > > >    gcc/testsuite/g++.old-deja/g++.robertl/eb58.C |  2 +-
> > > >    gcc/testsuite/g++.old-deja/g++.robertl/eb63.C |  2 +-
> > > >    7 files changed, 55 insertions(+), 22 deletions(-)
> > > >    create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init36.C
> > > >    create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init37.C
> > > > 
> > > > diff --git a/gcc/cp/init.c b/gcc/cp/init.c
> > > > index 3268ae4ad3f..fe4d49df402 100644
> > > > --- a/gcc/cp/init.c
> > > > +++ b/gcc/cp/init.c
> > > > @@ -3596,15 +3596,6 @@ build_new_1 (vec<tree, va_gc> **placement, tree 
> > > > type, tree nelts,
> > > >                   vecinit = digest_init (arraytype, vecinit, complain);
> > > >                 }
> > > >             }
> > > > -         /* This handles code like new char[]{"foo"}.  */
> > > > -         else if (len == 1
> > > > -                  && char_type_p (TYPE_MAIN_VARIANT (type))
> > > > -                  && TREE_CODE (tree_strip_any_location_wrapper 
> > > > ((**init)[0]))
> > > > -                     == STRING_CST)
> > > > -           {
> > > > -             vecinit = (**init)[0];
> > > > -             STRIP_ANY_LOCATION_WRAPPER (vecinit);
> > > > -           }
> > > >           else if (*init)
> > > >                {
> > > >                  if (complain & tf_error)
> > > > @@ -3944,9 +3935,8 @@ build_new (location_t loc, vec<tree, va_gc> 
> > > > **placement, tree type,
> > > >        }
> > > >      /* P1009: Array size deduction in new-expressions.  */
> > > > -  if (TREE_CODE (type) == ARRAY_TYPE
> > > > -      && !TYPE_DOMAIN (type)
> > > > -      && *init)
> > > > +  const bool array_p = TREE_CODE (type) == ARRAY_TYPE;
> > > > +  if (*init && (array_p || (nelts && cxx_dialect >= cxx20)))
> > > >        {
> > > >          /* This means we have 'new T[]()'.  */
> > > >          if ((*init)->is_empty ())
> > > > @@ -3959,12 +3949,16 @@ build_new (location_t loc, vec<tree, va_gc> 
> > > > **placement, tree type,
> > > >          /* The C++20 'new T[](e_0, ..., e_k)' case allowed by P0960.  
> > > > */
> > > >          if (!DIRECT_LIST_INIT_P (elt) && cxx_dialect >= cxx20)
> > > >         {
> > > > -         /* Handle new char[]("foo").  */
> > > > +         tree elt_type = array_p ? TREE_TYPE (type) : type;
> > > 
> > > I think this should condition on whether nelts is set, to handle e.g. new
> > > char[2][2] properly.
> > 
> > ...remove this code.
> > 
> > I've added new-array5.C to test multidimensional arrays too.
> > 
> > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> > 
> > -- >8 --
> > This patch corrects our handling of array new-expression with ()-init:
> > 
> >    new int[4](1, 2, 3, 4);
> > 
> > should work even with the explicit array bound, and
> > 
> >    new char[3]("so_sad");
> > 
> > should cause an error, but we weren't giving any.
> > 
> > Fixed by handling array new-expressions with ()-init in the same spot
> > where we deduce the array bound in array new-expression.  I'm now
> > always passing STRING_CSTs to build_new_1 wrapped in { } which allowed
> > me to remove the special handling of STRING_CSTs in build_new_1.  And
> > since the DIRECT_LIST_INIT_P block in build_new_1 calls digest_init, we
> > report errors about too short arrays. reshape_init now does the {"foo"}
> > -> "foo" transformation even for CONSTRUCTOR_IS_PAREN_INIT, so no need
> > to do it in build_new.
> > 
> > I took a stab at cp_complete_array_type's "FIXME: this code is duplicated
> > from reshape_init", but calling reshape_init there, I ran into issues
> > with has_designator_problem: when we reshape an already reshaped
> > CONSTRUCTOR again, d.cur.index has been filled, so we think that we
> > have a user-provided designator (though there was no designator in the
> > source code), and report an error.
> > 
> > gcc/cp/ChangeLog:
> > 
> >     PR c++/77841
> >     * decl.c (reshape_init): If we're initializing a char array from
> >     a string-literal that is enclosed in braces, unwrap it.
> >     * init.c (build_new_1): Don't handle string-initializers here.
> >     (build_new): Handle new-expression with paren-init when the
> >     array bound is known.  Always pass string constants to build_new_1
> >     enclosed in braces.  Don't handle string-initializers in any
> >     special way.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> >     PR c++/77841
> >     * g++.old-deja/g++.ext/arrnew2.C: Expect the error only in C++17
> >     and less.
> >     * g++.old-deja/g++.robertl/eb58.C: Adjust dg-error.
> >     * g++.old-deja/g++.robertl/eb63.C: Expect the error only in C++17
> >     and less.
> >     * g++.dg/cpp2a/new-array5.C: New test.
> >     * g++.dg/cpp2a/paren-init36.C: New test.
> >     * g++.dg/cpp2a/paren-init37.C: New test.
> >     * g++.dg/pr84729.C: Adjust dg-error.
> > ---
> >   gcc/cp/decl.c                                 | 12 ++++-
> >   gcc/cp/init.c                                 | 54 ++++++++-----------
> >   gcc/testsuite/g++.dg/cpp2a/new-array5.C       | 15 ++++++
> >   gcc/testsuite/g++.dg/cpp2a/paren-init36.C     | 14 +++++
> >   gcc/testsuite/g++.dg/cpp2a/paren-init37.C     | 14 +++++
> >   gcc/testsuite/g++.dg/pr84729.C                |  2 +-
> >   gcc/testsuite/g++.old-deja/g++.ext/arrnew2.C  |  2 +-
> >   gcc/testsuite/g++.old-deja/g++.robertl/eb58.C |  2 +-
> >   gcc/testsuite/g++.old-deja/g++.robertl/eb63.C |  2 +-
> >   9 files changed, 81 insertions(+), 36 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp2a/new-array5.C
> >   create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init36.C
> >   create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init37.C
> > 
> > diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
> > index 31d68745844..1287ce1efd1 100644
> > --- a/gcc/cp/decl.c
> > +++ b/gcc/cp/decl.c
> > @@ -6599,7 +6599,17 @@ reshape_init (tree type, tree init, tsubst_flags_t 
> > complain)
> >     /* Brace elision is not performed for a CONSTRUCTOR representing
> >        parenthesized aggregate initialization.  */
> >     if (CONSTRUCTOR_IS_PAREN_INIT (init))
> > -    return init;
> > +    {
> > +      tree elt = (*v)[0].value;
> > +      /* If we're initializing a char array from a string-literal that is
> > +    enclosed in braces, unwrap it here.  */
> > +      if (TREE_CODE (type) == ARRAY_TYPE
> > +     && vec_safe_length (v) == 1
> > +     && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type)))
> > +     && TREE_CODE (tree_strip_any_location_wrapper (elt)) == STRING_CST)
> > +   return elt;
> > +      return init;
> 
> You decided against unwrapping a reference_related_p initializer here?

Yeah, it doesn't seem to be needed: e.g. in

  struct X { int i; };
  struct Y : X { };
  int main ()
  {
    Y y;
    y.i = 42;
    X x2(y);
    __builtin_printf ("%d\n", x2.i);
  }

we don't reshape_init at all, and build_aggr_init creates an INIT_EXPR
  x2 = y.D.2087
which is the same code we generate with e.g. GCC 8, or if we use x2{y}.

Also, P0960 says that any existing meaning of A(b) should not change.

Marek

Reply via email to