OSDN Git Service

(struct initializer_stack): New field ELEMENTS.
[pf3gnuchains/gcc-fork.git] / gcc / c-typeck.c
index 434c9d5..51ee586 100644 (file)
@@ -1,5 +1,5 @@
 /* Build expressions with type checking for C compiler.
-   Copyright (C) 1987, 1988, 1989, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1989, 1992, 1993 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -33,6 +33,10 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "c-tree.h"
 #include "flags.h"
 
+/* Nonzero if we've already printed a "missing braces around initializer"
+   message within this initializer.  */
+static int missing_braces_mentioned;
+
 extern char *index ();
 extern char *rindex ();
 
@@ -51,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.)  */
@@ -188,6 +193,24 @@ common_type (t1, t2)
   code1 = TREE_CODE (t1);
   code2 = TREE_CODE (t2);
 
+  /* If one type is complex, form the common type
+     of the non-complex components,
+     then make that complex.  */
+  if (code1 == COMPLEX_TYPE || code2 == COMPLEX_TYPE)
+    {
+      tree subtype1, subtype2, subtype;
+      if (code1 == COMPLEX_TYPE)
+       subtype1 = TREE_TYPE (t1);
+      else
+       subtype1 = t1;
+      if (code2 == COMPLEX_TYPE)
+       subtype2 = TREE_TYPE (t2);
+      else
+       subtype2 = t2;
+      subtype = common_type (subtype1, subtype2);
+      return build_complex_type (subtype);
+    }
+
   switch (code1)
     {
     case INTEGER_TYPE:
@@ -209,12 +232,12 @@ common_type (t1, t2)
 
       /* Same precision.  Prefer longs to ints even when same size.  */
 
-      if (t1 == long_unsigned_type_node
-         || t2 == long_unsigned_type_node)
+      if (TYPE_MAIN_VARIANT (t1) == long_unsigned_type_node
+         || TYPE_MAIN_VARIANT (t2) == long_unsigned_type_node)
        return long_unsigned_type_node;
 
-      if (t1 == long_integer_type_node
-         || t2 == long_integer_type_node)
+      if (TYPE_MAIN_VARIANT (t1) == long_integer_type_node
+         || TYPE_MAIN_VARIANT (t2) == long_integer_type_node)
        {
          /* But preserve unsignedness from the other type,
             since long cannot hold all the values of an unsigned int.  */
@@ -391,8 +414,9 @@ comptypes (type1, type2)
   if (TYPE_VOLATILE (t1) != TYPE_VOLATILE (t2))
     return 0;
 
-  /* If generating auxiliary info, allow for two different type nodes which
-     have essentially the same definition.  */
+  /* Allow for two different type nodes which have essentially the same
+     definition.  Note that we already checked for equality of the type
+     type qualifiers (just above).  */
 
   if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
     return 1;
@@ -438,7 +462,8 @@ comptypes (type1, type2)
       }
 
     case RECORD_TYPE:
-      return maybe_objc_comptypes (t1, t2);
+      if (maybe_objc_comptypes (t1, t2, 0) == 1)
+       return 1;
     }
   return 0;
 }
@@ -450,8 +475,15 @@ static int
 comp_target_types (ttl, ttr)
      tree ttl, ttr;
 {
-  int val = comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (ttl)),
-                      TYPE_MAIN_VARIANT (TREE_TYPE (ttr)));
+  int val;
+
+  /* Give maybe_objc_comptypes a crack at letting these types through.  */
+  if (val = maybe_objc_comptypes (ttl, ttr, 1) >= 0)
+    return val;
+
+  val = comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (ttl)),
+                  TYPE_MAIN_VARIANT (TREE_TYPE (ttr)));
+
   if (val == 2 && pedantic)
     pedwarn ("types are not quite compatible");
   return val;
@@ -730,8 +762,8 @@ c_sizeof (type)
   t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type), 
                  size_int (TYPE_PRECISION (char_type_node)));
   /* size_binop does not put the constant in range, so do it now.  */
-  if (TREE_CODE (t) == INTEGER_CST)
-    TREE_CONSTANT_OVERFLOW (t) |= force_fit_type (t, 0);
+  if (TREE_CODE (t) == INTEGER_CST && force_fit_type (t, 0))
+    TREE_CONSTANT_OVERFLOW (t) = TREE_OVERFLOW (t) = 1;
   return t;
 }
 
@@ -889,6 +921,8 @@ default_conversion (exp)
   else if (optimize
           && TREE_CODE (exp) == VAR_DECL
           && TREE_READONLY (exp)
+          /* But not for iterators!  */
+          && !ITERATOR_P (exp)
           && DECL_MODE (exp) != BLKmode)
     {
       exp = decl_constant_value (exp);
@@ -910,7 +944,9 @@ default_conversion (exp)
     {
       type = type_for_size (MAX (TYPE_PRECISION (type),
                                 TYPE_PRECISION (integer_type_node)),
-                           (flag_traditional && TREE_UNSIGNED (type)));
+                           ((flag_traditional
+                             || TYPE_PRECISION (type) >= TYPE_PRECISION (integer_type_node))
+                            && TREE_UNSIGNED (type)));
       return convert (type, exp);
     }
 
@@ -924,7 +960,8 @@ default_conversion (exp)
        return convert (unsigned_type_node, exp);
       return convert (integer_type_node, exp);
     }
-  if (flag_traditional && TYPE_MAIN_VARIANT (type) == float_type_node)
+  if (flag_traditional && !flag_allow_single_precision
+      && TYPE_MAIN_VARIANT (type) == float_type_node)
     return convert (double_type_node, exp);
   if (code == VOID_TYPE)
     {
@@ -940,6 +977,21 @@ default_conversion (exp)
       register tree adr;
       tree restype = TREE_TYPE (type);
       tree ptrtype;
+      int constp = 0;
+      int volatilep = 0;
+
+      if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'r'
+         || TREE_CODE_CLASS (TREE_CODE (exp)) == 'd')
+       {
+         constp = TREE_READONLY (exp);
+         volatilep = TREE_THIS_VOLATILE (exp);
+       }
+
+      if (TYPE_READONLY (type) || TYPE_VOLATILE (type)
+         || constp || volatilep)
+       restype = c_build_type_variant (restype,
+                                       TYPE_READONLY (type) || constp,
+                                       TYPE_VOLATILE (type) || volatilep);
 
       if (TREE_CODE (exp) == INDIRECT_REF)
        return convert (TYPE_POINTER_TO (restype),
@@ -959,10 +1011,6 @@ default_conversion (exp)
          return error_mark_node;
        }
 
-      if (TYPE_READONLY (type) || TYPE_VOLATILE (type))
-       restype = c_build_type_variant (restype, TYPE_READONLY (type),
-                                       TYPE_VOLATILE (type));
-
       ptrtype = build_pointer_type (restype);
 
       if (TREE_CODE (exp) == VAR_DECL)
@@ -986,6 +1034,101 @@ default_conversion (exp)
   return exp;
 }
 \f
+/* Look up component name in the structure type definition.
+
+   If this component name is found indirectly within an anonymous union,
+   store in *INDIRECT the component which directly contains
+   that anonymous union.  Otherwise, set *INDIRECT to 0.  */
+     
+static tree
+lookup_field (type, component, indirect)
+     tree type, component;
+     tree *indirect;
+{
+  tree field;
+
+  /* If TYPE_LANG_SPECIFIC is set, then it is a sorted array of pointers
+     to the field elements.  Use a binary search on this array to quickly
+     find the element.  Otherwise, do a linear search.  TYPE_LANG_SPECIFIC
+     will always be set for structures which have many elements.  */
+
+  if (TYPE_LANG_SPECIFIC (type))
+    {
+      int bot, top, half;
+      tree *field_array = &TYPE_LANG_SPECIFIC (type)->elts[0];
+
+      field = TYPE_FIELDS (type);
+      bot = 0;
+      top = TYPE_LANG_SPECIFIC (type)->len;
+      while (top - bot > 1)
+       {
+         HOST_WIDE_INT cmp;
+
+         half = (top - bot + 1) >> 1;
+         field = field_array[bot+half];
+
+         if (DECL_NAME (field) == NULL_TREE)
+           {
+             /* Step through all anon unions in linear fashion.  */
+             while (DECL_NAME (field_array[bot]) == NULL_TREE)
+               {
+                 tree anon, junk;
+
+                 field = field_array[bot++];
+                 anon = lookup_field (TREE_TYPE (field), component, &junk);
+                 if (anon != NULL_TREE)
+                   {
+                     *indirect = field;
+                     return anon;
+                   }
+               }
+
+             /* Entire record is only anon unions.  */
+             if (bot > top)
+               return NULL_TREE;
+
+             /* Restart the binary search, with new lower bound.  */
+             continue;
+           }
+
+         cmp = (HOST_WIDE_INT) DECL_NAME (field) - (HOST_WIDE_INT) component;
+         if (cmp == 0)
+           break;
+         if (cmp < 0)
+           bot += half;
+         else
+           top = bot + half;
+       }
+
+      if (DECL_NAME (field_array[bot]) == component)
+       field = field_array[bot];
+      else if (DECL_NAME (field) != component)
+       field = 0;
+    }
+  else
+    {
+      for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+       {
+         if (DECL_NAME (field) == NULL_TREE)
+           {
+             tree junk;
+             tree anon = lookup_field (TREE_TYPE (field), component, &junk);
+             if (anon != NULL_TREE)
+               {
+                 *indirect = field;
+                 return anon;
+               }
+           }
+
+         if (DECL_NAME (field) == component)
+           break;
+       }
+    }
+
+  *indirect = NULL_TREE;
+  return field;
+}
+
 /* Make an expression to refer to the COMPONENT field of
    structure or union value DATUM.  COMPONENT is an IDENTIFIER_NODE.  */
 
@@ -1019,55 +1162,15 @@ build_component_ref (datum, component)
 
   if (code == RECORD_TYPE || code == UNION_TYPE)
     {
+      tree indirect = 0;
+
       if (TYPE_SIZE (type) == 0)
        {
          incomplete_type_error (NULL_TREE, type);
          return error_mark_node;
        }
 
-      /* Look up component name in the structure type definition.
-
-        If TYPE_LANG_SPECIFIC is set, then it is a sorted array of pointers
-        to the field elements.  Use a binary search on this array to quickly
-        find the element.  Otherwise, do a linear search.  TYPE_LANG_SPECIFIC
-        will always be set for structures which have many elements.  */
-
-      if (TYPE_LANG_SPECIFIC (type))
-       {
-         int bot, top, half;
-         tree *field_array = &TYPE_LANG_SPECIFIC (type)->elts[0];
-
-         field = TYPE_FIELDS (type);
-         bot = 0;
-         top = TYPE_LANG_SPECIFIC (type)->len;
-         while (top - bot > 1)
-           {
-             int cmp;
-
-             half = (top - bot + 1) >> 1;
-             field = field_array[bot+half];
-             cmp = (long)DECL_NAME (field) - (long)component;
-             if (cmp == 0)
-               break;
-             if (cmp < 0)
-               bot += half;
-             else
-               top = bot + half;
-           }
-
-         if (DECL_NAME (field_array[bot]) == component)
-           field = field_array[bot];
-         else if (DECL_NAME (field) != component)
-           field = 0;
-       }
-      else
-       {
-         for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
-           {
-             if (DECL_NAME (field) == component)
-               break;
-           }
-       }
+      field = lookup_field (type, component, &indirect);
 
       if (!field)
        {
@@ -1080,6 +1183,19 @@ build_component_ref (datum, component)
       if (TREE_TYPE (field) == error_mark_node)
        return error_mark_node;
 
+      /* If FIELD was found buried within an anonymous union,
+        make one COMPONENT_REF to get that anonymous union,
+        then fall thru to make a second COMPONENT_REF to get FIELD.  */
+      if (indirect != 0)
+       {
+         ref = build (COMPONENT_REF, TREE_TYPE (indirect), datum, indirect);
+         if (TREE_READONLY (datum) || TREE_READONLY (indirect))
+           TREE_READONLY (ref) = 1;
+         if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (indirect))
+           TREE_THIS_VOLATILE (ref) = 1;
+         datum = ref;
+       }
+
       ref = build (COMPONENT_REF, TREE_TYPE (field), datum, field);
 
       if (TREE_READONLY (datum) || TREE_READONLY (field))
@@ -1139,7 +1255,7 @@ build_indirect_ref (ptr, errorstring)
          TREE_READONLY (ref) = TYPE_READONLY (t);
          TREE_SIDE_EFFECTS (ref)
            = TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer) || flag_volatile;
-         TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t) || flag_volatile;
+         TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t);
          return ref;
        }
     }
@@ -1207,6 +1323,17 @@ build_array_ref (array, index)
          if (mark_addressable (array) == 0)
            return error_mark_node;
        }
+      /* An array that is indexed by a constant value which is not within
+        the array bounds cannot be stored in a register either; because we
+        would get a crash in store_bit_field/extract_bit_field when trying
+        to access a non-existent part of the register.  */
+      if (TREE_CODE (index) == INTEGER_CST
+         && TYPE_VALUES (TREE_TYPE (array))
+         && ! int_fits_type_p (index, TYPE_VALUES (TREE_TYPE (array))))
+       {
+         if (mark_addressable (array) == 0)
+           return error_mark_node;
+       }
 
       if (pedantic && !lvalue_p (array))
        {
@@ -1276,519 +1403,6 @@ build_array_ref (array, index)
   }
 }
 \f
