public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 0/3] P1997 'array-copy' patchset [PR103238]
@ 2021-11-22  2:51 Will Wray
  2021-11-22  2:51 ` [PATCH 1/3] c++: designated init of char array by string constant [PR55227] Will Wray
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Will Wray @ 2021-11-22  2:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: Will Wray

([PATCH 1/3] already submitted fix for PR c++/55227, is a dependency here.)

These patches implement C++ proposal P1997 "Relaxing restrictions on array"
that adds:

  C array copy semantics:
    * array-array initializations
    * array-array assignments
    * array return-by-value from functions
     (array formal parameters are unchanged; there's no pass-by-value).

  Plus, C++ specific:
    * array pseudo-destructors
    * array element type deduction
     (i.e. admitting placeholder auto in array variable declarations).

The features are added as an experimental extension, disabled by default.
The patches should have no effect until enabled by the new option:

    -farray-copy (flag_array_copy, a single flag to enable all features)

The extension is documented as experimental with no guarantee of stability;
features may be added, removed or changed in detail. In particular, there's
no guarantee of ABI stability; allowing array as a function return type has
ABI implications for calling conventions of the array return slot and, for
C++, name-mangling conventions must be defined.

The plan is to first merge array-copy as experimental, with ABI defined as
'what the code does', and then to go ahead with ABI work.

Will Wray (3):
  c++: designated init of char array by string constant [PR55227]
  c++: P1997 array-copy extensions: Initialization [PR103238]
  c++: P1997 array-copy extensions: Assignment, return, etc. [PR103238]

 gcc/c-family/c-common.c                  |   5 ++
 gcc/c-family/c.opt                       |   4 ++
 gcc/c/c-decl.c                           |   2 +-
 gcc/cp/call.c                            |  43 +++++++-----
 gcc/cp/decl.c                            | 111 ++++++++++++++++++-------------
 gcc/cp/init.c                            |   6 +-
 gcc/cp/parser.c                          |   4 +-
 gcc/cp/pt.c                              |  13 +++-
 gcc/cp/tree.c                            |   3 +-
 gcc/cp/typeck.c                          |  35 ++++++++--
 gcc/cp/typeck2.c                         |  30 ++++++---
 gcc/doc/invoke.texi                      |   6 ++
 gcc/testsuite/g++.dg/cpp2a/desig20.C     |  48 +++++++++++++
 gcc/testsuite/g++.dg/init/array-copy1.C  |  66 ++++++++++++++++++
 gcc/testsuite/g++.dg/init/array-copy10.C |  57 ++++++++++++++++
 gcc/testsuite/g++.dg/init/array-copy11.C |  13 ++++
 gcc/testsuite/g++.dg/init/array-copy12.C |  79 ++++++++++++++++++++++
 gcc/testsuite/g++.dg/init/array-copy2.C  |  68 +++++++++++++++++++
 gcc/testsuite/g++.dg/init/array-copy3.C  |  41 ++++++++++++
 gcc/testsuite/g++.dg/init/array-copy4.C  |  42 ++++++++++++
 gcc/testsuite/g++.dg/init/array-copy5.C  |  36 ++++++++++
 gcc/testsuite/g++.dg/init/array-copy6.C  |  51 ++++++++++++++
 gcc/testsuite/g++.dg/init/array-copy7.C  |  40 +++++++++++
 gcc/testsuite/g++.dg/init/array-copy8.C  |  56 ++++++++++++++++
 gcc/testsuite/g++.dg/init/array-copy9.C  |  57 ++++++++++++++++
 25 files changed, 835 insertions(+), 81 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/desig20.C
 create mode 100644 gcc/testsuite/g++.dg/init/array-copy1.C
 create mode 100644 gcc/testsuite/g++.dg/init/array-copy10.C
 create mode 100644 gcc/testsuite/g++.dg/init/array-copy11.C
 create mode 100644 gcc/testsuite/g++.dg/init/array-copy12.C
 create mode 100644 gcc/testsuite/g++.dg/init/array-copy2.C
 create mode 100644 gcc/testsuite/g++.dg/init/array-copy3.C
 create mode 100644 gcc/testsuite/g++.dg/init/array-copy4.C
 create mode 100644 gcc/testsuite/g++.dg/init/array-copy5.C
 create mode 100644 gcc/testsuite/g++.dg/init/array-copy6.C
 create mode 100644 gcc/testsuite/g++.dg/init/array-copy7.C
 create mode 100644 gcc/testsuite/g++.dg/init/array-copy8.C
 create mode 100644 gcc/testsuite/g++.dg/init/array-copy9.C

-- 
2.31.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/3] c++: designated init of char array by string constant [PR55227]
  2021-11-22  2:51 [PATCH 0/3] P1997 'array-copy' patchset [PR103238] Will Wray
@ 2021-11-22  2:51 ` Will Wray
  2021-11-25 16:05   ` Jason Merrill
  2021-11-22  2:51 ` [PATCH 2/3] c++: P1997 array-copy extensions: Initialization [PR103238] Will Wray
  2021-11-22  2:51 ` [PATCH 3/3] c++: P1997 array-copy extensions: Assignment, return, etc. [PR103238] Will Wray
  2 siblings, 1 reply; 9+ messages in thread
From: Will Wray @ 2021-11-22  2:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: Will Wray

Also address "FIXME: this code is duplicated from reshape_init" in
cp_complete_array_type by always calling reshape_init on init-list.

	PR c++/55227

gcc/cp/ChangeLog:

	* decl.c (reshape_init_r): Only call has_designator_check when
       first_initializer_p or for the inner constructor element.
	(cp_complete_array_type): Call reshape_init on braced-init-list.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp2a/desig20.C: New test.
---
 gcc/cp/decl.c                        | 42 +++++++++++++------------------
 gcc/testsuite/g++.dg/cpp2a/desig20.C | 48 ++++++++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+), 25 deletions(-)

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 2ddf0e4a524..83a2d3bf8f1 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -6824,28 +6824,31 @@ reshape_init_r (tree type, reshape_iter *d, tree first_initializer_p,
   if (TREE_CODE (type) == ARRAY_TYPE
       && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type))))
     {
-      tree str_init = init;
-      tree stripped_str_init = stripped_init;
+      tree arr_init = init;
+      tree stripped_arr_init = stripped_init;
+      reshape_iter stripd = {};
 
       /* Strip one level of braces if and only if they enclose a single
 	 element (as allowed by [dcl.init.string]).  */
       if (!first_initializer_p
-	  && TREE_CODE (stripped_str_init) == CONSTRUCTOR
-	  && CONSTRUCTOR_NELTS (stripped_str_init) == 1)
+	  && TREE_CODE (stripped_arr_init) == CONSTRUCTOR
+	  && CONSTRUCTOR_NELTS (stripped_arr_init) == 1)
 	{
-	  str_init = (*CONSTRUCTOR_ELTS (stripped_str_init))[0].value;
-	  stripped_str_init = tree_strip_any_location_wrapper (str_init);
+	  stripd.cur = CONSTRUCTOR_ELT (stripped_arr_init, 0);
+	  arr_init = stripd.cur->value;
+	  stripped_arr_init = tree_strip_any_location_wrapper (arr_init);
 	}
 
       /* If it's a string literal, then it's the initializer for the array
 	 as a whole. Otherwise, continue with normal initialization for
 	 array types (one value per array element).  */
-      if (TREE_CODE (stripped_str_init) == STRING_CST)
+      if (TREE_CODE (stripped_arr_init) == STRING_CST)
 	{
-	  if (has_designator_problem (d, complain))
+	  if ((first_initializer_p && has_designator_problem (d, complain))
+	      || (stripd.cur && has_designator_problem (&stripd, complain)))
 	    return error_mark_node;
 	  d->cur++;
-	  return str_init;
+	  return arr_init;
 	}
     }
 
@@ -9545,22 +9548,11 @@ cp_complete_array_type (tree *ptype, tree initial_value, bool do_default)
   if (initial_value)
     {
       /* An array of character type can be initialized from a
-	 brace-enclosed string constant.
-
-	 FIXME: this code is duplicated from reshape_init. Probably
-	 we should just call reshape_init here?  */
-      if (char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (*ptype)))
-	  && TREE_CODE (initial_value) == CONSTRUCTOR
-	  && !vec_safe_is_empty (CONSTRUCTOR_ELTS (initial_value)))
-	{
-	  vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (initial_value);
-	  tree value = (*v)[0].value;
-	  STRIP_ANY_LOCATION_WRAPPER (value);
-
-	  if (TREE_CODE (value) == STRING_CST
-	      && v->length () == 1)
-	    initial_value = value;
-	}
+	 brace-enclosed string constant so call reshape_init to
+	 remove the optional braces from a braced string literal.  */
+      if (BRACE_ENCLOSED_INITIALIZER_P (initial_value))
+	initial_value = reshape_init (*ptype, initial_value,
+				      tf_warning_or_error);
 
       /* If any of the elements are parameter packs, we can't actually
 	 complete this type now because the array size is dependent.  */
diff --git a/gcc/testsuite/g++.dg/cpp2a/desig20.C b/gcc/testsuite/g++.dg/cpp2a/desig20.C
new file mode 100644
index 00000000000..daadfa58855
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/desig20.C
@@ -0,0 +1,48 @@
+// PR c++/55227 
+// Test designated initializer for char array by string constant
+
+// { dg-options "" }
+
+struct C {char a[2];};
+
+/* Case a, designated, unbraced, string-literal of the exact same size
+   as the initialized char array; valid and accepted before and after.  */
+C a = {.a="a"};
+
+/* Cases b,c,d, designated, braced or mimatched-size, string literal,
+   previously rejected; "C99 designator 'a' outside aggregate initializer".  */
+C b = {.a=""};
+C c = {.a={""}};
+C d = {.a={"a"}};
+
+/* Case e, designated char array field and braced, designated array element(s)
+   (with GNU [N]= extension) valid and accepted before and after.  */
+C e = {.a={[0]='a'}};
+
+/* Cases f,g,h, braced string literal, 'designated' within inner braces;
+   invalid, previously accepted as positional with 'designator' ignored.  */
+C f = {{[0]="a"}}; // { dg-error "C99 designator .0. outside aggregate initializer" }
+C g = {{.a="a"}}; // { dg-error "C99 designator .a. outside aggregate initializer" }
+C h = {{.b="a"}}; // { dg-error "C99 designator .b. outside aggregate initializer" }
+
+char a2[][10] = { [0] = { "aaa" } };
+
+struct D { C c; int a[8]; };
+
+D x = { .c {.a={"a"}}, .a={1,2,3,4,5,6,7,8} };
+
+struct A { union { int a; char c[4]; }; };
+
+A non = { .c = "c++" };
+
+template <class T>
+void t()
+{
+  C ca[] = { {.a=""}, {.a={""}}, };
+
+}
+
+void u()
+{
+  return t<void>();
+}
-- 
2.31.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 2/3] c++: P1997 array-copy extensions: Initialization [PR103238]
  2021-11-22  2:51 [PATCH 0/3] P1997 'array-copy' patchset [PR103238] Will Wray
  2021-11-22  2:51 ` [PATCH 1/3] c++: designated init of char array by string constant [PR55227] Will Wray
