[C++ PATCH] Harmonize C++ flexible array member initialization with C (PR c++/80135, PR c++/81922)

Jakub Jelinek jakub@redhat.com
Fri Dec 8 16:15:00 GMT 2017


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  <jakub@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



More information about the Gcc-patches mailing list