c-decl.c (finish_struct): Detect flexible array members used in an inappropriate context.
* 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. From-SVN: r38705
This commit is contained in:
parent
00de56c7d0
commit
ffc5c6a984
@ -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
|
||||
|
22
gcc/c-decl.c
22
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;
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -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 @} @};
|
||||
|
||||
/* Legal. */
|
||||
struct line x = @{ 4, @{ 'g', 'o', 'o', 'd' @} @};
|
||||
|
||||
/* Illegal. */
|
||||
struct bar y = @{ @{ 3, @{ 'b', 'a', 'd' @} @} @};
|
||||
|
||||
/* Legal. */
|
||||
struct bar z = @{ @{ 0, @{ @} @} @};
|
||||
struct f2 @{
|
||||
struct f1 f1; int data[3];
|
||||
@} f2 = @{ @{ 1 @}, @{ 2, 3, 4 @} @};
|
||||
@end example
|
||||
|
||||
@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{[]}.
|
||||
|
||||
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:
|
||||
|
||||
@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
|
||||
|
62
gcc/varasm.c
62
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));
|
||||
|
Loading…
x
Reference in New Issue
Block a user