Output most constructors an element at a time.
authorRichard Stallman <rms@gnu.org>
Fri, 23 Jul 1993 18:49:55 +0000 (18:49 +0000)
committerRichard Stallman <rms@gnu.org>
Fri, 23 Jul 1993 18:49:55 +0000 (18:49 +0000)
(digest_init): Deleted code for raw constructors.
(process_init_constructor): Function deleted.
(start_init, finish_init): New functions.
(really_start_incremental_init)
(push_init_level, check_init_type_bitfields, pop_init_level)
(set_init_index, set_init_label, process_init_element)
(output_init_element, output_pending_init_elements): New functions.

From-SVN: r4973

gcc/c-typeck.c

index ab2b9216533c58f2e18f90b22679ce738891ac17..8c88dbb34520f88b9a42a1c6d8d9d5dc5b598d54 100644 (file)
@@ -55,13 +55,14 @@ static tree unary_complex_lvalue ();
 static tree process_init_constructor ();
 static tree convert_arguments ();
 static char *get_spelling ();
-tree digest_init ();
+static tree digest_init ();
 static void pedantic_lvalue_warning ();
 tree truthvalue_conversion ();
 void incomplete_type_error ();
 void readonly_warning ();
 static tree internal_build_compound_expr ();
 
+void process_init_element ();
 \f
 /* Do `exp = require_complete_type (exp);' to make sure exp
    does not have an incomplete type.  (That includes void types.)  */
@@ -4831,25 +4832,15 @@ static tree free_tree_list = NULL_TREE;
    (That is true for all nested calls to digest_init.)  */
 
 tree
-digest_init (type, init, tail, require_constant, constructor_constant, ofwhat)
+digest_init (type, init, tail, require_constant, constructor_constant)
      tree type, init, *tail;
      int require_constant, constructor_constant;
-     char *ofwhat;
 {
   enum tree_code code = TREE_CODE (type);
   tree element = 0;
   tree old_tail_contents;
-  /* Nonzero if INIT is a braced grouping, which comes in as a CONSTRUCTOR
-     tree node which has no TREE_TYPE.  */
-  int raw_constructor
-    = TREE_CODE (init) == CONSTRUCTOR && TREE_TYPE (init) == 0;
   tree inside_init = init;
 
-  /* Make sure there is just one "partially bracketed" message
-     per top-level initializer or constructor.  */
-  if (ofwhat != 0)
-    partial_bracket_mentioned = 0;
-
   /* By default, assume we use one element from a list.
      We correct this later in the cases where it is not true.
 
@@ -4876,16 +4867,6 @@ digest_init (type, init, tail, require_constant, constructor_constant, ofwhat)
   if (TREE_CODE (init) == NON_LVALUE_EXPR)
     inside_init = TREE_OPERAND (init, 0);
 
-  if (inside_init && raw_constructor
-      && CONSTRUCTOR_ELTS (inside_init) != 0
-      && TREE_CHAIN (CONSTRUCTOR_ELTS (inside_init)) == 0)
-    {
-      element = TREE_VALUE (CONSTRUCTOR_ELTS (inside_init));
-      /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue.  */
-      if (element && TREE_CODE (element) == NON_LVALUE_EXPR)
-       element = TREE_OPERAND (element, 0);
-    }
-
   /* Initialization of an array of chars from a string constant
      optionally enclosed in braces.  */
 
@@ -4907,7 +4888,7 @@ digest_init (type, init, tail, require_constant, constructor_constant, ofwhat)
              && TYPE_PRECISION (typ1) == TYPE_PRECISION (char_type_node))
            {
              error_init ("char-array%s initialized from wide string",
-                         " `%s'", ofwhat);
+                         " `%s'", NULL);
              return error_mark_node;
            }
          if ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (string)))
@@ -4915,7 +4896,7 @@ digest_init (type, init, tail, require_constant, constructor_constant, ofwhat)
              && TYPE_PRECISION (typ1) != TYPE_PRECISION (char_type_node))
            {
              error_init ("int-array%s initialized from non-wide string",
-                         " `%s'", ofwhat);
+                         " `%s'", NULL);
              return error_mark_node;
            }
 
@@ -4934,15 +4915,14 @@ digest_init (type, init, tail, require_constant, constructor_constant, ofwhat)
                     : 1))
                pedwarn_init (
                  "initializer-string for array of chars%s is too long",
-                 " `%s'", ofwhat);
+                 " `%s'", NULL);
            }
          return string;
        }
     }
 
-  /* Any type except an array can be initialized
-     from an expression of the same type, optionally with braces.
-     For an array, this is allowed only for a string constant.  */
+  /* Any type can be initialized
+     from an expression of the same type, optionally with braces.  */
 
   if (inside_init && TREE_TYPE (inside_init) != 0
       && ((TYPE_MAIN_VARIANT (TREE_TYPE (inside_init))
@@ -4959,10 +4939,11 @@ digest_init (type, init, tail, require_constant, constructor_constant, ofwhat)
          && (TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE
              || TREE_CODE (TREE_TYPE (inside_init)) == FUNCTION_TYPE))
        inside_init = default_conversion (inside_init);
-      else if (code == ARRAY_TYPE && TREE_CODE (inside_init) != STRING_CST)
+      else if (code == ARRAY_TYPE && TREE_CODE (inside_init) != STRING_CST
+              && TREE_CODE (inside_init) != CONSTRUCTOR)
        {
          error_init ("array%s initialized from non-constant array expression",
-                     " `%s'", ofwhat);
+                     " `%s'", NULL);
          return error_mark_node;
        }
 
@@ -4973,14 +4954,14 @@ digest_init (type, init, tail, require_constant, constructor_constant, ofwhat)
       if (require_constant && ! TREE_CONSTANT (inside_init))
        {
          error_init ("initializer element%s is not constant",
-                     " for `%s'", ofwhat);
+                     " for `%s'", NULL);
          inside_init = error_mark_node;
        }
       else if (require_constant
               && initializer_constant_valid_p (inside_init, TREE_TYPE (inside_init)) == 0)
        {
          error_init ("initializer element%s is not computable at load time",
-                     " for `%s'", ofwhat);
+                     " for `%s'", NULL);
          inside_init = error_mark_node;
        }
 
@@ -4994,7 +4975,7 @@ digest_init (type, init, tail, require_constant, constructor_constant, ofwhat)
       if (code == ARRAY_TYPE)
        {
          error_init ("array%s initialized from non-constant array expression",
-                     " `%s'", ofwhat);
+                     " `%s'", NULL);
          return error_mark_node;
        }
       if (pedantic && (code == RECORD_TYPE || code == UNION_TYPE))
@@ -5005,108 +4986,32 @@ digest_init (type, init, tail, require_constant, constructor_constant, ofwhat)
       if (require_constant && ! TREE_CONSTANT (element))
        {
          error_init ("initializer element%s is not constant",
-                     " for `%s'", ofwhat);
+                     " for `%s'", NULL);
          element = error_mark_node;
        }
       else if (require_constant
               && initializer_constant_valid_p (element, TREE_TYPE (element)) == 0)
        {
          error_init ("initializer element%s is not computable at load time",
-                     " for `%s'", ofwhat);
+                     " for `%s'", NULL);
          element = error_mark_node;
        }
 
       return element;
     }
 
