Re: [PATCH] c++: Implement P1009: Array size deduction in new-expressions.

2020-08-21 Thread Jason Merrill via Gcc-patches

On 8/20/20 4:22 PM, Marek Polacek wrote:

This patch implements C++20 P1009, allowing code like

   new double[]{1,2,3}; // array bound will be deduced

Since this proposal makes the initialization rules more consistent, it is
applied to all previous versions of C++ (thus, effectively, all the way back
to C++11).

My patch is based on Jason's patch that handled the basic case.  I've
extended it to work with ()-init and also the string literal case.
Further testing revealed that to handle stuff like

   new int[]{t...};

in a template, we have to consider such a NEW_EXPR type-dependent.
Obviously, we first have to expand the pack to be able to deduce the
number of elements in the array.

Curiously, while implementing this proposal, I noticed that we fail
to accept

   new char[4]{"abc"};

so I've assigned 77841 to self.  I think the fix will depend on the
build_new_1 hunk in this patch.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

gcc/cp/ChangeLog:

PR c++/93529
* init.c (build_new_1): Handle new char[]{"foo"}.
(build_new): Deduce the array size in new-expression if not
present.  Handle ()-init.  Handle initializing an array from
a string literal.
* parser.c (cp_parser_new_type_id): Leave [] alone.
(cp_parser_direct_new_declarator): Allow [].
* pt.c (type_dependent_expression_p): In a NEW_EXPR, consider
array types whose dimension has to be deduced type-dependent.

gcc/testsuite/ChangeLog:

PR c++/93529
* g++.dg/cpp0x/sfinae4.C: Adjust expected result after P1009.
* g++.dg/cpp2a/new-array1.C: New test.
* g++.dg/cpp2a/new-array2.C: New test.
* g++.dg/cpp2a/new-array3.C: New test.

Co-authored-by: Jason Merrill 
---
  gcc/cp/init.c   | 54 ++-
  gcc/cp/parser.c | 11 ++--
  gcc/cp/pt.c |  4 ++
  gcc/testsuite/g++.dg/cpp0x/sfinae4.C|  8 ++-
  gcc/testsuite/g++.dg/cpp2a/new-array1.C | 70 +
  gcc/testsuite/g++.dg/cpp2a/new-array2.C | 22 
  gcc/testsuite/g++.dg/cpp2a/new-array3.C | 17 ++
  7 files changed, 180 insertions(+), 6 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/cpp2a/new-array1.C
  create mode 100644 gcc/testsuite/g++.dg/cpp2a/new-array2.C
  create mode 100644 gcc/testsuite/g++.dg/cpp2a/new-array3.C

diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 872c23453fd..ae1177079e4 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -3559,8 +3559,8 @@ build_new_1 (vec **placement, tree type, 
tree nelts,
else if (array_p)
{
  tree vecinit = NULL_TREE;
- if (vec_safe_length (*init) == 1
- && DIRECT_LIST_INIT_P ((**init)[0]))
+ const size_t len = vec_safe_length (*init);
+ if (len == 1 && DIRECT_LIST_INIT_P ((**init)[0]))
{
  vecinit = (**init)[0];
  if (CONSTRUCTOR_NELTS (vecinit) == 0)
@@ -3578,6 +3578,15 @@ build_new_1 (vec **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)
@@ -3917,6 +3926,47 @@ build_new (location_t loc, vec **placement, 
tree type,
return error_mark_node;
  }
  
+  /* P1009: Array size deduction in new-expressions.  */

+  if (TREE_CODE (type) == ARRAY_TYPE
+  && !TYPE_DOMAIN (type)
+  && *init)
+{
+  /* This means we have 'new T[]()'.  */
+  if ((*init)->is_empty ())
+   {
+ tree ctor = build_constructor (init_list_type_node, NULL);
+ CONSTRUCTOR_IS_DIRECT_INIT (ctor) = true;
+ vec_safe_push (*init, ctor);
+   }
+  tree  = (**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").  */
+ if (vec_safe_length (*init) == 1
+ && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type)))
+ && TREE_CODE (tree_strip_any_location_wrapper (elt))
+== STRING_CST)
+   /* Leave it alone: the string should not be wrapped in {}.  */;
+ else
+   {
+ /* Create a CONSTRUCTOR from the vector INIT.  */
+ tree list = build_tree_list_vec (*init);
+ tree ctor = build_constructor_from_list (init_list_type_node, 
list);
+ CONSTRUCTOR_IS_DIRECT_INIT (ctor) = true;
+ CONSTRUCTOR_IS_PAREN_INIT 

[PATCH] c++: Implement P1009: Array size deduction in new-expressions.

2020-08-20 Thread Marek Polacek via Gcc-patches
This patch implements C++20 P1009, allowing code like

  new double[]{1,2,3}; // array bound will be deduced

Since this proposal makes the initialization rules more consistent, it is
applied to all previous versions of C++ (thus, effectively, all the way back
to C++11).

My patch is based on Jason's patch that handled the basic case.  I've
extended it to work with ()-init and also the string literal case.
Further testing revealed that to handle stuff like

  new int[]{t...};

in a template, we have to consider such a NEW_EXPR type-dependent.
Obviously, we first have to expand the pack to be able to deduce the
number of elements in the array.

Curiously, while implementing this proposal, I noticed that we fail
to accept

  new char[4]{"abc"};

so I've assigned 77841 to self.  I think the fix will depend on the
build_new_1 hunk in this patch.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

gcc/cp/ChangeLog:

PR c++/93529
* init.c (build_new_1): Handle new char[]{"foo"}.
(build_new): Deduce the array size in new-expression if not
present.  Handle ()-init.  Handle initializing an array from
a string literal.
* parser.c (cp_parser_new_type_id): Leave [] alone.
(cp_parser_direct_new_declarator): Allow [].
* pt.c (type_dependent_expression_p): In a NEW_EXPR, consider
array types whose dimension has to be deduced type-dependent.

gcc/testsuite/ChangeLog:

PR c++/93529
* g++.dg/cpp0x/sfinae4.C: Adjust expected result after P1009.
* g++.dg/cpp2a/new-array1.C: New test.
* g++.dg/cpp2a/new-array2.C: New test.
* g++.dg/cpp2a/new-array3.C: New test.

Co-authored-by: Jason Merrill 
---
 gcc/cp/init.c   | 54 ++-
 gcc/cp/parser.c | 11 ++--
 gcc/cp/pt.c |  4 ++
 gcc/testsuite/g++.dg/cpp0x/sfinae4.C|  8 ++-
 gcc/testsuite/g++.dg/cpp2a/new-array1.C | 70 +
 gcc/testsuite/g++.dg/cpp2a/new-array2.C | 22 
 gcc/testsuite/g++.dg/cpp2a/new-array3.C | 17 ++
 7 files changed, 180 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/new-array1.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/new-array2.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/new-array3.C

diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 872c23453fd..ae1177079e4 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -3559,8 +3559,8 @@ build_new_1 (vec **placement, tree type, 
tree nelts,
   else if (array_p)
{
  tree vecinit = NULL_TREE;
- if (vec_safe_length (*init) == 1
- && DIRECT_LIST_INIT_P ((**init)[0]))
+ const size_t len = vec_safe_length (*init);
+ if (len == 1 && DIRECT_LIST_INIT_P ((**init)[0]))
{
  vecinit = (**init)[0];
  if (CONSTRUCTOR_NELTS (vecinit) == 0)
@@ -3578,6 +3578,15 @@ build_new_1 (vec **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)
@@ -3917,6 +3926,47 @@ build_new (location_t loc, vec **placement, 
tree type,
   return error_mark_node;
 }
 
+  /* P1009: Array size deduction in new-expressions.  */
+  if (TREE_CODE (type) == ARRAY_TYPE
+  && !TYPE_DOMAIN (type)
+  && *init)
+{
+  /* This means we have 'new T[]()'.  */
+  if ((*init)->is_empty ())
+   {
+ tree ctor = build_constructor (init_list_type_node, NULL);
+ CONSTRUCTOR_IS_DIRECT_INIT (ctor) = true;
+ vec_safe_push (*init, ctor);
+   }
+  tree  = (**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").  */
+ if (vec_safe_length (*init) == 1
+ && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type)))
+ && TREE_CODE (tree_strip_any_location_wrapper (elt))
+== STRING_CST)
+   /* Leave it alone: the string should not be wrapped in {}.  */;
+ else
+   {
+ /* Create a CONSTRUCTOR from the vector INIT.  */
+ tree list = build_tree_list_vec (*init);
+ tree ctor = build_constructor_from_list (init_list_type_node, 
list);
+ CONSTRUCTOR_IS_DIRECT_INIT (ctor) = true;
+ CONSTRUCTOR_IS_PAREN_INIT (ctor) = true;
+ elt = ctor;
+ /* We've