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

	c++/42121
	c++/68478
	c++/68613
	c++/68689
	c++/68710
	* g++.dg/compat/struct-layout-1_generate.c: Avoid generating
	further fields after the first flexible array member.
	* 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/flexary.h: New file.
	* 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/ext/flexary8.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.

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

	c++/42121
	c++/68478
	c++/68613
	c++/68689
	c++/68710
	* 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.
	(flexmems_t): New type.
	(field_nonempty_p, find_flexarrays, diagnose_flexarrays)
	(check_flexarrays): New	functions.
	(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/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/cp/class.c b/gcc/cp/class.c
index 216a301..ee2784c 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.  */
@@ -145,6 +146,12 @@ static void build_base_fields (record_layout_info, splay_tree, tree *);
 static void check_methods (tree);
 static void remove_zero_width_bit_fields (tree);
 static bool accessible_nvdtor_p (tree);
+
+/* Used by find_flexarrays and related.  */
+struct flexmems_t;
+static void find_flexarrays (tree, flexmems_t *);
+static void diagnose_flexarrays (tree, const flexmems_t *);
+static void check_flexarrays (tree, flexmems_t * = NULL);
 static void check_bases (tree, int *, int *);
 static void check_bases_and_members (tree);
 static tree create_vtable_ptr (tree, tree *);
@@ -4114,7 +4121,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.  */
@@ -5703,9 +5713,9 @@ check_bases_and_members (tree t)
   cant_have_const_ctor = 0;
   no_const_asn_ref = 0;
 
-  /* Check all the base-classes.  */
-  check_bases (t, &cant_have_const_ctor,
-	       &no_const_asn_ref);
+  /* Check all the base-classes and set FMEM members to point to arrays
+     of potential interest.  */
+  check_bases (t, &cant_have_const_ctor, &no_const_asn_ref);
 
   /* Deduce noexcept on destructors.  This needs to happen after we've set
      triviality flags appropriately for our bases.  */
@@ -6236,6 +6246,7 @@ layout_class_type (tree t, tree *virtuals_p)
   /* Build FIELD_DECLs for all of the non-virtual base-types.  */
   empty_base_offsets = splay_tree_new (splay_tree_compare_integer_csts,
 				       NULL, NULL);
+
   build_base_fields (rli, empty_base_offsets, next_field);
 
   /* Layout the non-static data members.  */
@@ -6531,7 +6542,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);
@@ -6597,9 +6608,262 @@ sorted_fields_type_new (int n)
   return sft;
 }
 
