Commit ffc5c6a9 by Richard Henderson Committed by Richard Henderson

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
parent 00de56c7
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> 2001-01-05 Michael Hayes <m.hayes@elec.canterbury.ac.nz>
* config/c4x/c4x.c (c4x_expand_prologue): Don't compile an ISR * config/c4x/c4x.c (c4x_expand_prologue): Don't compile an ISR
......
...@@ -5200,6 +5200,7 @@ finish_struct (t, fieldlist, attributes) ...@@ -5200,6 +5200,7 @@ finish_struct (t, fieldlist, attributes)
{ {
register tree x; register tree x;
int toplevel = global_binding_level == current_binding_level; int toplevel = global_binding_level == current_binding_level;
int saw_named_field;
/* If this type was previously laid out as a forward reference, /* If this type was previously laid out as a forward reference,
make sure we lay it out again. */ make sure we lay it out again. */
...@@ -5238,6 +5239,7 @@ finish_struct (t, fieldlist, attributes) ...@@ -5238,6 +5239,7 @@ finish_struct (t, fieldlist, attributes)
Store 0 there, except for ": 0" fields (so we can find them Store 0 there, except for ": 0" fields (so we can find them
and delete them, below). */ and delete them, below). */
saw_named_field = 0;
for (x = fieldlist; x; x = TREE_CHAIN (x)) for (x = fieldlist; x; x = TREE_CHAIN (x))
{ {
DECL_CONTEXT (x) = t; DECL_CONTEXT (x) = t;
...@@ -5371,6 +5373,22 @@ finish_struct (t, fieldlist, attributes) ...@@ -5371,6 +5373,22 @@ finish_struct (t, fieldlist, attributes)
} }
DECL_INITIAL (x) = 0; 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 */ /* Delete all duplicate fields from the fieldlist */
...@@ -5416,8 +5434,8 @@ finish_struct (t, fieldlist, attributes) ...@@ -5416,8 +5434,8 @@ finish_struct (t, fieldlist, attributes)
fieldlistp = &TREE_CHAIN (*fieldlistp); fieldlistp = &TREE_CHAIN (*fieldlistp);
} }
/* Now we have the truly final field list. /* Now we have the truly final field list.
Store it in this type and in the variants. */ Store it in this type and in the variants. */
TYPE_FIELDS (t) = fieldlist; TYPE_FIELDS (t) = fieldlist;
......
...@@ -5162,6 +5162,11 @@ really_start_incremental_init (type) ...@@ -5162,6 +5162,11 @@ really_start_incremental_init (type)
{ {
constructor_max_index constructor_max_index
= TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type)); = 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 constructor_index
= convert (bitsizetype, = convert (bitsizetype,
TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type))); TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type)));
...@@ -5292,6 +5297,11 @@ push_init_level (implicit) ...@@ -5292,6 +5297,11 @@ push_init_level (implicit)
constructor_index constructor_index
= convert (bitsizetype, = convert (bitsizetype,
TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type))); 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 else
constructor_index = bitsize_zero_node; constructor_index = bitsize_zero_node;
...@@ -5337,20 +5347,42 @@ pop_init_level (implicit) ...@@ -5337,20 +5347,42 @@ pop_init_level (implicit)
/* Error for initializing a flexible array member, or a zero-length /* Error for initializing a flexible array member, or a zero-length
array member in an inappropriate context. */ array member in an inappropriate context. */
if (constructor_type if (constructor_type && constructor_fields
&& TREE_CODE (constructor_type) == ARRAY_TYPE && TREE_CODE (constructor_type) == ARRAY_TYPE
&& TYPE_DOMAIN (constructor_type) && TYPE_DOMAIN (constructor_type)
&& ! TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type))) && ! TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type)))
{ {
if (! TYPE_SIZE (constructor_type)) /* Silently discard empty initializations. The parser will
error_init ("initialization of a flexible array member"); already have pedwarned for empty brackets. */
/* Silently discard empty initializations of zero-length arrays. */ if (integer_zerop (constructor_unfilled_index))
else if (integer_zerop (constructor_unfilled_index)) constructor_type = NULL_TREE;
constructor_type = 0; else if (! TYPE_SIZE (constructor_type))
/* Otherwise we must be initializing a member of a top-level {
structure. */ if (constructor_depth > 2)
else if (constructor_depth != 2) error_init ("initialization of flexible array member in a nested context");
error_init ("initialization of zero-length array inside a nested structure"); 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. */ /* Warn when some struct elements are implicitly initialized to zero. */
...@@ -5359,9 +5391,18 @@ pop_init_level (implicit) ...@@ -5359,9 +5391,18 @@ pop_init_level (implicit)
&& TREE_CODE (constructor_type) == RECORD_TYPE && TREE_CODE (constructor_type) == RECORD_TYPE
&& constructor_unfilled_fields) && constructor_unfilled_fields)
{ {
push_member_name (constructor_unfilled_fields); /* Do not warn for flexible array members or zero-length arrays. */
warning_init ("missing initializer"); while (constructor_unfilled_fields
RESTORE_SPELLING_DEPTH (constructor_depth); && (! 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. */ /* Now output all pending elements. */
...@@ -6129,10 +6170,11 @@ process_init_element (value) ...@@ -6129,10 +6170,11 @@ process_init_element (value)
directly output as a constructor. */ directly output as a constructor. */
{ {
/* For a record, keep track of end position of last field. */ /* For a record, keep track of end position of last field. */
constructor_bit_index if (DECL_SIZE (constructor_fields))
= size_binop (PLUS_EXPR, constructor_bit_index
bit_position (constructor_fields), = size_binop (PLUS_EXPR,
DECL_SIZE (constructor_fields)); bit_position (constructor_fields),
DECL_SIZE (constructor_fields));
constructor_unfilled_fields = TREE_CHAIN (constructor_fields); constructor_unfilled_fields = TREE_CHAIN (constructor_fields);
/* Skip any nameless bit fields. */ /* Skip any nameless bit fields. */
......
...@@ -868,6 +868,7 @@ extension for floating-point constants of type @code{float}. ...@@ -868,6 +868,7 @@ extension for floating-point constants of type @code{float}.
@cindex arrays of length zero @cindex arrays of length zero
@cindex zero-length arrays @cindex zero-length arrays
@cindex length-zero arrays @cindex length-zero arrays
@cindex flexible array members
Zero-length arrays are allowed in GNU C. They are very useful as the 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 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, ...@@ -907,26 +908,52 @@ zero-length arrays anywhere. You may encounter problems, however,
defining structures containing only a zero-length array. Such usage defining structures containing only a zero-length array. Such usage
is deprecated, and we recommend using zero-length arrays only in is deprecated, and we recommend using zero-length arrays only in
places in which flexible array members would be allowed. places in which flexible array members would be allowed.
@end itemize
@item GCC versions before 3.0 allowed zero-length arrays to be statically
GCC allows static initialization of the zero-length array if the structure initialized. In addition to those cases that were useful, it also
is not nested inside another structure. In addition, for backward allowed initializations in situations that would corrupt later data.
compatibility with an earlier versions of gcc, we allow a degenerate empty Non-empty initialization of zero-length arrays is now deprecated.
initialization when nested inside another structure. I.e.
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 @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. */ @noindent
struct line x = @{ 4, @{ 'g', 'o', 'o', 'd' @} @}; 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. */ Of course, this extension only makes sense if the extra data comes at
struct bar y = @{ @{ 3, @{ 'b', 'a', 'd' @} @} @}; 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. */ @example
struct bar z = @{ @{ 0, @{ @} @} @}; 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 example
@end itemize
@node Variable Length @node Variable Length
@section Arrays of Variable Length @section Arrays of Variable Length
......
...@@ -108,7 +108,7 @@ struct varasm_status ...@@ -108,7 +108,7 @@ struct varasm_status
struct pool_constant *x_first_pool, *x_last_pool; struct pool_constant *x_first_pool, *x_last_pool;
/* Current offset in constant pool (does not include any machine-specific /* Current offset in constant pool (does not include any machine-specific
header. */ header). */
int x_pool_offset; int x_pool_offset;
/* Chain of all CONST_DOUBLE rtx's constructed for the current function. /* Chain of all CONST_DOUBLE rtx's constructed for the current function.
...@@ -171,7 +171,7 @@ static void mark_constant_pool PARAMS ((void)); ...@@ -171,7 +171,7 @@ static void mark_constant_pool PARAMS ((void));
static void mark_constants PARAMS ((rtx)); static void mark_constants PARAMS ((rtx));
static int output_addressed_constants PARAMS ((tree)); static int output_addressed_constants PARAMS ((tree));
static void output_after_function_constants PARAMS ((void)); 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)); static void output_constructor PARAMS ((tree, int));
#ifdef ASM_WEAKEN_LABEL #ifdef ASM_WEAKEN_LABEL
static void remove_from_pending_weak_list PARAMS ((const char *)); static void remove_from_pending_weak_list PARAMS ((const char *));
...@@ -4446,19 +4446,12 @@ output_constant (exp, size) ...@@ -4446,19 +4446,12 @@ output_constant (exp, size)
arrays of unspecified length. VAL must be a CONSTRUCTOR of an array arrays of unspecified length. VAL must be a CONSTRUCTOR of an array
type with an unspecified upper bound. */ type with an unspecified upper bound. */
static int static unsigned HOST_WIDE_INT
array_size_for_constructor (val) array_size_for_constructor (val)
tree val; tree val;
{ {
tree max_index, i; 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; max_index = NULL_TREE;
for (i = CONSTRUCTOR_ELTS (val); i ; i = TREE_CHAIN (i)) for (i = CONSTRUCTOR_ELTS (val); i ; i = TREE_CHAIN (i))
{ {
...@@ -4470,20 +4463,17 @@ array_size_for_constructor (val) ...@@ -4470,20 +4463,17 @@ array_size_for_constructor (val)
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) if (max_index == NULL_TREE)
abort (); return 0;
/* Compute the total number of array elements. */ /* Compute the total number of array elements. */
i = fold (build (MINUS_EXPR, TREE_TYPE (max_index), max_index, i = size_binop (MINUS_EXPR, convert (sizetype, max_index),
TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (val))))); convert (sizetype,
i = fold (build (PLUS_EXPR, TREE_TYPE (i), i, TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (val)))));
convert (TREE_TYPE (i), integer_one_node))); i = size_binop (PLUS_EXPR, i, convert (sizetype, integer_one_node));
/* Multiply by the array element unit size to find number of bytes. */ /* Multiply by the array element unit size to find number of bytes. */
i = fold (build (MULT_EXPR, TREE_TYPE (max_index), i, i = size_binop (MULT_EXPR, i, TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (val))));
TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (val)))));
return tree_low_cst (i, 1); return tree_low_cst (i, 1);
} }
...@@ -4607,18 +4597,30 @@ output_constructor (exp, size) ...@@ -4607,18 +4597,30 @@ output_constructor (exp, size)
/* Determine size this element should occupy. */ /* Determine size this element should occupy. */
if (field) if (field)
{ {
/* If the last field is an array with an unspecified upper fieldsize = 0;
bound, the initializer determines the size. */
if (TREE_CHAIN (field) == 0 /* If this is an array with an unspecified upper bound,
&& TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE the initializer determines the size. */
&& TYPE_DOMAIN (TREE_TYPE (field)) != 0 /* ??? This ought to only checked if DECL_SIZE_UNIT is NULL,
&& TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field))) == 0) 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); fieldsize = array_size_for_constructor (val);
else if (DECL_SIZE_UNIT (field) /* Given a non-empty initialization, this field had
&& host_integerp (DECL_SIZE_UNIT (field), 1)) better be last. */
fieldsize = tree_low_cst (DECL_SIZE_UNIT (field), 1); if (fieldsize != 0 && TREE_CHAIN (field) != NULL_TREE)
else abort ();
fieldsize = 0; }
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 else
fieldsize = int_size_in_bytes (TREE_TYPE (type)); fieldsize = int_size_in_bytes (TREE_TYPE (type));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment