PR c++/71912 - [6/7 regression] flexible array in struct in union rejected
authorMartin Sebor <msebor@gcc.gnu.org>
Thu, 13 Oct 2016 22:26:36 +0000 (16:26 -0600)
committerMartin Sebor <msebor@gcc.gnu.org>
Thu, 13 Oct 2016 22:26:36 +0000 (16:26 -0600)
gcc/cp/ChangeLog:

PR c++/71912
* class.c (struct flexmems_t):  Add members.
(find_flexarrays): Add arguments.  Correct handling of anonymous
structs.
(diagnose_flexarrays): Adjust to issue warnings in addition to errors.
(check_flexarrays): Add argument.
(diagnose_invalid_flexarray): New functions.

gcc/testsuite/ChangeLog:

PR c++/71912
* g++.dg/ext/flexary4.C: Adjust.
* g++.dg/ext/flexary5.C: Same.
* g++.dg/ext/flexary9.C: Same.
* g++.dg/ext/flexary19.C: New test.
* g++.dg/ext/flexary18.C: New test.
* g++.dg/torture/pr64312.C: Add a dg-error directive to an ill-formed
regression test.
        * g++.dg/compat/struct-layout-1_generate.c (subfield): Add argument.
        Avoid generating a flexible array member in an array.

From-SVN: r241143

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/compat/struct-layout-1_generate.c
gcc/testsuite/g++.dg/ext/flexary18.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/flexary19.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/flexary4.C
gcc/testsuite/g++.dg/ext/flexary5.C
gcc/testsuite/g++.dg/ext/flexary9.C
gcc/testsuite/g++.dg/torture/pr64312.C

index 5753ab1..cc16176 100644 (file)
@@ -1,3 +1,13 @@
+2016-10-13  Martin Sebor  <msebor@redhat.com>
+
+       PR c++/71912
+       * class.c (struct flexmems_t):  Add members.
+       (find_flexarrays): Add arguments.  Correct handling of anonymous
+       structs.
+       (diagnose_flexarrays): Adjust to issue warnings in addition to errors.
+       (check_flexarrays): Add argument.
+       (diagnose_invalid_flexarray): New functions.
+
 2016-10-13  Jakub Jelinek  <jakub@redhat.com>
            Jason Merrill  <jason@redhat.com>
 
@@ -39,6 +49,7 @@
 
        * decl.c (mark_inline_variable): New.
 
+>>>>>>> .r241142
 2016-10-13  Thomas Preud'homme  <thomas.preudhomme@arm.com>
 
        * decl2.c: Include memmodel.h.
index 34d10ba..46f1bac 100644 (file)
@@ -147,11 +147,12 @@ 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.  */
+/* Used by find_flexarrays and related functions.  */
 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 find_flexarrays (tree, flexmems_t *, bool = false,
+                            tree = NULL_TREE, tree = NULL_TREE);
+static void check_flexarrays (tree, flexmems_t * = NULL, bool = false);
 static void check_bases (tree, int *, int *);
 static void check_bases_and_members (tree);
 static tree create_vtable_ptr (tree, tree *);
@@ -6692,52 +6693,147 @@ field_nonempty_p (const_tree fld)
   return false;
 }
 
