diff mbox

Ping [PATCH] c++/42121 - diagnose invalid flexible array members

Message ID 566119C6.8020201@gmail.com
State New
Headers show

Commit Message

Martin Sebor Dec. 4, 2015, 4:42 a.m. UTC
[CC Jason for the C++ changes and Joseph for the one C change.]

Attached is a reworked and expanded patch for the bug plus three
others in the same area that I uncovered while developing and
testing the former patch:

c++/68689 - flexible array members in unions accepted in C++
c++/68478 - flexible array members have complete type
c++/68613 - initializer-string for array of chars is too long error
             on flexible array member

The patch should bring C++ support for flexible array members closer
to C (most of the same constructs should be accepted and rejected).
The only C change in this patch is to include the size of excessively
large types in diagnostics (I found knowing the size helpful when
adding tests and I think it might be helpful to others as well).

Unlike in my first attempt, this patch distinguishes flexible array
members from zero-length arrays by setting the upper bound of the
former to null.  This seems to be in line with what the C front end
does but has required bigger changes than I had hoped.  Hopefully,
the result is a more consistent treatment of the extension between
the two front ends (for example, both C and C++ now emit the same
ADA specification for flexible array members).

Tested by bootstrapping and running C and C++ tests (including
libstdc++) on x86_64.

I'm not sure if this is appropriate for this stage or if it needs
to wait until after the release.  Either is fine with me.

Martin

On 11/21/2015 03:17 PM, Martin Sebor wrote:
> Bug 42121 - g++ should warn or error on internal 0 size array in
> struct, is a request to diagnose declarations of flexible array
> members that aren't last in the enclosing struct, such as in the
> following:
>
>      struct S
>      {
>          int a;
>          char b[];   // invalid
>          int c;
>      };
>
> The C front end diagnoses such cases because they are invalid in
> standard C.  Comment 8 on the bug points out that flexible array
> members should not be treated identically to zero-size arrays
> (they're not in C).
>
> The attached patch implements the requested diagnostic, keeping
> comment 8 in mind.  It also issues a diagnostic for flexible array
> members in unions (which are also diagnosed as invalid in C mode).
> The patch found a number of instances of invalid flexible array
> members in the C++ test suites.  I corrected them.
>
> Since the C++ front end doesn't distinguish between flexible array
> members and zero-size arrays (both are considered to have an upper
> bound of SIZE_MAX), and since determining whether or not
> a declaration of such a member is valid cannot be done until
> the whole containing struct has been processed, the patch makes
> use one of the DECL_LANG_FLAGs to temporarily remember which is
> which (I somewhat arbitrarily picked DECL_LANG_FLAG_1), before
> clearing it. There might be a better flag to use, and it might
> be appropriate to define a descriptive macro for this purpose
> in cp-tree.h, along the same lines as the macros already defined
> for other such purposes.
>
> Martin

Comments

Bernd Schmidt Dec. 4, 2015, 11:33 a.m. UTC | #1
> The patch should bring C++ support for flexible array members closer
 > to C (most of the same constructs should be accepted and rejected).
 > The only C change in this patch is to include the size of excessively
 > large types in diagnostics (I found knowing the size helpful when
 > adding tests and I think it might be helpful to others as well).

Can't really comment on the C++ parts, but I spotted some formatting issues.

> +      && TREE_CODE (type) != ERROR_MARK
> +      && (DECL_NAME (fld) || RECORD_OR_UNION_TYPE_P (type)))
> +    {
> +
> +      return TYPE_SIZE (type)
> +	&& (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST
> +	    || !tree_int_cst_equal (size_zero_node, TYPE_SIZE (type)));

Unnecessary blank line. Multi-line expressions should be wrapped in 
parentheses for indentation. Lose braces around single statements.


> +   a flexible array member or a zero-size array.
> +*/

Comment terminators go at the end of the line.

> +  tree size_max_node =
> +    int_const_binop (MINUS_EXPR, size_zero_node, size_one_node);

The = operator should start the line.

> +	  tree flexarray =
> +	    check_flexarrays (t, TYPE_FIELDS (fldtype), seen_field);

Here too.

> +  {
> +    bool dummy = false;
> +    check_flexarrays (t, TYPE_FIELDS (t), &dummy);
> +  }

No reason to wrap this in braces.

>
> +  if (NULL_TREE == size)
> +    return build_index_type (NULL_TREE);

Don't know whether the conventions in cp/ are different, but usually 
this is "size == NULL_TREE".

> +	    pedwarn (input_location, OPT_Wpedantic,
> +		     "ISO C++ forbids zero-size arrays");
>  	}
> +
>      }

Extra blank line.

> @@ -11082,6 +11094,10 @@ grokdeclarator (const cp_declarator *declarator,
>  		     || !COMPLETE_TYPE_P (TREE_TYPE (type))
>  		     || initialized == 0))
>  	  {
> +	    if (TREE_CODE (type) != ARRAY_TYPE
> +		|| !COMPLETE_TYPE_P (TREE_TYPE (type)))
> +	      {
> +
>  		if (unqualified_id)

Here too.


Bernd
Joseph Myers Dec. 4, 2015, 4:15 p.m. UTC | #2
On Thu, 3 Dec 2015, Martin Sebor wrote:

> The only C change in this patch is to include the size of excessively
> large types in diagnostics (I found knowing the size helpful when
> adding tests and I think it might be helpful to others as well).

I don't see what that C change has to do with flexible array members.  
Could you post it separately with its own testcases, or explain why the C 
and C++ parts depend on each other?
Jason Merrill Dec. 4, 2015, 5:51 p.m. UTC | #3
On 12/03/2015 11:42 PM, Martin Sebor wrote:
> +	  if (next && TREE_CODE (next) == FIELD_DECL)

This will break if there's a non-field between the array and the next field.

> @@ -4114,7 +4115,10 @@ walk_subobject_offsets (tree type,
>
>        /* Avoid recursing into objects that are not interesting.  */
>        if (!CLASS_TYPE_P (element_type)
> -	  || !CLASSTYPE_CONTAINS_EMPTY_CLASS_P (element_type))
> +	  || !CLASSTYPE_CONTAINS_EMPTY_CLASS_P (element_type)
> +	  || !domain
> +	  /* Flexible array members have no upper bound.  */
> +	  || !TYPE_MAX_VALUE (domain))

Why is this desirable?  We do want to avoid empty bases at the same 
address as a flexible array of the same type.

> +	&& (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST
> +	    || !tree_int_cst_equal (size_zero_node, TYPE_SIZE (type)));

This can be integer_zerop.

> +       *seen_field = *seen_field || field_nonempty_p (f), fld = next)

Please add parens around the || expression.

> +	  && !tree_int_cst_equal (size_max_node, TYPE_MAX_VALUE (dom)))