@ 2021-11-22  2:51 ` Will Wray
  2021-11-27 22:56   ` Jason Merrill
  2021-11-22  2:51 ` [PATCH 3/3] c++: P1997 array-copy extensions: Assignment, return, etc. [PR103238] Will Wray
  2 siblings, 1 reply; 9+ messages in thread
From: Will Wray @ 2021-11-22  2:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: Will Wray

This patch implements initializations of arrays from array values.

The first of two 'array-copy' patches, it adds the option -farray-copy
(flag_array_copy) to enable all features of P1997 (copy related or not),
documented as experimental extensions.

It deals with initialization of array variables and member array fields.

Initialization of an array variable from an array of the same type performs
array copy-initialization; elementwise move or copy from an rvalue or lvalue
array respectively, in index order from begin to end. The existing code path
for a structured binding declaration with array initializer, auto[e...]{a};
performs the same array copy-initialization (as a special case superpower).
Borrowing from that, this was a relatively quick and easy change.

Initialization of member arrays proved much more difficult to do in general.
I resorted to trial and error, running gcc in gdb with test cases to work out
where and what to change, until eventually converging on this set of changes.

One starting point was the C special case of char array initialization from
string literals (as char array lvalue constants). However, a long-standing
bug in designated initialization of char arrays by string literals blocked
the task of extending this special case to general array type initializers.
A bugfix patch was separated out, to be merged ahead of these patches:

    https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55227
    https://gcc.gnu.org/pipermail/gcc-patches/2021-November/584897.html

Other cases to consider, array initializations:

    * by optionally brace-enclosed or paren-enclosed array values
    * by possibly-designated array-valued aggregate initializers
      (within possibly-elided braced init-lists)
    * by brace or paren-enclosed array values in member initialization lists
    * by array-valued member initializers

The patch adds tests for these cases, and for inner initializations of nested
array elements of array type.

The work has diverged in details from the P1997 wording, including catching
up with C++20 changes such as parenthesised initialization of aggregates.
The paper will be revised to reflect the implementation experience.

It is likely that there are omissions, errors in the conditions or that changed
code is inappropriate. For example, I inserted a new call to build_array_copy
in typeck2.c:digest_init_r which may not be correct for move-enabled elements.
Please review carefully with this in mind and suggest test cases to exercise.

	PR c++/103238

gcc/c-family/ChangeLog:

	* c-common.c (complete_array_type): Accept array type initial_value.
	* c.opt: New option -farray-copy "experimental extensions for P1997".

gcc/cp/ChangeLog:

	* decl.c (do_aggregate_paren_init): Accept single array type init.
	(maybe_deduce_size_from_array_init): Include same-type array inits,
	or complain for not same-type arrays.
	(reshape_init_r): Extend string-literal handling to all array types.
	* init.c (build_aggr_init): Follow existing path for array rhs.
	* typeck.c (cp_build_modify_expr): Follow path for synthetic op=.
	* typeck2.c (digest_init_r): Add call to build_array_copy for
	same-type arrays ('copy' feels wrong for move-eligible rhs).

gcc/ChangeLog:

	* doc/invoke.texi: -farray-copy help info documentation.

gcc/testsuite/ChangeLog:

	* g++.dg/init/array-copy1.C: New test. Variable init 'before' XFAILs
	* g++.dg/init/array-copy2.C: New test. Variable init 'after' PASSes
	* g++.dg/init/array-copy3.C: New test. Member init 'before' XFAILs
	* g++.dg/init/array-copy4.C: New test. Member init 'after' PASSes
	* g++.dg/init/array-copy5.C: New test. Member nsdmi & desig XFAILs
	* g++.dg/init/array-copy6.C: New test. Member nsdmi & desig PASSes
---
 gcc/c-family/c-common.c                 |  5 +++
 gcc/c-family/c.opt                      |  4 ++
 gcc/cp/decl.c                           | 61 ++++++++++++++++++++---------
 gcc/cp/init.c                           |  6 ++-
 gcc/cp/typeck.c                         |  9 +++--
 gcc/cp/typeck2.c                        | 30 +++++++++++----
 gcc/doc/invoke.texi                     |  6 +++
 gcc/testsuite/g++.dg/init/array-copy1.C | 66 ++++++++++++++++++++++++++++++++
 gcc/testsuite/g++.dg/init/array-copy2.C | 68 +++++++++++++++++++++++++++++++++
 gcc/testsuite/g++.dg/init/array-copy3.C | 41 ++++++++++++++++++++
 gcc/testsuite/g++.dg/init/array-copy4.C | 42 ++++++++++++++++++++
 gcc/testsuite/g++.dg/init/array-copy5.C | 36 +++++++++++++++++
 gcc/testsuite/g++.dg/init/array-copy6.C | 51 +++++++++++++++++++++++++
 13 files changed, 395 insertions(+), 30 deletions(-)

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 86c007f53de..fb0b1ef294f 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -6796,6 +6796,11 @@ complete_array_type (tree *ptype, tree initial_value, bool do_default)
 	    = int_size_in_bytes (TREE_TYPE (TREE_TYPE (initial_value)));
 	  maxindex = size_int (TREE_STRING_LENGTH (initial_value)/eltsize - 1);
 	}
+      else if (flag_array_copy
+	       && TREE_CODE (TREE_TYPE (initial_value)) == ARRAY_TYPE)
+	{
+	  maxindex = array_type_nelts (TREE_TYPE (initial_value));
+	}
       else if (TREE_CODE (initial_value) == CONSTRUCTOR)
 	{
 	  vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (initial_value);
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 3976fc368db..9d2a6ad8e1c 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -1579,6 +1579,10 @@ fcilkplus
 C ObjC C++ ObjC++ LTO Undocumented Ignore
 Removed in GCC 8.  This switch has no effect.
 
+farray-copy
+C ObjC C++ ObjC++ Var(flag_array_copy)
+Enable experimental extension for P1997; C array copy semantics.
+
 fconcepts
 C++ ObjC++ Var(flag_concepts)
 Enable support for C++ concepts.
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 83a2d3bf8f1..1010fa2c53f 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5834,15 +5834,19 @@ tree
 do_aggregate_paren_init (tree init, tree type)
 {
   tree val = TREE_VALUE (init);
+  tree stripped_val = tree_strip_any_location_wrapper (val);
 
   if (TREE_CHAIN (init) == NULL_TREE)
     {
       /* If the list has a single element and it's a string literal,
 	 then it's the initializer for the array as a whole.  */
-      if (TREE_CODE (type) == ARRAY_TYPE
-	  && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type)))
-	  && TREE_CODE (tree_strip_any_location_wrapper (val))
-	     == STRING_CST)
+      if ((TREE_CODE (type) == ARRAY_TYPE
+	   && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type)))
+	   && TREE_CODE (stripped_val) == STRING_CST)
+	  || (flag_array_copy
+	      && TREE_CODE (TREE_TYPE (stripped_val)) == ARRAY_TYPE
+	      && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (type),
+					TREE_TYPE (TREE_TYPE (stripped_val)))))
 	return val;
       /* Handle non-standard extensions like compound literals.  This also
 	 prevents triggering aggregate parenthesized-initialization in
@@ -6007,9 +6011,10 @@ maybe_deduce_size_from_array_init (tree decl, tree init)
 {
   tree type = TREE_TYPE (decl);
 
-  if (TREE_CODE (type) == ARRAY_TYPE
-      && TYPE_DOMAIN (type) == NULL_TREE
-      && TREE_CODE (decl) != TYPE_DECL)
+  if (TREE_CODE (type) != ARRAY_TYPE
+      || TREE_CODE (decl) == TYPE_DECL)
+    ;
+  else if (TYPE_DOMAIN (type) == NULL_TREE)
     {
       /* do_default is really a C-ism to deal with tentative definitions.
 	 But let's leave it here to ease the eventual merge.  */
@@ -6072,6 +6077,17 @@ maybe_deduce_size_from_array_init (tree decl, tree init)
 
       relayout_decl (decl);
     }
+  else if (flag_array_copy && init
+	   && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE
+	   && TREE_CODE (tree_strip_any_location_wrapper (init)) != STRING_CST
+	   && !same_type_ignoring_top_level_qualifiers_p (type,
+							  TREE_TYPE (init)))
+    {
+      error_at (DECL_SOURCE_LOCATION (decl),
+		"array of type %qT cannot be initialized with an "
+		"array of type %qT in %qD", type, TREE_TYPE (init), decl);
+      TREE_TYPE (decl) = error_mark_node;
+    }
 }
 
 /* Set DECL_SIZE, DECL_ALIGN, etc. for DECL (a VAR_DECL), and issue
@@ -6815,21 +6831,23 @@ reshape_init_r (tree type, reshape_iter *d, tree first_initializer_p,
       return init;
     }
 
-  /* [dcl.init.string]
+  /* [dcl.init.string] or flag_array_copy extension P1997
 
       A char array (whether plain char, signed char, or unsigned char)
       can be initialized by a string-literal (optionally enclosed in
       braces); a wchar_t array can be initialized by a wide
-      string-literal (optionally enclosed in braces).  */
-  if (TREE_CODE (type) == ARRAY_TYPE
-      && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type))))
+      string-literal (optionally enclosed in braces).
+      With flag_array_copy an array can be initialized by an array value
+      (optionally enclosed in braces).  */
+  if (TREE_CODE (type) == ARRAY_TYPE)
     {
       tree arr_init = init;
       tree stripped_arr_init = stripped_init;
       reshape_iter stripd = {};
 
-      /* Strip one level of braces if and only if they enclose a single
-	 element (as allowed by [dcl.init.string]).  */
+      /* Strip one level of braces if they enclose a single element,
+	 provisionally for elison in the optionally-braced case if the
+	 initializer is of compatible array type, as checked next. */
       if (!first_initializer_p
 	  && TREE_CODE (stripped_arr_init) == CONSTRUCTOR
 	  && CONSTRUCTOR_NELTS (stripped_arr_init) == 1)
@@ -6839,10 +6857,19 @@ reshape_init_r (tree type, reshape_iter *d, tree first_initializer_p,
 	  stripped_arr_init = tree_strip_any_location_wrapper (arr_init);
 	}
 
-      /* If it's a string literal, then it's the initializer for the array
-	 as a whole. Otherwise, continue with normal initialization for
-	 array types (one value per array element).  */
-      if (TREE_CODE (stripped_arr_init) == STRING_CST)
+      tree init_type = TREE_TYPE (stripped_arr_init);
+
+      /* If it's a string literal initializer for a char array target,
+	 or, with flag_array_copy, an array value of same element type,
+	 then it's the initializer for the array as a whole.
+	 Else, continue with element by element array initialization.  */
+      if ((TREE_CODE (stripped_arr_init) == STRING_CST
+	   && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type))))
+	  || (flag_array_copy
+	      && TREE_CODE (init_type) == ARRAY_TYPE
+	      && TYPE_DOMAIN (init_type) != NULL_TREE
+	      && same_type_ignoring_top_level_qualifiers_p (
+				TREE_TYPE (type), TREE_TYPE (init_type))))
 	{
 	  if ((first_initializer_p && has_designator_problem (d, complain))
 	      || (stripd.cur && has_designator_problem (&stripd, complain)))
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 3ba2e3bbe04..fd9a065ed95 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1787,7 +1787,11 @@ build_aggr_init (tree exp, tree init, int flags, tsubst_flags_t complain)
       tree itype = init ? TREE_TYPE (init) : NULL_TREE;
       int from_array = 0;
 
-      if (VAR_P (exp) && DECL_DECOMPOSITION_P (exp))
+      if (VAR_P (exp)
+	  && (DECL_DECOMPOSITION_P (exp)
+	      || (flag_array_copy
+		  && TREE_CODE (tree_strip_any_location_wrapper (init))
+		     != STRING_CST)))
 	{
 	  from_array = 1;
 	  init = mark_rvalue_use (init);
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index cb20329ceb5..8e96a925186 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -9144,11 +9144,12 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
 	}
 
       /* Allow array assignment in compiler-generated code.  */
-      else if (!current_function_decl
-	       || !DECL_DEFAULTED_FN (current_function_decl))
+      else if ((!current_function_decl
+		|| !DECL_DEFAULTED_FN (current_function_decl))
+	       && !flag_array_copy)
 	{
-          /* This routine is used for both initialization and assignment.
-             Make sure the diagnostic message differentiates the context.  */
+	  /* This routine is used for both initialization and assignment.
+	     Make sure the diagnostic message differentiates the context.  */
 	  if (complain & tf_error)
 	    {
 	      if (modifycode == INIT_EXPR)
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index e98fbf7f5fa..20d46716279 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -1175,6 +1175,9 @@ digest_init_r (tree type, tree init, int nested, int flags,
 	    }
 	  return init;
 	}
+      if (flag_array_copy
+	  && same_type_ignoring_top_level_qualifiers_p(type, TREE_TYPE (init)))
+	return build_array_copy(init);
     }
 
   /* Handle scalar types (including conversions) and references.  */
@@ -1244,13 +1247,18 @@ digest_init_r (tree type, tree init, int nested, int flags,
 				     complain);
   else
     {
-      if (COMPOUND_LITERAL_P (stripped_init) && code == ARRAY_TYPE)
+      if (COMPOUND_LITERAL_P (stripped_init) && code == ARRAY_TYPE
+	  && (complain & tf_error))
 	{
-	  if (complain & tf_error)
-	    error_at (loc, "cannot initialize aggregate of type %qT with "
-		      "a compound literal", type);
-
-	  return error_mark_node;
+	  if (flag_array_copy)
+	    pedwarn (loc, OPT_Wpedantic, "ISO C++ doesn%'t allow initialization"
+		     "of an array of type %qT with a compound literal", type);
+	  else
+	    {
+	      error_at (loc, "cannot initialize aggregate of type %qT with "
+			     "a compound literal", type);
+	      return error_mark_node;
+	    }
 	}
 
       if (code == ARRAY_TYPE
@@ -1265,8 +1273,14 @@ digest_init_r (tree type, tree init, int nested, int flags,
 	    return init;
 
 	  if (complain & tf_error)
-	    error_at (loc, "array must be initialized with a brace-enclosed"
-		      " initializer");
+	  {
+	    if (!flag_array_copy)
+	      error_at (loc, "array must be initialized with a brace-enclosed"
+			     " initializer");
+	    else
+	      error_at (loc, "array must be initialized with a brace-enclosed"
+			     " initializer or an array value of the same type");
+	    }
 	  return error_mark_node;
 	}
 
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index d62ec08150e..32a34ca74bb 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -213,6 +213,7 @@ in the following sections.
 @xref{C++ Dialect Options,,Options Controlling C++ Dialect}.
 @gccoptlist{-fabi-version=@var{n}  -fno-access-control @gol
 -faligned-new=@var{n}  -fargs-in-order=@var{n}  -fchar8_t  -fcheck-new @gol
+-farray-copy @gol
 -fconstexpr-depth=@var{n}  -fconstexpr-cache-depth=@var{n} @gol
 -fconstexpr-loop-limit=@var{n}  -fconstexpr-ops-limit=@var{n} @gol
 -fno-elide-constructors @gol
@@ -3001,6 +3002,11 @@ return value even without this option.  In all other cases, when
 exhaustion is signalled by throwing @code{std::bad_alloc}.  See also
 @samp{new (nothrow)}.
 
+@item -farray-copy
+@opindex farray-copy
+Enables experimental support for P1997; C array copy semantics, pseudo-
+destructors and auto placeholder for array element type.
+
 @item -fconcepts
 @itemx -fconcepts-ts
 @opindex fconcepts
diff --git a/gcc/testsuite/g++.dg/init/array-copy1.C b/gcc/testsuite/g++.dg/init/array-copy1.C
new file mode 100644
index 00000000000..15986a00d1b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/array-copy1.C
@@ -0,0 +1,66 @@
+// PR c++/103238 (array-copy extensions for P1997)
+// Array variable initialization nocompile tests -
+// should give same errors before and after the array-copy patch.
+
+// { dg-do compile { target c++11 } } c++11 for uniform init
+
+typedef int int2[2];
+int2 u = {11,66};
+
+int* p = new int2{u}; // { dg-error "invalid conversion from .int\\*. to .int. .\\-fpermissive." }
+
+// Initializations from from rvalue array
+int2 g = int2{11,66};
+int2 j ( int2{11,66} );  // takes P0960 paren-init path in c++20
+int2 k = { int2{11,66} };
+int2 l { int2{11,66} };
+// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-4 }
+// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-4 }
+// { dg-error "taking address of temporary array" "address of temporary" { target *-*-* } .-4 }
+// { dg-error "taking address of temporary array" "address of temporary" { target *-*-* } .-4 }
+
+// Initializations from from lvalue array
+int2 gc = u;
+int2 jc (u);  // takes P0960 paren-init path in c++20
+int2 kc = {u};
+int2 lc {u};
+// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-4 }
+// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-4 }
+// { dg-error "invalid conversion from .int\\*. to .int. .\\-fpermissive." "bad conv" { target *-*-* } .-4 }
+// { dg-error "invalid conversion from .int\\*. to .int. .\\-fpermissive." "bad conv" { target *-*-* } .-4 }
+
+char str[] = "str";
+
+char cpy[] = str;
+char cpp[] (str); // takes P0960 paren-init path in c++20
+char cpu[] = {str};
+char cpw[] {str};
+// { dg-error "initializer fails to determine size of .cpy." "deduce size" { target *-*-*  } .-4 }
+// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-5 }
+// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target c++17_down } .-5 }
+// { dg-error "initializer fails to determine size of .cpp." "deduce size" { target c++17_down  } .-6 }
+// { dg-error "invalid conversion from .char\\*. to .char. .\\-fpermissive." "bad conv" { target c++20 } .-7 }
+// { dg-error "invalid conversion from .char\\*. to .char. .\\-fpermissive." "bad conv" { target *-*-* } .-7 }
+// { dg-error "invalid conversion from .char\\*. to .char. .\\-fpermissive." "bad conv" { target *-*-* } .-7 }
+
+char cp5[5] = str;
+char cp3[3] = str;
+// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-2 }
+// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-2 }
+
+int2 s[2] = { u };
+// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-1 }
+int2 x[2] = { u
+	    , u };
+// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-2 }
+// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-2 }
+int2 y[2] = { 1,2
+	    , {u} };
+// { dg-error "invalid conversion from .int\\*. to .int. .\\-fpermissive." "bad conv" { target *-*-* } .-1 }
+int2 z[2] = { {u},
+	       3,{4} };
+// { dg-error "invalid conversion from .int\\*. to .int. .\\-fpermissive." "bad conv" { target *-*-* } .-2 }
+
+__UINT8_TYPE__ m222[2][2][2] {0,1,2,3,4,5,6,7};
+__UINT8_TYPE__ c222[2][2][2] { m222[0], m222[1][0], 6,7 };
+// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/init/array-copy2.C b/gcc/testsuite/g++.dg/init/array-copy2.C
new file mode 100644
index 00000000000..7e1ad23592b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/array-copy2.C
@@ -0,0 +1,68 @@
+// PR c++/103238 (array-copy extensions for P1997)
+// Array variable initialization compile tests, -farray-copy enabled
+// (c.f. array-copy1.C for compile fail tests)
+
+// { dg-do compile { target c++11 } }  c++11 for uniform init
+// { dg-additional-options "-farray-copy" }
+
+typedef int int2[2];
+int2 u = {11,66};
+
+int* p = new int2{u};
+
+// Initializations from from rvalue array
+int2 g = int2{11,66};
+int2 j ( int2{11,66} );  // takes P0960 paren-init path in c++20
+int2 k = { int2{11,66} };
+int2 l { int2{11,66} };
+
+// Initializations from from lvalue array
+int2 gc = u;
+int2 jc (u);  // takes P0960 paren-init path in c++20
+int2 kc = {u};
+int2 lc {u};
+
+char str[] = "str";
+
+char cpy[] = str;
+char cpp[] (str);  // takes P0960 paren-init path in c++20
+char cpu[] = {str};
+char cpw[] {str};
+
+char cp5[5] = str;
+char cp3[3] = str;
+// { dg-error "array of type .char .5.. cannot be initialized with an array of type .char .4.." "" { target *-*-* } .-2 }
+// { dg-error "array of type .char .3.. cannot be initialized with an array of type .char .4.." "" { target *-*-* } .-2 }
+
+constexpr char cstr[] = "str";
+constexpr char ccpy[] = cstr;
+static_assert(
+      __builtin_bit_cast(__UINT32_TYPE__, ccpy)
+   == __builtin_bit_cast(__UINT32_TYPE__, "str")
+, ""
+);
+
+constexpr __UINT32_TYPE__ ci[] = {11,66};
+constexpr __UINT32_TYPE__ cc[] = ci;
+static_assert(
+      __builtin_bit_cast(__UINT64_TYPE__, ci)
+   == __builtin_bit_cast(__UINT64_TYPE__, cc)
+, ""
+);
+
+int2 s[2] = { u };
+int2 x[2] = { u
+	    , u };
+int2 y[2] = { 1,2
+	    , {u} };
+int2 z[2] = { {u}
+	   , 3,{4} };
+
+__UINT8_TYPE__ m222[2][2][2] {0,1,2,3,4,5,6,7};
+__UINT8_TYPE__ c222[2][2][2] { m222[0], m222[1][0], 6,7 };
+
+int main() {
+  if (__builtin_bit_cast(__UINT64_TYPE__, m222)
+   != __builtin_bit_cast(__UINT64_TYPE__, c222))
+      __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/init/array-copy3.C b/gcc/testsuite/g++.dg/init/array-copy3.C
new file mode 100644
index 00000000000..bec78cb8435
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/array-copy3.C
@@ -0,0 +1,41 @@
+// PR c++/103238 (array-copy extensions for P1997)
+// Array member initialization nocompile tests -
+// should give same errors before and after the array-copy patch.
+
+// { dg-do compile { target c++11 } } c++11 for uniform init
+//
+
+typedef int int2[2];
+
+struct A { int2 a; };
+
+A ad { int2{11,66} }; // { dg-error "array must be initialized with a brace-enclosed initializer" }
+A ai = { int2{11,66} }; // { dg-error "array must be initialized with a brace-enclosed initializer" }
+
+struct B { int2 a, b, c, d; };
+
+constexpr
+B b {
+    {11,66}
+  , {b.a} // { dg-error "invalid conversion from .const int\\*. to .int. .\\-fpermissive." }
+  , (b.b) // { dg-error "array must be initialized with a brace-enclosed initializer" }
+  ,  b.c
+};
+
+struct C {
+  int2 a, b, c;
+  C(const int2& r = {11,66})
+   : a{r} // { dg-error "invalid conversion from .const int\\*. to .int. .\\-fpermissive." }
+   , b(a) // { dg-error "array used as initializer" }
+   , c{b} // { dg-error "invalid conversion from .int\\*. to .int. .\\-fpermissive." }
+     {}
+};
+
+// Not a test; a workaround to construct a single array member from array
+struct D {
+  int2 d;
+  constexpr D(const int2& r = {})
+   : D{__builtin_bit_cast(D,r)} {}
+};
+constexpr D d{{11,66}};
+constexpr D e{b.a};
diff --git a/gcc/testsuite/g++.dg/init/array-copy4.C b/gcc/testsuite/g++.dg/init/array-copy4.C
new file mode 100644
index 00000000000..8db2852011a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/array-copy4.C
@@ -0,0 +1,42 @@
+// PR c++/103238 (array-copy extensions for P1997)
+// Array member initialization compile tests -
+// (c.f. array-copy3.C for compile fail tests)
+
+// { dg-do compile { target c++11 } } c++11 for uniform init
+// { dg-additional-options "-farray-copy" }
+
+typedef int int2[2];
+
+struct A { int2 a; };
+
+A ad { int2{11,66} };
+A ai = { int2{11,66} };
+
+struct B { int2 a, b, c, d; };
+
+constexpr
+B b {
+    {11,66}
+  , {b.a}
+  , (b.b)
+  ,  b.c
+};
+
+struct C {
+  int2 a, b, c;
+  C(const int2& r = {11,66})
+   : a{r}
+   , b(a)
+   , c{b}
+     {}
+};
+
+template<class T>
+constexpr int equal(T const& a, T const& b) {
+  using bytes = unsigned char[sizeof(T)];
+  return __builtin_memcmp(
+         __builtin_bit_cast(bytes,a),
+         __builtin_bit_cast(bytes,b),
+         sizeof(T)) == 0;
+}
+static_assert( equal(b, B{{11,66},{11,66},{11,66},{11,66}}), "");
diff --git a/gcc/testsuite/g++.dg/init/array-copy5.C b/gcc/testsuite/g++.dg/init/array-copy5.C
new file mode 100644
index 00000000000..a3b6c275f2b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/array-copy5.C
@@ -0,0 +1,36 @@
+// PR c++/103238 (array-copy extensions for P1997)
+// Array member initialization nocompile tests, nsdmi and designated init
+// should give same errors before and after the array-copy patch.
+
+// { dg-do compile { target c++14 } } c++14 for aggregate with member inits
+// { dg-options "" }
+//
+
+typedef int int2[2];
+
+struct A { int2 a = int2{11,66}; }; // { dg-error "array must be initialized with a brace-enclosed initializer" }
+
+constexpr
+A a { .a = int2{11,66} }; // { dg-error "array must be initialized with a brace-enclosed initializer" }
+A y = { .a{int2{11,66}} }; // { dg-error "taking address of temporary array" }
+
+struct B {
+  int2 a = {11,66};
+  int2 b = a; // { dg-error "array must be initialized with a brace-enclosed initializer" }
+  int2 c = {b}; // { dg-error "invalid conversion from .int\\*. to .int. .\\-fpermissive." }
+  int2 d {c}; // { dg-error "invalid conversion from .int\\*. to .int. .\\-fpermissive." }
+};
+
+constexpr
+B b {
+    {11,66}
+  , {b.a} // { dg-error "invalid conversion from .const int\\*. to .int. .\\-fpermissive." }
+  , (b.b) // { dg-error "array must be initialized with a brace-enclosed initializer" }
+  ,  b.c
+};
+
+B bd { .a{11,66}, .b = bd.a, .c {bd.b}, .d = {bd.c} }; // { dg-error "array must be initialized with a brace-enclosed initializer" }
+
+struct D : A {
+  B b {.a{11,66}, .b = b.a, .c {b.b}, .d = {b.c}}; // { dg-error "array must be initialized with a brace-enclosed initializer" }
+};
diff --git a/gcc/testsuite/g++.dg/init/array-copy6.C b/gcc/testsuite/g++.dg/init/array-copy6.C
new file mode 100644
index 00000000000..09b7478e07f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/array-copy6.C
@@ -0,0 +1,51 @@
+// PR c++/103238 (array-copy extensions for P1997)
+// Array member initialization compile tests, nsdmi and designated init
+// (c.f. array-copy5.C for compile fail tests)
+
+// { dg-do compile { target c++20 } }
+//
+// { dg-additional-options "-farray-copy" }
+
+typedef int int2[2];
+
+struct A { int2 a = int2{11,66}; };
+
+constexpr
+A a { .a = int2{11,66} };
+A y = { .a{int2{11,66}} };
+
+struct B {
+  int2 a = {11,66};
+  int2 b = a;
+  int2 c = {b};
+  int2 d {c};
+};
+
+constexpr
+B b {
+    {11,66}
+  , {b.a}
+  , (b.b)
+  ,  b.c
+};
+
+B bd { .a{11,66}, .b = bd.a, .c {bd.b}, .d = {bd.c} };
+
+struct D : A {
+  B b {.a{11,66}, .b = b.a, .c {b.b}, .d = {b.c}};
+};
+
+constexpr
+D d;
+
+template<class T>
+constexpr int equal(T const& a, T const& b) {
+  using bytes = unsigned char[sizeof(T)];
+  return __builtin_memcmp(
+         __builtin_bit_cast(bytes,a),
+         __builtin_bit_cast(bytes,b),
+         sizeof(T)) == 0;
+}
+static_assert( equal(b, B{}), "");
+static_assert( equal(d, D{}), "");
+static_assert( equal(d, D{a,b}), "");
-- 
2.31.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 3/3] c++: P1997 array-copy extensions: Assignment, return, etc. [PR103238]
  2021-11-22  2:51 [PATCH 0/3] P1997 'array-copy' patchset [PR103238] Will Wray
  2021-11-22  2:51 ` [PATCH 1/3] c++: designated init of char array by string constant [PR55227] Will Wray
  2021-11-22  2:51 ` [PATCH 2/3] c++: P1997 array-copy extensions: Initialization [PR103238] Will Wray
@ 2021-11-22  2:51 ` Will Wray
  2021-11-22 20:41   ` Joseph Myers
  2021-11-29 22:44   ` Jason Merrill
  2 siblings, 2 replies; 9+ messages in thread