-/* Used by find_flexarrays and related.  */
-struct flexmems_t {
+/* Used by find_flexarrays and related functions.  */
+
+struct flexmems_t
+{
   /* The first flexible array member or non-zero array member found
-     in order of layout.  */
+     in the 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;
+  /* The first non-static non-empty data member following either
+     the flexible array member, if found, or the zero-length array member
+     otherwise.  AFTER[1] refers to the first such data member of a union
+     of which the struct containing the flexible array member or zero-length
+     array is a member, or NULL when no such union exists.  This element is
+     only used during searching, not for diagnosing problems.  AFTER[0]
+     refers to the first such data member that is not a member of such
+     a union.  */
+  tree after[2];
+
+  /* Refers to a struct (not union) in which the struct of which the flexible
+     array is member is defined.  Used to diagnose strictly (according to C)
+     invalid uses of the latter structs.  */
+  tree enclosing;
 };
 
 /* 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.  */
+   array, in that order of preference, among members of class T (but not
+   its base classes), and set members of FMEM accordingly.
+   BASE_P is true if T is a base class of another class.
+   PUN is set to the outermost union in which the flexible array member
+   (or zero-length array) is defined if one such union exists, otherwise
+   to NULL.
+   Similarly, PSTR is set to a data member of the outermost struct of
+   which the flexible array is a member if one such struct exists,
+   otherwise to NULL.  */
 
 static void
-find_flexarrays (tree t, flexmems_t *fmem)
+find_flexarrays (tree t, flexmems_t *fmem, bool base_p,
+                tree pun /* = NULL_TREE */,
+                tree pstr /* = NULL_TREE */)
 {
-  for (tree fld = TYPE_FIELDS (t), next; fld; fld = next)
+  /* Set the "pointer" to the outermost enclosing union if not set
+     yet and maintain it for the remainder of the recursion.   */
+  if (!pun && TREE_CODE (t) == UNION_TYPE)
+    pun = t;
+
+  for (tree fld = TYPE_FIELDS (t); fld; fld = DECL_CHAIN (fld))
     {
-      /* Find the next non-static data member if it exists.  */
-      for (next = fld;
-          (next = DECL_CHAIN (next))
-            && TREE_CODE (next) != FIELD_DECL; );
+      if (fld == error_mark_node)
+       return;
 
-      tree fldtype = TREE_TYPE (fld);
-      if (TREE_CODE (fld) != TYPE_DECL
-         && RECORD_OR_UNION_TYPE_P (fldtype)
-         && TYPE_UNNAMED_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);
+      /* Is FLD a typedef for an anonymous struct?  */
+
+      /* FIXME: Note that typedefs (as well as arrays) need to be fully
+        handled elsewhere so that errors like the following are detected
+        as well:
+          typedef struct { int i, a[], j; } S;   // bug c++/72753
+          S s [2];                               // bug c++/68489
+      */
+      if (TREE_CODE (fld) == TYPE_DECL
+         && DECL_IMPLICIT_TYPEDEF_P (fld)
+         && CLASS_TYPE_P (TREE_TYPE (fld))
+         && anon_aggrname_p (DECL_NAME (fld)))
+       {
+         /* Check the nested unnamed type referenced via a typedef
+            independently of FMEM (since it's not a data member of
+            the enclosing class).  */
+         check_flexarrays (TREE_TYPE (fld));
          continue;
        }
 
-      /* Skip anything that's not a (non-static) data member.  */
-      if (TREE_CODE (fld) != FIELD_DECL)
+      /* Skip anything that's GCC-generated or not a (non-static) data
+        member.  */
+      if (DECL_ARTIFICIAL (fld) || TREE_CODE (fld) != FIELD_DECL)
        continue;
 
-      /* Skip virtual table pointers.  */
-      if (DECL_ARTIFICIAL (fld))
-       continue;
+      /* Type of the member.  */
+      tree fldtype = TREE_TYPE (fld);
+      if (fldtype == error_mark_node)
+       return;
+
+      /* Determine the type of the array element or object referenced
+        by the member so that it can be checked for flexible array
+        members if it hasn't been yet.  */
+      tree eltype = fldtype;
+      while (TREE_CODE (eltype) == ARRAY_TYPE
+            || TREE_CODE (eltype) == POINTER_TYPE
+            || TREE_CODE (eltype) == REFERENCE_TYPE)
+       eltype = TREE_TYPE (eltype);
+
+      if (RECORD_OR_UNION_TYPE_P (eltype))
+       {
+         if (fmem->array && !fmem->after[bool (pun)])
+           {
+             /* Once the member after the flexible array has been found
+                we're done.  */
+             fmem->after[bool (pun)] = fld;
+             break;
+           }
+
+         if (eltype == fldtype || TYPE_UNNAMED_P (eltype))
+           {
+             /* Descend into the non-static member struct or union and try
+                to find a flexible array member or zero-length array among
+                its members.  This is only necessary for anonymous types
+                and types in whose context the current type T has not been
+                defined (the latter must not be checked again because they
+                are already in the process of being checked by one of the
+                recursive calls).  */
+
+             tree first = fmem->first;
+             tree array = fmem->array;
+
+             /* If this member isn't anonymous and a prior non-flexible array
+                member has been seen in one of the enclosing structs, clear
+                the FIRST member since it doesn't contribute to the flexible
+                array struct's members.  */
+             if (first && !array && !ANON_AGGR_TYPE_P (eltype))
+               fmem->first = NULL_TREE;
+
+             find_flexarrays (eltype, fmem, false, pun,
+                              !pstr && TREE_CODE (t) == RECORD_TYPE ? fld : pstr);
+
+             if (fmem->array != array)
+               continue;
+
+             if (first && !array && !ANON_AGGR_TYPE_P (eltype))
+               {
+                 /* Restore the FIRST member reset above if no flexible
+                    array member has been found in this member's struct.  */
+                 fmem->first = first;
+               }
+
+             /* If the member struct contains the first flexible array
+                member, or if this member is a base class, continue to
+                the next member and avoid setting the FMEM->NEXT pointer
+                to point to it.  */
+             if (base_p)
+               continue;
+           }
+       }
 
       if (field_nonempty_p (fld))
        {
@@ -6748,8 +6844,8 @@ find_flexarrays (tree t, flexmems_t *fmem)
          /* 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;
+         if (fmem->array && !fmem->after[bool (pun)])
+           fmem->after[bool (pun)] = fld;
        }
 
       /* Skip non-arrays.  */
@@ -6765,13 +6861,16 @@ find_flexarrays (tree t, flexmems_t *fmem)
                 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;
+             if (!fmem->after[bool (pun)])
+               fmem->after[bool (pun)] = fld;
            }
          else if (integer_all_onesp (TYPE_MAX_VALUE (TYPE_DOMAIN (fldtype))))
-           /* Remember the first zero-length array unless a flexible array
-              member has already been seen.  */
-           fmem->array = fld;
+           {
+             /* Remember the first zero-length array unless a flexible array
+                member has already been seen.  */
+             fmem->array = fld;
+             fmem->enclosing = pstr;
+           }
        }
       else
        {
@@ -6782,16 +6881,39 @@ find_flexarrays (tree t, flexmems_t *fmem)
                 reset the after pointer.  */
              if (TYPE_DOMAIN (TREE_TYPE (fmem->array)))
                {
+                 fmem->after[bool (pun)] = NULL_TREE;
                  fmem->array = fld;
-                 fmem->after = NULL_TREE;
+                 fmem->enclosing = pstr;
                }
            }
          else
-           fmem->array = fld;
+           {
+             fmem->array = fld;
+             fmem->enclosing = pstr;
+           }
        }
     }
 }
 
