Bootstrapped and regression tested on x86_64.


    c: harmonize handling of arrays of zero size
    
    Use common functions for creating and detecting arrays of zero size.
    The function to detect arrays of zero size is changed to also accept
    C++ style representation that are somtimes created (at least in
    complete_array_type).  A future change may switch to only use this
    representation.  Other code is refactored to use the new helper functions
    and to use flexible_array_member_type_p to properly distinguish between
    the two cases (instead of checking for TYPE_MAX_VALUE being NULL_TREE).
    As part of this, the explict check for complete types is removed from
    composite_type_internal, which may be helpful when potentially allowing
    arrays with incomplete element type (which also occur already for
    built-in va_arg types).
    
    gcc/ChangeLog:
            * c/c-tree.h (zero_length_array_type_p,
            c_build_array_type_zero_size) Add prototypes.
            * c/c-decl.cc (zero_length_array_type_p): External linkage.
            (c_build_array_type_zero_size): New.
            (grokdeclarator): Use new function.
            * c/c-typeck.cc (c_verify_type): New consistency checks.
            (c_build_array_type_zero_size): New function
            (composite_type_internal): Refactor.
            (comptypes_internal): Refactor.

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 39951db5c01..4ed19776a63 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5536,15 +5536,15 @@ one_element_array_type_p (const_tree type)
 }
 
 /* Determine whether TYPE is a zero-length array type "[0]".  */
-static bool
+bool
 zero_length_array_type_p (const_tree type)
 {
-  if (TREE_CODE (type) == ARRAY_TYPE)
-    if (tree type_size = TYPE_SIZE_UNIT (type))
-      if ((integer_zerop (type_size))
-          && TYPE_DOMAIN (type) != NULL_TREE
-          && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE)
-       return true;
+  if (TREE_CODE (type) == ARRAY_TYPE
+      && COMPLETE_TYPE_P (type)
+      && TYPE_DOMAIN (type) != NULL_TREE
+      && (TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE
+         || integer_all_onesp (TYPE_MAX_VALUE (TYPE_DOMAIN (type)))))
+    return true;
   return false;
 }
 
@@ -7587,8 +7587,16 @@ grokdeclarator (const struct c_declarator *declarator,
                                                 ENCODE_QUAL_ADDR_SPACE (as));
                if (array_parm_vla_unspec_p)
                  type = c_build_array_type_unspecified (type);
+               /* The GCC extension for zero-length arrays differs from
+                  ISO flexible array members in that sizeof yields
+                  zero.  */
+               else if (size && integer_zerop (size))
+                 type = c_build_array_type_zero_size (type);
                else
                  type = c_build_array_type (type, itype);
+
+               if (!valid_array_size_p (loc, type, name))
+                 type = error_mark_node;
              }
 
            if (array_parm_vla_unspec_p)
@@ -7607,23 +7615,6 @@ grokdeclarator (const struct c_declarator *declarator,
                size_varies = true;
              }
 
-           if (type != error_mark_node)
-             {
-               /* The GCC extension for zero-length arrays differs from
-                  ISO flexible array members in that sizeof yields
-                  zero.  */
-               if (size && integer_zerop (size))
-                 {
-                   gcc_assert (itype);
-                   type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type));
-                   TYPE_SIZE (type) = bitsize_zero_node;
-                   TYPE_SIZE_UNIT (type) = size_zero_node;
-                   SET_TYPE_STRUCTURAL_EQUALITY (type);
-                 }
-
-               if (!valid_array_size_p (loc, type, name))
-                 type = error_mark_node;
-             }
 
            gcc_assert (type == error_mark_node
                        || flexible_array_member
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 27784a2ffba..c7f2328f998 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -846,6 +846,7 @@ c_type_unspecified_p (tree t)
         && integer_zerop (TREE_OPERAND (TYPE_MAX_VALUE (TYPE_DOMAIN (t)), 1));
 }
 
+extern bool zero_length_array_type_p (const_tree type);
 extern bool char_type_p (tree);
 extern tree c_type_tag (const_tree t);
 extern tree c_objc_common_truthvalue_conversion (location_t, tree,
@@ -960,6 +961,7 @@ extern tree c_build_type_attribute_variant (tree ntype, 
tree attrs);
 extern tree c_build_pointer_type (tree type);
 extern tree c_build_array_type (tree type, tree domain);
 extern tree c_build_array_type_unspecified (tree type);
+extern tree c_build_array_type_zero_size (tree type);
 extern tree c_build_function_type (tree type, tree args, bool no = false);
 extern tree c_build_pointer_type_for_mode (tree type, machine_mode mode, bool 
m);
 
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 86e088c582a..b169a0116f7 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -392,8 +392,7 @@ c_verify_type (tree type)
       if (!TYPE_STRUCTURAL_EQUALITY_P (type)
          && TYPE_STRUCTURAL_EQUALITY_P (TREE_TYPE (type)))
        return false;
-
-     default:
+    default:
        break;
     }
 
@@ -422,6 +421,29 @@ c_verify_type (tree type)
          if (!C_TYPE_VARIABLY_MODIFIED (type))
            return false;
        }
+
+      /* va_list violates this, accept such types here.  */
+      if (!COMPLETE_TYPE_P (TREE_TYPE (type)))
+       return true;
+
+      if (COMPLETE_TYPE_P (type))
+       {
+         /* If the size is unknown, it can not be complete.  */
+         if (NULL_TREE == TYPE_DOMAIN (type))
+           return false;
+
+         /* Zero-length arrays must have size zero.  */
+         if (zero_length_array_type_p (type)
+             && !integer_zerop (TYPE_SIZE (type)))
+           return false;
+       }
+      else
+       {
+         /* If not complete but has a domain, it must be a FAM.  */
+         if (NULL_TREE != TYPE_DOMAIN (type)
+             && !flexible_array_member_type_p (type))
+           return false;
+       }
     default:
       break;
     }