+/* Helper of find_flexarrays.  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;
+}
+
+/* Used by find_flexarrays and related.  */
+struct flexmems_t {
+  /* The first flexible array member or non-zero array member found
+     in order of layout.  */
+  tree array;
+  /* First non-static non-empty data member in the class or its bases.  */
+  tree first;
+  /* First non-static non-empty data member following either the flexible
+     array member, if found, or the zero-length array member.  */
+  tree after;
+};
+
+/* Find either the first flexible array member or the first zero-length
+   array, in that order or preference, among members of class T (but not
+   its base classes), and set members of FMEM accordingly.  */
+
+static void
+find_flexarrays (tree t, flexmems_t *fmem)
+{
+  for (tree fld = TYPE_FIELDS (t), next; fld; fld = next)
+    {
+      /* Find the next non-static data member if it exists.  */
+      for (next = fld;
+	   (next = DECL_CHAIN (next))
+	     && TREE_CODE (next) != FIELD_DECL; );
+      
+      tree fldtype = TREE_TYPE (fld);
+      if (TREE_CODE (fld) != TYPE_DECL
+	  && RECORD_OR_UNION_TYPE_P (fldtype)
+	  && TYPE_ANONYMOUS_P (fldtype))
+	{
+	  /* Members of anonymous structs and unions are treated as if
+	     they were members of the containing class.  Descend into
+	     the anonymous struct or union and find a flexible array
+	     member or zero-length array among its fields.  */
+	  find_flexarrays (fldtype, fmem);
+	  continue;
+	}
+
+      /* Skip anything that's not a (non-static) data member.  */
+      if (TREE_CODE (fld) != FIELD_DECL)
+	continue;
+
+      /* Skip virtual table pointers.  */
+      if (DECL_ARTIFICIAL (fld))
+	continue;
+
+      if (field_nonempty_p (fld))
+	{
+	  /* Remember the first non-static data member.  */
+	  if (!fmem->first)
+	    fmem->first = fld;
+	  
+	  /* Remember the first non-static data member after the flexible
+	     array member, if one has been found, or the zero-length array
+	     if it has been found.  */
+	  if (!fmem->after && fmem->array)
+	    fmem->after = fld;
+	}
+	    
+      /* Skip non-arrays.  */
+      if (TREE_CODE (fldtype) != ARRAY_TYPE)
+	continue;
+
+      /* Determine the upper bound of the array if it has one.  */
+      tree dom = TYPE_DOMAIN (fldtype);
+
+      if (dom && TYPE_MAX_VALUE (dom))
+	{
+	  if (fmem->array)
+	    {
+	      /* Make a record of the zero-length array if either one
+		 such field or a flexible array member has been seen to
+		 handle the pathological and unlikely case of multiple
+		 such members.  */
+	      if (!fmem->after)
+		fmem->after = fld;
+	    }
+	  else if (integer_all_onesp (TYPE_MAX_VALUE (dom)))
+	    /* Remember the first zero-length array unless a flexible array
+	       member has already been seen.  */
+	    fmem->array = fld;
+	}
+      else
+	{
+	  /* Flexible array members have no upper bound.  */
+	  if (fmem->array)
+	    {
+	      /* Replace the zero-length array if it's been stored and
+		 reset the after pointer.  */
+	      dom = TYPE_DOMAIN (TREE_TYPE (fmem->array));
+	      if (dom && TYPE_MAX_VALUE (dom))
+		{
+		  fmem->array = fld;
+		  fmem->after = NULL_TREE;
+		}
+	    }
+	  else	
+	    fmem->array = fld;
+	}
+    }
+}
+
+/* Issue diagnostics for invalid flexible array members or zero-length
+   arrays that are not the last elements of the containg class or its
+   base classes or that are its sole members.  */
+
+static void
+diagnose_flexarrays (tree t, const flexmems_t *fmem)
+{
+  /* Members of anonymous structs and unions are considered to be members
+     of the containing struct or union.  */
+  if (TYPE_ANONYMOUS_P (t) || !fmem->array)
+    return;
+
+  const char *msg = 0;
+
+  const_tree dom = TYPE_DOMAIN (TREE_TYPE (fmem->array));
+  if (dom && TYPE_MAX_VALUE (dom))
+    {
+      if (fmem->after)
+	msg = G_("zero-size array member %qD not at end of %q#T");
+      else if (!fmem->first)
+	msg = G_("zero-size array member %qD in an otherwise empty %q#T");
+
+      if (msg && pedwarn (DECL_SOURCE_LOCATION (fmem->array),
+			  OPT_Wpedantic, msg, fmem->array, t))
+
+	inform (location_of (t), "in the definition of %q#T", t);
+    }
+  else
+    {
+      if (fmem->after)
+	msg = G_("flexible array member %qD not at end of %q#T");
+      else if (!fmem->first)
+	msg = G_("flexible array member %qD in an otherwise empty %q#T");
+
+      if (msg)
+	{
+	  error_at (DECL_SOURCE_LOCATION (fmem->array), msg,
+		    fmem->array, t);
+
+	  /* In the unlikely event that the member following the flexible
+	     array member is declared in a different class, point to it.
+	     Otherwise it should be obvious.  */
+	  if (fmem->after
+	      && (DECL_CONTEXT (fmem->after) != DECL_CONTEXT (fmem->array)))
+	      inform (DECL_SOURCE_LOCATION (fmem->after),
+		      "next member %q#D declared here",
+		      fmem->after);
+	  
+	  inform (location_of (t), "in the definition of %q#T", t);
+	}
+    }
+}
+
+
+/* Recursively check to make sure that any flexible array or zero-length
+   array members of class T or its bases are valid (i.e., not the sole
+   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.  */
+
+static void
+check_flexarrays (tree t, flexmems_t *fmem /* = NULL */)
+{
+  /* Initialize the result of a search for flexible array and zero-length
+     array members.  Avoid doing any work if the most interesting FMEM data
+     have already been populated.  */
+  flexmems_t flexmems = flexmems_t ();
+  if (!fmem)
+    fmem = &flexmems;
+  else if (fmem->array && fmem->first && fmem->after)
+    return;
+
+  /* Recursively check the primary base class first.  */
+  if (CLASSTYPE_HAS_PRIMARY_BASE_P (t))
+    {
+      tree basetype = BINFO_TYPE (CLASSTYPE_PRIMARY_BINFO (t));
+      check_flexarrays (basetype, fmem);
+    }
+
+  /* Recursively check the base classes.  */
+  int nbases = BINFO_N_BASE_BINFOS (TYPE_BINFO (t));
+  for (int i = 0; i < nbases; ++i)
+    {
+      tree base_binfo = BINFO_BASE_BINFO (TYPE_BINFO (t), i);
+
+      /* The primary base class was already checked above.  */
+      if (base_binfo == CLASSTYPE_PRIMARY_BINFO (t))
+	continue;
+
+      /* Virtual base classes are at the end.  */
+      if (BINFO_VIRTUAL_P (base_binfo))
+	continue;
+
+      /* Check the base class.  */
+      check_flexarrays (BINFO_TYPE (base_binfo), fmem);
+    }
+
+  if (fmem == &flexmems)
+    {
+      /* Check virtual base classes only once per derived class.
+	 I.e., this check is not performed recursively for base
+	 classes.  */
+      int i;
+      tree base_binfo;
+      vec<tree, va_gc> *vbases;
+      for (vbases = CLASSTYPE_VBASECLASSES (t), i = 0;
+	   vec_safe_iterate (vbases, i, &base_binfo); i++)
+	{
+	  /* Check the virtual base class.  */
+	  tree basetype = TREE_TYPE (base_binfo);
+
+	  check_flexarrays (basetype, fmem);
+	}
+    }
+
+  /* Search the members of the current (derived) class.  */
+  find_flexarrays (t, fmem);
+
+  if (fmem == &flexmems)
+    { 
+      /* Issue diagnostics for invalid flexible and zero-length array members
+	 found in base classes or among the members of the current class.  */
+      diagnose_flexarrays (t, fmem);
+    }
+}
 
 /* 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)
@@ -6661,6 +6925,11 @@ finish_struct_1 (tree t)
        needs a mode.  */
     compute_record_mode (CLASSTYPE_AS_BASE (t));
 