-/* Check a printf/fprintf/sprintf/scanf/fscanf/sscanf format against PARAMS.  */
-
-#define ISDIGIT(c)     ((c) >= '0' && (c) <= '9')
-
-#define T_I    &integer_type_node
-#define T_L    &long_integer_type_node
-#define T_S    &short_integer_type_node
-#define T_UI   &unsigned_type_node
-#define T_UL   &long_unsigned_type_node
-#define T_US   &short_unsigned_type_node
-#define T_F    &float_type_node
-#define T_D    &double_type_node
-#define T_LD   &long_double_type_node
-#define T_C    &char_type_node
-#define T_V    &void_type_node
-#define T_W    &wchar_type_node
-
-typedef struct
-{
-  char *format_chars;
-  int pointer_count;
-  /* Type of argument if no length modifier is used.  */
-  tree *nolen;
-  /* Type of argument if length modifier for shortening is used.
-     If NULL, then this modifier is not allowed.  */
-  tree *hlen;
-  /* Type of argument if length modifier `l' is used.
-     If NULL, then this modifier is not allowed.  */
-  tree *llen;
-  /* Type of argument if length modifier `L' is used.
-     If NULL, then this modifier is not allowed.  */
-  tree *bigllen;
-  /* List of other modifier characters allowed with these options.  */
-  char *flag_chars;
-} format_char_info;
-
-static format_char_info print_table[]
-  = {
-      { "di",          0,      T_I,    T_I,    T_L,    NULL,   "-wp0 +" },
-      { "oxX",         0,      T_UI,   T_UI,   T_UL,   NULL,   "-wp0#" },
-      { "u",           0,      T_UI,   T_UI,   T_UL,   NULL,   "-wp0" },
-      { "feEgG",       0,      T_D,    NULL,   NULL,   T_LD,   "-wp0 +#" },
-      { "c",           0,      T_I,    NULL,   T_W,    NULL,   "-w" },
-      { "C",           0,      T_W,    NULL,   NULL,   NULL,   "-w" },
-      { "s",           1,      T_C,    NULL,   T_W,    NULL,   "-wp" },
-      { "S",           1,      T_W,    NULL,   NULL,   NULL,   "-wp" },
-      { "p",           1,      T_V,    NULL,   NULL,   NULL,   "-" },
-      { "n",           1,      T_I,    T_S,    T_L,    NULL,   "" },
-      { NULL }
-    };
-
-static format_char_info scan_table[]
-  = {
-      { "di",          1,      T_I,    T_S,    T_L,    NULL,   "*" },
-      { "ouxX",                1,      T_UI,   T_US,   T_UL,   NULL,   "*" },  
-      { "efgEG",       1,      T_F,    NULL,   T_D,    T_LD,   "*" },
-      { "sc",          1,      T_C,    NULL,   T_W,    NULL,   "*" },
-      { "[",           1,      T_C,    NULL,   NULL,   NULL,   "*" },
-      { "C",           1,      T_W,    NULL,   NULL,   NULL,   "*" },
-      { "S",           1,      T_W,    NULL,   NULL,   NULL,   "*" },
-      { "p",           2,      T_V,    NULL,   NULL,   NULL,   "*" },
-      { "n",           1,      T_I,    T_S,    T_L,    NULL,   "" },
-      { NULL }
-    };
-
-typedef struct
-{
-  tree function_ident;         /* identifier such as "printf" */
-  int is_scan;                 /* TRUE if *scanf */
-  int format_num;              /* number of format argument */
-  int first_arg_num;           /* number of first arg (zero for varargs) */
-} function_info;
-
-static unsigned int function_info_entries = 0;
-static function_info *function_info_table = NULL;
-
-/* Record information for argument format checking.  FUNCTION_IDENT is
-   the identifier node for the name of the function to check (its decl
-   need not exist yet).  IS_SCAN is true for scanf-type format checking;
-   false indicates printf-style format checking.  FORMAT_NUM is the number
-   of the argument which is the format control string (starting from 1).
-   FIRST_ARG_NUM is the number of the first actual argument to check
-   against teh format string, or zero if no checking is not be done
-   (e.g. for varargs such as vfprintf).  */
-
-void
-record_format_info (function_ident, is_scan, format_num, first_arg_num)
-      tree function_ident;
-      int is_scan;
-      int format_num;
-      int first_arg_num;
-{
-  function_info *info;
-  
-  function_info_entries++;
-  if (function_info_table)
-    function_info_table
-      = (function_info *) xrealloc (function_info_table,
-                                   function_info_entries * sizeof (function_info));
-  else
-    function_info_table = (function_info *) xmalloc (sizeof (function_info));
-
-  info = &function_info_table[function_info_entries - 1];
-  
-  info->function_ident = function_ident;
-  info->is_scan = is_scan;
-  info->format_num = format_num;
-  info->first_arg_num = first_arg_num;
-}
-
-/* Initialize the table of functions to perform format checking on.
-   The ANSI functions are always checked (whether <stdio.h> is
-   included or not), since it is common to call printf without
-   including <stdio.h>.  There shouldn't be a problem with this,
-   since ANSI reserves these function names whether you include the
-   header file or not.  In any case, the checking is harmless.  */
-
-void
-init_format_info_table ()
-{
-  record_format_info (get_identifier ("printf"), 0, 1, 2);
-  record_format_info (get_identifier ("fprintf"), 0, 2, 3);
-  record_format_info (get_identifier ("sprintf"), 0, 2, 3);
-  record_format_info (get_identifier ("scanf"), 1, 1, 2);
-  record_format_info (get_identifier ("fscanf"), 1, 2, 3);
-  record_format_info (get_identifier ("sscanf"), 1, 2, 3);
-  record_format_info (get_identifier ("vprintf"), 0, 1, 0);
-  record_format_info (get_identifier ("vfprintf"), 0, 2, 0);
-  record_format_info (get_identifier ("vsprintf"), 0, 2, 0);
-}
-
-static char    tfaff[] = "too few arguments for format";
-\f
-/* Check the argument list of a call to printf, scanf, etc.
-   INFO points to the element of function_info_table.
-   PARAMS is the list of argument values.  */
-
-static void
-check_format (info, params)
-     function_info *info;
-     tree params;
-{
-  int i;
-  int arg_num;
-  int suppressed, wide, precise;
-  int length_char;
-  int format_char;
-  int format_length;
-  tree format_tree;
-  tree cur_param;
-  tree cur_type;
-  tree wanted_type;
-  char *format_chars;
-  format_char_info *fci;
-  static char message[132];
-  char flag_chars[8];
-
-  /* Skip to format argument.  If the argument isn't available, there's
-     no work for us to do; prototype checking will catch the problem.  */
-  for (arg_num = 1; ; ++arg_num)
-    {
-      if (params == 0)
-       return;
-      if (arg_num == info->format_num)
-       break;
-      params = TREE_CHAIN (params);
-    }
-  format_tree = TREE_VALUE (params);
-  params = TREE_CHAIN (params);
-  if (format_tree == 0)
-    return;
-  /* We can only check the format if it's a string constant.  */
-  while (TREE_CODE (format_tree) == NOP_EXPR)
-    format_tree = TREE_OPERAND (format_tree, 0); /* strip coercion */
-  if (format_tree == null_pointer_node)
-    {
-      warning ("null format string");
-      return;
-    }
-  if (TREE_CODE (format_tree) != ADDR_EXPR)
-    return;
-  format_tree = TREE_OPERAND (format_tree, 0);
-  if (TREE_CODE (format_tree) != STRING_CST)
-    return;
-  format_chars = TREE_STRING_POINTER (format_tree);
-  format_length = TREE_STRING_LENGTH (format_tree);
-  if (format_length <= 1)
-    warning ("zero-length format string");
-  if (format_chars[--format_length] != 0)
-    {
-      warning ("unterminated format string");
-      return;
-    }
-  /* Skip to first argument to check.  */
-  while (arg_num + 1 < info->first_arg_num)
-    {
-      if (params == 0)
-       return;
-      params = TREE_CHAIN (params);
-      ++arg_num;
-    }
-  while (1)
-    {
-      if (*format_chars == 0)
-       {
-         if (format_chars - TREE_STRING_POINTER (format_tree) != format_length)
-           warning ("embedded `\\0' in format");
-         if (info->first_arg_num != 0 && params != 0)
-           warning ("too many arguments for format");
-         return;
-       }
-      if (*format_chars++ != '%')
-       continue;
-      if (*format_chars == 0)
-       {
-         warning ("spurious trailing `%%' in format");
-         continue;
-       }
-      if (*format_chars == '%')
-       {
-         ++format_chars;
-         continue;
-       }
-      flag_chars[0] = 0;
-      suppressed = wide = precise = FALSE;
-      if (info->is_scan)
-       {
-         suppressed = *format_chars == '*';
-         if (suppressed)
-           ++format_chars;
-         while (ISDIGIT (*format_chars))
-           ++format_chars;
-       }
-      else
-       {
-         while (*format_chars != 0 && index (" +#0-", *format_chars) != 0)
-           {
-             if (index (flag_chars, *format_chars) != 0)
-               {
-                 sprintf (message, "repeated `%c' flag in format",
-                          *format_chars);
-                 warning (message);
-               }
-             i = strlen (flag_chars);
-             flag_chars[i++] = *format_chars++;
-             flag_chars[i] = 0;
-           }
-         /* "If the space and + flags both appear, 
-            the space flag will be ignored."  */
-         if (index (flag_chars, ' ') != 0
-             && index (flag_chars, '+') != 0)
-           warning ("use of both ` ' and `+' flags in format");
-         /* "If the 0 and - flags both appear,
-            the 0 flag will be ignored."  */
-         if (index (flag_chars, '0') != 0
-             && index (flag_chars, '-') != 0)
-           warning ("use of both `0' and `-' flags in format");
-         if (*format_chars == '*')
-           {
-             wide = TRUE;
-             /* "...a field width...may be indicated by an asterisk.
-                In this case, an int argument supplies the field width..."  */
-             ++format_chars;
-             if (params == 0)
-               {
-                 warning (tfaff);
-                 return;
-               }
-             if (info->first_arg_num != 0)
-               {
-                 cur_param = TREE_VALUE (params);
-                 params = TREE_CHAIN (params);
-                 ++arg_num;
-                 /* size_t is generally not valid here.
-                    It will work on most machines, because size_t and int
-                    have the same mode.  But might as well warn anyway,
-                    since it will fail on other machines.  */
-                 if (TYPE_MAIN_VARIANT (TREE_TYPE (cur_param))
-                     != integer_type_node)
-                   {
-                     sprintf (message,
-                              "field width is not type int (arg %d)",
-                              arg_num);
-                     warning (message);
-                   }
-               }
-           }
-         else
-           {
-             while (ISDIGIT (*format_chars))
-               {
-                 wide = TRUE;
-                 ++format_chars;
-               }
-           }
-         if (*format_chars == '.')
-           {
-             precise = TRUE;
-             ++format_chars;
-             if (*format_chars != '*' && !ISDIGIT (*format_chars))
-               warning ("`.' not followed by `*' or digit in format");
-             /* "...a...precision...may be indicated by an asterisk.
-                In this case, an int argument supplies the...precision."  */
-             if (*format_chars == '*')
-               {
-                 if (info->first_arg_num != 0)
-                   {
-                     ++format_chars;
-                     if (params == 0)
-                       {
-                         warning (tfaff);
-                         return;
-                       }
-                     cur_param = TREE_VALUE (params);
-                     params = TREE_CHAIN (params);
-                     ++arg_num;
-                     if (TYPE_MAIN_VARIANT (TREE_TYPE (cur_param))
-                         != integer_type_node)
-                       {
-                         sprintf (message,
-                                  "field width is not type int (arg %d)",
-                                  arg_num);
-                         warning (message);
-                       }
-                   }
-               }
-             else
-               {
-                 while (ISDIGIT (*format_chars))
-                   ++format_chars;
-               }
-           }
-       }
-      if (*format_chars == 'h' || *format_chars == 'l' || *format_chars == 'L')
-       length_char = *format_chars++;
-      else
-       length_char = 0;
-      if (suppressed && length_char != 0)
-       {
-         sprintf (message,
-                  "use of `*' and `%c' together in format",
-                  length_char);
-         warning (message);
-       }
-      format_char = *format_chars;
-      if (format_char == 0)
-       {
-         warning ("conversion lacks type at end of format");
-         continue;
-       }
-      format_chars++;
-      fci = info->is_scan ? scan_table : print_table;
-      while (1)
-       {
-         if (fci->format_chars == 0
-             || index (fci->format_chars, format_char) != 0)
-           break;
-         ++fci;
-       }
-      if (fci->format_chars == 0)
-       {
-         if (format_char >= 040 && format_char < 0177)
-           sprintf (message,
-                    "unknown conversion type character `%c' in format",
-                    format_char);
-         else
-           sprintf (message,
-                    "unknown conversion type character 0x%x in format",
-                    format_char);
-         warning (message);
-         continue;
-       }
-      if (wide && index (fci->flag_chars, 'w') == 0)
-       {
-         sprintf (message, "width used with `%c' format",
-                  format_char);
-         warning (message);
-       }
-      if (precise && index (fci->flag_chars, 'p') == 0)
-       {
-         sprintf (message, "precision used with `%c' format",
-                  format_char);
-         warning (message);
-       }
-      if (suppressed)
-       {
-         if (index (fci->flag_chars, '*') == 0)
-           {
-             sprintf (message,
-                      "suppression of `%c' conversion in format",
-                      format_char);
-             warning (message);
-           }
-         continue;
-       }
-      for (i = 0; flag_chars[i] != 0; ++i)
-       {
-         if (index (fci->flag_chars, flag_chars[i]) == 0)
-           {
-             sprintf (message, "flag `%c' used with type `%c'",
-                      flag_chars[i], format_char);
-             warning (message);
-           }
-       }
-      if (precise && index (flag_chars, '0') != 0
-         && (format_char == 'd' || format_char == 'i'
-             || format_char == 'o' || format_char == 'u'
-             || format_char == 'x' || format_char == 'x'))
-       {
-         sprintf (message,
-                  "precision and `0' flag not both allowed with `%c' format",
-                  format_char);
-         warning (message);
-       }
-      switch (length_char)
-       {
-       default: wanted_type = fci->nolen ? *(fci->nolen) : 0; break;
-       case 'h': wanted_type = fci->hlen ? *(fci->hlen) : 0; break;
-       case 'l': wanted_type = fci->llen ? *(fci->llen) : 0; break;
-       case 'L': wanted_type = fci->bigllen ? *(fci->bigllen) : 0; break;
-       }
-      if (wanted_type == 0)
-       {
-         sprintf (message,
-                  "use of `%c' length character with `%c' type character",
-                  length_char, format_char);
-         warning (message);
-       }
-
-      /*
-       ** XXX -- should kvetch about stuff such as
-       **      {
-       **              const int       i;
-       **
-       **              scanf ("%d", &i);
-       **      }
-       */
-
-      /* Finally. . .check type of argument against desired type!  */
-      if (info->first_arg_num == 0)
-       continue;
-      if (params == 0)
-       {
-         warning (tfaff);
-         return;
-       }
-      cur_param = TREE_VALUE (params);
-      params = TREE_CHAIN (params);
-      ++arg_num;
-      cur_type = TREE_TYPE (cur_param);
-
-      /* Check the types of any additional pointer arguments
-        that precede the "real" argument.  */
-      for (i = 0; i < fci->pointer_count; ++i)
-       {
-         if (TREE_CODE (cur_type) == POINTER_TYPE)
-           {
-             cur_type = TREE_TYPE (cur_type);
-             continue;
-           }
-         sprintf (message,
-                  "format argument is not a %s (arg %d)",
-                  ((fci->pointer_count == 1) ? "pointer" : "pointer to a pointer"),
-                  arg_num);
-         warning (message);
-         break;
-       }
-
-      /* Check the type of the "real" argument, if there's a type we want.  */
-      if (i == fci->pointer_count && wanted_type != 0
-         && wanted_type != TYPE_MAIN_VARIANT (cur_type)
-         /* If we want `void *', allow any pointer type.
-            (Anything else would already have got a warning.)  */
-         && ! (wanted_type == void_type_node
-               && fci->pointer_count > 0)
-         /* Don't warn about differences merely in signedness.  */
-         && !(TREE_CODE (wanted_type) == INTEGER_TYPE
-              && TREE_CODE (cur_type) == INTEGER_TYPE
-              && TYPE_PRECISION (wanted_type) == TYPE_PRECISION (cur_type)))
-       {
-         register char *this;
-         register char *that;
-  
-         this = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (wanted_type)));
-         that = 0;
-         if (TYPE_NAME (cur_type) != 0
-             && TREE_CODE (cur_type) != INTEGER_TYPE
-             && !(TREE_CODE (cur_type) == POINTER_TYPE
-                  && TREE_CODE (TREE_TYPE (cur_type)) == INTEGER_TYPE)
-             && DECL_NAME (TYPE_NAME (cur_type)) != 0)
-           that = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (cur_type)));
-
-         /* A nameless type can't possibly match what the format wants.
-            So there will be a warning for it.
-            Make up a string to describe vaguely what it is.  */
-         if (that == 0)
-           {
-             if (TREE_CODE (cur_type) == POINTER_TYPE)
-               that = "pointer";
-             else
-               that = "different type";
-           }
-
-         if (strcmp (this, that) != 0)
-           {
-             sprintf (message, "%s format, %s arg (arg %d)",
-                       this, that, arg_num);
-             warning (message);
-           }
-       }
-    }
-}
-\f
 /* Build a function call to function FUNCTION with parameters PARAMS.
    PARAMS is a list--a chain of TREE_LIST nodes--in which the
    TREE_VALUE of each node is a parameter-expression.
@@ -1798,9 +1412,9 @@ tree
 build_function_call (function, params)
      tree function, params;
 {
-  register tree fntype, fundecl;
+  register tree fntype, fundecl = 0;
   register tree coerced_params;
-  tree name = NULL_TREE;
+  tree name = NULL_TREE, assembler_name = NULL_TREE;
 
   /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue.  */
   STRIP_TYPE_NOPS (function);