-  /* Check for initializing a union by its first field.
-     Such an initializer must use braces.  */
-
-  if (code == UNION_TYPE)
-    {
-      tree result;
-      tree field = TYPE_FIELDS (type);
-
-      /* Find the first named field.  ANSI decided in September 1990
-        that only named fields count here.  */
-      while (field && DECL_NAME (field) == 0)
-       field = TREE_CHAIN (field);
-
-      if (field == 0)
-       {
-         error_init ("union%s with no named members cannot be initialized",
-                     " `%s'", ofwhat);
-         return error_mark_node;
-       }
-
-      if (raw_constructor)
-       result = process_init_constructor (type, inside_init, NULL_PTR,
-                                          require_constant,
-                                          constructor_constant, ofwhat);
-      else if (tail != 0)
-       {
-         *tail = old_tail_contents;
-         free_tree_list = NULL_TREE;
-         result = process_init_constructor (type, NULL_TREE, tail,
-                                            require_constant,
-                                            constructor_constant, ofwhat);
-       }
-      else
-       result = 0;
-
-      if (result)
-       return result;
-    }
-
   /* Handle scalar types, including conversions.  */
 
   if (code == INTEGER_TYPE || code == REAL_TYPE || code == POINTER_TYPE
       || code == ENUMERAL_TYPE || code == COMPLEX_TYPE)
     {
-      if (raw_constructor)
-       {
-         if (element == 0)
-           {
-             error_init (
-                 "initializer for scalar%s requires one element",
-                 " `%s'", ofwhat);
-             return error_mark_node;
-           }
-         else
-           {
-             /* Deal with extra levels of {...}.  */
-             if (TREE_CODE (element) == CONSTRUCTOR
-                 && TREE_TYPE (element) == 0)
-               {
-                 error_init (
-                             "initializer for scalar%s requires one element",
-                             " `%s'", ofwhat);
-                 return error_mark_node;
-               }
-             inside_init = element;
-           }
-       }
-
-#if 0  /* A non-raw constructor is an actual expression.  */
-      if (TREE_CODE (inside_init) == CONSTRUCTOR)
-       {
-         error_init ("initializer for scalar%s has extra braces",
-                     " `%s'", ofwhat);
-         return error_mark_node;
-       }
-#endif
-
       SAVE_SPELLING_DEPTH
        ({
-         if (ofwhat)
-           push_string (ofwhat);
-         if (!raw_constructor)
-           inside_init = init;
          /* Note that convert_for_assignment calls default_conversion
             for arrays and functions.  We must not call it in the
             case where inside_init is a null pointer constant.  */
          inside_init
-           = convert_for_assignment (type, inside_init, 
+           = convert_for_assignment (type, init, 
                                      &initialization_message,
                                      NULL_TREE, NULL_TREE, 0);
        });
@@ -5114,14 +5019,14 @@ digest_init (type, init, tail, require_constant, constructor_constant, ofwhat)
       if (require_constant && ! TREE_CONSTANT (inside_init))
        {
          error_init ("initializer element%s is not constant",
-                     " for `%s'", ofwhat);
+                     " for `%s'", NULL);
          inside_init = error_mark_node;
        }
       else if (require_constant
               && initializer_constant_valid_p (inside_init, TREE_TYPE (inside_init)) == 0)
        {
          error_init ("initializer element%s is not computable at load time",
-                     " for `%s'", ofwhat);
+                     " for `%s'", NULL);
          inside_init = error_mark_node;
        }
 
@@ -5133,582 +5038,1071 @@ digest_init (type, init, tail, require_constant, constructor_constant, ofwhat)
   if (TYPE_SIZE (type) && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
     {
       error_init ("variable-sized object%s may not be initialized",
-                 " `%s'", ofwhat);
+                 " `%s'", NULL);
       return error_mark_node;
     }
 
-  if (code == ARRAY_TYPE || code == RECORD_TYPE)
-    {
-      if (raw_constructor)
-       return process_init_constructor (type, inside_init,
-                                        NULL_PTR, constructor_constant,
-                                        constructor_constant, ofwhat);
-      else if (tail != 0)
-       {
-         *tail = old_tail_contents;
-         free_tree_list = NULL_TREE;
-         return process_init_constructor (type, NULL_TREE, tail,
-                                          constructor_constant,
-                                          constructor_constant, ofwhat);
-       }
-      else if (flag_traditional)
-       /* Traditionally one can say `char x[100] = 0;'.  */
-       return process_init_constructor (type,
-                                        build_nt (CONSTRUCTOR, NULL_TREE,
-                                                  tree_cons (NULL_TREE,
-                                                             inside_init,
-                                                             NULL_TREE)),
-                                        NULL_PTR, constructor_constant,
-                                        constructor_constant, ofwhat);
-    }
-
-  error_init ("invalid initializer%s", " for `%s'", ofwhat);
+  error_init ("invalid initializer%s", " for `%s'", NULL);
   return error_mark_node;
 }
 \f
-/* Process a constructor for a variable of type TYPE.
-   The constructor elements may be specified either with INIT or with ELTS,
-   only one of which should be non-null.
+/* Handle initializers that use braces.  */
 
-   If INIT is specified, it is a CONSTRUCTOR node which is specifically
-   and solely for initializing this datum.
+static void output_pending_init_elements ();
+static void check_init_type_bitfields ();
 
-   If ELTS is specified, it is the address of a variable containing
-   a list of expressions.  We take as many elements as we need
-   from the head of the list and update the list.
+/* Type of object we are accumulating a constructor for.
+   This type is always a RECORD_TYPE, UNION_TYPE or ARRAY_TYPE.  */
+static tree constructor_type;
 
-   In the resulting constructor, TREE_CONSTANT is set if all elts are
-   constant, and TREE_STATIC is set if, in addition, all elts are simple enough
-   constants that the assembler and linker can compute them.
+/* For a RECORD_TYPE or UNION_TYPE, this is the chain of fields
+   left to fill.  */
+static tree constructor_fields;
 
-   The argument CONSTANT_VALUE says to print an error if either the
-   value or any element is not a constant.
+/* For an ARRAY_TYPE, this is the specified index
+   at which to store the next element we get.
+   This is a special INTEGER_CST node that we modify in place.  */
+static tree constructor_index;
 
-   The argument CONSTANT_ELEMENT says to print an error if an element
-   of an aggregate is not constant.  It does not apply to a value
-   which is not a constructor.  
+/* For an ARRAY_TYPE, this is the end index of the range
+   to intitialize with the next element, or NULL in the ordinary case
+   where the element is used just once.  */
+static tree constructor_range_end;
 
-   OFWHAT is a character string describing the object being initialized,
-   for error messages.  It might be "variable" or "variable.member"
-   or "variable[17].member[5]".
+/* For an ARRAY_TYPE, this is the maximum index.  */
+static tree constructor_max_index;
 
-   If OFWHAT is null, the description string is stored on the spelling
-   stack.  That is always true for recursive calls.  */
+/* For a RECORD_TYPE, this is the first field not yet written out.  */
+static tree constructor_unfilled_fields;
 
-static tree
-process_init_constructor (type, init, elts, constant_value, constant_element,
-                         ofwhat)
-     tree type, init, *elts;
-     int constant_value, constant_element;
-     char *ofwhat;
+/* For an ARRAY_TYPE, this is the index of the first element
+   not yet written out.
+   This is a special INTEGER_CST node that we modify in place.  */
+static tree constructor_unfilled_index;
+
+/* If we are saving up the elements rather than allocating them,
+   this is the list of elements so far (in reverse order,
+   most recent first).  */
+static tree constructor_elements;
+
+/* 1 if so far this constructor's elements are all compile-time constants.  */
+static int constructor_constant;
+
+/* 1 if so far this constructor's elements are all valid address constants.  */
+static int constructor_simple;
+
+/* 1 if this constructor is erroneous so far.  */
+static int constructor_erroneous;
+
+/* 1 if have called defer_addressed_constants.  */
+static int constructor_subconstants_deferred;
+
+/* List of pending elements at this constructor level.
+   These are elements encountered out of order
+   which belong at places we haven't reached yet in actually
+   writing the output.  */
+static tree constructor_pending_elts;
+
+/* The SPELLING_DEPTH of this constructor.  */
+static int constructor_depth;
+
+/* 1 if this constructor level was entered implicitly.  */
+static int constructor_implicit;
+
+static int require_constant_value;
+static int require_constant_elements;
+
+/* 1 if it is ok to output this constructor as we read it.
+   0 means must accumulate a CONSTRUCTOR expression.  */
+static int constructor_incremental;
+
+/* DECL node for which an initializer is being read.
+   0 means we are reading a constructor expression
+   such as (struct foo) {...}.  */
+static tree constructor_decl;
+
+/* start_init saves the ASMSPEC arg here for really_start_incremental_init.  */
+static char *constructor_asmspec;
+
+/* Nonzero if this is an initializer for a top-level decl.  */
+static int constructor_top_level;
+
+/* When we finish reading a constructor expression
+   (constructor_decl is 0), the CONSTRUCTOR goes here.  */
+static tree constructor_result;
+
+struct constructor_stack
 {
-  register tree tail;
-  /* List of the elements of the result constructor,
-     in reverse order.  */
-  register tree members = NULL;
-  tree result;
-  int allconstant = 1;
-  int allsimple = 1;
-  int erroneous = 0;
-  int depth = SPELLING_DEPTH ();
+  struct constructor_stack *next;
+  tree type;
+  tree fields;
+  tree index;
+  tree range_end;
+  tree max_index;
+  tree unfilled_index;
+  tree unfilled_fields;
+  tree elements;
+  int offset;
+  tree pending_elts;
+  int depth;
+  char constant;
+  char simple;
+  char implicit;
+  char incremental;
+  char erroneous;
+  char outer;
+};
 
