c-typeck.c (store_init_value): Don't require constant initializer elements with ...
authorJakub Jelinek <jakub@redhat.com>
Fri, 12 Jan 2001 23:18:05 +0000 (00:18 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 12 Jan 2001 23:18:05 +0000 (00:18 +0100)
* c-typeck.c (store_init_value): Don't require constant initializer
elements with -pedantic -std=c99.
(digest_init): Change error about non-constant initializer elements
into pedwarn.
(constructor_range_end): Remove.
(constructor_incremental, designator_depth,
designator_errorneous): New variables.
(struct constructor_stack): Remove range_end, add incremental.
(struct constructor_range_stack, constructor_range_stack): New.
(struct initializer_stack): Add constructor_range_stack.
(finish_init): Set it.
(start_init): Likewise.  require_constant_elements for non-static
trees only if not flag_isoc99.
(really_start_incremental_init): Remove constructor_range_end, add
constructor_incremental.
(pop_init_level): Likewise.
(push_init_level): Likewise.  If implicit and the subobject had some
value set already, preinitialize the level with it.
Warn about missing braces only if not pushing due to designators.
(set_designator, push_range_stack): New functions.
(set_init_label): Use them.
(set_init_index): Likewise.  Remove constructor_range_end.
Error if designator index is outside of array bounds.
(add_pending_init): Compare values of purpose index trees, not the
trees themselves.  Allow overwriting of already initialized element.
Issue a warning if it had side-effects.
(set_nonincremental_init, set_nonincremental_init_from_string): New
functions.
(pending_init_member): Rename to...
(find_init_member): ...this function.  Call set_nonincremental_init
if necessary.  Compare values of purpose index trees, not the trees
themselves.  Return the actual value, not just non-zero if something
is found.
(output_init_element): Remove checks for duplicates.
If field has zero size, only check the initializer for correctness.
Call set_nonincremental_init if necessary.  Push RECORD/ARRAY into AVL
if constructor_incremental is zero.  Change error about initializers
not computable at load time into pedwarn.
(output_pending_init_elements): Compare bit positions, not
FIELD_DECLs to take into account zero-sized fields.
(process_init_element): Use constructor_range_stack to fill all
ranges in the designator lists from current level up.
* extend.texi: Update documentation for labeled elements.

* gcc.c-torture/execute/20000801-3.x: Remove.
* gcc.dg/c90-init-1.c: New test.
* gcc.dg/c99-init-1.c: New test.
* gcc.dg/c99-init-2.c: New test.
* gcc.dg/gnu99-init-1.c: New test.

From-SVN: r38968

gcc/ChangeLog
gcc/c-typeck.c
gcc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/20000801-3.x [deleted file]
gcc/testsuite/gcc.dg/c90-init-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c99-init-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c99-init-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/gnu99-init-1.c [new file with mode: 0644]

index 7ae8ae971325e43df30f27f25734a855f6135916..6e89eab2e07014a1843a47b4edca0b5474801ccb 100644 (file)
@@ -1,3 +1,49 @@
+2001-01-12  Jakub Jelinek  <jakub@redhat.com>
+
+       * c-typeck.c (store_init_value): Don't require constant initializer
+       elements with -pedantic -std=c99.
+       (digest_init): Change error about non-constant initializer elements
+       into pedwarn.
+       (constructor_range_end): Remove.
+       (constructor_incremental, designator_depth,
+       designator_errorneous): New variables.
+       (struct constructor_stack): Remove range_end, add incremental.
+       (struct constructor_range_stack, constructor_range_stack): New.
+       (struct initializer_stack): Add constructor_range_stack.
+       (finish_init): Set it.
+       (start_init): Likewise.  require_constant_elements for non-static
+       trees only if not flag_isoc99.
+       (really_start_incremental_init): Remove constructor_range_end, add
+       constructor_incremental.
+       (pop_init_level): Likewise.
+       (push_init_level): Likewise.  If implicit and the subobject had some
+       value set already, preinitialize the level with it.
+       Warn about missing braces only if not pushing due to designators.
+       (set_designator, push_range_stack): New functions.
+       (set_init_label): Use them.
+       (set_init_index): Likewise.  Remove constructor_range_end.
+       Error if designator index is outside of array bounds.
+       (add_pending_init): Compare values of purpose index trees, not the
+       trees themselves.  Allow overwriting of already initialized element.
+       Issue a warning if it had side-effects.
+       (set_nonincremental_init, set_nonincremental_init_from_string): New
+       functions.
+       (pending_init_member): Rename to...
+       (find_init_member): ...this function.  Call set_nonincremental_init
+       if necessary.  Compare values of purpose index trees, not the trees
+       themselves.  Return the actual value, not just non-zero if something
+       is found.
+       (output_init_element): Remove checks for duplicates.
+       If field has zero size, only check the initializer for correctness.
+       Call set_nonincremental_init if necessary.  Push RECORD/ARRAY into AVL
+       if constructor_incremental is zero.  Change error about initializers
+       not computable at load time into pedwarn.
+       (output_pending_init_elements): Compare bit positions, not
+       FIELD_DECLs to take into account zero-sized fields.
+       (process_init_element): Use constructor_range_stack to fill all
+       ranges in the designator lists from current level up.
+       * extend.texi: Update documentation for labeled elements.
+
 2001-01-12  Alexandre Oliva  <aoliva@redhat.com>
 
        * calls.c (emit_library_call_value_1): Add USEs and CLOBBERs
index 2868496a53d80adf1d103331d6fcba4f1e244021..9db269e9600d9705cb01f23f54dee255daa0135c 100644 (file)
@@ -76,8 +76,12 @@ static void warning_init             PARAMS ((const char *));
 static tree digest_init                        PARAMS ((tree, tree, int, int));
 static void output_init_element                PARAMS ((tree, tree, tree, int));
 static void output_pending_init_elements PARAMS ((int));
+static int set_designator              PARAMS ((int));
+static void push_range_stack           PARAMS ((tree));
 static void add_pending_init           PARAMS ((tree, tree));
-static int pending_init_member         PARAMS ((tree));
+static void set_nonincremental_init    PARAMS ((void));
+static void set_nonincremental_init_from_string        PARAMS ((tree));
+static tree find_init_member           PARAMS ((tree));
 \f
 /* Do `exp = require_complete_type (exp);' to make sure exp
    does not have an incomplete type.  (That includes void types.)  */
@@ -4410,7 +4414,7 @@ store_init_value (decl, init)
   /* Digest the specified initializer into an expression.  */
 
   value = digest_init (type, init, TREE_STATIC (decl),
-                      TREE_STATIC (decl) || pedantic);
+                      TREE_STATIC (decl) || (pedantic && !flag_isoc99));
 
   /* Store the expression if valid; else report error.  */
 
@@ -4769,10 +4773,7 @@ digest_init (type, init, require_constant, constructor_constant)
        }
       else if (require_constant
               && initializer_constant_valid_p (inside_init, TREE_TYPE (inside_init)) == 0)
-       {
-         error_init ("initializer element is not computable at load time");
-         inside_init = error_mark_node;
-       }
+       pedwarn ("initializer element is not computable at load time");
 
       return inside_init;
     }
@@ -4868,11 +4869,6 @@ static tree constructor_fields;
    at which to store the next element we get.  */
 static tree constructor_index;
 