+/* Diagnose a strictly (by the C standard) invalid use of a struct with
+   a flexible array member (or the zero-length array extension).  */
+
+static void
+diagnose_invalid_flexarray (const flexmems_t *fmem)
+{
+  if (fmem->array && fmem->enclosing
+      && pedwarn (location_of (fmem->enclosing), OPT_Wpedantic,
+                 TYPE_DOMAIN (TREE_TYPE (fmem->array))
+                 ? G_("invalid use of %q#T with a zero-size array "
+                      "in %q#D")
+                 : G_("invalid use of %q#T with a flexible array member "
+                      "in %q#T"),
+                 DECL_CONTEXT (fmem->array),
+                 DECL_CONTEXT (fmem->enclosing)))
+    inform (DECL_SOURCE_LOCATION (fmem->array),
+           "array member %q#D declared here", fmem->array);
+}
+
 /* Issue diagnostics for invalid flexible array members or zero-length
    arrays that are not the last elements of the containing class or its
    base classes or that are its sole members.  */
@@ -6799,49 +6921,70 @@ find_flexarrays (tree t, flexmems_t *fmem)
 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_UNNAMED_P (t) || !fmem->array)
+  if (!fmem->array)
     return;
 
+  if (fmem->first && !fmem->after[0])
+    {
+      diagnose_invalid_flexarray (fmem);
+      return;
+    }
+
+  /* Has a diagnostic been issued?  */
+  bool diagd = false;
+
   const char *msg = 0;
 
   if (TYPE_DOMAIN (TREE_TYPE (fmem->array)))
     {
-      if (fmem->after)
+      if (fmem->after[0])
        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))
+      if (msg)
+       {
+         location_t loc = DECL_SOURCE_LOCATION (fmem->array);
 
-       inform (location_of (t), "in the definition of %q#T", t);
+         if (pedwarn (loc, OPT_Wpedantic, msg, fmem->array, t))
+           {
+             inform (location_of (t), "in the definition of %q#T", t);
+             diagd = true;
+           }
+       }
     }
   else
     {
-      if (fmem->after)
+      if (fmem->after[0])
        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);
+         location_t loc = DECL_SOURCE_LOCATION (fmem->array);
+         diagd = true;
+
+         error_at (loc, 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.
+            array member is declared in a different class, or the member
+            overlaps another member of a common union, 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),
+         if (fmem->after[0]
+             && ((DECL_CONTEXT (fmem->after[0])
+                  != DECL_CONTEXT (fmem->array))))
+           {
+             inform (DECL_SOURCE_LOCATION (fmem->after[0]),
                      "next member %q#D declared here",
-                     fmem->after);
-
-         inform (location_of (t), "in the definition of %q#T", t);
+                     fmem->after[0]);
+             inform (location_of (t), "in the definition of %q#T", t);
+           }
        }
     }
+
+  if (!diagd && fmem->array && fmem->enclosing)
+    diagnose_invalid_flexarray (fmem);
 }
 
 
@@ -6854,7 +6997,8 @@ diagnose_flexarrays (tree t, const flexmems_t *fmem)
    that fails the checks.  */
 
 static void
-check_flexarrays (tree t, flexmems_t *fmem /* = NULL */)
+check_flexarrays (tree t, flexmems_t *fmem /* = NULL */,
+                 bool base_p /* = false */)
 {
   /* Initialize the result of a search for flexible array and zero-length
      array members.  Avoid doing any work if the most interesting FMEM data
@@ -6862,18 +7006,20 @@ check_flexarrays (tree t, flexmems_t *fmem /* = NULL */)
   flexmems_t flexmems = flexmems_t ();
   if (!fmem)
     fmem = &flexmems;
-  else if (fmem->array && fmem->first && fmem->after)
+  else if (fmem->array && fmem->first && fmem->after[0])
     return;
 
+  tree fam = fmem->array;
+
   /* 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);
+      check_flexarrays (basetype, fmem, true);
     }
 
   /* Recursively check the base classes.  */