@@ -1809,6 +1423,8 @@ build_function_call (function, params)
   if (TREE_CODE (function) == FUNCTION_DECL)
     {
       name = DECL_NAME (function);
+      assembler_name = DECL_ASSEMBLER_NAME (function);
+
       /* Differs from default_conversion by not setting TREE_ADDRESSABLE
         (because calling an inline function does not mean the function
         needs to be separately compiled).  */
@@ -1843,21 +1459,9 @@ build_function_call (function, params)
     = convert_arguments (TYPE_ARG_TYPES (fntype), params, name, fundecl);
 
   /* Check for errors in format strings.  */
-  if (warn_format && name != 0)
-    {
-      unsigned int i;
-
-      /* See if this function is a format function.  */
-      for (i = 0; i < function_info_entries; i++)
-       if (function_info_table[i].function_ident == name)
-         {
-           register char *message;
 
-           /* If so, check it.  */
-           check_format (&function_info_table[i], coerced_params);
-           break;
-         }
-    }
+  if (warn_format && (name || assembler_name))
+    check_function_format (name, assembler_name, coerced_params);
 
   /* Recognize certain built-in functions so we can make tree-codes
      other than CALL_EXPR.  We do this when it enables fold-const.c
@@ -1959,11 +1563,13 @@ convert_arguments (typelist, values, name, fundecl)
          else
            {
              tree parmname;
+             tree type0 = type;
 #ifdef PROMOTE_PROTOTYPES
              /* Rather than truncating and then reextending,
                 convert directly to int, if that's the type we will want.  */
              if (! flag_traditional
-                 && TREE_CODE (type) == INTEGER_TYPE
+                 && (TREE_CODE (type) == INTEGER_TYPE
+                     || TREE_CODE (type) == ENUMERAL_TYPE)
                  && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
                type = integer_type_node;
 #endif
@@ -2034,12 +1640,26 @@ convert_arguments (typelist, values, name, fundecl)
                        /* Change in signedness doesn't matter
                           if a constant value is unaffected.  */
                        ;
+                     /* Likewise for a constant in a NOP_EXPR.  */
+                     else if (TREE_CODE (val) == NOP_EXPR
+                              && TREE_CODE (TREE_OPERAND (val, 0)) == INTEGER_CST
+                              && int_fits_type_p (TREE_OPERAND (val, 0), type))
+                       ;
+#if 0 /* We never get such tree structure here.  */
                      else if (TREE_CODE (TREE_TYPE (val)) == ENUMERAL_TYPE
                               && int_fits_type_p (TYPE_MIN_VALUE (TREE_TYPE (val)), type)
                               && int_fits_type_p (TYPE_MAX_VALUE (TREE_TYPE (val)), type))
                        /* Change in signedness doesn't matter
                           if an enum value is unaffected.  */
                        ;
+#endif
+                     /* If the value is extended from a narrower
+                        unsigned type, it doesn't matter whether we
+                        pass it as signed or unsigned; the value
+                        certainly is the same either way.  */
+                     else if (TYPE_PRECISION (TREE_TYPE (val)) < TYPE_PRECISION (type)
+                              && TREE_UNSIGNED (TREE_TYPE (val)))
+                       ;
                      else if (TREE_UNSIGNED (type))
                        warn_for_assignment ("%s as unsigned due to prototype", (char *) 0, name, parmnum + 1);
                      else
@@ -2052,7 +1672,8 @@ convert_arguments (typelist, values, name, fundecl)
                                                fundecl, name, parmnum + 1);
              
 #ifdef PROMOTE_PROTOTYPES
-             if (TREE_CODE (type) == INTEGER_TYPE
+             if ((TREE_CODE (type) == INTEGER_TYPE
+                  || TREE_CODE (type) == ENUMERAL_TYPE)
                  && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
                parmval = default_conversion (parmval);
 #endif
@@ -2174,6 +1795,10 @@ parser_build_binary_op (code, arg1, arg2)
   else
     {
       int flag = TREE_CONSTANT (result);
+      /* We used to use NOP_EXPR rather than NON_LVALUE_EXPR
+        so that convert_for_assignment wouldn't strip it.
+        That way, we got warnings for things like p = (1 - 1).
+        But it turns out we should not get those warnings.  */
       result = build1 (NON_LVALUE_EXPR, TREE_TYPE (result), result);
       C_SET_EXP_ORIGINAL_CODE (result, code);
       TREE_CONSTANT (result) = flag;
@@ -2308,15 +1933,17 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
     case FLOOR_DIV_EXPR:
     case ROUND_DIV_EXPR:
     case EXACT_DIV_EXPR:
-      if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
-         && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
+      if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
+          || code0 == COMPLEX_TYPE)
+         && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
+             || code1 == COMPLEX_TYPE))
        {
          if (!(code0 == INTEGER_TYPE && code1 == INTEGER_TYPE))
            resultcode = RDIV_EXPR;
          else
            /* When dividing two signed integers, you have to promote to int.
               E.g. (short) -32868 / (short) -1 doesn't fit in a short.  */
-           shorten = TREE_UNSIGNED (op0);
+           shorten = TREE_UNSIGNED (orig_op0);
          common = 1;
        }
       break;
@@ -2355,7 +1982,17 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
     case TRUNC_MOD_EXPR:
     case FLOOR_MOD_EXPR:
       if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
-       shorten = 1;
+       {
+         /* Although it would be tempting to shorten always here, that loses
+            on some targets, since the modulo instruction is undefined if the
+            quotient can't be represented in the computation mode.  We shorten
+            only if unsigned or if dividing by something we know != -1.  */
+         shorten = (TREE_UNSIGNED (orig_op0)
+                    || (TREE_CODE (op1) == INTEGER_CST
+                        && (TREE_INT_CST_LOW (op1) != -1
+                            || TREE_INT_CST_HIGH (op1) != -1)));
+         common = 1;
+       }
       break;
 
     case TRUTH_ANDIF_EXPR:
@@ -2363,8 +2000,10 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
     case TRUTH_AND_EXPR:
     case TRUTH_OR_EXPR:
     case TRUTH_XOR_EXPR:
-      if ((code0 == INTEGER_TYPE || code0 == POINTER_TYPE || code0 == REAL_TYPE)
-         && (code1 == INTEGER_TYPE || code1 == POINTER_TYPE || code1 == REAL_TYPE))
+      if ((code0 == INTEGER_TYPE || code0 == POINTER_TYPE
+          || code0 == REAL_TYPE || code0 == COMPLEX_TYPE)
+         && (code1 == INTEGER_TYPE || code1 == POINTER_TYPE
+             || code1 == REAL_TYPE || code1 == COMPLEX_TYPE))
        {
          /* Result of these operations is always an int,
             but that does not mean the operands should be
@@ -2473,26 +2112,31 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
         but don't convert the args to int!  */
       result_type = integer_type_node;
       converted = 1;
-      if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
-         && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
+      if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
+          || code0 == COMPLEX_TYPE)
+         && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
+             || code1 == COMPLEX_TYPE))
        short_compare = 1;
       else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
        {
          register tree tt0 = TREE_TYPE (type0);
          register tree tt1 = TREE_TYPE (type1);
          /* Anything compares with void *.  void * compares with anything.
-            Otherwise, the targets must be the same.  */
+            Otherwise, the targets must be compatible
+            and both must be object or both incomplete.  */
          if (comp_target_types (type0, type1))
            ;
          else if (TYPE_MAIN_VARIANT (tt0) == void_type_node)
            {
-             if (pedantic && !integer_zerop (op0)
+             /* op0 != orig_op0 detects the case of something
+                whose value is 0 but which isn't a valid null ptr const.  */
+             if (pedantic && (!integer_zerop (op0) || op0 != orig_op0)
                  && TREE_CODE (tt1) == FUNCTION_TYPE)
                pedwarn ("ANSI C forbids comparison of `void *' with function pointer");
            }
          else if (TYPE_MAIN_VARIANT (tt1) == void_type_node)
            {
-             if (pedantic && !integer_zerop (op1)
+             if (pedantic && (!integer_zerop (op1) || op1 != orig_op1)
                  && TREE_CODE (tt0) == FUNCTION_TYPE)
                pedwarn ("ANSI C forbids comparison of `void *' with function pointer");
            }
@@ -2526,7 +2170,7 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
     case MAX_EXPR:
     case MIN_EXPR:
       if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
-          && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
+         && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
        shorten = 1;
       else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
        {
@@ -2544,12 +2188,15 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
     case LT_EXPR:
     case GT_EXPR:
       if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
-          && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
+         && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
        short_compare = 1;
       else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
        {
          if (! comp_target_types (type0, type1))
            pedwarn ("comparison of distinct pointer types lacks a cast");
+         else if ((TYPE_SIZE (TREE_TYPE (type0)) != 0)
+                  != (TYPE_SIZE (TREE_TYPE (type1)) != 0))
+           pedwarn ("comparison of complete and incomplete pointers");
          else if (pedantic 
                   && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
            pedwarn ("ANSI C forbids ordered comparisons of pointers to functions");
@@ -2560,7 +2207,7 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
        {
          result_type = integer_type_node;
          op1 = null_pointer_node;
-         if (! flag_traditional)
+         if (pedantic)
            pedwarn ("ordered comparison of pointer with integer zero");
        }
       else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
@@ -2589,9 +2236,12 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
       break;
     }
 
-  if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
-      && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
+  if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE)
+      &&
+      (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE))
     {
+      int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE);
+
       if (shorten || common || short_compare)
        result_type = common_type (type0, type1);
 
@@ -2606,7 +2256,7 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
         Eg, (short)-1 | (unsigned short)-1 is (int)-1
         but calculated in (unsigned short) it would be (unsigned short)-1.  */
 
-      if (shorten)
+      if (shorten && none_complex)
        {
          int unsigned0, unsigned1;
          tree arg0 = get_narrower (op0, &unsigned0);
@@ -2708,7 +2358,7 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
       /* Comparison operations are shortened too but differently.
         They identify themselves by setting short_compare = 1.  */
 
-      if (short_compare)
+      if (short_compare && none_complex)
        {
          /* Don't write &op0, etc., because that would prevent op0
             from being kept in a register.
@@ -2897,6 +2547,10 @@ pointer_diff (op0, op1)
 
   op0 = build_binary_op (MINUS_EXPR, convert (restype, op0),
                         convert (restype, op1), 1);
+  /* This generates an error if op1 is pointer to incomplete type.  */
+  if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (op1))) == 0)
+    error ("arithmetic on pointer to an incomplete type");
+  /* This generates an error if op0 is pointer to incomplete type.  */
   op1 = c_size_in_bytes (target_type);
 
   /* Divide by the size, in easiest possible way.  */
@@ -2938,36 +2592,55 @@ build_unary_op (code, xarg, noconvert)
       /* This is used for unary plus, because a CONVERT_EXPR
         is enough to prevent anybody from looking inside for
         associativity, but won't generate any code.  */
-      if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE))
+      if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE
+           || typecode == COMPLEX_TYPE))
         errstring = "wrong type argument to unary plus";
       else if (!noconvert)
        arg = default_conversion (arg);
       break;
 
     case NEGATE_EXPR:
