OSDN Git Service

* c-decl.c (finish_struct): Detect flexible array members
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 5 Jan 2001 05:58:23 +0000 (05:58 +0000)
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 5 Jan 2001 05:58:23 +0000 (05:58 +0000)
        used in an inappropriate context.
        * c-typeck.c (really_start_incremental_init): Special case
        constructor_max_index for zero length arrays.
        (pop_init_level): Allow initialization of flexible array
        members.  Deprecate initialization of zero length arrays.
        Don't issue missing initializer warning for flexible array
        members or zero length arrays.
        (process_init_element): Don't dereference null DECL_SIZE.
        * varasm.c (array_size_for_constructor): Return a HOST_WIDE_INT.
        Don't abort for empty constructors.  Use size_binop
        (output_constructor): Add commentary regarding zero length
        array futures.  Abort if we try to initialize an array of
        unspecified length with a non-empty constructor in the middle
        of a structure.

        * extend.texi (Zero Length): Update and clarify documentation
        on static initialization.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@38705 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/c-decl.c
gcc/c-typeck.c
gcc/extend.texi
gcc/varasm.c

index fd4905a..9f5680f 100644 (file)
@@ -1,3 +1,24 @@
+2001-01-04  Richard Henderson  <rth@redhat.com>
+
+       * c-decl.c (finish_struct): Detect flexible array members
+       used in an inappropriate context.
+       * c-typeck.c (really_start_incremental_init): Special case
+       constructor_max_index for zero length arrays.
+       (pop_init_level): Allow initialization of flexible array
+       members.  Deprecate initialization of zero length arrays.
+       Don't issue missing initializer warning for flexible array
+       members or zero length arrays.
+       (process_init_element): Don't dereference null DECL_SIZE.
+       * varasm.c (array_size_for_constructor): Return a HOST_WIDE_INT.
+       Don't abort for empty constructors.  Use size_binop
+       (output_constructor): Add commentary regarding zero length 
+       array futures.  Abort if we try to initialize an array of
+       unspecified length with a non-empty constructor in the middle
+       of a structure.
+
+       * extend.texi (Zero Length): Update and clarify documentation
+       on static initialization.
+
 2001-01-05  Michael Hayes  <m.hayes@elec.canterbury.ac.nz>
 
        * config/c4x/c4x.c (c4x_expand_prologue): Don't compile an ISR
index c813d3e..0a94db0 100644 (file)
@@ -5200,6 +5200,7 @@ finish_struct (t, fieldlist, attributes)
 {
   register tree x;
   int toplevel = global_binding_level == current_binding_level;
+  int saw_named_field;
 
   /* If this type was previously laid out as a forward reference,
      make sure we lay it out again.  */
@@ -5238,6 +5239,7 @@ finish_struct (t, fieldlist, attributes)
      Store 0 there, except for ": 0" fields (so we can find them
      and delete them, below).  */
 
+  saw_named_field = 0;
   for (x = fieldlist; x; x = TREE_CHAIN (x))
     {
       DECL_CONTEXT (x) = t;
@@ -5371,6 +5373,22 @@ finish_struct (t, fieldlist, attributes)
        }
 
       DECL_INITIAL (x) = 0;
+
+      /* Detect flexible array member in an invalid context.  */
+      if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
+         && TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE
+         && TYPE_DOMAIN (TREE_TYPE (x)) != NULL_TREE
+         && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (x))) == NULL_TREE)
+       {
+         if (TREE_CODE (t) == UNION_TYPE)
+           error_with_decl (x, "flexible array member in union");
+         else if (TREE_CHAIN (x) != NULL_TREE)
+           error_with_decl (x, "flexible array member not at end of struct");
+         else if (! saw_named_field)
+           error_with_decl (x, "flexible array member in otherwise empty struct");
+       }
+      if (DECL_NAME (x))
+       saw_named_field = 1;
     }
 
   /* Delete all duplicate fields from the fieldlist */
@@ -5416,8 +5434,8 @@ finish_struct (t, fieldlist, attributes)
        fieldlistp = &TREE_CHAIN (*fieldlistp);
   }
 
-  /*  Now we have the truly final field list.
-      Store it in this type and in the variants.  */
+  /* Now we have the truly final field list.
+     Store it in this type and in the variants.  */
 
   TYPE_FIELDS (t) = fieldlist;
 