This can be integer_minus_onep or integer_all_onesp.

> +	     its fields.  The recursive call to the function will
> +	     either return 0 or the flexible array member whose

Let's say NULL_TREE here rather than 0.

> +  {
> +    bool dummy = false;
> +    check_flexarrays (t, TYPE_FIELDS (t), &dummy);
> +  }

This should be called from check_bases_and_members, or even integrated 
into check_field_decls.

> -	  else if (name)
> -	    pedwarn (input_location, OPT_Wpedantic, "ISO C++ forbids zero-size array %qD", name);

Why?

> @@ -10912,11 +10916,19 @@ grokdeclarator (const cp_declarator *declarator,
>  	if (!staticp && TREE_CODE (type) == ARRAY_TYPE
>  	    && TYPE_DOMAIN (type) == NULL_TREE)
>  	  {
> -	    tree itype = compute_array_index_type (dname, integer_zero_node,
> +	    if (TREE_CODE (ctype) == UNION_TYPE
> +		|| TREE_CODE (ctype) == QUAL_UNION_TYPE)
> +	      {
> +		error ("flexible array member in union");
> +		type = error_mark_node;
> +	      }
> +	    else
> +	      {
> +		tree itype = compute_array_index_type (dname, NULL_TREE,
>  						       tf_warning_or_error);
>  		type = build_cplus_array_type (TREE_TYPE (type), itype);
>  	      }

Can we leave TYPE_DOMAIN null for flexible arrays so you don't need to 
add special new handling all over the place?

> -    tree decl;
> +    tree decl = NULL_TREE;

Why?

> +++ b/gcc/testsuite/g++.dg/cpp0x/bad_array_new2.C
> @@ -1,7 +1,16 @@
>  // Test for throwing bad_array_new_length on invalid array length
>  // { dg-do run { target c++11 } }
>
> -#include <new>
> +// #include <new>
> +
> +namespace std {
> +struct exception {
> +    virtual ~exception () { }
> +};
> +
> +struct bad_alloc: exception { };
> +struct bad_array_new_length { };
> +}

Why?

Jason
diff mbox

Patch

gcc/testsuite/ChangeLog:
2015-12-02  Martin Sebor  <msebor@redhat.com>

	c++/42121
	c++/68478
	c++/68613
	c++/68689
	* g++.dg/ext/flexary2.C: Expect a sole flexible array member
	to be rejected.  Add a test case exercising zero-length array.
	* g++.dg/ext/flexary3.C: Expect a sole flexible array member
	to be rejected.
	* g++.dg/ext/flexary4.C: New file.
	* g++.dg/ext/flexary5.C: New file.
	* g++.dg/ext/flexary6.C: New file.
	* g++.dg/ext/flexary7.C: New file.
	* g++.dg/other/dump-ada-spec-2.C: Adjust to reflect flexible
	array members.
	* g++.dg/parse/pr43765.C: Add a member to make a struct with
	a flexible array member valid.  Adjust expected error message.
	* g++.dg/torture/pr64280.C: Expect a sole flexible array member
	to be rejected.
	* g++.dg/torture/pr64312.C: Add a member to make a struct with
	a flexible array member valid.
	* g++.dg/ubsan/object-size-1.C: Adjust expected diagnostic.
	* g++.dg/other/dump-ada-spec-2.C: Adjust expected type.

gcc/cp/ChangeLog:
2015-12-02  Martin Sebor  <msebor@redhat.com>

	c++/42121
	c++/68478
	c++/68613
	c++/68689
	* class.c (walk_subobject_offsets): Avoid assuming type domain
	is non-null or has an upper bound.
	(layout_class_type): Include type size in error message.
	(all_bases_empty_p, field_nonempty_p): New helper functions.
	(check_flexarrays): New function.
	(finish_struct_1): Call check_flexarrays.
	* decl.c (compute_array_index_type): Distinguish flexible array
	members from zero-length arrays.
	(grokdeclarator): Reject flexible array members in unions.  Avoid
	rejecting members of incomplete types that are flexible array members.
	* error.c (dump_type_suffix): Handle flexible array members with null
	upper bound.
	* init.c (perform_member_init): Same.
	* pt.c (instantiate_class_template_1): Allow flexible array members.
	(tsubst): Handle flexible array members with null upper bound.
	* typeck2.c (digest_init_r): Warn for initialization of flexible
	array members.
	(process_init_constructor_record): Handle flexible array members.

gcc/c/ChangeLog:
2015-12-02  Martin Sebor  <msebor@redhat.com>

	c++/42121
	 * c-decl.c (grokdeclarator): Include type size in error message.
	(finish_struct): Same.

gcc/ChangeLog:
2015-12-02  Martin Sebor  <msebor@redhat.com>

	c++/42121
	* tree-chkp.c (chkp_find_bound_slots_1): Handle flexible array
	members.
	* tree.c (type_contains_placeholder_1): Avoid assuming type has
	a non-null domain or an upper bound to handle flexible array
	members.
	* varasm.c (array_size_for_constructor): Same.
	(output_constructor_regular_field):  Same.
	(output_constructor): Set min_index to integer_zero_node rather
	than null when a type has no domain to avoid crashing later.

diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 7b9ab8a..e55471f 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -5868,10 +5868,12 @@  grokdeclarator (const struct c_declarator *declarator,
 			&& !int_fits_type_p (size, index_type))
 		      {
 			if (name)
-			  error_at (loc, "size of array %qE is too large",
-			            name);
+			  error_at (loc, "size of array %qE is too large "
+				    "(%qE bytes)",
+			            name, size);
 			else
-			  error_at (loc, "size of unnamed array is too large");
+			  error_at (loc, "size of unnamed array is too large"
+				    " (%qE bytes)", size);
 			type = error_mark_node;
 			continue;
 		      }
@@ -7701,7 +7703,7 @@  finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
       && TREE_CODE (TYPE_SIZE_UNIT (t)) == INTEGER_CST
       && !TREE_OVERFLOW (TYPE_SIZE_UNIT (t))
       && !valid_constant_size_p (TYPE_SIZE_UNIT (t)))
-    error ("type %qT is too large", t);
+    error ("size of type %qT is too large (%qE bytes)", t, TYPE_SIZE_UNIT (t));
 
   /* Give bit-fields their proper types and rewrite the type of array fields
      with scalar component if the enclosing type has reverse storage order.  */
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 216a301..e0c6758 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -35,6 +35,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "convert.h"
 #include "dumpfile.h"
 #include "gimplify.h"
+#include "intl.h"
 
 /* The number of nested classes being processed.  If we are not in the
    scope of any class, this is zero.  */
@@ -4114,7 +4115,10 @@  walk_subobject_offsets (tree type,
 
       /* Avoid recursing into objects that are not interesting.  */
       if (!CLASS_TYPE_P (element_type)
-	  || !CLASSTYPE_CONTAINS_EMPTY_CLASS_P (element_type))
+	  || !CLASSTYPE_CONTAINS_EMPTY_CLASS_P (element_type)
+	  || !domain
+	  /* Flexible array members have no upper bound.  */
+	  || !TYPE_MAX_VALUE (domain))
 	return 0;
 
       /* Step through each of the elements in the array.  */
@@ -6531,7 +6535,7 @@  layout_class_type (tree t, tree *virtuals_p)
       && TREE_CODE (TYPE_SIZE_UNIT (t)) == INTEGER_CST
       && !TREE_OVERFLOW (TYPE_SIZE_UNIT (t))
       && !valid_constant_size_p (TYPE_SIZE_UNIT (t)))
-    error ("type %qT is too large", t);
+    error ("size of type %qT is too large (%qE bytes)", t, TYPE_SIZE_UNIT (t));
 
   /* Warn about bases that can't be talked about due to ambiguity.  */
   warn_about_ambiguous_bases (t);
@@ -6598,12 +6602,184 @@  sorted_fields_type_new (int n)
 }
 
 