-  int nbases = BINFO_N_BASE_BINFOS (TYPE_BINFO (t));
+  int nbases = TYPE_BINFO (t) ? BINFO_N_BASE_BINFOS (TYPE_BINFO (t)) : 0;
   for (int i = 0; i < nbases; ++i)
     {
       tree base_binfo = BINFO_BASE_BINFO (TYPE_BINFO (t), i);
@@ -6887,7 +7033,7 @@ check_flexarrays (tree t, flexmems_t *fmem /* = NULL */)
        continue;
 
       /* Check the base class.  */
-      check_flexarrays (BINFO_TYPE (base_binfo), fmem);
+      check_flexarrays (BINFO_TYPE (base_binfo), fmem, /*base_p=*/true);
     }
 
   if (fmem == &flexmems)
@@ -6904,17 +7050,26 @@ check_flexarrays (tree t, flexmems_t *fmem /* = NULL */)
          /* Check the virtual base class.  */
          tree basetype = TREE_TYPE (base_binfo);
 
-         check_flexarrays (basetype, fmem);
+         check_flexarrays (basetype, fmem, /*base_p=*/true);
        }
     }
 
-  /* Search the members of the current (derived) class.  */
-  find_flexarrays (t, fmem);
+  /* Is the type unnamed (and therefore a member of it potentially
+     an anonymous struct or union)?  */
+  bool maybe_anon_p = TYPE_UNNAMED_P (t);
 
-  if (fmem == &flexmems)
+  /* Search the members of the current (possibly derived) class, skipping
+     unnamed structs and unions since those could be anonymous.  */
+  if (fmem != &flexmems || !maybe_anon_p)
+    find_flexarrays (t, fmem, base_p || fam != fmem->array);
+
+  if (fmem == &flexmems && !maybe_anon_p)
     {
-      /* Issue diagnostics for invalid flexible and zero-length array members
-        found in base classes or among the members of the current class.  */
+      /* Issue diagnostics for invalid flexible and zero-length array
+        members found in base classes or among the members of the current
+        class.  Ignore anonymous structs and unions whose members are
+        considered to be members of the enclosing class and thus will
+        be diagnosed when checking it.  */
       diagnose_flexarrays (t, fmem);
     }
 }
index 93bb49e..2978ca6 100644 (file)
 
 2016-10-13  Martin Sebor  <msebor@redhat.com>
 
+       PR c++/71912
+       * g++.dg/ext/flexary4.C: Adjust.
+       * g++.dg/ext/flexary5.C: Same.
+       * g++.dg/ext/flexary9.C: Same.
+       * g++.dg/ext/flexary19.C: New test.
+       * g++.dg/ext/flexary18.C: New test.
+       * g++.dg/torture/pr64312.C: Add a dg-error directive to an ill-formed
+       regression test.
+        * g++.dg/compat/struct-layout-1_generate.c (subfield): Add argument.
+        Avoid generating a flexible array member in an array.
+
+2016-10-13  Martin Sebor  <msebor@redhat.com>
+
        * gcc.dg/tree-ssa/builtin-sprintf-warn-1.c: Cast 0 to wint_t
        to placate -Wformat on targets where the type is not int.
 
        * gcc.target/msp430/function-attributes-2.c: New test.
        * gcc.target/msp430/function-attributes-3.c: New test.
 
+2015-04-18  Martin Sebor  <msebor@redhat.com>
+
+       * gfortran.dg/pr32627.f03 (strptr): Change size to match the number
+       of non-nul characters.
+       * gfortran.dg/substr_6.f90: Make the NUL character visible on stdout
+
 2016-09-13  Jakub Jelinek  <jakub@redhat.com>
 
        * g++.dg/cpp0x/gen-attrs-61.C: New test.
index 71d4af9..8b620e4 100644 (file)
@@ -495,7 +495,16 @@ struct types attrib_array_types[] = {
 #define HASH_SIZE 32749
 static struct entry *hash_table[HASH_SIZE];
 
-static int idx, limidx, output_one, short_enums;
+/* The index of the current type being output.  */
+static int idx;
+
+/* The maximum index of the type(s) to output.  */
+static int limidx;
+
+/* Set to non-zero to output a single type in response to the -i option
+   (which sets LIMIDX to the index of the type to output.  */
+static int output_one;
+static int short_enums;
 static const char *destdir;
 static const char *srcdir;
 static const char *srcdir_safe;
@@ -535,6 +544,7 @@ switchfiles (int fields)
       fputs ("failed to create test files\n", stderr);
       exit (1);
     }