From: Will Wray @ 2021-11-22  2:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: Will Wray

This second patch completes the work of the first 'array-copy' patch to
provide first-cut implementations of all P1997 features. It adds:

 * Assignments to arrays from array values,    a = b;
 * Placeholder auto in array declarations,     auto cp[] = a;
 * Array as a return type from functions WIP,  auto f() -> T[N];
 * Parsing of array pseudo-destructors         a.~A()
   (only parsing for now, untested)

Assignments a = b were easily allowed by changing branch conditions.
Assignments a = {e...} were trickier (a case not mentioned in P1997):

    int a[16]; a = {0,1,1,2}; a = {}; // assignments from init-lists

The semantics is the same as for struct aggregates:
(1) Aggregate initialization of an rhs array of the lhs type
    (so trailing elements with no initializer are value initialized)
(2) Copy-initialization of the lhs from the rhs.

The special case of an optionally-braced array value is allowed so that
a = b and a = {b} are generally equivalent for same type arrays a and b.
However, the now special-special case of assignment from a braced string-
literal currently only supports exact-match (same as for other arrays):

    char a[4]; a={"c++"} /* OK */; a={"c"} /* FAILs but should work */;

Array return from function is work in progress. The tests show what works.
I'm stuck in unfamiliar territory so it's best to submit what I have to be
reviewed for hints on how to progress.

Please try the patch; play, stress it, and report the FAILS.

	PR c++/103238

gcc/c/ChangeLog:

	* c-decl.c (grokdeclarator): Don't complain of array returns.

gcc/cp/ChangeLog:

	* call.c (can_convert_array): Extend to include array inits.
	(standard_conversion): No decay for same-type array. Call build_conv.
	(implicit_conversion_1): Call reshape_init for arrays too.
	* decl.c (grokdeclarator): Don't complain of array returns.
	* parser.c (cp_parser_postfix_dot_deref_expression): parse array ~A().
	* pt.c (tsubst_function_type): Array type return is not a failure.
	(do_auto_deduction): Placeholder auto deduction of array element type.
	* tree.c (lvalue_kind): clk_class should include array (I think?).
	* typeck.c (cp_build_modify_expr): Call reshape init to strip optional
	braces. Allow NOP_EXPR for array assignment.
	(convert_for_assignment): New if-block for same-type array convert,
	strips optional braces, but rejects STRING_CST rhs shorter than lhs.

gcc/testsuite/ChangeLog:

	* g++.dg/init/array-copy10.C: New test. auto[] deduce 'after' PASSes
	* g++.dg/init/array-copy11.C: New test. Array return 'before' XFAILs
	* g++.dg/init/array-copy12.C: New test. Array return 'after' PASSes
	* g++.dg/init/array-copy7.C: New test. Array assign 'before' XFAILs
	* g++.dg/init/array-copy8.C: New test. Array assign 'after' PASSes
	* g++.dg/init/array-copy9.C: New test. auto[] deduce 'before' XFAILs
---
 gcc/c/c-decl.c                           |  2 +-
 gcc/cp/call.c                            | 43 +++++++++++------
 gcc/cp/decl.c                            |  2 +-
 gcc/cp/parser.c                          |  4 +-
 gcc/cp/pt.c                              | 13 +++++-
 gcc/cp/tree.c                            |  3 +-
 gcc/cp/typeck.c                          | 26 +++++++++--
 gcc/testsuite/g++.dg/init/array-copy10.C | 57 +++++++++++++++++++++++
 gcc/testsuite/g++.dg/init/array-copy11.C | 13 ++++++
 gcc/testsuite/g++.dg/init/array-copy12.C | 79 ++++++++++++++++++++++++++++++++
 gcc/testsuite/g++.dg/init/array-copy7.C  | 40 ++++++++++++++++
 gcc/testsuite/g++.dg/init/array-copy8.C  | 56 ++++++++++++++++++++++
 gcc/testsuite/g++.dg/init/array-copy9.C  | 57 +++++++++++++++++++++++
 13 files changed, 372 insertions(+), 23 deletions(-)

diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 3e28a038095..031c43d189f 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -7055,7 +7055,7 @@ grokdeclarator (const struct c_declarator *declarator,
 			    "returning a function");
 		type = integer_type_node;
 	      }
