struct-layout-1_generate.c: Avoid generating further fields after the first flexible...
authorMartin Sebor <msebor@redhat.com>
Tue, 15 Dec 2015 21:04:08 +0000 (21:04 +0000)
committerMartin Sebor <msebor@gcc.gnu.org>
Tue, 15 Dec 2015 21:04:08 +0000 (14:04 -0700)
gcc/testsuite/ChangeLog:
2015-12-15  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-15  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-15  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 (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.

From-SVN: r231665

27 files changed:
gcc/ChangeLog
gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/decl.c
gcc/cp/error.c
gcc/cp/init.c
gcc/cp/pt.c
gcc/cp/typeck2.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/compat/struct-layout-1_generate.c
gcc/testsuite/g++.dg/ext/flexary.h [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/flexary2.C
gcc/testsuite/g++.dg/ext/flexary3.C
gcc/testsuite/g++.dg/ext/flexary4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/flexary5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/flexary6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/flexary7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/flexary8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/flexary9.C [new file with mode: 0644]
gcc/testsuite/g++.dg/other/dump-ada-spec-2.C
gcc/testsuite/g++.dg/parse/pr43765.C
gcc/testsuite/g++.dg/torture/pr64280.C
gcc/testsuite/g++.dg/torture/pr64312.C
gcc/testsuite/g++.dg/ubsan/object-size-1.C
gcc/tree-chkp.c
gcc/tree.c
gcc/varasm.c

index f48dfe74b0cc645c0b47a6dca8a857348239154a..57f957503597da2e67ce06c4880c599f31f7998d 100644 (file)
@@ -1,3 +1,15 @@
+2015-12-15  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 (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.
+
 2015-12-15  Nathan Sidwell  <nathan@acm.org>
 
        * config/nvptx/nvptx.c (write_one_arg): Rename to ...
index 0598be5a2f54db48759da760925931748c11fcda..a23d05f7bd214d27a621023513aa6c82b984623f 100644 (file)
@@ -1,3 +1,30 @@
+2015-12-15  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.
+
 2015-12-15  Patrick Palka  <ppalka@gcc.gnu.org>
 
        PR c++/21802
index 216a30141d486755a2479c6472dd72fc1475d45b..ab9ba26cef38bd13b10e0547bf836a5dd2bc88bd 100644 (file)
@@ -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.  */
@@ -6531,7 +6541,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 +6607,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 containing 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 +6924,11 @@ finish_struct_1 (tree t)
        needs a mode.  */
     compute_record_mode (CLASSTYPE_AS_BASE (t));
 
+  /* With the layout complete, check for flexible array members and
+     zero-length arrays that might overlap other members in the final
+     layout.  */
+  check_flexarrays (t);
+
   virtuals = modify_all_vtables (t, nreverse (virtuals));
 
   /* If necessary, create the primary vtable for this class.  */
index 62636c9eefaed72def3ec29d6b5950b0711ed0af..77358c4c6856d290ea302fb0047237c3d13cfcdc 100644 (file)
@@ -8627,8 +8627,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)
@@ -8636,6 +8637,9 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
   tree itype;
   tree osize = size;
 
+  if (size == NULL_TREE)
+    return build_index_type (NULL_TREE);
+
   if (error_operand_p (size))
     return error_mark_node;
 
@@ -10905,7 +10909,7 @@ grokdeclarator (const cp_declarator *declarator,
     }
 
   {
-    tree decl;
+    tree decl = NULL_TREE;
 
     if (decl_context == PARM)
       {
@@ -10929,9 +10933,18 @@ 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,
-                                                  tf_warning_or_error);
-           type = build_cplus_array_type (TREE_TYPE (type), itype);
+           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)
@@ -11099,17 +11112,21 @@ grokdeclarator (const cp_declarator *declarator,
                     || !COMPLETE_TYPE_P (TREE_TYPE (type))
                     || initialized == 0))
          {
-           if (unqualified_id)
+           if (TREE_CODE (type) != ARRAY_TYPE
+               || !COMPLETE_TYPE_P (TREE_TYPE (type)))
              {
-               error ("field %qD has incomplete type %qT",
-                      unqualified_id, type);
-               cxx_incomplete_type_inform (strip_array_types (type));
-             }
-           else
-             error ("name %qT has incomplete type", type);
+               if (unqualified_id)
+                 {
+                   error ("field %qD has incomplete type %qT",
+                          unqualified_id, type);
+                   cxx_incomplete_type_inform (strip_array_types (type));
+                 }
+               else
+                 error ("name %qT has incomplete type", type);
 
-           type = error_mark_node;
-           decl = NULL_TREE;
+               type = error_mark_node;
+               decl = NULL_TREE;
+             }
          }
        else
          {
index e0ba806b32d571fc216198c97bc4aaf95ceedfb1..412d6381b163cb4f3a4b7d4a4cc1d4248faf6298 100644 (file)
@@ -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);
index 5ecf9fb1cad492c64ec3a9e04fcde072340991f2..a08f7d70b258e5b2b7019e249c153d86e92bcd2d 100644 (file)
@@ -729,9 +729,14 @@ perform_member_init (tree member, tree init)
              || same_type_ignoring_top_level_qualifiers_p (type,
                                                            TREE_TYPE (init)))
            {
-             init = build_vec_init_expr (type, init, tf_warning_or_error);
-             init = build2 (INIT_EXPR, type, decl, init);
-             finish_expr_stmt (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);
index a45e6df9e8b0b1bb2927b41a1c03e954e2704daf..8a39ca4861abc917de22ffd2a4883e2ef7d59385 100644 (file)
@@ -10026,7 +10026,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;
@@ -12763,9 +12772,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)
-       return t;
+      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);
index 839091c565ec473e0864fb0597c5c089174b5298..68d2e7110b86337f544134704803a192fb25ad30 100644 (file)
@@ -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);
index 17c1b661e198ae2e20b8b59bb6f73dfee21bf3a8..7e45765159c78eede71b9374ec9431bd07277ef9 100644 (file)
@@ -1,3 +1,32 @@
+2015-12-15  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.
+
 2015-12-15  Marek Polacek  <polacek@redhat.com>
 
        PR c/68907