+
   for (i = 0; i < NDG_OPTIONS; i++)
     fprintf (outfile, dg_options[i], "", srcdir_safe);
   fprintf (outfile, "\n\
@@ -607,9 +617,14 @@ getrandll (void)
 
 /* 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*/
+   prevents subsequent fields from being generated (a flexible array member
+   must be the last member of the struct it's defined in).  ARRAY is non-
+   zero when the enclosing structure is part of an array.  In that case,
+   avoid generating a flexible array member as a subfield (such a member
+   would be invalid).  */
+
 int
-subfield (struct entry *e, char *letter, int *flex)
+subfield (struct entry *e, char *letter, int *flex, int array)
 {
   int i, type;
   char buf[20];
@@ -664,7 +679,14 @@ subfield (struct entry *e, char *letter, int *flex)
        }
 
       for (i = 1; !*flex && i <= e[0].len; )
-       i += subfield (e + i, letter, flex);
+       {
+         /* Avoid generating flexible array members if the enclosing
+            type is an array.  */
+         int array
+           = (e[0].etype == ETYPE_STRUCT_ARRAY
+              || e[0].etype == ETYPE_UNION_ARRAY);
+           i += subfield (e + i, letter, flex, array);
+       }
 
       switch (type)
        {
@@ -685,7 +707,7 @@ subfield (struct entry *e, char *letter, int *flex)
     case ETYPE_ARRAY:
       if (e[0].etype == ETYPE_ARRAY)
        {
-         if (e[0].arr_len == 255)
+         if (!array && e[0].arr_len == 255)
            {
              *flex = 1;
              snprintf (buf, 20, "%c[]", *letter);
@@ -1141,6 +1163,7 @@ e_insert (struct entry *e)
   hash_table[hval % HASH_SIZE] = e;
 }
 
+/* Output a single type.  */
 void
 output (struct entry *e)
 {
@@ -1169,7 +1192,7 @@ output (struct entry *e)
 
   int flex = 0;
   for (i = 1; i <= e[0].len; )
-    i += subfield (e + i, &c, &flex);
+    i += subfield (e + i, &c, &flex, 0);
   
   fputs (",", outfile);
   c = 'a';
diff --git a/gcc/testsuite/g++.dg/ext/flexary18.C b/gcc/testsuite/g++.dg/ext/flexary18.C
new file mode 100644 (file)
index 0000000..4353425
--- /dev/null
@@ -0,0 +1,213 @@
+// PR c++/71912 - [6/7 regression] flexible array in struct in union rejected
+// { dg-do compile }
+// { dg-additional-options "-Wpedantic -Wno-error=pedantic" }
+
+#if __cplusplus
+
+namespace pr71912 {
+
+#endif
+
+struct foo {
+  int a;
+  char s[];                             // { dg-message "array member .char pr71912::foo::s \\\[\\\]. declared here" }
+};
+
+struct bar {
+  double d;
+  char t[];
+};
+
+struct baz {
+  union {
+    struct foo f;
+    struct bar b;
+  }
+  // The definition of struct foo is fine but the use of struct foo
+  // in the definition of u below is what's invalid and must be clearly
+  // diagnosed.
+    u;                                  // { dg-warning "invalid use of .struct pr71912::foo. with a flexible array member in .struct pr71912::baz." }
+};
+
+struct xyyzy {
+  union {
+    struct {
+      int a;
+      char s[];                         // { dg-message "declared here" }
+    } f;
+    struct {
+      double d;
+      char t[];
+    } b;
+  } u;                                  // { dg-warning "invalid use" }
+};
+
+struct baz b;
+struct xyyzy x;
+
+#if __cplusplus
+
+}
+
+#endif
+
+// The following definitions aren't strictly valid but, like those above,
+// are accepted for compatibility with GCC (in C mode).  They are benign
+// in that the flexible array member is at the highest offset within
+// the outermost type and doesn't overlap with other members except for
+// those of the union.
+union UnionStruct1 {
+  struct { int n1, a[]; } s;
+  int n2;
+};
+
+union UnionStruct2 {
+  struct { int n1, a1[]; } s1;
+  struct { int n2, a2[]; } s2;
+  int n3;
+};
+
+union UnionStruct3 {
+  struct { int n1, a1[]; } s1;
+  struct { double n2, a2[]; } s2;
+  char n3;
+};
+
+union UnionStruct4 {
+  struct { int n1, a1[]; } s1;
+  struct { struct { int n2, a2[]; } s2; } s3;
+  char n3;
+};
+
+union UnionStruct5 {
+  struct { struct { int n1, a1[]; } s1; } s2;   // { dg-warning "invalid use" }
+  struct { double n2, a2[]; } s3;
+  char n3;
+};
+
+union UnionStruct6 {
+  struct { struct { int n1, a1[]; } s1; } s2;   // { dg-warning "invalid use" }
+  struct { struct { int n2, a2[]; } s3; } s4;
+  char n3;
+};
+
+union UnionStruct7 {
+  struct { int n1, a1[]; } s1;
+  struct { double n2, a2[]; } s2;
+  struct { struct { int n3, a3[]; } s3; } s4;
+};
+
+union UnionStruct8 {
+  struct { int n1, a1[]; } s1;
+  struct { struct { int n2, a2[]; } s2; } s3;
+  struct { struct { int n3, a3[]; } s4; } s5;
+};
+
+union UnionStruct9 {
+  struct { struct { int n1, a1[]; } s1; } s2;   // { dg-warning "invalid use" }
+  struct { struct { int n2, a2[]; } s3; } s4;
+  struct { struct { int n3, a3[]; } s5; } s6;
+};
+
+struct StructUnion1 {
+  union {
+    struct { int n1, a1[]; } s1;        // { dg-message "declared here" }
+    struct { double n2, a2[]; } s2;
+    char n3;
+  } u;                                  // { dg-warning "invalid use" }
+};
+
+// The following are invalid and rejected.
+struct StructUnion2 {
+  union {
+    struct { int n1, a1[]; } s1;        // { dg-error "not at end" }
+  } u;
+  char n3;                              // { dg-message "next member" }
+};
+
+struct StructUnion3 {
+  union {
+    struct { int n1, a1[]; } s1;        // { dg-error "not at end" }
+    struct { double n2, a2[]; } s2;
+  } u;
+  char n3;                              // { dg-message "next member" }
+};
+
+struct StructUnion4 {
+  union {
+    struct { int n1, a1[]; } s1;        // { dg-error "not at end" }
+  } u1;
+  union {
+    struct { double n2, a2[]; } s2;
+  } u2;                                 // { dg-message "next member" }
+};
+
+struct StructUnion5 {
+  union {
+    union {
+      struct { int n1, a1[]; } s1;      // { dg-message "declared here" }
+    } u1;
+    union { struct { int n2, a2[]; } s2; } u2;
+  } u;                                  // { dg-warning "invalid use" }
+};
+
+struct StructUnion6 {
+  union {
+    struct { int n1, a1[]; } s1;        // { dg-message "declared here" }
+    union { struct { int n2, a2[]; } s2; } u2;
+  } u;                                  // { dg-warning "invalid use" }
+};
+
+struct StructUnion7 {
+  union {
+    union {
+      struct { double n2, a2[]; } s2;   // { dg-message "declared here" }
+    } u2;
+    struct { int n1, a1[]; } s1;
+  } u;                                  // { dg-warning "invalid use" }
+};
+
+struct StructUnion8 {
+  struct {
+    union {
+      union {
+       struct { int n1, a1[]; } s1;    // { dg-error "not at end" }
+      } u1;
+      union {
+       struct { double n2, a2[]; } s2;
+      } u2;
+    } u;
+  } s1;
+
+  struct {
+    union {
+      union {
+       struct { int n1, a1[]; } s1;
+      } u1;
+      union {
+       struct { double n2, a2[]; } s2;
+      } u2;
+    } u; } s2;                              // { dg-message "next member" }
+};
+
+struct StructUnion9 {                       // { dg-message "in the definition" }
+  struct A1 {
+    union B1 {
+      union C1 {
+       struct Sx1 { int n1, a1[]; } sx1;   // { dg-error "not at end" }
+      } c1;
+      union D1 {
+       struct Sx2 { double n2, a2[]; } sx2;
+      } d1;
+    } b1;                                   // { dg-warning "invalid use" }
+  } a1;
+
+  struct A2 {
+    union B2 {
+      union C2 {
+       struct Sx3 { int n3, a3[]; } sx3;   // { dg-message "declared here" }
+      } c2;
+      union D2 { struct Sx4 { double n4, a4[]; } sx4; } d2;
+    } b2;                                   // { dg-warning "invalid use" }
+  } a2;                                     // { dg-message "next member" }
+};
diff --git a/gcc/testsuite/g++.dg/ext/flexary19.C b/gcc/testsuite/g++.dg/ext/flexary19.C
new file mode 100644 (file)
index 0000000..27d08ec
--- /dev/null
@@ -0,0 +1,343 @@
+// { dg-do compile }
+// { dg-additional-options "-Wpedantic -Wno-error=pedantic" }
+
+// Verify that flexible array members are recognized as either valid
+// or invalid in anonymous structs (a G++ extension) and C++ anonymous
+// unions as well as in structs and unions that look anonymous but
+// aren't.
+struct S1
+{
+  int i;
+
+  // The following declares a named data member of an unnamed struct
+  // (i.e., it is not an anonymous struct).
+  struct {
+    int a[];        // { dg-error "in an otherwise empty" }
+  } s;
+};
+
+struct S2
+{
+  int i;
+
+  struct {
+    int a[];        // { dg-error "in an otherwise empty" }
+  } s[1];
+};
+
+struct S3
+{
+  int i;
+
+  struct {
+    int a[];        // { dg-error "in an otherwise empty" }
+  } s[];
+};
+
+struct S4
+{
+  int i;
+
+  struct {
+    int a[];        // { dg-error "in an otherwise empty" }
+  } s[2];
+};
+
+struct S5
+{
+  int i;
+
+  struct {
+    int a[];        // { dg-error "in an otherwise empty" }
+  } s[1][2];
+};
+
+struct S6
+{
+  int i;
+
+  struct {
+    int a[];        // { dg-error "in an otherwise empty" }
+  } s[][2];
+};
+
+struct S7
+{
+  int i;
+
+  struct {
+    int a[];        // { dg-error "in an otherwise empty" }
+  } *s;
+};
+
+struct S8
+{
+  int i;
+
+  struct {
+    int a[];        // { dg-error "in an otherwise empty" }
+  } **s;
+};
+
+struct S9
+{
+  int i;
+
+  struct {
+    int a[];        // { dg-error "in an otherwise empty" }
+  } *s[1];
+};
+
+struct S10
+{
+  int i;
+
+  struct {
+    int a[];        // { dg-error "in an otherwise empty" }
+  } *s[];
+};
+
+struct S11
+{
+  int i;
+
+  struct {
+    int a[];        // { dg-error "in an otherwise empty" }
+  } **s[1];
+};
+
+struct S12
+{
+  int i;
+
+  struct {
+    int a[];        // { dg-error "in an otherwise empty" }
+  } **s[];
+};
+
+struct S13
+{
+  int i;
+
+  struct {
+    int a[];        // { dg-error "in an otherwise empty" }
+  } **s[2];
+};
+
+struct S14
+{
+  int i;
+
+  struct {
+    int a[];        // { dg-error "in an otherwise empty" }
+  } &s;
+};
+
+struct S15
+{
+  int i;
+
+  typedef struct {
+    int a[];        // { dg-error "in an otherwise empty" }
+  } T15;
+};
+
+struct S16
+{
+  int i;
+
+  struct {          // { dg-warning "invalid use" }
+    // A flexible array as a sole member of an anonymous struct is
+    // rejected with an error in C mode but emits just a pedantic
+    // warning in C++.  Other than excessive pedantry there is no
+    // reason to reject it.
+    int a[];
+  };                // { dg-warning "anonymous struct" }
+};
+
+struct S17
+{
+  int i;
+
+  union {           // anonymous union
+    int a[];        // { dg-error "flexible array member in union" }
+  };
+};
+
+struct S18
+{
+  int i;
+
+  struct {
+    int j, a[];     // { dg-message "declared here" }
+  } s;              // { dg-warning "invalid use" }
+};
+
+struct S19
+{
+  int i;
+
+  struct {          // { dg-warning "invalid use" }
+    int j, a[];     // { dg-message "declared here" }
+  };                // { dg-warning "anonymous struct" }
+};
+
+struct S20
+{
+  static int i;
+  typedef int A[];
+
+  struct {
+    int j;
+    A a;            // { dg-message "declared here" }
+  } s;              // { dg-warning "invalid use" }
+};
+
+struct S21
+{
+  static int i;
+  typedef int A[];
+
+  struct {          // { dg-warning "invalid use" }
+    int j;
+    A a;            // { dg-message "declared here" }
+  };                // { dg-warning "anonymous struct" }
+};
+
+struct S22
+{
+  struct S22S {
+    static int i;
+
+    int a[];        // { dg-error "in an otherwise empty" }
+  } s;
+};
+
+struct S23
+{
+  struct {
+    static int i;   // { dg-error "static data member" }
+
+    int a[];        // { dg-error "in an otherwise empty" }
+  };                // { dg-warning "anonymous struct" }
+};
+
+struct S24
+{
+  static int i;
+
+  struct {
+    int a[];        // { dg-error "in an otherwise empty" }
+  } s;
+};
+
+struct S25
+{
+  int i;
+
+  struct {
+    int j, a[];     // { dg-message "declared here" }
+  } s;              // { dg-warning "invalid use" }
+
+  // Verify that a static data member of the enclosing class doesn't
+  // cause infinite recursion or some such badness.
+  static S25 s2;
+};
+
+struct S26
+{
+  template <class>
+  struct S26S {
+    static int a;
+  };
+
+  struct {
+    int a[];        // { dg-error "in an otherwise empty" }
+  } s;
+};
+
+struct S27
+{
+  S27 *p;
+  int a[];
+};
+
+struct S28
+{
+  struct A {
+    struct B {
+      S28 *ps28;
+      A   *pa;
+      B   *pb;
+    } b, *pb;
+    A *pa;
+  } a, *pa;
+
+  S28::A *pa2;
+  S28::A::B *pb;
+
+  int flexarray[];
+};
+
+// Verify that the notes printed along with the warnings point to the types
+// or members they should point to and mention the correct relationships
+// with the flexible array members.
+namespace Notes
+{
+union A
+{
+  struct {
+    struct {
+      int i, a[];   // { dg-message "declared here" }
+    } c;            // { dg-warning "invalid use" }
+  } d;
+  int j;
+};
+
+union B
+{
+  struct {
+    struct {        // { dg-warning "invalid use" }
+      int i, a[];   // { dg-message "declared here" }
+    };              // { dg-warning "anonymous struct" }
+  };                // { dg-warning "anonymous struct" }
+  int j;
+};
+
+}
+
+typedef struct Opaque* P29;
+struct S30 { P29 p; };
+struct S31 { S30 s; };
+
+typedef struct { } S32;
+typedef struct { S32 *ps32; } S33;
+typedef struct
+{
+  S33 *ps33;
+} S34;
+
+struct S35
+{
+  struct A {
+    int i1, a1[];
+  };
+
+  struct B {
+    int i2, a2[];
+  };
+
+  typedef struct {
+    int i3, a3[];
+  } C;
+
+  typedef struct {
+    int i4, a4[];
+  } D;
+
+  typedef A A2;
+  typedef B B2;
+  typedef C C2;
+  typedef D D2;
+};
+
index 97ec625..29d6bdd 100644 (file)
@@ -102,31 +102,28 @@ struct Sx17 {
   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
+// An empty struct is treated as if it had a single member of type
+// char but the member cannot be accessed.  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 { };
+  struct { /* empty */ } 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.
+// Anonymous structs are a G++ extension.  Members of anonymous structs
+// are treated as if they were declared in the enclosing class.
 struct Sx19 {
-  struct S { };
-  union U { };
-  int a_x [];               // { dg-error "in an otherwise empty" }
+  struct { int i; };        // anonymous struct
+  int a_x [];
 };
 
-// Unlike in the case above, a named member of an anonymous struct
-// prevents a subsequent flexible array member from being diagnosed.
+// Unlike in the case above, a named struct is not anonymous and
+// so doesn't contribute its member to that of the enclosing struct.
 struct Sx20 {
-  struct S { } s;
-  int a_x [];
+  struct S { int i; };
+  int a_x [];               // { dg-error "in an otherwise empty" }
 };
 
 struct Sx21 {
@@ -298,6 +295,15 @@ struct Anon1 {
 
 ASSERT_AT_END (Anon1, good);
 
+struct NotAnon1 {
+  int n;
+  // The following is not an anonymous struct -- the type is unnamed
+  // but the object has a name.
+  struct {
+    int bad[];              // { dg-error "otherwise empty" }
+  } name;
+};
+
 struct Anon2 {
   struct {
     int n;
@@ -352,7 +358,6 @@ struct Anon7 {
   int n;
 };
 
-
 struct Six {
   int i;
   int a[];
index 3e76d3e..d6d8e32 100644 (file)
@@ -64,19 +64,29 @@ struct D5: E1, E2, NE { char a[]; };
 
 ASSERT_AT_END (D5, a);   // { dg-warning "offsetof within non-standard-layout" }
 
-struct A2x {
+struct A2x_1 {
   size_t n;
-  size_t a[];   // { dg-error "not at end of .struct D6.| D7.| D8." }
+  size_t a[];   // { dg-error "not at end of .struct D6." }
+};
+
+struct A2x_2 {
+  size_t n;
+  size_t a[];   // { dg-error "not at end of .struct D7." }
+};
+
+struct A2x_3 {
+  size_t n;
+  size_t a[];   // { dg-error "not at end of .struct 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 D6: A2x_1, E1, A1x { };
+struct D7: E1, A2x_2, E2, A1x { };
+struct D8: E1, E2, A2x_3, A1x { };
 
-struct DA2x: A2x { };
+struct DA2x: A2x_1 { };
 
 struct D9: DA2x, E1, E2 { };
 
@@ -194,16 +204,27 @@ 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[];
+  size_t a[];               // { dg-error "flexible array member .A7x::a. not at end of .struct D33." }
 };
 
+// Verify that a flexible array member in a virtual base class is not
+// diagnosed.
 struct DA7xV1: virtual A7x { };
 struct DA7xV2: virtual A7x { };
 
 struct D30: DA7xV1, DA7xV2 { };
 struct D31: DA7xV1, DA7xV2 { };
 struct D32: D30, D31 { };
+
+// Verify the diagnostic when the flexible array is in an anonymous struct.
+struct A8x {
+  struct {                  // { dg-message "next member .A8x::<unnamed struct> A8x::<anonymous>. declared here" }
+    size_t n;
+    size_t a[];
+  };
+};
+
+struct D33:                 // { dg-message "in the definition of .struct D33." }
+  A7x, A8x { };
index 3228542..07eb966 100644 (file)
@@ -281,15 +281,15 @@ struct S_S_S_x {
 
 struct Anon1 {
   int n;
-  struct {
-    int good[0];            // { dg-warning "zero-size array" }
+  struct {                  // { dg-warning "invalid use \[^\n\r\]* with a zero-size array" }
+    int good[0];            // { dg-warning "forbids zero-size array" }
   };                        // { dg-warning "anonymous struct" }
 };
 
 ASSERT_AT_END (Anon1, good);
 
 struct Anon2 {
-  struct {
+  struct {                  // { dg-warning "invalid use" }
     int n;
     struct {
       int good[0];          // { dg-warning "zero-size array" }
@@ -300,7 +300,7 @@ struct Anon2 {
 ASSERT_AT_END (Anon2, good);
 
 struct Anon3 {
-  struct {
+  struct {                  // { dg-warning "invalid use" }
     struct {
       int n;
       int good[0];          // { dg-warning "zero-size array" }
index 85211f2..c7a56d7 100644 (file)
@@ -44,7 +44,7 @@ class F
 {
 public:
   int nelems;
-  int elems[];
+  int elems[];   // { dg-error "not at end" }
   int *
   m_fn1 ()
   {
@@ -88,7 +88,7 @@ public:
       m_impl->~any_incrementable_iterator_interface ();
   }
   G m_buffer;
-  any_incrementable_iterator_interface *m_impl;
+  any_incrementable_iterator_interface *m_impl;   // { dg-message "next member" }
 };
 template <class Reference> class K : public I<any_iterator<Reference> >
 {