+/* Return true when all base classes of class T (a class type) are
+   empty, false otherwise.  */
+
+static bool
+all_bases_empty_p (tree t)
+{
+  int i;
+  tree binfo;
+  tree base_binfo;
+
+  for (binfo = TYPE_BINFO (t), i = 0;
+       BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+    {
+      tree basetype = TREE_TYPE (base_binfo);
+      gcc_assert (COMPLETE_TYPE_P (basetype));
+
+      if (!is_empty_class (basetype))
+	return false;
+    }
+
+  return true;
+}
+
+/* Helper of finish_struct_1.  Return true when FLD refers to a non-static
+   class data member of non-zero size, otherwise false.  */
+
+static inline bool
+field_nonempty_p (const_tree fld)
+{
+  if (TREE_CODE (fld) == ERROR_MARK)
+    return false;
+
+  tree type = TREE_TYPE (fld);
+  if (TREE_CODE (fld) == FIELD_DECL
+      && TREE_CODE (type) != ERROR_MARK
+      && (DECL_NAME (fld) || RECORD_OR_UNION_TYPE_P (type)))
+    {
+
+      return TYPE_SIZE (type)
+	&& (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST
+	    || !tree_int_cst_equal (size_zero_node, TYPE_SIZE (type)));
+    }
+
+  return false;
+}
+
+/* Check to make sure any definitions of flexible array members
+   and zero-size arrays in a chain of FIELDS are valid, and
+   diagnose those that aren't.  T denotes a struct, class, or
+   union whose fields are being checked.  SEEN_FIELD is used
+   internally by recursive invocations of the function to set
+   the pointed-to object to true when a declaration of a non-
+   empty non-static data member precedes the declaration of
+   a flexible array member or a zero-size array.
+*/
+
+static tree
+check_flexarrays (tree t, tree fields, bool *seen_field)
+{
+  /* Members of anonymous structs and unions are considered to be members
+     of the containing struct or union.  */
+  if (TYPE_ANONYMOUS_P (t))
+    return NULL_TREE;
+
+  /* Unlike the C front end, the C++ front end sets the upper bound
+     of a flexible array member to SIZE_MAX.  Precompute that value
+     up front to avoid recomputing it on each iteration.  */
+  tree size_max_node =
+    int_const_binop (MINUS_EXPR, size_zero_node, size_one_node);
+
+  /* Iterate over struct members, looking for definitions of non-static
+     flexible array members and zero-size arrays and determine whether
+     each is valid.  */
+  for (tree fld = fields, next, f; fld;
+       *seen_field = *seen_field || field_nonempty_p (f), fld = next)
+    {
+      next = DECL_CHAIN (fld);
+
+      /* Use f below to check the current field, or to substitute
+	 for it the flexible array member or zero-size array of
+	 the anonymous struct it represents.  */
+      f = fld;
+
+      const_tree fldtype = TREE_TYPE (f);
+      if (TREE_CODE (f) != TYPE_DECL
+	  && RECORD_OR_UNION_TYPE_P (fldtype)
+	  && TYPE_ANONYMOUS_P (fldtype))
+	{
+	  /* Descend into the anonymous struct or union and check
+	     its fields.  The recursive call to the function will
+	     either return 0 or the flexible array member whose
+	     validity depends on whether any non-static data members
+	     are declared in the enclosing struct.  */
+	  tree flexarray =
+	    check_flexarrays (t, TYPE_FIELDS (fldtype), seen_field);
+	  if (flexarray)
+	    {
+	      f = flexarray;
+	      fldtype = TREE_TYPE (flexarray);
+	    }
+	}
+
+      /* Skip anything that's not a (non-static) data member.  */
+      if (TREE_CODE (f) != FIELD_DECL)
+	continue;
+
+      /* Skip non-arrays.  */
+      if (TREE_CODE (fldtype) != ARRAY_TYPE || !DECL_CHAIN (f))
+	continue;
+
+      /* Determine the upper bound of the array if it has one.  */
+      const_tree dom = TYPE_DOMAIN (fldtype);
+
+      /* Skip arrays whose upper bound is less than SIZE_MAX.  */
+      if (dom && TYPE_MAX_VALUE (dom)
+	  && !tree_int_cst_equal (size_max_node, TYPE_MAX_VALUE (dom)))
+	continue;
+
+      if (dom && TYPE_MAX_VALUE (dom))
+	{
+	  /* Zero-length arrays have a domain with an upper bound
+	     of SIZE_MAX.  */
+	  const char *msg = 0;
+
+	  if (next && TREE_CODE (next) == FIELD_DECL)
+	    msg = G_("zero-size array member %qD not at end of %q#T");
+	  else if (!*seen_field && all_bases_empty_p (t))
+	    msg = G_("zero-size array member %qD in an otherwise empty %q#T");
+
+	  if (msg && pedwarn (DECL_SOURCE_LOCATION (f), OPT_Wpedantic,
+			      msg, f, t))
+	    inform (input_location, "%q#T declared here",
+		    DECL_FIELD_CONTEXT (f));
+	}
+      else
+	{
+	  /* Flexible array members don't have an upper bound.  */
+	  const char *msg = 0;
+
+	  if (next && TREE_CODE (next) == FIELD_DECL)
+	    msg = G_("flexible array member %qD not at end of %q#T");
+	  else if (!*seen_field && all_bases_empty_p (t))
+	    {
+	      /* When f is a member of anonymous struct, return
+		 the (possibly invalid) flexible array member to
+		 the (recursive) caller to determine whether it
+		 is followed by any other data members in the
+		 containing struct.  */
+	      if (DECL_CONTEXT (fld) != t)
+		return f;
+
+	      msg = G_("flexible array member %qD in an otherwise empty %q#T");
+	    }
+
+	  if (msg)
+	    {
+	      error_at (DECL_SOURCE_LOCATION (f), msg, f, t);
+	      inform (input_location, "%q#T declared here",
+		      DECL_FIELD_CONTEXT (f));
+	    }
+	}
+    }
+
+  return NULL_TREE;
+}
+
 /* Perform processing required when the definition of T (a class type)
-   is complete.  */
+   is complete.  Diagnose invalid definitions of flexible array members
+   and zero-size arrays.  */
 
 void
 finish_struct_1 (tree t)
 {
+  {
+    bool dummy = false;
+    check_flexarrays (t, TYPE_FIELDS (t), &dummy);
+  }
+
   tree x;
   /* A TREE_LIST.  The TREE_VALUE of each node is a FUNCTION_DECL.  */
   tree virtuals = NULL_TREE;
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 675342e..79c6299 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -8610,8 +8610,9 @@  fold_sizeof_expr (tree t)
 }
 
 /* Given the SIZE (i.e., number of elements) in an array, compute an
-   appropriate index type for the array.  If non-NULL, NAME is the
-   name of the thing being declared.  */
+   appropriate index type for the array.  When SIZE is null, the array
+   is a flexible array member.  If non-NULL, NAME is the name of
+   the entity being declared.  */
 
 tree
 compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
@@ -8619,6 +8620,9 @@  compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
   tree itype;
   tree osize = size;
 
+  if (NULL_TREE == size)
+    return build_index_type (NULL_TREE);
+
   if (error_operand_p (size))
     return error_mark_node;
 
@@ -8739,11 +8743,11 @@  compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
 	    return error_mark_node;
 	  else if (in_system_header_at (input_location))
 	    /* Allow them in system headers because glibc uses them.  */;
-	  else if (name)
-	    pedwarn (input_location, OPT_Wpedantic, "ISO C++ forbids zero-size array %qD", name);
 	  else
-	    pedwarn (input_location, OPT_Wpedantic, "ISO C++ forbids zero-size array");
+	    pedwarn (input_location, OPT_Wpedantic,
+		     "ISO C++ forbids zero-size arrays");
 	}