index 6a57eed..2868496 100644 (file)
@@ -5162,6 +5162,11 @@ really_start_incremental_init (type)
        {
          constructor_max_index
            = TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type));
+
+         /* Detect non-empty initializations of zero-length arrays.  */
+         if (constructor_max_index == NULL_TREE)
+           constructor_max_index = build_int_2 (-1, -1);
+
          constructor_index
            = convert (bitsizetype,
                       TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type)));
@@ -5292,6 +5297,11 @@ push_init_level (implicit)
          constructor_index
            = convert (bitsizetype, 
                       TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type)));
+
+         /* ??? For GCC 3.1, remove special case initialization of
+            zero-length array members from pop_init_level and set
+            constructor_max_index such that we get the normal
+            "excess elements" warning.  */
        }
       else
        constructor_index = bitsize_zero_node;
@@ -5337,20 +5347,42 @@ pop_init_level (implicit)
 
   /* Error for initializing a flexible array member, or a zero-length
      array member in an inappropriate context.  */
-  if (constructor_type
+  if (constructor_type && constructor_fields
       && TREE_CODE (constructor_type) == ARRAY_TYPE
       && TYPE_DOMAIN (constructor_type)
       && ! TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type)))
     {
-      if (! TYPE_SIZE (constructor_type))
-       error_init ("initialization of a flexible array member");
-      /* Silently discard empty initializations of zero-length arrays.  */
-      else if (integer_zerop (constructor_unfilled_index))
-       constructor_type = 0;
-      /* Otherwise we must be initializing a member of a top-level
-        structure.  */
-      else if (constructor_depth != 2)
-       error_init ("initialization of zero-length array inside a nested structure");
+      /* Silently discard empty initializations.  The parser will
+        already have pedwarned for empty brackets.  */
+      if (integer_zerop (constructor_unfilled_index))
+       constructor_type = NULL_TREE;
+      else if (! TYPE_SIZE (constructor_type))
+       {
+         if (constructor_depth > 2)
+           error_init ("initialization of flexible array member in a nested context");
+         else if (pedantic)
+           pedwarn_init ("initialization of a flexible array member");
+
+          /* We have already issued an error message for the existance
+            of a flexible array member not at the end of the structure.
+            Discard the initializer so that we do not abort later.  */
+         if (TREE_CHAIN (constructor_fields) != NULL_TREE)
+           constructor_type = NULL_TREE;
+       }
+      else
+       {
+         warning_init ("deprecated initialization of zero-length array");
+
+          /* We must be initializing the last member of a top-level struct.  */
+         if (TREE_CHAIN (constructor_fields) != NULL_TREE)
+           {
+             error_init ("initialization of zero-length array before end of structure");
+             /* Discard the initializer so that we do not abort later.  */
+             constructor_type = NULL_TREE;
+           }
+         else if (constructor_depth > 2)
+           error_init ("initialization of zero-length array inside a nested context");
+       }
     }
 
   /* Warn when some struct elements are implicitly initialized to zero.  */
@@ -5359,9 +5391,18 @@ pop_init_level (implicit)
       && TREE_CODE (constructor_type) == RECORD_TYPE
       && constructor_unfilled_fields)
     {
-      push_member_name (constructor_unfilled_fields);
-      warning_init ("missing initializer");
-      RESTORE_SPELLING_DEPTH (constructor_depth);
+      /* Do not warn for flexible array members or zero-length arrays.  */
+      while (constructor_unfilled_fields
+            && (! DECL_SIZE (constructor_unfilled_fields)
+                || integer_zerop (DECL_SIZE (constructor_unfilled_fields))))
+       constructor_unfilled_fields = TREE_CHAIN (constructor_unfilled_fields);
+
+      if (constructor_unfilled_fields)
+       {
+         push_member_name (constructor_unfilled_fields);
+         warning_init ("missing initializer");
+         RESTORE_SPELLING_DEPTH (constructor_depth);
+       }
     }
 
   /* Now output all pending elements.  */
