Hi!

Martin's patch a few years ago started allowing flexible array members
inside of nested aggregates, similarly to what we were doing in C.
But C rejects cases where we in nested context try to initialize a flexible
array member with a non-empty initializer, because that is something that
can't really work. Say if a flexible array member is inside of a struct
and we are initializing an array of such structs, we can't really have
each array element with a different width based on how large was the
initializer for a particular element's flexible array member.
After Martin's change, we were accepting those and silently generating bogus
assembly (claiming some size of elements but the initializer really followed
the sizes of what was added there), then I think Nathan added some
verification and since then we usually just ICE on those.

This patch does the similar thing in the C++ FE to what the C FE does, i.e.
allow empty initializers of flexible array members ( {}, not "" as that is
already non-zero size) everywhere, and for others allow them only for the
outermost struct/class/union.
Allowing the empty flexible array members is IMHO useful, people can have
say some general structure that is sometimes used as toplevel object and
can be initialized with arbitrarily sized array, and sometimes just use it
inside other structs or arrays if the array isn't needed.

digest_init_r already had a nested argument, but it wasn't actually the
nesting this patch is looking for, because nested true is already in
processing the CONSTRUCTOR for flexible array member, so I've changed it to
an int that tracks limited depth information (just 0 (former nested ==
false), 1 and 2 (both former nested == true), where 2 is used when we
digest_init_r once or more times more).

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2017-12-08  Jakub Jelinek  <ja...@redhat.com>

        PR c++/80135
        PR c++/81922
        * typeck2.c (digest_init_r): Change nested argument type from bool to
        int.  Use code instead of TREE_CODE (type) where possible.  If
        nested == 2, diagnose initialization of flexible array member with
        STRING_CST.  Pass nested to process_init_constructor.  Formatting fix.
        (digest_init, digest_init_flags): Adjust digest_init_r caller.
        (massage_init_elt): Add nested argument.  Pass 2 instead of 1 to
        digest_init_r's nested argument if nested is non-zero.
        (process_init_constructor_array): Add nested argument.  If nested == 2,
        diagnose initialization of flexible array member with non-empty
        braced enclosed list.  Pass nested to massage_init_elt.
        (process_init_constructor_record, process_init_constructor_union): Add
        nested argument, pass it to massage_init_elt.
        (process_init_constructor): Add nested argument, pass it to
        process_init_constructor_{array,record,union}.
        * init.c (find_field_init): Return NULL_TREE if init is
        error_mark_node.  Don't look through nested CONSTRUCTORs.

        * g++.dg/warn/Wplacement-new-size-1.C (fBx1): Initialize nested
        flexible array member only with {}.  Add dg-warning.
        (fBx2, fBx3): Remove.
        * g++.dg/warn/Wplacement-new-size-2.C (fBx1): Initialize nested
        flexible array member only with {}.  Add dg-warning.
        (fBx2, fBx3): Remove.
        * g++.dg/warn/Wplacement-new-size-6.C: New test.
        * g++.dg/ext/flexary13.C (main): Remove test for initialization
        of nested flexible array member with non-empty initializer.
        * g++.dg/ext/flexary25.C: New test.
        * g++.dg/ext/flexary26.C: New test.
        * g++.dg/ext/flexary27.C: New test.
        * g++.dg/parse/pr43765.C: Expect diagnostics about initialization
        of nested flexible array member with non-empty initializer.  Expect
        C++2A diagnostics about mixing of designated and non-designated
        initializers.

--- gcc/cp/typeck2.c.jj 2017-12-07 18:04:54.362753051 +0100
+++ gcc/cp/typeck2.c    2017-12-08 12:55:39.740361230 +0100
@@ -34,7 +34,8 @@ along with GCC; see the file COPYING3.
 #include "intl.h"
 
 static tree
