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

Message ID 20171208161507.GY2353@tucnak
State New
Headers show
Series
  • [C++] Harmonize C++ flexible array member initialization with C (PR c++/80135, PR c++/81922)
Related show

Commit Message

Jakub Jelinek Dec. 8, 2017, 4:15 p.m.
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.


	Jakub

Comments

Martin Sebor Dec. 8, 2017, 5:25 p.m. | #1
On 12/08/2017 09:15 AM, Jakub Jelinek wrote:
> 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.


Harmonizing C++ with C was one of my goals when I made those
changes so rejecting the nested initialization makes sense.
I suspect I just missed that C errors out on these and assumed
it allowed them like it does at the top level (rather than
deliberately relaxing the rules), so thank you for tightening
it up.

While testing the patch I noticed it issues some diagnostics
multiple times.  It would be nice if the last (redundant)
pedantic warning in the error case below could be avoided.

struct B { int i; struct { int j, a[]; } a; };

struct B g (void)
{
   return (struct B){ 1, { 2, { 3 } } };
}

u.C:1:37: warning: ISO C++ forbids flexible array member ‘a’ [-Wpedantic]
  struct B { int i; struct { int j, a[]; } a; };
                                      ^
u.C:1:42: warning: invalid use of ‘struct B::<unnamed>’ with a flexible 
array member in ‘struct B’ [-Wpedantic]
  struct B { int i; struct { int j, a[]; } a; };
                                           ^
u.C:1:37: note: array member ‘int B::<unnamed struct>::a []’ declared here
  struct B { int i; struct { int j, a[]; } a; };
                                      ^
u.C: In function ‘B g()’:
u.C:5:38: warning: ISO C++ forbids compound-literals [-Wpedantic]
    return (struct B){ 1, { 2, { 3 } } };
                                       ^
u.C:5:38: warning: initialization of a flexible array member [-Wpedantic]
u.C:5:38: error: initialization of flexible array member in a nested context

Martin
Jakub Jelinek Dec. 8, 2017, 5:34 p.m. | #2
On Fri, Dec 08, 2017 at 10:25:48AM -0700, Martin Sebor wrote:
> While testing the patch I noticed it issues some diagnostics

> multiple times.  It would be nice if the last (redundant)

> pedantic warning in the error case below could be avoided.


You mean completely drop the pedwarn "initialization of a flexible array member"
in all cases, because in theory we should have emitted already
"ISO C++ forbids flexible array member" pedwarn earlier?
I think it is better to pedwarn in both spots, the earlier pedwarn
might be disabled because of system headers or whatever else.

Or do you just mean to pedwarn only if we are not emitting the
"initialization of flexible array member in a nested context" error?
That is going to be harder, as that error is emitted in a different spot
(actually 2, because the STRING_CST vs. brace enclosed initializer is
separate), unlike the pedwarn is complain & tf_error guarded, etc.

	Jakub
Martin Sebor Dec. 8, 2017, 5:40 p.m. | #3
On 12/08/2017 10:34 AM, Jakub Jelinek wrote:
> On Fri, Dec 08, 2017 at 10:25:48AM -0700, Martin Sebor wrote:

>> While testing the patch I noticed it issues some diagnostics

>> multiple times.  It would be nice if the last (redundant)

>> pedantic warning in the error case below could be avoided.

>

> You mean completely drop the pedwarn "initialization of a flexible array member"

> in all cases, because in theory we should have emitted already

> "ISO C++ forbids flexible array member" pedwarn earlier?

> I think it is better to pedwarn in both spots, the earlier pedwarn

> might be disabled because of system headers or whatever else.


I agree.

>

> Or do you just mean to pedwarn only if we are not emitting the

> "initialization of flexible array member in a nested context" error?

> That is going to be harder, as that error is emitted in a different spot

> (actually 2, because the STRING_CST vs. brace enclosed initializer is

> separate), unlike the pedwarn is complain & tf_error guarded, etc.


I meant the latter.  It's no big deal if it's too hard.  It's
just something I noticed and thought might be easy to handle.

Martin
Jason Merrill Dec. 15, 2017, 8:09 p.m. | #4
On 12/08/2017 11:15 AM, Jakub Jelinek wrote:
> 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.


So this change is because the caller is only interested in flexible 
arrays, which can't be deeply nested anymore?  In that case, this is no 
longer a general purpose function and should be called find_flexarray_init.

OK with that change.

Jason
Jakub Jelinek Dec. 15, 2017, 8:21 p.m. | #5
On Fri, Dec 15, 2017 at 03:09:53PM -0500, Jason Merrill wrote:
> So this change is because the caller is only interested in flexible arrays,

> which can't be deeply nested anymore?  In that case, this is no longer a


Yes.

> general purpose function and should be called find_flexarray_init.


Done and committed.  Thanks.
As a follow up, I'll try (next week) to avoid walking the whole CONSTRUCTOR
and just look at the last element in it instead in find_flexarray_init.

	Jakub

Patch

--- 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 }