@@ -6129,10 +6170,11 @@ process_init_element (value)
               directly output as a constructor.  */
            {
              /* For a record, keep track of end position of last field.  */
-             constructor_bit_index
-               = size_binop (PLUS_EXPR,
-                             bit_position (constructor_fields),
-                             DECL_SIZE (constructor_fields));
+             if (DECL_SIZE (constructor_fields))
+               constructor_bit_index
+                 = size_binop (PLUS_EXPR,
+                               bit_position (constructor_fields),
+                               DECL_SIZE (constructor_fields));
 
              constructor_unfilled_fields = TREE_CHAIN (constructor_fields);
              /* Skip any nameless bit fields.  */
index 1a0b0e1..7eaf6e9 100644 (file)
@@ -868,6 +868,7 @@ extension for floating-point constants of type @code{float}.
 @cindex arrays of length zero
 @cindex zero-length arrays
 @cindex length-zero arrays
+@cindex flexible array members
 
 Zero-length arrays are allowed in GNU C.  They are very useful as the
 last element of a structure which is really a header for a variable-length
@@ -907,26 +908,52 @@ zero-length arrays anywhere.  You may encounter problems, however,
 defining structures containing only a zero-length array.  Such usage
 is deprecated, and we recommend using zero-length arrays only in
 places in which flexible array members would be allowed.
+@end itemize
 
-@item
-GCC allows static initialization of the zero-length array if the structure
-is not nested inside another structure.  In addition, for backward
-compatibility with an earlier versions of gcc, we allow a degenerate empty
-initialization when nested inside another structure.  I.e.
+GCC versions before 3.0 allowed zero-length arrays to be statically
+initialized.  In addition to those cases that were useful, it also
+allowed initializations in situations that would corrupt later data.
+Non-empty initialization of zero-length arrays is now deprecated.
+
+Instead GCC allows static initialization of flexible array members.
+This is equivalent to defining a new structure containing the original
+structure followed by an array of sufficient size to contain the data.
+I.e. in the following, @code{f1} is constructed as if it were declared
+like @code{f2}.
 
 @example
-struct bar @{ struct line a; @};
+struct f1 @{
+  int x; int y[];
+@} f1 = @{ 1, @{ 2, 3, 4 @} @};
+
+struct f2 @{
+  struct f1 f1; int data[3];
+@} f2 = @{ @{ 1 @}, @{ 2, 3, 4 @} @};
+@end example
 
-/* Legal.  */
-struct line x = @{ 4, @{ 'g', 'o', 'o', 'd' @} @};
+@noindent
+The convenience of this extension is that @code{f1} has the desired
+type, eliminating the need to consistently refer to @code{f2.f1}.
+
+This has symmetry with normal static arrays, in that an array of
+unknown size is also written with @code{[]}.
 
-/* Illegal.  */
-struct bar y = @{ @{ 3, @{ 'b', 'a', 'd' @} @} @};
+Of course, this extension only makes sense if the extra data comes at
+the end of a top-level object, as otherwise we would be overwriting
+data at subsequent offsets.  To avoid undue complication and confusion
+with initialization of deeply nested arrays, we simply disallow any
+non-empty initialization except when the structure is the top-level
+object.  For example:
 
-/* Legal.  */
-struct bar z = @{ @{ 0, @{ @} @} @};
+@example
+struct foo @{ int x; int y[]; @};
+struct bar @{ struct foo z; @};
+
+struct foo a = @{ 1, @{ 2, 3, 4 @} @};        // Legal.
+struct bar b = @{ @{ 1, @{ 2, 3, 4 @} @} @};    // Illegal.
+struct bar c = @{ @{ 1, @{ @} @} @};            // Legal.
+struct foo d[1] = @{ @{ 1 @{ 2, 3, 4 @} @} @};  // Illegal.
 @end example
-@end itemize
 
 @node Variable Length
 @section Arrays of Variable Length
index 4dbbbfb..984f40d 100644 (file)
@@ -108,7 +108,7 @@ struct varasm_status
   struct pool_constant *x_first_pool, *x_last_pool;
 
   /* Current offset in constant pool (does not include any machine-specific
-     header.  */
+     header).  */
   int x_pool_offset;
 
   /* Chain of all CONST_DOUBLE rtx's constructed for the current function.
@@ -171,7 +171,7 @@ static void mark_constant_pool              PARAMS ((void));
 static void mark_constants             PARAMS ((rtx));
 static int output_addressed_constants  PARAMS ((tree));
 static void output_after_function_constants PARAMS ((void));
-static int array_size_for_constructor  PARAMS ((tree));
+static unsigned HOST_WIDE_INT array_size_for_constructor PARAMS ((tree));
 static void output_constructor         PARAMS ((tree, int));
 #ifdef ASM_WEAKEN_LABEL
 static void remove_from_pending_weak_list      PARAMS ((const char *));
@@ -4446,19 +4446,12 @@ output_constant (exp, size)
    arrays of unspecified length.  VAL must be a CONSTRUCTOR of an array
    type with an unspecified upper bound.  */
 