-  if (ofwhat)
-    push_string (ofwhat);
+struct constructor_stack *constructor_stack;
 
-  /* Make TAIL be the list of elements to use for the initialization,
-     no matter how the data was given to us.  */
+/* 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) { ... } ... }.  */
 
-  if (elts)
+struct initializer_stack
+{
+  struct initializer_stack *next;
+  tree decl;
+  char *asmspec;
+  struct constructor_stack *constructor_stack;
+  struct spelling *spelling;
+  struct spelling *spelling_base;
+  int spelling_size;
+  char top_level;
+  char incremental;
+  char require_constant_value;
+  char require_constant_elements;
+  char deferred;
+};
+
+struct initializer_stack *initializer_stack;
+\f
+/* Prepare to parse and output the initializer for variable DECL.  */
+
+void
+start_init (decl, asmspec, top_level)
+     tree decl;
+     char *asmspec;
+     int top_level;
+{
+  char *locus;
+  struct initializer_stack *p
+    = (struct initializer_stack *) xmalloc (sizeof (struct initializer_stack));
+
+  p->decl = constructor_decl;
+  p->asmspec = constructor_asmspec;
+  p->incremental = constructor_incremental;
+  p->require_constant_value = require_constant_value;
+  p->require_constant_elements = require_constant_elements;
+  p->constructor_stack = constructor_stack;
+  p->spelling = spelling;
+  p->spelling_base = spelling_base;
+  p->spelling_size = spelling_size;
+  p->deferred = constructor_subconstants_deferred;
+  p->top_level = constructor_top_level;
+  p->next = 0;
+  initializer_stack = p;
+
+  constructor_decl = decl;
+  constructor_incremental = top_level;
+  constructor_asmspec = asmspec;
+  constructor_subconstants_deferred = 0;
+  constructor_top_level = top_level;
+
+  if (decl != 0)
     {
-      if (warn_missing_braces)
-       {
-         if (! partial_bracket_mentioned)
-           warning ("aggregate has a partly bracketed initializer");
-         partial_bracket_mentioned = 1;
-       }
-      tail = *elts;
+      require_constant_value = TREE_STATIC (decl);
+      require_constant_elements = TREE_STATIC (decl) || pedantic;
+      locus = IDENTIFIER_POINTER (DECL_NAME (decl));
+      constructor_incremental |= TREE_STATIC (decl);
     }
   else
-    tail = CONSTRUCTOR_ELTS (init);
+    {
+      require_constant_value = 0;
+      require_constant_elements = 0;
+      locus = "(anonymous)";
+    }
 
-  /* Gobble as many elements as needed, and make a constructor or initial value
-     for each element of this aggregate.  Chain them together in result.
-     If there are too few, use 0 for each scalar ultimate component.  */
+  constructor_stack = 0;
 
-  if (TREE_CODE (type) == ARRAY_TYPE)
-    {
-      tree min_index, max_index;
-      /* These are non-zero only within a range initializer.  */
-      tree start_index = 0, end_index = 0;
-      /* Within a range, this is the value for the elts in the range.  */
-      tree range_val = 0;
-      /* Do arithmetic using double integers, but don't use fold/build,
-        because these allocate a new tree object everytime they are called,
-        thus resulting in gcc using too much memory for large
-        initializers.  */
-      union tree_node current_index_node, members_index_node;
-      tree current_index = &current_index_node;
-      tree members_index = &members_index_node;
-      TREE_TYPE (current_index) = integer_type_node;
-      TREE_TYPE (members_index) = integer_type_node;
-
-      /* If we have array bounds, set our bounds from that.  Otherwise,
-        we have a lower bound of zero and an unknown upper bound.  */
-      if (TYPE_DOMAIN (type))
-       {
-         min_index = TYPE_MIN_VALUE (TYPE_DOMAIN (type));
-         max_index = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
-       }
-      else
-       {
-         min_index = integer_zero_node;
-         max_index = 0;
-       }
+  spelling_base = 0;
+  spelling_size = 0;
+  RESTORE_SPELLING_DEPTH (0);
 
-      TREE_INT_CST_LOW (members_index) = TREE_INT_CST_LOW (min_index);
-      TREE_INT_CST_HIGH (members_index) = TREE_INT_CST_HIGH (min_index);
+  if (locus)
+    push_string (locus);
+}
 
-      /* Don't leave the loop based on index if the next item has an explicit
-        index value that will override it. */
+void
+finish_init ()
+{
+  struct initializer_stack *p = initializer_stack;
 
-      for (TREE_INT_CST_LOW (current_index) = TREE_INT_CST_LOW (min_index),
-          TREE_INT_CST_HIGH (current_index) = TREE_INT_CST_HIGH (min_index);
-          tail != 0 || end_index;
-          add_double (TREE_INT_CST_LOW (current_index),
-                      TREE_INT_CST_HIGH (current_index), 1, 0,
-                      &TREE_INT_CST_LOW (current_index),
-                      &TREE_INT_CST_HIGH (current_index)))
-       {
-         register tree next1 = 0;
+  /* Output subconstants (string constants, usually)
+     that were referenced within this initializer and saved up.
+     Must do this if and only if we called defer_addressed_constants.  */
+  if (constructor_subconstants_deferred)
+    output_deferred_addressed_constants ();
 
-         /* Handle the case where we are inside of a range.
-            current_index increments through the range,
-            so just keep reusing the same element of TAIL
-            until the end of the range.  */
-         if (end_index != 0)
-           {
-             next1 = range_val;
-             if (!tree_int_cst_lt (current_index, end_index))
-               end_index = 0;
-           }
+  /* Free the whole constructor stack of this initializer.  */
+  while (constructor_stack)
+    {
+      struct constructor_stack *q = constructor_stack;
+      constructor_stack = q->next;
+      free (q);
+    }
 
-         /* If this element specifies an index,
-            move to that index before storing it in the new list.  */
-         else if (TREE_PURPOSE (tail) != 0)
-           {
-             int win = 0;
-             tree index = TREE_PURPOSE (tail);
+  /* Pop back to the data of the outer initializer (if any).  */
+  constructor_decl = p->decl;
+  constructor_asmspec = p->asmspec;
+  constructor_incremental = p->incremental;
+  require_constant_value = p->require_constant_value;
+  require_constant_elements = p->require_constant_elements;
+  constructor_stack = p->constructor_stack;
+  spelling = p->spelling;
+  spelling_base = p->spelling_base;
+  spelling_size = p->spelling_size;
+  constructor_subconstants_deferred = p->deferred;
+  constructor_top_level = p->top_level;
+  initializer_stack = p->next;
+  free (p);
+}
+\f
+/* Call here when we see the initializer is surrounded by braces.
+   This is instead of a call to push_init_level;
+   it is matched by a call to pop_init_level.
 
-             if (index && (TREE_CODE (index) == NON_LVALUE_EXPR
-                           || TREE_CODE (index) == NOP_EXPR))
-               index = TREE_OPERAND (index, 0);
+   TYPE is the type to initialize, for a constructor expression.
+   For an initializer for a decl, TYPE is zero.  */
 
-             /* Begin a range.  */
-             if (TREE_CODE (index) == TREE_LIST)
-               {
-                 start_index = TREE_PURPOSE (index);
-                 end_index = TREE_PURPOSE (TREE_CHAIN (index));
-
-                 /* Expose constants.  It Doesn't matter if we change
-                    the mode.*/
-                 if (end_index
-                     && (TREE_CODE (end_index) == NON_LVALUE_EXPR
-                         || TREE_CODE (end_index) == NOP_EXPR))
-                   end_index = TREE_OPERAND (end_index, 0);
-                 if (start_index
-                     && (TREE_CODE (start_index) == NON_LVALUE_EXPR
-                         || TREE_CODE (start_index) == NOP_EXPR))
-                   start_index = TREE_OPERAND (start_index, 0);
-
-                 constant_expression_warning (start_index);
-                 constant_expression_warning (end_index);
-
-                 if ((TREE_CODE (start_index) == IDENTIFIER_NODE) 
-                     || (TREE_CODE (end_index) == IDENTIFIER_NODE))
-                   error ("field name used as index in array initializer");
-                 else if ((TREE_CODE (start_index) != INTEGER_CST)
-                          || (TREE_CODE (end_index) != INTEGER_CST))
-                   error ("non-constant or non-integer array index in initializer");
-                 else if (tree_int_cst_lt (start_index, min_index)
-                          || (max_index && tree_int_cst_lt (max_index, start_index))
-                          || tree_int_cst_lt (end_index, min_index)
-                          || (max_index && tree_int_cst_lt (max_index, end_index)))
-                   error ("array index out of range in initializer");
-                 else if (tree_int_cst_lt (end_index, start_index))
-                   {
-                     /* If the range is empty, don't initialize any elements,
-                        but do reset current_index for the next initializer
-                        element.  */
-                     warning ("empty array initializer range");
-                     tail = TREE_CHAIN (tail);
-                     TREE_INT_CST_LOW (current_index)
-                       = TREE_INT_CST_LOW (end_index);
-                     TREE_INT_CST_HIGH (current_index)
-                       = TREE_INT_CST_HIGH (end_index);
-                     continue;
-                   }
-                 else
-                   {
-                     TREE_INT_CST_LOW (current_index)
-                       = TREE_INT_CST_LOW (start_index);
-                     TREE_INT_CST_HIGH (current_index)
-                       = TREE_INT_CST_HIGH (start_index);
-                     win = 1;
-                     /* See if the first element is also the last.  */
-                     if (!tree_int_cst_lt (current_index, end_index))
-                       end_index = 0;
-                   }
-               }
-             else if (TREE_CODE (index) == IDENTIFIER_NODE)
-               error ("field name used as index in array initializer");
-             else if (TREE_CODE (index) != INTEGER_CST)
-               error ("non-constant array index in initializer");
-             else if (tree_int_cst_lt (index, min_index)
-                      || (max_index && tree_int_cst_lt (max_index, index)))
-               error ("array index out of range in initializer");
-             else
-               {
-                 constant_expression_warning (index);
-                 TREE_INT_CST_LOW (current_index) = TREE_INT_CST_LOW (index);
-                 TREE_INT_CST_HIGH (current_index)
-                   = TREE_INT_CST_HIGH (index);
-                 win = 1;
-               }
+void
+really_start_incremental_init (type)
+     tree type;
+{
+  struct constructor_stack *p
+    = (struct constructor_stack *) xmalloc (sizeof (struct constructor_stack));
+
+  if (type == 0)
+    type = TREE_TYPE (constructor_decl);
+
+  /* Turn off constructor_incremental if type is a struct with bitfields.
+     Do this before the first push, so that the corrected value
+     is available in finish_init.  */
+  check_init_type_bitfields (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;
+  p->elements = 0;
+  p->constant = constructor_constant;
+  p->simple = constructor_simple;
+  p->erroneous = constructor_erroneous;
+  p->pending_elts = constructor_pending_elts;
+  p->depth = constructor_depth;
+  p->implicit = 0;
+  p->incremental = constructor_incremental;
+  p->outer = 0;
+  p->next = 0;
+  constructor_stack = p;
+
+  constructor_constant = 1;
+  constructor_simple = 1;
+  constructor_depth = SPELLING_DEPTH ();
+  constructor_elements = 0;
+  constructor_pending_elts = 0;
+  constructor_type = type;
+
+  if (TREE_CODE (constructor_type) == RECORD_TYPE
+      || TREE_CODE (constructor_type) == UNION_TYPE)
+    {
+      constructor_fields = TYPE_FIELDS (constructor_type);
+      constructor_unfilled_fields = constructor_fields;
+    }
+  else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+    {
+      constructor_index = copy_node (integer_zero_node);
+      constructor_range_end = 0;
+      constructor_unfilled_index = copy_node (integer_zero_node);
+      if (TYPE_DOMAIN (constructor_type))
+       constructor_max_index
+         = TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type));
+    }
+  else
+    {
+      /* Handle the case of int x = {5}; */
+      constructor_fields = constructor_type;
+      constructor_unfilled_fields = constructor_type;
+    }
 
-             if (!win)
-               {
-                 /* If there was an error, end the current range.  */
-                 end_index = 0;
-                 TREE_VALUE (tail) = error_mark_node;
-               }
-           }
+  if (constructor_incremental)
+    {
+      int momentary = suspend_momentary ();
+      push_obstacks_nochange ();
+      if (TREE_PERMANENT (constructor_decl))
+       end_temporary_allocation ();
+      make_decl_rtl (constructor_decl, constructor_asmspec,
+                    constructor_top_level);
+      assemble_variable (constructor_decl, constructor_top_level, 0, 1);
+      pop_obstacks ();
+      resume_momentary (momentary);
+    }
 
-         if (max_index && tree_int_cst_lt (max_index, current_index))
-           break;  /* Stop if we've indeed run out of elements. */
+  if (constructor_incremental)
+    {
+      defer_addressed_constants ();
+      constructor_subconstants_deferred = 1;
+    }
+}
+\f
+/* 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.  */
 
-         /* Now digest the value specified.  */
-         if (next1 != 0)
-           ;
-         else if (TREE_VALUE (tail) != 0)
-           {
-             tree tail1 = tail;
-
-             /* Build the element of this array, with "[]" notation.  For
-                error messages, we assume that the index fits within a
-                host int.  */
-             SAVE_SPELLING_DEPTH
-               ({
-                 push_array_bounds (TREE_INT_CST_LOW (current_index));
-                 next1 = digest_init (TYPE_MAIN_VARIANT (TREE_TYPE (type)),
-                                      TREE_VALUE (tail), &tail1,
-                                      /* Both of these are the same because
-                                         a value here is an elt overall.  */
-                                      constant_element, constant_element,
-                                      NULL_PTR);
-               });
-
-             if (tail1 != 0 && TREE_CODE (tail1) != TREE_LIST)
-               abort ();
-             if (tail == tail1 && TYPE_DOMAIN (type) == 0)
-               {
-                 error_init (
-                   "non-empty initializer for array%s of empty elements",
-                   " `%s'", NULL_PTR);
-                 /* Just ignore what we were supposed to use.  */
-                 tail1 = 0;
-               }
-             tail = tail1;
-           }
-         else
-           {
-             next1 = error_mark_node;
-             tail = TREE_CHAIN (tail);
-           }
+void
+push_init_level (implicit)
+     int implicit;
+{
+  struct constructor_stack *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;
+  p->elements = constructor_elements;
+  p->constant = constructor_constant;
+  p->simple = constructor_simple;
+  p->erroneous = constructor_erroneous;
+  p->pending_elts = constructor_pending_elts;
+  p->depth = constructor_depth;
+  p->implicit = implicit;
+  p->incremental = constructor_incremental;
+  p->outer = 0;
+  p->next = constructor_stack;
+  constructor_stack = p;
+
+  constructor_constant = 1;
+  constructor_simple = 1;
+  constructor_depth = SPELLING_DEPTH ();
+  constructor_elements = 0;
+  constructor_pending_elts = 0;
+
+  if (TREE_CODE (constructor_type) == RECORD_TYPE
+      || TREE_CODE (constructor_type) == UNION_TYPE)
+    {
+      constructor_type = TREE_TYPE (constructor_fields);
+      push_member_name (IDENTIFIER_POINTER (DECL_NAME (constructor_fields)));
+    }
+  else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+    {
+      constructor_type = TREE_TYPE (constructor_type);
+      push_array_bounds (TREE_INT_CST_LOW (constructor_index));
+    }
 
-         if (end_index != 0)
-           range_val = next1;
+  /* Turn off constructor_incremental if type is a struct with bitfields.  */
+  check_init_type_bitfields (constructor_type);
 
-         if (next1 == error_mark_node)
-           erroneous = 1;
-         else if (!TREE_CONSTANT (next1))
-           allconstant = 0;
-         else if (initializer_constant_valid_p (next1, TREE_TYPE (next1)) == 0)
-           allsimple = 0;
+  if (TREE_CODE (constructor_type) == RECORD_TYPE
+      || TREE_CODE (constructor_type) == UNION_TYPE)
+    {
+      constructor_fields = TYPE_FIELDS (constructor_type);
+      constructor_unfilled_fields = constructor_fields;
+    }
+  else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+    {
+      constructor_index = copy_node (integer_zero_node);
+      constructor_range_end = 0;
+      constructor_unfilled_index = copy_node (integer_zero_node);
+      if (TYPE_DOMAIN (constructor_type))
+       constructor_max_index
+         = TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type));
+    }
+  else
+    {
+      error_init ("braces where a scalar is expected%s", " for `%s'", NULL);
+      constructor_fields = constructor_type;
+      constructor_unfilled_fields = constructor_type;
+    }
+}
 
