public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] c++/42121 - diagnose invalid flexible array members
@ 2015-11-21 22:26 Martin Sebor
  2015-12-04  4:42 ` Ping " Martin Sebor
  0 siblings, 1 reply; 12+ messages in thread
From: Martin Sebor @ 2015-11-21 22:26 UTC (permalink / raw)
  To: Gcc Patch List

[-- Attachment #1: Type: text/plain, Size: 1493 bytes --]

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

[-- Attachment #2: gcc-42121.patch --]
[-- Type: text/x-patch, Size: 22892 bytes --]

gcc/
2015-11-20  Martin Sebor  <msebor@redhat.com>

	PR c++/42121
	* c/c-decl.c (grokdeclarator): Mention type size in a diagnostic.
	(finish_struct): Same.

gcc/cp/
2015-11-20  Martin Sebor  <msebor@redhat.com>

	PR c++/42121
	* cp/class.c (layout_class_type): Mention type size in a diagnostic.
	(all_bases_empty_p, field_nonempty_p, check_flexarrays): New helper
	functions.
	(finish_struct_1): Call check_flexarrays.
	* cp/decl.c (compute_array_index_type): Add argument. Enhance
	diagnostic.
	(grokdeclarator): Reject flexible array members in unions.
	Distinguish flexible array members from zero-size arrays.

gcc/testsuite/
2015-11-20  Martin Sebor  <msebor@redhat.com>

	PR c++/42121
	* g++.dg/ext/flexary2.C: Adjust and enhance.
	* g++.dg/ext/flexary3.C: Adjust.
	* g++.dg/ext/flexary3.C: New test.
	* g++.dg/torture/pr64280.C: Adjust.
	* g++.dg/torture/pr64312.C: Adjust.
	* g++.dg/parse/pr43765.C: Adjust.
	* g++.dg/torture/pr64280.C: Adjust.

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..4803f55 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.  */
@@ -6531,7 +6532,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 +6599,196 @@ 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 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)
+{
+  /* inform (DECL_SOURCE_LOCATION (fields), */
+  /* 	  "entering %s with fields = %qD", __func__, fields); */
+
+  /* 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 array's domain type.  */
+      const_tree dom = TYPE_DOMAIN (fldtype);
+      if (!dom)
+	continue;
+
+      /* Determine the upper bound of the array.  */
+      const_tree upbnd = TYPE_MAX_VALUE (dom);
+      if (!upbnd)
+	continue;
+
+      /* In C++, flexible array members and zero-size arrays have
+	 an upper bound of SIZE_MAX.  Skip those whose upper bound
+	 is less than that.  */
+      if (!tree_int_cst_equal (size_max_node, upbnd))
+	continue;
+
+      /* Flag is clear for zero-size arrays, set for flexible array
+	 members.  */
+      if (0 == DECL_LANG_FLAG_1 (f))
+	{
+	  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
+	{
+	  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)
+	    {
+	      /* Clear the flag specifically set for this purpose
+		 only when a diagnostic is issued but leave it set
+		 for prior (recursive) calls to the function so that
+		 the appropriate message can be issued.  */
+	      DECL_LANG_FLAG_1 (f) = 0;
+	      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..ba3daf3 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -8614,10 +8614,18 @@ fold_sizeof_expr (tree t)
    name of the thing being declared.  */

 tree
-compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
+compute_array_index_type (tree name, tree size,
+			  tsubst_flags_t complain)
 {
   tree itype;
   tree osize = size;
+  bool flexarray = false;
+
+  if (NULL_TREE == size)
+    {
+      flexarray = true;
+      size = size_zero_node;
+    }

   if (error_operand_p (size))
     return error_mark_node;
@@ -8739,11 +8747,12 @@ 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,
+		     flexarray ? "flexible array members are a C++ extension"
+		     : "ISO C++ forbids zero-size arrays");
 	}
+
     }
   else if (TREE_CONSTANT (size)
 	   /* We don't allow VLAs at non-function scopes, or during
@@ -9182,6 +9191,8 @@ grokdeclarator (const cp_declarator *declarator,
   source_location saved_loc = input_location;
   const char *errmsg;
   tree reqs = NULL_TREE;
+  /* Is the declarator a flexible array member?  */
+  bool flexarray = false;

   signed_p = decl_spec_seq_has_spec_p (declspecs, ds_signed);
   unsigned_p = decl_spec_seq_has_spec_p (declspecs, ds_unsigned);
@@ -10888,7 +10899,7 @@ grokdeclarator (const cp_declarator *declarator,
     }

   {
-    tree decl;
+    tree decl = NULL_TREE;

     if (decl_context == PARM)
       {
@@ -10912,11 +10923,20 @@ 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
+	      {
+		flexarray = true;
+		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
@@ -11404,6 +11424,9 @@ grokdeclarator (const cp_declarator *declarator,
     if (!processing_template_decl)
       cp_apply_type_quals_to_decl (type_quals, decl);

+    if (flexarray)
+      DECL_LANG_FLAG_1 (decl) = 1;
+
     return decl;
   }
 }
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..5c4a658 100644
--- a/gcc/testsuite/g++.dg/ext/flexary3.C
+++ b/gcc/testsuite/g++.dg/ext/flexary3.C
@@ -1,10 +1,19 @@
-// 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.
+
 // { dg-options "" }

-struct s { char c[]; };
+struct s {
+    char c[];   // { dg-error "flexible array member .* in an otherwise empty" }
+};

 int main()
 {
-    struct s s = { .c = 0 };	// { dg-error "initializer" }
+    struct s s = { .c = 0 };	// { dg-error "invalid initializer" }
     return 0;
 }
diff --git a/gcc/testsuite/g++.dg/ext/flexary4.C b/gcc/testsuite/g++.dg/ext/flexary4.C
new file mode 100644
index 0000000..dd001f3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/flexary4.C
@@ -0,0 +1,370 @@
+// 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];
+};
+
+template <class T>
+struct ST: 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/parse/pr43765.C b/gcc/testsuite/g++.dg/parse/pr43765.C
index 0b341dd..e115aa5 100644
--- a/gcc/testsuite/g++.dg/parse/pr43765.C
+++ b/gcc/testsuite/g++.dg/parse/pr43765.C
@@ -3,12 +3,13 @@

 struct SomeType
 {
+    int n;
     const char *values[];
 };
 const char *temp[] = {"607", "612", 0};

 SomeType vals[] =
     {
-        { values : temp, },
+        { 0, values : temp, },
         0
     };          // { dg-error "invalid" }
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 ()

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Ping [PATCH] c++/42121 - diagnose invalid flexible array members
  2015-11-21 22:26 [PATCH] c++/42121 - diagnose invalid flexible array members Martin Sebor
@ 2015-12-04  4:42 ` Martin Sebor
  2015-12-04 11:33   ` Bernd Schmidt
                     ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Martin Sebor @ 2015-12-04  4:42 UTC (permalink / raw)
  To: Gcc Patch List, Jason Merrill, Joseph S. Myers

[-- Attachment #1: Type: text/plain, Size: 3054 bytes --]

[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


[-- Attachment #2: gcc-42121.patch --]
[-- Type: text/x-patch, Size: 39579 bytes --]

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;

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Ping [PATCH] c++/42121 - diagnose invalid flexible array members
  2015-12-04  4:42 ` Ping " Martin Sebor