index 2884c25f337260a2c46299bd12af028f526afe15..9fab3a8d0f7860a7ca627a17fb654045fc232aca 100644 (file)
@@ -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,7 +686,10 @@ 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);
+           }
          else
            snprintf (buf, 20, "%c[%d]", *letter, e[0].arr_len);
        }
@@ -1157,8 +1166,11 @@ output (struct entry *e)
   else
     fprintf (outfile, "U(%d,", idx);
   c = 'a';
+
+  int flex = 0;
   for (i = 1; i <= e[0].len; )
-    i += subfield (e + i, &c);
+    i += subfield (e + i, &c, &flex);
+  
   fputs (",", outfile);
   c = 'a';
   for (i = 1; i <= e[0].len; )
diff --git a/gcc/testsuite/g++.dg/ext/flexary.h b/gcc/testsuite/g++.dg/ext/flexary.h
new file mode 100644 (file)
index 0000000..a8dff7d
--- /dev/null
@@ -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;
index 4855b3f5725c4f91b3fe2c5da70aff05652dafdd..c0253777a1e967d47e752278b00966c028966b65 100644 (file)
@@ -1,11 +1,23 @@
-// 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 {
-   A(int);
+  A(int);
 };
 
 struct B {
-   B() {}
-   A a[];
+  B() {}
+  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
 };
+
index 906877b11b780e88ee88b4c48e18876e7ca02996..c7c0e79335546498891f58ceb89d6b56a1debc00 100644 (file)
@@ -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 (file)
index 0000000..97ec625
--- /dev/null
@@ -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 (file)
index 0000000..3e76d3e
--- /dev/null
@@ -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 (file)
index 0000000..92677cd
--- /dev/null
@@ -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 (file)
index 0000000..fdea4d4
--- /dev/null
@@ -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 (file)
index 0000000..7a1811d
--- /dev/null
@@ -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 (file)
index 0000000..3228542
--- /dev/null
@@ -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];
+};
index 87c183aab66e5e45df0139be1df129336ed9878d..d1af7e028fedb784dd2c7b14509f68984733331b 100644 (file)
@@ -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 } } */
index 0b341ddb8ab1d4e5d6855492a037062930b44f53..800f2c7cbbb316be00c0a983ca0c2397caf0e64c 100644 (file)
@@ -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)
index 6ea31481bd57a1add5f11054c20da6b2b8af5ed7..e756e02eca1f49f13c486f66fc4028b8d0c6899d 100644 (file)
@@ -15,7 +15,7 @@ public:
 typedef int jmp_buf[];
 struct C
 {
-  jmp_buf cond_;
+  jmp_buf cond_;   // { dg-error "flexible array member" }
 };
 class F
 {
index dc3e95dbb9440453de089ab446373965b2c77337..85211f25d265ab83b1d27763d93f0be85a146b3d 100644 (file)
@@ -43,6 +43,7 @@ protected:
 class F
 {
 public:
+  int nelems;
   int elems[];
   int *
   m_fn1 ()
index e2aad4670bbb16c3a84fa95eb6e7efe28a3f038a..e6cdefc5c7b1e0f360e21991b3c032a5872d5d82 100644 (file)
@@ -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)
index b666e9706432e5bde07633d57f0c97e3cfd4e7ab..3768bc80c447fd82c9eb3f6b7deb05adbddcd885 100644 (file)
@@ -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));
index 21c5fe1652ea13a215b69d6f6371677322c67e91..66c06c992f6b30fb6bf3b572ac8e72c1ce056626 100644 (file)
@@ -3581,9 +3581,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:
index c4c55e7cd06fd1cec6d3664ffe9cacd007a58a6d..643d682dc19164e9b304825325737c1b2c321e98 100644 (file)
@@ -4974,13 +4974,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 +5198,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;