-/* For an ARRAY_TYPE, this is the end index of the range
-   to initialize with the next element, or NULL in the ordinary case
-   where the element is used just once.  */
-static tree constructor_range_end;
-
 /* For an ARRAY_TYPE, this is the maximum index.  */
 static tree constructor_max_index;
 
@@ -4892,6 +4888,10 @@ static tree constructor_bit_index;
    most recent first).  */
 static tree constructor_elements;
 
+/* 1 if constructor should be incrementally stored into a constructor chain,
+   0 if all the elements should be kept in AVL tree.  */
+static int constructor_incremental;
+
 /* 1 if so far this constructor's elements are all compile-time constants.  */
 static int constructor_constant;
 
@@ -4943,6 +4943,12 @@ static const char *constructor_asmspec;
 /* Nonzero if this is an initializer for a top-level decl.  */
 static int constructor_top_level;
 
+/* Nesting depth of designator list.  */
+static int designator_depth;
+
+/* Nonzero if there were diagnosed errors in this designator list.  */
+static int designator_errorneous;
+
 \f
 /* This stack has a level for each implicit or explicit level of
    structuring in the initializer, including the outermost one.  It
@@ -4954,7 +4960,6 @@ struct constructor_stack
   tree type;
   tree fields;
   tree index;
-  tree range_end;
   tree max_index;
   tree unfilled_index;
   tree unfilled_fields;
@@ -4971,10 +4976,26 @@ struct constructor_stack
   char implicit;
   char erroneous;
   char outer;
+  char incremental;
 };
 
 struct constructor_stack *constructor_stack;
 
+/* This stack represents designators from some range designator up to
+   the last designator in the list.  */
+
+struct constructor_range_stack
+{
+  struct constructor_range_stack *next, *prev;
+  struct constructor_stack *stack;
+  tree range_start;
+  tree index;
+  tree range_end;
+  tree fields;
+};
+
+struct constructor_range_stack *constructor_range_stack;
+
 /* This stack records separate initializers that are nested.
    Nested initializers can't happen in ANSI C, but GNU C allows them
    in cases like { ... (struct foo) { ... } ... }.  */
@@ -4985,6 +5006,7 @@ struct initializer_stack
   tree decl;
   const char *asmspec;
   struct constructor_stack *constructor_stack;
+  struct constructor_range_stack *constructor_range_stack;
   tree elements;
   struct spelling *spelling;
   struct spelling *spelling_base;
@@ -5018,6 +5040,7 @@ start_init (decl, asmspec_tree, top_level)
   p->require_constant_value = require_constant_value;
   p->require_constant_elements = require_constant_elements;
   p->constructor_stack = constructor_stack;
+  p->constructor_range_stack = constructor_range_stack;
   p->elements = constructor_elements;
   p->spelling = spelling;
   p->spelling_base = spelling_base;