-      if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE))
+      if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE
+           || typecode == COMPLEX_TYPE))
         errstring = "wrong type argument to unary minus";
       else if (!noconvert)
        arg = default_conversion (arg);
       break;
 
     case BIT_NOT_EXPR:
-      if (typecode != INTEGER_TYPE)
+      if (typecode == COMPLEX_TYPE)
+       {
+         code = CONJ_EXPR;
+         if (!noconvert)
+           arg = default_conversion (arg);
+       }
+      else if (typecode != INTEGER_TYPE)
         errstring = "wrong type argument to bit-complement";
       else if (!noconvert)
        arg = default_conversion (arg);
       break;
 
     case ABS_EXPR:
-      if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE))
+      if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE
+           || typecode == COMPLEX_TYPE))
         errstring = "wrong type argument to abs";
       else if (!noconvert)
        arg = default_conversion (arg);
       break;
 
+    case CONJ_EXPR:
+      /* Conjugating a real value is a no-op, but allow it anyway.  */
+      if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE
+           || typecode == COMPLEX_TYPE))
+       errstring = "wrong type argument to conjugation";
+      else if (!noconvert)
+       arg = default_conversion (arg);
+      break;
+
     case TRUTH_NOT_EXPR:
       if (typecode != INTEGER_TYPE
          && typecode != REAL_TYPE && typecode != POINTER_TYPE
+         && typecode != COMPLEX_TYPE
          /* These will convert to a pointer.  */
          && typecode != ARRAY_TYPE && typecode != FUNCTION_TYPE)
        {
@@ -2979,6 +2652,22 @@ build_unary_op (code, xarg, noconvert)
 
     case NOP_EXPR:
       break;
+
+    case REALPART_EXPR:
+      if (TREE_CODE (arg) == COMPLEX_CST)
+       return TREE_REALPART (arg);
+      else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
+       return fold (build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
+      else
+       return arg;
+
+    case IMAGPART_EXPR:
+      if (TREE_CODE (arg) == COMPLEX_CST)
+       return TREE_IMAGPART (arg);
+      else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
+       return fold (build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
+      else
+       return convert (TREE_TYPE (arg), integer_zero_node);
       
     case PREINCREMENT_EXPR:
     case POSTINCREMENT_EXPR:
@@ -2991,6 +2680,19 @@ build_unary_op (code, xarg, noconvert)
       if (val != 0)
        return val;
 
+      /* Increment or decrement the real part of the value,
+        and don't change the imaginary part.  */
+      if (typecode == COMPLEX_TYPE)
+       {
+         tree real, imag;
+
+         arg = stabilize_reference (arg);
+         real = build_unary_op (REALPART_EXPR, arg, 1);
+         imag = build_unary_op (IMAGPART_EXPR, arg, 1);
+         return build (COMPLEX_EXPR, TREE_TYPE (arg),
+                       build_unary_op (code, real, 1), imag);
+       }
+
       /* Report invalid types.  */
 
       if (typecode != POINTER_TYPE
@@ -3014,9 +2716,16 @@ build_unary_op (code, xarg, noconvert)
 
        if (typecode == POINTER_TYPE)
          {
-           if ((pedantic || warn_pointer_arith)
-               && (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE
-                   || TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE))
+           /* If pointer target is an undefined struct,
+              we just cannot know how to do the arithmetic.  */
+           if (TYPE_SIZE (TREE_TYPE (result_type)) == 0)
+             error ("%s of pointer to unknown structure",
+                      ((code == PREINCREMENT_EXPR
+                        || code == POSTINCREMENT_EXPR)
+                       ? "increment" : "decrement"));
+           else if ((pedantic || warn_pointer_arith)
+                    && (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE
+                        || TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE))
              pedwarn ("wrong type argument to %s",
                       ((code == PREINCREMENT_EXPR
                         || code == POSTINCREMENT_EXPR)
@@ -3266,6 +2975,8 @@ lvalue_p (ref)
 
   switch (code)
     {
+    case REALPART_EXPR:
+    case IMAGPART_EXPR:
     case COMPONENT_REF:
       return lvalue_p (TREE_OPERAND (ref, 0));
 
@@ -3356,6 +3067,13 @@ readonly_warning (arg, string)
   char buf[80];
   strcpy (buf, string);
 
+  /* Forbid assignments to iterators.  */
+  if (TREE_CODE (arg) == VAR_DECL && ITERATOR_P (arg))
+    {
+      strcat (buf, " of iterator `%s'");
+      pedwarn (buf, IDENTIFIER_POINTER (DECL_NAME (arg)));
+    }
+
   if (TREE_CODE (arg) == COMPONENT_REF)
     {
       if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0))))
@@ -3392,6 +3110,8 @@ mark_addressable (exp)
       case ADDR_EXPR:
       case COMPONENT_REF:
       case ARRAY_REF:
+      case REALPART_EXPR:
+      case IMAGPART_EXPR:
        x = TREE_OPERAND (x, 0);
        break;
 
@@ -3452,6 +3172,7 @@ build_conditional_expr (ifexp, op1, op2)
   register enum tree_code code1;
   register enum tree_code code2;
   register tree result_type = NULL;
+  tree orig_op1 = op1, orig_op2 = op2;
 
   /* If second operand is omitted, it is the same as the first one;
      make sure it is calculated only once.  */
@@ -3464,11 +3185,6 @@ build_conditional_expr (ifexp, op1, op2)
 
   ifexp = truthvalue_conversion (default_conversion (ifexp));
 
-  if (TREE_CODE (ifexp) == ERROR_MARK
-      || TREE_CODE (TREE_TYPE (op1)) == ERROR_MARK
-      || TREE_CODE (TREE_TYPE (op2)) == ERROR_MARK)
-    return error_mark_node;
-
 #if 0 /* Produces wrong result if within sizeof.  */
   /* Don't promote the operands separately if they promote
      the same way.  Return the unpromoted type and let the combined
@@ -3480,21 +3196,26 @@ build_conditional_expr (ifexp, op1, op2)
       && TREE_CODE (TREE_TYPE (op1)) != FUNCTION_TYPE)
     {
       if (TREE_CODE (ifexp) == INTEGER_CST)
-       return (integer_zerop (ifexp) ? op2 : op1);
+       return pedantic_non_lvalue (integer_zerop (ifexp) ? op2 : op1);
 
       return fold (build (COND_EXPR, TREE_TYPE (op1), ifexp, op1, op2));
     }
 #endif
 
-  /* They don't match; promote them both and then try to reconcile them.  */
+  /* Promote both alternatives.  */
 
   if (TREE_CODE (TREE_TYPE (op1)) != VOID_TYPE)
     op1 = default_conversion (op1);
   if (TREE_CODE (TREE_TYPE (op2)) != VOID_TYPE)
     op2 = default_conversion (op2);
 
-  type1 = TREE_TYPE (op1);
-  code1 = TREE_CODE (type1);
+  if (TREE_CODE (ifexp) == ERROR_MARK
+      || TREE_CODE (TREE_TYPE (op1)) == ERROR_MARK
+      || TREE_CODE (TREE_TYPE (op2)) == ERROR_MARK)
+    return error_mark_node;
+
+  type1 = TREE_TYPE (op1);
+  code1 = TREE_CODE (type1);
   type2 = TREE_TYPE (op2);
   code2 = TREE_CODE (type2);
       
@@ -3522,9 +3243,11 @@ build_conditional_expr (ifexp, op1, op2)
     {
       if (comp_target_types (type1, type2))
        result_type = common_type (type1, type2);
-      else if (integer_zerop (op1) && TREE_TYPE (type1) == void_type_node)
+      else if (integer_zerop (op1) && TREE_TYPE (type1) == void_type_node
+              && TREE_CODE (orig_op1) != NOP_EXPR)
        result_type = qualify_type (type2, type1);
-      else if (integer_zerop (op2) && TREE_TYPE (type2) == void_type_node)
+      else if (integer_zerop (op2) && TREE_TYPE (type2) == void_type_node
+              && TREE_CODE (orig_op2) != NOP_EXPR)
        result_type = qualify_type (type1, type2);
       else if (TYPE_MAIN_VARIANT (TREE_TYPE (type1)) == void_type_node)
        {
@@ -3600,7 +3323,7 @@ build_conditional_expr (ifexp, op1, op2)
     {
       result_type = TREE_TYPE (op1);
       if (TREE_CONSTANT (ifexp))
-       return (integer_zerop (ifexp) ? op2 : op1);
+       return pedantic_non_lvalue (integer_zerop (ifexp) ? op2 : op1);
 
       if (TYPE_MODE (result_type) == BLKmode)
        {
@@ -3633,7 +3356,7 @@ build_conditional_expr (ifexp, op1, op2)
 #endif /* 0 */
     
   if (TREE_CODE (ifexp) == INTEGER_CST)
-    return integer_zerop (ifexp) ? op2 : op1;
+    return pedantic_non_lvalue (integer_zerop (ifexp) ? op2 : op1);
 
   return fold (build (COND_EXPR, result_type, ifexp, op1, op2));
 }
@@ -3681,7 +3404,9 @@ internal_build_compound_expr (list, first_p)
 
   rest = internal_build_compound_expr (TREE_CHAIN (list), FALSE);
 
-  if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)))
+  /* When pedantic, a compound expression can be neither an lvalue
+     nor an integer constant expression.  */
+  if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)) && ! pedantic)
     return rest;
 
   return build (COMPOUND_EXPR, TREE_TYPE (rest), TREE_VALUE (list), rest);
@@ -3730,6 +3455,10 @@ build_c_cast (type, expr)
   else if (TREE_CODE (type) == UNION_TYPE)
     {
       tree field;
+      if (TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
+         || TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE)
+       value = default_conversion (value);
+
       for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
        if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)),
                       TYPE_MAIN_VARIANT (TREE_TYPE (value))))
@@ -3738,7 +3467,7 @@ build_c_cast (type, expr)
       if (field)
        {
          char *name;
-         tree nvalue;
+         tree t;
 
          if (pedantic)
            pedwarn ("ANSI C forbids casts to union type");
@@ -3751,16 +3480,18 @@ build_c_cast (type, expr)
            }
          else
            name = "";
