diff mbox

have chkp skip flexible member arrays (PR #79986)

Message ID df64eca8-9112-e496-fdfc-27a922fd130d@gmail.com
State New
Headers show

Commit Message

Martin Sebor March 29, 2017, 11:07 p.m. UTC
On 03/21/2017 01:33 PM, Jason Merrill wrote:
> On Tue, Mar 21, 2017 at 11:08 AM, Martin Sebor <msebor@gmail.com> wrote:
>> On 03/20/2017 10:27 PM, Jason Merrill wrote:
>>>
>>> On Mon, Mar 20, 2017 at 7:58 PM, Martin Sebor <msebor@gmail.com> wrote:
>>>>
>>>> On 03/20/2017 05:51 PM, Jason Merrill wrote:
>>>>>
>>>>> On Mon, Mar 20, 2017 at 7:04 PM, Martin Sebor <msebor@gmail.com> wrote:
>>>>>>
>>>>>>
>>>>>> Attached is a minimal patch to avoid an ICE in CHKP upon
>>>>>> encountering one form of an initializer for a flexible array
>>>>>> member, specifically the empty string:
>>>>>>
>>>>>>   int f ()
>>>>>>   {
>>>>>>     struct B { int n; char a[]; };
>>>>>>
>>>>>>     return ((struct B){ 1, "" }).a[0];
>>>>>>   }
>>>>>>
>>>>>> Although GCC accepts (and doesn't ICE on) non-empty initializers
>>>>>> for flexible array members, such as
>>>>>>
>>>>>>     (struct B){ 1, "123" }
>>>>>
>>>>> How do you mean?  When I compile this with the C front end, I get
>>>>>
>>>>> error: non-static initialization of a flexible array member
>>>>
>>>> I meant that G++ accepts it, doesn't ICE, but emits wrong code.
>>>> (it's consistently rejected by the C front end).  Sorry for not
>>>> being clear about it.
>>>
>>> Ah, OK.  It seems to me that the wrong code bug is worth addressing;
>>> why does rejecting the code seem risky to you?
>>
>> I have a few reasons: First, it's not a regression (I raised
>> bug 69696 for it in early 2016) so strictly it's out of scope
>> for this stage.  Second, there are a number of bugs related
>> to the initialization of flexible array members so the fixes
>> are probably not going to be contained to a single function
>> or file.  Third, the flexible member array changes I made in
>> the past were not trivial, took time to develop, and the two
>> of us iterated over some of them for weeks.  Despite your
>> careful review and my extensive testing some of them
>> introduced regressions that are still being patched up.
>> Fourth, making a change to reject code this close to a release
>> runs the risk of breaking code that has successfully compiled
>> in mass rebuilds and others' tests with the new compiler.
>> While that could be viewed as a good change for invalid code
>> that's exercised at run time, it could also break programs
>> where the bad code is never exercised.
>
> Fair enough.  But I think the ICE is preferable to wrong code.

I agree in general, although in this case it seems that ICE is
more likely to penalize -fcheck-pointer-bounds users without
benefiting anyone else.

I decided to go ahead and implemented your suggestion just in
case it was easier and safer than I thought.  The attached patch
is the result.  I think the changes are actually not as risky as
I had initially feared but they are still fairly extensive and
I would hesitate to recommend they be made at this stage.

Regardless of what happens to this patch, for GCC 8, I'd like
to look into making the initialization work correctly in all
contexts (i.e., including auto variables) .  As I said in my
response to Marek, I expect rejecting it will only lead users
determined enough to make use of flexible array members for
local variables to invent error-prone hacks.

Martin

Comments

Jason Merrill April 7, 2017, 4:50 p.m. UTC | #1
On Wed, Mar 29, 2017 at 7:07 PM, Martin Sebor <msebor@gmail.com> wrote:
> On 03/21/2017 01:33 PM, Jason Merrill wrote:
>> On Tue, Mar 21, 2017 at 11:08 AM, Martin Sebor <msebor@gmail.com> wrote:
>>> On 03/20/2017 10:27 PM, Jason Merrill wrote:
>>>> On Mon, Mar 20, 2017 at 7:58 PM, Martin Sebor <msebor@gmail.com> wrote:
>>>>> On 03/20/2017 05:51 PM, Jason Merrill wrote:
>>>>>> On Mon, Mar 20, 2017 at 7:04 PM, Martin Sebor <msebor@gmail.com>
>>>>>> wrote:
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Attached is a minimal patch to avoid an ICE in CHKP upon
>>>>>>> encountering one form of an initializer for a flexible array
>>>>>>> member, specifically the empty string:
>>>>>>>
>>>>>>>   int f ()
>>>>>>>   {
>>>>>>>     struct B { int n; char a[]; };
>>>>>>>
>>>>>>>     return ((struct B){ 1, "" }).a[0];
>>>>>>>   }
>>>>>>>
>>>>>>> Although GCC accepts (and doesn't ICE on) non-empty initializers
>>>>>>> for flexible array members, such as
>>>>>>>
>>>>>>>     (struct B){ 1, "123" }
>>>>>>
>>>>>>
>>>>>> How do you mean?  When I compile this with the C front end, I get
>>>>>>
>>>>>> error: non-static initialization of a flexible array member
>>>>>
>>>>> I meant that G++ accepts it, doesn't ICE, but emits wrong code.
>>>>> (it's consistently rejected by the C front end).  Sorry for not
>>>>> being clear about it.
>>>>
>>>> Ah, OK.  It seems to me that the wrong code bug is worth addressing;
>>>> why does rejecting the code seem risky to you?
>>>
>>> I have a few reasons: First, it's not a regression (I raised
>>> bug 69696 for it in early 2016) so strictly it's out of scope
>>> for this stage.  Second, there are a number of bugs related
>>> to the initialization of flexible array members so the fixes
>>> are probably not going to be contained to a single function
>>> or file.  Third, the flexible member array changes I made in
>>> the past were not trivial, took time to develop, and the two
>>> of us iterated over some of them for weeks.  Despite your
>>> careful review and my extensive testing some of them
>>> introduced regressions that are still being patched up.
>>> Fourth, making a change to reject code this close to a release
>>> runs the risk of breaking code that has successfully compiled
>>> in mass rebuilds and others' tests with the new compiler.
>>> While that could be viewed as a good change for invalid code
>>> that's exercised at run time, it could also break programs
>>> where the bad code is never exercised.
>>
>> Fair enough.  But I think the ICE is preferable to wrong code.
>
> I agree in general, although in this case it seems that ICE is
> more likely to penalize -fcheck-pointer-bounds users without
> benefiting anyone else.
>
> I decided to go ahead and implemented your suggestion just in
> case it was easier and safer than I thought.  The attached patch
> is the result.  I think the changes are actually not as risky as
> I had initially feared but they are still fairly extensive and
> I would hesitate to recommend they be made at this stage.

Agreed.  A safer patch for GCC 7 might be to add your find_flexarray
function and call that from finish_compound_literal.

> Regardless of what happens to this patch, for GCC 8, I'd like
> to look into making the initialization work correctly in all
> contexts (i.e., including auto variables) .  As I said in my
> response to Marek, I expect rejecting it will only lead users
> determined enough to make use of flexible array members for
> local variables to invent error-prone hacks.

I would expect such users of C++ to be vanishingly few; who would be
determined to use a C feature in a way not allowed by C?

Jason
diff mbox

Patch

PR c++/79986 - ICE in fold_convert_loc with a flexible array

gcc/c-family/ChangeLog:

	PR c++/79986
	* c.opt (-Wflexarray, -Wflexarray-init): New C++ options.

gcc/cp/ChangeLog:

	PR c++/79986
	* class.c (find_flexarrays): Add argument.
	(check_flexarrays): Same and handle it.  Return tree instead of void.
	(find_flexarray): New extern function.
	(finish_struct_1): Adjust.
	* cp-tree.h (find_flexarray): Declare it.
	* decl.c (maybe_reject_flexarray_decl): New function.
	(check_array_initializer): Call it.
	(cp_finish_decl): Same.
	(grokdeclarator): Replace OPT_Wpedantic with OPT_Wflexarray.
	* pt.c (tsubst): Reject types with invalid flexible array members.
	* typeck2.c (init_ctor_info): New struct.
	(store_init_value): Use it.
	(process_init_constructor): Same.
	(maybe_diag_flexinit): New function.
	(digest_init_r, digest_init, digest_init_flags): Use init_ctor_info.
	(digest_init_flags): New overload.
	(digest_nsdmi_init): Use init_ctor_info.
	(massage_init_elt): Same.
	(process_init_constructor_array): Same.  Call maybe_diag_flexinit.
	(process_init_constructor_record): Use init_ctor_info.
	(process_init_constructor_union): Same.

gcc/ChangeLog:

	PR c++/79986
	* doc/invoke.texi (Warning Options): Document -Wflexarray
	and -Wflexarray-init.

gcc/testsuite/ChangeLog:

	PR c++/79986
	* g++.dg/pr79986.C: New test.
	* g++.dg/ext/flexary24.C: New test.
	* g++.dg/ext/flexary25.C: New test.
	* g++.dg/cpp1z/has-unique-obj-representations1.C: Adjust.
	* g++.dg/ext/flexarray-mangle-2.C: Same.
	* g++.dg/ext/flexarray-mangle.C: Same.
	* g++.dg/ext/flexarray-subst.C: Same.
	* g++.dg/ext/flexary10.C: Same.
	* g++.dg/ext/flexary11.C: Same.
	* g++.dg/ext/flexary12.C: Same.
	* g++.dg/ext/flexary13.C: Same.
	* g++.dg/ext/flexary15.C: Same.
	* g++.dg/ext/flexary18.C: Same.
	* g++.dg/ext/flexary19.C: Same.
	* g++.dg/ext/flexary3.C: Same.
	* g++.dg/ext/flexary7.C: Same.
	* g++.dg/parse/pr43765.C: Same.
	* g++.dg/warn/Wplacement-new-size-1.C: Same.
	* g++.dg/warn/Wplacement-new-size-2.C: Same.

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 78fea61..a095e99 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -342,6 +342,14 @@  Wbool-operation
 C ObjC C++ ObjC++ Var(warn_bool_op) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
 Warn about certain operations on boolean expressions.
 
+Wflexarray
+C++ ObjC++ Var(warn_flexarray) Warning LangEnabledBy(C++ ObjC++,Wpedantic)
+Warn when a declaration of a flexible array member is found.
+
+Wflexarray-init
+C++ ObjC++ Var(warn_flexarray_init) Warning LangEnabledBy(C++ ObjC++,Wpedantic)
+Warn for initialization of flexible array members.
+
 Wframe-address
 C ObjC C++ ObjC++ Var(warn_frame_address) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
 Warn when __builtin_frame_address or __builtin_return_address is used unsafely.
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 9e4b4c4..7d52857 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -150,9 +150,9 @@  static bool accessible_nvdtor_p (tree);
 /* Used by find_flexarrays and related functions.  */
 struct flexmems_t;
 static void diagnose_flexarrays (tree, const flexmems_t *);
-static void find_flexarrays (tree, flexmems_t *, bool = false,
+static void find_flexarrays (tree, bool, flexmems_t *, bool = false,
 			     tree = NULL_TREE, tree = NULL_TREE);
-static void check_flexarrays (tree, flexmems_t * = NULL, bool = false);
+static tree check_flexarrays (tree, bool, flexmems_t * = NULL, bool = false);
 static void check_bases (tree, int *, int *);
 static void check_bases_and_members (tree);
 static tree create_vtable_ptr (tree, tree *);
@@ -6821,6 +6821,8 @@  struct flexmems_t
 /* Find either the first flexible array member or the first zero-length
    array, in that order of preference, among members of class T (but not
    its base classes), and set members of FMEM accordingly.
+   DIAG is true if invalid instances of flexible array members found
+   during the search should be diagnosed, false otherwise.
    BASE_P is true if T is a base class of another class.
    PUN is set to the outermost union in which the flexible array member
    (or zero-length array) is defined if one such union exists, otherwise
@@ -6830,7 +6832,7 @@  struct flexmems_t
    otherwise to NULL.  */
 
 static void
-find_flexarrays (tree t, flexmems_t *fmem, bool base_p,
+find_flexarrays (tree t, bool diag, flexmems_t *fmem, bool base_p,
 		 tree pun /* = NULL_TREE */,
 		 tree pstr /* = NULL_TREE */)
 {
@@ -6860,7 +6862,7 @@  find_flexarrays (tree t, flexmems_t *fmem, bool base_p,
 	  /* Check the nested unnamed type referenced via a typedef
 	     independently of FMEM (since it's not a data member of
 	     the enclosing class).  */
-	  check_flexarrays (TREE_TYPE (fld));
+	  check_flexarrays (TREE_TYPE (fld), diag);
 	  continue;
 	}
 
@@ -6913,8 +6915,8 @@  find_flexarrays (tree t, flexmems_t *fmem, bool base_p,
 	      if (first && !array && !ANON_AGGR_TYPE_P (eltype))
 		fmem->first = NULL_TREE;
 
-	      find_flexarrays (eltype, fmem, false, pun,
-			       !pstr && TREE_CODE (t) == RECORD_TYPE ? fld : pstr);
+	      tree ps = !pstr && TREE_CODE (t) == RECORD_TYPE ? fld : pstr;
+	      find_flexarrays (eltype, diag, fmem, false, pun, ps);
 
 	      if (fmem->array != array)
 		continue;
@@ -7001,17 +7003,28 @@  find_flexarrays (tree t, flexmems_t *fmem, bool base_p,
 static void
 diagnose_invalid_flexarray (const flexmems_t *fmem)
 {
-  if (fmem->array && fmem->enclosing
-      && pedwarn (location_of (fmem->enclosing), OPT_Wpedantic,
-		  TYPE_DOMAIN (TREE_TYPE (fmem->array))
-		  ? G_("invalid use of %q#T with a zero-size array "
-		       "in %q#D")
-		  : G_("invalid use of %q#T with a flexible array member "
-		       "in %q#T"),
-		  DECL_CONTEXT (fmem->array),
-		  DECL_CONTEXT (fmem->enclosing)))
-    inform (DECL_SOURCE_LOCATION (fmem->array),
-	    "array member %q#D declared here", fmem->array);
+  if (fmem->array && fmem->enclosing)
+    {
+      location_t loc = location_of (fmem->enclosing);
+
+      bool warn;
+
+      if (TYPE_DOMAIN (TREE_TYPE (fmem->array)))
+	  warn = pedwarn (loc, OPT_Wpedantic,
+			  "invalid use of %q#T with a zero-size array in %q#D",
+			  DECL_CONTEXT (fmem->array),
+			  DECL_CONTEXT (fmem->enclosing));
+      else
+	warn = warning_at (loc, OPT_Wflexarray,
+			   "invalid use of %q#T with a flexible array member "
+			   "in %q#T",
+			   DECL_CONTEXT (fmem->array),
+			   DECL_CONTEXT (fmem->enclosing));
+
+      if (warn)
+	inform (DECL_SOURCE_LOCATION (fmem->array),
+		"array member %q#D declared here", fmem->array);
+    }
 }
 
 /* Issue diagnostics for invalid flexible array members or zero-length
@@ -7093,11 +7106,11 @@  diagnose_flexarrays (tree t, const flexmems_t *fmem)
    non-static data member of T and, if one exists, that it is the last
    non-static data member of T and its base classes.  FMEM is expected
    to be initially null and is used internally by recursive calls to
-   the function.  Issue the appropriate diagnostics for the array member
-   that fails the checks.  */
+   the function.  if DIAG is true, issue the appropriate diagnostics
+   for the array member that fails the checks.  */
 
-static void
-check_flexarrays (tree t, flexmems_t *fmem /* = NULL */,
+static tree
+check_flexarrays (tree t, bool diag, flexmems_t *fmem /* = NULL */,
 		  bool base_p /* = false */)
 {
   /* Initialize the result of a search for flexible array and zero-length
@@ -7107,7 +7120,7 @@  check_flexarrays (tree t, flexmems_t *fmem /* = NULL */,
   if (!fmem)
     fmem = &flexmems;
   else if (fmem->array && fmem->first && fmem->after[0])
-    return;
+    return NULL_TREE;
 
   tree fam = fmem->array;
 
@@ -7115,7 +7128,7 @@  check_flexarrays (tree t, flexmems_t *fmem /* = NULL */,
   if (CLASSTYPE_HAS_PRIMARY_BASE_P (t))
     {
       tree basetype = BINFO_TYPE (CLASSTYPE_PRIMARY_BINFO (t));
-      check_flexarrays (basetype, fmem, true);
+      check_flexarrays (basetype, diag, fmem, true);
     }
 
   /* Recursively check the base classes.  */
@@ -7133,7 +7146,7 @@  check_flexarrays (tree t, flexmems_t *fmem /* = NULL */,
 	continue;
 
       /* Check the base class.  */
-      check_flexarrays (BINFO_TYPE (base_binfo), fmem, /*base_p=*/true);
+      check_flexarrays (BINFO_TYPE (base_binfo), diag, fmem, /*base_p=*/true);
     }
 
   if (fmem == &flexmems)
@@ -7150,7 +7163,7 @@  check_flexarrays (tree t, flexmems_t *fmem /* = NULL */,
 	  /* Check the virtual base class.  */
 	  tree basetype = TREE_TYPE (base_binfo);
 
-	  check_flexarrays (basetype, fmem, /*base_p=*/true);
+	  check_flexarrays (basetype, diag, fmem, /*base_p=*/true);
 	}
     }
 
@@ -7161,9 +7174,9 @@  check_flexarrays (tree t, flexmems_t *fmem /* = NULL */,
   /* Search the members of the current (possibly derived) class, skipping
      unnamed structs and unions since those could be anonymous.  */
   if (fmem != &flexmems || !maybe_anon_p)
-    find_flexarrays (t, fmem, base_p || fam != fmem->array);
+    find_flexarrays (t, diag, fmem, base_p || fam != fmem->array);
 
-  if (fmem == &flexmems && !maybe_anon_p)
+  if (diag && fmem == &flexmems && !maybe_anon_p)
     {
       /* Issue diagnostics for invalid flexible and zero-length array
 	 members found in base classes or among the members of the current
@@ -7172,6 +7185,32 @@  check_flexarrays (tree t, flexmems_t *fmem /* = NULL */,
 	 be diagnosed when checking it.  */
       diagnose_flexarrays (t, fmem);
     }
+
+  return fmem->array;
+}
+
+/* Return a tree node pointing to the first flexible array member or,
+   when ZERO_LENGTH is true, zero-length array member, declared in TYPE
+   or its bases.  Violations of C/C++ constraints on such members are
+   not diagnosed.  */
+
+tree
+find_flexarray (tree type, bool zero_length /* = false */)
+{
+  if (TREE_CODE (type) != RECORD_TYPE
+      || TYPE_PTRMEMFUNC_P (type))
+    return NULL_TREE;
+
+  if (tree flexarray = check_flexarrays (type, false))
+    {
+      bool is_zero_length = TYPE_DOMAIN (TREE_TYPE (flexarray));
+      if (zero_length)
+	return is_zero_length ? flexarray : NULL_TREE;
+
+      return is_zero_length ? NULL_TREE : flexarray;
+    }
+
+  return NULL_TREE;
 }
 
 /* Perform processing required when the definition of T (a class type)
@@ -7241,7 +7280,7 @@  finish_struct_1 (tree t)
   /* With the layout complete, check for flexible array members and
      zero-length arrays that might overlap other members in the final
      layout.  */
-  check_flexarrays (t);
+  check_flexarrays (t, true);
 
   virtuals = modify_all_vtables (t, nreverse (virtuals));
 
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 5be5dfe..05ad86a 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5774,6 +5774,7 @@  extern void insert_late_enum_def_into_classtype_sorted_fields (tree, tree);
 extern bool uniquely_derived_from_p             (tree, tree);
 extern bool publicly_uniquely_derived_p         (tree, tree);
 extern tree common_enclosing_class		(tree, tree);
+extern tree find_flexarray			(tree, bool = false);
 
 /* in cvt.c */
 extern tree convert_to_reference		(tree, tree, int, int, tree,
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 0a92566..bea90c0 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -6129,6 +6129,43 @@  reshape_init (tree type, tree init, tsubst_flags_t complain)
   return new_init;
 }
 
+/* Diagnose an invalid DECLaration of an object or type with a flexible
+   array member.  Return true if the declaration was rejected with a hard
+   error, false otherwise.  */
+
+static bool
+maybe_reject_flexarray_decl (tree decl, tree type)
+{
+  /* Strip top level reference and pointers, in that order.  */
+  if (TREE_CODE (type) == REFERENCE_TYPE)
+    type = TREE_TYPE (type);
+
+  while (TREE_CODE (type) == POINTER_TYPE)
+    type = TREE_TYPE (type);
+
+  /* Determine array element type.  */
+  tree eltype = type;
+  while (TREE_CODE (eltype) == ARRAY_TYPE)
+    eltype = TREE_TYPE (eltype);
+
+  tree flexarray;
+  if (TREE_CODE (eltype) == RECORD_TYPE
+      && eltype != type
+      && !TYPE_NEEDS_CONSTRUCTING (eltype)
+      && (flexarray = find_flexarray (eltype)))
+    {
+      error_at (DECL_SOURCE_LOCATION (decl),
+		"invalid use of %#qT with flexible array member %#qD",
+		eltype, flexarray);
+      inform (DECL_SOURCE_LOCATION (flexarray),
+	      "member declared here");
+
+      return true;
+    }
+
+  return false;
+}
+
 /* Verify array initializer.  Returns true if errors have been reported.  */
 
 bool
@@ -6156,7 +6193,8 @@  check_array_initializer (tree decl, tree type, tree init)
       error ("variable-sized compound literal");
       return true;
     }
-  return false;
+
+  return maybe_reject_flexarray_decl (decl, type);
 }
 
 /* Subroutine of check_initializer; args are passed down from that function.
@@ -6974,6 +7012,8 @@  cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
 	  set_identifier_type_value (DECL_NAME (decl), decl);
 	}
 
+      maybe_reject_flexarray_decl (decl, type);
+
       /* If we have installed this as the canonical typedef for this
 	 type, and that type has not been defined yet, delay emitting
 	 the debug information for it, as we will emit it later.  */
@@ -7061,12 +7101,19 @@  cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
 	  if (!DECL_EXTERNAL (decl))
 	    var_definition_p = true;
 	}
-      /* If the variable has an array type, lay out the type, even if
-	 there is no initializer.  It is valid to index through the
-	 array, and we must get TYPE_ALIGN set correctly on the array
-	 type.  */
-      else if (TREE_CODE (type) == ARRAY_TYPE)
-	layout_type (type);
+      else
+	{
+	  /* Reject invalid uninitialized declarations of objects
+	     of types with flexible array members.  */
+	  maybe_reject_flexarray_decl (decl, type);
+
+	  /* If the variable has an array type, lay out the type, even if
+	     there is no initializer.  It is valid to index through the
+	     array, and we must get TYPE_ALIGN set correctly on the array
+	     type.  */
+	  if (TREE_CODE (type) == ARRAY_TYPE)
+	    layout_type (type);
+	}
 
       if (TREE_STATIC (decl)
 	  && !at_function_scope_p ()
@@ -11835,10 +11882,10 @@  grokdeclarator (const cp_declarator *declarator,
 		  /* Do not warn on flexible array members in system
 		     headers because glibc uses them.  */;
 		else if (name)
-		  pedwarn (input_location, OPT_Wpedantic,
+		  pedwarn (input_location, OPT_Wflexarray,
 			   "ISO C++ forbids flexible array member %qs", name);
 		else
-		  pedwarn (input_location, OPT_Wpedantic,
+		  pedwarn (input_location, OPT_Wflexarray,
 			   "ISO C++ forbids flexible array members");
 
 		/* Flexible array member has a null domain.  */
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index b8ce9fe..466e443 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -13925,6 +13925,21 @@  tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	    return error_mark_node;
 	  }
 
+	/* As an extension, deduction also fails when substitution would
+	   result in creating an array of structs with a flexible array
+	   member.  */
+	if (tree flexarray = find_flexarray (type))
+	  {
+	    if (complain & tf_error)
+	      {
+		error ("invalid use of %#qT with flexible array member %qD",
+		       type, flexarray);
+		inform (DECL_SOURCE_LOCATION (flexarray),
+			"member declared here");
+	      }
+	    return error_mark_node;
+	  }
+
 	if (abstract_virtuals_error_sfinae (ACU_ARRAY, type, complain))
 	  return error_mark_node;
 
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 58a01c9..f56f591 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -33,8 +33,31 @@  along with GCC; see the file COPYING3.  If not see
 #include "varasm.h"
 #include "intl.h"
 
+/* Description of a initializer CONSTRUCTOR.  */
+struct init_ctor_info
+{
+  /* The DECL of the outermost full object being initialized if one
+     exists, or the type of the unnamed temporary being initialized
+     when it's a compound literal, or NULL_TREE otherwise.  */
+  tree decl;
+
+  /* The TYPE of the subobject being initialized.  */
+  tree type;
+
+  /* The DECL of the current subobject of DECL being initialized,
+     or NULL_TREE when no such subobject has been found yet (i.e.,
+     when the initializer applies to the outermost full object.  */
+  tree field;
+
+  /* The initializer expression.  */
+  tree init;
+};
+
 static tree
-process_init_constructor (tree type, tree init, tsubst_flags_t complain);
+process_init_constructor (init_ctor_info &, tsubst_flags_t);
+
+static tree
+digest_init_flags (init_ctor_info &, int, tsubst_flags_t);
 
 
 /* Print an error message stemming from an attempt to use
@@ -799,8 +822,16 @@  store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
   if (flags & LOOKUP_ALREADY_DIGESTED)
     value = init;
   else
-    /* Digest the specified initializer into an expression.  */
-    value = digest_init_flags (type, init, flags, tf_warning_or_error);
+    {
+      init_ctor_info init_info;
+      init_info.decl = decl;
+      init_info.type = type;
+      init_info.field = NULL_TREE;
+      init_info.init = init;
+
+      /* Digest the specified initializer into an expression.  */
+      value = digest_init_flags (init_info, flags, tf_warning_or_error);
+    }
 
   value = extend_ref_init_temps (decl, value, cleanups);
 
@@ -986,9 +1017,67 @@  check_narrowing (tree type, tree init, tsubst_flags_t complain)
   return ok;
 }
 
-/* Process the initializer INIT for a variable of type TYPE, emitting
-   diagnostics for invalid initializers and converting the initializer as
-   appropriate.
+/* Diagnose an invalid initialization of an object with a flexible array
+   member.  */
+
+static void
+maybe_diag_flexinit (const init_ctor_info &init_info)
+{
+  /* Bail if no member has been found yet, or if the member is not
+     a flexible array, or if the initializer for the flexible array
+     member is empty (it's fine to initialize others members of
+     a struct containing a flexible array member).  */
+  if (!init_info.field
+      || TREE_CODE (init_info.type) != ARRAY_TYPE
+      || TYPE_DOMAIN (init_info.type)
+      || EMPTY_CONSTRUCTOR_P (init_info.init))
+    return;
+
+  bool diag = true;
+
+  if (!init_info.decl)
+    {
+      /* This is an object with dynamic storage duration.  */
+      diag = false;
+    }
+  else if (TYPE_P (init_info.decl))
+    {
+      /* As a special case, when INIT_INFO.DECL refers to a type,
+	 it's a compound literal.  */
+      error ("initializing flexible array member %qD "
+	     "of a compound literal",
+	     init_info.field);
+    }
+  else if (DECL_THREAD_LOCAL_P (init_info.decl))
+    diag = warning (OPT_Wflexarray_init,
+		    "initializing flexible array member %qD "
+		    "of an object with thread storage duration",
+		    init_info.field);
+  else if (TREE_STATIC (init_info.decl))
+    diag = warning (OPT_Wflexarray_init,
+		    "initializing flexible array member %qD "
+		    "of an object with static storage duration",
+		    init_info.field);
+  else
+    error ("initializing flexible array member %qD "
+	   "of an object with automatic storage duration",
+	   init_info.field);
+
+  if (diag)
+    {
+      tree type = (TYPE_P (init_info.decl)
+		   ? init_info.decl : TREE_TYPE (init_info.decl));
+
+      tree flexarray = find_flexarray (type);
+      gcc_assert (flexarray);
+
+      inform (DECL_SOURCE_LOCATION (flexarray),
+	      "member declared here");
+    }
+}
+
+/* Process the initializer described by INIT_INFO, emitting diagnostics
+   for invalid initializers and converting the initializer as appropriate.
 
    For aggregate types, it assumes that reshape_init has already run, thus the
    initializer will have the right shape (brace elision has been undone).
@@ -996,9 +1085,12 @@  check_narrowing (tree type, tree init, tsubst_flags_t complain)
    NESTED is true iff we are being called for an element of a CONSTRUCTOR.  */
 
 static tree
-digest_init_r (tree type, tree init, bool nested, int flags,
+digest_init_r (init_ctor_info &init_info, bool nested, int flags,
 	       tsubst_flags_t complain)
 {
+  tree type = init_info.type;
+  tree init = init_info.init;
+
   enum tree_code code = TREE_CODE (type);
 
   if (error_operand_p (init))
@@ -1025,13 +1117,6 @@  digest_init_r (tree type, tree init, bool nested, int flags,
      them if they were present.  */
   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");
-	}
-
       tree typ1 = TYPE_MAIN_VARIANT (TREE_TYPE (type));
       if (char_type_p (typ1)
 	  /*&& init */
@@ -1066,6 +1151,9 @@  digest_init_r (tree type, tree init, bool nested, int flags,
 		}
 	    }
 
+	  /* Diagnose the initialization of a flexible array member.  */
+	  maybe_diag_flexinit (init_info);
+
 	  if (type != TREE_TYPE (init))
 	    {
 	      init = copy_node (init);
@@ -1128,7 +1216,10 @@  digest_init_r (tree type, tree init, bool nested, int flags,
 
   if (BRACE_ENCLOSED_INITIALIZER_P (init)
       && !TYPE_NON_AGGREGATE_CLASS (type))
-    return process_init_constructor (type, init, complain);
+    {
+      init_info.init = init;
+      return process_init_constructor (init_info, complain);
+    }
   else
     {
       if (COMPOUND_LITERAL_P (init) && TREE_CODE (type) == ARRAY_TYPE)
@@ -1164,16 +1255,43 @@  digest_init_r (tree type, tree init, bool nested, int flags,
     }
 }
 
+/* Wrapper around digest_init_r. */
+
 tree
 digest_init (tree type, tree init, tsubst_flags_t complain)
 {
-  return digest_init_r (type, init, false, LOOKUP_IMPLICIT, complain);
+  init_ctor_info init_info;
+  init_info.decl = NULL_TREE;
+  init_info.field = NULL_TREE;
+  init_info.type = type;
+  init_info.init = init;
+  return digest_init_r (init_info, false, LOOKUP_IMPLICIT, complain);
 }
 
+/* Wrapper around digest_init_r called only for compound literals
+   (from finish_compound_literal in semantics.c). */
+
 tree
 digest_init_flags (tree type, tree init, int flags, tsubst_flags_t complain)
 {
-  return digest_init_r (type, init, false, flags, complain);
+  init_ctor_info init_info;
+
+  /* As a special case, set DECL to TYPE as an indication that
+     an object with automatic storage duration is being initialized.  */
+  init_info.decl = type;
+  init_info.field = NULL_TREE;
+  init_info.type = type;
+  init_info.init = init;
+  return digest_init_r (init_info, false, flags, complain);
+}
+
+/* Internal wrapper around digest_init_r. */
+
+static tree
+digest_init_flags (init_ctor_info &init_info, int flags,
+		   tsubst_flags_t complain)
+{
+  return digest_init_r (init_info, false, flags, complain);
 }
 
 /* Process the initializer INIT for an NSDMI DECL (a FIELD_DECL).  */
@@ -1189,7 +1307,15 @@  digest_nsdmi_init (tree decl, tree init)
   if (BRACE_ENCLOSED_INITIALIZER_P (init)
       && CP_AGGREGATE_TYPE_P (type))
     init = reshape_init (type, init, tf_warning_or_error);
-  init = digest_init_flags (type, init, flags, tf_warning_or_error);
+
+  init_ctor_info init_info;
+  init_info.decl = NULL_TREE;
+  init_info.type = type;
+  init_info.field = NULL_TREE;
+  init_info.init = init;
+
+  init = digest_init_flags (init_info, flags, tf_warning_or_error);
+
   if (TREE_CODE (init) == TARGET_EXPR)
     /* This represents the whole initialization.  */
     TARGET_EXPR_DIRECT_INIT_P (init) = true;
@@ -1226,9 +1352,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 (init_ctor_info &init_info, tsubst_flags_t complain)
 {
-  init = digest_init_r (type, init, true, LOOKUP_IMPLICIT, complain);
+  tree init = digest_init_r (init_info, true, 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);
@@ -1241,14 +1367,20 @@  massage_init_elt (tree type, tree init, tsubst_flags_t complain)
   return init;
 }
 
+/* Diagnose questionable or unsupported initialization of a flexible
+   array member.  */
+
 /* Subroutine of process_init_constructor, which will process an initializer
    INIT for an array or vector of type TYPE. Returns the flags (PICFLAG_*)
    which describe the initializers.  */
 
 static int
-process_init_constructor_array (tree type, tree init,
+process_init_constructor_array (init_ctor_info &init_info,
 				tsubst_flags_t complain)
 {
+  tree type = init_info.type;
+  tree init = init_info.init;
+
   unsigned HOST_WIDE_INT i, len = 0;
   int flags = 0;
   bool unbounded = false;
@@ -1261,14 +1393,23 @@  process_init_constructor_array (tree type, tree init,
   if (TREE_CODE (type) == ARRAY_TYPE)
     {
       /* C++ flexible array members have a null domain.  */
-      tree domain = TYPE_DOMAIN (type);
-      if (domain && TREE_CONSTANT (TYPE_MAX_VALUE (domain)))
-	len = wi::ext (wi::to_offset (TYPE_MAX_VALUE (domain))
-                       - wi::to_offset (TYPE_MIN_VALUE (domain)) + 1,
-		       TYPE_PRECISION (TREE_TYPE (domain)),
-		       TYPE_SIGN (TREE_TYPE (domain))).to_uhwi ();
+      if (tree domain = TYPE_DOMAIN (type))
+	{
+	  if (TREE_CONSTANT (TYPE_MAX_VALUE (domain)))
+	    len = wi::ext (wi::to_offset (TYPE_MAX_VALUE (domain))
+			   - wi::to_offset (TYPE_MIN_VALUE (domain)) + 1,
+			   TYPE_PRECISION (TREE_TYPE (domain)),
+			   TYPE_SIGN (TREE_TYPE (domain))).to_uhwi ();
+	  else
+	    unbounded = true;  /* Take as many elements as there are.  */
+	}
       else
-	unbounded = true;  /* Take as many as there are.  */
+	{
+	  unbounded = true;  /* Take as many elements as there are.  */
+
+	  /* Diagnose initialization of a flexible array member.  */
+	  maybe_diag_flexinit (init_info);
+	}
     }
   else
     /* Vectors are like simple fixed-size arrays.  */
@@ -1297,7 +1438,11 @@  process_init_constructor_array (tree type, tree init,
       else
 	ce->index = size_int (i);
       gcc_assert (ce->value);
-      ce->value = massage_init_elt (TREE_TYPE (type), ce->value, complain);
+
+      init_info.type = TREE_TYPE (type);
+      init_info.field = ce->index;
+      init_info.init = ce->value;
+      ce->value = massage_init_elt (init_info, complain);
 
       if (ce->value != error_mark_node)
 	gcc_assert (same_type_ignoring_top_level_qualifiers_p
@@ -1319,7 +1464,10 @@  process_init_constructor_array (tree type, tree init,
 	       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);
+
+	    init_info.type = TREE_TYPE (type);
+	    init_info.init = next;
+	    next = massage_init_elt (init_info, complain);
 	    if (initializer_zerop (next))
 	      /* The default zero-initialization is fine for us; don't
 		 add anything to the CONSTRUCTOR.  */
@@ -1350,9 +1498,12 @@  process_init_constructor_array (tree type, tree init,
    the initializers.  */
 
 static int
-process_init_constructor_record (tree type, tree init,
+process_init_constructor_record (init_ctor_info &init_info,
 				 tsubst_flags_t complain)
 {
+  tree type = init_info.type;
+  tree init = init_info.init;
+
   vec<constructor_elt, va_gc> *v = NULL;
   tree field;
   int skipped = 0;
@@ -1409,7 +1560,11 @@  process_init_constructor_record (tree type, tree init,
 	    }
 
 	  gcc_assert (ce->value);
-	  next = massage_init_elt (type, ce->value, complain);
+
+	  init_info.type = type;
+	  init_info.field = field;
+	  init_info.init = ce->value;
+	  next = massage_init_elt (init_info, complain);
 	  ++idx;
 	}
       else if (DECL_INITIAL (field))
@@ -1432,7 +1587,11 @@  process_init_constructor_record (tree type, tree init,
 	     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);
+
+	  init_info.type = TREE_TYPE (field);
+	  init_info.init = next;
+	  init_info.field = field;
+	  next = massage_init_elt (init_info, complain);
 
 	  /* Warn when some struct elements are implicitly initialized.  */
 	  if ((complain & tf_warning)
@@ -1458,14 +1617,28 @@  process_init_constructor_record (tree type, tree init,
 		return PICFLAG_ERRONEOUS;
 	    }
 
-	  /* Warn when some struct elements are implicitly initialized
-	     to zero.  However, avoid issuing the warning for flexible
-	     array members since they need not have any elements.  */
-	  if ((TREE_CODE (fldtype) != ARRAY_TYPE || TYPE_DOMAIN (fldtype))
-	      && (complain & tf_warning)
-	      && !EMPTY_CONSTRUCTOR_P (init))
-	    warning (OPT_Wmissing_field_initializers,
-		     "missing initializer for member %qD", field);
+	  if (TREE_CODE (fldtype) == ARRAY_TYPE && !TYPE_DOMAIN (fldtype))
+	    {
+#if 0
+	      if (!EMPTY_CONSTRUCTOR_P (init))
+		{
+		  if (diag_flexarray_p)
+		    error ("initializing flexible array member %qD", field);
+		  else
+		    warning (OPT_Wpedantic,
+			     "initializing flexible array member %qD", field);
+		}
+#endif
+	    }
+	  else if ((complain & tf_warning)
+		   && !EMPTY_CONSTRUCTOR_P (init))
+	    {
+	      /* Warn when some struct elements are implicitly initialized
+		 to zero.  However, avoid issuing the warning for flexible
+		 array members since they need not have any elements.  */
+	      warning (OPT_Wmissing_field_initializers,
+		       "missing initializer for member %qD", field);
+	    }
 
 	  if (!zero_init_p (fldtype)
 	      || skipped < 0)
@@ -1504,9 +1677,11 @@  process_init_constructor_record (tree type, tree init,
    which describe the initializer.  */
 
 static int
-process_init_constructor_union (tree type, tree init,
+process_init_constructor_union (init_ctor_info &init_info,
 				tsubst_flags_t complain)
 {
+  tree type = init_info.type;
+  tree init = init_info.init;
   constructor_elt *ce;
   int len;
 
@@ -1589,7 +1764,12 @@  process_init_constructor_union (tree type, tree init,
     }
 
   if (ce->value && ce->value != error_mark_node)
-    ce->value = massage_init_elt (TREE_TYPE (ce->index), ce->value, complain);
+    {
+      init_info.type = TREE_TYPE (ce->index);
+      init_info.field = ce->index;
+      init_info.init = ce->value;
+      ce->value = massage_init_elt (init_info, complain);
+    }
 
   return picflag_from_initializer (ce->value);
 }
@@ -1609,18 +1789,21 @@  process_init_constructor_union (tree type, tree init,
    of error.  */
 
 static tree
-process_init_constructor (tree type, tree init, tsubst_flags_t complain)
+process_init_constructor (init_ctor_info &init_info, tsubst_flags_t complain)
 {
+  tree type = init_info.type;
+  tree init = init_info.init;
+
   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 (init_info, complain);
   else if (TREE_CODE (type) == RECORD_TYPE)
-    flags = process_init_constructor_record (type, init, complain);
+    flags = process_init_constructor_record (init_info, complain);
   else if (TREE_CODE (type) == UNION_TYPE)
-    flags = process_init_constructor_union (type, init, complain);
+    flags = process_init_constructor_union (init_info, complain);
   else
     gcc_unreachable ();
 
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index f301aa3..8e21596 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -274,7 +274,8 @@  Objective-C and Objective-C++ Dialects}.
 -Wno-discarded-qualifiers  -Wno-discarded-array-qualifiers @gol
 -Wno-div-by-zero  -Wdouble-promotion  -Wduplicated-cond @gol
 -Wempty-body  -Wenum-compare  -Wno-endif-labels  -Wexpansion-to-defined @gol
--Werror  -Werror=*  -Wfatal-errors  -Wfloat-equal  -Wformat  -Wformat=2 @gol
+-Werror  -Werror=*  -Wfatal-errors -Wflexarray -Wflexarray-init @gol
+-Wfloat-equal  -Wformat  -Wformat=2 @gol
 -Wno-format-contains-nul  -Wno-format-extra-args  @gol
 -Wformat-nonliteral -Wformat-overflow=@var{n} @gol
 -Wformat-security  -Wformat-signedness  -Wformat-truncation=@var{n} @gol
@@ -3853,6 +3854,25 @@  of a derived class.
 
 @end itemize
 
+@item -Wflexarray @r{(C++ only)}
+@opindex Wflexarray
+@opindex Wno-flexarray
+Warn when a declaration of a flexible array member is found.  Flexible
+array members are a C feature that is not specified by the C++ standard.
+G++ accepts flexible array members for compatibility with C.
+The @option{-Wflexarray} option is enabled by @option{-Wpedantic}.
+
+@item -Wflexarray-init @r{(C++ only)}
+@opindex Wflexarray
+@opindex Wno-flexarray-init
+Warn when one or more elements of a flexible array member are explicitly
+initialized.  C doesn't permit structures containing a flexible array
+member to be initialized.  However, as an extension, GCC allows objects
+with flexible array members to be initialized in limited contexts, and
+G++ supports a similar extension.  In other contexts G++ rejects
+initialization of such objects with an error.
+The @option{-Wflexarray-init} option is enabled by @option{-Wpedantic}.
+
 @item -Wchar-subscripts
 @opindex Wchar-subscripts
 @opindex Wno-char-subscripts
diff --git a/gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations1.C b/gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations1.C
index bca03a1..b90c017 100644
--- a/gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations1.C
+++ b/gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations1.C
@@ -1,5 +1,5 @@ 
 // { dg-do compile { target c++11 } }
-// { dg-additional-options "-Wno-error=pedantic" }
+// { dg-additional-options "-Wno-error=pedantic -Wno-error=flexarray" }
 
 #define INTB (__SIZEOF_INT__ * __CHAR_BIT__)
 struct S { int i : INTB * 3 / 4; S (); };
diff --git a/gcc/testsuite/g++.dg/ext/flexarray-mangle-2.C b/gcc/testsuite/g++.dg/ext/flexarray-mangle-2.C
index 3abb407..0a240d4 100644
--- a/gcc/testsuite/g++.dg/ext/flexarray-mangle-2.C
+++ b/gcc/testsuite/g++.dg/ext/flexarray-mangle-2.C
@@ -1,6 +1,6 @@ 
 // PR c++/69277 - [6 Regression] ICE mangling a flexible array member
 // { dg-do compile { target c++11 } }
-// { dg-additional-options "-Wno-error=pedantic" }
+// { dg-additional-options "-Wno-error=flexarray" }
 
 struct A {
   int n;
diff --git a/gcc/testsuite/g++.dg/ext/flexarray-mangle.C b/gcc/testsuite/g++.dg/ext/flexarray-mangle.C
index 658d935..6a45285 100644
--- a/gcc/testsuite/g++.dg/ext/flexarray-mangle.C
+++ b/gcc/testsuite/g++.dg/ext/flexarray-mangle.C
@@ -1,6 +1,6 @@ 
 // PR c++/69277 - [6 Regression] ICE mangling a flexible array member
 // { dg-do compile }
-// { dg-additional-options "-Wno-error=pedantic" }
+// { dg-additional-options "-Wno-error=flexarray" }
 
 struct A {
   int n;
diff --git a/gcc/testsuite/g++.dg/ext/flexarray-subst.C b/gcc/testsuite/g++.dg/ext/flexarray-subst.C
index 6cf03a4..d83b2dd 100644
--- a/gcc/testsuite/g++.dg/ext/flexarray-subst.C
+++ b/gcc/testsuite/g++.dg/ext/flexarray-subst.C
@@ -1,7 +1,7 @@ 
 // PR c++/69251 - [6 Regression] ICE (segmentation fault) in unify_array_domain
 // on i686-linux-gnu
 // { dg-do compile }
-// { dg-additional-options "-Wno-error=pedantic" }
+// { dg-additional-options "-Wno-error=flexarray" }
 
 struct A {
   int n;
diff --git a/gcc/testsuite/g++.dg/ext/flexary10.C b/gcc/testsuite/g++.dg/ext/flexary10.C
index 4d1ff56..eae527b 100644
--- a/gcc/testsuite/g++.dg/ext/flexary10.C
+++ b/gcc/testsuite/g++.dg/ext/flexary10.C
@@ -12,7 +12,7 @@  struct A foo (void)
   // Verify the initializer below is accepted for compatibility with gcc
   // (in C mode).
   static struct A
-    a = { 2, { 1, 0 } };   // { dg-warning "initialization of a flexible array member" }
+    a = { 2, { 1, 0 } };   // { dg-warning "initializing flexible array member" }
 
   return a;
 }
diff --git a/gcc/testsuite/g++.dg/ext/flexary10.s b/gcc/testsuite/g++.dg/ext/flexary10.s
new file mode 100644
index 0000000..e69de29
diff --git a/gcc/testsuite/g++.dg/ext/flexary11.C b/gcc/testsuite/g++.dg/ext/flexary11.C
index f958cc5..5b0e3c4 100644
--- a/gcc/testsuite/g++.dg/ext/flexary11.C
+++ b/gcc/testsuite/g++.dg/ext/flexary11.C
@@ -15,5 +15,6 @@  void f ()
   // The following use of a flexible array member in a compound literal
   // is invalid in C and rejected by GCC in C mode and so it's also
   // rejected in C++ mode.
-  (struct A){ 1, "" };   // { dg-error "forbids compound-literals|initialization of a flexible array member|invalid use of a flexible array member" }
+  (struct A){ 1, "" };   // { dg-error "forbids compound-literals" }
+  // { dg-error "initializing flexible array member" "" { target *-*-* } .-1 }
 }
diff --git a/gcc/testsuite/g++.dg/ext/flexary12.C b/gcc/testsuite/g++.dg/ext/flexary12.C
index 61726f6..0deb74c 100644
--- a/gcc/testsuite/g++.dg/ext/flexary12.C
+++ b/gcc/testsuite/g++.dg/ext/flexary12.C
@@ -13,8 +13,11 @@  void f1 ()
 {
   // This is the meat of the test from c++/69290:
   struct A a
-    = { "c" };   // { dg-error "invalid conversion from .const char\\*. to .int." }
+    = { "c" };     // { dg-error "initializing flexible array member" }
+  // { dg-error "invalid conversion" "" { target *-*-* } .-1 }
 
+  // The location of the error is poor.  It should point at the initializer
+  // in the initializer list that corresponds to the flexible array member.
   (void)&a;
 }
 
@@ -28,13 +31,15 @@  struct B {
 void f2 ()
 {
   struct B b1
-    = { 0, "c" };   // { dg-error "invalid conversion from .const char\\*. to .int." }
+    = { 0, "c" };       // { dg-error "initializing flexible array member" }
+  // { dg-error "invalid conversion" "" { target *-*-* } .-1 }
 
   (void)&b1;
 
   const char s[] = "c";
   struct B b2
-    = { 0, s };   // { dg-error "invalid conversion from .const char\\*. to .int." }
+    = { 0, s };     // { dg-error "initializing flexible array member" }
+  // { dg-error "invalid conversion" "" { target *-*-* } .-1 }
 
   (void)&b2;
 }
@@ -58,7 +63,8 @@  struct C {
 void f3 ()
 {
   struct C<double> cd
-    = { "c" };   // { dg-error "cannot convert .const char\\*. to .double." }
+    = { "c" };   // { dg-error "initializing flexible array member" }
+  // { dg-error "cannot conver" "" { target *-*-* } .-1 }
 
   (void)&cd;
 }
diff --git a/gcc/testsuite/g++.dg/ext/flexary13.C b/gcc/testsuite/g++.dg/ext/flexary13.C
index 462ed65..cf65554 100644
--- a/gcc/testsuite/g++.dg/ext/flexary13.C
+++ b/gcc/testsuite/g++.dg/ext/flexary13.C
@@ -15,50 +15,46 @@  int i = 12345678;
 int main ()
 {
   {
+    // It's okay to initialize other members of a struct containing
+    // a flexible artay member.  It's just not okay to explicitly
+    // initialize members of the flexible artay member unless the
+    // object has static or thread storage duration.
     Ax s = { 0 };
     ASSERT (s.n == 0);
   }
   {
-    Ax s =
-      { 0, { } };   // dg-warning "initialization of a flexible array member" }
+    Ax s = { 0, { } };
     ASSERT (s.n == 0);
   }
   {
-    Ax s =
-      { 1, { 2 } };   // dg-warning "initialization of a flexible array member" }
+    Ax s = { 1, { 2 } };   // { dg-error "initializing flexible array member" }
     ASSERT (s.n == 1 && s.a [0] == 2);
   }
   {
-    Ax s =
-      { 2, { 3, 4 } }; // dg-warning "initialization of a flexible array member" }
+    Ax s = { 2, { 3, 4 } }; // { dg-error "initializing flexible array member" }
     ASSERT (s.n = 2 && s.a [0] == 3 && s.a [1] == 4);
   }
   {
-    Ax s =
-      { 123, i };   // dg-warning "initialization of a flexible array member" }
+    Ax s = { 123, i };   // { dg-error "initializing flexible array member" }
     ASSERT (s.n == 123 && s.a [0] == i);
   }
   {
-    Ax s =
-      { 456, { i } }; // dg-warning "initialization of a flexible array member" }
+    Ax s = { 456, { i } }; // { dg-error "initializing flexible array member" }
     ASSERT (s.n == 456 && s.a [0] == i);
   }
   {
     int j = i + 1, k = j + 1;
-    Ax s =
-      { 3, { i, j, k } }; // dg-warning "initialization of a flexible array member" }
+    Ax s = { 3, { i, j, k } }; // { dg-error "initializing flexible array member" }
     ASSERT (s.n == 3 && s.a [0] == i && s.a [1] == j && s.a [2] == k);
   }
 
   {
-    AAx s =
-      { 1, { 2 } };   // dg-warning "initialization of a flexible array member" }
+    AAx s = { 1, { 2 } };
     ASSERT (s.i == 1 && s.ax.n == 2);
   }
 
   {
-    AAx s =
-      { 1, { 2, { 3 } } };   // dg-warning "initialization of a flexible array member" }
+    AAx s = { 1, { 2, { 3 } } };   // { dg-error "initializing flexible array member" }
     ASSERT (s.i == 1 && s.ax.n == 2 && s.ax.a [0] == 3);
   }
 }
diff --git a/gcc/testsuite/g++.dg/ext/flexary15.C b/gcc/testsuite/g++.dg/ext/flexary15.C
index c03a60e..d83f00f 100644
--- a/gcc/testsuite/g++.dg/ext/flexary15.C
+++ b/gcc/testsuite/g++.dg/ext/flexary15.C
@@ -4,11 +4,13 @@ 
 // { dg-options "-Wno-pedantic -Wno-write-strings -fpermissive" }
 
 struct S {
-  int n; 
+  int n;
   char *a[];
 };
 
 void foo (const char *a)
 {
-  const S s = { 1, { a, "b" } };   // { dg-warning "invalid conversion" }
+  const S t
+    = { 1, { a, "b" } };   // { dg-error "initializing flexible array member" }
+  // { dg-warning "invalid conversion" "" { target *-*-* } .-1 }
 }
diff --git a/gcc/testsuite/g++.dg/ext/flexary18.C b/gcc/testsuite/g++.dg/ext/flexary18.C
index 4ab864d..2d1eb95 100644
--- a/gcc/testsuite/g++.dg/ext/flexary18.C
+++ b/gcc/testsuite/g++.dg/ext/flexary18.C
@@ -1,6 +1,6 @@ 
 // PR c++/71912 - [6/7 regression] flexible array in struct in union rejected
 // { dg-do compile }
-// { dg-additional-options "-Wpedantic -Wno-error=pedantic" }
+// { dg-additional-options "-Wpedantic -Wno-error=flexarray" }
 
 #if __cplusplus
 
diff --git a/gcc/testsuite/g++.dg/ext/flexary19.C b/gcc/testsuite/g++.dg/ext/flexary19.C
index 5eaf11b..82c16ad 100644
--- a/gcc/testsuite/g++.dg/ext/flexary19.C
+++ b/gcc/testsuite/g++.dg/ext/flexary19.C
@@ -1,5 +1,5 @@ 
 // { dg-do compile }
-// { dg-additional-options "-Wpedantic -Wno-error=pedantic" }
+// { dg-additional-options "-Wpedantic -Wno-error=pedantic -Wno-error=flexarray" }
 
 // Verify that flexible array members are recognized as either valid
 // or invalid in anonymous structs (a G++ extension) and C++ anonymous
diff --git a/gcc/testsuite/g++.dg/ext/flexary24.C b/gcc/testsuite/g++.dg/ext/flexary24.C
new file mode 100644
index 0000000..acabae2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/flexary24.C
@@ -0,0 +1,82 @@ 
+// PR c++/?????
+// { dg-do compile }
+// { dg-options "-Wflexarray-init" }
+
+struct A { int i, a[]; };
+
+void static_test (void)
+{
+  static A a0;
+  static A a1 = {  };
+  static A a2 = { 0 };
+  static A a3 = { 0, { } };
+
+  static A a4
+    = { 1, { 0 } };    // { dg-warning "initializing flexible array member .A::a' of an object with static storage duration" }
+
+  (void)&a0;
+  (void)&a1;
+  (void)&a2;
+  (void)&a3;
+  (void)&a4;
+}
+
+void auto_test (void)
+{
+  A a0;
+  A a1 = {  };
+  A a2 = { 0 };
+  A a3 = { 0, { } };
+  A a4
+    = { 1, { 0 } };    // { dg-error "initializing flexible array member .A::a' of an object with automatic storage duration" }
+
+  (void)&a0;
+  (void)&a1;
+  (void)&a2;
+  (void)&a3;
+  (void)&a4;
+}
+
+#if __cplusplus > 199711
+
+void thread_test (void)
+{
+  thread_local A a0;
+  thread_local A a1 = {  };
+  thread_local A a2 = { 0 };
+  thread_local A a3 = { 0, { } };
+  thread_local A a4
+    = { 1, { 0 } };    // { dg-warning "initializing flexible array member .A::a' of an object with thread storage duration" "C++ 11 and above" { target { ! c++98_only } } }
+
+  (void)&a0;
+  (void)&a1;
+  (void)&a2;
+  (void)&a3;
+  (void)&a4;
+}
+
+#endif
+
+void compound_literal_test (void)
+{
+  void f (const A&);
+
+  f ((A){ });
+  f ((A){ 0 });
+  f ((A){ 0, { } });
+  f ((A){ 1, { 0 } });    // { dg-error "initializing flexible array member .A::a' of a compound literal" }
+}
+
+#if __cplusplus > 201103
+
+void dynamic_test (void)
+{
+  void f (A*);
+
+  f (new A { });
+  f (new A { 0 });
+  f (new A { 0, { } });
+  f (new A { 1, { 0 } });
+}
+
+#endif
diff --git a/gcc/testsuite/g++.dg/ext/flexary25.C b/gcc/testsuite/g++.dg/ext/flexary25.C
new file mode 100644
index 0000000..08c9ddd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/flexary25.C
@@ -0,0 +1,30 @@ 
+// PR c++/?????
+// { dg-do compile }
+
+struct A { int i, a[]; };  // { dg-error "forbids flexible array member" }
+
+extern A a_extern[];   // { dg-error "invalid use of .struct A. with flexible array member .int A::a []." }
+
+A a_uninit[2];   // { dg-error "invalid use of .struct A. with flexible array member" }
+
+A a_init[2] = { { 0 }, { 0 } };   // { dg-error "invalid use of .struct A. with flexible array member" }
+
+typedef A A2[2];   // { dg-error "invalid use of .struct A. with flexible array member" }
+
+typedef A (*PA2)[2];   // { dg-error "invalid use of .struct A. with flexible array member" }
+
+typedef A (&RA2)[2];      // { dg-error "invalid use of .struct A. with flexible array member" }
+
+typedef A (* const &PRA1)[1];   // { dg-error "invalid use of .struct A. with flexible array member" }
+
+template <class T, class U = T[2]>
+struct S;
+
+S<A> *sa;   // { dg-error "invalid use of .struct A. with flexible array member" }
+// { dg-error "template argument 2 is invalid" "" { target *-*-* } .-1 }
+
+template <class T, class U = T (*)[2]>
+struct S2;
+
+S2<A> *s2a;   // { dg-error "invalid use of .struct A. with flexible array member" }
+// { dg-error "template argument 2 is invalid" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/ext/flexary3.C b/gcc/testsuite/g++.dg/ext/flexary3.C
index c7c0e79..575537f 100644
--- a/gcc/testsuite/g++.dg/ext/flexary3.C
+++ b/gcc/testsuite/g++.dg/ext/flexary3.C
@@ -16,6 +16,7 @@  struct s {
 
 int main()
 {
-    struct s s = { .c = 0 };	// { dg-error "initializer" }
+    struct s s = { .c = 0 };	// { dg-error "designated initializer" }
+    // { dg-error "initializing flexible array member \[^\n\r]+ of an object with automatic storage duration" "" { target *-*-* } .-1 }
     return 0;
 }
diff --git a/gcc/testsuite/g++.dg/ext/flexary7.C b/gcc/testsuite/g++.dg/ext/flexary7.C
index 1b22f21..d476778 100644
--- a/gcc/testsuite/g++.dg/ext/flexary7.C
+++ b/gcc/testsuite/g++.dg/ext/flexary7.C
@@ -8,8 +8,8 @@  struct FlexChar {
     char a[];       // { dg-warning "forbids flexible array member" }
 };
 
-struct FlexChar ac =
-  { 4, { "abc" } }; // { dg-warning "initialization of a flexible array member" }
+struct FlexChar
+ac = { 4, { "abc" } }; // { dg-warning "initializing flexible array member" }
 
 
 #if !__cplusplus
@@ -21,8 +21,8 @@  struct FlexWchar {
     wchar_t a[];    // { dg-warning "forbids flexible array member" }
 };
 
-struct FlexWchar awc =
-  { 3, { L"ab" } }; // { dg-warning "initialization of a flexible array member" }
+struct FlexWchar
+awc = { 3, { L"ab" } }; // { dg-warning "initializing flexible array member" }
 
 
 struct FlexInt {
@@ -33,14 +33,16 @@  struct FlexInt {
 // Verify that no warning is issued for the case when a flexible array
 // member is not initialized (i.e., that a -Wmissing-field-initializer
 // isn't issued) because such arrays need not have any elements.
-struct FlexInt ai0 =
-  { 0 };
+struct FlexInt ai0 = { 0 };
 
-struct FlexInt ai0_ =
-  { 0, { } };      // { dg-warning "initialization of a flexible array member" }
+// Initialization involving other members of a struct containing
+// a flexible array member is silently accepted as long as elements
+// of the flexible array members are not explicitly initialized.
+struct FlexInt
+ai1 = { 0, { } };
 
-struct FlexInt ai2 =
-  { 2, { 1, 2 } }; // { dg-warning "initialization of a flexible array member" }
+struct FlexInt
+ai2 = { 2, { 1, 2 } }; // { dg-warning "initializing flexible array member" }
 
 
 #if __cplusplus
@@ -51,7 +53,7 @@  struct FlexT {
     T a[];          // { dg-warning "forbids flexible array member" }
 };
 
-struct FlexT<char> atc =
-  { 4, { "abc" } }; // { dg-warning "initialization of a flexible array member" }
+struct FlexT<char>
+atc = { 4, { "abc" } }; // { dg-warning "initializing flexible array member" }
 
 #endif
diff --git a/gcc/testsuite/g++.dg/parse/pr43765.C b/gcc/testsuite/g++.dg/parse/pr43765.C
index 800f2c7..fdda7f8 100644
--- a/gcc/testsuite/g++.dg/parse/pr43765.C
+++ b/gcc/testsuite/g++.dg/parse/pr43765.C
@@ -8,10 +8,9 @@  struct SomeType
 };
 const char *temp[] = {"607", "612", 0};
 
-SomeType vals[] =
-    {
-        { 0, values : temp, },
-        0
-    };   // { dg-error "GNU-style designated initializer for an array|cannot convert" }
-// (note the error above is on the wrong line)
- 
+SomeType vals[] =  // { dg-error "invalid use of .struct SomeType. with flexible array member .const char\\* SomeType::values []." }
+  // { dg-error "storage size of .vals. isn't known" "" { target *-*-* } .-1 }
+  {
+    { 0, values : temp, },
+    0
+  };
diff --git a/gcc/testsuite/g++.dg/pr79986.C b/gcc/testsuite/g++.dg/pr79986.C
new file mode 100644
index 0000000..43c8328
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr79986.C
@@ -0,0 +1,10 @@ 
+/* PR c++/79986 - [CHKP] ICE in fold_convert_loc with a flexible array
+   { dg-do compile { target { { i?86-*-* x86_64-*-* } && { ! x32 } } } }
+   { dg-options "-fcheck-pointer-bounds -mmpx" } */
+
+int f (int i)
+{
+  struct A { int n; char a[]; };
+
+  return ((struct A){ 1, "" }).a[i];   // { dg-error "initializing flexible array member .f\\(int\\)::A::a. of a compound literal" }
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wplacement-new-size-1.C b/gcc/testsuite/g++.dg/warn/Wplacement-new-size-1.C
index b549ae1..c9a28d0 100644
--- a/gcc/testsuite/g++.dg/warn/Wplacement-new-size-1.C
+++ b/gcc/testsuite/g++.dg/warn/Wplacement-new-size-1.C
@@ -28,7 +28,7 @@  void fAx (Ax *px, Ax &rx)
 
 void fAx2 ()
 {
-  Ax ax2 = { 1, { 2, 3 } };
+  Ax ax2 = { 1, { 2, 3 } };   // { dg-error "initializing flexible array" }
 
   new (ax2.a) Int16;
   new (ax2.a) Int32;    // { dg-warning "placement" }
@@ -83,6 +83,7 @@  void fBx (BAx *pbx, BAx &rbx)
 void fBx1 ()
 {
   BAx bax1 = { 1, /* Ax = */ { 2, /* a[] = */ { 3 } } };
+  // { dg-error "initializing flexible array" "" { target *-*-* } .-1 }
 
   new (bax1.ax.a) char;
   new (bax1.ax.a) char[2];  // { dg-warning "placement" }
@@ -93,6 +94,7 @@  void fBx1 ()
 void fBx2 ()
 {
   BAx bax2 = { 1, /* Ax = */ { 2, /* a[] = */ { 3, 4 } } };
+  // { dg-error "initializing flexible array" "" { target *-*-* } .-1 }
 
   new (bax2.ax.a) char;
   new (bax2.ax.a) char[2];
@@ -105,6 +107,7 @@  void fBx2 ()
 void fBx3 ()
 {
   BAx bax2 = { 1, /* Ax = */ { 3, /* a[] = */ { 4, 5, 6 } } };
+  // { dg-error "initializing flexible array" "" { target *-*-* } .-1 }
 
   new (bax2.ax.a) char;
   new (bax2.ax.a) char[2];
diff --git a/gcc/testsuite/g++.dg/warn/Wplacement-new-size-2.C b/gcc/testsuite/g++.dg/warn/Wplacement-new-size-2.C
index 23d4324..01ebc78 100644
--- a/gcc/testsuite/g++.dg/warn/Wplacement-new-size-2.C
+++ b/gcc/testsuite/g++.dg/warn/Wplacement-new-size-2.C
@@ -37,6 +37,7 @@  void fAx2 ()
   // well to avoid c++/69696 - incorrect initialization of block-scope
   // flexible array members.
   Ax ax2 = { 1, { 2, 3 } };
+  // { dg-error "initializing flexible array" "" { target *-*-* } .-1 }
 
   new (ax2.a) Int16;
   new (ax2.a) Int16[1];
@@ -141,6 +142,7 @@  void fBx (BAx *pbx, BAx &rbx)
 void fBx1 ()
 {
   BAx bax1 = { 1, /* Ax = */ { 2, /* a[] = */ { 3 } } };
+  // { dg-error "initializing flexible array" "" { target *-*-* } .-1 }
 
   new (bax1.ax.a) char;
   new (bax1.ax.a) char[2];    // { dg-warning "placement" }
@@ -151,6 +153,7 @@  void fBx1 ()
 void fBx2 ()
 {
   BAx bax2 = { 1, /* Ax = */ { 2, /* a[] = */ { 3, 4 } } };
+  // { dg-error "initializing flexible array" "" { target *-*-* } .-1 }
 
   new (bax2.ax.a) char;
   new (bax2.ax.a) char[2];
@@ -163,6 +166,7 @@  void fBx2 ()
 void fBx3 ()
 {
   BAx bax2 = { 1, /* Ax = */ { 3, /* a[] = */ { 4, 5, 6 } } };
+  // { dg-error "initializing flexible array" "" { target *-*-* } .-1 }
 
   new (bax2.ax.a) char;
   new (bax2.ax.a) char[2];
diff --git a/libstdc++-v3/testsuite/20_util/is_copy_constructible/value.s b/libstdc++-v3/testsuite/20_util/is_copy_constructible/value.s
new file mode 100644
index 0000000..7b7ec20
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_copy_constructible/value.s
@@ -0,0 +1 @@ 
+	.file	"value.cc"