* c-decl.c (grokdeclarator): Support flexible array members.
Use open-ended ranges for these and zero-length arrays.
* c-typeck.c (push_init_level): Validate the context of
initialization of a zero-length array.
* tree.c (int_fits_type_p): Be prepared for missing bounds.
* varasm.c (array_size_for_constructor): New.
(output_constructor): Use it for arrays of unspecified length.
* extend.texi (Zero Length): Mention C99 flexible array members.
Document initialization in a top-level struct as valid.
From-SVN: r37576
+2000-11-19 Richard Henderson <rth@redhat.com>
+
+ * c-decl.c (grokdeclarator): Support flexible array members.
+ Use open-ended ranges for these and zero-length arrays.
+ * c-typeck.c (push_init_level): Validate the context of
+ initialization of a zero-length array.
+ * tree.c (int_fits_type_p): Be prepared for missing bounds.
+ * varasm.c (array_size_for_constructor): New.
+ (output_constructor): Use it for arrays of unspecified length.
+ * extend.texi (Zero Length): Mention C99 flexible array members.
+ Document initialization in a top-level struct as valid.
+
2000-11-19 Joseph S. Myers <jsm28@cam.ac.uk>
* config.gcc, invoke.texi: Fix errors in spelling of "deprecated".
2000-11-17 Neil Booth <neilb@earthling.net>
- * cpperror.c (print_file_and_line): Don't display line number
- if 0.
+ * cpperror.c (print_file_and_line): Don't display line number if 0.
2000-11-17 Zack Weinberg <zack@wolery.stanford.edu>
{
/* A zero-length array cannot be represented with an
unsigned index type, which is what we'll get with
- build_index_type. Create a signed range instead. */
- itype = build_range_type (index_type, size,
- build_int_2 (-1, -1));
+ build_index_type. Create an open-ended range instead. */
+ itype = build_range_type (sizetype, size, NULL_TREE);
}
else
{
itype = build_index_type (itype);
}
}
+ else if (decl_context == FIELD)
+ {
+ /* ??? Need to check somewhere that this is a structure
+ and not a union, that this field is last, and that
+ this structure has at least one other named member. */
+
+ if (pedantic && !flag_isoc99 && !in_system_header)
+ pedwarn ("ISO C89 does not support flexible array members");
+
+ /* ISO C99 Flexible array members are effectively identical
+ to GCC's zero-length array extension. */
+ itype = build_range_type (sizetype, size_zero_node, NULL_TREE);
+ }
#if 0
/* This had bad results for pointers to arrays, as in
{
constructor_max_index
= TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type));
+
+ if (constructor_max_index == NULL_TREE)
+ {
+ /* This is a zero-length array or flexible array member. */
+ if (pedantic)
+ pedwarn_init ("ISO C does not support initialization of flexible array members");
+ if (constructor_depth != 2)
+ error_init ("initialization of zero-length array inside a nested structure");
+ }
+
constructor_index
= convert (bitsizetype,
TYPE_MIN_VALUE
@}
@end example
-In standard C, you would have to give @code{contents} a length of 1, which
+In ISO C89, you would have to give @code{contents} a length of 1, which
means either you waste space or complicate the argument to @code{malloc}.
-Static initialization of the zero-length array is not allowed. A
-warning will be generated for each initializer attempting to initialize
-the zero-length array.
+In ISO C99, you would use a @dfn{flexible array member}, which uses a
+slightly different syntax: leave out the @code{0} and write
+@code{contents[]}.
+
+GCC allows static initialization of the zero-length array if
+the structure is not nested inside another structure. I.e.
+
+@example
+/* Legal. */
+struct line x = @{ 4, @{ 'g', 'o', 'o', 'd' @} @};
+
+/* Illegal. */
+struct bar @{
+ struct line a;
+@} y = @{ @{ 3, @{ 'b', 'a', 'd' @} @} @};
+@end example
@node Variable Length
@section Arrays of Variable Length
{
/* If the bounds of the type are integers, we can check ourselves.
Otherwise,. use force_fit_type, which checks against the precision. */
- if (TREE_CODE (TYPE_MAX_VALUE (type)) == INTEGER_CST
+ if (TYPE_MAX_VALUE (type) != NULL_TREE
+ && TYPE_MIN_VALUE (type) != NULL_TREE
+ && TREE_CODE (TYPE_MAX_VALUE (type)) == INTEGER_CST
&& TREE_CODE (TYPE_MIN_VALUE (type)) == INTEGER_CST)
{
if (TREE_UNSIGNED (type))
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 void output_constructor PARAMS ((tree, int));
#ifdef ASM_WEAKEN_LABEL
static void remove_from_pending_weak_list PARAMS ((const char *));
}
\f
-/* Subroutine of output_constant, used for CONSTRUCTORs
- (aggregate constants).
+/* Subroutine of output_constructor, used for computing the size of
+ arrays of unspecified length. VAL must be a CONSTRUCTOR of an array
+ type with an unspecified upper bound. */
+
+static 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))
+ {
+ tree index = TREE_PURPOSE (i);
+
+ if (TREE_CODE (index) == RANGE_EXPR)
+ index = TREE_OPERAND (index, 1);
+ if (max_index == NULL_TREE || tree_int_cst_lt (max_index, index))
+ 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 ();
+
+ /* 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)));
+
+ /* 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)))));
+
+ return tree_low_cst (i, 1);
+}
+
+/* Subroutine of output_constant, used for CONSTRUCTORs (aggregate constants).
Generate at least SIZE bytes, padding if necessary. */
static void
/* Determine size this element should occupy. */
if (field)
- fieldsize = tree_low_cst (DECL_SIZE_UNIT (field), 1);
+ {
+ if (DECL_SIZE_UNIT (field))
+ fieldsize = tree_low_cst (DECL_SIZE_UNIT (field), 1);
+ else
+ {
+ /* If DECL_SIZE is not set, then this must be an array
+ of unspecified length. The initialized value must
+ be a CONSTRUCTOR, and we take the length from the
+ last initialized element. */
+ fieldsize = array_size_for_constructor (val);
+ }
+ }
else
fieldsize = int_size_in_bytes (TREE_TYPE (type));