@@ -507,7 +529,6 @@ c_build_array_type (tree type, tree domain)
   return c_set_type_bits (ret, type);
 }
 
-
 /* Build an array type of unspecified size.  */
 tree
 c_build_array_type_unspecified (tree type)
@@ -517,6 +538,20 @@ c_build_array_type_unspecified (tree type)
   return c_build_array_type (type, build_index_type (upper));
 }
 
+/* Build an array type of zero size.  */
+tree
+c_build_array_type_zero_size (tree type)
+{
+  /* The GCC extension for zero-length arrays differs from
+     ISO flexible array members in that sizeof yields
+     zero.  */
+  type = c_build_array_type (type, build_index_type (NULL_TREE));
+  type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type));
+  TYPE_SIZE (type) = bitsize_zero_node;
+  TYPE_SIZE_UNIT (type) = size_zero_node;
+  SET_TYPE_STRUCTURAL_EQUALITY (type);
+  return type;
+}
 
 tree
 c_build_type_attribute_qual_variant (tree type, tree attrs, int quals)
@@ -824,17 +859,16 @@ composite_type_internal (tree t1, tree t2, tree cond,
        gcc_assert (!TYPE_QUALS_NO_ADDR_SPACE (t1)
                    && !TYPE_QUALS_NO_ADDR_SPACE (t2));
 
-       bool t1_complete = COMPLETE_TYPE_P (t1);
-       bool t2_complete = COMPLETE_TYPE_P (t2);
-
-       bool d1_zero = d1 == NULL_TREE || !TYPE_MAX_VALUE (d1);
-       bool d2_zero = d2 == NULL_TREE || !TYPE_MAX_VALUE (d2);
+       bool d1_zero = zero_length_array_type_p (t1)
+                      || flexible_array_member_type_p (t1);
+       bool d2_zero = zero_length_array_type_p (t2)
+                      || flexible_array_member_type_p (t2);
 
        bool d1_variable = top_array_vla_p (t1);
        bool d2_variable = top_array_vla_p (t2);
 
-       bool use1 = d1 && (d2_variable || d2_zero || !d1_variable);
-       bool use2 = d2 && (d1_variable || d1_zero || !d2_variable);
+       bool use1 = d1 && (d2_variable || !d2 || d2_zero || !d1_variable);
+       bool use2 = d2 && (d1_variable || !d1 || d1_zero || !d2_variable);
 
        /* If the first is an unspecified size pick the other one.  */
        if (d2_variable && c_type_unspecified_p (t1))
@@ -889,24 +923,18 @@ composite_type_internal (tree t1, tree t2, tree cond,
        int quals = TYPE_QUALS (strip_array_types (elt));
        tree unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED);
 
-       t1 = c_build_array_type (unqual_elt, td);
+       if ((!d1 || d1_zero) && (!d2 || d2_zero) && (d1 || d2))
+         t1 = c_build_array_type_zero_size (unqual_elt);
+       else
+         t1 = c_build_array_type (unqual_elt, td);
 
        /* Check that a type which has a varying outermost dimension
-          got marked has having a variable size.  */
+          got marked as having a variable size.  */
        bool varsize = (d1_variable && d2_variable)
-                      || (d1_variable && !t2_complete)
-                      || (d2_variable && !t1_complete);
+                      || (d1_variable && !d2)
+                      || (d2_variable && !d1);
        gcc_checking_assert (!varsize || C_TYPE_VARIABLE_SIZE (t1));
 
-       /* Ensure a composite type involving a zero-length array type
-          is a zero-length type not an incomplete type.  */
-       if (d1_zero && d2_zero
-           && (t1_complete || t2_complete)
-           && !COMPLETE_TYPE_P (t1))
-         {
-           TYPE_SIZE (t1) = bitsize_zero_node;
-           TYPE_SIZE_UNIT (t1) = size_zero_node;
-         }
        t1 = c_build_qualified_type (t1, quals);
        return c_build_type_attribute_variant (t1, attributes);
       }
@@ -1809,9 +1837,6 @@ comptypes_internal (const_tree type1, const_tree type2,
        if (d1 == NULL_TREE || d2 == NULL_TREE || d1 == d2)
          return true;
 
-       bool d1_zero = !TYPE_MAX_VALUE (d1);
-       bool d2_zero = !TYPE_MAX_VALUE (d2);
-
        bool d1_variable = top_array_vla_p (t1);
        bool d2_variable = top_array_vla_p (t2);
 
@@ -1819,10 +1844,19 @@ comptypes_internal (const_tree type1, const_tree type2,
          data->different_types_p = true;
        if (d1_variable || d2_variable)
          return true;
+
+       bool d1_zero = zero_length_array_type_p (t1)
+                      || flexible_array_member_type_p (t1);
+
+       bool d2_zero = zero_length_array_type_p (t2)
+                      || flexible_array_member_type_p (t2);
+
        if (d1_zero && d2_zero)
          return true;
-       if (d1_zero || d2_zero
-           || !tree_int_cst_equal (TYPE_MIN_VALUE (d1), TYPE_MIN_VALUE (d2))
+       if (d1_zero || d2_zero)
+         return false;
+
+       if (!tree_int_cst_equal (TYPE_MIN_VALUE (d1), TYPE_MIN_VALUE (d2))
            || !tree_int_cst_equal (TYPE_MAX_VALUE (d1), TYPE_MAX_VALUE (d2)))
          return false;
 

Reply via email to