+
     }
   else if (TREE_CONSTANT (size)
 	   /* We don't allow VLAs at non-function scopes, or during
@@ -10888,7 +10892,7 @@  grokdeclarator (const cp_declarator *declarator,
     }
 
   {
-    tree decl;
+    tree decl = NULL_TREE;
 
     if (decl_context == PARM)
       {
@@ -10912,11 +10916,19 @@  grokdeclarator (const cp_declarator *declarator,
 	if (!staticp && TREE_CODE (type) == ARRAY_TYPE
 	    && TYPE_DOMAIN (type) == NULL_TREE)
 	  {
-	    tree itype = compute_array_index_type (dname, integer_zero_node,
+	    if (TREE_CODE (ctype) == UNION_TYPE
+		|| TREE_CODE (ctype) == QUAL_UNION_TYPE)
+	      {
+		error ("flexible array member in union");
+		type = error_mark_node;
+	      }
+	    else
+	      {
+		tree itype = compute_array_index_type (dname, NULL_TREE,
 						       tf_warning_or_error);
 		type = build_cplus_array_type (TREE_TYPE (type), itype);
 	      }
-
+	  }
 	if (type == error_mark_node)
 	  {
 	    /* Happens when declaring arrays of sizes which
@@ -11082,6 +11094,10 @@  grokdeclarator (const cp_declarator *declarator,
 		     || !COMPLETE_TYPE_P (TREE_TYPE (type))
 		     || initialized == 0))
 	  {
+	    if (TREE_CODE (type) != ARRAY_TYPE
+		|| !COMPLETE_TYPE_P (TREE_TYPE (type)))
+	      {
+
 		if (unqualified_id)
 		  {
 		    error ("field %qD has incomplete type %qT",
@@ -11094,6 +11110,7 @@  grokdeclarator (const cp_declarator *declarator,
 		type = error_mark_node;
 		decl = NULL_TREE;
 	      }
+	  }
 	else
 	  {
 	    if (friendp)
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 38548c7..56ce14b 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -875,7 +875,7 @@  dump_type_suffix (cxx_pretty_printer *pp, tree t, int flags)
     case ARRAY_TYPE:
       pp_maybe_space (pp);
       pp_cxx_left_bracket (pp);
-      if (TYPE_DOMAIN (t))
+      if (TYPE_DOMAIN (t) && TYPE_MAX_VALUE (TYPE_DOMAIN (t)))
 	{
 	  tree dtype = TYPE_DOMAIN (t);
 	  tree max = TYPE_MAX_VALUE (dtype);
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index fccd289..6b93504 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -729,10 +729,15 @@  perform_member_init (tree member, tree init)
 	      || same_type_ignoring_top_level_qualifiers_p (type,
 							    TREE_TYPE (init)))
 	    {
+	      if (TYPE_DOMAIN (type) && TYPE_MAX_VALUE (TYPE_DOMAIN (type)))
+		{
+		  /* Initialize the array only if it's not a flexible
+		     array member (i.e., if it has an upper bound).  */
 		  init = build_vec_init_expr (type, init, tf_warning_or_error);
 		  init = build2 (INIT_EXPR, type, decl, init);
 		  finish_expr_stmt (init);
 		}
+	    }
 	  else
 	    error ("invalid initializer for array member %q#D", member);
 	}
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 2904657..2bfaaee 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -10005,7 +10005,16 @@  instantiate_class_template_1 (tree type)
 			  if (can_complete_type_without_circularity (rtype))
 			    complete_type (rtype);
 
