diff mbox series

c++ PR 55227: designated init of char array by string constant

Message ID CAKjnZWpA2Bm0BHRaPBvuJs4VSeRbvwE7iSDhxmuuEohosMNhig@mail.gmail.com
State New
Headers show
Series c++ PR 55227: designated init of char array by string constant | expand

Commit Message

will wray Nov. 4, 2021, 11:37 p.m. UTC
This patch aims to fix PR 55227; two underlying bugs that have caused:

(1) Rejection of valid designated initialization of char array fields by
string literals (a) when enclosed in optional braces or (b) unbraced
when the string literal is shorter than the target char array field.

(2) Acceptance of an invalid designator appearing within the braces of a
braced string literal, in which case the 'designator' was entirely
ignored and the string literal treated as a positional initializer.

Please review these changes carefully; I'm fairly new to this, so likely
to have made errors of omission, logic or an anon anomaly.

The fixes above also allow to address a FIXME in cp_complete_array_type,
otherwise obstructed by the designator bugs (see relevant comment here
https://patchwork.ozlabs.org/project/gcc/list/?series=199783)

Please suggest test cases for the newly inserted call to reshape_init.

(This patch is split from my upcoming 'P1997 array copy-semantic' patch,
 which will then extend this from string literal to any array value.)
Boostraps/regtests on x86_64-pc-linux-gnu.

        PR c++/55227

gcc/cp/ChangeLog:

        * decl.c (reshape_init_r): restrict has_designator_check,
        (cp_complete_array_type): do reshape_init on braced-init-list.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp2a/desig20.C: New test.
---
+
+template <class T>
+void t()
+{
+  C ca[] = { {.a=""}, {.a={""}}, };
+// { dg-warning "designated initializers only available with" "" {
target c++17_down } .-1 }
+}
+
+void u()
+{
+  return t<void>();
+}
diff mbox series

Patch

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 7c2a134e406..3bd6ed68a45 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -6820,6 +6820,7 @@  reshape_init_r (tree type, reshape_iter *d, tree
first_initializer_p,
     {
       tree str_init = init;
       tree stripped_str_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]).  */
@@ -6827,7 +6828,8 @@  reshape_init_r (tree type, reshape_iter *d, tree
first_initializer_p,
    && TREE_CODE (stripped_str_init) == CONSTRUCTOR
    && CONSTRUCTOR_NELTS (stripped_str_init) == 1)
  {
-   str_init = (*CONSTRUCTOR_ELTS (stripped_str_init))[0].value;
+   stripd.cur = CONSTRUCTOR_ELT (stripped_str_init, 0);
+   str_init = stripd.cur->value;
    stripped_str_init = tree_strip_any_location_wrapper (str_init);
  }

@@ -6836,7 +6838,8 @@  reshape_init_r (tree type, reshape_iter *d, tree
first_initializer_p,
  array types (one value per array element).  */
       if (TREE_CODE (stripped_str_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;
@@ -9541,23 +9544,10 @@  cp_complete_array_type (tree *ptype, tree
initial_value, bool do_default)
       unsigned HOST_WIDE_INT i;
       tree 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;
- }
+      if (TREE_CODE (initial_value) == CONSTRUCTOR
+   && 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..eb3ef5eda08
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/desig20.C
@@ -0,0 +1,47 @@ 
+// PR c++/55227
+// Test designated initializer for char array by string constant
+
+// { dg-do compile }
+// { dg-options "-pedantic" }
+
+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"}; // { dg-warning "designated initializers only
available with" "" { target c++17_down } .-0 }
+
+/* Cases b,c,d, designated, braced or mimatched-size, string literal,
+   previously rejected; "C99 designator 'a' outside aggregate initializer".
+*/
+C b = {.a=""}; // { dg-warning "designated initializers only
available with" "" { target c++17_down } .-0 }
+C c = {.a={""}}; // { dg-warning "designated initializers only
available with" "" { target c++17_down } .-0 }
+C d = {.a={"a"}}; // { dg-warning "designated initializers only
available with" "" { target c++17_down } .-0 }
+
+/* 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'}}; // { dg-warning "ISO C.. does not allow C99
designated initializers" }
+// { dg-warning "designated initializers only available with" "" {
target c++17_down } .-1 }
+
+/* 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" }
+// { dg-warning "ISO C.. does not allow C99 designated initializers"
"C99 desig" { target *-*-* } .-1 }
+C g = {{.a="a"}}; // { dg-error "C99 designator .a. outside aggregate
initializer" }
+// { dg-warning "designated initializers only available with" "" {
target c++17_down } .-1 }
+C h = {{.b="a"}}; // { dg-error "C99 designator .b. outside aggregate
initializer" }
+// { dg-warning "designated initializers only available with" "" {
target c++17_down } .-1 }