@ 2015-12-04 11:33   ` Bernd Schmidt
  2015-12-04 16:15   ` Joseph Myers
  2015-12-04 17:51   ` Jason Merrill
  2 siblings, 0 replies; 12+ messages in thread
From: Bernd Schmidt @ 2015-12-04 11:33 UTC (permalink / raw)
  To: Martin Sebor, Gcc Patch List, Jason Merrill, Joseph S. Myers

 > 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

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Ping [PATCH] c++/42121 - diagnose invalid flexible array members
  2015-12-04  4:42 ` Ping " Martin Sebor
  2015-12-04 11:33   ` Bernd Schmidt
@ 2015-12-04 16:15   ` Joseph Myers
  2015-12-04 17:51   ` Jason Merrill
  2 siblings, 0 replies; 12+ messages in thread
From: Joseph Myers @ 2015-12-04 16:15 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Gcc Patch List, Jason Merrill

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?

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Ping [PATCH] c++/42121 - diagnose invalid flexible array members
  2015-12-04  4:42 ` Ping " Martin Sebor
  2015-12-04 11:33   ` Bernd Schmidt
  2015-12-04 16:15   ` Joseph Myers
@ 2015-12-04 17:51   ` Jason Merrill
  2015-12-08 16:59     ` Martin Sebor
  2 siblings, 1 reply; 12+ messages in thread
