[PATCH 3/3] c++: P1997 array-copy extensions: Assignment, return, etc. [PR103238]

Will Wray wjwray@gmail.com
Mon Nov 22 02:51:14 GMT 2021


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



More information about the Gcc-patches mailing list