@@ -5036,7 +5059,7 @@ start_init (decl, asmspec_tree, top_level)
     {
       require_constant_value = TREE_STATIC (decl);
       require_constant_elements
-       = ((TREE_STATIC (decl) || pedantic)
+       = ((TREE_STATIC (decl) || (pedantic && !flag_isoc99))
           /* For a scalar, you can always use any value to initialize,
              even within braces.  */
           && (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
@@ -5053,6 +5076,7 @@ start_init (decl, asmspec_tree, top_level)
     }
 
   constructor_stack = 0;
+  constructor_range_stack = 0;
 
   missing_braces_mentioned = 0;
 
@@ -5083,12 +5107,16 @@ finish_init ()
       free (q);
     }
 
+  if (constructor_range_stack)
+    abort ();
+
   /* Pop back to the data of the outer initializer (if any).  */
   constructor_decl = p->decl;
   constructor_asmspec = p->asmspec;
   require_constant_value = p->require_constant_value;
   require_constant_elements = p->require_constant_elements;
   constructor_stack = p->constructor_stack;
+  constructor_range_stack = p->constructor_range_stack;
   constructor_elements = p->elements;
   spelling = p->spelling;
   spelling_base = p->spelling_base;
@@ -5119,7 +5147,6 @@ really_start_incremental_init (type)
   p->type = constructor_type;
   p->fields = constructor_fields;
   p->index = constructor_index;
-  p->range_end = constructor_range_end;
   p->max_index = constructor_max_index;
   p->unfilled_index = constructor_unfilled_index;
   p->unfilled_fields = constructor_unfilled_fields;
@@ -5133,6 +5160,7 @@ really_start_incremental_init (type)
   p->replacement_value = 0;
   p->implicit = 0;
   p->outer = 0;
+  p->incremental = constructor_incremental;
   p->next = 0;
   constructor_stack = p;
 
@@ -5142,6 +5170,9 @@ really_start_incremental_init (type)
   constructor_elements = 0;
   constructor_pending_elts = 0;
   constructor_type = type;
+  constructor_incremental = 1;
+  designator_depth = 0;
+  designator_errorneous = 0;
 
   if (TREE_CODE (constructor_type) == RECORD_TYPE
       || TREE_CODE (constructor_type) == UNION_TYPE)
@@ -5157,7 +5188,6 @@ really_start_incremental_init (type)
     }
   else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
     {
-      constructor_range_end = 0;
       if (TYPE_DOMAIN (constructor_type))
        {
          constructor_max_index
@@ -5187,13 +5217,14 @@ really_start_incremental_init (type)
 /* Push down into a subobject, for initialization.
    If this is for an explicit set of braces, IMPLICIT is 0.
    If it is because the next element belongs at a lower level,
-   IMPLICIT is 1.  */
+   IMPLICIT is 1 (or 2 if the push is because of designator list).  */
 
 void
 push_init_level (implicit)
      int implicit;
 {
   struct constructor_stack *p;
+  tree value = NULL_TREE;
 
   /* If we've exhausted any levels that didn't have braces,
      pop them now.  */
@@ -5210,11 +5241,22 @@ push_init_level (implicit)
        break;
     }
 
+  /* Unless this is an explicit brace, we need to preserve previous
+     content if any.  */
+  if (implicit)
+    {
+      if ((TREE_CODE (constructor_type) == RECORD_TYPE
+          || TREE_CODE (constructor_type) == UNION_TYPE)
+         && constructor_fields)
+       value = find_init_member (constructor_fields);
+      else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+       value = find_init_member (constructor_index);
+    }
+
   p = (struct constructor_stack *) xmalloc (sizeof (struct constructor_stack));
   p->type = constructor_type;
   p->fields = constructor_fields;
   p->index = constructor_index;
-  p->range_end = constructor_range_end;
   p->max_index = constructor_max_index;
   p->unfilled_index = constructor_unfilled_index;
   p->unfilled_fields = constructor_unfilled_fields;
@@ -5228,6 +5270,7 @@ push_init_level (implicit)
   p->replacement_value = 0;
   p->implicit = implicit;
   p->outer = 0;
+  p->incremental = constructor_incremental;
   p->next = constructor_stack;
   constructor_stack = p;
 
@@ -5235,7 +5278,13 @@ push_init_level (implicit)
   constructor_simple = 1;
   constructor_depth = SPELLING_DEPTH ();
   constructor_elements = 0;
+  constructor_incremental = 1;
   constructor_pending_elts = 0;
+  if (!implicit)
+    {
+      designator_depth = 0;
+      designator_errorneous = 0;
+    }
 
   /* Don't die if an entire brace-pair level is superfluous
      in the containing level.  */
@@ -5269,7 +5318,18 @@ push_init_level (implicit)
       return;
     }
 
-  if (implicit && warn_missing_braces && !missing_braces_mentioned)
+  if (value && TREE_CODE (value) == CONSTRUCTOR)
+    {
+      constructor_constant = TREE_CONSTANT (value);
+      constructor_simple = TREE_STATIC (value);
+      constructor_elements = TREE_OPERAND (value, 1);
+      if (constructor_elements
+         && (TREE_CODE (constructor_type) == RECORD_TYPE
+             || TREE_CODE (constructor_type) == ARRAY_TYPE))
+       set_nonincremental_init ();
+    }
+
+  if (implicit == 1 && warn_missing_braces && !missing_braces_mentioned)
     {
       missing_braces_mentioned = 1;
       warning_init ("missing braces around initializer");
@@ -5289,7 +5349,6 @@ push_init_level (implicit)
     }
   else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
     {
-      constructor_range_end = 0;
       if (TYPE_DOMAIN (constructor_type))
        {
          constructor_max_index
@@ -5307,6 +5366,13 @@ push_init_level (implicit)
        constructor_index = bitsize_zero_node;
 
       constructor_unfilled_index = constructor_index;
+      if (value && TREE_CODE (value) == STRING_CST)
+       {
+         /* We need to split the char/wchar array into individual
+            characters, so that we don't have to special case it
+            everywhere.  */
+         set_nonincremental_init_from_string (value);
+       }
     }
   else
     {
@@ -5363,7 +5429,7 @@ pop_init_level (implicit)
          else if (pedantic)
            pedwarn_init ("initialization of a flexible array member");
 
-          /* We have already issued an error message for the existance
+         /* 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)
@@ -5373,7 +5439,7 @@ pop_init_level (implicit)
        {
          warning_init ("deprecated initialization of zero-length array");
 
-          /* We must be initializing the last member of a top-level struct.  */
+         /* 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");
@@ -5391,21 +5457,22 @@ pop_init_level (implicit)
       && TREE_CODE (constructor_type) == RECORD_TYPE
       && constructor_unfilled_fields)
     {
-      /* 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);
+       /* 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);
-       }
+       if (constructor_unfilled_fields)
+         {
+           push_member_name (constructor_unfilled_fields);
+           warning_init ("missing initializer");
+           RESTORE_SPELLING_DEPTH (constructor_depth);
+         }
     }
 
   /* Now output all pending elements.  */
+  constructor_incremental = 1;
   output_pending_init_elements (1);
 
   /* Pad out the end of the structure.  */
@@ -5423,7 +5490,8 @@ pop_init_level (implicit)
         the element, after verifying there is just one.  */
       if (constructor_elements == 0)
        {
-         error_init ("empty scalar initializer");
+         if (!constructor_erroneous)
+           error_init ("empty scalar initializer");
          constructor = error_mark_node;
        }
       else if (TREE_CHAIN (constructor_elements) != 0)
@@ -5452,7 +5520,6 @@ pop_init_level (implicit)
   constructor_type = p->type;
   constructor_fields = p->fields;
   constructor_index = p->index;
-  constructor_range_end = p->range_end;
   constructor_max_index = p->max_index;
   constructor_unfilled_index = p->unfilled_index;
   constructor_unfilled_fields = p->unfilled_fields;
@@ -5461,6 +5528,7 @@ pop_init_level (implicit)
   constructor_constant = p->constant;
   constructor_simple = p->simple;
   constructor_erroneous = p->erroneous;
+  constructor_incremental = p->incremental;
   constructor_pending_elts = p->pending_elts;
   constructor_depth = p->depth;
   RESTORE_SPELLING_DEPTH (constructor_depth);
@@ -5477,6 +5545,97 @@ pop_init_level (implicit)
   return constructor;
 }
 
+/* Common handling for both array range and field name designators.
+   ARRAY argument is non-zero for array ranges.  Returns zero for success.  */
+
+static int
+set_designator (array)
+     int array;
+{
+  tree subtype;
+  enum tree_code subcode;
+
+  /* Don't die if an entire brace-pair level is superfluous
+     in the containing level.  */
+  if (constructor_type == 0)
+    return 1;
+
+  /* If there were errors in this designator list already, bail out silently.  */
+  if (designator_errorneous)
+    return 1;
+
+  if (!designator_depth)
+    {
+      if (constructor_range_stack)
+       abort ();
+
+      /* Designator list starts at the level of closest explicit
+        braces.  */
+      while (constructor_stack->implicit)
+       process_init_element (pop_init_level (1));
+      return 0;
+    }
+
+  if (constructor_no_implicit)
+    {
+      error_init ("initialization designators may not nest");
+      return 1;
+    }
+
+  if (TREE_CODE (constructor_type) == RECORD_TYPE
+      || TREE_CODE (constructor_type) == UNION_TYPE)
+    {
+      subtype = TREE_TYPE (constructor_fields);
+      if (subtype != error_mark_node)
+       subtype = TYPE_MAIN_VARIANT (subtype);
+    }
+  else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+    {
+      subtype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type));
+    }
+  else
+    abort ();
+
+  subcode = TREE_CODE (subtype);
+  if (array && subcode != ARRAY_TYPE)
+    {
+      error_init ("array index in non-array initializer");
+      return 1;
+    }
+  else if (!array && subcode != RECORD_TYPE && subcode != UNION_TYPE)
+    {
+      error_init ("field name not in record or union initializer");
+      return 1;
+    }
+
+  push_init_level (2);
+  return 0;
+}
+
+/* If there are range designators in designator list, push a new designator
+   to constructor_range_stack.  RANGE_END is end of such stack range or
+   NULL_TREE if there is no range designator at this level.  */
+
+static void
+push_range_stack (range_end)
+     tree range_end;
+{
+  struct constructor_range_stack *p;
+
+  p = (struct constructor_range_stack *)
+      ggc_alloc (sizeof (struct constructor_range_stack));
+  p->prev = constructor_range_stack;
+  p->next = 0;
+  p->fields = constructor_fields;
+  p->range_start = constructor_index;
+  p->index = constructor_index;
+  p->stack = constructor_stack;
+  p->range_end = range_end;
+  if (constructor_range_stack)
+    constructor_range_stack->next = p;
+  constructor_range_stack = p;
+}
+
 /* Within an array initializer, specify the next index to be initialized.
    FIRST is that index.  If LAST is nonzero, then initialize a range
    of indices, running from FIRST through LAST.  */
@@ -5485,6 +5644,11 @@ void
 set_init_index (first, last)
      tree first, last;
 {
+  if (set_designator (1))
+    return;
+
+  designator_errorneous = 1;
+
   while ((TREE_CODE (first) == NOP_EXPR
          || TREE_CODE (first) == CONVERT_EXPR
          || TREE_CODE (first) == NON_LVALUE_EXPR)
@@ -5504,18 +5668,34 @@ set_init_index (first, last)
     error_init ("nonconstant array index in initializer");
   else if (last != 0 && TREE_CODE (last) != INTEGER_CST)
     error_init ("nonconstant array index in initializer");
-  else if (! constructor_unfilled_index)
+  else if (TREE_CODE (constructor_type) != ARRAY_TYPE)
     error_init ("array index in non-array initializer");
-  else if (tree_int_cst_lt (first, constructor_unfilled_index))
-    error_init ("duplicate array index in initializer");
+  else if (constructor_max_index
+          && tree_int_cst_lt (constructor_max_index, first))
+    error_init ("array index in initializer exceeds array bounds");
   else
     {
       constructor_index = convert (bitsizetype, first);
 
       if (last != 0 && tree_int_cst_lt (last, first))
-       error_init ("empty index range in initializer");
-      else
-       constructor_range_end = last ? convert (bitsizetype, last) : 0;
+       {
+         error_init ("empty index range in initializer");
+         last = 0;
+       }
+      else if (last)
+       {
+         last = convert (bitsizetype, last);
+         if (constructor_max_index != 0
+             && tree_int_cst_lt (constructor_max_index, last))
+           {
+             error_init ("array index range in initializer exceeds array bounds");
+             last = 0;
+           }
+       }
+      designator_depth++;
+      designator_errorneous = 0;
+      if (constructor_range_stack || last)
+       push_range_stack (last);
     }
 }
 
@@ -5526,18 +5706,22 @@ set_init_label (fieldname)
      tree fieldname;
 {
   tree tail;
-  int passed = 0;
 
-  /* Don't die if an entire brace-pair level is superfluous
-     in the containing level.  */
-  if (constructor_type == 0)
+  if (set_designator (0))
     return;
 
+  designator_errorneous = 1;
+
+  if (TREE_CODE (constructor_type) != RECORD_TYPE
+      && TREE_CODE (constructor_type) != UNION_TYPE)
+    {
+      error_init ("field name not in record or union initializer");
+      return;
+    }
+    
   for (tail = TYPE_FIELDS (constructor_type); tail;
        tail = TREE_CHAIN (tail))
     {
-      if (tail == constructor_unfilled_fields)
-       passed = 1;
       if (DECL_NAME (tail) == fieldname)
        break;
     }
@@ -5545,11 +5729,14 @@ set_init_label (fieldname)
   if (tail == 0)
     error ("unknown field `%s' specified in initializer",
           IDENTIFIER_POINTER (fieldname));
-  else if (!passed)
-    error ("field `%s' already initialized",
-          IDENTIFIER_POINTER (fieldname));
   else
-    constructor_fields = tail;
+    {
+      constructor_fields = tail;
+      designator_depth++;
+      designator_errorneous = 0;
+      if (constructor_range_stack)
+       push_range_stack (NULL_TREE);
+    }
 }
 \f
 /* Add a new initializer to the tree of pending initializers.  PURPOSE
@@ -5572,24 +5759,36 @@ add_pending_init (purpose, value)
          p = *q;
          if (tree_int_cst_lt (purpose, p->purpose))
            q = &p->left;
-         else if (p->purpose != purpose)
+         else if (tree_int_cst_lt (p->purpose, purpose))
            q = &p->right;
          else
-           abort ();
+           {
+             if (TREE_SIDE_EFFECTS (p->value))
+               warning_init ("initialized field with side-effects overwritten");
+             p->value = value;
+             return;
+           }
        }
     }
   else
     {
+      tree bitpos;
+
+      bitpos = bit_position (purpose);
       while (*q != NULL)
        {
          p = *q;
-         if (tree_int_cst_lt (bit_position (purpose),
-                              bit_position (p->purpose)))
+         if (tree_int_cst_lt (bitpos, bit_position (p->purpose)))
            q = &p->left;
          else if (p->purpose != purpose)
            q = &p->right;
          else
-           abort ();
+           {
+             if (TREE_SIDE_EFFECTS (p->value))
+               warning_init ("initialized field with side-effects overwritten");
+             p->value = value;
+             return;
+           }
        }
     }
 
@@ -5758,41 +5957,178 @@ add_pending_init (purpose, value)
     }
 }
 
-/* Return nonzero if FIELD is equal to the index of a pending initializer.  */
+/* Build AVL tree from a sorted chain.  */
 
-static int
-pending_init_member (field)
+static void
+set_nonincremental_init ()
+{
+  tree chain;
+
+  if (TREE_CODE (constructor_type) != RECORD_TYPE
+      && TREE_CODE (constructor_type) != ARRAY_TYPE)
+    return;
+
+  for (chain = constructor_elements; chain; chain = TREE_CHAIN (chain))
+    add_pending_init (TREE_PURPOSE (chain), TREE_VALUE (chain));
+  constructor_elements = 0;
+  if (TREE_CODE (constructor_type) == RECORD_TYPE)
+    {
+      constructor_unfilled_fields = TYPE_FIELDS (constructor_type);
+      /* Skip any nameless bit fields at the beginning.  */
+      while (constructor_unfilled_fields != 0
+            && DECL_C_BIT_FIELD (constructor_unfilled_fields)
+            && DECL_NAME (constructor_unfilled_fields) == 0)
+       constructor_unfilled_fields = TREE_CHAIN (constructor_unfilled_fields);
+      
+    }
+  else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+    {
+      if (TYPE_DOMAIN (constructor_type))
+       constructor_unfilled_index
+           = convert (bitsizetype,
+                      TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type)));
+      else
+       constructor_unfilled_index = bitsize_zero_node;
+    }
+  constructor_incremental = 0;
+}
+
+/* Build AVL tree from a string constant.  */
+
+static void
+set_nonincremental_init_from_string (str)
+     tree str;
+{
+  tree value, purpose, type;
+  HOST_WIDE_INT val[2];
+  const char *p, *end;
+  int byte, wchar_bytes, charwidth, bitpos;
+
+  if (TREE_CODE (constructor_type) != ARRAY_TYPE)
+    abort ();
+
+  if (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (str)))
+      == TYPE_PRECISION (char_type_node))
+    wchar_bytes = 1;
+  else if (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (str)))
+          == TYPE_PRECISION (wchar_type_node))
+    wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
+  else
+    abort ();
+
+  charwidth = TYPE_PRECISION (char_type_node);
+  type = TREE_TYPE (constructor_type);
+  p = TREE_STRING_POINTER (str);
+  end = p + TREE_STRING_LENGTH (str);
+
+  for (purpose = bitsize_zero_node;
+       p < end && !tree_int_cst_lt (constructor_max_index, purpose);
+       purpose = size_binop (PLUS_EXPR, purpose, bitsize_one_node))
+    {
+      if (wchar_bytes == 1)
+       {
+         val[1] = (unsigned char) *p++;
+         val[0] = 0;
+       }
+      else
+       {
+         val[0] = 0;
+         val[1] = 0;
+         for (byte = 0; byte < wchar_bytes; byte++)
+           {
+             if (BYTES_BIG_ENDIAN)
+               bitpos = (wchar_bytes - byte - 1) * charwidth;
+             else
+               bitpos = byte * charwidth;
+             val[bitpos < HOST_BITS_PER_WIDE_INT]
+               |= ((unsigned HOST_WIDE_INT) ((unsigned char) *p++))
+                  << (bitpos % HOST_BITS_PER_WIDE_INT);
+           }
+       }
+
+      if (!TREE_UNSIGNED (type))
+       {
+         bitpos = ((wchar_bytes - 1) * charwidth) + HOST_BITS_PER_CHAR;
+         if (bitpos < HOST_BITS_PER_WIDE_INT)
+           {
+             if (val[1] & (((HOST_WIDE_INT) 1) << (bitpos - 1)))
+               {
+                 val[1] |= ((HOST_WIDE_INT) -1) << bitpos;
+                 val[0] = -1;
+               }
+           }
+         else if (bitpos == HOST_BITS_PER_WIDE_INT)
+           {
+             if (val[1] < 0)
+               val[0] = -1;
+           }
+         else if (val[0] & (((HOST_WIDE_INT) 1)
+                            << (bitpos - 1 - HOST_BITS_PER_WIDE_INT)))
+           val[0] |= ((HOST_WIDE_INT) -1)
+                     << (bitpos - HOST_BITS_PER_WIDE_INT);
+       }
+
+      value = build_int_2 (val[1], val[0]);
+      TREE_TYPE (value) = type;
+      add_pending_init (purpose, value);
+    }
+
+  constructor_incremental = 0;
+}
+
+/* Return value of FIELD in pending initializer or zero if the field was
+   not initialized yet.  */
+
+static tree
+find_init_member (field)
      tree field;
 {
   struct init_node *p;
 
-  p = constructor_pending_elts;
   if (TREE_CODE (constructor_type) == ARRAY_TYPE)
     {
+      if (constructor_incremental
+         && tree_int_cst_lt (field, constructor_unfilled_index))
+       set_nonincremental_init ();
+
+      p = constructor_pending_elts;
       while (p)
        {
-         if (field == p->purpose)
-           return 1;
-         else if (tree_int_cst_lt (field, p->purpose))
+         if (tree_int_cst_lt (field, p->purpose))
            p = p->left;
-         else
+         else if (tree_int_cst_lt (p->purpose, field))
            p = p->right;
+         else
+           return p->value;
        }
     }
-  else
+  else if (TREE_CODE (constructor_type) == RECORD_TYPE)
     {
+      tree bitpos = bit_position (field);
+
+      if (constructor_incremental
+         && (!constructor_unfilled_fields
+             || tree_int_cst_lt (bitpos,
+                                 bit_position (constructor_unfilled_fields))))
+       set_nonincremental_init ();
+
+      p = constructor_pending_elts;
       while (p)
        {
          if (field == p->purpose)
-           return 1;
-         else if (tree_int_cst_lt (bit_position (field),
-                                   bit_position (p->purpose)))
+           return p->value;
+         else if (tree_int_cst_lt (bitpos, bit_position (p->purpose)))
            p = p->left;
          else
            p = p->right;
        }
     }
-
+  else if (TREE_CODE (constructor_type) == UNION_TYPE)
+    {
+      if (constructor_elements
+         && TREE_PURPOSE (constructor_elements) == field)
+       return TREE_VALUE (constructor_elements);
+    }
   return 0;
 }
 
@@ -5811,8 +6147,6 @@ output_init_element (value, type, field, pending)
      tree value, type, field;
      int pending;
 {
-  int duplicate = 0;
-
   if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE
       || (TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
          && !(TREE_CODE (value) == STRING_CST
@@ -5840,90 +6174,111 @@ output_init_element (value, type, field, pending)
     }
   else if (require_constant_elements
           && initializer_constant_valid_p (value, TREE_TYPE (value)) == 0)
-    {
-      error_init ("initializer element is not computable at load time");
-      value = error_mark_node;
-    }
+    pedwarn ("initializer element is not computable at load time");
+
+  /* If this field is empty (and not at the end of structure),
+     don't do anything other than checking the initializer.  */
+  if (field
+      && (TREE_TYPE (field) == error_mark_node
+         || (COMPLETE_TYPE_P (TREE_TYPE (field))
+             && integer_zerop (TYPE_SIZE (TREE_TYPE (field)))
+             && (TREE_CODE (constructor_type) == ARRAY_TYPE
+                 || TREE_CHAIN (field)))))
+    return;
 
-  /* If this element duplicates one on constructor_pending_elts,
-     print a message and ignore it.  Don't do this when we're
-     processing elements taken off constructor_pending_elts,
-     because we'd always get spurious errors.  */
-  if (pending)
+  if (value == error_mark_node)
     {
-      if (TREE_CODE (constructor_type) == RECORD_TYPE
-         || TREE_CODE (constructor_type) == UNION_TYPE
-         || TREE_CODE (constructor_type) == ARRAY_TYPE)
-       {
-         if (pending_init_member (field))
-           {
-             error_init ("duplicate initializer");
-             duplicate = 1;
-           }
-       }
+      constructor_erroneous = 1;
+      return;
     }
 
   /* If this element doesn't come next in sequence,
      put it on constructor_pending_elts.  */
   if (TREE_CODE (constructor_type) == ARRAY_TYPE
-      && ! tree_int_cst_equal (field, constructor_unfilled_index))
+      && (!constructor_incremental
+         || !tree_int_cst_equal (field, constructor_unfilled_index)))
     {
-      if (! duplicate)
-       add_pending_init (field,
-                         digest_init (type, value, require_constant_value, 
-                                      require_constant_elements));
+      if (constructor_incremental
+         && tree_int_cst_lt (field, constructor_unfilled_index))
+       set_nonincremental_init ();
+
+      add_pending_init (field,
+                       digest_init (type, value, require_constant_value, 
+                                    require_constant_elements));
+      return;
     }
   else if (TREE_CODE (constructor_type) == RECORD_TYPE
-          && field != constructor_unfilled_fields)
+          && (!constructor_incremental
+              || field != constructor_unfilled_fields))
     {
       /* We do this for records but not for unions.  In a union,
         no matter which field is specified, it can be initialized
         right away since it starts at the beginning of the union.  */
-      if (!duplicate)
-       add_pending_init (field,
-                         digest_init (type, value, require_constant_value, 
-                                      require_constant_elements));
+      if (constructor_incremental)
+       {
+         if (!constructor_unfilled_fields)
+           set_nonincremental_init ();
+         else
+           {
+             tree bitpos, unfillpos;
+
+             bitpos = bit_position (field);
+             unfillpos = bit_position (constructor_unfilled_fields);
+
+             if (tree_int_cst_lt (bitpos, unfillpos))
+               set_nonincremental_init ();
+           }
+       }
+
+      add_pending_init (field,
+                       digest_init (type, value, require_constant_value, 
+                                    require_constant_elements));
+      return;
     }
-  else
+  else if (TREE_CODE (constructor_type) == UNION_TYPE
+          && constructor_elements)
     {
-      /* Otherwise, output this element either to
-        constructor_elements or to the assembler file.  */
+      if (TREE_SIDE_EFFECTS (TREE_VALUE (constructor_elements)))
+       warning_init ("initialized field with side-effects overwritten");
 
-      if (!duplicate)
-       {
-         if (field && TREE_CODE (field) == INTEGER_CST)
-           field = copy_node (field);
-         constructor_elements
-           = tree_cons (field, digest_init (type, value,
-                                            require_constant_value, 
-                                            require_constant_elements),
-                        constructor_elements);
-       }
+      /* We can have just one union field set.  */
+      constructor_elements = 0;
+    }
 
-      /* Advance the variable that indicates sequential elements output.  */
-      if (TREE_CODE (constructor_type) == ARRAY_TYPE)
-       constructor_unfilled_index
-         = size_binop (PLUS_EXPR, constructor_unfilled_index,
-                       bitsize_one_node);
-      else if (TREE_CODE (constructor_type) == RECORD_TYPE)
-       {
-         constructor_unfilled_fields
-           = TREE_CHAIN (constructor_unfilled_fields);
-
-         /* Skip any nameless bit fields.  */
-         while (constructor_unfilled_fields != 0
-                && DECL_C_BIT_FIELD (constructor_unfilled_fields)
-                && DECL_NAME (constructor_unfilled_fields) == 0)
-           constructor_unfilled_fields =
-             TREE_CHAIN (constructor_unfilled_fields);
-       }
-      else if (TREE_CODE (constructor_type) == UNION_TYPE)
-       constructor_unfilled_fields = 0;
+  /* Otherwise, output this element either to
+     constructor_elements or to the assembler file.  */
+
+  if (field && TREE_CODE (field) == INTEGER_CST)
+    field = copy_node (field);
+  constructor_elements
+    = tree_cons (field, digest_init (type, value,
+                                    require_constant_value, 
+                                    require_constant_elements),
+                constructor_elements);
+
+  /* Advance the variable that indicates sequential elements output.  */
+  if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+    constructor_unfilled_index
+      = size_binop (PLUS_EXPR, constructor_unfilled_index,
+                   bitsize_one_node);
+  else if (TREE_CODE (constructor_type) == RECORD_TYPE)
+    {
+      constructor_unfilled_fields
+       = TREE_CHAIN (constructor_unfilled_fields);
 
-      /* Now output any pending elements which have become next.  */
-      if (pending)
-       output_pending_init_elements (0);
+      /* Skip any nameless bit fields.  */
+      while (constructor_unfilled_fields != 0
+            && DECL_C_BIT_FIELD (constructor_unfilled_fields)
+            && DECL_NAME (constructor_unfilled_fields) == 0)
+       constructor_unfilled_fields =
+         TREE_CHAIN (constructor_unfilled_fields);
     }
