This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
zero-length array tweeks
- To: gcc-patches at gcc dot gnu dot org
- Subject: zero-length array tweeks
- From: Richard Henderson <rth at redhat dot com>
- Date: Wed, 3 Jan 2001 17:22:10 -0800
Some of the changes I made last month slightly changed some of
the semantics of GCC's old zero-length array extension. Which
broke extant code, largely (of course) in the Linux kernel.
After some (only slightly heated) discussion, I don't see much
harm continuing to support some of the old semantics. Hopefully
the changes to extend.texi clarify the extent of these.
r~
* c-decl.c (grokdeclarator): Give zero-length arrays size zero.
Remove dead code.
* c-typeck.c (push_init_level): Move checks for flexible array
members and zero length arrays ...
(pop_init_level): ... here. Silently discard empty initializations.
Remove dead code.
* varasm.c (output_constructor): Update for sizeof change to
zero-length arrays.
* extend.texi (Zero Length): Clarify semantics.
* gcc.dg/940510-1.c: Update expected error wording.
* gcc.dg/array-2.c, gcc.dg/array-3.c, gcc.dg/array-4.c: New.
Index: c-decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/c-decl.c,v
retrieving revision 1.196
diff -c -p -d -r1.196 c-decl.c
*** c-decl.c 2001/01/02 15:58:16 1.196
--- c-decl.c 2001/01/04 01:04:09
*************** grokdeclarator (declarator, declspecs, d
*** 4518,4531 ****
if (type_quals)
type = c_build_qualified_type (type, type_quals);
- #if 0
- /* Don't clear these; leave them set so that the array type
- or the variable is itself const or volatile. */
- type_quals = TYPE_UNQUALIFIED;
- #endif
-
if (size_varies)
C_TYPE_VARIABLE_SIZE (type) = 1;
}
else if (TREE_CODE (declarator) == CALL_EXPR)
{
--- 4518,4534 ----
if (type_quals)
type = c_build_qualified_type (type, type_quals);
if (size_varies)
C_TYPE_VARIABLE_SIZE (type) = 1;
+
+ /* The GCC extension for zero-length arrays differs from
+ ISO flexible array members in that sizeof yields zero. */
+ if (size && integer_zerop (size))
+ {
+ layout_type (type);
+ TYPE_SIZE (type) = bitsize_zero_node;
+ TYPE_SIZE_UNIT (type) = size_zero_node;
+ }
}
else if (TREE_CODE (declarator) == CALL_EXPR)
{
Index: c-typeck.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/c-typeck.c,v
retrieving revision 1.106
diff -c -p -d -r1.106 c-typeck.c
*** c-typeck.c 2000/12/20 18:18:24 1.106
--- c-typeck.c 2001/01/04 01:04:09
*************** push_init_level (implicit)
*** 5289,5308 ****
{
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
! (TYPE_DOMAIN (constructor_type)));
}
else
constructor_index = bitsize_zero_node;
--- 5289,5297 ----
{
constructor_max_index
= TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type));
constructor_index
= convert (bitsizetype,
! TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type)));
}
else
constructor_index = bitsize_zero_node;
*************** pop_init_level (implicit)
*** 5346,5351 ****
--- 5335,5358 ----
if (constructor_type != 0)
size = int_size_in_bytes (constructor_type);
+ /* Error for initializing a flexible array member, or a zero-length
+ array member in an inappropriate context. */
+ if (constructor_type
+ && 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");
+ }
+
/* Warn when some struct elements are implicitly initialized to zero. */
if (extra_warnings
&& constructor_type
*************** pop_init_level (implicit)
*** 5360,5376 ****
/* Now output all pending elements. */
output_pending_init_elements (1);
- #if 0 /* c-parse.in warns about {}. */
- /* In ANSI, each brace level must have at least one element. */
- if (! implicit && pedantic
- && (TREE_CODE (constructor_type) == ARRAY_TYPE
- ? integer_zerop (constructor_unfilled_index)
- : constructor_unfilled_fields == TYPE_FIELDS (constructor_type)))
- pedwarn_init ("empty braces in initializer");
- #endif
-
/* Pad out the end of the structure. */
-
if (p->replacement_value)
/* If this closes a superfluous brace pair,
just pass out the element between them. */
--- 5367,5373 ----
Index: varasm.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/varasm.c,v
retrieving revision 1.150
diff -c -p -d -r1.150 varasm.c
*** varasm.c 2000/12/29 20:34:20 1.150
--- varasm.c 2001/01/04 01:04:10
*************** output_constructor (exp, size)
*** 4607,4622 ****
/* Determine size this element should occupy. */
if (field)
{
! 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));
--- 4607,4625 ----
/* Determine size this element should occupy. */
if (field)
{
! if (DECL_SIZE_UNIT (field)
! && ! integer_zerop (DECL_SIZE_UNIT (field)))
fieldsize = tree_low_cst (DECL_SIZE_UNIT (field), 1);
! else if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE)
{
! /* If DECL_SIZE is not set or is zero, 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 = 0;
}
else
fieldsize = int_size_in_bytes (TREE_TYPE (type));
Index: extend.texi
===================================================================
RCS file: /cvs/gcc/egcs/gcc/extend.texi,v
retrieving revision 1.80
diff -c -p -d -r1.80 extend.texi
*** extend.texi 2001/01/02 02:56:00 1.80
--- extend.texi 2001/01/04 01:04:09
*************** extension for floating-point constants o
*** 869,876 ****
@cindex zero-length arrays
@cindex length-zero arrays
! 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
object:
@example
--- 869,876 ----
@cindex zero-length arrays
@cindex length-zero arrays
! 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
object:
@example
*************** struct line @{
*** 879,910 ****
char contents[0];
@};
! @{
! struct line *thisline = (struct line *)
! malloc (sizeof (struct line) + this_length);
! thisline->length = this_length;
! @}
@end example
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}.
! 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
--- 879,932 ----
char contents[0];
@};
! struct line *thisline = (struct line *)
! malloc (sizeof (struct line) + this_length);
! thisline->length = this_length;
@end example
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}.
! In ISO C99, you would use a @dfn{flexible array member}, which is
! slightly different in syntax and semantics:
! @itemize @bullet
! @item
! Flexible array members are written as @code{contents[]} without
! the @code{0}.
!
! @item
! Flexible array members have incomplete type, and so the @code{sizeof}
! operator may not be applied. As a quirk of the original implementation
! of zero-length arrays, @code{sizeof} evaluates to zero.
!
! @item
! Flexible array members may only appear as the last member of a
! @code{struct} that is otherwise non-empty. GCC currently allows
! 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.
!
! @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.
@example
+ struct bar @{ struct line a; @};
+
/* Legal. */
struct line x = @{ 4, @{ 'g', 'o', 'o', 'd' @} @};
/* Illegal. */
! struct bar y = @{ @{ 3, @{ 'b', 'a', 'd' @} @} @};
!
! /* Legal. */
! struct bar z = @{ @{ 0, @{ @} @} @};
@end example
+ @end itemize
@node Variable Length
@section Arrays of Variable Length
Index: testsuite/gcc.dg/940510-1.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/testsuite/gcc.dg/940510-1.c,v
retrieving revision 1.1
diff -c -p -d -r1.1 940510-1.c
*** 940510-1.c 2000/11/28 22:25:51 1.1
--- 940510-1.c 2001/01/04 01:04:11
***************
*** 1,3 ****
/* { dg-do compile } */
/* { dg-options "-std=c89 -pedantic" } */
! struct { int a[]; } x = { 0 }; /* { dg-error "(does not support)|(near initialization)" } */
--- 1,3 ----
/* { dg-do compile } */
/* { dg-options "-std=c89 -pedantic" } */
! struct { int a[]; } x = { 0 }; /* { dg-error "(flexible array member)|(near initialization)" } */
Index: testsuite/gcc.dg/array-2.c
===================================================================
RCS file: array-2.c
diff -N array-2.c
*** /dev/null Tue May 5 13:32:27 1998
--- array-2.c Wed Jan 3 17:04:11 2001
***************
*** 0 ****
--- 1,10 ----
+ /* { dg-do compile } */
+ /* { dg-options "" } */
+
+ /* Verify that we can't do things to get ourselves in trouble
+ with GCC's zero-length array extension. */
+
+ struct f { int w; int x[0]; };
+ struct g { struct f f; };
+ struct g g1 = { { 0, { } } };
+ struct g g2 = { { 0, { 1 } } }; /* { dg-error "(nested structure)|(near initialization)" "nested" } */
Index: testsuite/gcc.dg/array-3.c
===================================================================
RCS file: array-3.c
diff -N array-3.c
*** /dev/null Tue May 5 13:32:27 1998
--- array-3.c Wed Jan 3 17:04:11 2001
***************
*** 0 ****
--- 1,11 ----
+ /* { dg-do compile } */
+ /* { dg-options "" } */
+
+ /* ISO C99 flexible array members don't have a size. GCC's zero-length
+ array extension does. */
+
+ struct f { int w; int x[0]; } f;
+ struct g { int w; int x[]; } g;
+
+ char test_gcc[sizeof (f.x) ? -1 : 1];
+ char test_iso[sizeof (g.x) ? -1 : 1]; /* { dg-error "incomplete type" "iso" } */
Index: testsuite/gcc.dg/array-4.c
===================================================================
RCS file: array-4.c
diff -N array-4.c
*** /dev/null Tue May 5 13:32:27 1998
--- array-4.c Wed Jan 3 17:04:11 2001
***************
*** 0 ****
--- 1,19 ----
+ /* { dg-do run } */
+ /* { dg-options "" } */
+
+ /* Verify that GCC's extension to initialize a zero-length array
+ member works properly. */
+
+ extern void abort(void);
+ extern void exit(int);
+
+ struct f { int w; int x[0]; } f = { 4, { 0, 1, 2, 3 } };
+
+ int main()
+ {
+ int i;
+ for (i = 0; i < f.w; ++i)
+ if (f.x[i] != i)
+ abort ();
+ exit(0);
+ }