From: Jason Merrill @ 2015-12-04 17:51 UTC (permalink / raw)
  To: Martin Sebor, Gcc Patch List, Joseph S. Myers

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

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Ping [PATCH] c++/42121 - diagnose invalid flexible array members
  2015-12-04 17:51   ` Jason Merrill
@ 2015-12-08 16:59     ` Martin Sebor
  2015-12-14 16:45       ` Martin Sebor
  0 siblings, 1 reply; 12+ messages in thread
From: Martin Sebor @ 2015-12-08 16:59 UTC (permalink / raw)
  To: Jason Merrill, Gcc Patch List

[-- Attachment #1: Type: text/plain, Size: 5580 bytes --]

Thanks for the review and the helpful hints!

I've reworked and simplified the diagnostic part of the patch and
corrected the remaining issues I uncovered while testing the new
version (failing to reject some invalid flexible array members in
base classes).  Please find the new version in the attachment.

FWIW, in the patch, I tried to address only the reported problems
with flexible array members without changing how zero-length arrays
are treated.  That means that the latter are accepted in more cases
(with a pedantic warning) than the latter.  For example, the
following is accepted:

     struct A {
         int a[0];   // pedantic warning: zero-size array member
         int n;      // not at end of struct A
     };

while this is rejected

     struct B {
         int a[];    // hard error: flexible array member not at
         int n;      // end of struct B
     };

It would be easy to change the patch to treat zero-length arrays
more like flexible array members if that's viewed as desirable.

I also tried to avoid rejecting flexible array members that are
currently accepted and that are safe.  For example, GCC currently
accepts both flexible array members and zero-length arrays in base
classes (even polymorphic ones).  The patch continues to accept
those for compatibility with code that relies on it as long as
the flexible array members didn't overlap other members in derived
classes.  For example, this is still accepted:

     struct A { int x; };
     struct B { int n, a[]; };
     struct C: A, B { };

but this is rejected:

     struct D: B, A { };

My replies to your comments are below.

On 12/04/2015 10:51 AM, Jason Merrill wrote:
> 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.

You're right, I missed that case in my testing.  Fixed.

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

As we discussed on IRC, this bit is fine.  I added a few tests for
the layout to make sure the offset of flexible array members matches
the size of the containing class.  While adding these tests I found
a couple of regressions unrelated to my changes (68727 and 68711) so
it was time well spent.

>> +      && !tree_int_cst_equal (size_max_node, TYPE_MAX_VALUE (dom)))
>
> This can be integer_minus_onep or integer_all_onesp.

Thanks.

>
>> +         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.

Sure.

>
>> +  {
>> +    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.

I tried moving it to check_bases_and_members there but with more
testing found out that calling it there was too early. In order
to detect invalid flexible array members in virtual base classes
without rejecting valid ones, the primary base class needs to
have been determined.  That happens in in layout_class_type()
called later on in finish_struct_1(). So I moved it just past
that call.

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

At one point, the diagnostic would emit a badly messed up name
in some corner cases.  I think it might have been when I set
TYPE_DOMAIN to NULL_TREE rather than with the current approach
(I can't reproduce it anymore). I've restored the else block.

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

This was my initial approach until I noticed that it diverged
from C where TYPE_DOMAIN is set to the range [0, NULL_TREE], so
I redid it for consistency.

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

To avoid an ICE later on.  I didn't spend too much time trying
to understand how the control flow changed to trigger it but my
guess is that it has to do with the change to the upper bound.

/home/msebor/scm/fsf/gcc-42121/gcc/testsuite/g++.dg/ext/flexary2.C:16:9: 
internal compiler error: tree check: expected tree that contains 'typed' 
structure, have '<invalid tree code>' in cp_apply_type_quals_to_decl, at 
cp/typeck.c:9134
0x13103fe tree_contains_struct_check_failed(tree_node const*, 
tree_node_structure_enum, char const*, int, char const*)
          /home/msebor/scm/fsf/gcc-42121/gcc/tree.c:9760
0x726b12 contains_struct_check(tree_node*, tree_node_structure_enum, 
char const*, int, char const*)
          /home/msebor/scm/fsf/gcc-42121/gcc/tree.h:3070
0x901d20 cp_apply_type_quals_to_decl(int, tree_node*)
          /home/msebor/scm/fsf/gcc-42121/gcc/cp/typeck.c:9134
0x77bf8b grokdeclarator(cp_declarator const*, cp_decl_specifier_seq*, 
decl_context, int, tree_node**)
          /home/msebor/scm/fsf/gcc-42121/gcc/cp/decl.c:11423

>
>> +++ b/gcc/testsuite/g++.dg/cpp0x/bad_array_new2.C
...
> Why?

This wasn't meant to be a part of the patch. I removed it.

Martin

[-- Attachment #2: gcc-42121.patch --]
[-- Type: text/x-patch, Size: 58433 bytes --]

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

	c++/42121
	c++/68478
	c++/68613
	c++/68689
	c++/68710
	* 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/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;

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Ping [PATCH] c++/42121 - diagnose invalid flexible array members
  2015-12-08 16:59     ` Martin Sebor
@ 2015-12-14 16:45       ` Martin Sebor
  2015-12-14 16:50         ` Jakub Jelinek
                           ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Martin Sebor @ 2015-12-14 16:45 UTC (permalink / raw)
  To: Jason Merrill, Gcc Patch List

[-- Attachment #1: Type: text/plain, Size: 6207 bytes --]

Ping:

The most recent patch revealed a problem in the test suite where
the g++.dg/compat/struct-layout-1_generate.c program generates
structs with invalid flexible array members.  The attached patch
fixes the generator to avoid that.

Jason,

Are there any further changes you'd like to suggest for this patch
or is it okay to commit?

Thanks
Martin

On 12/08/2015 09:59 AM, Martin Sebor wrote:
> Thanks for the review and the helpful hints!
>
> I've reworked and simplified the diagnostic part of the patch and
> corrected the remaining issues I uncovered while testing the new
> version (failing to reject some invalid flexible array members in
> base classes).  Please find the new version in the attachment.
>
> FWIW, in the patch, I tried to address only the reported problems
> with flexible array members without changing how zero-length arrays
> are treated.  That means that the latter are accepted in more cases
> (with a pedantic warning) than the latter.  For example, the
> following is accepted:
>
>      struct A {
>          int a[0];   // pedantic warning: zero-size array member
>          int n;      // not at end of struct A
>      };
>
> while this is rejected
>
>      struct B {
>          int a[];    // hard error: flexible array member not at
>          int n;      // end of struct B
>      };
>
> It would be easy to change the patch to treat zero-length arrays
> more like flexible array members if that's viewed as desirable.
>
> I also tried to avoid rejecting flexible array members that are
> currently accepted and that are safe.  For example, GCC currently
> accepts both flexible array members and zero-length arrays in base
> classes (even polymorphic ones).  The patch continues to accept
> those for compatibility with code that relies on it as long as
> the flexible array members didn't overlap other members in derived
> classes.  For example, this is still accepted:
>
>      struct A { int x; };
>      struct B { int n, a[]; };
>      struct C: A, B { };
>
> but this is rejected:
>
>      struct D: B, A { };
>
> My replies to your comments are below.
>
> On 12/04/2015 10:51 AM, Jason Merrill wrote:
>> 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.
>
> You're right, I missed that case in my testing.  Fixed.
>
>>> @@ -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.
>
> As we discussed on IRC, this bit is fine.  I added a few tests for
> the layout to make sure the offset of flexible array members matches
> the size of the containing class.  While adding these tests I found
> a couple of regressions unrelated to my changes (68727 and 68711) so
> it was time well spent.
>
>>> +      && !tree_int_cst_equal (size_max_node, TYPE_MAX_VALUE (dom)))
>>
>> This can be integer_minus_onep or integer_all_onesp.
>
> Thanks.
>
>>
>>> +         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.
>
> Sure.
>
>>
>>> +  {
>>> +    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.
>
> I tried moving it to check_bases_and_members there but with more
> testing found out that calling it there was too early. In order
> to detect invalid flexible array members in virtual base classes
> without rejecting valid ones, the primary base class needs to
> have been determined.  That happens in in layout_class_type()
> called later on in finish_struct_1(). So I moved it just past
> that call.
>
>>
>>> -      else if (name)
>>> -        pedwarn (input_location, OPT_Wpedantic, "ISO C++ forbids
>>> zero-size array %qD", name);
>>
>> Why?
>
> At one point, the diagnostic would emit a badly messed up name
> in some corner cases.  I think it might have been when I set
> TYPE_DOMAIN to NULL_TREE rather than with the current approach
> (I can't reproduce it anymore). I've restored the else block.
>
>> Can we leave TYPE_DOMAIN null for flexible arrays so you don't need to
>> add special new handling all over the place?
>
> This was my initial approach until I noticed that it diverged
> from C where TYPE_DOMAIN is set to the range [0, NULL_TREE], so
> I redid it for consistency.
>
>>
>>> -    tree decl;
>>> +    tree decl = NULL_TREE;
>>
>> Why?
>
> To avoid an ICE later on.  I didn't spend too much time trying
> to understand how the control flow changed to trigger it but my
> guess is that it has to do with the change to the upper bound.
>
> /home/msebor/scm/fsf/gcc-42121/gcc/testsuite/g++.dg/ext/flexary2.C:16:9:
> internal compiler error: tree check: expected tree that contains 'typed'
> structure, have '<invalid tree code>' in cp_apply_type_quals_to_decl, at
> cp/typeck.c:9134
> 0x13103fe tree_contains_struct_check_failed(tree_node const*,
> tree_node_structure_enum, char const*, int, char const*)
>           /home/msebor/scm/fsf/gcc-42121/gcc/tree.c:9760
> 0x726b12 contains_struct_check(tree_node*, tree_node_structure_enum,
> char const*, int, char const*)
>           /home/msebor/scm/fsf/gcc-42121/gcc/tree.h:3070
> 0x901d20 cp_apply_type_quals_to_decl(int, tree_node*)
>           /home/msebor/scm/fsf/gcc-42121/gcc/cp/typeck.c:9134
> 0x77bf8b grokdeclarator(cp_declarator const*, cp_decl_specifier_seq*,
> decl_context, int, tree_node**)
>           /home/msebor/scm/fsf/gcc-42121/gcc/cp/decl.c:11423
>
>>
>>> +++ b/gcc/testsuite/g++.dg/cpp0x/bad_array_new2.C
> ...
>> Why?
>
> This wasn't meant to be a part of the patch. I removed it.
>
> Martin


[-- Attachment #2: gcc-42121.patch --]
[-- Type: text/x-patch, Size: 60316 bytes --]

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;

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Ping [PATCH] c++/42121 - diagnose invalid flexible array members
  2015-12-14 16:45       ` Martin Sebor
@ 2015-12-14 16:50         ` Jakub Jelinek
  2015-12-14 20:32         ` Jason Merrill
  2015-12-16  7:53         ` Tom de Vries
  2 siblings, 0 replies; 12+ messages in thread
From: Jakub Jelinek @ 2015-12-14 16:50 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Jason Merrill, Gcc Patch List

On Mon, Dec 14, 2015 at 09:45:16AM -0700, Martin Sebor wrote:
> --- 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)

Formatting, space before * instead of after it.

	Jakub

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Ping [PATCH] c++/42121 - diagnose invalid flexible array members
  2015-12-14 16:45       ` Martin Sebor
  2015-12-14 16:50         ` Jakub Jelinek
@ 2015-12-14 20:32         ` Jason Merrill
  2015-12-16  7:53         ` Tom de Vries
  2 siblings, 0 replies; 12+ messages in thread
From: Jason Merrill @ 2015-12-14 20:32 UTC (permalink / raw)
  To: Martin Sebor, Gcc Patch List

On 12/14/2015 11:45 AM, Martin Sebor wrote:
> +  if (NULL_TREE == size)

Usually NULL_TREE goes on the right.

> @@ -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");
>  	}
> +
>      }

Unnecessary blank line.

> +	    if (TREE_CODE (type) != ARRAY_TYPE
> +		|| !COMPLETE_TYPE_P (TREE_TYPE (type)))
> +	      {
> +
>  		if (unqualified_id)

Here too.

OK with those changes and the one Jakub suggested.

Jason

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Ping [PATCH] c++/42121 - diagnose invalid flexible array members
  2015-12-14 16:45       ` Martin Sebor
  2015-12-14 16:50         ` Jakub Jelinek
  2015-12-14 20:32         ` Jason Merrill
@ 2015-12-16  7:53         ` Tom de Vries
  2015-12-16 15:57           ` Martin Sebor
  2015-12-16 15:57           ` Martin Sebor
  2 siblings, 2 replies; 12+ messages in thread
From: Tom de Vries @ 2015-12-16  7:53 UTC (permalink / raw)
  To: Martin Sebor, Jason Merrill, Gcc Patch List

On 14/12/15 17:45, Martin Sebor wrote:
> 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.

I think this caused PR68932 - FAIL: 
obj-c++.dg/property/at-property-23.mm -fgnu-runtime (internal compiler 
error)

Thanks,
- Tom

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Ping [PATCH] c++/42121 - diagnose invalid flexible array members
  2015-12-16  7:53         ` Tom de Vries
@ 2015-12-16 15:57           ` Martin Sebor
  2015-12-16 15:57           ` Martin Sebor
  1 sibling, 0 replies; 12+ messages in thread
From: Martin Sebor @ 2015-12-16 15:57 UTC (permalink / raw)
  To: Tom de Vries, Jason Merrill, Gcc Patch List

> I think this caused PR68932 - FAIL:
> obj-c++.dg/property/at-property-23.mm -fgnu-runtime (internal compiler
> error)

Sorry about that. I'll look into it today.

Martin

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Ping [PATCH] c++/42121 - diagnose invalid flexible array members
  2015-12-16  7:53         ` Tom de Vries
  2015-12-16 15:57           ` Martin Sebor
@ 2015-12-16 15:57           ` Martin Sebor
  1 sibling, 0 replies; 12+ messages in thread
From: Martin Sebor @ 2015-12-16 15:57 UTC (permalink / raw)
  To: Tom de Vries, Jason Merrill, Gcc Patch List

> I think this caused PR68932 - FAIL:
> obj-c++.dg/property/at-property-23.mm -fgnu-runtime (internal compiler
> error)

Sorry about that. I'll look into it today.

Martin

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2015-12-16 15:57 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-11-21 22:26 [PATCH] c++/42121 - diagnose invalid flexible array members Martin Sebor
2015-12-04  4:42 ` Ping " Martin Sebor
2015-12-04 11:33   ` Bernd Schmidt
2015-12-04 16:15   ` Joseph Myers
2015-12-04 17:51   ` Jason Merrill
2015-12-08 16:59     ` Martin Sebor
2015-12-14 16:45       ` Martin Sebor
2015-12-14 16:50         ` Jakub Jelinek
2015-12-14 20:32         ` Jason Merrill
2015-12-16  7:53         ` Tom de Vries
2015-12-16 15:57           ` Martin Sebor
2015-12-16 15:57           ` Martin Sebor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).