+  /* With the layout complete and the primary base class determined,
+     check for flexible array members and zero-length arrays that
+     might overlap other members in the final layout.  */
+  check_flexarrays (t);
+
   virtuals = modify_all_vtables (t, nreverse (virtuals));
 
   /* If necessary, create the primary vtable for this class.  */
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 675342e..44e7440 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;
 
@@ -8744,6 +8748,7 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
  	  else
 	    pedwarn (input_location, OPT_Wpedantic, "ISO C++ forbids zero-size array");
 	}
+
     }
   else if (TREE_CONSTANT (size)
 	   /* We don't allow VLAs at non-function scopes, or during
@@ -10888,7 +10893,7 @@ grokdeclarator (const cp_declarator *declarator,
     }
 
   {
-    tree decl;
+    tree decl = NULL_TREE;
 
     if (decl_context == PARM)
       {
@@ -10912,11 +10917,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 +11095,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 +11111,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/compat/struct-layout-1_generate.c b/gcc/testsu
ite/g++.dg/compat/struct-layout-1_generate.c
index 2884c25..9d31f8e 100644
--- a/gcc/testsuite/g++.dg/compat/struct-layout-1_generate.c
+++ b/gcc/testsuite/g++.dg/compat/struct-layout-1_generate.c
@@ -605,8 +605,11 @@ getrandll (void)
   return ret;
 }
 
+/* Generate a subfield.  The object pointed to by FLEX is set to a non-zero
+   value when the generated field is a flexible array member.  When set, it
+   prevents subsequent fields from being generated (a flexible array mem*/
 int
-subfield (struct entry *e, char *letter)
+subfield (struct entry *e, char *letter, int* flex)
 {
   int i, type;
   char buf[20];
@@ -625,7 +628,10 @@ subfield (struct entry *e, char *letter)
       if (e[0].etype == ETYPE_STRUCT_ARRAY || e[0].etype == ETYPE_UNION_ARRAY)
        {
          if (e[0].arr_len == 255)
-           snprintf (buf, 20, "%c[]", *letter);
+           {
+             *flex = 1;
+             snprintf (buf, 20, "%c[]", *letter);
+           }
          else
            snprintf (buf, 20, "%c[%d]", *letter, e[0].arr_len);
          /* If this is an array type, do not put aligned attributes on
@@ -657,8 +663,8 @@ subfield (struct entry *e, char *letter)
          break;
        }
 
-      for (i = 1; i <= e[0].len; )
-       i += subfield (e + i, letter);
+      for (i = 1; !*flex && i <= e[0].len; )
+       i += subfield (e + i, letter, flex);
 
       switch (type)
        {
@@ -680,4 +686,6 @@ subfield (struct entry *e, char *letter)
       if (e[0].etype == ETYPE_ARRAY)
        {
          if (e[0].arr_len == 255)
-           snprintf (buf, 20, "%c[]", *letter);
+           {
+             *flex = 1;
+             snprintf (buf, 20, "%c[]", *letter);
diff --git a/gcc/testsuite/g++.dg/ext/flexary.h b/gcc/testsuite/g++.dg/ext/flexary.h
new file mode 100644
index 0000000..a8dff7d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/flexary.h
@@ -0,0 +1,22 @@
+// Definitions of helper macros for tests of flexible array members.
+
+#if __cplusplus < 201102L
+#  define _CAT(x, y)  x ## y
+#  define CAT(x, y)  _CAT (x, y)
+
+// Generate a struct with a unique name containing a bitfield
+// of size that must evaluate to a non-zero value, otherwise
+// generate a compiler error.
+#  define ASSERT(expr)                                                  \
+  struct CAT (FAM_Assert, __LINE__) { unsigned asrt: 0 != (expr); }
+#else
+// In C++ 11 and beyond, use static_assert.
+# define ASSERT(expr) static_assert (expr, #expr)
+#endif
+
+// Macro to verify that a flexible array member is allocated
+// at the very end of the containing struct.
+#define ASSERT_AT_END(T, m)                             \
+  ASSERT (__builtin_offsetof (T, m) == sizeof (T))
+
+typedef __SIZE_TYPE__ size_t;
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..97ec625
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/flexary4.C
@@ -0,0 +1,421 @@
+// 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.
+
+#include "flexary.h"
+
+struct Sx {
+  int a[];                  // { dg-error "in an otherwise empty" }
+};
+
+// Verify that non-data members or static data members either before
+// or after a flexible array member in an otherwise empty struct don't
+// suppress the diagnostic.
+struct Sx2 {
+  int a[];                  // { dg-error "in an otherwise empty" }
+  typedef int I;
+};
+
+struct Sx3 {
+  typedef int I;
+  int a[];                  // { dg-error "in an otherwise empty" }
+};
+
+struct Sx4 {
+  int a[];                  // { dg-error "in an otherwise empty" }
+  enum E { e };
+};
+
+struct Sx5 {
+  enum E { e };
+  int a[];                  // { dg-error "in an otherwise empty" }
+};
+
+struct Sx6 {
+  int a[];                  // { dg-error "in an otherwise empty" }
+  static int i;
+};
+
+struct Sx7 {
+  static int i;
+  int a[];                  // { dg-error "in an otherwise empty" }
+};
+
+struct Sx8 {
+  int a[];                  // { dg-error "in an otherwise empty" }
+  Sx8 () { }
+};
+
+struct Sx9 {
+  Sx9 () { }
+  int a[];                  // { dg-error "in an otherwise empty" }
+};
+
+struct Sx10 {
+  int a[];                  // { dg-error "in an otherwise empty" }
+  virtual ~Sx10 () { }
+};
+
+struct Sx11 {
+  virtual ~Sx11 () { }
+  int a[];                  // { dg-error "in an otherwise empty" }
+};
+
+struct Sx12 {
+  int a[];                  // { dg-error "in an otherwise empty" }
+  virtual void foo () = 0;
+};
+
+struct Sx13 {
+  virtual void foo () = 0;
+  int a[];                  // { dg-error "in an otherwise empty" }
+};
+
+struct Sx14 {
+  int a[][1];               // { dg-error "in an otherwise empty" }
+};
+
+struct Sx15 {
+  typedef int A[];
+  A a;                      // { dg-error "in an otherwise empty" }
+};
+
+// 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 "in an otherwise empty" }
+};
+
+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];
+};
+
+// Empty structs are a GCC extension that (in C++ only) is treated
+// as if it had a single member of type char.  Therefore, a struct
+// containing a flexible array member followed by an empty struct
+// is diagnosed to prevent the former subobject from sharing space
+// with the latter.
+struct Sx18 {
+  int a_x [];               // { dg-error "flexible array member" }
+  struct S { };
+};
+
+// Anonymous structs and unions are another GCC extension.  Since
+// they cannot be named and thus used to store the size of a flexible
+// array member, a struct containing both is diagnosed as if
+// the flexible array member appeared alone.
+struct Sx19 {
+  struct S { };
+  union U { };
+  int a_x [];               // { dg-error "in an otherwise empty" }
+};
+
+// Unlike in the case above, a named member of an anonymous struct
+// prevents a subsequent flexible array member from being diagnosed.
+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 [];
+};
+
+ASSERT_AT_END (Sx27, 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 [];
+};
+
+ASSERT_AT_END (Sx32, a);
+
+struct Sx33 {
+  int a [];                 // { dg-error "otherwise empty" }
+  friend int foo ();
+};
+
+struct Sx34 {
+  friend int foo ();
+  int a [];                 // { dg-error "otherwise empty" }
+};
+
+// Verify that intervening non-field declarations of members other
+// than non-static data members don't affect the diagnostics.
+struct Sx35 {
+  int a[];                  // { dg-error "not at end" }
+  typedef int I;
+  int n;
+};
+
+struct Sx36 {
+  int n;
+  typedef int I;
+  int a[];
+};
+
+ASSERT_AT_END (Sx36, a);
+
+struct Sx37 {
+  int a[];                  // { dg-error "not at end" }
+  enum E { };
+  int n;
+};
+
+struct Sx38 {
+  int n;
+  enum E { };
+  int a[];
+};
+
+ASSERT_AT_END (Sx38, a);
+
+struct Sx39 {
+  int a[];                  // { dg-error "not at end" }
+  struct S;
+  int n;
+};
+
+struct Sx40 {
+  int n;
+  struct S;
+  int a[];
+};
+
+ASSERT_AT_END (Sx40, a);
+
+struct Sx41 {
+  int a[];                  // { dg-error "not at end" }
+  static int i;
+  int n;
+};
+
+struct Sx42 {
+  int n;
+  static int i;
+  int a[];
+};
+
+ASSERT_AT_END (Sx42, a);
+
+struct Sx43 {
+  int a[];                  // { dg-error "not at end" }
+  Sx43 ();
+  int n;
+};
+
+struct Sx44 {
+  int n;
+  Sx44 ();
+  int a[];
+};
+
+ASSERT_AT_END (Sx44, 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[];
+  };
+};
+
+ASSERT_AT_END (Anon1, good);
+
+struct Anon2 {
+  struct {
+    int n;
+    struct {
+      int good[];
+    };
+  };
+};
+
+ASSERT_AT_END (Anon2, good);
+
+struct Anon3 {
+  struct {
+    struct {
+      int n;
+      int good[];
+    };
+  };
+};
+
+ASSERT_AT_END (Anon3, 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[];
+};
+
+ASSERT_AT_END (Six, 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 a0[0];
+  int ax[];                 // { dg-error "flexible array member" }
+};
+
+struct S_a0_i_ax {
+  int a0[0];
+  int i;
+  int ax[];
+};
+
+ASSERT_AT_END (S_a0_i_ax, ax);
+
+struct Si_a0_ax {
+  int i;
+  int a0[0];
+  int ax[];
+};
+
+ASSERT_AT_END (Si_a0_ax, ax);
+
+struct Si_ax_a0 {
+  int i;
+  int ax[];                 // { dg-error "not at end" }
+  int a0[0];
+};
+
+struct S_u0_ax {
+  union { } u[0];
+  int ax[];                 // { dg-error "flexible array member" }
+};
+
+struct S_a1_s2 {
+  int a[1];
+  int b[2];
+};
diff --git a/gcc/testsuite/g++.dg/ext/flexary5.C b/gcc/testsuite/g++.dg/ext/flexary5.C
new file mode 100644
index 0000000..3e76d3e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/flexary5.C
@@ -0,0 +1,209 @@
+// { dg-do compile }
+// { dg-options "-Wno-error=pedantic" }
+
+// Test to verify flexible array members handling in base and derived
+// classes.
+
+#include "flexary.h"
+
+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 E { };
+
+STx_1<E<0> > stx_empty_1;
+STIx<E<0>, 0> stix_empty_1;
+
+// Verify that a sole flexible array member in a class with all empty
+// base classes is diagnosed.
+struct E1: E<0>, E<1> { };
+struct E2: E<2>, E<3> { };
+struct D1: E1, E2
+{
+    char a[];   // { dg-error "flexible array member" }
+};
+
+struct NE { size_t i; };
+
+struct A1x { int n, a[]; };
+struct D2: A1x, E1, E2 { };
+
+// Verify that the offset of the flexible array member is equal
+// to the size of each of the valid structs.
+ASSERT_AT_END (D2, a);
+
+struct D3: E1, A1x, E2 { };
+
+ASSERT_AT_END (D3, a);
+
+struct D4: E1, E2, A1x { };
+
+ASSERT_AT_END (D4, a);
+
+// Class with non-static data members and at least one base class
+// with such a member is not a standard layout class.  The warning
+// below is benign since GCC computes the expected value.
+struct D5: E1, E2, NE { char a[]; };
+
+ASSERT_AT_END (D5, a);   // { dg-warning "offsetof within non-standard-layout" }
+
+struct A2x {
+  size_t n;
+  size_t a[];   // { dg-error "not at end of .struct D6.| D7.| D8." }
+};
+
+// Verify that the flexible array member in A2x above is diagnosed
+// for each of the three struct defintions below which also derive
+// from another struct with a flexible array member.
+struct D6: A2x, E1, A1x { };
+struct D7: E1, A2x, E2, A1x { };
+struct D8: E1, E2, A2x, A1x { };
+
+struct DA2x: A2x { };
+
+struct D9: DA2x, E1, E2 { };
+
+ASSERT_AT_END (D9, a);
+
+struct D10: E1, DA2x, E2 { };
+
+ASSERT_AT_END (D10, a);
+
+struct D11: E1, E2, DA2x { };
+
+ASSERT_AT_END (D11, a);
+
+struct A3x {
+  size_t n;
+  size_t a[];   // { dg-error "not at end of .struct D12.| D13.| D14.| D15." }
+};
+
+// Verify that the flexible array member in A3x above is diagnosed
+// for each of the three struct defintions below which also derive
+// from another struct with a non-static member.
+struct D12: A3x, E1, NE { };
+struct D13: E1, A3x, NE { };
+struct D14: E1, E2, A3x, NE { };
+struct D15: E1, E2, NE, A3x { };
+
+struct A4x {
+  A4x ();
+  ~A4x ();
+
+  size_t n;
+  struct AS {
+    AS (int);
+    ~AS ();
+    size_t i;
+  } a[];
+};
+
+struct D16: A4x, E1, E2 { };
+
+ASSERT_AT_END (D16, a);
+
+struct D17: E1, A4x, E2 { };
+
+ASSERT_AT_END (D17, a);
+
+struct D18: E1, E2, A4x { };
+
+ASSERT_AT_END (D18, a);
+
+struct DA4x: A4x { };
+
+struct D19: DA4x, E1, E2 { };
+
+ASSERT_AT_END (D19, a);
+
+struct D20: E1, DA4x, E2 { };
+
+ASSERT_AT_END (D20, a);
+
+struct D21: E1, E2, DA4x { };
+
+ASSERT_AT_END (D21, a);
+
+
+struct A5x {
+  A5x (int);
+  virtual ~A5x ();
+
+  size_t n;
+  struct AS {
+    AS (int);
+    ~AS ();
+    size_t i;
+  } a[];
+};
+
+struct D22: A5x, E1, E2 { };
+
+ASSERT_AT_END (D22, a);   // { dg-warning "offsetof within non-standard-layout" }
+
+struct D23: E1, A5x, E2 { };
+
+ASSERT_AT_END (D23, a);   // { dg-warning "offsetof within non-standard-layout" }
+
+struct D24: E1, E2, A5x { };
+
+ASSERT_AT_END (D24, a);   // { dg-warning "offsetof within non-standard-layout" }
+
+struct DA5x: A5x { };
+
+struct D25: DA5x, E1, E2 { };
+
+ASSERT_AT_END (D25, a);   // { dg-warning "offsetof within non-standard-layout" }
+
+struct D26: E1, DA5x, E2 { };
+
+ASSERT_AT_END (D26, a);   // { dg-warning "offsetof within non-standard-layout" }
+
+struct D27: E1, E2, DA5x { };
+
+ASSERT_AT_END (D27, a);   // { dg-warning "offsetof within non-standard-layout" }
+
+// Verfify that a flexible array member is diagnosed even when deep
+// in the base class hierarchy.
+struct A6x {
+  size_t n;
+  size_t a[];               // { dg-error "not at end of .struct D28.| D29." }
+};
+
+struct AA6x: A6x { };
+struct NE1: NE { };
+struct NE2: NE { };
+
+struct D28: NE1, AA6x { };
+struct D29: AA6x, NE1 { };
+
+// Verify that a flexible array member in a virtual base class is not
+// diagnosed.
+struct A7x {
+  size_t n;
+  size_t a[];
+};
+
+struct DA7xV1: virtual A7x { };
+struct DA7xV2: virtual A7x { };
+
+struct D30: DA7xV1, DA7xV2 { };
+struct D31: DA7xV1, DA7xV2 { };
+struct D32: D30, D31 { };
diff --git a/gcc/testsuite/g++.dg/ext/flexary6.C b/gcc/testsuite/g++.dg/ext/flexary6.C
new file mode 100644
index 0000000..92677cd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/flexary6.C
@@ -0,0 +1,23 @@
+// 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 {
+    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/ext/flexary8.C b/gcc/testsuite/g++.dg/ext/flexary8.C
new file mode 100644
index 0000000..7a1811d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/flexary8.C
@@ -0,0 +1,33 @@
+// 68689 - flexible array members in unions accepted in C++
+// { dg-do compile }
+// { dg-options "-Wno-error=pedantic" }
+
+union U_i_ax {
+    int i;
+    int a[];                  // { dg-error "flexible array member in union" }
+};
+
+struct SU1 {
+  union {
+    int a[];                  // { dg-error "flexible array member in union" }
+  };
+};
+
+struct SU2 {
+  int n;
+  union {
+    int a[];                  // { dg-error "flexible array member in union" }
+  };
+};
+
+struct SU3 {
+  union {
+    int n;
+    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/flexary9.C b/gcc/testsuite/g++.dg/ext/flexary9.C
new file mode 100644
index 0000000..3228542
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/flexary9.C
@@ -0,0 +1,405 @@
+// { dg-do compile }
+// { dg-options "-Wpedantic -Wno-error=pedantic" }
+
+#include "flexary.h"
+
+struct Sx {
+  int a[0];                 // { dg-warning "zero-size|in an otherwise empty" }
+};
+
+// Verify that non-data members or static data members either before
+// or after a zero-length array in an otherwise empty struct don't
+// suppress the diagnostic.
+struct Sx2 {
+  int a[0];                 // { dg-warning "zero-size|in an otherwise empty" }
+  typedef int I;
+};
+
+struct Sx3 {
+  typedef int I;
+  int a[0];                 // { dg-warning "zero-size|in an otherwise empty" }
+};
+
+struct Sx4 {
+  int a[0];                 // { dg-warning "zero-size|in an otherwise empty" }
+  enum E { e };
+};
+
+struct Sx5 {
+  enum E { e };
+  int a[0];                 // { dg-warning "zero-size|in an otherwise empty" }
+};
+
+struct Sx6 {
+  int a[0];                 // { dg-warning "zero-size|in an otherwise empty" }
+  static int i;
+};
+
+struct Sx7 {
+  static int i;
+  int a[0];                 // { dg-warning "zero-size|in an otherwise empty" }
+};
+
+struct Sx8 {
+  int a[0];                 // { dg-warning "zero-size|in an otherwise empty" }
+  Sx8 () { }
+};
+
+struct Sx9 {
+  Sx9 () { }
+  int a[0];                 // { dg-warning "zero-size|in an otherwise empty" }
+};
+
+struct Sx10 {
+  int a[0];                 // { dg-warning "zero-size|in an otherwise empty" }
+  virtual ~Sx10 () { }
+};
+
+struct Sx11 {
+  virtual ~Sx11 () { }
+  int a[0];                 // { dg-warning "zero-size|in an otherwise empty" }
+};
+
+struct Sx12 {
+  int a[0];                 // { dg-warning "zero-size|in an otherwise empty" }
+  virtual void foo () = 0;
+};
+
+struct Sx13 {
+  virtual void foo () = 0;
+  int a[0];                 // { dg-warning "zero-size|in an otherwise empty" }
+};
+
+struct Sx14 {
+  int a[0][1];             // { dg-warning "zero-size|in an otherwise empty" }
+};
+
+struct Sx15 {
+  typedef int A[0];         // { dg-warning "zero-size" }
+  A a;                      // { dg-warning "in an otherwise empty" }
+};
+
+// Verify also that a zero-size array doesn't suppress the diagnostic.
+struct Sx16 {
+  int a_0 [0];              // { dg-warning "zero-size|in an otherwise empty" }
+  int a_x [0];              // { dg-warning "zero-size array" }
+};
+
+struct Sx17 {
+  int a_x [0];              // { dg-warning "zero-size|in an otherwise empty" }
+  int a_0 [0];              // { dg-warning "zero-size array" }
+};
+
+// Empty structs are a GCC extension that (in C++ only) is treated
+// as if it had a single member of type char.  Therefore, a struct
+// containing a zero-length array followed by an empty struct
+// is diagnosed to prevent the former subobject from sharing space
+// with the latter.
+struct Sx18 {
+  int a_x [0];              // { dg-warning "zero-size array" }
+  struct S { };
+};
+
+// Anonymous structs and unions are another GCC extension.  Since
+// they cannot be named and thus used to store the size of a zero
+// length array member, a struct containing both is diagnosed as
+// if the zero-length array appeared alone.
+struct Sx19 {
+  struct S { };
+  union U { };
+  int a_x [0];              // { dg-warning "zero-size|in an otherwise empty" }
+};
+
+// Unlike in the case above, a named member of an anonymous struct
+// prevents a subsequent zero-length array from being diagnosed.
+struct Sx20 {
+  struct S { } s;
+  int a_x [0];              // { dg-warning "zero-size array" }
+};
+
+struct Sx21 {
+  int a_x [0];              // { dg-warning "zero-size array|not at end" }
+  struct S { } s;
+};
+
+struct Sx22 {
+  int a_x [0];              // { dg-warning "zero-size array|not at end" }
+  union { int i; };
+};
+
+struct Sx23 {
+  union { int i; };
+  int a_x [0];              // { dg-warning "zero-size array" }
+};
+
+// The following causes an incomplete type error error and a zero-size
+// array warning.
+struct Sx24 {
+  struct S;
+  S a_x [0];                // { dg-message "incomplete type|zero-size array" }
+};
+
+struct Sx25 {
+  struct S { };
+  S a_x [0];                // { dg-warning "zero-size array" }
+};
+
+struct Sx26 {
+  struct { }
+    a_x [0];                // { dg-warning "zero-size array" }
+};
+
+struct Sx27 {
+  int i;
+  struct { }
+    a_x [0];                // { dg-warning "zero-size array" }
+};
+
+ASSERT_AT_END (Sx27, a_x);
+
+struct Sx28 {
+  struct { }
+    a_x [0];                // { dg-warning "zero-size array|not at end" }
+  int i;
+};
+
+struct Sx29 {
+  // Pointer to an array of zero size.
+  int (*a_x)[0];            // { dg-warning "zero-size array" }
+};
+
+struct Sx30 {
+  // Reference to an array of zero size.
+  int (&a_x)[0];            // { dg-warning "zero-size array" }
+};
+
+struct Sx31 {
+  int a [0];                // { dg-warning "zero-size array|not at end" }
+  unsigned i: 1;
+};
+
+struct Sx32 {
+  unsigned i: 1;
+  int a [0];                // { dg-warning "zero-size array" }
+};
+
+ASSERT_AT_END (Sx32, a);
+
+struct Sx33 {
+  int a [0];                // { dg-warning "zero-size array|otherwise empty" }
+  friend int foo ();
+};
+
+struct Sx34 {
+  friend int foo ();
+  int a [0];                // { dg-warning "zero-size array|otherwise empty" }
+};
+
+// Verify that intervening non-field declarations of members other
+// than non-static data members don't affect the diagnostics.
+struct Sx35 {
+  int a[0];                 // { dg-warning "zero-size array|not at end" }
+  typedef int I;
+  int n;
+};
+
+struct Sx36 {
+  int n;
+  typedef int I;
+  int a[0];                 // { dg-warning "zero-size array" }
+};
+
+ASSERT_AT_END (Sx36, a);
+
+struct Sx37 {
+  int a[0];                 // { dg-warning "zero-size array|not at end" }
+  enum E { };
+  int n;
+};
+
+struct Sx38 {
+  int n;
+  enum E { };
+  int a[0];                 // { dg-warning "zero-size array" }
+};
+
+ASSERT_AT_END (Sx38, a);
+
+struct Sx39 {
+  int a[0];                 // { dg-warning "zero-size array|not at end" }
+  struct S;
+  int n;
+};
+
+struct Sx40 {
+  int n;
+  struct S;
+  int a[0];                 // { dg-warning "zero-size array" }
+};
+
+ASSERT_AT_END (Sx40, a);
+
+struct Sx41 {
+  int a[0];                 // { dg-warning "zero-size array|not at end" }
+  static int i;
+  int n;
+};
+
+struct Sx42 {
+  int n;
+  static int i;
+  int a[0];                 // { dg-warning "zero-size array" }
+};
+
+ASSERT_AT_END (Sx42, a);
+
+struct Sx43 {
+  int a[0];                 // { dg-warning "zero-size array|not at end" }
+  Sx43 ();
+  int n;
+};
+
+struct Sx44 {
+  int n;
+  Sx44 ();
+  int a[0];                 // { dg-warning "zero-size array" }
+};
+
+ASSERT_AT_END (Sx44, a);
+
+struct S_S_S_x {
+  struct A {
+    struct B {
+      int a[0];             // { dg-warning "zero-size array" }
+    } 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[0];            // { dg-warning "zero-size array" }
+  };                        // { dg-warning "anonymous struct" }
+};
+
+ASSERT_AT_END (Anon1, good);
+
+struct Anon2 {
+  struct {
+    int n;
+    struct {
+      int good[0];          // { dg-warning "zero-size array" }
+    };                      // { dg-warning "anonymous struct" }
+  };                        // { dg-warning "anonymous struct" }
+};
+
+ASSERT_AT_END (Anon2, good);
+
+struct Anon3 {
+  struct {
+    struct {
+      int n;
+      int good[0];          // { dg-warning "zero-size array" }
+    };                      // { dg-warning "anonymous struct" }
+  };                        // { dg-warning "anonymous struct" }
+};
+
+ASSERT_AT_END (Anon3, good);
+
+struct Anon4 {
+  struct {
+    int in_empty_struct[0]; // { dg-warning "zero-size array|in an otherwise empty" }
+  };                        // { dg-warning "anonymous struct" }
+};
+
+struct Anon5 {
+  struct {
+    int not_at_end[0];      // { dg-warning "zero-size array|not at end" }
+  };                        // { dg-warning "anonymous struct" }
+  int n;
+};
+
+struct Anon6 {
+  struct {
+    struct {
+      int not_at_end[0];    // { dg-warning "zero-size array|not at end" }
+    };                      // { dg-warning "anonymous struct" }
+    int n;
+  };                        // { dg-warning "anonymous struct" }
+};
+
+
+struct Anon7 {
+  struct {
+    struct {
+      int not_at_end[0];    // { dg-warning "zero-size array|not at end" }
+    };                      // { dg-warning "anonymous struct" }
+  };                        // { dg-warning "anonymous struct" }
+  int n;
+};
+
+
+struct Six {
+  int i;
+  int a[0];                 // { dg-warning "zero-size array" }
+};
+
+ASSERT_AT_END (Six, a);
+
+class Cx {
+  int a[0];                 // { dg-warning "zero-size array" }
+};
+
+class Cix {
+  int i;
+  int a[0];                 // { dg-warning "zero-size array" }
+};
+
+struct Sxi {
+  int a[0];                 // { dg-warning "zero-size array|not at end" }
+  int i;
+};
+
+struct S0 {
+  int a[0];                 // { dg-warning "zero-size array" }
+};
+
+struct S0i {
+  int a[0];                 // { dg-warning "zero-size array" }
+  int i;
+};
+
+struct S_a0_ax {
+  int a1[0];                // { dg-warning "zero-size array" }
+  int ax[0];                // { dg-warning "zero-size array" }
+};
+
+struct S_a0_i_ax {
+  int a1[0];                // { dg-warning "zero-size array" }
+  int i;
+  int ax[0];                // { dg-warning "zero-size array" }
+};
+
+ASSERT_AT_END (S_a0_i_ax, ax);
+
+struct Si_a0_ax {
+  int i;
+  int a1[0];                // { dg-warning "zero-size array" }
+  int ax[0];                // { dg-warning "zero-size array" }
+};
+
+ASSERT_AT_END (Si_a0_ax, ax);
+
+struct S_u0_ax {
+  union { } u[0];           // { dg-warning "zero-size array" }
+  int ax[0];                // { dg-warning "zero-size array" }
+};
+
+struct S_a1_s2 {
+  int a[1];
+  int b[2];
+};
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;
