c-decl.c (grokdeclarator): Give zero-length arrays size zero.
authorRichard Henderson <rth@redhat.com>
Thu, 4 Jan 2001 01:14:16 +0000 (17:14 -0800)
committerRichard Henderson <rth@gcc.gnu.org>
Thu, 4 Jan 2001 01:14:16 +0000 (17:14 -0800)
        * 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.

From-SVN: r38678

gcc/ChangeLog
gcc/c-decl.c
gcc/c-typeck.c
gcc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/940510-1.c
gcc/testsuite/gcc.dg/array-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/array-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/array-4.c [new file with mode: 0644]
gcc/varasm.c

index 697f42a061f09840f584dff266d1c1d7d4da9a2d..ec1565dcd7511fc2cfa6468108c5b4c5c1e1201f 100644 (file)
@@ -1,3 +1,16 @@
+2000-01-03  Richard Henderson  <rth@redhat.com>
+
+       * 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.
+
 2001-01-03  Alexandre Oliva  <aoliva@redhat.com>
 
        * configure.in (tm.h): Include isns-codes.h last.
index 0521aa779361f7d7c72b088ef495cb54477e2337..826608ba4c19b7561550eb2e20f6623e947b5c00 100644 (file)
@@ -4518,14 +4518,17 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
          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;
+
+         /* 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 d7efc2d56f7e98e5fc447b771989e99090559f10..6a57eed24bdb1aac23f23a94d366b45595a18e59 100644 (file)
@@ -1,6 +1,6 @@
 /* Build expressions with type checking for C compiler.
    Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -5289,20 +5289,9 @@ push_init_level (implicit)
        {
          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)));
+                      TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type)));
        }
       else
        constructor_index = bitsize_zero_node;
@@ -5346,6 +5335,24 @@ pop_init_level (implicit)
   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
@@ -5360,17 +5367,7 @@ pop_init_level (implicit)
   /* 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.  */
index 811a423e7db55c2eae235b2d6cb877c4443a5b4c..1a0b0e14c733abcdbbf5f0d008d770c6b4967dff 100644 (file)
@@ -869,8 +869,8 @@ extension for floating-point constants of type @code{float}.
 @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
+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
@@ -879,32 +879,54 @@ struct line @{
   char contents[0];
 @};
 
-@{
-  struct line *thisline = (struct line *)
-    malloc (sizeof (struct line) + this_length);
-  thisline->length = this_length;
-@}
+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[]}.
+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.
 
-GCC allows static initialization of the zero-length array if
-the structure is not nested inside another structure.  I.e.
+@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 @{
-  struct line a;
-@} y = @{ @{ 3, @{ 'b', 'a', 'd' @} @} @};
+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 6bf11589d66683aa37d423e435ebcbb0ac8d0892..204efd1cc3f3e58551a4198120d9bbb66d8006d7 100644 (file)
@@ -1,3 +1,8 @@
+2001-01-03  Richard Henderson  <rth@redhat.com>
+
+       * 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.
+
 2001-01-03  Jeffrey Oldham  <oldham@codesourcery.com>
 
        * lib/target-supports.exp (check_alias_available): Modified to
index 5f241f57c9447232611cdf4d29df36889da98f89..a734c8f80d7679affba14422f0a69123db2bc943 100644 (file)
@@ -1,3 +1,3 @@
 /* { dg-do compile } */
 /* { dg-options "-std=c89 -pedantic" } */
-struct { int a[]; } x = { 0 }; /* { dg-error "(does not support)|(near initialization)" } */
+struct { int a[]; } x = { 0 }; /* { dg-error "(flexible array member)|(near initialization)" } */
diff --git a/gcc/testsuite/gcc.dg/array-2.c b/gcc/testsuite/gcc.dg/array-2.c
new file mode 100644 (file)
index 0000000..aa6f0c6
--- /dev/null
@@ -0,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" } */
diff --git a/gcc/testsuite/gcc.dg/array-3.c b/gcc/testsuite/gcc.dg/array-3.c
new file mode 100644 (file)
index 0000000..f0709d2
--- /dev/null
@@ -0,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" } */
diff --git a/gcc/testsuite/gcc.dg/array-4.c b/gcc/testsuite/gcc.dg/array-4.c
new file mode 100644 (file)
index 0000000..9396dec
--- /dev/null
@@ -0,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 0ebcbd9da2aa79623901514eff270b122272e256..b87d9beeaca443200fac8085616df95f6f1af388 100644 (file)
@@ -1,6 +1,6 @@
 /* Output variables, constants and external declarations, for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -4607,16 +4607,19 @@ output_constructor (exp, size)
          /* Determine size this element should occupy.  */
          if (field)
            {
-             if (DECL_SIZE_UNIT (field))
+             if (DECL_SIZE_UNIT (field)
+                 && ! integer_zerop (DECL_SIZE_UNIT (field)))
                fieldsize = tree_low_cst (DECL_SIZE_UNIT (field), 1);
-             else
+             else if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE)
                {
-                 /* 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
+                 /* 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));