-         /* Now store NEXT1 in the list, I elements from the *end*.
-            Make the list longer if necessary.  */
-         while (! tree_int_cst_lt (current_index, members_index))
-           {
-             if (free_tree_list)
-               {
-                 TREE_CHAIN (free_tree_list) = members;
-                 TREE_PURPOSE (free_tree_list) = NULL_TREE;
-                 TREE_VALUE (free_tree_list) = NULL_TREE;
-                 members = free_tree_list;
-                 free_tree_list = NULL_TREE;
-               }
-             else
-               members = tree_cons (NULL_TREE, NULL_TREE, members);
-             add_double (TREE_INT_CST_LOW (members_index),
-                         TREE_INT_CST_HIGH (members_index), 1, 0,
-                         &TREE_INT_CST_LOW (members_index),
-                         &TREE_INT_CST_HIGH (members_index));
-           }
+/* Don't read a struct incrementally if it has any bitfields,
+   because the incremental reading code doesn't know how to
+   handle bitfields yet.  */
 
+static void
+check_init_type_bitfields (type)
+     tree type;
+{
+  if (TREE_CODE (type) == RECORD_TYPE)
+    {
+      tree tail;
+      for (tail = TYPE_FIELDS (type); tail;
+          tail = TREE_CHAIN (tail))
+       if (DECL_BIT_FIELD (tail))
          {
-           tree temp;
-           union tree_node idx_node;
-           tree idx = &idx_node;
-           TREE_TYPE (idx) = integer_type_node;
-
-           temp = members;
-           for (add_double (TREE_INT_CST_LOW (members_index),
-                            TREE_INT_CST_HIGH (members_index), -1, -1,
-                            &TREE_INT_CST_LOW (idx),
-                            &TREE_INT_CST_HIGH (idx));
-                tree_int_cst_lt (current_index, idx);
-                add_double (TREE_INT_CST_LOW (idx),
-                            TREE_INT_CST_HIGH (idx), -1, -1,
-                            &TREE_INT_CST_LOW (idx),
-                            &TREE_INT_CST_HIGH (idx)))
-             temp = TREE_CHAIN (temp);
-           TREE_VALUE (temp) = next1;
+           constructor_incremental = 0;
+           break;
          }
-       }
     }