-	    if (TREE_CODE (type) == ARRAY_TYPE)
+	    if (TREE_CODE (type) == ARRAY_TYPE && !flag_array_copy)
 	      {
 		if (name)
 		  error_at (loc, "%qE declared as function returning an array",
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 4ee21c7bdbd..c73fb73d86e 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -908,29 +908,34 @@ static bool
 can_convert_array (tree atype, tree from, int flags, tsubst_flags_t complain)
 {
   tree elttype = TREE_TYPE (atype);
-  unsigned i;
 
   if (TREE_CODE (from) == CONSTRUCTOR)
     {
-      for (i = 0; i < CONSTRUCTOR_NELTS (from); ++i)
+      for (auto&& ce : CONSTRUCTOR_ELTS (from))
 	{
-	  tree val = CONSTRUCTOR_ELT (from, i)->value;
-	  bool ok;
-	  if (TREE_CODE (elttype) == ARRAY_TYPE)
-	    ok = can_convert_array (elttype, val, flags, complain);
-	  else
-	    ok = can_convert_arg (elttype, TREE_TYPE (val), val, flags,
-				  complain);
-	  if (!ok)
+	  tree val = tree_strip_any_location_wrapper (ce.value);
+	  if ((TREE_CODE (val) == STRING_CST
+	       && !can_convert_array (elttype, val, flags, complain))
+	      || (TREE_CODE (elttype) == ARRAY_TYPE
+		  ? !can_convert_array (elttype, val, flags, complain)
+		  : !can_convert_arg (elttype, TREE_TYPE (val), val, flags,
+				      complain)))
 	    return false;
 	}
       return true;
     }
 
+  from = tree_strip_any_location_wrapper (from);
+
   if (char_type_p (TYPE_MAIN_VARIANT (elttype))
-      && TREE_CODE (tree_strip_any_location_wrapper (from)) == STRING_CST)
+      && TREE_CODE (from) == STRING_CST)
     return array_string_literal_compatible_p (atype, from);
 
+  if (flag_array_copy
+      && TREE_CODE (from) == ARRAY_TYPE)
+    return same_type_ignoring_top_level_qualifiers_p (atype,
+			   tree_strip_any_location_wrapper (from));
+
   /* No other valid way to aggregate initialize an array.  */
   return false;
 }
@@ -1241,7 +1246,10 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
   tcode = TREE_CODE (to);
 
   conv = build_identity_conv (from, expr);
-  if (fcode == FUNCTION_TYPE || fcode == ARRAY_TYPE)
+  if (fcode == FUNCTION_TYPE
+      || (fcode == ARRAY_TYPE
+	  && !(flag_array_copy && tcode == ARRAY_TYPE
+	       && same_type_ignoring_top_level_qualifiers_p (to, from))))
     {
       from = type_decays_to (from);
       fcode = TREE_CODE (from);
@@ -1538,6 +1546,10 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
   else if (fcode == VECTOR_TYPE && tcode == VECTOR_TYPE
 	   && vector_types_convertible_p (from, to, false))
     return build_conv (ck_std, to, conv);
+  else if (flag_array_copy
+	   && fcode == ARRAY_TYPE && tcode == ARRAY_TYPE
+	   && same_type_ignoring_top_level_qualifiers_p (from, to))
+    return build_conv (ck_std, to, conv);
   else if (MAYBE_CLASS_TYPE_P (to) && MAYBE_CLASS_TYPE_P (from)
 	   && is_properly_derived_from (from, to))
     {
@@ -2015,9 +2027,10 @@ implicit_conversion_1 (tree to, tree from, tree expr, bool c_cast_p,
 
   /* Call reshape_init early to remove redundant braces.  */
   if (expr && BRACE_ENCLOSED_INITIALIZER_P (expr)
-      && CLASS_TYPE_P (to)
-      && COMPLETE_TYPE_P (complete_type (to))
-      && !CLASSTYPE_NON_AGGREGATE (to))
+      && ((CLASS_TYPE_P (to)
+	  && COMPLETE_TYPE_P (complete_type (to))
+	  && !CLASSTYPE_NON_AGGREGATE (to))
+	 || (flag_array_copy && TREE_CODE (to) == ARRAY_TYPE)))
     {
       expr = reshape_init (to, expr, complain);
       if (expr == error_mark_node)
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 1010fa2c53f..872403b1ac1 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -12719,7 +12719,7 @@ grokdeclarator (const cp_declarator *declarator,
 			  "a function", name);
 		return error_mark_node;
 	      }
-	    if (TREE_CODE (type) == ARRAY_TYPE)
+	    if (TREE_CODE (type) == ARRAY_TYPE && !flag_array_copy)
 	      {
 		error_at (typespec_loc, "%qs declared as function returning "
 			  "an array", name);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 65f0f112011..5dd6126dc50 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -8120,7 +8120,9 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser,
      we must be looking at a pseudo-destructor-name.  If POSTFIX_EXPRESSION
      is type dependent, it can be pseudo-destructor-name or something else.
      Try to parse it as pseudo-destructor-name first.  */
-  if ((scope && SCALAR_TYPE_P (scope)) || dependent_p)
+  if ((scope && (SCALAR_TYPE_P (scope)
+		 || (flag_array_copy && TREE_CODE (scope) == ARRAY_TYPE)))
+      || dependent_p) /* TODO: P1997 array pseudo-destructor.  */
     {
       tree s;
       tree type;
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index b27eea33272..66ed90699cd 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -15152,7 +15152,7 @@ tsubst_function_type (tree t,
     return error_mark_node;
   /* DR 486 clarifies that creation of a function type with an
      invalid return type is a deduction failure.  */
-  if (TREE_CODE (return_type) == ARRAY_TYPE
+  if ((TREE_CODE (return_type) == ARRAY_TYPE && !flag_array_copy)
       || TREE_CODE (return_type) == FUNCTION_TYPE)
     {
       if (complain & tf_error)
@@ -29812,6 +29812,17 @@ do_auto_deduction (tree type, tree init, tree auto_node,
       targs = make_tree_vec (1);
       TREE_VEC_ELT (targs, 0) = TREE_TYPE (init);
     }
+  else if (flag_array_copy
+	   && (context == adc_variable_type
+	       || context == adc_return_type)
+	   && auto_node == TREE_TYPE (type)
+	   && !TYPE_REF_P (type)
+	   && init != error_mark_node
+	   && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE)
+    {
+      targs = make_tree_vec (1);
+      TREE_VEC_ELT (targs, 0) = TREE_TYPE (TREE_TYPE (init));
+    }
   else if (AUTO_IS_DECLTYPE (auto_node))
     {
       tree stripped_init = tree_strip_any_location_wrapper (init);
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 32ddf835a91..e10c574de94 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -280,7 +280,8 @@ lvalue_kind (const_tree ref)
 
     case CALL_EXPR:
       /* We can see calls outside of TARGET_EXPR in templates.  */
-      if (CLASS_TYPE_P (TREE_TYPE (ref)))
+      if (CLASS_TYPE_P (TREE_TYPE (ref))
+	  || TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE)
 	return clk_class;
       return clk_none;
 
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 8e96a925186..e1a9446fd0f 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -9105,9 +9105,11 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
     {
       int from_array;
 
+      if (flag_array_copy && BRACE_ENCLOSED_INITIALIZER_P (newrhs))
+	newrhs = reshape_init (lhstype, newrhs, complain);
       if (BRACE_ENCLOSED_INITIALIZER_P (newrhs))
 	{
-	  if (modifycode != INIT_EXPR)
+	  if (modifycode != INIT_EXPR && !flag_array_copy)
 	    {
 	      if (complain & tf_error)
 		error_at (loc,
@@ -9127,7 +9129,8 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
       else if ((TREE_CODE (tree_strip_any_location_wrapper (newrhs))
 		== STRING_CST)
 	       && char_type_p (TREE_TYPE (TYPE_MAIN_VARIANT (lhstype)))
-	       && modifycode == INIT_EXPR)
+	       && (modifycode == INIT_EXPR
+		   || (modifycode == NOP_EXPR && flag_array_copy)))
 	{
 	  newrhs = digest_init (lhstype, newrhs, complain);
 	  if (newrhs == error_mark_node)
@@ -9682,7 +9685,24 @@ convert_for_assignment (tree type, tree rhs,
       rhs = mark_rvalue_use (rhs);
       return convert (type, rhs);
     }
-
+  /* Deal with array-valued rhs of same type as lhs 'type', optionally braced.
+     This includes STRING_CST, but only of same type - i.e. same size;
+     TODO: P1997 convert STRING_CST shorter than 'type' to full size.  */
+  if (flag_array_copy && TREE_CODE (type) == ARRAY_TYPE)
+    {
+      if (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (rhs)))
+	{
+	  rhs = mark_rvalue_use (rhs);
+	  return convert (type, rhs);
+	}
+      if (BRACE_ENCLOSED_INITIALIZER_P (rhs)
+	  && CONSTRUCTOR_NELTS (rhs) == 1
+	  && same_type_ignoring_top_level_qualifiers_p (type,
+	     TREE_TYPE (tree_strip_any_location_wrapper (
+					CONSTRUCTOR_ELT (rhs, 0)->value))))
+	return convert (type, mark_rvalue_use (
+					CONSTRUCTOR_ELT (rhs, 0)->value));
+    }
   if (rhs == error_mark_node || rhstype == error_mark_node)
     return error_mark_node;
   if (TREE_CODE (rhs) == TREE_LIST && TREE_VALUE (rhs) == error_mark_node)
diff --git a/gcc/testsuite/g++.dg/init/array-copy10.C b/gcc/testsuite/g++.dg/init/array-copy10.C
new file mode 100644
index 00000000000..5fc2df727fa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/array-copy10.C
@@ -0,0 +1,57 @@
+// PR c++/103238 (array-copy extensions for P1997)
+// Array auto placeholder element deduction compile tests
+// (c.f. array-copy9.C for compile fail tests)
+
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-farray-copy" }
+
+template <typename...> struct same{ enum:bool{v=false}; };
+template <typename T> struct same<T,T>{ enum:bool{v=true}; };
+template <typename T, typename X, typename...Y>
+struct same<T,X,Y...>{ enum:bool{v = same<T,X>::v && same<T,Y...>::v}; };
+template<typename...T>
+constexpr bool all_same_t(T const&...){return same<T...>::v;}
+
+typedef int int2[2];
+int2 a {11,66};
+
+auto er[2] {1,2};
+// { dg-error "direct-list-initialization of .auto. requires exactly one element .\\-fpermissive." "" { target *-*-* } .-1 }
+// { dg-error "deducing from brace-enclosed initializer list requires" "" { target *-*-* } .-2 }
+auto il[2] = {1,2};
+// { dg-error "deducing from brace-enclosed initializer list requires" "" { target *-*-* } .-1 }
+auto um[2] = {a};
+// { dg-error "deducing from brace-enclosed initializer list requires" "" { target *-*-* } .-1 }
+
+// Initializations from from rvalue array
+auto g[2] = int2{11,66};
+auto j[2] ( int2{11,66} );  // P0960
+auto l[2] { int2{11,66} };
+// auto + size deduction :
+auto m[] = int2{11,66};
+auto n[] ( int2{11,66} );  // P0960
+auto p[] { int2{11,66} };
+
+static_assert( all_same_t(a,g,j,l,m,n,p), "");
+
+auto str[] = "str"; 
+
+auto cpy[4] = str;
+auto cpp[4] (str); // P0960
+auto cpw[4] {str};
+// auto + size deduction :
+auto cpu[] = str;
+auto cpv[] (str); // P0960
+auto cpx[] {str};
+
+static_assert( all_same_t(str,cpy,cpp,cpw,cpu,cpv,cpx), "");
+
+auto const& ref = "str";
+
+auto rpy[4] = ref;
+auto rpp[4] (ref); // P0960
+auto rpw[4] {ref};
+// auto + size deduction :
+auto rpu[] = ref;
+auto rpv[] (ref); // P0960
+auto rpx[] {ref};
diff --git a/gcc/testsuite/g++.dg/init/array-copy11.C b/gcc/testsuite/g++.dg/init/array-copy11.C
new file mode 100644
index 00000000000..ac4d0c0dcb8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/array-copy11.C
@@ -0,0 +1,13 @@
+// PR c++/103238 (array-copy extensions for P1997)
+// Array function return nocompile tests -
+// should give same errors before and after the array-copy patch.
+
+// { dg-do compile { target c++11 } }
+//
+
+constexpr auto a() -> char[2] {return "a";} // { dg-error "declared as function returning an array" }
+
+constexpr char char2(char,char)[2]; // { dg-error "declared as function returning an array" }
+constexpr auto char2(char,char) -> char[2]; // { dg-error "declared as function returning an array" }
+
+constexpr char char2(char a,char b)[2] {return{a,b};} // { dg-error "declared as function returning an array" }
diff --git a/gcc/testsuite/g++.dg/init/array-copy12.C b/gcc/testsuite/g++.dg/init/array-copy12.C
new file mode 100644
index 00000000000..f6588b002ab
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/array-copy12.C
@@ -0,0 +1,79 @@
+// PR c++/103238 (array-copy extensions for P1997)
+// Array function return compile tests -
+// (c.f. array-copy11.C for compile fail tests)
+
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-farray-copy" }
+
+constexpr bool equal(const char(&a)[2]
+                    ,const char(&b)[2])
+{
+  return a[0]==b[0]
+      && a[1]==b[1];
+}
+
+template<int N>
+using charN = char[N];
+using chars = char[];
+
+// Note a() return is const qualified, else constexpr test below fails FIXME
+constexpr auto a() -> const char[2] {return "a";}
+constexpr auto b() -> char[2] {return{'b'};} // init-list not folding causes ICE
+constexpr auto c() -> char[2] {return{"c"};}
+constexpr auto d() -> char[2] {return chars{"d"};}
+
+// Note the lambda return is not const qualified yet works constexpr below
+auto e = []() -> char[2] {char ce[2]{'e'}; return ce;};
+
+static_assert( equal(a(),"a"), "");
+//static_assert( equal(b(),"b"), ""); // ICE gcc assert
+static_assert( equal(c(),"c"), "");
+static_assert( equal(d(),"d"), "");
+static_assert( equal(e(),"e"), "");
+// { dg-error "non-constant condition for static assertion" "" { target c++14_down } .-1 }
+// { dg-error "call to non-.constexpr. function ..lambda" "" { target c++14_down } .-2 }
+
+constexpr auto bc[] = b();
+static_assert( equal(bc,"b"), "");
+
+constexpr char char2(char,char)[2];
+constexpr auto char2(char,char) -> char[2]; // same type redeclaration
+constexpr char char2(char a,char b)[2] {return{a,b};} // .. definition
+
+//static_assert( equal(char2('a','b'),{'a','b'}), ""); // ICE gcc assert
+
+constexpr charN<2> char2cp(const charN<2>& a) {return a;}
+constexpr charN<2> char2cb(const charN<2>& a) {return{a};}
+
+constexpr char c2a[2] = char2('a',0);
+constexpr char cpa[] = char2cp("a");
+constexpr auto cpb[] = char2cb("a");
+
+static_assert( equal( c2a, "a") ,"");
+static_assert( equal( cpa, "a") ,"");
+static_assert( equal( cpb, "a") ,"");
+
+constexpr auto f8(const float(&a)[8]) -> float[8] {return{};}
+
+template <int N>
+constexpr int atoi()[N] { return {__integer_pack(N)...}; }
+
+template <typename T, int N>
+constexpr int ind(const T (&r)[N], int i) { return r[i]; }
+
+constexpr auto atoi6[] = atoi<6>();
+
+static_assert(ind(atoi6,4) == 4, "");
+
+// FAILs below, can't pass array return to a reference argument
+
+//static_assert(ind(atoi<6>(),4) == 4, ""); // ICE
+
+int main() {
+  if (!equal(a(),"a")) __builtin_abort();
+  // if (!equal(b(),"b")) __builtin_abort(); // ICE
+  if (!equal(c(),"c")) __builtin_abort();
+  if (!equal(d(),"d")) __builtin_abort();
+  if (!equal(e(),"e")) __builtin_abort();
+   // if (ind(atoi<6>(),4) != 4) __builtin_abort(); // ICE
+}
diff --git a/gcc/testsuite/g++.dg/init/array-copy7.C b/gcc/testsuite/g++.dg/init/array-copy7.C
new file mode 100644
index 00000000000..9cee097d560
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/array-copy7.C
@@ -0,0 +1,40 @@
+// PR c++/103238 (array-copy extensions for P1997)
+// Array assignment nocompile tests
+// should give same errors before and after the array-copy patch.
+
+// { dg-do compile { target c++11 } }
+//
+
+int aggr_ass()
+{
+  int a[2] = {11,66}, b[2] = {};
+
+  b = a; // { dg-error "invalid array assignment" }
+  b = {a}; // { dg-error "assigning to an array from an initializer list" }
+  b = {11,66}; // { dg-error "assigning to an array from an initializer list" }
+  b = {}; // { dg-error "assigning to an array from an initializer list" }
+  a = {11}; // { dg-error "assigning to an array from an initializer list" }
+  return a[1] + b[0] + b[1];
+}
+
+char clr()
+{
+  char abc[] = {'a','b','c'};
+  abc = {""}; // { dg-error "assigning to an array from an initializer list" }
+  return abc[0] + abc[1] + abc[2];
+}
+
+struct A
+{
+  int a[2];
+  A(const int(&b)[2]) { a = b; } // { dg-error "invalid array assignment" }
+};
+
+char strtab[4][8] = {"hello","world"};
+
+void str_ass()
+{
+  strtab = {"Hello","World"}; // { dg-error "assigning to an array from an initializer list" }
+  strtab[0] = {"hi"}; // { dg-error "assigning to an array from an initializer list" }
+  strtab[1] = strtab[0]; // { dg-error "invalid array assignment" }
+}
diff --git a/gcc/testsuite/g++.dg/init/array-copy8.C b/gcc/testsuite/g++.dg/init/array-copy8.C
new file mode 100644
index 00000000000..582f35f4340
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/array-copy8.C
@@ -0,0 +1,56 @@
+// PR c++/103238 (array-copy extensions for P1997)
+// Array assignment compile tests -
+// (c.f. array-copy7.C for compile fail tests)
+
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-farray-copy" }
+
+int aggr_ass()
+{
+  int a[2] = {11,66}, b[2] = {};
+
+  b = a;
+  b = {a};
+  b = {11,66};
+  b = {};
+  a = {11};
+  return a[1] + b[0] + b[1];
+}
+
+char clr()
+{
+  char abc[] = {'a','b','c'};
+  abc = {""};
+  return abc[0] + abc[1] + abc[2];
+}
+
+struct A
+{
+  int a[2];
+  A(const int(&b)[2]) { a = b; }
+};
+
+char strtab[4][8] = {"hello","world"};
+
+void str_ass()
+{
+  strtab = {"Hello","World"};
+  strtab[0] = {"hi"};
+  strtab[1] = strtab[0];
+}
+
+int main()
+{
+  char hi[8] = "hi";
+  str_ass();
+  if (__builtin_memcmp(strtab[0],hi,8) != 0
+   || __builtin_memcmp(strtab[1],hi,8) != 0)
+    __builtin_abort();
+
+  if (aggr_ass() || clr())
+    __builtin_abort();
+
+  A a({11,66});
+  if (a.a[0] != 11 || a.a[1] != 66)
+   __builtin_abort();
+}
diff --git a/gcc/testsuite/g++.dg/init/array-copy9.C b/gcc/testsuite/g++.dg/init/array-copy9.C
new file mode 100644
index 00000000000..7bbc615a204
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/array-copy9.C
@@ -0,0 +1,57 @@
+// PR c++/103238 (array-copy extensions for P1997)
+// Array auto placeholder element deduction nocompile tests
+// should give same errors before and after the array-copy patch.
+
+// { dg-do compile { target c++11 } }
+//
+
+template <typename...> struct same{ enum:bool{v=false}; };
+template <typename T> struct same<T,T>{ enum:bool{v=true}; };
+template <typename T, typename X, typename...Y>
+struct same<T,X,Y...>{ enum:bool{v = same<T,X>::v && same<T,Y...>::v}; };
+template<typename...T>
+constexpr bool all_same_t(T const&...){return same<T...>::v;}
+
+typedef int int2[2];
+int2 a {11,66};
+
+auto er[2] {1,2};
+// { dg-error "direct-list-initialization of .auto. requires exactly one element .\\-fpermissive." "" { target *-*-* } .-1 }
+// { dg-error "deducing from brace-enclosed initializer list requires" "" { target *-*-* } .-2 }
+auto il[2] = {1,2};
+// { dg-error "deducing from brace-enclosed initializer list requires" "" { target *-*-* } .-1 }
+auto um[2] = {a};
+// { dg-error "deducing from brace-enclosed initializer list requires" "" { target *-*-* } .-1 }
+
+// Initializations from from rvalue array
+auto g[2] = int2{11,66}; // { dg-error "unable to deduce" }
+auto j[2] ( int2{11,66} ); // { dg-error "unable to deduce" }
+auto l[2] { int2{11,66} }; // { dg-error "unable to deduce" }
+// auto + size deduction :
+auto m[] = int2{11,66}; // { dg-error "unable to deduce" }
+auto n[] ( int2{11,66} ); // { dg-error "unable to deduce" }
+auto p[] { int2{11,66} }; // { dg-error "unable to deduce" }
+
+static_assert( all_same_t(a,g,j,l,m,n,p), "");
+
+auto stp[] = "str"; // { dg-error "unable to deduce" }
+char str[] = "str";
+auto cpy[4] = str; // { dg-error "unable to deduce" }
+auto cpp[4] (str); // { dg-error "unable to deduce" }
+auto cpw[4] {str}; // { dg-error "unable to deduce" }
+// auto + size deduction :
+auto cpu[] = str; // { dg-error "unable to deduce" }
+auto cpv[] (str); // { dg-error "unable to deduce" }
+auto cpx[] {str}; // { dg-error "unable to deduce" }
+
+static_assert( all_same_t(str,cpy,cpp,cpw,cpu,cpv,cpx), "");
+
+auto const& ref = "str";
+
+auto rpy[4] = ref; // { dg-error "unable to deduce" }
+auto rpp[4] (ref); // { dg-error "unable to deduce" }
+auto rpw[4] {ref}; // { dg-error "unable to deduce" }
+// auto + size deduction :
+auto rpu[] = ref; // { dg-error "unable to deduce" }
+auto rpv[] (ref); // { dg-error "unable to deduce" }
+auto rpx[] {ref}; // { dg-error "unable to deduce" }
-- 
2.31.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 3/3] c++: P1997 array-copy extensions: Assignment, return,  etc. [PR103238]
  2021-11-22  2:51 ` [PATCH 3/3] c++: P1997 array-copy extensions: Assignment, return, etc. [PR103238] Will Wray
@ 2021-11-22 20:41   ` Joseph Myers
  2021-11-22 21:21     ` will wray
  2021-11-29 22:44   ` Jason Merrill
  1 sibling, 1 reply; 9+ messages in thread
From: Joseph Myers @ 2021-11-22 20:41 UTC (permalink / raw)
  To: Will Wray; +Cc: gcc-patches

On Sun, 21 Nov 2021, Will Wray via Gcc-patches wrote:

> gcc/c/ChangeLog:
> 
> 	* c-decl.c (grokdeclarator): Don't complain of array returns.

A C front-end change like this doesn't belong in a C++ patch (I don't see 
any reason why this C++ patch would need such a C front-end change, it's 
not e.g. changing the interface to a function called from shared code but 
defined separately for both front ends).

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 3/3] c++: P1997 array-copy extensions: Assignment, return,  etc. [PR103238]
  2021-11-22 20:41   ` Joseph Myers
@ 2021-11-22 21:21     ` will wray
  0 siblings, 0 replies; 9+ messages in thread
From: will wray @ 2021-11-22 21:21 UTC (permalink / raw)
  To: Joseph Myers; +Cc: gcc-patches List

On Mon, Nov 22, 2021 at 3:42 PM Joseph Myers <joseph@codesourcery.com> wrote:
>
> On Sun, 21 Nov 2021, Will Wray via Gcc-patches wrote:
>
> > gcc/c/ChangeLog:
> >
> >       * c-decl.c (grokdeclarator): Don't complain of array returns.
>
> A C front-end change like this doesn't belong in a C++ patch

Of course, thanks. I'll remove it.
Hopefully it'll be back before long, in a compatible C array-copy patchset.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/3] c++: designated init of char array by string constant [PR55227]
  2021-11-22  2:51 ` [PATCH 1/3] c++: designated init of char array by string constant [PR55227] Will Wray
@ 2021-11-25 16:05   ` Jason Merrill
  0 siblings, 0 replies; 9+ messages in thread
From: Jason Merrill @ 2021-11-25 16:05 UTC (permalink / raw)
  To: Will Wray, gcc-patches

On 11/21/21 21:51, Will Wray via Gcc-patches wrote:
> Also address "FIXME: this code is duplicated from reshape_init" in
> cp_complete_array_type by always calling reshape_init on init-list.
> 
> 	PR c++/55227
> 
> gcc/cp/ChangeLog:
> 
> 	* decl.c (reshape_init_r): Only call has_designator_check when
>         first_initializer_p or for the inner constructor element.
> 	(cp_complete_array_type): Call reshape_init on braced-init-list.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp2a/desig20.C: New test.
> ---
>   gcc/cp/decl.c                        | 42 +++++++++++++------------------
>   gcc/testsuite/g++.dg/cpp2a/desig20.C | 48 ++++++++++++++++++++++++++++++++++++
>   2 files changed, 65 insertions(+), 25 deletions(-)
> 
> diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
> index 2ddf0e4a524..83a2d3bf8f1 100644
> --- a/gcc/cp/decl.c
> +++ b/gcc/cp/decl.c
> @@ -6824,28 +6824,31 @@ reshape_init_r (tree type, reshape_iter *d, tree first_initializer_p,
>     if (TREE_CODE (type) == ARRAY_TYPE
>         && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type))))
>       {
> -      tree str_init = init;
> -      tree stripped_str_init = stripped_init;
> +      tree arr_init = init;
> +      tree stripped_arr_init = stripped_init;

This renaming seems unnecessary; OK without the name change.

> +      reshape_iter stripd = {};
>   
>         /* Strip one level of braces if and only if they enclose a single
>   	 element (as allowed by [dcl.init.string]).  */
>         if (!first_initializer_p
> -	  && TREE_CODE (stripped_str_init) == CONSTRUCTOR
> -	  && CONSTRUCTOR_NELTS (stripped_str_init) == 1)
> +	  && TREE_CODE (stripped_arr_init) == CONSTRUCTOR
> +	  && CONSTRUCTOR_NELTS (stripped_arr_init) == 1)
>   	{
> -	  str_init = (*CONSTRUCTOR_ELTS (stripped_str_init))[0].value;
> -	  stripped_str_init = tree_strip_any_location_wrapper (str_init);
> +	  stripd.cur = CONSTRUCTOR_ELT (stripped_arr_init, 0);
> +	  arr_init = stripd.cur->value;
> +	  stripped_arr_init = tree_strip_any_location_wrapper (arr_init);
>   	}
>   
>         /* If it's a string literal, then it's the initializer for the array
>   	 as a whole. Otherwise, continue with normal initialization for
>   	 array types (one value per array element).  */
> -      if (TREE_CODE (stripped_str_init) == STRING_CST)
> +      if (TREE_CODE (stripped_arr_init) == STRING_CST)
>   	{
> -	  if (has_designator_problem (d, complain))
> +	  if ((first_initializer_p && has_designator_problem (d, complain))
> +	      || (stripd.cur && has_designator_problem (&stripd, complain)))
>   	    return error_mark_node;
>   	  d->cur++;
> -	  return str_init;
> +	  return arr_init;
>   	}
>       }
>   
> @@ -9545,22 +9548,11 @@ cp_complete_array_type (tree *ptype, tree initial_value, bool do_default)
>     if (initial_value)
>       {
>         /* An array of character type can be initialized from a
> -	 brace-enclosed string constant.
> -
> -	 FIXME: this code is duplicated from reshape_init. Probably
> -	 we should just call reshape_init here?  */
> -      if (char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (*ptype)))
> -	  && TREE_CODE (initial_value) == CONSTRUCTOR
> -	  && !vec_safe_is_empty (CONSTRUCTOR_ELTS (initial_value)))
> -	{
> -	  vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (initial_value);
> -	  tree value = (*v)[0].value;
> -	  STRIP_ANY_LOCATION_WRAPPER (value);
> -
> -	  if (TREE_CODE (value) == STRING_CST
> -	      && v->length () == 1)
> -	    initial_value = value;
> -	}
> +	 brace-enclosed string constant so call reshape_init to
> +	 remove the optional braces from a braced string literal.  */
> +      if (BRACE_ENCLOSED_INITIALIZER_P (initial_value))
> +	initial_value = reshape_init (*ptype, initial_value,
> +				      tf_warning_or_error);
>   
>         /* If any of the elements are parameter packs, we can't actually
>   	 complete this type now because the array size is dependent.  */
> diff --git a/gcc/testsuite/g++.dg/cpp2a/desig20.C b/gcc/testsuite/g++.dg/cpp2a/desig20.C
> new file mode 100644
> index 00000000000..daadfa58855
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/desig20.C
> @@ -0,0 +1,48 @@
> +// PR c++/55227
> +// Test designated initializer for char array by string constant
> +
> +// { dg-options "" }
> +
> +struct C {char a[2];};
> +
> +/* Case a, designated, unbraced, string-literal of the exact same size
> +   as the initialized char array; valid and accepted before and after.  */
> +C a = {.a="a"};
> +
> +/* Cases b,c,d, designated, braced or mimatched-size, string literal,
> +   previously rejected; "C99 designator 'a' outside aggregate initializer".  */
> +C b = {.a=""};
> +C c = {.a={""}};
> +C d = {.a={"a"}};
> +
> +/* Case e, designated char array field and braced, designated array element(s)
> +   (with GNU [N]= extension) valid and accepted before and after.  */
> +C e = {.a={[0]='a'}};
> +
> +/* Cases f,g,h, braced string literal, 'designated' within inner braces;
> +   invalid, previously accepted as positional with 'designator' ignored.  */
> +C f = {{[0]="a"}}; // { dg-error "C99 designator .0. outside aggregate initializer" }
> +C g = {{.a="a"}}; // { dg-error "C99 designator .a. outside aggregate initializer" }
> +C h = {{.b="a"}}; // { dg-error "C99 designator .b. outside aggregate initializer" }
> +
> +char a2[][10] = { [0] = { "aaa" } };
> +
> +struct D { C c; int a[8]; };
> +
> +D x = { .c {.a={"a"}}, .a={1,2,3,4,5,6,7,8} };
> +
> +struct A { union { int a; char c[4]; }; };
> +
> +A non = { .c = "c++" };
> +
> +template <class T>
> +void t()
> +{
> +  C ca[] = { {.a=""}, {.a={""}}, };
> +
> +}
> +
> +void u()
> +{
> +  return t<void>();
> +}
> 


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/3] c++: P1997 array-copy extensions: Initialization [PR103238]
  2021-11-22  2:51 ` [PATCH 2/3] c++: P1997 array-copy extensions: Initialization [PR103238] Will Wray
@ 2021-11-27 22:56   ` Jason Merrill
  0 siblings, 0 replies; 9+ messages in thread
From: Jason Merrill @ 2021-11-27 22:56 UTC (permalink / raw)
  To: Will Wray, gcc-patches

On 11/21/21 21:51, Will Wray via Gcc-patches wrote:
> This patch implements initializations of arrays from array values.
> 
> The first of two 'array-copy' patches, it adds the option -farray-copy
> (flag_array_copy) to enable all features of P1997 (copy related or not),
> documented as experimental extensions.
> 
> It deals with initialization of array variables and member array fields.
> 
> Initialization of an array variable from an array of the same type performs
> array copy-initialization; elementwise move or copy from an rvalue or lvalue
> array respectively, in index order from begin to end. The existing code path
> for a structured binding declaration with array initializer, auto[e...]{a};
> performs the same array copy-initialization (as a special case superpower).
> Borrowing from that, this was a relatively quick and easy change.
> 
> Initialization of member arrays proved much more difficult to do in general.
> I resorted to trial and error, running gcc in gdb with test cases to work out
> where and what to change, until eventually converging on this set of changes.
> 
> One starting point was the C special case of char array initialization from
> string literals (as char array lvalue constants). However, a long-standing
> bug in designated initialization of char arrays by string literals blocked
> the task of extending this special case to general array type initializers.
> A bugfix patch was separated out, to be merged ahead of these patches:
> 
>      https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55227
>      https://gcc.gnu.org/pipermail/gcc-patches/2021-November/584897.html
> 
> Other cases to consider, array initializations:
> 
>      * by optionally brace-enclosed or paren-enclosed array values
>      * by possibly-designated array-valued aggregate initializers
>        (within possibly-elided braced init-lists)
>      * by brace or paren-enclosed array values in member initialization lists
>      * by array-valued member initializers
> 
> The patch adds tests for these cases, and for inner initializations of nested
> array elements of array type.
> 
> The work has diverged in details from the P1997 wording, including catching
> up with C++20 changes such as parenthesised initialization of aggregates.
> The paper will be revised to reflect the implementation experience.
> 
> It is likely that there are omissions, errors in the conditions or that changed
> code is inappropriate. For example, I inserted a new call to build_array_copy
> in typeck2.c:digest_init_r which may not be correct for move-enabled elements.
> Please review carefully with this in mind and suggest test cases to exercise.

You would want a testcase with an array of move-only type, e.g. (untested)

struct A { A(int); A(A&&); int i; };
using Ar = A[2];
struct B { A a[2]; };
B b = { Ar{1,2} }; // should move

I don't think the new call to build_array_copy needs to change, but it's 
good to test.

> 	PR c++/103238
> 
> gcc/c-family/ChangeLog:
> 
> 	* c-common.c (complete_array_type): Accept array type initial_value.
> 	* c.opt: New option -farray-copy "experimental extensions for P1997".
> 
> gcc/cp/ChangeLog:
> 
> 	* decl.c (do_aggregate_paren_init): Accept single array type init.
> 	(maybe_deduce_size_from_array_init): Include same-type array inits,
> 	or complain for not same-type arrays.
> 	(reshape_init_r): Extend string-literal handling to all array types.
> 	* init.c (build_aggr_init): Follow existing path for array rhs.
> 	* typeck.c (cp_build_modify_expr): Follow path for synthetic op=.
> 	* typeck2.c (digest_init_r): Add call to build_array_copy for
> 	same-type arrays ('copy' feels wrong for move-eligible rhs).
> 
> gcc/ChangeLog:
> 
> 	* doc/invoke.texi: -farray-copy help info documentation.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/init/array-copy1.C: New test. Variable init 'before' XFAILs
> 	* g++.dg/init/array-copy2.C: New test. Variable init 'after' PASSes
> 	* g++.dg/init/array-copy3.C: New test. Member init 'before' XFAILs
> 	* g++.dg/init/array-copy4.C: New test. Member init 'after' PASSes
> 	* g++.dg/init/array-copy5.C: New test. Member nsdmi & desig XFAILs
> 	* g++.dg/init/array-copy6.C: New test. Member nsdmi & desig PASSes
> ---
>   gcc/c-family/c-common.c                 |  5 +++
>   gcc/c-family/c.opt                      |  4 ++
>   gcc/cp/decl.c                           | 61 ++++++++++++++++++++---------
>   gcc/cp/init.c                           |  6 ++-
>   gcc/cp/typeck.c                         |  9 +++--
>   gcc/cp/typeck2.c                        | 30 +++++++++++----
>   gcc/doc/invoke.texi                     |  6 +++
>   gcc/testsuite/g++.dg/init/array-copy1.C | 66 ++++++++++++++++++++++++++++++++
>   gcc/testsuite/g++.dg/init/array-copy2.C | 68 +++++++++++++++++++++++++++++++++
>   gcc/testsuite/g++.dg/init/array-copy3.C | 41 ++++++++++++++++++++
>   gcc/testsuite/g++.dg/init/array-copy4.C | 42 ++++++++++++++++++++
>   gcc/testsuite/g++.dg/init/array-copy5.C | 36 +++++++++++++++++
>   gcc/testsuite/g++.dg/init/array-copy6.C | 51 +++++++++++++++++++++++++
>   13 files changed, 395 insertions(+), 30 deletions(-)
> 
> diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
> index 86c007f53de..fb0b1ef294f 100644
> --- a/gcc/c-family/c-common.c
> +++ b/gcc/c-family/c-common.c
> @@ -6796,6 +6796,11 @@ complete_array_type (tree *ptype, tree initial_value, bool do_default)
>   	    = int_size_in_bytes (TREE_TYPE (TREE_TYPE (initial_value)));
>   	  maxindex = size_int (TREE_STRING_LENGTH (initial_value)/eltsize - 1);
>   	}
> +      else if (flag_array_copy
> +	       && TREE_CODE (TREE_TYPE (initial_value)) == ARRAY_TYPE)
> +	{
> +	  maxindex = array_type_nelts (TREE_TYPE (initial_value));
> +	}
>         else if (TREE_CODE (initial_value) == CONSTRUCTOR)
>   	{
>   	  vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (initial_value);
> diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
> index 3976fc368db..9d2a6ad8e1c 100644
> --- a/gcc/c-family/c.opt
> +++ b/gcc/c-family/c.opt
> @@ -1579,6 +1579,10 @@ fcilkplus
>   C ObjC C++ ObjC++ LTO Undocumented Ignore
>   Removed in GCC 8.  This switch has no effect.
>   
> +farray-copy
> +C ObjC C++ ObjC++ Var(flag_array_copy)
> +Enable experimental extension for P1997; C array copy semantics.
> +
>   fconcepts
>   C++ ObjC++ Var(flag_concepts)
>   Enable support for C++ concepts.
> diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
> index 83a2d3bf8f1..1010fa2c53f 100644
> --- a/gcc/cp/decl.c
> +++ b/gcc/cp/decl.c
> @@ -5834,15 +5834,19 @@ tree
>   do_aggregate_paren_init (tree init, tree type)
>   {
>     tree val = TREE_VALUE (init);
> +  tree stripped_val = tree_strip_any_location_wrapper (val);
>   
>     if (TREE_CHAIN (init) == NULL_TREE)
>       {
>         /* If the list has a single element and it's a string literal,
>   	 then it's the initializer for the array as a whole.  */
> -      if (TREE_CODE (type) == ARRAY_TYPE
> -	  && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type)))
> -	  && TREE_CODE (tree_strip_any_location_wrapper (val))
> -	     == STRING_CST)
> +      if ((TREE_CODE (type) == ARRAY_TYPE
> +	   && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type)))
> +	   && TREE_CODE (stripped_val) == STRING_CST)
> +	  || (flag_array_copy
> +	      && TREE_CODE (TREE_TYPE (stripped_val)) == ARRAY_TYPE
> +	      && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (type),
> +					TREE_TYPE (TREE_TYPE (stripped_val)))))
>   	return val;
>         /* Handle non-standard extensions like compound literals.  This also
>   	 prevents triggering aggregate parenthesized-initialization in
> @@ -6007,9 +6011,10 @@ maybe_deduce_size_from_array_init (tree decl, tree init)
>   {
>     tree type = TREE_TYPE (decl);
>   
> -  if (TREE_CODE (type) == ARRAY_TYPE
> -      && TYPE_DOMAIN (type) == NULL_TREE
> -      && TREE_CODE (decl) != TYPE_DECL)
> +  if (TREE_CODE (type) != ARRAY_TYPE
> +      || TREE_CODE (decl) == TYPE_DECL)
> +    ;
> +  else if (TYPE_DOMAIN (type) == NULL_TREE)
>       {
>         /* do_default is really a C-ism to deal with tentative definitions.
>   	 But let's leave it here to ease the eventual merge.  */
> @@ -6072,6 +6077,17 @@ maybe_deduce_size_from_array_init (tree decl, tree init)
>   
>         relayout_decl (decl);
>       }
> +  else if (flag_array_copy && init
> +	   && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE
> +	   && TREE_CODE (tree_strip_any_location_wrapper (init)) != STRING_CST
> +	   && !same_type_ignoring_top_level_qualifiers_p (type,
> +							  TREE_TYPE (init)))
> +    {
> +      error_at (DECL_SOURCE_LOCATION (decl),
> +		"array of type %qT cannot be initialized with an "
> +		"array of type %qT in %qD", type, TREE_TYPE (init), decl);
> +      TREE_TYPE (decl) = error_mark_node;
> +    }
>   }
>   
>   /* Set DECL_SIZE, DECL_ALIGN, etc. for DECL (a VAR_DECL), and issue
> @@ -6815,21 +6831,23 @@ reshape_init_r (tree type, reshape_iter *d, tree first_initializer_p,
>         return init;
>       }
>   
> -  /* [dcl.init.string]
> +  /* [dcl.init.string] or flag_array_copy extension P1997
>   
>         A char array (whether plain char, signed char, or unsigned char)
>         can be initialized by a string-literal (optionally enclosed in
>         braces); a wchar_t array can be initialized by a wide
> -      string-literal (optionally enclosed in braces).  */
> -  if (TREE_CODE (type) == ARRAY_TYPE
> -      && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type))))
> +      string-literal (optionally enclosed in braces).
> +      With flag_array_copy an array can be initialized by an array value
> +      (optionally enclosed in braces).  */
> +  if (TREE_CODE (type) == ARRAY_TYPE)
>       {
>         tree arr_init = init;
>         tree stripped_arr_init = stripped_init;

The renaming belongs in this patch.

>         reshape_iter stripd = {};
>   
> -      /* Strip one level of braces if and only if they enclose a single
> -	 element (as allowed by [dcl.init.string]).  */
> +      /* Strip one level of braces if they enclose a single element,
> +	 provisionally for elison in the optionally-braced case if the
> +	 initializer is of compatible array type, as checked next. */
>         if (!first_initializer_p
>   	  && TREE_CODE (stripped_arr_init) == CONSTRUCTOR
>   	  && CONSTRUCTOR_NELTS (stripped_arr_init) == 1)
> @@ -6839,10 +6857,19 @@ reshape_init_r (tree type, reshape_iter *d, tree first_initializer_p,
>   	  stripped_arr_init = tree_strip_any_location_wrapper (arr_init);
>   	}
>   
> -      /* If it's a string literal, then it's the initializer for the array
> -	 as a whole. Otherwise, continue with normal initialization for
> -	 array types (one value per array element).  */
> -      if (TREE_CODE (stripped_arr_init) == STRING_CST)
> +      tree init_type = TREE_TYPE (stripped_arr_init);
> +
> +      /* If it's a string literal initializer for a char array target,
> +	 or, with flag_array_copy, an array value of same element type,
> +	 then it's the initializer for the array as a whole.
> +	 Else, continue with element by element array initialization.  */
> +      if ((TREE_CODE (stripped_arr_init) == STRING_CST
> +	   && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type))))
> +	  || (flag_array_copy
> +	      && TREE_CODE (init_type) == ARRAY_TYPE
> +	      && TYPE_DOMAIN (init_type) != NULL_TREE
> +	      && same_type_ignoring_top_level_qualifiers_p (
> +				TREE_TYPE (type), TREE_TYPE (init_type))))
>   	{
>   	  if ((first_initializer_p && has_designator_problem (d, complain))
>   	      || (stripd.cur && has_designator_problem (&stripd, complain)))
> diff --git a/gcc/cp/init.c b/gcc/cp/init.c
> index 3ba2e3bbe04..fd9a065ed95 100644
> --- a/gcc/cp/init.c
> +++ b/gcc/cp/init.c
> @@ -1787,7 +1787,11 @@ build_aggr_init (tree exp, tree init, int flags, tsubst_flags_t complain)
>         tree itype = init ? TREE_TYPE (init) : NULL_TREE;
>         int from_array = 0;
>   
> -      if (VAR_P (exp) && DECL_DECOMPOSITION_P (exp))
> +      if (VAR_P (exp)
> +	  && (DECL_DECOMPOSITION_P (exp)
> +	      || (flag_array_copy
> +		  && TREE_CODE (tree_strip_any_location_wrapper (init))
> +		     != STRING_CST)))
>   	{
>   	  from_array = 1;
>   	  init = mark_rvalue_use (init);
> diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
> index cb20329ceb5..8e96a925186 100644
> --- a/gcc/cp/typeck.c
> +++ b/gcc/cp/typeck.c
> @@ -9144,11 +9144,12 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
>   	}
>   
>         /* Allow array assignment in compiler-generated code.  */
> -      else if (!current_function_decl
> -	       || !DECL_DEFAULTED_FN (current_function_decl))
> +      else if ((!current_function_decl
> +		|| !DECL_DEFAULTED_FN (current_function_decl))
> +	       && !flag_array_copy)
>   	{
> -          /* This routine is used for both initialization and assignment.
> -             Make sure the diagnostic message differentiates the context.  */
> +	  /* This routine is used for both initialization and assignment.
> +	     Make sure the diagnostic message differentiates the context.  */
>   	  if (complain & tf_error)
>   	    {
>   	      if (modifycode == INIT_EXPR)
> diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
> index e98fbf7f5fa..20d46716279 100644
> --- a/gcc/cp/typeck2.c
> +++ b/gcc/cp/typeck2.c
> @@ -1175,6 +1175,9 @@ digest_init_r (tree type, tree init, int nested, int flags,
>   	    }
>   	  return init;
>   	}
> +      if (flag_array_copy
> +	  && same_type_ignoring_top_level_qualifiers_p(type, TREE_TYPE (init)))
> +	return build_array_copy(init);

Missing space before ( on two lines.

>       }
>   
>     /* Handle scalar types (including conversions) and references.  */
> @@ -1244,13 +1247,18 @@ digest_init_r (tree type, tree init, int nested, int flags,
>   				     complain);
>     else
>       {
> -      if (COMPOUND_LITERAL_P (stripped_init) && code == ARRAY_TYPE)
> +      if (COMPOUND_LITERAL_P (stripped_init) && code == ARRAY_TYPE
> +	  && (complain & tf_error))
>   	{
> -	  if (complain & tf_error)
> -	    error_at (loc, "cannot initialize aggregate of type %qT with "
> -		      "a compound literal", type);
> -
> -	  return error_mark_node;
> +	  if (flag_array_copy)
> +	    pedwarn (loc, OPT_Wpedantic, "ISO C++ doesn%'t allow initialization"
> +		     "of an array of type %qT with a compound literal", type);
> +	  else
> +	    {
> +	      error_at (loc, "cannot initialize aggregate of type %qT with "
> +			     "a compound literal", type);
> +	      return error_mark_node;
> +	    }

This changes the function to only return error_mark_node when we're 
diagnosing errors, which seems wrong; we need it to fail in SFINAE 
context as well.

>   	}
>   
>         if (code == ARRAY_TYPE
> @@ -1265,8 +1273,14 @@ digest_init_r (tree type, tree init, int nested, int flags,
>   	    return init;
>   
>   	  if (complain & tf_error)
> -	    error_at (loc, "array must be initialized with a brace-enclosed"
> -		      " initializer");
> +	  {
> +	    if (!flag_array_copy)
> +	      error_at (loc, "array must be initialized with a brace-enclosed"
> +			     " initializer");
> +	    else
> +	      error_at (loc, "array must be initialized with a brace-enclosed"
> +			     " initializer or an array value of the same type");
> +	    }
>   	  return error_mark_node;
>   	}
>   
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index d62ec08150e..32a34ca74bb 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -213,6 +213,7 @@ in the following sections.
>   @xref{C++ Dialect Options,,Options Controlling C++ Dialect}.
>   @gccoptlist{-fabi-version=@var{n}  -fno-access-control @gol
>   -faligned-new=@var{n}  -fargs-in-order=@var{n}  -fchar8_t  -fcheck-new @gol
> +-farray-copy @gol
>   -fconstexpr-depth=@var{n}  -fconstexpr-cache-depth=@var{n} @gol
>   -fconstexpr-loop-limit=@var{n}  -fconstexpr-ops-limit=@var{n} @gol
>   -fno-elide-constructors @gol
> @@ -3001,6 +3002,11 @@ return value even without this option.  In all other cases, when
>   exhaustion is signalled by throwing @code{std::bad_alloc}.  See also
>   @samp{new (nothrow)}.
>   
> +@item -farray-copy
> +@opindex farray-copy
> +Enables experimental support for P1997; C array copy semantics, pseudo-
> +destructors and auto placeholder for array element type.
> +
>   @item -fconcepts
>   @itemx -fconcepts-ts
>   @opindex fconcepts
> diff --git a/gcc/testsuite/g++.dg/init/array-copy1.C b/gcc/testsuite/g++.dg/init/array-copy1.C
> new file mode 100644
> index 00000000000..15986a00d1b
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/init/array-copy1.C
> @@ -0,0 +1,66 @@
> +// PR c++/103238 (array-copy extensions for P1997)
> +// Array variable initialization nocompile tests -
> +// should give same errors before and after the array-copy patch.
> +
> +// { dg-do compile { target c++11 } } c++11 for uniform init
> +
> +typedef int int2[2];
> +int2 u = {11,66};
> +
> +int* p = new int2{u}; // { dg-error "invalid conversion from .int\\*. to .int. .\\-fpermissive." }
> +
> +// Initializations from from rvalue array
> +int2 g = int2{11,66};
> +int2 j ( int2{11,66} );  // takes P0960 paren-init path in c++20
> +int2 k = { int2{11,66} };
> +int2 l { int2{11,66} };
> +// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-4 }
> +// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-4 }
> +// { dg-error "taking address of temporary array" "address of temporary" { target *-*-* } .-4 }
> +// { dg-error "taking address of temporary array" "address of temporary" { target *-*-* } .-4 }
> +
> +// Initializations from from lvalue array
> +int2 gc = u;
> +int2 jc (u);  // takes P0960 paren-init path in c++20
> +int2 kc = {u};
> +int2 lc {u};
> +// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-4 }
> +// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-4 }
> +// { dg-error "invalid conversion from .int\\*. to .int. .\\-fpermissive." "bad conv" { target *-*-* } .-4 }
> +// { dg-error "invalid conversion from .int\\*. to .int. .\\-fpermissive." "bad conv" { target *-*-* } .-4 }
> +
> +char str[] = "str";
> +
> +char cpy[] = str;
> +char cpp[] (str); // takes P0960 paren-init path in c++20
> +char cpu[] = {str};
> +char cpw[] {str};
> +// { dg-error "initializer fails to determine size of .cpy." "deduce size" { target *-*-*  } .-4 }
> +// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-5 }
> +// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target c++17_down } .-5 }
> +// { dg-error "initializer fails to determine size of .cpp." "deduce size" { target c++17_down  } .-6 }
> +// { dg-error "invalid conversion from .char\\*. to .char. .\\-fpermissive." "bad conv" { target c++20 } .-7 }
> +// { dg-error "invalid conversion from .char\\*. to .char. .\\-fpermissive." "bad conv" { target *-*-* } .-7 }
> +// { dg-error "invalid conversion from .char\\*. to .char. .\\-fpermissive." "bad conv" { target *-*-* } .-7 }
> +
> +char cp5[5] = str;
> +char cp3[3] = str;
> +// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-2 }
> +// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-2 }
> +
> +int2 s[2] = { u };
> +// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-1 }
> +int2 x[2] = { u
> +	    , u };
> +// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-2 }
> +// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-2 }
> +int2 y[2] = { 1,2
> +	    , {u} };
> +// { dg-error "invalid conversion from .int\\*. to .int. .\\-fpermissive." "bad conv" { target *-*-* } .-1 }
> +int2 z[2] = { {u},
> +	       3,{4} };
> +// { dg-error "invalid conversion from .int\\*. to .int. .\\-fpermissive." "bad conv" { target *-*-* } .-2 }
> +
> +__UINT8_TYPE__ m222[2][2][2] {0,1,2,3,4,5,6,7};
> +__UINT8_TYPE__ c222[2][2][2] { m222[0], m222[1][0], 6,7 };
> +// { dg-error "array must be initialized with a brace-enclosed initializer" "array init" { target *-*-* } .-1 }
> diff --git a/gcc/testsuite/g++.dg/init/array-copy2.C b/gcc/testsuite/g++.dg/init/array-copy2.C
> new file mode 100644
> index 00000000000..7e1ad23592b
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/init/array-copy2.C
> @@ -0,0 +1,68 @@
> +// PR c++/103238 (array-copy extensions for P1997)
> +// Array variable initialization compile tests, -farray-copy enabled
> +// (c.f. array-copy1.C for compile fail tests)
> +
> +// { dg-do compile { target c++11 } }  c++11 for uniform init
> +// { dg-additional-options "-farray-copy" }
> +
> +typedef int int2[2];
> +int2 u = {11,66};
> +
> +int* p = new int2{u};
> +
> +// Initializations from from rvalue array
> +int2 g = int2{11,66};
> +int2 j ( int2{11,66} );  // takes P0960 paren-init path in c++20
> +int2 k = { int2{11,66} };
> +int2 l { int2{11,66} };
> +
> +// Initializations from from lvalue array
> +int2 gc = u;
> +int2 jc (u);  // takes P0960 paren-init path in c++20
> +int2 kc = {u};
> +int2 lc {u};
> +
> +char str[] = "str";
> +
> +char cpy[] = str;
> +char cpp[] (str);  // takes P0960 paren-init path in c++20
> +char cpu[] = {str};
> +char cpw[] {str};
> +
> +char cp5[5] = str;
> +char cp3[3] = str;
> +// { dg-error "array of type .char .5.. cannot be initialized with an array of type .char .4.." "" { target *-*-* } .-2 }
> +// { dg-error "array of type .char .3.. cannot be initialized with an array of type .char .4.." "" { target *-*-* } .-2 }
> +
> +constexpr char cstr[] = "str";
> +constexpr char ccpy[] = cstr;
> +static_assert(
> +      __builtin_bit_cast(__UINT32_TYPE__, ccpy)
> +   == __builtin_bit_cast(__UINT32_TYPE__, "str")
> +, ""
> +);
> +
> +constexpr __UINT32_TYPE__ ci[] = {11,66};
> +constexpr __UINT32_TYPE__ cc[] = ci;
> +static_assert(
> +      __builtin_bit_cast(__UINT64_TYPE__, ci)
> +   == __builtin_bit_cast(__UINT64_TYPE__, cc)
> +, ""
> +);
> +
> +int2 s[2] = { u };
> +int2 x[2] = { u
> +	    , u };
> +int2 y[2] = { 1,2
> +	    , {u} };
> +int2 z[2] = { {u}
> +	   , 3,{4} };
> +
> +__UINT8_TYPE__ m222[2][2][2] {0,1,2,3,4,5,6,7};
> +__UINT8_TYPE__ c222[2][2][2] { m222[0], m222[1][0], 6,7 };
> +
> +int main() {
> +  if (__builtin_bit_cast(__UINT64_TYPE__, m222)
> +   != __builtin_bit_cast(__UINT64_TYPE__, c222))
> +      __builtin_abort ();
> +}
> diff --git a/gcc/testsuite/g++.dg/init/array-copy3.C b/gcc/testsuite/g++.dg/init/array-copy3.C
> new file mode 100644
> index 00000000000..bec78cb8435
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/init/array-copy3.C
> @@ -0,0 +1,41 @@
> +// PR c++/103238 (array-copy extensions for P1997)
> +// Array member initialization nocompile tests -
> +// should give same errors before and after the array-copy patch.
> +
> +// { dg-do compile { target c++11 } } c++11 for uniform init
> +//
> +
> +typedef int int2[2];
> +
> +struct A { int2 a; };
> +
> +A ad { int2{11,66} }; // { dg-error "array must be initialized with a brace-enclosed initializer" }
> +A ai = { int2{11,66} }; // { dg-error "array must be initialized with a brace-enclosed initializer" }
> +
> +struct B { int2 a, b, c, d; };
> +
> +constexpr
> +B b {
> +    {11,66}
> +  , {b.a} // { dg-error "invalid conversion from .const int\\*. to .int. .\\-fpermissive." }
> +  , (b.b) // { dg-error "array must be initialized with a brace-enclosed initializer" }
> +  ,  b.c
> +};
> +
> +struct C {
> +  int2 a, b, c;
> +  C(const int2& r = {11,66})
> +   : a{r} // { dg-error "invalid conversion from .const int\\*. to .int. .\\-fpermissive." }
> +   , b(a) // { dg-error "array used as initializer" }
> +   , c{b} // { dg-error "invalid conversion from .int\\*. to .int. .\\-fpermissive." }
> +     {}
> +};
> +
> +// Not a test; a workaround to construct a single array member from array
> +struct D {
> +  int2 d;
> +  constexpr D(const int2& r = {})
> +   : D{__builtin_bit_cast(D,r)} {}
> +};
> +constexpr D d{{11,66}};
> +constexpr D e{b.a};
> diff --git a/gcc/testsuite/g++.dg/init/array-copy4.C b/gcc/testsuite/g++.dg/init/array-copy4.C
> new file mode 100644
> index 00000000000..8db2852011a
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/init/array-copy4.C
> @@ -0,0 +1,42 @@
> +// PR c++/103238 (array-copy extensions for P1997)
> +// Array member initialization compile tests -
> +// (c.f. array-copy3.C for compile fail tests)
> +
> +// { dg-do compile { target c++11 } } c++11 for uniform init
> +// { dg-additional-options "-farray-copy" }
> +
> +typedef int int2[2];
> +
> +struct A { int2 a; };
> +
> +A ad { int2{11,66} };
> +A ai = { int2{11,66} };
> +
> +struct B { int2 a, b, c, d; };
> +
> +constexpr
> +B b {
> +    {11,66}
> +  , {b.a}
> +  , (b.b)
> +  ,  b.c
> +};
> +
> +struct C {
> +  int2 a, b, c;
> +  C(const int2& r = {11,66})
> +   : a{r}
> +   , b(a)
> +   , c{b}
> +     {}
> +};
> +
> +template<class T>
> +constexpr int equal(T const& a, T const& b) {
> +  using bytes = unsigned char[sizeof(T)];
> +  return __builtin_memcmp(
> +         __builtin_bit_cast(bytes,a),
> +         __builtin_bit_cast(bytes,b),
> +         sizeof(T)) == 0;
> +}
> +static_assert( equal(b, B{{11,66},{11,66},{11,66},{11,66}}), "");
> diff --git a/gcc/testsuite/g++.dg/init/array-copy5.C b/gcc/testsuite/g++.dg/init/array-copy5.C
> new file mode 100644
> index 00000000000..a3b6c275f2b
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/init/array-copy5.C
> @@ -0,0 +1,36 @@
> +// PR c++/103238 (array-copy extensions for P1997)
> +// Array member initialization nocompile tests, nsdmi and designated init
> +// should give same errors before and after the array-copy patch.
> +
> +// { dg-do compile { target c++14 } } c++14 for aggregate with member inits
> +// { dg-options "" }
> +//
> +
> +typedef int int2[2];
> +
> +struct A { int2 a = int2{11,66}; }; // { dg-error "array must be initialized with a brace-enclosed initializer" }
> +
> +constexpr
> +A a { .a = int2{11,66} }; // { dg-error "array must be initialized with a brace-enclosed initializer" }
> +A y = { .a{int2{11,66}} }; // { dg-error "taking address of temporary array" }
> +
> +struct B {
> +  int2 a = {11,66};
> +  int2 b = a; // { dg-error "array must be initialized with a brace-enclosed initializer" }
> +  int2 c = {b}; // { dg-error "invalid conversion from .int\\*. to .int. .\\-fpermissive." }
> +  int2 d {c}; // { dg-error "invalid conversion from .int\\*. to .int. .\\-fpermissive." }
> +};
> +
> +constexpr
> +B b {
> +    {11,66}
> +  , {b.a} // { dg-error "invalid conversion from .const int\\*. to .int. .\\-fpermissive." }
> +  , (b.b) // { dg-error "array must be initialized with a brace-enclosed initializer" }
> +  ,  b.c
> +};
> +
> +B bd { .a{11,66}, .b = bd.a, .c {bd.b}, .d = {bd.c} }; // { dg-error "array must be initialized with a brace-enclosed initializer" }
> +
> +struct D : A {
> +  B b {.a{11,66}, .b = b.a, .c {b.b}, .d = {b.c}}; // { dg-error "array must be initialized with a brace-enclosed initializer" }
> +};
> diff --git a/gcc/testsuite/g++.dg/init/array-copy6.C b/gcc/testsuite/g++.dg/init/array-copy6.C
> new file mode 100644
> index 00000000000..09b7478e07f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/init/array-copy6.C
> @@ -0,0 +1,51 @@
> +// PR c++/103238 (array-copy extensions for P1997)
> +// Array member initialization compile tests, nsdmi and designated init
> +// (c.f. array-copy5.C for compile fail tests)
> +
> +// { dg-do compile { target c++20 } }
> +//
> +// { dg-additional-options "-farray-copy" }
> +
> +typedef int int2[2];
> +
> +struct A { int2 a = int2{11,66}; };
> +
> +constexpr
> +A a { .a = int2{11,66} };
> +A y = { .a{int2{11,66}} };
> +
> +struct B {
> +  int2 a = {11,66};
> +  int2 b = a;
> +  int2 c = {b};
> +  int2 d {c};
> +};
> +
> +constexpr
> +B b {
> +    {11,66}
> +  , {b.a}
> +  , (b.b)
> +  ,  b.c
> +};
> +
> +B bd { .a{11,66}, .b = bd.a, .c {bd.b}, .d = {bd.c} };
> +
> +struct D : A {
> +  B b {.a{11,66}, .b = b.a, .c {b.b}, .d = {b.c}};
> +};
> +
> +constexpr
> +D d;
> +
> +template<class T>
> +constexpr int equal(T const& a, T const& b) {
> +  using bytes = unsigned char[sizeof(T)];
> +  return __builtin_memcmp(
> +         __builtin_bit_cast(bytes,a),
> +         __builtin_bit_cast(bytes,b),
> +         sizeof(T)) == 0;
> +}
> +static_assert( equal(b, B{}), "");
> +static_assert( equal(d, D{}), "");
> +static_assert( equal(d, D{a,b}), "");
> 


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 3/3] c++: P1997 array-copy extensions: Assignment, return,  etc. [PR103238]
  2021-11-22  2:51 ` [PATCH 3/3] c++: P1997 array-copy extensions: Assignment, return, etc. [PR103238] Will Wray
  2021-11-22 20:41   ` Joseph Myers
@ 2021-11-29 22:44   ` Jason Merrill
  1 sibling, 0 replies; 9+ messages in thread
From: Jason Merrill @ 2021-11-29 22:44 UTC (permalink / raw)
  To: Will Wray, gcc-patches

On 11/21/21 21:51, Will Wray via Gcc-patches wrote:
> This second patch completes the work of the first 'array-copy' patch to
> provide first-cut implementations of all P1997 features. It adds:
> 
>   * Assignments to arrays from array values,    a = b;
>   * Placeholder auto in array declarations,     auto cp[] = a;
>   * Array as a return type from functions WIP,  auto f() -> T[N];
>   * Parsing of array pseudo-destructors         a.~A()
>     (only parsing for now, untested)

Let's not accept the pseudo-destructor and silently ignore it.  Either 
we should delay the parsing change until the semantics are implemented, 
or parse it and give a sorry().

> Assignments a = b were easily allowed by changing branch conditions.
> Assignments a = {e...} were trickier (a case not mentioned in P1997):
> 
>      int a[16]; a = {0,1,1,2}; a = {}; // assignments from init-lists
> 
> The semantics is the same as for struct aggregates:
> (1) Aggregate initialization of an rhs array of the lhs type
>      (so trailing elements with no initializer are value initialized)
> (2) Copy-initialization of the lhs from the rhs.
> 
> The special case of an optionally-braced array value is allowed so that
> a = b and a = {b} are generally equivalent for same type arrays a and b.
> However, the now special-special case of assignment from a braced string-
> literal currently only supports exact-match (same as for other arrays):
> 
>      char a[4]; a={"c++"} /* OK */; a={"c"} /* FAILs but should work */;
> 
> Array return from function is work in progress. The tests show what works.
> I'm stuck in unfamiliar territory so it's best to submit what I have to be
> reviewed for hints on how to progress.

Let's split out array return into a separate patch for now.  It also has 
ABI implications.

> Please try the patch; play, stress it, and report the FAILS.
> 
> 	PR c++/103238
> 
> gcc/c/ChangeLog:
> 
> 	* c-decl.c (grokdeclarator): Don't complain of array returns.
> 
> gcc/cp/ChangeLog:
> 
> 	* call.c (can_convert_array): Extend to include array inits.
> 	(standard_conversion): No decay for same-type array. Call build_conv.
> 	(implicit_conversion_1): Call reshape_init for arrays too.
> 	* decl.c (grokdeclarator): Don't complain of array returns.
> 	* parser.c (cp_parser_postfix_dot_deref_expression): parse array ~A().
> 	* pt.c (tsubst_function_type): Array type return is not a failure.
> 	(do_auto_deduction): Placeholder auto deduction of array element type.
> 	* tree.c (lvalue_kind): clk_class should include array (I think?).
> 	* typeck.c (cp_build_modify_expr): Call reshape init to strip optional
> 	braces. Allow NOP_EXPR for array assignment.
> 	(convert_for_assignment): New if-block for same-type array convert,
> 	strips optional braces, but rejects STRING_CST rhs shorter than lhs.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/init/array-copy10.C: New test. auto[] deduce 'after' PASSes
> 	* g++.dg/init/array-copy11.C: New test. Array return 'before' XFAILs
> 	* g++.dg/init/array-copy12.C: New test. Array return 'after' PASSes
> 	* g++.dg/init/array-copy7.C: New test. Array assign 'before' XFAILs
> 	* g++.dg/init/array-copy8.C: New test. Array assign 'after' PASSes
> 	* g++.dg/init/array-copy9.C: New test. auto[] deduce 'before' XFAILs
> ---
>   gcc/c/c-decl.c                           |  2 +-
>   gcc/cp/call.c                            | 43 +++++++++++------
>   gcc/cp/decl.c                            |  2 +-
>   gcc/cp/parser.c                          |  4 +-
>   gcc/cp/pt.c                              | 13 +++++-
>   gcc/cp/tree.c                            |  3 +-
>   gcc/cp/typeck.c                          | 26 +++++++++--
>   gcc/testsuite/g++.dg/init/array-copy10.C | 57 +++++++++++++++++++++++
>   gcc/testsuite/g++.dg/init/array-copy11.C | 13 ++++++
>   gcc/testsuite/g++.dg/init/array-copy12.C | 79 ++++++++++++++++++++++++++++++++
>   gcc/testsuite/g++.dg/init/array-copy7.C  | 40 ++++++++++++++++
>   gcc/testsuite/g++.dg/init/array-copy8.C  | 56 ++++++++++++++++++++++
>   gcc/testsuite/g++.dg/init/array-copy9.C  | 57 +++++++++++++++++++++++
>   13 files changed, 372 insertions(+), 23 deletions(-)
> 
> diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
> index 3e28a038095..031c43d189f 100644
> --- a/gcc/c/c-decl.c
> +++ b/gcc/c/c-decl.c
> @@ -7055,7 +7055,7 @@ grokdeclarator (const struct c_declarator *declarator,
>   			    "returning a function");
>   		type = integer_type_node;
>   	      }
> -	    if (TREE_CODE (type) == ARRAY_TYPE)
> +	    if (TREE_CODE (type) == ARRAY_TYPE && !flag_array_copy)
>   	      {
>   		if (name)
>   		  error_at (loc, "%qE declared as function returning an array",
> diff --git a/gcc/cp/call.c b/gcc/cp/call.c
> index 4ee21c7bdbd..c73fb73d86e 100644
> --- a/gcc/cp/call.c
> +++ b/gcc/cp/call.c
> @@ -908,29 +908,34 @@ static bool
>   can_convert_array (tree atype, tree from, int flags, tsubst_flags_t complain)
>   {
>     tree elttype = TREE_TYPE (atype);
> -  unsigned i;
>   
>     if (TREE_CODE (from) == CONSTRUCTOR)
>       {
> -      for (i = 0; i < CONSTRUCTOR_NELTS (from); ++i)
> +      for (auto&& ce : CONSTRUCTOR_ELTS (from))
>   	{
> -	  tree val = CONSTRUCTOR_ELT (from, i)->value;
> -	  bool ok;
> -	  if (TREE_CODE (elttype) == ARRAY_TYPE)
> -	    ok = can_convert_array (elttype, val, flags, complain);
> -	  else
> -	    ok = can_convert_arg (elttype, TREE_TYPE (val), val, flags,
> -				  complain);
> -	  if (!ok)
> +	  tree val = tree_strip_any_location_wrapper (ce.value);
> +	  if ((TREE_CODE (val) == STRING_CST
> +	       && !can_convert_array (elttype, val, flags, complain))
> +	      || (TREE_CODE (elttype) == ARRAY_TYPE
> +		  ? !can_convert_array (elttype, val, flags, complain)
> +		  : !can_convert_arg (elttype, TREE_TYPE (val), val, flags,
> +				      complain)))

I don't understand this change; you add STRING_CST handling but handle 
it with the same call as an array elttype, with which the old code 
should have already handled string constants.  What are you trying to do 
here?

>   	    return false;
>   	}
>         return true;
>       }
>   
> +  from = tree_strip_any_location_wrapper (from);
> +
>     if (char_type_p (TYPE_MAIN_VARIANT (elttype))
> -      && TREE_CODE (tree_strip_any_location_wrapper (from)) == STRING_CST)
> +      && TREE_CODE (from) == STRING_CST)
>       return array_string_literal_compatible_p (atype, from);
>   
> +  if (flag_array_copy
> +      && TREE_CODE (from) == ARRAY_TYPE)
> +    return same_type_ignoring_top_level_qualifiers_p (atype,
> +			   tree_strip_any_location_wrapper (from));

Previously 'from' was an expression; here you're treating it as a type. 
  This 'if' will never succeed.

> +
>     /* No other valid way to aggregate initialize an array.  */
>     return false;
>   }
> @@ -1241,7 +1246,10 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
>     tcode = TREE_CODE (to);
>   
>     conv = build_identity_conv (from, expr);
> -  if (fcode == FUNCTION_TYPE || fcode == ARRAY_TYPE)
> +  if (fcode == FUNCTION_TYPE
> +      || (fcode == ARRAY_TYPE
> +	  && !(flag_array_copy && tcode == ARRAY_TYPE
> +	       && same_type_ignoring_top_level_qualifiers_p (to, from))))
>       {
>         from = type_decays_to (from);
>         fcode = TREE_CODE (from);
> @@ -1538,6 +1546,10 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
>     else if (fcode == VECTOR_TYPE && tcode == VECTOR_TYPE
>   	   && vector_types_convertible_p (from, to, false))
>       return build_conv (ck_std, to, conv);
> +  else if (flag_array_copy
> +	   && fcode == ARRAY_TYPE && tcode == ARRAY_TYPE
> +	   && same_type_ignoring_top_level_qualifiers_p (from, to))
> +    return build_conv (ck_std, to, conv);

Rather than change two places in this function, let's do this just 
before the call to type_decays_to in the previous hunk.

>     else if (MAYBE_CLASS_TYPE_P (to) && MAYBE_CLASS_TYPE_P (from)
>   	   && is_properly_derived_from (from, to))
>       {
> @@ -2015,9 +2027,10 @@ implicit_conversion_1 (tree to, tree from, tree expr, bool c_cast_p,
>   
>     /* Call reshape_init early to remove redundant braces.  */
>     if (expr && BRACE_ENCLOSED_INITIALIZER_P (expr)
> -      && CLASS_TYPE_P (to)
> -      && COMPLETE_TYPE_P (complete_type (to))
> -      && !CLASSTYPE_NON_AGGREGATE (to))
> +      && ((CLASS_TYPE_P (to)
> +	  && COMPLETE_TYPE_P (complete_type (to))
> +	  && !CLASSTYPE_NON_AGGREGATE (to))
> +	 || (flag_array_copy && TREE_CODE (to) == ARRAY_TYPE)))
>       {
>         expr = reshape_init (to, expr, complain);
>         if (expr == error_mark_node)
> diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
> index 1010fa2c53f..872403b1ac1 100644
> --- a/gcc/cp/decl.c
> +++ b/gcc/cp/decl.c
> @@ -12719,7 +12719,7 @@ grokdeclarator (const cp_declarator *declarator,
>   			  "a function", name);
>   		return error_mark_node;
>   	      }
> -	    if (TREE_CODE (type) == ARRAY_TYPE)
> +	    if (TREE_CODE (type) == ARRAY_TYPE && !flag_array_copy)
>   	      {
>   		error_at (typespec_loc, "%qs declared as function returning "
>   			  "an array", name);
> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
> index 65f0f112011..5dd6126dc50 100644
> --- a/gcc/cp/parser.c
> +++ b/gcc/cp/parser.c
> @@ -8120,7 +8120,9 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser,
>        we must be looking at a pseudo-destructor-name.  If POSTFIX_EXPRESSION
>        is type dependent, it can be pseudo-destructor-name or something else.
>        Try to parse it as pseudo-destructor-name first.  */
> -  if ((scope && SCALAR_TYPE_P (scope)) || dependent_p)
> +  if ((scope && (SCALAR_TYPE_P (scope)
> +		 || (flag_array_copy && TREE_CODE (scope) == ARRAY_TYPE)))
> +      || dependent_p) /* TODO: P1997 array pseudo-destructor.  */
>       {
>         tree s;
>         tree type;
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index b27eea33272..66ed90699cd 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -15152,7 +15152,7 @@ tsubst_function_type (tree t,
>       return error_mark_node;
>     /* DR 486 clarifies that creation of a function type with an
>        invalid return type is a deduction failure.  */
> -  if (TREE_CODE (return_type) == ARRAY_TYPE
> +  if ((TREE_CODE (return_type) == ARRAY_TYPE && !flag_array_copy)
>         || TREE_CODE (return_type) == FUNCTION_TYPE)
>       {
>         if (complain & tf_error)
> @@ -29812,6 +29812,17 @@ do_auto_deduction (tree type, tree init, tree auto_node,
>         targs = make_tree_vec (1);
>         TREE_VEC_ELT (targs, 0) = TREE_TYPE (init);
>       }
> +  else if (flag_array_copy
> +	   && (context == adc_variable_type
> +	       || context == adc_return_type)
> +	   && auto_node == TREE_TYPE (type)
> +	   && !TYPE_REF_P (type)

I think this line should check TREE_CODE (type) == ARRAY_TYPE; we also 
don't want this case to handle auto*.

This isn't doing what the proposal says, which involves template 
argument deduction of reference-to-array type, but the wording in the 
proposal won't handle deducing the array bound, so it's fine to go with 
this simple approach for now.

> +	   && init != error_mark_node
> +	   && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE)
> +    {
> +      targs = make_tree_vec (1);
> +      TREE_VEC_ELT (targs, 0) = TREE_TYPE (TREE_TYPE (init));
> +    }
>     else if (AUTO_IS_DECLTYPE (auto_node))
>       {
>         tree stripped_init = tree_strip_any_location_wrapper (init);
> diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
> index 32ddf835a91..e10c574de94 100644
> --- a/gcc/cp/tree.c
> +++ b/gcc/cp/tree.c
> @@ -280,7 +280,8 @@ lvalue_kind (const_tree ref)
>   
>       case CALL_EXPR:
>         /* We can see calls outside of TARGET_EXPR in templates.  */
> -      if (CLASS_TYPE_P (TREE_TYPE (ref)))
> +      if (CLASS_TYPE_P (TREE_TYPE (ref))
> +	  || TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE)
>   	return clk_class;
>         return clk_none;
>   
> diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
> index 8e96a925186..e1a9446fd0f 100644
> --- a/gcc/cp/typeck.c
> +++ b/gcc/cp/typeck.c
> @@ -9105,9 +9105,11 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
>       {
>         int from_array;
>   
> +      if (flag_array_copy && BRACE_ENCLOSED_INITIALIZER_P (newrhs))
> +	newrhs = reshape_init (lhstype, newrhs, complain);

Let's move this into the BRACE_ENCLOSED_INITIALIZER_P block just below.

>         if (BRACE_ENCLOSED_INITIALIZER_P (newrhs))
>   	{
> -	  if (modifycode != INIT_EXPR)
> +	  if (modifycode != INIT_EXPR && !flag_array_copy)
>   	    {
>   	      if (complain & tf_error)
>   		error_at (loc,
> @@ -9127,7 +9129,8 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
>         else if ((TREE_CODE (tree_strip_any_location_wrapper (newrhs))
>   		== STRING_CST)
>   	       && char_type_p (TREE_TYPE (TYPE_MAIN_VARIANT (lhstype)))
> -	       && modifycode == INIT_EXPR)
> +	       && (modifycode == INIT_EXPR
> +		   || (modifycode == NOP_EXPR && flag_array_copy)))
>   	{
>   	  newrhs = digest_init (lhstype, newrhs, complain);
>   	  if (newrhs == error_mark_node)

I'm surprised there's no change to the following code, a bit lower in 
the function:
>       /* Allow array assignment in compiler-generated code.  */
>       else if (!current_function_decl
>                || !DECL_DEFAULTED_FN (current_function_decl))

> @@ -9682,7 +9685,24 @@ convert_for_assignment (tree type, tree rhs,
>         rhs = mark_rvalue_use (rhs);
>         return convert (type, rhs);
>       }
> -
> +  /* Deal with array-valued rhs of same type as lhs 'type', optionally braced.
> +     This includes STRING_CST, but only of same type - i.e. same size;
> +     TODO: P1997 convert STRING_CST shorter than 'type' to full size.  */
> +  if (flag_array_copy && TREE_CODE (type) == ARRAY_TYPE)
> +    {
> +      if (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (rhs)))
> +	{
> +	  rhs = mark_rvalue_use (rhs);
> +	  return convert (type, rhs);
> +	}
> +      if (BRACE_ENCLOSED_INITIALIZER_P (rhs)
> +	  && CONSTRUCTOR_NELTS (rhs) == 1
> +	  && same_type_ignoring_top_level_qualifiers_p (type,
> +	     TREE_TYPE (tree_strip_any_location_wrapper (
> +					CONSTRUCTOR_ELT (rhs, 0)->value))))
> +	return convert (type, mark_rvalue_use (
> +					CONSTRUCTOR_ELT (rhs, 0)->value));
> +    }

This hunk shouldn't be needed; I think instead you want to change the 
code in reshape_init_r that handles { e }:
>   /* "If T is a class type and the initializer list has a single element of                                    
>      type cv U, where U is T or a class derived from T, the object is                                          
>      initialized from that element."  Even if T is an aggregate.  */


>     if (rhs == error_mark_node || rhstype == error_mark_node)
>       return error_mark_node;
>     if (TREE_CODE (rhs) == TREE_LIST && TREE_VALUE (rhs) == error_mark_node)
> diff --git a/gcc/testsuite/g++.dg/init/array-copy10.C b/gcc/testsuite/g++.dg/init/array-copy10.C
> new file mode 100644
> index 00000000000..5fc2df727fa
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/init/array-copy10.C
> @@ -0,0 +1,57 @@
> +// PR c++/103238 (array-copy extensions for P1997)
> +// Array auto placeholder element deduction compile tests
> +// (c.f. array-copy9.C for compile fail tests)
> +
> +// { dg-do compile { target c++11 } }
> +// { dg-additional-options "-farray-copy" }
> +
> +template <typename...> struct same{ enum:bool{v=false}; };
> +template <typename T> struct same<T,T>{ enum:bool{v=true}; };
> +template <typename T, typename X, typename...Y>
> +struct same<T,X,Y...>{ enum:bool{v = same<T,X>::v && same<T,Y...>::v}; };
> +template<typename...T>
> +constexpr bool all_same_t(T const&...){return same<T...>::v;}
> +
> +typedef int int2[2];
> +int2 a {11,66};
> +
> +auto er[2] {1,2};
> +// { dg-error "direct-list-initialization of .auto. requires exactly one element .\\-fpermissive." "" { target *-*-* } .-1 }
> +// { dg-error "deducing from brace-enclosed initializer list requires" "" { target *-*-* } .-2 }

These errors are wrong with this extension, we certainly shouldn't test 
for them.

> +auto il[2] = {1,2};
> +// { dg-error "deducing from brace-enclosed initializer list requires" "" { target *-*-* } .-1 }
> +auto um[2] = {a};
> +// { dg-error "deducing from brace-enclosed initializer list requires" "" { target *-*-* } .-1 }
> +
> +// Initializations from from rvalue array
> +auto g[2] = int2{11,66};
> +auto j[2] ( int2{11,66} );  // P0960
> +auto l[2] { int2{11,66} };
> +// auto + size deduction :
> +auto m[] = int2{11,66};
> +auto n[] ( int2{11,66} );  // P0960
> +auto p[] { int2{11,66} };
> +
> +static_assert( all_same_t(a,g,j,l,m,n,p), "");
> +
> +auto str[] = "str";
> +
> +auto cpy[4] = str;
> +auto cpp[4] (str); // P0960
> +auto cpw[4] {str};
> +// auto + size deduction :
> +auto cpu[] = str;
> +auto cpv[] (str); // P0960
> +auto cpx[] {str};
> +
> +static_assert( all_same_t(str,cpy,cpp,cpw,cpu,cpv,cpx), "");
> +
> +auto const& ref = "str";
> +
> +auto rpy[4] = ref;
> +auto rpp[4] (ref); // P0960
> +auto rpw[4] {ref};
> +// auto + size deduction :
> +auto rpu[] = ref;
> +auto rpv[] (ref); // P0960
> +auto rpx[] {ref};
> diff --git a/gcc/testsuite/g++.dg/init/array-copy11.C b/gcc/testsuite/g++.dg/init/array-copy11.C
> new file mode 100644
> index 00000000000..ac4d0c0dcb8
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/init/array-copy11.C
> @@ -0,0 +1,13 @@
> +// PR c++/103238 (array-copy extensions for P1997)
> +// Array function return nocompile tests -
> +// should give same errors before and after the array-copy patch.
> +
> +// { dg-do compile { target c++11 } }
> +//
> +
> +constexpr auto a() -> char[2] {return "a";} // { dg-error "declared as function returning an array" }
> +
> +constexpr char char2(char,char)[2]; // { dg-error "declared as function returning an array" }
> +constexpr auto char2(char,char) -> char[2]; // { dg-error "declared as function returning an array" }
> +
> +constexpr char char2(char a,char b)[2] {return{a,b};} // { dg-error "declared as function returning an array" }
> diff --git a/gcc/testsuite/g++.dg/init/array-copy12.C b/gcc/testsuite/g++.dg/init/array-copy12.C
> new file mode 100644
> index 00000000000..f6588b002ab
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/init/array-copy12.C
> @@ -0,0 +1,79 @@
> +// PR c++/103238 (array-copy extensions for P1997)
> +// Array function return compile tests -
> +// (c.f. array-copy11.C for compile fail tests)
> +
> +// { dg-do run { target c++11 } }
> +// { dg-additional-options "-farray-copy" }
> +
> +constexpr bool equal(const char(&a)[2]
> +                    ,const char(&b)[2])
> +{
> +  return a[0]==b[0]
> +      && a[1]==b[1];
> +}
> +
> +template<int N>
> +using charN = char[N];
> +using chars = char[];
> +
> +// Note a() return is const qualified, else constexpr test below fails FIXME
> +constexpr auto a() -> const char[2] {return "a";}
> +constexpr auto b() -> char[2] {return{'b'};} // init-list not folding causes ICE
> +constexpr auto c() -> char[2] {return{"c"};}
> +constexpr auto d() -> char[2] {return chars{"d"};}
> +
> +// Note the lambda return is not const qualified yet works constexpr below
> +auto e = []() -> char[2] {char ce[2]{'e'}; return ce;};
> +
> +static_assert( equal(a(),"a"), "");
> +//static_assert( equal(b(),"b"), ""); // ICE gcc assert
> +static_assert( equal(c(),"c"), "");
> +static_assert( equal(d(),"d"), "");
> +static_assert( equal(e(),"e"), "");
> +// { dg-error "non-constant condition for static assertion" "" { target c++14_down } .-1 }
> +// { dg-error "call to non-.constexpr. function ..lambda" "" { target c++14_down } .-2 }
> +
> +constexpr auto bc[] = b();
> +static_assert( equal(bc,"b"), "");
> +
> +constexpr char char2(char,char)[2];
> +constexpr auto char2(char,char) -> char[2]; // same type redeclaration
> +constexpr char char2(char a,char b)[2] {return{a,b};} // .. definition
> +
> +//static_assert( equal(char2('a','b'),{'a','b'}), ""); // ICE gcc assert
> +
> +constexpr charN<2> char2cp(const charN<2>& a) {return a;}
> +constexpr charN<2> char2cb(const charN<2>& a) {return{a};}
> +
> +constexpr char c2a[2] = char2('a',0);
> +constexpr char cpa[] = char2cp("a");
> +constexpr auto cpb[] = char2cb("a");
> +
> +static_assert( equal( c2a, "a") ,"");
> +static_assert( equal( cpa, "a") ,"");
> +static_assert( equal( cpb, "a") ,"");
> +
> +constexpr auto f8(const float(&a)[8]) -> float[8] {return{};}
> +
> +template <int N>
> +constexpr int atoi()[N] { return {__integer_pack(N)...}; }
> +
> +template <typename T, int N>
> +constexpr int ind(const T (&r)[N], int i) { return r[i]; }
> +
> +constexpr auto atoi6[] = atoi<6>();
> +
> +static_assert(ind(atoi6,4) == 4, "");
> +
> +// FAILs below, can't pass array return to a reference argument
> +
> +//static_assert(ind(atoi<6>(),4) == 4, ""); // ICE
> +
> +int main() {
> +  if (!equal(a(),"a")) __builtin_abort();
> +  // if (!equal(b(),"b")) __builtin_abort(); // ICE
> +  if (!equal(c(),"c")) __builtin_abort();
> +  if (!equal(d(),"d")) __builtin_abort();
> +  if (!equal(e(),"e")) __builtin_abort();
> +   // if (ind(atoi<6>(),4) != 4) __builtin_abort(); // ICE
> +}
> diff --git a/gcc/testsuite/g++.dg/init/array-copy7.C b/gcc/testsuite/g++.dg/init/array-copy7.C
> new file mode 100644
> index 00000000000..9cee097d560
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/init/array-copy7.C
> @@ -0,0 +1,40 @@
> +// PR c++/103238 (array-copy extensions for P1997)
> +// Array assignment nocompile tests
> +// should give same errors before and after the array-copy patch.
> +
> +// { dg-do compile { target c++11 } }
> +//
> +
> +int aggr_ass()
> +{
> +  int a[2] = {11,66}, b[2] = {};
> +
> +  b = a; // { dg-error "invalid array assignment" }
> +  b = {a}; // { dg-error "assigning to an array from an initializer list" }
> +  b = {11,66}; // { dg-error "assigning to an array from an initializer list" }
> +  b = {}; // { dg-error "assigning to an array from an initializer list" }
> +  a = {11}; // { dg-error "assigning to an array from an initializer list" }
> +  return a[1] + b[0] + b[1];
> +}
> +
> +char clr()
> +{
> +  char abc[] = {'a','b','c'};
> +  abc = {""}; // { dg-error "assigning to an array from an initializer list" }
> +  return abc[0] + abc[1] + abc[2];
> +}
> +
> +struct A
> +{
> +  int a[2];
> +  A(const int(&b)[2]) { a = b; } // { dg-error "invalid array assignment" }
> +};
> +
> +char strtab[4][8] = {"hello","world"};
> +
> +void str_ass()
> +{
> +  strtab = {"Hello","World"}; // { dg-error "assigning to an array from an initializer list" }
> +  strtab[0] = {"hi"}; // { dg-error "assigning to an array from an initializer list" }
> +  strtab[1] = strtab[0]; // { dg-error "invalid array assignment" }
> +}
> diff --git a/gcc/testsuite/g++.dg/init/array-copy8.C b/gcc/testsuite/g++.dg/init/array-copy8.C
> new file mode 100644
> index 00000000000..582f35f4340
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/init/array-copy8.C
> @@ -0,0 +1,56 @@
> +// PR c++/103238 (array-copy extensions for P1997)
> +// Array assignment compile tests -
> +// (c.f. array-copy7.C for compile fail tests)
> +
> +// { dg-do run { target c++11 } }
> +// { dg-additional-options "-farray-copy" }
> +
> +int aggr_ass()
> +{
> +  int a[2] = {11,66}, b[2] = {};
> +
> +  b = a;
> +  b = {a};
> +  b = {11,66};
> +  b = {};
> +  a = {11};
> +  return a[1] + b[0] + b[1];
> +}
> +
> +char clr()
> +{
> +  char abc[] = {'a','b','c'};
> +  abc = {""};

It looks like you don't test e.g.

abc = "";

anywhere.

> +  return abc[0] + abc[1] + abc[2];
> +}
> +
> +struct A
> +{
> +  int a[2];
> +  A(const int(&b)[2]) { a = b; }
> +};
> +
> +char strtab[4][8] = {"hello","world"};
> +
> +void str_ass()
> +{
> +  strtab = {"Hello","World"};
> +  strtab[0] = {"hi"};
> +  strtab[1] = strtab[0];
> +}
> +
> +int main()
> +{
> +  char hi[8] = "hi";
> +  str_ass();
> +  if (__builtin_memcmp(strtab[0],hi,8) != 0
> +   || __builtin_memcmp(strtab[1],hi,8) != 0)
> +    __builtin_abort();
> +
> +  if (aggr_ass() || clr())
> +    __builtin_abort();
> +
> +  A a({11,66});
> +  if (a.a[0] != 11 || a.a[1] != 66)
> +   __builtin_abort();
> +}
> diff --git a/gcc/testsuite/g++.dg/init/array-copy9.C b/gcc/testsuite/g++.dg/init/array-copy9.C
> new file mode 100644
> index 00000000000..7bbc615a204
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/init/array-copy9.C
> @@ -0,0 +1,57 @@
> +// PR c++/103238 (array-copy extensions for P1997)
> +// Array auto placeholder element deduction nocompile tests
> +// should give same errors before and after the array-copy patch.
> +
> +// { dg-do compile { target c++11 } }
> +//
> +
> +template <typename...> struct same{ enum:bool{v=false}; };
> +template <typename T> struct same<T,T>{ enum:bool{v=true}; };
> +template <typename T, typename X, typename...Y>
> +struct same<T,X,Y...>{ enum:bool{v = same<T,X>::v && same<T,Y...>::v}; };
> +template<typename...T>
> +constexpr bool all_same_t(T const&...){return same<T...>::v;}
> +
> +typedef int int2[2];
> +int2 a {11,66};
> +
> +auto er[2] {1,2};
> +// { dg-error "direct-list-initialization of .auto. requires exactly one element .\\-fpermissive." "" { target *-*-* } .-1 }
> +// { dg-error "deducing from brace-enclosed initializer list requires" "" { target *-*-* } .-2 }
> +auto il[2] = {1,2};
> +// { dg-error "deducing from brace-enclosed initializer list requires" "" { target *-*-* } .-1 }
> +auto um[2] = {a};
> +// { dg-error "deducing from brace-enclosed initializer list requires" "" { target *-*-* } .-1 }
> +
> +// Initializations from from rvalue array
> +auto g[2] = int2{11,66}; // { dg-error "unable to deduce" }
> +auto j[2] ( int2{11,66} ); // { dg-error "unable to deduce" }
> +auto l[2] { int2{11,66} }; // { dg-error "unable to deduce" }
> +// auto + size deduction :
> +auto m[] = int2{11,66}; // { dg-error "unable to deduce" }
> +auto n[] ( int2{11,66} ); // { dg-error "unable to deduce" }
> +auto p[] { int2{11,66} }; // { dg-error "unable to deduce" }
> +
> +static_assert( all_same_t(a,g,j,l,m,n,p), "");
> +
> +auto stp[] = "str"; // { dg-error "unable to deduce" }
> +char str[] = "str";
> +auto cpy[4] = str; // { dg-error "unable to deduce" }
> +auto cpp[4] (str); // { dg-error "unable to deduce" }
> +auto cpw[4] {str}; // { dg-error "unable to deduce" }
> +// auto + size deduction :
> +auto cpu[] = str; // { dg-error "unable to deduce" }
> +auto cpv[] (str); // { dg-error "unable to deduce" }
> +auto cpx[] {str}; // { dg-error "unable to deduce" }
> +
> +static_assert( all_same_t(str,cpy,cpp,cpw,cpu,cpv,cpx), "");
> +
> +auto const& ref = "str";
> +
> +auto rpy[4] = ref; // { dg-error "unable to deduce" }
> +auto rpp[4] (ref); // { dg-error "unable to deduce" }
> +auto rpw[4] {ref}; // { dg-error "unable to deduce" }
> +// auto + size deduction :
> +auto rpu[] = ref; // { dg-error "unable to deduce" }
> +auto rpv[] (ref); // { dg-error "unable to deduce" }
> +auto rpx[] {ref}; // { dg-error "unable to deduce" }
> 


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2021-11-29 22:44 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-22  2:51 [PATCH 0/3] P1997 'array-copy' patchset [PR103238] Will Wray
2021-11-22  2:51 ` [PATCH 1/3] c++: designated init of char array by string constant [PR55227] Will Wray
2021-11-25 16:05   ` Jason Merrill
2021-11-22  2:51 ` [PATCH 2/3] c++: P1997 array-copy extensions: Initialization [PR103238] Will Wray
2021-11-27 22:56   ` Jason Merrill
2021-11-22  2:51 ` [PATCH 3/3] c++: P1997 array-copy extensions: Assignment, return, etc. [PR103238] Will Wray
2021-11-22 20:41   ` Joseph Myers
2021-11-22 21:21     ` will wray
2021-11-29 22:44   ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).