+  else if (TREE_CODE (constructor_type) == UNION_TYPE)
+    constructor_unfilled_fields = 0;
+
+  /* Now output any pending elements which have become next.  */
+  if (pending)
+    output_pending_init_elements (0);
 }
 
 /* Output any pending elements which have become next.
@@ -5999,18 +6354,23 @@ output_pending_init_elements (all)
       else if (TREE_CODE (constructor_type) == RECORD_TYPE
               || TREE_CODE (constructor_type) == UNION_TYPE)
        {
+         tree ctor_unfilled_bitpos, elt_bitpos;
+
          /* If the current record is complete we are done.  */
          if (constructor_unfilled_fields == 0)
            break;
-         if (elt->purpose == constructor_unfilled_fields)
+
+         ctor_unfilled_bitpos = bit_position (constructor_unfilled_fields);
+         elt_bitpos = bit_position (elt->purpose);
+         /* We can't compare fields here because there might be empty
+            fields in between.  */
+         if (tree_int_cst_equal (elt_bitpos, ctor_unfilled_bitpos))
            {
-             output_init_element (elt->value,
-                                  TREE_TYPE (constructor_unfilled_fields),
-                                  constructor_unfilled_fields,
-                                  0);
+             constructor_unfilled_fields = elt->purpose;
+             output_init_element (elt->value, TREE_TYPE (elt->purpose),
+                                  elt->purpose, 0);
            }
-         else if (tree_int_cst_lt (bit_position (constructor_unfilled_fields),
-                                   bit_position (elt->purpose)))
+         else if (tree_int_cst_lt (ctor_unfilled_bitpos, elt_bitpos))
            {
              /* Advance to the next smaller node.  */
              if (elt->left)
@@ -6036,9 +6396,8 @@ output_pending_init_elements (all)
                    elt = elt->parent;
                  elt = elt->parent;
                  if (elt
-                     && (tree_int_cst_lt
-                         (bit_position (constructor_unfilled_fields),
-                          bit_position (elt->purpose))))
+                     && (tree_int_cst_lt (ctor_unfilled_bitpos,
+                                          bit_position (elt->purpose))))
                    {
                      next = elt->purpose;
                      break;
@@ -6081,6 +6440,9 @@ process_init_element (value)
   tree orig_value = value;
   int string_flag = value != 0 && TREE_CODE (value) == STRING_CST;
 
+  designator_depth = 0;
+  designator_errorneous = 0;
+
   /* Handle superfluous braces around string cst as in
      char x[] = {"foo"}; */
   if (string_flag
@@ -6123,6 +6485,10 @@ process_init_element (value)
        break;
     }
 
+  /* In the case of [LO ... HI] = VALUE, only evaluate VALUE once.  */
+  if (constructor_range_stack)
+    value = save_expr (value);
+
   while (1)
     {
       if (TREE_CODE (constructor_type) == RECORD_TYPE)
@@ -6191,9 +6557,8 @@ process_init_element (value)
                 && DECL_C_BIT_FIELD (constructor_fields)
                 && DECL_NAME (constructor_fields) == 0)
            constructor_fields = TREE_CHAIN (constructor_fields);
-         break;
        }
-      if (TREE_CODE (constructor_type) == UNION_TYPE)
+      else if (TREE_CODE (constructor_type) == UNION_TYPE)
        {
          tree fieldtype;
          enum tree_code fieldcode;
@@ -6252,9 +6617,8 @@ process_init_element (value)
            }
 
          constructor_fields = 0;
-         break;
        }
-      if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+      else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
        {
          tree elttype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type));
          enum tree_code eltcode = TREE_CODE (elttype);
@@ -6285,61 +6649,93 @@ process_init_element (value)
              break;
            }
 
-         /* In the case of [LO .. HI] = VALUE, only evaluate VALUE once.  */
-         if (constructor_range_end)
+         /* Now output the actual element.  */
+         if (value)
            {
-             if (constructor_max_index != 0
-                 && tree_int_cst_lt (constructor_max_index, 
-                                     constructor_range_end))
-               {
-                 pedwarn_init ("excess elements in array initializer");
-                 constructor_range_end = constructor_max_index;
-               }
-
-             value = save_expr (value);
+             push_array_bounds (tree_low_cst (constructor_index, 0));
+             output_init_element (value, elttype, constructor_index, 1);
+             RESTORE_SPELLING_DEPTH (constructor_depth);
            }
 
-         /* Now output the actual element.
-            Ordinarily, output once.
-            If there is a range, repeat it till we advance past the range.  */
-         do
-           {
-             if (value)
-               {
-                 push_array_bounds (tree_low_cst (constructor_index, 0));
-                 output_init_element (value, elttype, constructor_index, 1);
-                 RESTORE_SPELLING_DEPTH (constructor_depth);
-               }
-
-             constructor_index
-               = size_binop (PLUS_EXPR, constructor_index, bitsize_one_node);
-
-             if (! value)
-               /* If we are doing the bookkeeping for an element that was
-                  directly output as a constructor, we must update
-                  constructor_unfilled_index.  */
-               constructor_unfilled_index = constructor_index;
-           }
-         while (! (constructor_range_end == 0
-                   || tree_int_cst_lt (constructor_range_end,
-                                       constructor_index)));
+         constructor_index
+           = size_binop (PLUS_EXPR, constructor_index, bitsize_one_node);
 