-  if (TREE_CODE (type) == RECORD_TYPE)
+}
+
+/* At the end of an implicit or explicit brace level, 
+   finish up that level of constructor.
+   If we were outputting the elements as they are read, return 0
+   from inner levels (process_init_element ignores that),
+   but return error_mark_node from the outermost level
+   (that's what we want to put in DECL_INITIAL).
+   Otherwise, return a CONSTRUCTOR expression.  */
+
+tree
+pop_init_level (implicit)
+     int implicit;
+{
+  struct constructor_stack *p;
+  int size;
+  tree constructor = 0;
+
+  if (implicit == 0)
     {
-      register tree field;
-      int members_length = 0;
-      int i;
+      /* When we come to an explicit close brace,
+        pop any inner levels that didn't have explicit braces.  */
+      while (constructor_stack->implicit)
+       process_init_element (pop_init_level (1));
+    }
 
-      /* Don't leave the loop based on field just yet; see if next item
-        overrides the expected field first. */
+  p = constructor_stack;
+  size = int_size_in_bytes (constructor_type);
 
-      for (field = TYPE_FIELDS (type), i = 0; tail;
-          field = TREE_CHAIN (field), i++)
+  /* Now output all pending elements.  */
+  output_pending_init_elements (1);
+
+  /* Pad out the end of the structure.  */
+  
+  if (! constructor_incremental)
+    {
+      if (constructor_erroneous)
+       constructor = error_mark_node;
+      else
        {
-         register tree next1;
+         int momentary = suspend_momentary ();
+
+         constructor = build (CONSTRUCTOR, constructor_type, NULL_TREE,
+                              nreverse (constructor_elements));
+         if (constructor_constant)
+           TREE_CONSTANT (constructor) = 1;
+         if (constructor_constant && constructor_simple)
+           TREE_STATIC (constructor) = 1;
+         resume_momentary (momentary);
+       }
+    }
+  else
+    {
+      tree filled;
+      int momentary = suspend_momentary ();
 
-         /* If this element specifies a field, 
-            move to that field before storing it in the new list.  */
-         if (TREE_PURPOSE (tail) != 0)
+      if (TREE_CODE (constructor_type) == RECORD_TYPE
+         || TREE_CODE (constructor_type) == UNION_TYPE)
+       {
+         tree tail;
+         /* Find the last field written out.  */
+         for (tail = TYPE_FIELDS (constructor_type); tail;
+              tail = TREE_CHAIN (tail))
+           if (TREE_CHAIN (tail) == constructor_unfilled_fields)
+             break;
+         /* Find the offset of the end of that field.  */
+         filled = size_binop (CEIL_DIV_EXPR,
+                              size_binop (PLUS_EXPR,
+                                          DECL_FIELD_BITPOS (tail),
+                                          DECL_SIZE (tail)),
+                              size_int (BITS_PER_UNIT));
+       }
+      else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+       {
+         /* If initializing an array of unknown size,
+            determine the size now.  */
+         if (TREE_CODE (constructor_type) == ARRAY_TYPE
+             && TYPE_DOMAIN (constructor_type) == 0)
            {
-             int win = 0;
+             tree maxindex
+               = size_binop (MINUS_EXPR,
+                             constructor_unfilled_index,
+                             integer_one_node);
+
+             push_obstacks_nochange ();
+             if (TREE_PERMANENT (constructor_type))
+               end_temporary_allocation ();
+             maxindex = copy_node (maxindex);
+             TYPE_DOMAIN (constructor_type) = build_index_type (maxindex);
+             TREE_TYPE (maxindex) = TYPE_DOMAIN (constructor_type);
+
+             /* We shouldn't have an incomplete array type within
+                some other type.  */
+             if (constructor_stack->next)
+               abort ();
 
-             if (TREE_CODE (TREE_PURPOSE (tail)) != IDENTIFIER_NODE)
-               error ("index value instead of field name in structure initializer");
-             else
-               {
-                 tree temp;
-                 int j;
-                 for (temp = TYPE_FIELDS (type), j = 0;
-                      temp;
-                      temp = TREE_CHAIN (temp), j++)
-                   if (DECL_NAME (temp) == TREE_PURPOSE (tail))
-                     break;
-                 if (temp)
-                   field = temp, i = j, win = 1;
-                 else
-                   error ("no field `%s' in structure being initialized",
-                          IDENTIFIER_POINTER (TREE_PURPOSE (tail))); 
-               }
-             if (!win)
-               TREE_VALUE (tail) = error_mark_node;
+             if (pedantic
+                 && tree_int_cst_lt (TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type)),
+                                     integer_zero_node))
+               error_with_decl (constructor_decl, "zero-size array `%s'");
+             layout_type (constructor_type);
+             size = int_size_in_bytes (constructor_type);
+             pop_obstacks ();
            }
 
-         if (field == 0)
-           break;  /* No more fields to init. */
+         filled = size_binop (MULT_EXPR, constructor_unfilled_index,
+                              size_in_bytes (TREE_TYPE (constructor_type)));
+       }
+      else
+       filled = 0;
 