-			  if (!COMPLETE_TYPE_P (rtype))
+                          if (TREE_CODE (r) == FIELD_DECL
+                              && TREE_CODE (rtype) == ARRAY_TYPE
+                              && COMPLETE_TYPE_P (TREE_TYPE (rtype))
+                              && !COMPLETE_TYPE_P (rtype))
+                            {
+                              /* Flexible array mmembers of elements
+                                 of complete type have an incomplete type
+                                 and that's okay.  */
+                            }
+                          else if (!COMPLETE_TYPE_P (rtype))
 			    {
 			      cxx_incomplete_type_error (r, rtype);
 			      TREE_TYPE (r) = error_mark_node;
@@ -12730,9 +12739,14 @@  tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       if (t == integer_type_node)
 	return t;
 
-      if (TREE_CODE (TYPE_MIN_VALUE (t)) == INTEGER_CST
-	  && TREE_CODE (TYPE_MAX_VALUE (t)) == INTEGER_CST)
+      if (TREE_CODE (TYPE_MIN_VALUE (t)) == INTEGER_CST)
+        {
+          if (!TYPE_MAX_VALUE (t))
+            return compute_array_index_type (NULL_TREE, NULL_TREE, complain);
+          
+          if (TREE_CODE (TYPE_MAX_VALUE (t)) == INTEGER_CST)
             return t;
+        }
 
       {
 	tree max, omax = TREE_OPERAND (TYPE_MAX_VALUE (t), 0);
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 839091c..68d2e71 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -1013,6 +1013,14 @@  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) || !TYPE_MAX_VALUE (TYPE_DOMAIN (type))))
+	{
+	  /* Flexible array members do not have an upper bound.  */
+	  pedwarn (EXPR_LOC_OR_LOC (init, input_location), OPT_Wpedantic,
+		   "initialization of a flexible array member");
+	}
+      
       tree typ1 = TYPE_MAIN_VARIANT (TREE_TYPE (type));
       if (char_type_p (typ1)
 	  /*&& init */
@@ -1051,8 +1059,11 @@  digest_init_r (tree type, tree init, bool nested, int flags,
 	      init = copy_node (init);
 	      TREE_TYPE (init) = type;
 	    }
-	  if (TYPE_DOMAIN (type) != 0 && TREE_CONSTANT (TYPE_SIZE (type)))
+	  if (TYPE_DOMAIN (type)
+	      && TYPE_MAX_VALUE (TYPE_DOMAIN (type))
+	      && TREE_CONSTANT (TYPE_SIZE (type)))
 	    {
+	      /* Not a flexible array member.  */
 	      int size = TREE_INT_CST_LOW (TYPE_SIZE (type));
 	      size = (size + BITS_PER_UNIT - 1) / BITS_PER_UNIT;
 	      /* In C it is ok to subtract 1 from the length of the string
@@ -1240,8 +1251,10 @@  process_init_constructor_array (tree type, tree init,
   if (TREE_CODE (type) == ARRAY_TYPE)
     {
       tree domain = TYPE_DOMAIN (type);
-      if (domain && TREE_CONSTANT (TYPE_MAX_VALUE (domain)))
-	len = wi::ext (wi::to_offset (TYPE_MAX_VALUE (domain))
+      /* Flexible array members have no upper bound.  */
+      tree maxval = domain ? TYPE_MAX_VALUE (domain) : NULL_TREE;
+      if (domain && maxval && TREE_CONSTANT (maxval))
+	len = wi::ext (wi::to_offset (maxval)
 		       - wi::to_offset (TYPE_MIN_VALUE (domain)) + 1,
 		       TYPE_PRECISION (TREE_TYPE (domain)),
 		       TYPE_SIGN (TREE_TYPE (domain))).to_uhwi ();
@@ -1417,14 +1430,15 @@  process_init_constructor_record (tree type, tree init,
 	}
       else
 	{
-	  if (TREE_CODE (TREE_TYPE (field)) == REFERENCE_TYPE)
+	  const_tree fldtype = TREE_TYPE (field);
+	  if (TREE_CODE (fldtype) == REFERENCE_TYPE)
 	    {
 	      if (complain & tf_error)
 		error ("member %qD is uninitialized reference", field);
 	      else
 		return PICFLAG_ERRONEOUS;
 	    }
-	  else if (CLASSTYPE_REF_FIELDS_NEED_INIT (TREE_TYPE (field)))
+	  else if (CLASSTYPE_REF_FIELDS_NEED_INIT (fldtype))
 	    {
 	      if (complain & tf_error)
 		error ("member %qD with uninitialized reference fields", field);
@@ -1433,13 +1447,17 @@  process_init_constructor_record (tree type, tree init,
 	    }
 
 	  /* Warn when some struct elements are implicitly initialized
-	     to zero.  */
-	  if ((complain & tf_warning)
+	     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)
+		   && TYPE_MAX_VALUE (TYPE_DOMAIN (fldtype))))
+	      && (complain & tf_warning)
 	      && !EMPTY_CONSTRUCTOR_P (init))
 	    warning (OPT_Wmissing_field_initializers,
 		     "missing initializer for member %qD", field);
 
-	  if (!zero_init_p (TREE_TYPE (field))
+	  if (!zero_init_p (fldtype)
 	      || skipped < 0)
 	    next = build_zero_init (TREE_TYPE (field), /*nelts=*/NULL_TREE,
 				    /*static_storage_p=*/false);
diff --git a/gcc/testsuite/g++.dg/cpp0x/bad_array_new2.C b/gcc/testsuite/g++.dg/cpp0x/bad_array_new2.C
index bcc9b9a..d56410b 100644
--- a/gcc/testsuite/g++.dg/cpp0x/bad_array_new2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/bad_array_new2.C
@@ -1,7 +1,16 @@ 
 // Test for throwing bad_array_new_length on invalid array length
 // { dg-do run { target c++11 } }
 
-#include <new>
+// #include <new>
+
+namespace std {
+struct exception {
+    virtual ~exception () { }
+};
+
+struct bad_alloc: exception { };
+struct bad_array_new_length { };
+}
 
 void * f(int i)
 {
diff --git a/gcc/testsuite/g++.dg/ext/flexary2.C b/gcc/testsuite/g++.dg/ext/flexary2.C
index 4855b3f..dcd1bde 100644
--- a/gcc/testsuite/g++.dg/ext/flexary2.C
+++ b/gcc/testsuite/g++.dg/ext/flexary2.C
@@ -1,4 +1,10 @@ 
-// PR c++/46688
+// PR c++/46688 - [4.6 Regression] g++ requires a function declaration
+// when it should not
+// Note that although the definition of struct B in the test case for
+// c++/46688 was thought to be valid, it is, in fact, invalid, in C and
+// as noted in c++/42121, should be treated as invalid in C++ as well.
+// The test verifies that gcc detects and reports the right error.
+
 // { dg-options "" }
 
 struct A {
@@ -7,5 +13,10 @@  struct A {
 
 struct B {
     B() {}
-   A a[];
+    A a[];   // { dg-error "extension|flexible array .* in an otherwise empty" }
+};
+
+struct C {
+    C() {}
+    A a[0];  // -Wpedantic warning: ISO C++ forbids zero-size arrays
 };
diff --git a/gcc/testsuite/g++.dg/ext/flexary3.C b/gcc/testsuite/g++.dg/ext/flexary3.C
index 906877b..c7c0e79 100644
--- a/gcc/testsuite/g++.dg/ext/flexary3.C
+++ b/gcc/testsuite/g++.dg/ext/flexary3.C
@@ -1,7 +1,18 @@ 
-// PR c++/54441
+// PR c++/54441 - [4.7/4.8 Regression] Infinite loop with brace initializer
+//                on zero-length array
+// Note that although the definition of struct s in the test case for
+// c++/54441 was accepted as valid, it is, in fact, invalid in C, and
+// as noted in c++/42121, should be treated as invalid in C++ as well.
+// The test verifies that gcc detects, reports, and handles both errors
+// gracefully.
+// Note also that the error(s) issued for the invalid initializer depend
+// on c++/55606.
+
 // { dg-options "" }
 
-struct s { char c[]; };
+struct s {
+    char c[];   // { dg-error "flexible array member .* in an otherwise empty" }
+};
 
 int main()
 {
diff --git a/gcc/testsuite/g++.dg/ext/flexary4.C b/gcc/testsuite/g++.dg/ext/flexary4.C
new file mode 100644
index 0000000..fefce47
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/flexary4.C
@@ -0,0 +1,328 @@ 
+// PR c++/42121 - g++ should warn or error on internal 0 size array in struct
+// { dg-do compile }
+// { dg-options "-Wno-error=pedantic" }
+
+// Flexible array members are a feature of C99 (and newer) not provided
+// by C++ 2014 and prior.  G++ supports both the C99/C11 kind of flexible
+// array members and pre-C99 zero-size arrays (defining an array of size
+// zero).  Since both features are provided for compatibility with C,
+// G++ allows them in the same contexts as in C.
+
+struct Sx {
+    int a[];                  // { dg-error "flexible array member" }
+};
+
+// Verify that non-data members or static data members don't suppress
+// the diagnostic.
+struct Sx2 {
+    int a[];                  // { dg-error "flexible array member" }
+    typedef int I;
+};
+
+struct Sx3 {
+    typedef int I;
+    int a[];                  // { dg-error "flexible array member" }
+};
+
+struct Sx4 {
+    int a[];                  // { dg-error "flexible array member" }
+    enum E { e };
+};
+
+struct Sx5 {
+    enum E { e };
+    int a[];                  // { dg-error "flexible array member" }
+};
+
+struct Sx6 {
+    int a[];                  // { dg-error "flexible array member" }
+    static int i;
+};
+
+int Sx6::i;
+
+struct Sx7 {
+    static int i;
+    int a[];                  // { dg-error "flexible array member" }
+};
+
+int Sx7::i;
+
+struct Sx8 {
+    int a[];                  // { dg-error "flexible array member" }
+    Sx8 () { }
+};
+
+struct Sx9 {
+    Sx9 () { }
+    int a[];                  // { dg-error "flexible array member" }
+};
+
+struct Sx10 {
+    int a[];                  // { dg-error "flexible array member" }
+    virtual ~Sx10 () { }
+};
+
+struct Sx11 {
+    virtual ~Sx11 () { }
+    int a[];                  // { dg-error "flexible array member" }
+};
+
+struct Sx12 {
+    int a[];                  // { dg-error "flexible array member" }
+    virtual void foo () = 0;
+};
+
+struct Sx13 {
+    virtual void foo () = 0;
+    int a[];                  // { dg-error "flexible array member" }
+};
+
+struct Sx14 {
+    int a[][1];               // { dg-error "flexible array member" }
+};
+
+struct Sx15 {
+    typedef int A[];
+    A a;                      // { dg-error "flexible array member" }
+};
+
+// Verify also that a zero-size array doesn't suppress the diagnostic.
+struct Sx16 {
+    // a_0 below is diagnosed with -Wpedantic only and emits
+    // warning: ISO C++ forbids zero-size arrays
+    int a_0 [0];
+    int a_x [];               // { dg-error "flexible array member" }
+};
+
+struct Sx17 {
+    int a_x [];               // { dg-error "flexible array member" }
+
+    // a_0 below is diagnosed with -Wpedantic only and emits
+    // warning: ISO C++ forbids zero-size arrays
+    int a_0 [0];
+};
+
+struct Sx18 {
+    int a_x [];               // { dg-error "flexible array member" }
+    struct S { };
+};
+
+struct Sx19 {
+    struct S { };
+    int a_x [];               // { dg-error "flexible array member" }
+};
+
+struct Sx20 {
+    struct S { } s;
+    int a_x [];
+};
+
+struct Sx21 {
+    int a_x [];               // { dg-error "not at end" }
+    struct S { } s;
+};
+
+struct Sx22 {
+    int a_x [];               // { dg-error "not at end" }
+    union { int i; };
+};
+
+struct Sx23 {
+    union { int i; };
+    int a_x [];
+};
+
+struct Sx24 {
+    struct S;
+    S a_x [];                 // { dg-error "incomplete type" }
+};
+
+struct Sx25 {
+    struct S { };
+    S a_x [];                 // { dg-error "flexible array member" }
+};
+
+struct Sx26 {
+    struct { }
+    a_x [];                   // { dg-error "flexible array member" }
+};
+
+struct Sx27 {
+    int i;
+    struct { }
+    a_x [];
+};
+
+struct Sx28 {
+    struct { }
+    a_x [];                   // { dg-error "not at end" }
+    int i;
+};
+
+struct Sx29 {
+    // Pointer to an array of unknown size.
+    int (*a_x)[];
+};
+
+struct Sx30 {
+    // Reference to an array of unknown size.
+    int (&a_x)[];
+};
+
+struct Sx31 {
+    int a [];                 // { dg-error "not at end" }
+    unsigned i: 1;
+};
+
+struct Sx32 {
+    unsigned i: 1;
+    int a [];
+};
+
+struct S_S_S_x {
+    struct A {
+        struct B {
+            int a[];          // { dg-error "flexible array member" }
+        } b;
+    } a;
+};
+
+// Since members of an anonymous struct or union are considered to be
+// members of the enclosing union the below defintions are valid and
+// must be accepted.
+
+struct Anon1 {
+    int n;
+    struct {
+        int good[];
+    };
+};
+
+struct Anon2 {
+    struct {
+        int n;
+        struct {
+            int good[];
+        };
+    };
+};
+
+struct Anon3 {
+    struct {
+        struct {
+            int n;
+            int good[];
+        };
+    };
+};
+
+struct Anon4 {
+    struct {
+        int in_empty_struct[];// { dg-error "in an otherwise empty" }
+    };
+};
+
+struct Anon5 {
+    struct {
+        int not_at_end[];     // { dg-error "not at end" }
+    };
+    int n;
+};
+
+struct Anon6 {
+    struct {
+        struct {
+            int not_at_end[]; // { dg-error "not at end" }
+        };
+        int n;
+    };
+};
+
+
+struct Anon7 {
+    struct {
+        struct {
+            int not_at_end[]; // { dg-error "not at end" }
+        };
+    };
+    int n;
+};
+
+
+struct Six {
+    int i;
+    int a[];
+};
+
+class Cx {
+    int a[];                  // { dg-error "flexible array member" }
+};
+
+class Cix {
+    int i;
+    int a[];
+};
+
+struct Sxi {
+    int a[];                  // { dg-error "not at end" }
+    int i;
+};
+
+struct S0 {
+    int a[0];
+};
+
+struct S0i {
+    int a[0];
+    int i;
+};
+
+struct S_a0_ax {
+    int a1[0];
+    int ax[];                 // { dg-error "flexible array member" }
+};
+
+struct S_a0_i_ax {
+    int a1[0];
+    int i;
+    int ax[];
+};
+
+struct Si_a0_ax {
+    int i;
+    int a1[0];
+    int ax[];
+};
+
+struct S_u_ax {
+    struct {
+        // An empty struct is in C++ treated as if it had a single
+        // member of type char.  Arguably, though, since neither
+        // the struct nor the member has a name, the flexible array
+        // member should be diagnosed because its size cannot easily
+        // be stored in the contaning object.  This seems like too
+        // much of a corner case to worry about.
+    };
+    int ax[];                 // no warning because of the above
+};
+
+struct S_u0_ax {
+    union { } u[0];
+    int ax[];                 // { dg-error "flexible array member" }
+};
+
+struct S_a1_s2 {
+    int a[1];
+    int b[2];
+};
+
+union U_i_ax {
+    int i;
+    int a[];                  // { dg-error "flexible array member in union" }
+};
+
+union U_i_a0 {
+    int i;
+    int a[0];
+};
diff --git a/gcc/testsuite/g++.dg/ext/flexary5.C b/gcc/testsuite/g++.dg/ext/flexary5.C
new file mode 100644
index 0000000..91c9a4c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/flexary5.C
@@ -0,0 +1,52 @@ 
+// { dg-do compile }
+// { dg-options "-Wno-error=pedantic" }
+
+// Flexible array members are a feature of C99 (and newer) not provided
+// by C++ 2014 and prior.  G++ supports both the C99/C11 kind of flexible
+// array members and pre-C99 zero-size arrays (defining an array of size
+// zero).  Since both features are provided for compatibility with C,
+// G++ allows them in the same contexts as in C.  This test verifies
+// that invalid flexible array members are diagnosed in templates that
+// are instantiated and not otherwise.
+
+template <class T>
+struct S_no_diag: T {
+  char a[];   // cannot be diagnosed unless/until T is known
+};
+
+template <class T>
+struct STx_1: T {
+  char a[];   // { dg-error "flexible array member" }
+};
+
+template <class T, int I>
+struct STI: T {
+  char a[I];   // cannot be diagnosed unless/until T and I are known
+};
+
+template <class T, int I>
+struct STIx: T {
+  char a[I];
+};
+
+template <int>
+struct Empty { };
+
+STx_1<Empty<0> > stx_empty_1;
+STIx<Empty<0>, 0> stix_empty_1;
+
+struct EmptyBase1: Empty<0>, Empty<1> { };
+struct EmptyBase2: Empty<2>, Empty<3> { };
+struct EmptyDerived: EmptyBase1, EmptyBase2
+{
+    char a[];   // { dg-error "flexible array member" }
+};
+
+struct NonEmpty { int i; };
+struct NonEmptyBase: NonEmpty { };
+struct NonEmptyDerived: NonEmptyBase { };
+
+struct FinalDerived: EmptyBase1, EmptyBase2, NonEmpty, Empty<4>
+{
+    char a[];   // okay
+};
diff --git a/gcc/testsuite/g++.dg/ext/flexary6.C b/gcc/testsuite/g++.dg/ext/flexary6.C
new file mode 100644
index 0000000..b3fc456
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/flexary6.C
@@ -0,0 +1,25 @@ 
+// PR c++/68478 - flexible array members have complete type
+// { dg-do compile }
+// { dg-options "-Wno-error=pedantic" }
+
+// Test to verify that attempting to use a flexible array member where
+// a complete type is required is rejected.
+
+struct A {
+  int n;
+  int a[];
+  enum {
+    e = sizeof a   // { dg-error "invalid application of .sizeof. to incomplete type" }
+  };
+};
+
+struct B {
+  int n;
+  typedef int A[];
+  A a;
+  enum {
+    // Verify that attempting to use a flexible array member where
+    // a complete type is required is rejected.
+    e = sizeof a   // { dg-error "invalid application of .sizeof. to incomplete type" }
+  };
+};
diff --git a/gcc/testsuite/g++.dg/ext/flexary7.C b/gcc/testsuite/g++.dg/ext/flexary7.C
new file mode 100644
index 0000000..fdea4d4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/flexary7.C
@@ -0,0 +1,57 @@ 
+// PR c++/68613 - initializer-string for array of chars is too long error
+// on flexible array member
+// { dg-do compile }
+// { dg-options "-Wpedantic -Wno-error=pedantic" }
+
+struct FlexChar {
+    int n;
+    char a[];
+};
+
+struct FlexChar ac =
+  { 4, { "abc" } }; // { dg-warning "initialization of a flexible array member" }
+
+
+#if !__cplusplus
+typedef __WCHAR_TYPE__ wchar_t;
+#endif
+
+struct FlexWchar {
+    int n;
+    wchar_t a[];
+};
+
+struct FlexWchar awc =
+  { 3, { L"ab" } }; // { dg-warning "initialization of a flexible array member" }
+
+
+struct FlexInt {
+    int n;
+    int a[];
+};
+
+// 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, { } };      // { dg-warning "initialization of a flexible array member" }
+
+struct FlexInt ai2 =
+  { 2, { 1, 2 } }; // { dg-warning "initialization of a flexible array member" }
+
+
+#if __cplusplus
+
+template <class T>
+struct FlexT {
+    int n;
+    T a[];
+};
+
+struct FlexT<char> atc =
+  { 4, { "abc" } }; // { dg-warning "initialization of a flexible array member" }
+
+#endif
diff --git a/gcc/testsuite/g++.dg/other/dump-ada-spec-2.C b/gcc/testsuite/g++.dg/other/dump-ada-spec-2.C
index 87c183a..d1af7e0 100644
--- a/gcc/testsuite/g++.dg/other/dump-ada-spec-2.C
+++ b/gcc/testsuite/g++.dg/other/dump-ada-spec-2.C
@@ -7,5 +7,5 @@  struct S
   __extension__ unsigned char data[];
 };
 
-/* { dg-final { scan-ada-spec "array \\(0 .. -1\\)" } } */
+/* { dg-final { scan-ada-spec "array \\(0 .. 0\\)" } } */
 /* { dg-final { cleanup-ada-spec } } */
diff --git a/gcc/testsuite/g++.dg/parse/pr43765.C b/gcc/testsuite/g++.dg/parse/pr43765.C
index 0b341dd..800f2c7 100644
--- a/gcc/testsuite/g++.dg/parse/pr43765.C
+++ b/gcc/testsuite/g++.dg/parse/pr43765.C
@@ -3,12 +3,15 @@ 
 
 struct SomeType
 {
+    int n;
     const char *values[];
 };
 const char *temp[] = {"607", "612", 0};
 
 SomeType vals[] =
     {
-        { values : temp, },
+        { 0, values : temp, },
         0
-    };          // { dg-error "invalid" }
+    };   // { dg-error "GNU-style designated initializer for an array|cannot convert" }
+// (note the error above is on the wrong line)
+ 
diff --git a/gcc/testsuite/g++.dg/torture/pr64280.C b/gcc/testsuite/g++.dg/torture/pr64280.C
index 6ea3148..e756e02 100644
--- a/gcc/testsuite/g++.dg/torture/pr64280.C
+++ b/gcc/testsuite/g++.dg/torture/pr64280.C
@@ -15,7 +15,7 @@  public:
 typedef int jmp_buf[];
 struct C
 {
-  jmp_buf cond_;
+  jmp_buf cond_;   // { dg-error "flexible array member" }
 };
 class F
 {
diff --git a/gcc/testsuite/g++.dg/torture/pr64312.C b/gcc/testsuite/g++.dg/torture/pr64312.C
index dc3e95d..85211f2 100644
--- a/gcc/testsuite/g++.dg/torture/pr64312.C
+++ b/gcc/testsuite/g++.dg/torture/pr64312.C
@@ -43,6 +43,7 @@  protected:
 class F
 {
 public:
+  int nelems;
   int elems[];
   int *
   m_fn1 ()
diff --git a/gcc/testsuite/g++.dg/ubsan/object-size-1.C b/gcc/testsuite/g++.dg/ubsan/object-size-1.C
index e2aad46..e6cdefc 100644
--- a/gcc/testsuite/g++.dg/ubsan/object-size-1.C
+++ b/gcc/testsuite/g++.dg/ubsan/object-size-1.C
@@ -1,9 +1,9 @@ 
 // { dg-do compile }
-// { dg-options "-fsanitize=undefined -fpermissive" }
+// { dg-options "-Wpedantic -Wno-error=pedantic -fsanitize=undefined -fpermissive" }
 
 struct T { int c; char d[]; };
 
-struct T t = { 1, "a" }; // { dg-warning "initializer-string for array of chars is too long" }
+struct T t = { 1, "a" }; // { dg-warning "initialization of a flexible array member " }
 
 int
 baz (int i)
diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c
index 34d9dfc..6a6b07b 100644
--- a/gcc/tree-chkp.c
+++ b/gcc/tree-chkp.c
@@ -1664,8 +1664,10 @@  chkp_find_bound_slots_1 (const_tree type, bitmap have_bound,
 				     offs + field_offs);
 	  }
     }
-  else if (TREE_CODE (type) == ARRAY_TYPE)
+  else if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
     {
+      /* The object type is an array of complete type, i.e., other
+	 than a flexible array.  */
       tree maxval = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
       tree etype = TREE_TYPE (type);
       HOST_WIDE_INT esize = TREE_INT_CST_LOW (TYPE_SIZE (etype));
diff --git a/gcc/tree.c b/gcc/tree.c
index 1d770c3..2ba786f 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -3588,9 +3588,10 @@  type_contains_placeholder_1 (const_tree type)
 	      || CONTAINS_PLACEHOLDER_P (TYPE_MAX_VALUE (type)));
 
     case ARRAY_TYPE:
-      /* We have already checked the component type above, so just check the
-	 domain type.  */
-      return type_contains_placeholder_p (TYPE_DOMAIN (type));
+      /* We have already checked the component type above, so just check
+	 the domain type.  Flexible array members have a null domain.  */
+      return TYPE_DOMAIN (type) ?
+	type_contains_placeholder_p (TYPE_DOMAIN (type)) : false;
 
     case RECORD_TYPE:
     case UNION_TYPE:
diff --git a/gcc/varasm.c b/gcc/varasm.c
index ec6aabf..606de4d 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -4821,8 +4821,7 @@  array_size_for_constructor (tree val)
 {
   tree max_index;
   unsigned HOST_WIDE_INT cnt;
-  tree index, value, tmp;
-  offset_int i;
+  tree index, value;
 
   /* This code used to attempt to handle string constants that are not
      arrays of single-bytes, but nothing else does, so there's no point in
@@ -4842,9 +4841,14 @@  array_size_for_constructor (tree val)
   if (max_index == NULL_TREE)
     return 0;
 
+  offset_int i = wi::to_offset (max_index) + 1;
+
+  if (TYPE_DOMAIN (TREE_TYPE (val)))
+    {
       /* Compute the total number of array elements.  */
-  tmp = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (val)));
-  i = wi::to_offset (max_index) - wi::to_offset (tmp) + 1;
+      tree tmp = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (val)));
+      i -= wi::to_offset (tmp);
+    }
   
   /* Multiply by the array element unit size to find number of bytes.  */
   i *= wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (val))));