-static int
+static unsigned HOST_WIDE_INT
 array_size_for_constructor (val)
      tree val;
 {
   tree max_index, i;
 
-  if (!val || TREE_CODE (val) != CONSTRUCTOR
-      || TREE_CODE (TREE_TYPE (val)) != ARRAY_TYPE
-      || TYPE_DOMAIN (TREE_TYPE (val)) == NULL_TREE
-      || TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (val))) != NULL_TREE
-      || TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (val))) == NULL_TREE)
-    abort ();
-
   max_index = NULL_TREE;
   for (i = CONSTRUCTOR_ELTS (val); i ; i = TREE_CHAIN (i))
     {
@@ -4470,20 +4463,17 @@ array_size_for_constructor (val)
        max_index = index;
     }
 
-  /* ??? I'm fairly certain if there were no elements, we shouldn't have
-     created the constructor in the first place.  */
   if (max_index == NULL_TREE)
-    abort ();
+    return 0;
 
   /* Compute the total number of array elements.  */
-  i = fold (build (MINUS_EXPR, TREE_TYPE (max_index), max_index
-                  TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (val)))));
-  i = fold (build (PLUS_EXPR, TREE_TYPE (i), i,
-                  convert (TREE_TYPE (i), integer_one_node)));
+  i = size_binop (MINUS_EXPR, convert (sizetype, max_index)
+                 convert (sizetype,
+                          TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (val)))));
+  i = size_binop (PLUS_EXPR, i, convert (sizetype, integer_one_node));
 
   /* Multiply by the array element unit size to find number of bytes.  */
-  i = fold (build (MULT_EXPR, TREE_TYPE (max_index), i,
-                  TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (val)))));
+  i = size_binop (MULT_EXPR, i, TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (val))));
 
   return tree_low_cst (i, 1);
 }
@@ -4607,18 +4597,30 @@ output_constructor (exp, size)
          /* Determine size this element should occupy.  */
          if (field)
            {
-             /* If the last field is an array with an unspecified upper
-                bound, the initializer determines the size.  */
-             if (TREE_CHAIN (field) == 0
-                 && TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
-                 && TYPE_DOMAIN (TREE_TYPE (field)) != 0
-                 && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field))) == 0)
+             fieldsize = 0;
+
+             /* If this is an array with an unspecified upper bound,
+                the initializer determines the size.  */
+             /* ??? This ought to only checked if DECL_SIZE_UNIT is NULL,
+                but we cannot do this until the deprecated support for
+                initializing zero-length array members is removed.  */
+             if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
+                 && TYPE_DOMAIN (TREE_TYPE (field))
+                 && ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field))))
+               {
                  fieldsize = array_size_for_constructor (val);
-             else if (DECL_SIZE_UNIT (field)
-                 && host_integerp (DECL_SIZE_UNIT (field), 1))
-               fieldsize = tree_low_cst (DECL_SIZE_UNIT (field), 1);
-             else
-               fieldsize = 0;
+                 /* Given a non-empty initialization, this field had
+                    better be last.  */
+                 if (fieldsize != 0 && TREE_CHAIN (field) != NULL_TREE)
+                   abort ();
+               }
+             else if (DECL_SIZE_UNIT (field))
+               {
+                 /* ??? This can't be right.  If the decl size overflows
+                    a host integer we will silently emit no data.  */
+                 if (host_integerp (DECL_SIZE_UNIT (field), 1))
+                   fieldsize = tree_low_cst (DECL_SIZE_UNIT (field), 1);
+               }
            }
          else
            fieldsize = int_size_in_bytes (TREE_TYPE (type));