-         if (! DECL_NAME (field))
-           {
-             next1 = integer_zero_node;
-           }
-         else if (TREE_VALUE (tail) != 0)
-           {
-             tree tail1 = tail;
-
-             /* Build the name of this member, with a "." for membership.  */
-             SAVE_SPELLING_DEPTH
-               ({
-                 push_member_name (IDENTIFIER_POINTER (DECL_NAME (field)));
-                 next1 = digest_init (TREE_TYPE (field),
-                                      TREE_VALUE (tail), &tail1,
-                                      constant_element, constant_element,
-                                      NULL_PTR);
-               });
-             if (tail1 != 0 && TREE_CODE (tail1) != TREE_LIST)
-               abort ();
-             tail = tail1;
-           }
-         else
+      if (filled != 0)
+       assemble_zeros (size - TREE_INT_CST_LOW (filled));
+
+      resume_momentary (momentary);
+    }
+
+         
+  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;
+  constructor_elements = p->elements;
+  constructor_constant = p->constant;
+  constructor_simple = p->simple;
+  constructor_erroneous = p->erroneous;
+  constructor_pending_elts = p->pending_elts;
+  constructor_depth = p->depth;
+  constructor_incremental = p->incremental;
+  RESTORE_SPELLING_DEPTH (constructor_depth);
+
+  constructor_stack = p->next;
+  free (p);
+
+  if (constructor == 0)
+    {
+      if (constructor_stack == 0)
+       return error_mark_node;
+      return NULL_TREE;
+    }
+  return constructor;
+}
+
+/* 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.  */
+
+void
+set_init_index (first, last)
+     tree first, last;
+{
+  if (tree_int_cst_lt (first, constructor_unfilled_index))
+    error_init ("duplicate array index in initializer%s", " for `%s'", NULL);
+  else
+    {
+      TREE_INT_CST_LOW (constructor_index)
+       = TREE_INT_CST_LOW (first);
+      TREE_INT_CST_HIGH (constructor_index)
+       = TREE_INT_CST_HIGH (first);
+
+      if (last != 0 && tree_int_cst_lt (last, first))
+       error_init ("empty index range in initializer%s", " for `%s'", NULL);
+      else
+       constructor_range_end = last;
+    }
+}
+
+/* Within a struct initializer, specify the next field to be initialized.  */
+
+void 
+set_init_label (fieldname)
+     tree fieldname;
+{
+  tree tail;
+  int passed = 0;
+
+  for (tail = TYPE_FIELDS (constructor_type); tail;
+       tail = TREE_CHAIN (tail))
+    {
+      if (tail == constructor_unfilled_fields)
+       passed = 1;
+      if (DECL_NAME (tail) == fieldname)
+       break;
+    }
+
+  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;
+}
+\f
+/* "Output" the next constructor element.
+   At top level, really output it to assembler code now.
+   Otherwise, collect it in a list from which we will make a CONSTRUCTOR.
+   TYPE is the data type that the containing data type wants here.
+   FIELD is the field (a FIELD_DECL) or the index that this element fills.
+
+   PENDING if non-nil means output pending elements that belong
+   right after this element.  (PENDING is normally 1;
+   it is 0 while outputting pending elements, to avoid recursion.)  */
+
+void
+output_init_element (value, type, field, pending)
+     tree value, type, field;
+     int pending;
+{
+  int duplicate = 0;
+
+  if (require_constant_value && ! TREE_CONSTANT (value))
+    {
+      error_init ("initializer element%s is not constant",
+                 " for `%s'", NULL);
+      value = error_mark_node;
+    }
+  else if (require_constant_elements
+          && initializer_constant_valid_p (value, TREE_TYPE (value)) == 0)
+    {
+      error_init ("initializer element%s is not computable at load time",
+                 " for `%s'", NULL);
+      value = error_mark_node;
+    }
+
+  /* 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 (TREE_CODE (constructor_type) == RECORD_TYPE
+         || TREE_CODE (constructor_type) == UNION_TYPE)
+       {
+         if (purpose_member (field, constructor_pending_elts))
            {
-             next1 = error_mark_node;
-             tail = TREE_CHAIN (tail);
+             error_init ("duplicate initializer%s", " for `%s'", NULL);
+             duplicate = 1;
            }
+       }
+      if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+       {
+         tree tail;
+         for (tail = constructor_pending_elts; tail;
+              tail = TREE_CHAIN (tail))
+           if (TREE_PURPOSE (tail) != 0
+               && TREE_CODE (TREE_PURPOSE (tail)) == INTEGER_CST
+               && tree_int_cst_equal (TREE_PURPOSE (tail), constructor_index))
+             break;
 
-         if (next1 == error_mark_node)
-           erroneous = 1;
-         else if (!TREE_CONSTANT (next1))
-           allconstant = 0;
-         else if (initializer_constant_valid_p (next1, TREE_TYPE (next1)) == 0)
-           allsimple = 0;
-
-         /* Now store NEXT1 in the list, I elements from the *end*.
-            Make the list longer if necessary.  */
-         while (i >= members_length)
+         if (tail != 0)
            {
-             if (free_tree_list)
-               {
-                 TREE_CHAIN (free_tree_list) = members;
-                 TREE_PURPOSE (free_tree_list) = NULL_TREE;
-                 TREE_VALUE (free_tree_list) = NULL_TREE;
-                 members = free_tree_list;
-                 free_tree_list = NULL_TREE;
-               }
-             else
-               members = tree_cons (NULL_TREE, NULL_TREE, members);
-             members_length++;
+             error_init ("duplicate initializer%s", " for `%s'", NULL);
+             duplicate = 1;
            }
-         {
-           tree temp;
-           int j;
-
-           temp = members;
-           for (j = members_length - 1; j > i; j--)
-             temp = TREE_CHAIN (temp);
-           TREE_VALUE (temp) = next1;
-           TREE_PURPOSE (temp) = field;
-         }
        }
     }