-         break;
+         if (! value)
+           /* If we are doing the bookkeeping for an element that was
+              directly output as a constructor, we must update
+              constructor_unfilled_index.  */
+           constructor_unfilled_index = constructor_index;
        }
 
       /* Handle the sole element allowed in a braced initializer
         for a scalar variable.  */
-      if (constructor_fields == 0)
+      else if (constructor_fields == 0)
        {
          pedwarn_init ("excess elements in scalar initializer");
          break;
        }
+      else
+       {
+         if (value)
+           output_init_element (value, constructor_type, NULL_TREE, 1);
+         constructor_fields = 0;
+       }
+
+      /* Handle range initializers either at this level or anywhere higher
+        in the designator stack.  */
+      if (constructor_range_stack)
+       {
+         struct constructor_range_stack *p, *range_stack;
+         int finish = 0;
+
+         range_stack = constructor_range_stack;
+         constructor_range_stack = 0;
+         while (constructor_stack != range_stack->stack)
+           {
+             if (!constructor_stack->implicit)
+               abort ();
+             process_init_element (pop_init_level (1));
+           }
+         for (p = range_stack;
+              !p->range_end || tree_int_cst_equal (p->index, p->range_end);
+              p = p->prev)
+           {
+             if (!constructor_stack->implicit)
+               abort ();
+             process_init_element (pop_init_level (1));
+           }
+
+         p->index = size_binop (PLUS_EXPR, p->index, bitsize_one_node);
+         if (tree_int_cst_equal (p->index, p->range_end) && !p->prev)
+           finish = 1;
+
+         while (1)
+           {
+             constructor_index = p->index;
+             constructor_fields = p->fields;
+             if (finish && p->range_end && p->index == p->range_start)
+               {
+                 finish = 0;
+                 p->prev = 0;
+               }
+             p = p->next;
+             if (!p)
+               break;
+             push_init_level (2);
+             p->stack = constructor_stack;
+             if (p->range_end && tree_int_cst_equal (p->index, p->range_end))
+               p->index = p->range_start;
+           }
+
+         if (!finish)
+           constructor_range_stack = range_stack;
+         continue;
+       }
 
-      if (value)
-       output_init_element (value, constructor_type, NULL_TREE, 1);
-      constructor_fields = 0;
       break;
     }