@@ -4974,13 +4978,15 @@  output_constructor_regular_field (oc_local_state *local)
 	 but we cannot do this until the deprecated support for
 	 initializing zero-length array members is removed.  */
       if (TREE_CODE (TREE_TYPE (local->field)) == ARRAY_TYPE
-	  && TYPE_DOMAIN (TREE_TYPE (local->field))
-	  && ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (local->field))))
+	  && (!TYPE_DOMAIN (TREE_TYPE (local->field))
+	      || !TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (local->field)))))
 	{
 	  fieldsize = array_size_for_constructor (local->val);
-	  /* Given a non-empty initialization, this field had
-	     better be last.  */
-	  gcc_assert (!fieldsize || !DECL_CHAIN (local->field));
+	  /* Given a non-empty initialization, this field had better
+	     be last.  Given a flexible array member, the next field
+	     on the chain is a TYPE_DECL of the enclosing struct.  */
+	  const_tree next = DECL_CHAIN (local->field);
+	  gcc_assert (!fieldsize || !next || TREE_CODE (next) != FIELD_DECL);
 	}
       else
 	fieldsize = tree_to_uhwi (DECL_SIZE_UNIT (local->field));
@@ -5196,7 +5202,7 @@  output_constructor (tree exp, unsigned HOST_WIDE_INT size, unsigned int align,
   if (TREE_CODE (local.type) == ARRAY_TYPE && TYPE_DOMAIN (local.type))
     local.min_index = TYPE_MIN_VALUE (TYPE_DOMAIN (local.type));
   else
-    local.min_index = NULL_TREE;
+    local.min_index = integer_zero_node;
 
   local.total_bytes = 0;
   local.byte_buffer_in_use = outer != NULL;