-  if (TREE_CODE (type) == UNION_TYPE)
-    {
-      register tree field = TYPE_FIELDS (type);
-      register tree next1;
-
-      /* Find the first named field.  ANSI decided in September 1990
-        that only named fields count here.  */
-      while (field && DECL_NAME (field) == 0)
-       field = TREE_CHAIN (field);
 
-      /* For a union, get the initializer for 1 fld.  */
+  /* 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))
+    {
+      if (! duplicate)
+       constructor_pending_elts
+         = tree_cons (field,
+                      digest_init (type, value, (tree *)NULL,
+                                   require_constant_value,
+                                   require_constant_elements),
+                      constructor_pending_elts);
+    }
+  else if ((TREE_CODE (constructor_type) == RECORD_TYPE
+           || TREE_CODE (constructor_type) == UNION_TYPE)
+          && field != constructor_unfilled_fields)
+    {
+      if (!duplicate)
+       constructor_pending_elts
+         = tree_cons (field,
+                      digest_init (type, value, (tree *)NULL,
+                                   require_constant_value,
+                                   require_constant_elements),
+                      constructor_pending_elts);
+    }
+  else
+    {
+      /* Otherwise, output this element either to
+        constructor_elements or to the assembler file.  */
 
-      if (tail == 0)
+      if (!duplicate)
        {
-         error ("empty initializer for union");
-         tail = build_tree_list (0, 0);
+         if (! constructor_incremental)
+           constructor_elements
+             = tree_cons ((TREE_CODE (constructor_type) != ARRAY_TYPE
+                           ? field : NULL),
+                          digest_init (type, value, (tree *)NULL,
+                                       require_constant_value,
+                                       require_constant_elements),
+                          constructor_elements);
+         else
+           output_constant (value, int_size_in_bytes (type));
        }
 
-      /* If this element specifies a field, initialize via that field.  */
-      if (TREE_PURPOSE (tail) != 0)
+      /* Advance the variable that indicates sequential elements output.  */
+      if (TREE_CODE (constructor_type) == ARRAY_TYPE)
        {
-         int win = 0;
+         tree tem = size_binop (PLUS_EXPR, constructor_unfilled_index,
+                                integer_one_node);
+         TREE_INT_CST_LOW (constructor_unfilled_index)
+           = TREE_INT_CST_LOW (tem);
+         TREE_INT_CST_HIGH (constructor_unfilled_index)
+           = TREE_INT_CST_HIGH (tem);
+       }
+      else if (TREE_CODE (constructor_type) == RECORD_TYPE)
+       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);
+    }
+}
 
-         if (TREE_CODE (TREE_PURPOSE (tail)) == FIELD_DECL)
-           /* Handle the case of a call by build_c_cast.  */
-           field = TREE_PURPOSE (tail), win = 1;
-         else if (TREE_CODE (TREE_PURPOSE (tail)) != IDENTIFIER_NODE)
-           error ("index value instead of field name in union initializer");
-         else
+/* Output any pending elements which have become next.
+   As we output elements, constructor_unfilled_{fields,index}
+   advances, which may cause other elements to become next;
+   if so, they too are output.
+
+   If ALL is 0, we return when there are
+   no more pending elements to output now.
+
+   If ALL is 1, we output space as necessary so that
+   we can output all the pending elements.  */
+
+static void
+output_pending_init_elements (all)
+     int all;
+{
+  tree tail;
+  tree next;
+
+ retry:
+
+  /* Look thru the whole pending list.
+     If we find an element that should be output now,
+     output it.  Otherwise, set NEXT to the element
+     that comes first among those still pending.  */
+     
+  next = 0;
+  for (tail = constructor_pending_elts; tail;
+       tail = TREE_CHAIN (tail))
+    {
+      if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+       {
+         if (tree_int_cst_equal (TREE_PURPOSE (tail),
+                                 constructor_unfilled_index))
            {
-             tree temp;
-             for (temp = TYPE_FIELDS (type);
-                  temp;
-                  temp = TREE_CHAIN (temp))
-               if (DECL_NAME (temp) == TREE_PURPOSE (tail))
-                 break;
-             if (temp)
-               field = temp, win = 1;
-             else
-               error ("no field `%s' in union being initialized",
-                      IDENTIFIER_POINTER (TREE_PURPOSE (tail)));
+             output_init_element (TREE_VALUE (tail), TREE_TYPE (constructor_type),
+                                  constructor_unfilled_index, 0);
+             goto retry;
+           }
+         else if (tree_int_cst_lt (TREE_PURPOSE (tail),
+                                   constructor_unfilled_index))
+           ;
+         else if (next == 0
+                  || tree_int_cst_lt (TREE_PURPOSE (tail),
+                                         next))
+           next = TREE_PURPOSE (tail);
+       }
+      else if (TREE_CODE (constructor_type) == RECORD_TYPE
+              || TREE_CODE (constructor_type) == UNION_TYPE)
+       {
+         if (TREE_PURPOSE (tail) == constructor_unfilled_fields)
+           {
+             output_init_element (TREE_VALUE (tail),
+                                  TREE_TYPE (constructor_unfilled_fields),
+                                  constructor_unfilled_fields,
+                                  0);
+             goto retry;
            }
-         if (!win)
-           TREE_VALUE (tail) = error_mark_node;
+         else if (tree_int_cst_lt (DECL_FIELD_BITPOS (TREE_PURPOSE (tail)),
+                                   DECL_FIELD_BITPOS (constructor_unfilled_fields)))
+           ;
+         else if (next == 0
+                  || tree_int_cst_lt (DECL_FIELD_BITPOS (TREE_PURPOSE (tail)),
+                                      DECL_FIELD_BITPOS (next)))
+           next = TREE_PURPOSE (tail);
        }
+    }
+
+  /* Ordinarily return, but not if we want to output all
+     and there are elements left.  */
+  if (! (all && next != 0))
+    return;
+
+  /* Generate space up to the position of NEXT.  */
+  if (constructor_incremental)
+    {
+      tree filled;
+      tree nextpos_tree;
 
-      if (TREE_VALUE (tail) != 0)
+      if (TREE_CODE (constructor_type) == RECORD_TYPE
+         || TREE_CODE (constructor_type) == UNION_TYPE)
        {
-         tree tail1 = tail;
-
-         /* Build the name of this member, with a "." for membership.  */
-         SAVE_SPELLING_DEPTH
-           ({
-             push_member_name (IDENTIFIER_POINTER (DECL_NAME (field)));
-             next1 = digest_init (TREE_TYPE (field),
-                                  TREE_VALUE (tail), &tail1,
-                                  constant_value, constant_element, NULL_PTR);
-           });
-         if (tail1 != 0 && TREE_CODE (tail1) != TREE_LIST)
-           abort ();
-         tail = tail1;
+         /* Find the last field written out.  */
+         for (tail = TYPE_FIELDS (constructor_type); tail;
+              tail = TREE_CHAIN (tail))
+           if (TREE_CHAIN (tail) == constructor_unfilled_fields)
+             break;
+         /* Find the offset of the end of that field.  */
+         filled = size_binop (CEIL_DIV_EXPR,
+                              size_binop (PLUS_EXPR,
+                                          DECL_FIELD_BITPOS (tail),
+                                          DECL_SIZE (tail)),
+                              size_int (BITS_PER_UNIT));
+         nextpos_tree = size_binop (CEIL_DIV_EXPR,
+                                    DECL_FIELD_BITPOS (next),
+                                    size_int (BITS_PER_UNIT));
+         constructor_unfilled_fields = next;
        }
-      else
+      else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
        {
-         next1 = error_mark_node;
-         tail = TREE_CHAIN (tail);
+         filled = size_binop (MULT_EXPR, constructor_unfilled_index,
+                              size_in_bytes (TREE_TYPE (constructor_type)));
+         nextpos_tree
+           = size_binop (MULT_EXPR, next,
+                         size_in_bytes (TREE_TYPE (constructor_type)));
+         TREE_INT_CST_LOW (constructor_unfilled_index)
+           = TREE_INT_CST_LOW (next);
+         TREE_INT_CST_HIGH (constructor_unfilled_index)
+           = TREE_INT_CST_HIGH (next);
        }
+      else
+       filled = 0;
 
-      if (next1 == error_mark_node)
-       erroneous = 1;
-      else if (!TREE_CONSTANT (next1))
-       allconstant = 0;
-      else if (initializer_constant_valid_p (next1, TREE_TYPE (next1)) == 0)
-       allsimple = 0; 
-     if (free_tree_list)
+      if (filled)
        {
-         TREE_CHAIN (free_tree_list) = members;
-         TREE_PURPOSE (free_tree_list) = field;
-         TREE_VALUE (free_tree_list) = next1;
-         members = free_tree_list;
-         free_tree_list = NULL_TREE;
+         int nextpos = TREE_INT_CST_LOW (nextpos_tree);
+
+         assemble_zeros (nextpos - TREE_INT_CST_LOW (filled));
        }
+    }
+
+  goto retry;
+}
+\f
+/* Add one non-braced element to the current constructor level.
+   This adjusts the current position within the constructor's type.
+   This may also start or terminate implicit levels
+   to handle a partly-braced initializer.
+
+   Once this has found the correct level for the new element,
+   it calls output_init_element.
+
+   Note: if we are incrementally outputting this constructor,
+   this function may be called with a null argument
+   representing a sub-constructor that was already incrementally output.
+   When that happens, we output nothing, but we do the bookkeeping
+   to skip past that element of the current constructor.  */
+
+void
+process_init_element (value)
+     tree value;
+{
+  if (value != 0)
+    value = default_conversion (value);
+
+  if (value == 0)
+    ;
+  else if (value == error_mark_node)
+    constructor_erroneous = 1;
+  else if (!TREE_CONSTANT (value))
+    constructor_constant = 0;
+  else if (initializer_constant_valid_p (value, TREE_TYPE (value)) == 0)
+    constructor_simple = 0;
+
+  /* If we've exhausted any levels that didn't have braces,
+     pop them now.  */
+  while (constructor_stack->implicit)
+    {
+      if ((TREE_CODE (constructor_type) == RECORD_TYPE
+          || TREE_CODE (constructor_type) == UNION_TYPE)
+         && constructor_fields == 0)
+       process_init_element (pop_init_level (1));
+      else if (TREE_CODE (constructor_type) == ARRAY_TYPE
+              && tree_int_cst_lt (constructor_max_index, constructor_index))
+       process_init_element (pop_init_level (1));
       else
-       members = tree_cons (field, next1, members);
+       break;
     }
 
-  /* If arguments were specified as a list, just remove the ones we used.  */
-  if (elts)
-    *elts = tail;
-  /* If arguments were specified as a constructor,
-     complain unless we used all the elements of the constructor.  */
-  else if (tail)
+  while (1)
     {
-      if (TREE_CODE (type) == UNION_TYPE)
+      if (TREE_CODE (constructor_type) == RECORD_TYPE)
        {
-         pedwarn_init ("excess elements in union initializer%s",
-                       " after `%s'", NULL_PTR);
+         tree fieldtype;
+         enum tree_code fieldcode;
+
+         if (constructor_fields == 0)
+           {
+             pedwarn_init ("excess elements in struct initializer%s",
+                           " after `%s'", NULL_PTR);
+             break;
+           }
+
+         fieldtype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_fields));
+         fieldcode = TREE_CODE (fieldtype);
+
+         if (value != 0 && TYPE_MAIN_VARIANT (TREE_TYPE (value)) != fieldtype
+             && (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE
+                 || fieldcode == UNION_TYPE))
+           {
+             push_init_level (1);
+             continue;
+           }
+
+         if (value)
+           {
+             push_member_name (IDENTIFIER_POINTER (DECL_NAME (constructor_fields)));
+             output_init_element (value, fieldtype, constructor_fields, 1);
+             RESTORE_SPELLING_DEPTH (constructor_depth);
+           }
+         else
+           /* If we are doing the bookkeeping for an element that was
+              directly output as a constructor,
+              we must update constructor_unfilled_fields.  */
+           constructor_unfilled_fields = TREE_CHAIN (constructor_fields);
+
+         constructor_fields = TREE_CHAIN (constructor_fields);
+         break;
        }