-         return digest_init (type, build_nt (CONSTRUCTOR, NULL_TREE,
-                                             build_tree_list (field, value)),
-                             NULL_PTR, 0, 0, name);
+         t = digest_init (type, build (CONSTRUCTOR, type, NULL_TREE,
+                                       build_tree_list (field, value)),
+                          0, 0);
+         TREE_CONSTANT (t) = TREE_CONSTANT (value);
+         return t;
        }
       error ("cast to union type from type not present in union");
       return error_mark_node;
     }
   else
     {
-      tree otype;
+      tree otype, ovalue;
 
       /* If casting to void, avoid the error that would come
         from default_conversion in the case of a non-lvalue array.  */
@@ -3815,18 +3546,27 @@ build_c_cast (type, expr)
          && !TREE_CONSTANT (value))
        warning ("cast to pointer from integer of different size");
 
+      ovalue = value;
       value = convert (type, value);
 
       /* Ignore any integer overflow caused by the cast.  */
       if (TREE_CODE (value) == INTEGER_CST)
-       TREE_CONSTANT_OVERFLOW (value) = 0;
+       {
+         TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue);
+         TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_OVERFLOW (ovalue);
+       }
     }
 
+  /* Pedantically, don't ley (void *) (FOO *) 0 be a null pointer constant.  */
+  if (pedantic && TREE_CODE (value) == INTEGER_CST
+      && TREE_CODE (expr) == INTEGER_CST
+      && TREE_CODE (TREE_TYPE (expr)) != INTEGER_TYPE)
+    value = non_lvalue (value);
+
+  /* If pedantic, don't let a cast be an lvalue.  */
   if (value == expr && pedantic)
-    {
-      /* If pedantic, don't let a cast be an lvalue.  */
-      return non_lvalue (value);
-    }
+    value = non_lvalue (value);
+
   return value;
 }
 \f
@@ -3867,11 +3607,13 @@ build_modify_expr (lhs, modifycode, rhs)
       /* Handle (a, b) used as an "lvalue".  */
     case COMPOUND_EXPR:
       pedantic_lvalue_warning (COMPOUND_EXPR);
+      newrhs = build_modify_expr (TREE_OPERAND (lhs, 1),
+                                 modifycode, rhs);
+      if (TREE_CODE (newrhs) == ERROR_MARK)
+       return error_mark_node;
       return build (COMPOUND_EXPR, lhstype,
-                   TREE_OPERAND (lhs, 0),
-                   build_modify_expr (TREE_OPERAND (lhs, 1),
-                                      modifycode, rhs));
-
+                   TREE_OPERAND (lhs, 0), newrhs);
       /* Handle (a ? b : c) used as an "lvalue".  */
     case COND_EXPR:
       pedantic_lvalue_warning (COND_EXPR);
@@ -3886,6 +3628,8 @@ build_modify_expr (lhs, modifycode, rhs)
                                                       modifycode, rhs),
                                    build_modify_expr (TREE_OPERAND (lhs, 2),
                                                       modifycode, rhs));
+       if (TREE_CODE (cond) == ERROR_MARK)
+         return cond;
        /* Make sure the code to compute the rhs comes out
           before the split.  */
        return build (COMPOUND_EXPR, TREE_TYPE (lhs),
@@ -3928,6 +3672,8 @@ build_modify_expr (lhs, modifycode, rhs)
        result = build_modify_expr (inner_lhs, NOP_EXPR,
                                    convert (TREE_TYPE (inner_lhs),
                                             convert (lhstype, newrhs)));
+       if (TREE_CODE (result) == ERROR_MARK)
+         return result;
        pedantic_lvalue_warning (CONVERT_EXPR);
        return convert (TREE_TYPE (lhs), result);
       }
@@ -4033,6 +3779,9 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
   if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
     {
       overflow_warning (rhs);
+      /* Check for Objective-C protocols.  This will issue a warning if
+        there are protocol violations.  No need to use the return value.  */
+      maybe_objc_comptypes (type, rhstype, 0);
       return rhs;
     }
 
@@ -4042,12 +3791,14 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
       return error_mark_node;
     }
   /* Arithmetic types all interconvert, and enum is treated like int.  */
-  if ((codel == INTEGER_TYPE || codel == REAL_TYPE || codel == ENUMERAL_TYPE)
+  if ((codel == INTEGER_TYPE || codel == REAL_TYPE || codel == ENUMERAL_TYPE
+       || codel == COMPLEX_TYPE)
        &&
-      (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == ENUMERAL_TYPE))
+      (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == ENUMERAL_TYPE
+       || coder == COMPLEX_TYPE))
     return convert_and_check (type, rhs);
   /* Conversion to a union from its member types.  */
-  else if (codel = UNION_TYPE)
+  else if (codel == UNION_TYPE)
     {
       tree memb_types;
       for (memb_types = TYPE_FIELDS (type); memb_types;
@@ -4060,6 +3811,51 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
                pedwarn ("ANSI C prohibits argument conversion to union type");
              return build1 (NOP_EXPR, type, rhs);
            }
+         else if (coder == POINTER_TYPE
+                  && TREE_CODE (TREE_TYPE (memb_types)) == POINTER_TYPE)
+           {
+             tree memb_type = TREE_TYPE (memb_types);
+             register tree ttl = TREE_TYPE (memb_type);
+             register tree ttr = TREE_TYPE (rhstype);
+
+             /* Any non-function converts to a [const][volatile] void *
+                and vice versa; otherwise, targets must be the same.
+                Meanwhile, the lhs target must have all the qualifiers of the rhs.  */
+             if (TYPE_MAIN_VARIANT (ttl) == void_type_node
+                 || TYPE_MAIN_VARIANT (ttr) == void_type_node
+                 || comp_target_types (memb_type, rhstype))
+               {
+                 /* Const and volatile mean something different for function types,
+                    so the usual warnings are not appropriate.  */
+                 if (TREE_CODE (ttr) != FUNCTION_TYPE
+                     || TREE_CODE (ttl) != FUNCTION_TYPE)
+                   {
+                     if (! TYPE_READONLY (ttl) && TYPE_READONLY (ttr))
+                       warn_for_assignment ("%s discards `const' from pointer target type",
+                                            get_spelling (errtype), funname, parmnum);
+                     if (! TYPE_VOLATILE (ttl) && TYPE_VOLATILE (ttr))
+                       warn_for_assignment ("%s discards `volatile' from pointer target type",
+                                            get_spelling (errtype), funname, parmnum);
+                   }
+                 else
+                   {
+                     /* Because const and volatile on functions are restrictions
+                        that say the function will not do certain things,
+                        it is okay to use a const or volatile function
+                        where an ordinary one is wanted, but not vice-versa.  */
+                     if (TYPE_READONLY (ttl) && ! TYPE_READONLY (ttr))
+                       warn_for_assignment ("%s makes `const *' function pointer from non-const",
+                                            get_spelling (errtype), funname, parmnum);
+                     if (TYPE_VOLATILE (ttl) && ! TYPE_VOLATILE (ttr))
+                       warn_for_assignment ("%s makes `volatile *' function pointer from non-volatile",
+                                            get_spelling (errtype), funname, parmnum);
+                   }
+                 if (pedantic
+                     && !(fundecl != 0 && DECL_IN_SYSTEM_HEADER (fundecl)))
+                   pedwarn ("ANSI C prohibits argument conversion to union type");
+                 return build1 (NOP_EXPR, type, rhs);
+               }
+           }
        }
     }
   /* Conversions among pointers */
@@ -4074,17 +3870,17 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
       if (TYPE_MAIN_VARIANT (ttl) == void_type_node
          || TYPE_MAIN_VARIANT (ttr) == void_type_node
          || comp_target_types (type, rhstype)
-         || (!pedantic   /* Unless pedantic, mix signed and unsigned.  */
-             && TREE_CODE (ttl) == INTEGER_TYPE
-             && TREE_CODE (ttr) == INTEGER_TYPE
-             && TYPE_PRECISION (ttl) == TYPE_PRECISION (ttr)))
+         || (unsigned_type (TYPE_MAIN_VARIANT (ttl))
+             == unsigned_type (TYPE_MAIN_VARIANT (ttr))))
        {
          if (pedantic
              && ((TYPE_MAIN_VARIANT (ttl) == void_type_node
                   && TREE_CODE (ttr) == FUNCTION_TYPE)
                  ||
                  (TYPE_MAIN_VARIANT (ttr) == void_type_node
-                  && !integer_zerop (rhs)
+                  /* Check TREE_CODE to catch cases like (void *) (char *) 0
+                     which are not ANSI null ptr constants.  */
+                  && (!integer_zerop (rhs) || TREE_CODE (rhs) == NOP_EXPR)
                   && TREE_CODE (ttl) == FUNCTION_TYPE)))
            warn_for_assignment ("ANSI forbids %s between function pointer and `void *'",
                                 get_spelling (errtype), funname, parmnum);
@@ -4096,9 +3892,19 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
              if (! TYPE_READONLY (ttl) && TYPE_READONLY (ttr))
                warn_for_assignment ("%s discards `const' from pointer target type",
                                     get_spelling (errtype), funname, parmnum);
-             if (! TYPE_VOLATILE (ttl) && TYPE_VOLATILE (ttr))
+             else if (! TYPE_VOLATILE (ttl) && TYPE_VOLATILE (ttr))
                warn_for_assignment ("%s discards `volatile' from pointer target type",
                                     get_spelling (errtype), funname, parmnum);
+             /* If this is not a case of ignoring a mismatch in signedness,
+                no warning.  */
+             else if (TYPE_MAIN_VARIANT (ttl) == void_type_node
+                      || TYPE_MAIN_VARIANT (ttr) == void_type_node
+                      || comp_target_types (type, rhstype))
+               ;
+             /* If there is a mismatch, do warn.  */
+             else if (pedantic)
+               warn_for_assignment ("pointer targets in %s differ in signedness",
+                                    get_spelling (errtype), funname, parmnum);
            }
          else
            {
@@ -4114,10 +3920,6 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
                                     get_spelling (errtype), funname, parmnum);
            }
        }
-      else if (unsigned_type (TYPE_MAIN_VARIANT (ttl))
-              == unsigned_type (TYPE_MAIN_VARIANT (ttr)))
-       warn_for_assignment ("pointer targets in %s differ in signedness",
-                            get_spelling (errtype), funname, parmnum);
       else
        warn_for_assignment ("%s from incompatible pointer type",
                             get_spelling (errtype), funname, parmnum);
@@ -4126,8 +3928,14 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
   else if (codel == POINTER_TYPE && coder == INTEGER_TYPE)
     {
       /* An explicit constant 0 can convert to a pointer,
-        but not a 0 that results from casting or folding.  */
-      if (! (TREE_CODE (rhs) == INTEGER_CST && integer_zerop (rhs)))
+        or one that results from arithmetic, even including
+        a cast to integer type.  */
+      if (! (TREE_CODE (rhs) == INTEGER_CST && integer_zerop (rhs))
+         &&
+         ! (TREE_CODE (rhs) == NOP_EXPR
+            && TREE_CODE (TREE_TYPE (rhs)) == INTEGER_TYPE
+            && TREE_CODE (TREE_OPERAND (rhs, 0)) == INTEGER_CST
+            && integer_zerop (TREE_OPERAND (rhs, 0))))
        {
          warn_for_assignment ("%s makes pointer from integer without a cast",
                               get_spelling (errtype), funname, parmnum);
@@ -4145,8 +3953,16 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
   if (!errtype)
     {
       if (funname)
-       error ("incompatible type for argument %d of `%s'",
-              parmnum, IDENTIFIER_POINTER (funname));
+       {
+         tree selector = maybe_building_objc_message_expr ();
+         if (selector && parmnum > 2)
+           error ("incompatible type for argument %d of `%s'",
+                  parmnum - 2, IDENTIFIER_POINTER (selector));
+         else
+           error ("incompatible type for argument %d of `%s'",
+                  parmnum, IDENTIFIER_POINTER (funname));
+       }
       else
        error ("incompatible type for argument %d of indirect function call",
               parmnum);
@@ -4217,11 +4033,16 @@ initializer_constant_valid_p (value, endtype)
   switch (TREE_CODE (value))
     {
     case CONSTRUCTOR:
+      if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE
+         && TREE_CONSTANT (value))
+       return initializer_constant_valid_p (TREE_VALUE (CONSTRUCTOR_ELTS (value)));
+       
       return TREE_STATIC (value) ? null_pointer_node : 0;
 
     case INTEGER_CST:
     case REAL_CST:
     case STRING_CST:
+    case COMPLEX_CST:
       return null_pointer_node;
 
     case ADDR_EXPR:
@@ -4308,6 +4129,32 @@ initializer_constant_valid_p (value, endtype)
 
   return 0;
 }
+
+/* If VALUE is a compound expr all of whose expressions are constant, then
+   return its value.  Otherwise, return error_mark_node.
+
+   This is for handling COMPOUND_EXPRs as initializer elements
+   which is allowed with a warning when -pedantic is specified.  */
+
+static tree
+valid_compound_expr_initializer (value, endtype)
+     tree value;
+     tree endtype;
+{
+  if (TREE_CODE (value) == COMPOUND_EXPR)
+    {
+      if (valid_compound_expr_initializer (TREE_OPERAND (value, 0), endtype)
+         == error_mark_node)
+       return error_mark_node;
+      return valid_compound_expr_initializer (TREE_OPERAND (value, 1),
+                                             endtype);
+    }
+  else if (! TREE_CONSTANT (value)
+          && ! initializer_constant_valid_p (value, endtype))
+    return error_mark_node;
+  else
+    return value;
+}
 \f
 /* Perform appropriate conversions on the initial value of a variable,
    store it in the declaration DECL,
@@ -4328,9 +4175,8 @@ store_init_value (decl, init)
 
   /* Digest the specified initializer into an expression.  */
 
-  value = digest_init (type, init, NULL_PTR, TREE_STATIC (decl),
-                      TREE_STATIC (decl) || pedantic, 
-                      IDENTIFIER_POINTER (DECL_NAME (decl)));
+  value = digest_init (type, init, TREE_STATIC (decl),
+                      TREE_STATIC (decl) || pedantic);
 
   /* Store the expression if valid; else report error.  */
 
@@ -4363,10 +4209,11 @@ store_init_value (decl, init)
     }
 #endif
 
+  DECL_INITIAL (decl) = value;
+
   /* ANSI wants warnings about out-of-range constant initializers.  */
+  STRIP_TYPE_NOPS (value);
   constant_expression_warning (value);
-
-  DECL_INITIAL (decl) = value;
 }
 \f
 /* Methods for storing and printing names for error messages.  */
