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}), "");