-      else
+      if (TREE_CODE (constructor_type) == UNION_TYPE)
        {
-         pedwarn_init ("excess elements in aggregate initializer%s",
-                       " after `%s'", NULL_PTR);
+         tree fieldtype;
+         enum tree_code fieldcode;
+
+         if (constructor_fields == 0)
+           {
+             pedwarn_init ("excess elements in union initializer%s",
+                           " after `%s'", NULL_PTR);
+             break;
+           }
+
+         fieldtype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_fields));
+         fieldcode = TREE_CODE (fieldtype);
+
+         if (value != 0 && TYPE_MAIN_VARIANT (TREE_TYPE (value)) != fieldtype
+             && (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE
+                 || fieldcode == UNION_TYPE))
+           {
+             push_init_level (1);
+             continue;
+           }
+
+         if (value)
+           {
+             push_member_name (IDENTIFIER_POINTER (DECL_NAME (constructor_fields)));
+             output_init_element (value, fieldtype, constructor_fields, 1);
+             RESTORE_SPELLING_DEPTH (constructor_depth);
+           }
+         else
+           /* If we are doing the bookkeeping for an element that was
+              directly output as a constructor,
+              we must update constructor_unfilled_fields.  */
+           constructor_unfilled_fields = 0;
+
+         constructor_fields = 0;
+         break;
        }
-    }
+      if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+       {
+         tree elttype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type));
+         enum tree_code eltcode = TREE_CODE (elttype);
+
+         if (value != 0 && TYPE_MAIN_VARIANT (TREE_TYPE (value)) != elttype
+             && (eltcode == RECORD_TYPE || eltcode == ARRAY_TYPE
+                 || eltcode == UNION_TYPE))
+           {
+             push_init_level (1);
+             continue;
+           }
+
+         if (constructor_max_index != 0
+             && tree_int_cst_lt (constructor_max_index, constructor_index))
+           {
+             pedwarn_init ("excess elements in array initializer%s",
+                           " after `%s'", NULL_PTR);
+             break;
+           }
 
-  /* It might be possible to use SAVE_SPELLING_DEPTH, but I suspect that
-     some preprocessor somewhere won't accept that much text as an argument.
-     It's also likely to make debugging difficult.  */
+         /* Now output the actual element.
+            Ordinarily, output once.
+            If there is a range, repeat it till we advance past the range.  */
+         do
+           {
+             tree tem;
 
-  RESTORE_SPELLING_DEPTH (depth);
+             if (value)
+               {
+                 push_array_bounds (TREE_INT_CST_LOW (constructor_index));
+                 output_init_element (value, elttype, constructor_index, 1);
+                 RESTORE_SPELLING_DEPTH (constructor_depth);
+               }
 
-  if (erroneous)
-    return error_mark_node;
+             tem = size_binop (PLUS_EXPR, constructor_index,
+                               integer_one_node);
+             TREE_INT_CST_LOW (constructor_index)
+               = TREE_INT_CST_LOW (tem);
+             TREE_INT_CST_HIGH (constructor_index)
+               = TREE_INT_CST_HIGH (tem);
+
+             if (!value)
+               /* If we are doing the bookkeeping for an element that was
+                  directly output as a constructor,
+                  we must update constructor_unfilled_index.  */
+               {
+                 TREE_INT_CST_LOW (constructor_unfilled_index)
+                   = TREE_INT_CST_LOW (constructor_index);
+                 TREE_INT_CST_HIGH (constructor_unfilled_index)
+                   = TREE_INT_CST_HIGH (constructor_index);
+               }
+           }
+         while (! (constructor_range_end == 0
+                   || tree_int_cst_lt (constructor_range_end,
+                                       constructor_index)));
 
-  if (elts)
-    result = build (CONSTRUCTOR, type, NULL_TREE, nreverse (members));
-  else
-    {
-      result = init;
-      CONSTRUCTOR_ELTS (result) = nreverse (members);
-      TREE_TYPE (result) = type;
-      TREE_CONSTANT (result) = 0;
-      TREE_STATIC (result) = 0;
+         break;
+       }
+
+      /* Handle the sole element allowed in a braced initializer
+        for a scalar variable.  */
+      if (constructor_fields == 0)
+       {
+         pedwarn_init ("excess elements in scalar initializer%s",
+                       " after `%s'", NULL_PTR);
+         break;
+       }
+
+      if (value)
+       output_init_element (value, constructor_type, NULL_TREE, 1);
+      constructor_fields = 0;
+      break;
     }
-  if (allconstant) TREE_CONSTANT (result) = 1;
-  if (allconstant && allsimple) TREE_STATIC (result) = 1;
-  return result;
+
+  /* If the (lexically) previous elments are not now saved,
+     we can discard the storage for them.  */
+  if (constructor_incremental && constructor_pending_elts == 0)
+    clear_momentary ();
 }
 \f
 /* Expand an ASM statement with operands, handling output operands