This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

zero-length array tweeks


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);
+ }

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]