diff options
-rw-r--r-- | gcc/ChangeLog | 21 | ||||
-rw-r--r-- | gcc/c-decl.c | 22 | ||||
-rw-r--r-- | gcc/c-typeck.c | 76 | ||||
-rw-r--r-- | gcc/extend.texi | 53 | ||||
-rw-r--r-- | gcc/varasm.c | 62 |
5 files changed, 172 insertions, 62 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index fd4905a..9f5680f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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 diff --git a/gcc/c-decl.c b/gcc/c-decl.c index c813d3e..0a94db0 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -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; diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 6a57eed..2868496 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -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. */ diff --git a/gcc/extend.texi b/gcc/extend.texi index 1a0b0e1..7eaf6e9 100644 --- a/gcc/extend.texi +++ b/gcc/extend.texi @@ -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 diff --git a/gcc/varasm.c b/gcc/varasm.c index 4dbbbfb..984f40d 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -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)); |