@@ -4444,9 +4291,12 @@ push_string (string)
 /* Push a member name on the stack.  Printed as '.' STRING.  */
 
 static void
-push_member_name (string)
-     char *string;
+push_member_name (decl)
+     tree decl;
+     
 {
+  char *string
+    = DECL_NAME (decl) ? IDENTIFIER_POINTER (DECL_NAME (decl)) : "<anonymous>";
   PUSH_SPELLING (SPELLING_MEMBER, string, u.s);
 }
 
@@ -4553,7 +4403,7 @@ error_init (format, local, ofwhat)
   char *buffer;
 
   if (ofwhat == 0)
-    ofwhat = print_spelling (alloca (spelling_length () + 1));
+    ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
   buffer = (char *) alloca (strlen (local) + strlen (ofwhat) + 2);
 
   if (*ofwhat)
@@ -4579,7 +4429,7 @@ pedwarn_init (format, local, ofwhat)
   char *buffer;
 
   if (ofwhat == 0)
-    ofwhat = print_spelling (alloca (spelling_length () + 1));
+    ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
   buffer = (char *) alloca (strlen (local) + strlen (ofwhat) + 2);
 
   if (*ofwhat)
@@ -4589,48 +4439,48 @@ pedwarn_init (format, local, ofwhat)
 
   pedwarn (format, buffer);
 }
+
+/* Issue a warning for a bad initializer component.
+   FORMAT describes the message.  OFWHAT is the name for the component.
+   LOCAL is a format string for formatting the insertion of the name
+   into the message.
+
+   If OFWHAT is null, the component name is stored on the spelling stack.
+   If the component name is a null string, then LOCAL is omitted entirely.  */
+
+static void
+warning_init (format, local, ofwhat)
+     char *format, *local, *ofwhat;
+{
+  char *buffer;
+
+  if (ofwhat == 0)
+    ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
+  buffer = (char *) alloca (strlen (local) + strlen (ofwhat) + 2);
+
+  if (*ofwhat)
+    sprintf (buffer, local, ofwhat);
+  else
+    buffer[0] = 0;
+
+  warning (format, buffer);
+}
 \f
 /* Digest the parser output INIT as an initializer for type TYPE.
    Return a C expression of type TYPE to represent the initial value.
 
-   If TAIL is nonzero, it points to a variable holding a list of elements
-   of which INIT is the first.  We update the list stored there by
-   removing from the head all the elements that we use.
-   Normally this is only one; we use more than one element only if
-   TYPE is an aggregate and INIT is not a constructor.
-
    The arguments REQUIRE_CONSTANT and CONSTRUCTOR_CONSTANT request errors
    if non-constant initializers or elements are seen.  CONSTRUCTOR_CONSTANT
-   applies only to elements of constructors.
+   applies only to elements of constructors.  */
 
-   If OFWHAT is nonnull, it specifies what we are initializing, for error
-   messages.   Examples: variable name, variable.member, array[44].
-   If OFWHAT is null, the component name is stored on the spelling stack.  */
-
-tree
-digest_init (type, init, tail, require_constant, constructor_constant, ofwhat)
-     tree type, init, *tail;
+static tree
+digest_init (type, init, require_constant, constructor_constant)
+     tree type, init;
      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;
 
-  /* By default, assume we use one element from a list.
-     We correct this later in the sole case where it is not true.  */
-
-  if (tail)
-    {
-      old_tail_contents = *tail;
-      *tail = TREE_CHAIN (*tail);
-    }
-
   if (init == error_mark_node)
     return init;
 
@@ -4640,16 +4490,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.  */
 
@@ -4661,52 +4501,56 @@ digest_init (type, init, tail, require_constant, constructor_constant, ofwhat)
           || typ1 == unsigned_char_type_node
           || typ1 == unsigned_wchar_type_node
           || typ1 == signed_wchar_type_node)
-         && ((inside_init && TREE_CODE (inside_init) == STRING_CST)
-             || (element && TREE_CODE (element) == STRING_CST)))
+         && ((inside_init && TREE_CODE (inside_init) == STRING_CST)))
        {
-         tree string = element ? element : inside_init;
+         if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
+                        TYPE_MAIN_VARIANT (type)))
+           return inside_init;
 
-         if ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (string)))
+         if ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init)))
               != char_type_node)
              && 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)))
+         if ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init)))
               == char_type_node)
              && 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;
            }
 
-         TREE_TYPE (string) = type;
+         TREE_TYPE (inside_init) = type;
          if (TYPE_DOMAIN (type) != 0
              && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
            {
              register int size = TREE_INT_CST_LOW (TYPE_SIZE (type));
              size = (size + BITS_PER_UNIT - 1) / BITS_PER_UNIT;
-             /* Subtract 1 because it's ok to ignore the terminating null char
+             /* Subtract 1 (or sizeof (wchar_t))
+                because it's ok to ignore the terminating null char
                 that is counted in the length of the constant.  */
-             if (size < TREE_STRING_LENGTH (string) - 1)
+             if (size < TREE_STRING_LENGTH (inside_init)
+                 - (TYPE_PRECISION (typ1) != TYPE_PRECISION (char_type_node)
+                    ? TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT
+                    : 1))
                pedwarn_init (
                  "initializer-string for array of chars%s is too long",
-                 " `%s'", ofwhat);
+                 " `%s'", NULL);
            }
-         return string;
+         return inside_init;
        }
     }
 
-  /* 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))
-          == TYPE_MAIN_VARIANT (type))
+      && (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
+                    TYPE_MAIN_VARIANT (type))
          || (code == ARRAY_TYPE
              && comptypes (TREE_TYPE (inside_init), type))
          || (code == POINTER_TYPE
@@ -4719,10 +4563,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;
        }
 
@@ -4730,155 +4575,64 @@ digest_init (type, init, tail, require_constant, constructor_constant, ofwhat)
          && TREE_CODE (inside_init) == VAR_DECL)
        inside_init = decl_constant_value (inside_init);
 
-      if (require_constant && ! TREE_CONSTANT (inside_init))
+      /* Compound expressions can only occur here if -pedantic or
+        -pedantic-errors is specified.  In the later case, we always want
+        an error.  In the former case, we simply want a warning.  */
+      if (require_constant && pedantic
+         && TREE_CODE (inside_init) == COMPOUND_EXPR)
+       {
+         inside_init
+           = valid_compound_expr_initializer (inside_init,
+                                              TREE_TYPE (inside_init));
+         if (inside_init == error_mark_node)
+           error_init ("initializer element%s is not constant",
+                       " for `%s'", NULL);
+         else
+           pedwarn_init ("initializer element%s is not constant",
+                         " for `%s'", NULL);
+         if (flag_pedantic_errors)
+           inside_init = error_mark_node;
+       }
+      else 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;
        }
 
       return inside_init;
     }
 
-  if (element && (TREE_TYPE (element) == type
-                 || (code == ARRAY_TYPE && TREE_TYPE (element)
-                     && comptypes (TREE_TYPE (element), type))))
-    {
-      if (code == ARRAY_TYPE)
-       {
-         error_init ("array%s initialized from non-constant array expression",
-                     " `%s'", ofwhat);
-         return error_mark_node;
-       }
-      if (pedantic && (code == RECORD_TYPE || code == UNION_TYPE))
-       pedwarn ("single-expression nonscalar initializer has braces");
-      if (optimize && TREE_READONLY (element) && TREE_CODE (element) == VAR_DECL)
-       element = decl_constant_value (element);
-
-      if (require_constant && ! TREE_CONSTANT (element))
-       {
-         error_init ("initializer element%s is not constant",
-                     " for `%s'", ofwhat);
-         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);
-         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;
-         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 == 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);
-         inside_init
-           = convert_for_assignment (type,
-                                     default_conversion (raw_constructor
-                                                         ? inside_init
-                                                         : init),
-                                     &initialization_message,
-                                     NULL_TREE, NULL_TREE, 0);
-       });
+      /* 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, init, "initialization",
+                                 NULL_TREE, NULL_TREE, 0);
 
       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;
        }
 
@@ -4890,512 +4644,1451 @@ 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)
+  /* Traditionally, you can write  struct foo x = 0;
+     and it initializes the first element of x to 0.  */
+  if (flag_traditional)
     {
-      if (raw_constructor)
-       return process_init_constructor (type, inside_init,
-                                        NULL_PTR, constructor_constant,
-                                        constructor_constant, ofwhat);
-      else if (tail != 0)
+      tree top = 0, prev = 0;
+      while (TREE_CODE (type) == RECORD_TYPE
+            || TREE_CODE (type) == ARRAY_TYPE
+            || TREE_CODE (type) == QUAL_UNION_TYPE
+            || TREE_CODE (type) == UNION_TYPE)
        {
-         *tail = old_tail_contents;
-         return process_init_constructor (type, NULL_TREE, tail,
-                                          constructor_constant,
-                                          constructor_constant, ofwhat);
+         tree temp = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE);
+         if (prev == 0)
+           top = temp;
+         else
+           TREE_OPERAND (prev, 1) = build_tree_list (NULL_TREE, temp);
+         prev = temp;
+         if (TREE_CODE (type) == ARRAY_TYPE)
+           type = TREE_TYPE (type);
+         else if (TYPE_FIELDS (type))
+           type = TREE_TYPE (TYPE_FIELDS (type));
+         else
+           {
+             error_init ("invalid initializer%s", " for `%s'", NULL);
+             return error_mark_node;
+           }
        }
-      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);
+      TREE_OPERAND (prev, 1)
+       = build_tree_list (NULL_TREE,
+                          digest_init (type, init, require_constant,
+                                       constructor_constant));
+      return top;
+    }
+  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_init_element ();
+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]".  If OFWHAT is null, the description string
-   is stored on the spelling stack.  */
+/* For an ARRAY_TYPE, this is the maximum index.  */
+static tree constructor_max_index;
 
-static tree
-process_init_constructor (type, init, elts, constant_value, constant_element,
-                         ofwhat)
-     tree type, init, *elts;
-     int constant_value, constant_element;
-     char *ofwhat;
-{
-  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 ();
+/* For a RECORD_TYPE, this is the first field not yet written out.  */
+static tree constructor_unfilled_fields;
 
-  if (ofwhat)
-    push_string (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;
 
-  /* Make TAIL be the list of elements to use for the initialization,
-     no matter how the data was given to us.  */
+/* In a RECORD_TYPE, the byte index of the next consecutive field.
+   This is so we can generate gaps between fields, when appropriate.
+   This is a special INTEGER_CST node that we modify in place.  */
+static tree constructor_bit_index;
 
-  if (elts)
-    {
-      if (warn_missing_braces)
-       warning ("aggregate has a partly bracketed initializer");
-      tail = *elts;
-    }
-  else
-    tail = CONSTRUCTOR_ELTS (init);
+/* 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;
 
-  /* 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.  */
+/* 1 if so far this constructor's elements are all compile-time constants.  */
+static int constructor_constant;
 
-  if (TREE_CODE (type) == ARRAY_TYPE)
-    {
-      tree min_index, max_index, current_index, members_index;
-      tree bound_type;
-      tree one;
-      /* 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;
-
-      /* If we have array bounds, set our bounds from that.  Otherwise,
-        we have a lower bound of zero and an unknown upper bound.  Also
-        set the type of the bounds; use "int" as default.  */
-      if (TYPE_DOMAIN (type))
-       {
-         min_index = members_index = TYPE_MIN_VALUE (TYPE_DOMAIN (type));
-         max_index = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
-         bound_type = TREE_TYPE (min_index);
-       }
-      else
-       {
-         min_index = members_index = integer_zero_node;
-         max_index = 0;
-         bound_type = integer_type_node;
-       }
+/* 1 if so far this constructor's elements are all valid address constants.  */
+static int constructor_simple;
 
-      one = convert (bound_type, integer_one_node);
+/* 1 if this constructor is erroneous so far.  */
+static int constructor_erroneous;
 
-      /* Don't leave the loop based on index if the next item has an explicit
-        index value that will override it. */
+/* 1 if have called defer_addressed_constants.  */
+static int constructor_subconstants_deferred;
 
-      for (current_index = min_index; tail != 0 || end_index;
-          current_index = fold (build (PLUS_EXPR, bound_type,
-                                       current_index, one)))
-       {
-         register tree next1 = 0;
+/* 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;
 
-         /* 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;
-           }
+/* The SPELLING_DEPTH of this constructor.  */
+static int constructor_depth;
 
-         /* 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);
+/* 0 if implicitly pushing constructor levels is allowed.  */
+int constructor_no_implicit = 0; /* 0 for C; 1 for some other languages. */
 
-             if (index && (TREE_CODE (index) == NON_LVALUE_EXPR
-                           || TREE_CODE (index) == NOP_EXPR))
-               index = TREE_OPERAND (index, 0);
+/* 1 if this constructor level was entered implicitly.  */
+static int constructor_implicit;
 
-             /* 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);
-                     current_index = end_index;
-                     continue;
-                   }
-                 else
-                   {
-                     current_index = 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);
-                 current_index = index, win = 1;
-               }
+static int require_constant_value;
+static int require_constant_elements;
 
-             if (!win)
-               {
-                 /* If there was an error, end the current range.  */
-                 end_index = 0;
-                 TREE_VALUE (tail) = error_mark_node;
-               }
-           }
+/* 1 if it is ok to output this constructor as we read it.
+   0 means must accumulate a CONSTRUCTOR expression.  */
+static int constructor_incremental;
 
-         if (max_index && tree_int_cst_lt (max_index, current_index))
-           break;  /* Stop if we've indeed run out of elements. */
+/* 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;
 
-         /* 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);
-           }
+/* start_init saves the ASMSPEC arg here for really_start_incremental_init.  */
+static char *constructor_asmspec;
 
-         if (end_index != 0)
-           range_val = next1;
+/* Nonzero if this is an initializer for a top-level decl.  */
+static int constructor_top_level;
 
-         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;
+/* When we finish reading a constructor expression
+   (constructor_decl is 0), the CONSTRUCTOR goes here.  */
+static tree constructor_result;
+\f
+/* This stack has a level for each implicit or explicit level of
+   structuring in the initializer, including the outermost one.  It
+   saves the values of most of the variables above.  */
 
-         /* 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))
-           {
-             members = tree_cons (NULL_TREE, NULL_TREE, members);
-             members_index = fold (build (PLUS_EXPR, bound_type,
-                                          members_index, one));
-           }
+struct constructor_stack
+{
+  struct constructor_stack *next;
+  tree type;
+  tree fields;
+  tree index;
+  tree range_end;
+  tree max_index;
+  tree unfilled_index;
+  tree unfilled_fields;
+  tree bit_index;
+  tree elements;
+  int offset;
+  tree pending_elts;
+  int depth;
+  /* If nonzero, this value should replace the entire
+     constructor at this level.  */
+  tree replacement_value;
+  char constant;
+  char simple;
+  char implicit;
+  char incremental;
+  char erroneous;
+  char outer;
+};
 
-         {
-           tree temp;
-           tree idx;
-
-           temp = members;
-           for (idx = fold (build (MINUS_EXPR, bound_type,
-                                   members_index, one));
-                tree_int_cst_lt (current_index, idx);
-                idx = fold (build (MINUS_EXPR, bound_type, idx, one)))
-             temp = TREE_CHAIN (temp);
-           TREE_VALUE (temp) = next1;
-         }
-       }
-    }
-  if (TREE_CODE (type) == RECORD_TYPE)
-    {
-      register tree field;
-      int members_length = 0;
-      int i;
+struct constructor_stack *constructor_stack;
 
-      /* Don't leave the loop based on field just yet; see if next item
-        overrides the expected field first. */
+/* 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) { ... } ... }.  */
 
-      for (field = TYPE_FIELDS (type), i = 0; tail;
-          field = TREE_CHAIN (field), i++)
-       {
-         register tree next1;
+struct initializer_stack
+{
+  struct initializer_stack *next;
+  tree decl;
+  char *asmspec;
+  struct constructor_stack *constructor_stack;
+  tree elements;
+  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;
+};
 
-         /* If this element specifies a field, 
-            move to that field before storing it in the new list.  */
-         if (TREE_PURPOSE (tail) != 0)
-           {
-             int win = 0;
+struct initializer_stack *initializer_stack;
+\f
+/* Prepare to parse and output the initializer for variable DECL.  */
 
-             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;
-           }
+void
+start_init (decl, asmspec_tree, top_level)
+     tree decl;
+     tree asmspec_tree;
+     int top_level;
+{
+  char *locus;
+  struct initializer_stack *p
+    = (struct initializer_stack *) xmalloc (sizeof (struct initializer_stack));
+  char *asmspec = 0;
+
+  if (asmspec_tree)
+    asmspec = TREE_STRING_POINTER (asmspec_tree);
+
+  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->elements = constructor_elements;
+  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 = initializer_stack;
+  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)
+    {
+      require_constant_value = TREE_STATIC (decl);
+      require_constant_elements
+       = ((TREE_STATIC (decl) || pedantic)
+          /* For a scalar, you can always use any value to initialize,
+             even within braces.  */
+          && (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
+              || TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
+              || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE
+              || TREE_CODE (TREE_TYPE (decl)) == QUAL_UNION_TYPE));
+      locus = IDENTIFIER_POINTER (DECL_NAME (decl));
+      constructor_incremental |= TREE_STATIC (decl);
+    }
+  else
+    {
+      require_constant_value = 0;
+      require_constant_elements = 0;
+      locus = "(anonymous)";
+    }
 
-         if (field == 0)
-           break;  /* No more fields to init. */
+  constructor_stack = 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
-           {
-             next1 = error_mark_node;
-             tail = TREE_CHAIN (tail);
-           }
+  missing_braces_mentioned = 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;
+  spelling_base = 0;
+  spelling_size = 0;
+  RESTORE_SPELLING_DEPTH (0);
 
-         /* Now store NEXT1 in the list, I elements from the *end*.
-            Make the list longer if necessary.  */
-         while (i >= members_length)
-           {
-             members = tree_cons (NULL_TREE, NULL_TREE, members);
-             members_length++;
-           }
-         {
-           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;
+  if (locus)
+    push_string (locus);
+}
 
-      /* 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);
+void
+finish_init ()
+{
+  struct initializer_stack *p = initializer_stack;
 
-      /* For a union, get the initializer for 1 fld.  */
+  /* 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 ();
 
-      if (tail == 0)
-       {
-         error ("empty initializer for union");
-         tail = build_tree_list (0, 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 a field, initialize via that field.  */
-      if (TREE_PURPOSE (tail) != 0)
-       {
-         int win = 0;
+  /* 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;
+  constructor_elements = p->elements;
+  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 (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
-           {
-             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)));
-           }
-         if (!win)
-           TREE_VALUE (tail) = error_mark_node;
-       }
+   TYPE is the type to initialize, for a constructor expression.
+   For an initializer for a decl, TYPE is zero.  */
 
-      if (TREE_VALUE (tail) != 0)
+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->bit_index = constructor_bit_index;
+  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->replacement_value = 0;
+  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);
+      /* Skip any nameless bit fields atthe beginning.  */
+      while (constructor_fields != 0 && DECL_BIT_FIELD (constructor_fields)
+            && DECL_NAME (constructor_fields) == 0)
+       constructor_fields = TREE_CHAIN (constructor_fields);
+      constructor_unfilled_fields = constructor_fields;
+      constructor_bit_index = copy_node (integer_zero_node);
+    }
+  else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+    {
+      constructor_range_end = 0;
+      if (TYPE_DOMAIN (constructor_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;
+         constructor_max_index
+           = TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type));
+         constructor_index
+           = copy_node (TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type)));
        }
       else
-       {
-         next1 = error_mark_node;
-         tail = TREE_CHAIN (tail);
-       }
-
-      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;
-      members = tree_cons (field, next1, members);
+       constructor_index = copy_node (integer_zero_node);
+      constructor_unfilled_index = copy_node (constructor_index);
     }
