diff mbox series

[1/3] c++: designated init of char array by string constant [PR55227]

Message ID 20211122025114.3167997-2-wjwray@gmail.com
State New
Headers show
Series P1997 'array-copy' patchset [PR103238] | expand

Commit Message

will wray Nov. 22, 2021, 2:51 a.m. UTC
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(-)

Comments

Jason Merrill Nov. 25, 2021, 4:05 p.m. UTC | #1
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>();
> +}
>
diff mbox series

Patch

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>();
+}