+
+  constructor_range_stack = 0;
 }
 \f
 /* Build an asm-statement, whose components are a CV_QUALIFIER, a
index 45dda7cb3197d4f70d6f91a65b4f96979d3750de..005bd7ec848fd89bebd4f2683c41550dffe5dec2 100644 (file)
@@ -1260,6 +1260,10 @@ extension.  For example,
 int widths[] = @{ [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 @};
 @end example
 
+@noindent
+If the value in it has side-effects, the side-effects will happen only once,
+not for each initialized field by the range initializer.
+
 @noindent
 Note that the length of the array is the highest value specified
 plus one.
@@ -1345,6 +1349,12 @@ example, with the @samp{struct point} declaration above:
 struct point ptarray[10] = @{ [2].y = yv2, [2].x = xv2, [0].x = xv0 @};
 @end example
 
+@noindent
+If the same field is initialized multiple times, it will have value from
+the last initialization.  If any such overridden initialization has
+side-effect, it is unspecified whether the side-effect happens or not.
+Currently, gcc will discard them and issue a warning.
+
 @node Case Ranges
 @section Case Ranges
 @cindex case ranges
index 52c7aed7b0d43a157906044c074a27d7cc0af4d6..f34c384267e0618346c0d8569c6a9f4ec36ad7fb 100644 (file)
@@ -1,3 +1,11 @@
+2001-01-12  Jakub Jelinek  <jakub@redhat.com>
+
+       * gcc.c-torture/execute/20000801-3.x: Remove.
+       * gcc.dg/c90-init-1.c: New test.
+       * gcc.dg/c99-init-1.c: New test.
+       * gcc.dg/c99-init-2.c: New test.
+       * gcc.dg/gnu99-init-1.c: New test.
+
 2001-01-12  Richard Earnshaw <rearnsha@arm.com>
 
        * lib/f-torture.exp (f_torture_compile): Prune the warnings before
diff --git a/gcc/testsuite/gcc.c-torture/execute/20000801-3.x b/gcc/testsuite/gcc.c-torture/execute/20000801-3.x
deleted file mode 100644 (file)
index 2f397b9..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-set torture_execute_xfail "*-*-*"
-return 0
diff --git a/gcc/testsuite/gcc.dg/c90-init-1.c b/gcc/testsuite/gcc.dg/c90-init-1.c
new file mode 100644 (file)
index 0000000..1ea0bdb
--- /dev/null
@@ -0,0 +1,25 @@
+/* Test for C99 designated initializers */
+/* Origin: Jakub Jelinek <jakub@redhat.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */
+
+struct A {
+  int B;
+  short C[2];
+};
+int a[10] = { 10, [4] = 15 };                  /* { dg-error "ISO C89 forbids specifying subobject to initialize" } */
+struct A b = { .B = 2 };                       /* { dg-error "ISO C89 forbids specifying subobject to initialize" } */
+struct A c[] = { [3].C[1] = 1 };               /* { dg-error "ISO C89 forbids specifying subobject to initialize" } */
+struct A d[] = { [4 ... 6].C[0 ... 1] = 2 };   /* { dg-error "(forbids specifying range of elements to initialize)|(ISO C89 forbids specifying subobject to initialize)" } */
+int e[] = { [2] 2 };                           /* { dg-error "use of designated initializer without" } */
+struct A f = { C: { 0, 1 } };                  /* { dg-error "use of designated initializer with " } */
+int g;
+
+void foo (int *);
+
+void bar (void)
+{
+  int x[] = { g++, 2 };                                /* { dg-error "is not computable at load time" } */
+
+  foo (x);
+}
diff --git a/gcc/testsuite/gcc.dg/c99-init-1.c b/gcc/testsuite/gcc.dg/c99-init-1.c
new file mode 100644 (file)
index 0000000..95803c2
--- /dev/null
@@ -0,0 +1,78 @@
+/* Test for C99 designated initializers */
+/* Origin: Jakub Jelinek <jakub@redhat.com> */
+/* { dg-do run } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+
+typedef __SIZE_TYPE__ size_t;
+typedef __WCHAR_TYPE__ wchar_t;
+extern int memcmp (const void *, const void *, size_t);
+extern void abort (void);
+extern void exit (int);
+
+int a[10] = { 10, 0, 12, 13, 14, 0, 0, 17, 0, 0 };
+int b[10] = { 10, [4] = 15, [2] = 12, [4] = 14, [7] = 17 };
+int c[10] = { 10, [4] = 15, [2] = 12, [3] = 13, 14, [7] = 17 };
+struct A {
+  int B;
+  short C[2];
+};
+struct A d[] = { { 0, { 1, 2 } }, { 0, { 0, 0 } }, { 10, { 11, 12 } } };
+struct A e[] = { 0, 1, 2, [2] = 10, 11, 12 };
+struct A f[] = { 0, 1, 2, [2].C = 11, 12, 13 };
+struct A g[] = { 0, 1, 2, [2].C[1] = 12, 13, 14 };
+struct A h[] = { 0, 1, 2, [2] = { .C[1] = 12 }, 13, 14 };
+struct A i[] = { 0, 1, 2, [2] = { .C = { [1] = 12 } }, 13, 14 };
+union D {
+  int E;
+  double F;
+  struct A G;
+};
+union D j[] = { [4] = 1, [4].F = 1.0, [1].G.C[1] = 4 };
+struct H {
+  char I[6];
+  int J;
+} k[] = { { { "foo" }, 1 }, [0].I[0] = 'b' };
+struct K {
+  wchar_t L[6];
+  int M;
+} l[] = { { { L"foo" }, 1 }, [0].L[2] = L'x', [0].L[4] = L'y' };
+struct H m[] = { { { "foo" }, 1 }, [0] = { .I[0] = 'b' } };
+struct H n[] = { { { "foo" }, 1 }, [0].I = { "a" }, [0].J = 2 };
+int o = { 22 };
+
+int main (void)
+{
+  if (b[3])
+    abort ();
+  b[3] = 13;
+  if (memcmp (a, b, sizeof (a)) || memcmp (a, c, sizeof (a)))
+    abort ();
+  if (memcmp (d, e, sizeof (d)) || sizeof (d) != sizeof (e))
+    abort ();
+  if (f[2].B != 0 || g[2].B != 0 || g[2].C[0] != 0)
+    abort ();
+  if (memcmp (g, h, sizeof (g)) || memcmp (g, i, sizeof (g)))
+    abort ();
+  f[2].B = 10;
+  g[2].B = 10;
+  g[2].C[0] = 11;
+  if (memcmp (d, f, sizeof (d)) || memcmp (d, g, sizeof (d)))
+    abort ();
+  if (f[3].B != 13 || g[3].B != 13 || g[3].C[0] != 14)
+    abort ();
+  if (j[0].E || j[1].G.B || j[1].G.C[0] || j[1].G.C[1] != 4)
+    abort ();
+  if (j[2].E || j[3].E || j[4].F != 1.0)
+    abort ();
+  if (memcmp (k[0].I, "boo\0\0", 6) || k[0].J != 1)
+    abort ();
+  if (memcmp (l[0].L, L"fox\0y", 6 * sizeof(wchar_t)) || l[0].M != 1)
+    abort ();
+  if (memcmp (m[0].I, "b\0\0\0\0", 6) || m[0].J)
+    abort ();
+  if (memcmp (n[0].I, "a\0\0\0\0", 6) || n[0].J != 2)
+    abort ();
+  if (o != 22)
+    abort ();
+  exit (0);
+}
diff --git a/gcc/testsuite/gcc.dg/c99-init-2.c b/gcc/testsuite/gcc.dg/c99-init-2.c
new file mode 100644 (file)
index 0000000..d3a331f
--- /dev/null
@@ -0,0 +1,30 @@
+/* Test for C99 designated initializer warnings and errors */
+/* Origin: Jakub Jelinek <jakub@redhat.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -Wall -pedantic-errors" } */
+
+typedef struct {
+  int B;
+  short C[2];
+} A;
+A a = { [2] = 1 };                     /* { dg-error "(array index in non-array)|(near initialization)" } */
+int b[] = { .B = 1 };                  /* { dg-error "(field name not in record)|(near initialization)" } */
+A c[] = { [0].D = 1 };                 /* { dg-error "unknown field" } */
+int d;
+int e = { d++ };                       /* { dg-error "(is not constant)|(near initialization)" } */
+A f[2] = { [0].C[0] = 1, [2] = { 2, { 1, 2 } } };/* { dg-error "(array index in initializer exceeds array bounds)|(near initialization)" } */
+int g[4] = { [1] = 1, 2, [6] = 5 };    /* { dg-error "(array index in initializer exceeds array bounds)|(near initialization)" } */
+int h[] = { [0 ... 3] = 5 };           /* { dg-error "forbids specifying range of elements" } */
+int i[] = { [2] 4 };                   /* { dg-error "use of designated initializer without" } */
+A j = { B: 2 };                                /* { dg-error "use of designated initializer with " } */
+
+void foo (int *, A *);
+
+void bar (void)
+{
+  int a[] = { d++, [0] = 1 };          /* { dg-warning "(initialized field with side-effects overwritten)|(near initialization)" } */
+  A b = { 1, { d++, 2 }, .C[0] = 3 };/* { dg-warning "(initialized field with side-effects overwritten)|(near initialization)" } */
+  A c = { d++, { 2, 3 }, .B = 4 };     /* { dg-warning "(initialized field with side-effects overwritten)|(near initialization)" } */
+
+  foo (a, d ? &b : &c);
+}
diff --git a/gcc/testsuite/gcc.dg/gnu99-init-1.c b/gcc/testsuite/gcc.dg/gnu99-init-1.c
new file mode 100644 (file)
index 0000000..c78f176
--- /dev/null
@@ -0,0 +1,62 @@
+/* Test for GNU extensions to C99 designated initializers */
+/* Origin: Jakub Jelinek <jakub@redhat.com> */
+/* { dg-do run } */
+/* { dg-options "-std=gnu99" } */
+
+typedef __SIZE_TYPE__ size_t;
+extern int memcmp (const void *, const void *, size_t);
+extern void abort (void);
+extern void exit (int);
+
+int a[][2][4] = { [2 ... 4][0 ... 1][2 ... 3] = 1, [2] = 2, [2][0][2] = 3 };
+struct E {};
+struct F { struct E H; };
+struct G { int I; struct E J; int K; };
+struct H { int I; struct F J; int K; };
+struct G k = { .J = {}, 1 };
+struct H l = { .J.H = {}, 2 };
+struct H m = { .J = {}, 3 };
+struct I { int J; int K[3]; int L; };
+struct M { int N; struct I O[3]; int P; };
+struct M n[] = { [0 ... 5].O[1 ... 2].K[0 ... 1] = 4, 5, 6, 7 };
+
+int main (void)
+{
+  int x, y, z;
+
+  if (a[2][0][0] != 2 || a[2][0][2] != 3)
+    abort ();
+  a[2][0][0] = 0;
+  a[2][0][2] = 1;
+  for (x = 0; x <= 4; x++)
+    for (y = 0; y <= 1; y++)
+      for (z = 0; z <= 3; z++)
+       if (a[x][y][z] != (x >= 2 && z >= 2))
+         abort ();
+  if (k.I || l.I || m.I || k.K != 1 || l.K != 2 || m.K != 3)
+    abort ();
+  for (x = 0; x <= 5; x++)
+    {
+      if (n[x].N || n[x].O[0].J || n[x].O[0].L)
+       abort ();
+      for (y = 0; y <= 2; y++)
+       if (n[x].O[0].K[y])
+         abort ();
+      for (y = 1; y <= 2; y++)
+       {
+         if (n[x].O[y].J)
+           abort ();
+         if (n[x].O[y].K[0] != 4)
+           abort ();
+         if (n[x].O[y].K[1] != 4)
+           abort ();
+         if ((x < 5 || y < 2) && (n[x].O[y].K[2] || n[x].O[y].L))
+           abort ();
+       }
+      if (x < 5 && n[x].P)
+       abort ();
+    }
+  if (n[5].O[2].K[2] != 5 || n[5].O[2].L != 6 || n[5].P != 7)
+    abort ();
+  exit (0);
+}