-process_init_constructor (tree type, tree init, tsubst_flags_t complain);
+process_init_constructor (tree type, tree init, int nested,
+                         tsubst_flags_t complain);
 
 
 /* Print an error message stemming from an attempt to use
@@ -996,10 +997,11 @@ check_narrowing (tree type, tree init, t
    For aggregate types, it assumes that reshape_init has already run, thus the
    initializer will have the right shape (brace elision has been undone).
 
-   NESTED is true iff we are being called for an element of a CONSTRUCTOR.  */
+   NESTED is non-zero iff we are being called for an element of a CONSTRUCTOR,
+   2 iff the element of a CONSTRUCTOR is inside another CONSTRUCTOR.  */
 
 static tree
-digest_init_r (tree type, tree init, bool nested, int flags,
+digest_init_r (tree type, tree init, int nested, int flags,
               tsubst_flags_t complain)
 {
   enum tree_code code = TREE_CODE (type);
@@ -1011,7 +1013,7 @@ digest_init_r (tree type, tree init, boo
 
   /* We must strip the outermost array type when completing the type,
      because the its bounds might be incomplete at the moment.  */
-  if (!complete_type_or_maybe_complain (TREE_CODE (type) == ARRAY_TYPE
+  if (!complete_type_or_maybe_complain (code == ARRAY_TYPE
                                        ? TREE_TYPE (type) : type, NULL_TREE,
                                        complain))
     return error_mark_node;
@@ -1029,11 +1031,9 @@ digest_init_r (tree type, tree init, boo
   if (code == ARRAY_TYPE)
     {
       if (nested && !TYPE_DOMAIN (type))
-       {
-         /* C++ flexible array members have a null domain.  */
-         pedwarn (loc, OPT_Wpedantic,
-                  "initialization of a flexible array member");
-       }
+       /* C++ flexible array members have a null domain.  */
+       pedwarn (loc, OPT_Wpedantic,
+                "initialization of a flexible array member");
 
       tree typ1 = TYPE_MAIN_VARIANT (TREE_TYPE (type));
       if (char_type_p (typ1)
@@ -1069,6 +1069,14 @@ digest_init_r (tree type, tree init, boo
                }
            }
 
+         if (nested == 2 && !TYPE_DOMAIN (type))
+           {
+             if (complain & tf_error)
+               error_at (loc, "initialization of flexible array member "
+                              "in a nested context");
+             return error_mark_node;
+           }
+
          if (type != TREE_TYPE (init)
              && !variably_modified_type_p (type, NULL_TREE))
            {
@@ -1093,8 +1101,7 @@ digest_init_r (tree type, tree init, boo
     }
 
   /* Handle scalar types (including conversions) and references.  */
-  if ((TREE_CODE (type) != COMPLEX_TYPE
-       || BRACE_ENCLOSED_INITIALIZER_P (init))
+  if ((code != COMPLEX_TYPE || BRACE_ENCLOSED_INITIALIZER_P (init))
       && (SCALAR_TYPE_P (type) || code == REFERENCE_TYPE))
     {
       if (nested)
@@ -1108,11 +1115,11 @@ digest_init_r (tree type, tree init, boo
 
   /* Come here only for aggregates: records, arrays, unions, complex numbers
      and vectors.  */
-  gcc_assert (TREE_CODE (type) == ARRAY_TYPE
+  gcc_assert (code == ARRAY_TYPE
              || VECTOR_TYPE_P (type)
-             || TREE_CODE (type) == RECORD_TYPE
-             || TREE_CODE (type) == UNION_TYPE
-             || TREE_CODE (type) == COMPLEX_TYPE);
+             || code == RECORD_TYPE
+             || code == UNION_TYPE
+             || code == COMPLEX_TYPE);
 
   /* "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,
@@ -1132,10 +1139,10 @@ digest_init_r (tree type, tree init, boo
 
   if (BRACE_ENCLOSED_INITIALIZER_P (init)
       && !TYPE_NON_AGGREGATE_CLASS (type))
-    return process_init_constructor (type, init, complain);
+    return process_init_constructor (type, init, nested, complain);
   else
     {
-      if (COMPOUND_LITERAL_P (init) && TREE_CODE (type) == ARRAY_TYPE)
+      if (COMPOUND_LITERAL_P (init) && code == ARRAY_TYPE)
        {
          if (complain & tf_error)
            error_at (loc, "cannot initialize aggregate of type %qT with "
@@ -1144,7 +1151,7 @@ digest_init_r (tree type, tree init, boo
          return error_mark_node;
        }
 
-      if (TREE_CODE (type) == ARRAY_TYPE
+      if (code == ARRAY_TYPE
          && !BRACE_ENCLOSED_INITIALIZER_P (init))
        {
          /* Allow the result of build_array_copy and of
@@ -1171,13 +1178,13 @@ digest_init_r (tree type, tree init, boo
 tree
 digest_init (tree type, tree init, tsubst_flags_t complain)
 {
-  return digest_init_r (type, init, false, LOOKUP_IMPLICIT, complain);
+  return digest_init_r (type, init, 0, LOOKUP_IMPLICIT, complain);
 }
 
 tree
 digest_init_flags (tree type, tree init, int flags, tsubst_flags_t complain)
 {
-  return digest_init_r (type, init, false, flags, complain);
+  return digest_init_r (type, init, 0, flags, complain);
 }
 
 /* Process the initializer INIT for an NSDMI DECL (a FIELD_DECL).  */
@@ -1230,9 +1237,9 @@ picflag_from_initializer (tree init)
 /* Adjust INIT for going into a CONSTRUCTOR.  */
 
 static tree
-massage_init_elt (tree type, tree init, tsubst_flags_t complain)
+massage_init_elt (tree type, tree init, int nested, tsubst_flags_t complain)
 {
-  init = digest_init_r (type, init, true, LOOKUP_IMPLICIT, complain);
+  init = digest_init_r (type, init, nested ? 2 : 1, LOOKUP_IMPLICIT, complain);
   /* Strip a simple TARGET_EXPR when we know this is an initializer.  */
   if (SIMPLE_TARGET_EXPR_P (init))
     init = TARGET_EXPR_INITIAL (init);
@@ -1250,7 +1257,7 @@ massage_init_elt (tree type, tree init,
    which describe the initializers.  */
 
 static int
-process_init_constructor_array (tree type, tree init,
+process_init_constructor_array (tree type, tree init, int nested,
                                tsubst_flags_t complain)
 {
   unsigned HOST_WIDE_INT i, len = 0;
@@ -1273,6 +1280,15 @@ process_init_constructor_array (tree typ
                       TYPE_SIGN (TREE_TYPE (domain))).to_uhwi ();
       else
        unbounded = true;  /* Take as many as there are.  */
+
+      if (nested == 2 && !domain && !vec_safe_is_empty (v))
+       {
+         if (complain & tf_error)
+           error_at (EXPR_LOC_OR_LOC (init, input_location),
+                     "initialization of flexible array member "
+                     "in a nested context");
+         return PICFLAG_ERRONEOUS;
+       }
     }
   else
     /* Vectors are like simple fixed-size arrays.  */
@@ -1301,7 +1317,8 @@ process_init_constructor_array (tree typ
       else
        ce->index = size_int (i);
       gcc_assert (ce->value);
-      ce->value = massage_init_elt (TREE_TYPE (type), ce->value, complain);
+      ce->value
+       = massage_init_elt (TREE_TYPE (type), ce->value, nested, complain);
 
       if (ce->value != error_mark_node)
        gcc_assert (same_type_ignoring_top_level_qualifiers_p
@@ -1323,7 +1340,7 @@ process_init_constructor_array (tree typ
               we can't rely on the back end to do it for us, so make the
               initialization explicit by list-initializing from T{}.  */
            next = build_constructor (init_list_type_node, NULL);
-           next = massage_init_elt (TREE_TYPE (type), next, complain);
+           next = massage_init_elt (TREE_TYPE (type), next, nested, complain);
            if (initializer_zerop (next))
              /* The default zero-initialization is fine for us; don't
                 add anything to the CONSTRUCTOR.  */
@@ -1354,7 +1371,7 @@ process_init_constructor_array (tree typ
    the initializers.  */
 
 static int
-process_init_constructor_record (tree type, tree init,
+process_init_constructor_record (tree type, tree init, int nested,
                                 tsubst_flags_t complain)
 {
   vec<constructor_elt, va_gc> *v = NULL;
@@ -1436,7 +1453,7 @@ process_init_constructor_record (tree ty
          if (ce)
            {
              gcc_assert (ce->value);
-             next = massage_init_elt (type, next, complain);
+             next = massage_init_elt (type, next, nested, complain);
              ++idx;
            }
        }
@@ -1462,7 +1479,7 @@ process_init_constructor_record (tree ty
             for us, so build up TARGET_EXPRs.  If the type in question is
             a class, just build one up; if it's an array, recurse.  */
          next = build_constructor (init_list_type_node, NULL);
-         next = massage_init_elt (TREE_TYPE (field), next, complain);
+         next = massage_init_elt (TREE_TYPE (field), next, nested, complain);
 
          /* Warn when some struct elements are implicitly initialized.  */
          if ((complain & tf_warning)
@@ -1576,7 +1593,7 @@ process_init_constructor_record (tree ty
    which describe the initializer.  */
 
 static int
-process_init_constructor_union (tree type, tree init,
+process_init_constructor_union (tree type, tree init, int nested,
                                tsubst_flags_t complain)
 {
   constructor_elt *ce;
@@ -1662,7 +1679,8 @@ process_init_constructor_union (tree typ
     }
 
   if (ce->value && ce->value != error_mark_node)
-    ce->value = massage_init_elt (TREE_TYPE (ce->index), ce->value, complain);
+    ce->value = massage_init_elt (TREE_TYPE (ce->index), ce->value, nested,
+                                 complain);
 
   return picflag_from_initializer (ce->value);
 }
@@ -1682,18 +1700,19 @@ process_init_constructor_union (tree typ
    of error.  */
 
 static tree
-process_init_constructor (tree type, tree init, tsubst_flags_t complain)
+process_init_constructor (tree type, tree init, int nested,
+                         tsubst_flags_t complain)
 {
   int flags;
 
   gcc_assert (BRACE_ENCLOSED_INITIALIZER_P (init));
 
   if (TREE_CODE (type) == ARRAY_TYPE || VECTOR_TYPE_P (type))
-    flags = process_init_constructor_array (type, init, complain);
+    flags = process_init_constructor_array (type, init, nested, complain);
   else if (TREE_CODE (type) == RECORD_TYPE)
-    flags = process_init_constructor_record (type, init, complain);
+    flags = process_init_constructor_record (type, init, nested, complain);
   else if (TREE_CODE (type) == UNION_TYPE)
-    flags = process_init_constructor_union (type, init, complain);
+    flags = process_init_constructor_union (type, init, nested, complain);
   else
     gcc_unreachable ();
 
--- gcc/cp/init.c.jj    2017-11-28 09:37:08.000000000 +0100
+++ gcc/cp/init.c       2017-12-08 14:00:07.210615314 +0100
@@ -2459,7 +2459,7 @@ throw_bad_array_new_length (void)
 static tree
 find_field_init (tree t, tree init)
 {
-  if (!init)
+  if (!init || init == error_mark_node)
     return NULL_TREE;
 
   unsigned HOST_WIDE_INT idx;
@@ -2471,11 +2471,6 @@ find_field_init (tree t, tree init)
       /* If the member T is found, return it.  */
       if (field == t)
        return elt;
-
-      /* Otherwise continue and/or recurse into nested initializers.  */
-      if (TREE_CODE (elt) == CONSTRUCTOR
-         && (init = find_field_init (t, elt)))
-       return init;
     }
   return NULL_TREE;
 }
--- gcc/testsuite/g++.dg/warn/Wplacement-new-size-1.C.jj        2016-02-08 
18:39:16.000000000 +0100
+++ gcc/testsuite/g++.dg/warn/Wplacement-new-size-1.C   2017-12-08 
13:38:57.000000000 +0100
@@ -82,38 +82,14 @@ void fBx (BAx *pbx, BAx &rbx)
 
 void fBx1 ()
 {
-  BAx bax1 = { 1, /* Ax = */ { 2, /* a[] = */ { 3 } } };
+  BAx bax1 = { 1, /* Ax = */ { 2, /* a[] = */ {} } };
 
-  new (bax1.ax.a) char;
+  new (bax1.ax.a) char;            // { dg-warning "placement" }
   new (bax1.ax.a) char[2];  // { dg-warning "placement" }
   new (bax1.ax.a) Int16;    // { dg-warning "placement" }
   new (bax1.ax.a) Int32;    // { dg-warning "placement" }
 }
 
-void fBx2 ()
-{
-  BAx bax2 = { 1, /* Ax = */ { 2, /* a[] = */ { 3, 4 } } };
-
-  new (bax2.ax.a) char;
-  new (bax2.ax.a) char[2];
-  new (bax2.ax.a) char[3];    // { dg-warning "placement" }
-  new (bax2.ax.a) Int16;
-  new (bax2.ax.a) char[4];    // { dg-warning "placement" }
-  new (bax2.ax.a) Int32;      // { dg-warning "placement" }
-}
-
-void fBx3 ()
-{
-  BAx bax2 = { 1, /* Ax = */ { 3, /* a[] = */ { 4, 5, 6 } } };
-
-  new (bax2.ax.a) char;
-  new (bax2.ax.a) char[2];
-  new (bax2.ax.a) Int16;
-  new (bax2.ax.a) char[3];
-  new (bax2.ax.a) char[4];    // { dg-warning "placement" }
-  new (bax2.ax.a) Int32;      // { dg-warning "placement" }
-}
-
 void fB0 (BA0 *pb0, BA0 &rb0)
 {
   BA0 ba0;
--- gcc/testsuite/g++.dg/warn/Wplacement-new-size-2.C.jj        2016-02-08 
18:39:16.000000000 +0100
+++ gcc/testsuite/g++.dg/warn/Wplacement-new-size-2.C   2017-12-08 
13:44:39.000000000 +0100
@@ -140,38 +140,14 @@ void fBx (BAx *pbx, BAx &rbx)
 
 void fBx1 ()
 {
-  BAx bax1 = { 1, /* Ax = */ { 2, /* a[] = */ { 3 } } };
+  BAx bax1 = { 1, /* Ax = */ { 2, /* a[] = */ {} } };
 
-  new (bax1.ax.a) char;
+  new (bax1.ax.a) char;              // { dg-warning "placement" }
   new (bax1.ax.a) char[2];    // { dg-warning "placement" }
   new (bax1.ax.a) Int16;      // { dg-warning "placement" }
   new (bax1.ax.a) Int32;      // { dg-warning "placement" }
 }
 
-void fBx2 ()
-{
-  BAx bax2 = { 1, /* Ax = */ { 2, /* a[] = */ { 3, 4 } } };
-
-  new (bax2.ax.a) char;
-  new (bax2.ax.a) char[2];
-  new (bax2.ax.a) char[3];    // { dg-warning "placement" }
-  new (bax2.ax.a) Int16;
-  new (bax2.ax.a) char[4];    // { dg-warning "placement" }
-  new (bax2.ax.a) Int32;      // { dg-warning "placement" }
-}
-
-void fBx3 ()
-{
-  BAx bax2 = { 1, /* Ax = */ { 3, /* a[] = */ { 4, 5, 6 } } };
-
-  new (bax2.ax.a) char;
-  new (bax2.ax.a) char[2];
-  new (bax2.ax.a) Int16;
-  new (bax2.ax.a) char[3];
-  new (bax2.ax.a) char[4];    // { dg-warning "placement" }
-  new (bax2.ax.a) Int32;      // { dg-warning "placement" }
-}
-
 void fB0 (BA0 *pb0, BA0 &rb0)
 {
   BA0 ba0;
--- gcc/testsuite/g++.dg/warn/Wplacement-new-size-6.C.jj        2017-12-08 
13:48:24.443433300 +0100
+++ gcc/testsuite/g++.dg/warn/Wplacement-new-size-6.C   2017-12-08 
13:48:17.000000000 +0100
@@ -0,0 +1,48 @@
+// { dg-do compile }
+// { dg-options "-Wno-pedantic -Wplacement-new=1" }
+
+typedef __typeof__ (sizeof 0) size_t;
+
+void* operator new (size_t, void *p) { return p; }
+void* operator new[] (size_t, void *p) { return p; }
+
+struct Ax { char n, a []; };
+
+typedef __INT16_TYPE__ Int16;
+typedef __INT32_TYPE__ Int32;
+
+struct BAx { int i; Ax ax; };
+
+void fBx1 ()
+{
+  BAx bax1 = { 1, /* Ax = */ { 2, /* a[] = */ { 3 } } };       // { dg-error 
"initialization of flexible array member in a nested context" }
+
+  new (bax1.ax.a) char;     // { dg-warning "placement" }
+  new (bax1.ax.a) char[2];  // { dg-warning "placement" }
+  new (bax1.ax.a) Int16;    // { dg-warning "placement" }
+  new (bax1.ax.a) Int32;    // { dg-warning "placement" }
+}
+
+void fBx2 ()
+{
+  BAx bax2 = { 1, /* Ax = */ { 2, /* a[] = */ { 3, 4 } } };    // { dg-error 
"initialization of flexible array member in a nested context" }
+
+  new (bax2.ax.a) char;       // { dg-warning "placement" }
+  new (bax2.ax.a) char[2];    // { dg-warning "placement" }
+  new (bax2.ax.a) char[3];    // { dg-warning "placement" }
+  new (bax2.ax.a) Int16;      // { dg-warning "placement" }
+  new (bax2.ax.a) char[4];    // { dg-warning "placement" }
+  new (bax2.ax.a) Int32;      // { dg-warning "placement" }
+}
+
+void fBx3 ()
+{
+  BAx bax2 = { 1, /* Ax = */ { 3, /* a[] = */ { 4, 5, 6 } } }; // { dg-error 
"initialization of flexible array member in a nested context" }
+
+  new (bax2.ax.a) char;       // { dg-warning "placement" }
+  new (bax2.ax.a) char[2];    // { dg-warning "placement" }
+  new (bax2.ax.a) Int16;      // { dg-warning "placement" }
+  new (bax2.ax.a) char[3];    // { dg-warning "placement" }
+  new (bax2.ax.a) char[4];    // { dg-warning "placement" }
+  new (bax2.ax.a) Int32;      // { dg-warning "placement" }
+}
--- gcc/testsuite/g++.dg/ext/flexary13.C.jj     2016-02-04 10:00:25.000000000 
+0100
+++ gcc/testsuite/g++.dg/ext/flexary13.C        2017-12-08 13:52:22.465431378 
+0100
@@ -55,10 +55,4 @@ int main ()
       { 1, { 2 } };   // dg-warning "initialization of a flexible array 
member" }
     ASSERT (s.i == 1 && s.ax.n == 2);
   }
-
-  {
-    AAx s =
-      { 1, { 2, { 3 } } };   // dg-warning "initialization of a flexible array 
member" }
-    ASSERT (s.i == 1 && s.ax.n == 2 && s.ax.a [0] == 3);
-  }
 }
--- gcc/testsuite/g++.dg/ext/flexary25.C.jj     2017-12-08 12:57:41.000000000 
+0100
+++ gcc/testsuite/g++.dg/ext/flexary25.C        2017-12-08 12:57:26.000000000 
+0100
@@ -0,0 +1,20 @@
+// PR c++/81922
+// { dg-do compile }
+// { dg-options "" }
+
+struct S { const char *a; char b[]; };
+struct T { int a; int b[]; };
+#if __cplusplus >= 201103L
+S c[] { "", "" };              // { dg-error "initialization of flexible array 
member in a nested context" "" { target c++11 } }
+S d[] { "", { 0 } };           // { dg-error "initialization of flexible array 
member in a nested context" "" { target c++11 } }
+T e[] { 1, { 2 }, 3, { 4 } };  // { dg-error "initialization of flexible array 
member in a nested context" "" { target c++11 } }
+T f[] { 1, {}, 3, {} };
+T g { 1, { 1, 2, 3 } };
+S h { "abcd", "" };
+#endif
+S i[] = { "", "", "", "" };    // { dg-error "initialization of flexible array 
member in a nested context" }
+S j[] = { "", { 1 }, "", { 2, 3 } };   // { dg-error "initialization of 
flexible array member in a nested context" }
+T k[] = { 1, { 2 }, 3, { 4 } };        // { dg-error "initialization of 
flexible array member in a nested context" }
+T l[] = { 1, {}, 3, {} };
+T m = { 1, { 1, 2, 3 } };
+S n = { "", "abcde" };
--- gcc/testsuite/g++.dg/ext/flexary26.C.jj     2017-12-08 13:00:45.000000000 
+0100
+++ gcc/testsuite/g++.dg/ext/flexary26.C        2017-12-08 13:00:38.000000000 
+0100
@@ -0,0 +1,26 @@
+// PR c++/81922
+// { dg-do compile }
+// { dg-options "-Wpedantic" }
+
+struct S { const char *a; char b[]; }; // { dg-warning "forbids flexible array 
member" }
+struct T { int a; int b[]; };  // { dg-warning "forbids flexible array member" 
}
+#if __cplusplus >= 201103L
+S c[] { "", "" };              // { dg-error "initialization of flexible array 
member in a nested context" "" { target c++11 } }
+                               // { dg-warning "initialization of a flexible 
array member" "" { target c++11 } .-1 }
+S d[] { "", { 0 } };           // { dg-error "initialization of flexible array 
member in a nested context" "" { target c++11 } }
+                               // { dg-warning "initialization of a flexible 
array member" "" { target c++11 } .-1 }
+T e[] { 1, { 2 }, 3, { 4 } };  // { dg-error "initialization of flexible array 
member in a nested context" "" { target c++11 } }
+                               // { dg-warning "initialization of a flexible 
array member" "" { target c++11 } .-1 }
+T f[] { 1, {}, 3, {} };                // { dg-warning "initialization of a 
flexible array member" "" { target c++11 } }
+T g { 1, { 1, 2, 3 } };                // { dg-warning "initialization of a 
flexible array member" "" { target c++11 } }
+S h { "abcd", "" };            // { dg-warning "initialization of a flexible 
array member" "" { target c++11 } }
+#endif
+S i[] = { "", "", "", "" };    // { dg-error "initialization of flexible array 
member in a nested context" }
+                               // { dg-warning "initialization of a flexible 
array member" "" { target *-*-* } .-1 }
+S j[] = { "", { 1 }, "", { 2, 3 } };   // { dg-error "initialization of 
flexible array member in a nested context" }
+                               // { dg-warning "initialization of a flexible 
array member" "" { target *-*-* } .-1 }
+T k[] = { 1, { 2 }, 3, { 4 } };        // { dg-error "initialization of 
flexible array member in a nested context" }
+                               // { dg-warning "initialization of a flexible 
array member" "" { target *-*-* } .-1 }
+T l[] = { 1, {}, 3, {} };      // { dg-warning "initialization of a flexible 
array member" }
+T m = { 1, { 1, 2, 3 } };      // { dg-warning "initialization of a flexible 
array member" }
+S n = { "", "abcde" };         // { dg-warning "initialization of a flexible 
array member" }
--- gcc/testsuite/g++.dg/ext/flexary27.C.jj     2017-12-08 13:00:53.000000000 
+0100
+++ gcc/testsuite/g++.dg/ext/flexary27.C        2017-12-08 13:01:12.000000000 
+0100
@@ -0,0 +1,25 @@
+// PR c++/81922
+// { dg-do compile }
+
+struct S { const char *a; char b[]; }; // { dg-error "forbids flexible array 
member" }
+struct T { int a; int b[]; };  // { dg-error "forbids flexible array member" }
+#if __cplusplus >= 201103L
+S c[] { "", "" };              // { dg-error "initialization of flexible array 
member in a nested context" "" { target c++11 } }
+                               // { dg-error "initialization of a flexible 
array member" "" { target c++11 } .-1 }
+S d[] { "", { 0 } };           // { dg-error "initialization of flexible array 
member in a nested context" "" { target c++11 } }
+                               // { dg-error "initialization of a flexible 
array member" "" { target c++11 } .-1 }
+T e[] { 1, { 2 }, 3, { 4 } };  // { dg-error "initialization of flexible array 
member in a nested context" "" { target c++11 } }
+                               // { dg-error "initialization of a flexible 
array member" "" { target c++11 } .-1 }
+T f[] { 1, {}, 3, {} };                // { dg-error "initialization of a 
flexible array member" "" { target c++11 } }
+T g { 1, { 1, 2, 3 } };                // { dg-error "initialization of a 
flexible array member" "" { target c++11 } }
+S h { "abcd", "" };            // { dg-error "initialization of a flexible 
array member" "" { target c++11 } }
+#endif
+S i[] = { "", "", "", "" };    // { dg-error "initialization of flexible array 
member in a nested context" }
+                               // { dg-error "initialization of a flexible 
array member" "" { target *-*-* } .-1 }
+S j[] = { "", { 1 }, "", { 2, 3 } };   // { dg-error "initialization of 
flexible array member in a nested context" }
+                               // { dg-error "initialization of a flexible 
array member" "" { target *-*-* } .-1 }
+T k[] = { 1, { 2 }, 3, { 4 } };        // { dg-error "initialization of 
flexible array member in a nested context" }
+                               // { dg-error "initialization of a flexible 
array member" "" { target *-*-* } .-1 }
+T l[] = { 1, {}, 3, {} };      // { dg-error "initialization of a flexible 
array member" }
+T m = { 1, { 1, 2, 3 } };      // { dg-error "initialization of a flexible 
array member" }
+S n = { "", "abcde" };         // { dg-error "initialization of a flexible 
array member" }
--- gcc/testsuite/g++.dg/parse/pr43765.C.jj     2015-12-16 09:02:07.000000000 
+0100
+++ gcc/testsuite/g++.dg/parse/pr43765.C        2017-12-08 14:08:48.259251433 
+0100
@@ -10,8 +10,8 @@ const char *temp[] = {"607", "612", 0};
 
 SomeType vals[] =
     {
-        { 0, values : temp, },
+        { 0, values : temp, },  // { dg-error "either all initializer clauses 
should be designated or none of them should be" "" { target c++2a } }
         0
     };   // { dg-error "GNU-style designated initializer for an array|cannot 
convert" }
 // (note the error above is on the wrong line)
- 
+        // { dg-error "initialization of flexible array member in a nested 
context" "" { target *-*-* } .-2 }

        Jakub

Reply via email to