-
-  /* 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)
+  else
     {
-      if (TREE_CODE (type) == UNION_TYPE)
+      /* Handle the case of int x = {5}; */
+      constructor_fields = constructor_type;
+      constructor_unfilled_fields = constructor_type;
+    }
+
+  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 (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.  */
+
+void
+push_init_level (implicit)
+     int implicit;
+{
+  struct constructor_stack *p;
+
+  /* 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
+       break;
+    }
+
+  /* Structure elements may require alignment.  Do this now
+     if necessary for the subaggregate.  */
+  if (constructor_incremental && TREE_CODE (constructor_type) == RECORD_TYPE
+      && constructor_fields)
+    {
+      /* Advance to offset of this element.  */
+      if (! tree_int_cst_equal (constructor_bit_index,
+                               DECL_FIELD_BITPOS (constructor_fields)))
        {
-         pedwarn_init ("excess elements in union initializer%s",
-                       " after `%s'", NULL_PTR);
+         int next = (TREE_INT_CST_LOW
+                     (DECL_FIELD_BITPOS (constructor_fields))
+                     / BITS_PER_UNIT);
+         int here = (TREE_INT_CST_LOW (constructor_bit_index)
+                     / BITS_PER_UNIT);
+
+         assemble_zeros (next - here);
        }
+    }
+
+  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->bit_index = constructor_bit_index;
+  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->replacement_value = 0;
+  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;
+
+  /* Don't die if an entire brace-pair level is superfluous
+     in the containing level.  */
+  if (constructor_type == 0)
+    ;
+  else if (TREE_CODE (constructor_type) == RECORD_TYPE
+          || TREE_CODE (constructor_type) == UNION_TYPE)
+    {
+      /* Don't die if there are extra init elts at the end.  */
+      if (constructor_fields == 0)
+       constructor_type = 0;
       else
        {
-         pedwarn_init ("excess elements in aggregate initializer%s",
-                       " after `%s'", NULL_PTR);
+         constructor_type = TREE_TYPE (constructor_fields);
+         push_member_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));
+    }
 
-  /* 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.  */
+  if (constructor_type == 0)
+    {
+      error_init ("extra brace group at end of initializer%s",
+                 " for `%s'", NULL);
+      constructor_fields = 0;
+      constructor_unfilled_fields = 0;
+      return;
+    }
 
-  RESTORE_SPELLING_DEPTH (depth);
+  /* Turn off constructor_incremental if type is a struct with bitfields.  */
+  check_init_type_bitfields (constructor_type);
 
-  if (erroneous)
-    return error_mark_node;
+  if (implicit && warn_missing_braces && !missing_braces_mentioned)
+    {
+      missing_braces_mentioned = 1;
+      warning_init ("missing braces around initializer%s", " for `%s'", NULL);
+    }
 
-  result = build (CONSTRUCTOR, type, NULL_TREE, nreverse (members));
-  if (allconstant) TREE_CONSTANT (result) = 1;
-  if (allconstant && allsimple) TREE_STATIC (result) = 1;
-  return result;
+  if (TREE_CODE (constructor_type) == RECORD_TYPE
+          || TREE_CODE (constructor_type) == UNION_TYPE)
+    {
+      constructor_fields = TYPE_FIELDS (constructor_type);
+      /* Skip any nameless bit fields atthe beginning.  */
+      while (constructor_fields != 0 && DECL_BIT_FIELD (constructor_fields)
+            && DECL_NAME (constructor_fields) == 0)
+       constructor_fields = TREE_CHAIN (constructor_fields);
+      constructor_unfilled_fields = constructor_fields;
+      constructor_bit_index = copy_node (integer_zero_node);
+    }
+  else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+    {
+      constructor_range_end = 0;
+      if (TYPE_DOMAIN (constructor_type))
+       {
+         constructor_max_index
+           = TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type));
+         constructor_index
+           = copy_node (TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type)));
+       }
+      else
+       constructor_index = copy_node (integer_zero_node);
+      constructor_unfilled_index = copy_node (constructor_index);
+    }
+  else
+    {
+      warning_init ("braces around scalar initializer%s", " for `%s'", NULL);
+      constructor_fields = constructor_type;
+      constructor_unfilled_fields = constructor_type;
+    }
+}
+
+/* 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)
+           /* This catches cases like `int foo : 8;'.  */
+           || DECL_MODE (tail) != TYPE_MODE (TREE_TYPE (tail)))
+         {
+           constructor_incremental = 0;
+           break;
+         }
+    }
+}
+
+/* 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)
+    {
+      /* 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));
+    }
+
+  p = constructor_stack;
+
+  if (constructor_type != 0)
+    size = int_size_in_bytes (constructor_type);
+
+  /* Now output all pending elements.  */
+  output_pending_init_elements (1);
+
+#if 0 /* c-parse.in warns about {}.  */
+  /* In ANSI, each brace level must have at least one element.  */
+  if (! implicit && pedantic
+      && (TREE_CODE (constructor_type) == ARRAY_TYPE
+         ? integer_zerop (constructor_unfilled_index)
+         : constructor_unfilled_fields == TYPE_FIELDS (constructor_type)))
+    pedwarn_init ("empty braces in initializer%s", " for `%s'", NULL);
+#endif
+
+  /* Pad out the end of the structure.  */
+  
+  if (p->replacement_value)
+    {
+      /* If this closes a superfluous brace pair,
+        just pass out the element between them.  */
+      constructor = p->replacement_value;
+      /* If this is the top level thing within the initializer,
+        and it's for a variable, then since we already called
+        assemble_variable, we must output the value now.  */
+      if (p->next == 0 && constructor_decl != 0
+         && constructor_incremental)
+       {
+         constructor = digest_init (constructor_type, constructor,
+                                    0, 0);
+
+         /* If initializing an array of unknown size,
+            determine the size now.  */
+         if (TREE_CODE (constructor_type) == ARRAY_TYPE
+             && TYPE_DOMAIN (constructor_type) == 0)
+           {
+             int failure;
+             int momentary_p;
+
+             push_obstacks_nochange ();
+             if (TREE_PERMANENT (constructor_type))
+               end_temporary_allocation ();
+
+             momentary_p = suspend_momentary ();
+
+             /* We shouldn't have an incomplete array type within
+                some other type.  */
+             if (constructor_stack->next)
+               abort ();
+
+             failure
+               = complete_array_type (constructor_type,
+                                      constructor, 0);
+             if (failure)
+               abort ();
+
+             size = int_size_in_bytes (constructor_type);
+             resume_momentary (momentary_p);
+             pop_obstacks ();
+           }
+
+         output_constant (constructor, size);
+       }
+    }
+  else if (constructor_type == 0)
+    ;
+  else if (TREE_CODE (constructor_type) != RECORD_TYPE
+          && TREE_CODE (constructor_type) != UNION_TYPE
+          && TREE_CODE (constructor_type) != ARRAY_TYPE
+          && ! constructor_incremental)
+    {
+      /* A nonincremental scalar initializer--just return
+        the element, after verifying there is just one.  */
+      if (constructor_elements == 0)
+       {
+         error_init ("empty scalar initializer%s",
+                     " for `%s'", NULL);
+         constructor = error_mark_node;
+       }
+      else if (TREE_CHAIN (constructor_elements) != 0)
+       {
+         error_init ("extra elements in scalar initializer%s",
+                     " for `%s'", NULL);
+         constructor = TREE_VALUE (constructor_elements);
+       }
+      else
+       constructor = TREE_VALUE (constructor_elements);
+    }
+  else if (! constructor_incremental)
+    {
+      if (constructor_erroneous)
+       constructor = error_mark_node;
+      else
+       {
+         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 (TREE_CODE (constructor_type) == RECORD_TYPE
+         || TREE_CODE (constructor_type) == UNION_TYPE)
+       {
+         /* Find the offset of the end of that field.  */
+         filled = size_binop (CEIL_DIV_EXPR,
+                              constructor_bit_index,
+                              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)
+           {
+             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 (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 ();
+           }
+
+         filled = size_binop (MULT_EXPR, constructor_unfilled_index,
+                              size_in_bytes (TREE_TYPE (constructor_type)));
+       }
+      else
+       filled = 0;
+
+      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_bit_index = p->bit_index;
+  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;
+{
+  while ((TREE_CODE (first) == NOP_EXPR
+         || TREE_CODE (first) == CONVERT_EXPR
+         || TREE_CODE (first) == NON_LVALUE_EXPR)
+        && (TYPE_MODE (TREE_TYPE (first))
+            == TYPE_MODE (TREE_TYPE (TREE_OPERAND (first, 0)))))
+    (first) = TREE_OPERAND (first, 0);
+  if (last)
+    while ((TREE_CODE (last) == NOP_EXPR
+           || TREE_CODE (last) == CONVERT_EXPR
+           || TREE_CODE (last) == NON_LVALUE_EXPR)
+          && (TYPE_MODE (TREE_TYPE (last))
+              == TYPE_MODE (TREE_TYPE (TREE_OPERAND (last, 0)))))
+      (last) = TREE_OPERAND (last, 0);
+
+  if (TREE_CODE (first) != INTEGER_CST)
+    error_init ("nonconstant array index in initializer%s", " for `%s'", NULL);
+  else if (last != 0 && TREE_CODE (last) != INTEGER_CST)
+    error_init ("nonconstant array index in initializer%s", " for `%s'", NULL);
+  else 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
+       {
+         if (pedantic)
+           pedwarn ("ANSI C forbids specifying element to initialize");
+         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;
+      if (pedantic)
+       pedwarn ("ANSI C forbids specifying structure member to initialize");
+    }
+}
+\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.)  */
+
+static void
+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
+              && TREE_CODE (type) == ARRAY_TYPE
+              && TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE)
+         && !comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (value)),
+                        TYPE_MAIN_VARIANT (type))))
+    value = default_conversion (value);
+
+  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 (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))
+           {
+             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 (tail != 0)
+           {
+             error_init ("duplicate initializer%s", " for `%s'", NULL);
+             duplicate = 1;
+           }
+       }
+    }
+
+  /* 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)
+       /* The copy_node is needed in case field is actually
+          constructor_index, which is modified in place.  */
+       constructor_pending_elts
+         = tree_cons (copy_node (field),
+                      digest_init (type, value, 0, 0),
+                      constructor_pending_elts);
+    }
+  else if (TREE_CODE (constructor_type) == RECORD_TYPE
+          && 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)
+       constructor_pending_elts
+         = tree_cons (field,
+                      digest_init (type, value, 0, 0),
+                      constructor_pending_elts);
+    }
+  else
+    {
+      /* Otherwise, output this element either to
+        constructor_elements or to the assembler file.  */
+
+      if (!duplicate)
+       {
+         if (! constructor_incremental)
+           {
+             if (field && TREE_CODE (field) == INTEGER_CST)
+               field = copy_node (field);
+             constructor_elements
+               = tree_cons (field, digest_init (type, value, 0, 0),
+                            constructor_elements);
+           }
+         else
+           {
+             /* Structure elements may require alignment.
+                Do this, if necessary.  */
+             if (TREE_CODE (constructor_type) == RECORD_TYPE)
+               {
+                 /* Advance to offset of this element.  */
+                 if (! tree_int_cst_equal (constructor_bit_index,
+                                           DECL_FIELD_BITPOS (constructor_fields)))
+                   {
+                     int next = (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field))
+                                 / BITS_PER_UNIT);
+                     int here = (TREE_INT_CST_LOW (constructor_bit_index)
+                                 / BITS_PER_UNIT);
+
+                     assemble_zeros (next - here);
+                   }
+               }
+             output_constant (digest_init (type, value, 0, 0),
+                              int_size_in_bytes (type));
+
+             /* For a record or union,
+                keep track of end position of last field.  */
+             if (TREE_CODE (constructor_type) == RECORD_TYPE
+                 || TREE_CODE (constructor_type) == UNION_TYPE)
+               {
+                 tree temp = size_binop (PLUS_EXPR,
+                                         DECL_FIELD_BITPOS (constructor_fields),
+                                         DECL_SIZE (constructor_fields));
+                 TREE_INT_CST_LOW (constructor_bit_index)
+                   = TREE_INT_CST_LOW (temp);
+                 TREE_INT_CST_HIGH (constructor_bit_index)
+                   = TREE_INT_CST_HIGH (temp);
+               }
+           }
+       }
+
+      /* Advance the variable that indicates sequential elements output.  */
+      if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+       {
+         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);
+    }
+}
+
+/* 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))
+           {
+             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;
+           }
+         else if (constructor_unfilled_fields == 0
+                  || 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_CODE (constructor_type) == RECORD_TYPE
+         || TREE_CODE (constructor_type) == UNION_TYPE)
+       {
+         /* 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 if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+       {
+         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 (filled)
+       {
+         int nextpos = TREE_INT_CST_LOW (nextpos_tree);
+
+         assemble_zeros (nextpos - TREE_INT_CST_LOW (filled));
+       }
+    }
+  else
+    {
+      /* If it's not incremental, just skip over the gap,
+        so that after jumping to retry we will output the next
+        successive element.  */
+      if (TREE_CODE (constructor_type) == RECORD_TYPE
+         || TREE_CODE (constructor_type) == UNION_TYPE)
+       constructor_unfilled_fields = next;
+      else if (TREE_CODE (constructor_type) == ARRAY_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);
+       }
+    }
+
+  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;
+{
+  tree orig_value = value;
+  int string_flag = value != 0 && TREE_CODE (value) == STRING_CST;
+
+  /* Handle superfluous braces around string cst as in
+     char x[] = {"foo"}; */
+  if (string_flag
+      && TREE_CODE (constructor_type) == ARRAY_TYPE
+      && TREE_CODE (TREE_TYPE (constructor_type)) == INTEGER_TYPE
+      && integer_zerop (constructor_unfilled_index))
+    {
+      constructor_stack->replacement_value = value;
+      return;
+    }
+
+  if (constructor_stack->replacement_value != 0)
+    {
+      error_init ("excess elements in struct initializer%s",
+                 " after `%s'", NULL_PTR);
+      return;
+    }
+
+  /* Ignore elements of a brace group if it is entirely superfluous
+     and has already been diagnosed.  */
+  if (constructor_type == 0)
+    return;
+
+  /* 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
+       break;
+    }
+
+  while (1)
+    {
+      if (TREE_CODE (constructor_type) == RECORD_TYPE)
+       {
+         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);
+
+         /* Accept a string constant to initialize a subarray.  */
+         if (value != 0
+             && fieldcode == ARRAY_TYPE
+             && TREE_CODE (TREE_TYPE (fieldtype)) == INTEGER_TYPE
+             && string_flag)
+           value = orig_value;
+         /* Otherwise, if we have come to a subaggregate,
+            and we don't have an element of its type, push into it.  */
+         else if (value != 0 && !constructor_no_implicit
+                  && 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 (constructor_fields);
+             output_init_element (value, fieldtype, constructor_fields, 1);
+             RESTORE_SPELLING_DEPTH (constructor_depth);
+           }
+         else
+           /* Do the bookkeeping for an element that was
+              directly output as a constructor.  */
+           {
+             /* For a record, keep track of end position of last field.  */
+             tree temp = size_binop (PLUS_EXPR,
+                                     DECL_FIELD_BITPOS (constructor_fields),
+                                     DECL_SIZE (constructor_fields));
+             TREE_INT_CST_LOW (constructor_bit_index)
+               = TREE_INT_CST_LOW (temp);
+             TREE_INT_CST_HIGH (constructor_bit_index)
+               = TREE_INT_CST_HIGH (temp);
+
+             constructor_unfilled_fields = TREE_CHAIN (constructor_fields);
+           }
+
+         constructor_fields = TREE_CHAIN (constructor_fields);
+         /* Skip any nameless bit fields atthe beginning.  */
+         while (constructor_fields != 0 && DECL_BIT_FIELD (constructor_fields)
+                && DECL_NAME (constructor_fields) == 0)
+           constructor_fields = TREE_CHAIN (constructor_fields);
+         break;
+       }
+      if (TREE_CODE (constructor_type) == UNION_TYPE)
+       {
+         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);
+
+         /* Accept a string constant to initialize a subarray.  */
+         if (value != 0
+             && fieldcode == ARRAY_TYPE
+             && TREE_CODE (TREE_TYPE (fieldtype)) == INTEGER_TYPE
+             && string_flag)
+           value = orig_value;
+         /* Otherwise, if we have come to a subaggregate,
+            and we don't have an element of its type, push into it.  */
+         else if (value != 0 && !constructor_no_implicit
+                  && 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 (constructor_fields);
+             output_init_element (value, fieldtype, constructor_fields, 1);
+             RESTORE_SPELLING_DEPTH (constructor_depth);
+           }
+         else
+           /* Do the bookkeeping for an element that was
+              directly output as a constructor.  */
+           {
+             TREE_INT_CST_LOW (constructor_bit_index)
+               = TREE_INT_CST_LOW (DECL_SIZE (constructor_fields));
+             TREE_INT_CST_HIGH (constructor_bit_index)
+               = TREE_INT_CST_HIGH (DECL_SIZE (constructor_fields));
+
+             constructor_unfilled_fields = TREE_CHAIN (constructor_fields);
+           }
+
+         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);
+
+         /* Accept a string constant to initialize a subarray.  */
+         if (value != 0
+             && eltcode == ARRAY_TYPE
+             && TREE_CODE (TREE_TYPE (elttype)) == INTEGER_TYPE
+             && string_flag)
+           value = orig_value;
+         /* Otherwise, if we have come to a subaggregate,
+            and we don't have an element of its type, push into it.  */
+         else if (value != 0 && !constructor_no_implicit
+                  && 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;
+           }
+
+         /* Now output the actual element.
+            Ordinarily, output once.
+            If there is a range, repeat it till we advance past the range.  */
+         do
+           {
+             tree tem;
+
+             if (value)
+               {
+                 push_array_bounds (TREE_INT_CST_LOW (constructor_index));
+                 output_init_element (value, elttype, constructor_index, 1);
+                 RESTORE_SPELLING_DEPTH (constructor_depth);
+               }
+
+             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)));
+
+         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 the (lexically) previous elments are not now saved,
+     we can discard the storage for them.  */
+  if (constructor_incremental && constructor_pending_elts == 0 && value != 0)
+    clear_momentary ();
 }
 \f
 /* Expand an ASM statement with operands, handling output operands
@@ -5500,8 +6193,13 @@ c_expand_return (retval)
       tree t = convert_for_assignment (valtype, retval, "return",
                                       NULL_TREE, NULL_TREE, 0);
       tree res = DECL_RESULT (current_function_decl);
+
+      if (t == error_mark_node)
+       return;
+
       t = build (MODIFY_EXPR, TREE_TYPE (res),
                 res, convert (TREE_TYPE (res), t));
+      TREE_SIDE_EFFECTS (t) = 1;
       expand_return (t);
       current_function_returns_value = 1;
     }