OSDN Git Service

Remove bogus patch.
[pf3gnuchains/gcc-fork.git] / gcc / c-typeck.c
index 08523b5..bc9de48 100644 (file)
@@ -1,6 +1,6 @@
 /* Build expressions with type checking for C compiler.
    Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -40,8 +40,8 @@ Boston, MA 02111-1307, USA.  */
 #include "expr.h"
 #include "toplev.h"
 #include "intl.h"
-#include "defaults.h"
 #include "ggc.h"
+#include "target.h"
 
 /* Nonzero if we've already printed a "missing braces around initializer"
    message within this initializer.  */
@@ -76,8 +76,12 @@ static void warning_init             PARAMS ((const char *));
 static tree digest_init                        PARAMS ((tree, tree, int, int));
 static void output_init_element                PARAMS ((tree, tree, tree, int));
 static void output_pending_init_elements PARAMS ((int));
+static int set_designator              PARAMS ((int));
+static void push_range_stack           PARAMS ((tree));
 static void add_pending_init           PARAMS ((tree, tree));
-static int pending_init_member         PARAMS ((tree));
+static void set_nonincremental_init    PARAMS ((void));
+static void set_nonincremental_init_from_string        PARAMS ((tree));
+static tree find_init_member           PARAMS ((tree));
 \f
 /* Do `exp = require_complete_type (exp);' to make sure exp
    does not have an incomplete type.  (That includes void types.)  */
@@ -202,7 +206,7 @@ common_type (t1, t2)
     return t1;
 
   /* Merge the attributes.  */
-  attributes = merge_machine_type_attributes (t1, t2);
+  attributes = (*target.merge_type_attributes) (t1, t2);
 
   /* Treat an enum type as the unsigned integer type of the same width.  */
 
@@ -350,6 +354,9 @@ common_type (t1, t2)
        /* If both args specify argument types, we must merge the two
           lists, argument by argument.  */
 
+       pushlevel (0);
+       declare_parm_level (1);
+
        len = list_length (p1);
        newargs = 0;
 
@@ -409,6 +416,8 @@ common_type (t1, t2)
          parm_done: ;
          }
 
+       poplevel (0, 0, 0);
+
        t1 = build_function_type (valtype, newargs);
        /* ... falls through ...  */
       }
@@ -474,12 +483,8 @@ comptypes (type1, type2)
   if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
     return 1;
 
-#ifndef COMP_TYPE_ATTRIBUTES
-#define COMP_TYPE_ATTRIBUTES(t1,t2)    1
-#endif
-
   /* 1 if no need for warning yet, 2 if warning cause has been seen.  */
-  if (! (attrval = COMP_TYPE_ATTRIBUTES (t1, t2)))
+  if (! (attrval = (*target.comp_type_attributes) (t1, t2)))
      return 0;
 
   /* 1 if no need for warning yet, 2 if warning cause has been seen.  */
@@ -643,7 +648,8 @@ type_lists_compatible_p (args1, args2)
          if (simple_type_promotes_to (TREE_VALUE (args1)) != NULL_TREE)
            return 0;
        }
-      else if (! (newval = comptypes (TREE_VALUE (args1), TREE_VALUE (args2))))
+      else if (! (newval = comptypes (TYPE_MAIN_VARIANT (TREE_VALUE (args1)), 
+                                     TYPE_MAIN_VARIANT (TREE_VALUE (args2)))))
        {
          /* Allow  wait (union {union wait *u; int *i} *)
             and  wait (union wait *)  to be compatible.  */
@@ -697,33 +703,38 @@ c_sizeof (type)
      tree type;
 {
   enum tree_code code = TREE_CODE (type);
+  tree size;
 
   if (code == FUNCTION_TYPE)
     {
       if (pedantic || warn_pointer_arith)
        pedwarn ("sizeof applied to a function type");
-      return size_one_node;
+      size = size_one_node;
     }
-  if (code == VOID_TYPE)
+  else if (code == VOID_TYPE)
     {
       if (pedantic || warn_pointer_arith)
        pedwarn ("sizeof applied to a void type");
-      return size_one_node;
+      size = size_one_node;
     }
-
-  if (code == ERROR_MARK)
-    return size_one_node;
-
-  if (!COMPLETE_TYPE_P (type))
+  else if (code == ERROR_MARK)
+    size = size_one_node;
+  else if (!COMPLETE_TYPE_P (type))
     {
       error ("sizeof applied to an incomplete type");
-      return size_zero_node;
+      size = size_zero_node;
     }
-
-  /* Convert in case a char is more than one unit.  */
-  return size_binop (CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type),
-                    size_int (TYPE_PRECISION (char_type_node)
-                              / BITS_PER_UNIT));
+  else
+    /* Convert in case a char is more than one unit.  */
+    size = size_binop (CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type),
+                      size_int (TYPE_PRECISION (char_type_node)
+                                / BITS_PER_UNIT));
+
+  /* SIZE will have an integer type with TYPE_IS_SIZETYPE set.
+     TYPE_IS_SIZETYPE means that certain things (like overflow) will
+     never happen.  However, this node should really have type
+     `size_t', which is just a typedef for an ordinary integer type.  */
+  return fold (build1 (NOP_EXPR, c_size_type_node, size));
 }
 
 tree
@@ -731,17 +742,23 @@ c_sizeof_nowarn (type)
      tree type;
 {
   enum tree_code code = TREE_CODE (type);
+  tree size;
 
   if (code == FUNCTION_TYPE || code == VOID_TYPE || code == ERROR_MARK)
-    return size_one_node;
-
-  if (!COMPLETE_TYPE_P (type))
-    return size_zero_node;
-
-  /* Convert in case a char is more than one unit.  */
-  return size_binop (CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type),
-                    size_int (TYPE_PRECISION (char_type_node)
-                              / BITS_PER_UNIT));
+    size = size_one_node;
+  else if (!COMPLETE_TYPE_P (type))
+    size = size_zero_node;
+  else
+    /* Convert in case a char is more than one unit.  */
+    size = size_binop (CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type),
+                      size_int (TYPE_PRECISION (char_type_node)
+                                / BITS_PER_UNIT));
+
+  /* SIZE will have an integer type with TYPE_IS_SIZETYPE set.
+     TYPE_IS_SIZETYPE means that certain things (like overflow) will
+     never happen.  However, this node should really have type
+     `size_t', which is just a typedef for an ordinary integer type.  */
+  return fold (build1 (NOP_EXPR, c_size_type_node, size));
 }
 
 /* Compute the size to increment a pointer by.  */
@@ -775,20 +792,23 @@ c_alignof (type)
      tree type;
 {
   enum tree_code code = TREE_CODE (type);
+  tree t;
 
   if (code == FUNCTION_TYPE)
-    return size_int (FUNCTION_BOUNDARY / BITS_PER_UNIT);
-
-  if (code == VOID_TYPE || code == ERROR_MARK)
-    return size_one_node;
-
-  if (!COMPLETE_TYPE_P (type))
+    t = size_int (FUNCTION_BOUNDARY / BITS_PER_UNIT);
+  else if (code == VOID_TYPE || code == ERROR_MARK)
+    t = size_one_node;
+  else if (code == ERROR_MARK)
+    t = size_one_node;
+  else if (!COMPLETE_TYPE_P (type))
     {
       error ("__alignof__ applied to an incomplete type");
-      return size_zero_node;
+      t = size_zero_node;
     }
+  else
+    t = size_int (TYPE_ALIGN (type) / BITS_PER_UNIT);
 
-  return size_int (TYPE_ALIGN (type) / BITS_PER_UNIT);
+  return fold (build1 (NOP_EXPR, c_size_type_node, t));
 }
 \f
 /* Implement the __alignof keyword: Return the minimum required
@@ -800,20 +820,22 @@ tree
 c_alignof_expr (expr)
      tree expr;
 {
+  tree t;
+
   if (TREE_CODE (expr) == VAR_DECL)
-    return size_int (DECL_ALIGN (expr) / BITS_PER_UNIT);
+    t = size_int (DECL_ALIGN (expr) / BITS_PER_UNIT);
  
-  if (TREE_CODE (expr) == COMPONENT_REF
-      && DECL_C_BIT_FIELD (TREE_OPERAND (expr, 1)))
+  else if (TREE_CODE (expr) == COMPONENT_REF
+          && DECL_C_BIT_FIELD (TREE_OPERAND (expr, 1)))
     {
       error ("`__alignof' applied to a bit-field");
-      return size_one_node;
+      t = size_one_node;
     }
   else if (TREE_CODE (expr) == COMPONENT_REF
       && TREE_CODE (TREE_OPERAND (expr, 1)) == FIELD_DECL)
-    return size_int (DECL_ALIGN (TREE_OPERAND (expr, 1)) / BITS_PER_UNIT);
+    t = size_int (DECL_ALIGN (TREE_OPERAND (expr, 1)) / BITS_PER_UNIT);
  
-  if (TREE_CODE (expr) == INDIRECT_REF)
+  else if (TREE_CODE (expr) == INDIRECT_REF)
     {
       tree t = TREE_OPERAND (expr, 0);
       tree best = t;
@@ -833,6 +855,8 @@ c_alignof_expr (expr)
     }
   else
     return c_alignof (TREE_TYPE (expr));
+
+  return fold (build1 (NOP_EXPR, c_size_type_node, t));
 }
 
 /* Return either DECL or its known constant value (if it has one).  */
@@ -928,14 +952,14 @@ default_conversion (exp)
   if (TREE_CODE (exp) == COMPONENT_REF
       && DECL_C_BIT_FIELD (TREE_OPERAND (exp, 1))
       /* If it's thinner than an int, promote it like a
-        C_PROMOTING_INTEGER_TYPE_P, otherwise leave it alone.  */
+        c_promoting_integer_type_p, otherwise leave it alone.  */
       && 0 > compare_tree_int (DECL_SIZE (TREE_OPERAND (exp, 1)),
                               TYPE_PRECISION (integer_type_node)))
     return convert (flag_traditional && TREE_UNSIGNED (type)
                    ? unsigned_type_node : integer_type_node,
                    exp);
 
-  if (C_PROMOTING_INTEGER_TYPE_P (type))
+  if (c_promoting_integer_type_p (type))
     {
       /* Traditionally, unsignedness is preserved in default promotions.
          Also preserve unsignedness if not really getting any wider.  */
@@ -1647,19 +1671,25 @@ convert_arguments (typelist, values, name, fundecl)
            {
              /* Optionally warn about conversions that
                 differ from the default conversions.  */
-             if (warn_conversion)
+             if (warn_conversion || warn_traditional)
                {
                  int formal_prec = TYPE_PRECISION (type);
 
                  if (INTEGRAL_TYPE_P (type)
                      && TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
                    warn_for_assignment ("%s as integer rather than floating due to prototype", (char *) 0, name, parmnum + 1);
+                 if (INTEGRAL_TYPE_P (type)
+                     && TREE_CODE (TREE_TYPE (val)) == COMPLEX_TYPE)
+                   warn_for_assignment ("%s as integer rather than complex due to prototype", (char *) 0, name, parmnum + 1);
                  else if (TREE_CODE (type) == COMPLEX_TYPE
                           && TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
                    warn_for_assignment ("%s as complex rather than floating due to prototype", (char *) 0, name, parmnum + 1);
                  else if (TREE_CODE (type) == REAL_TYPE
                           && INTEGRAL_TYPE_P (TREE_TYPE (val)))
                    warn_for_assignment ("%s as floating rather than integer due to prototype", (char *) 0, name, parmnum + 1);
+                 else if (TREE_CODE (type) == COMPLEX_TYPE
+                          && INTEGRAL_TYPE_P (TREE_TYPE (val)))
+                   warn_for_assignment ("%s as complex rather than integer due to prototype", (char *) 0, name, parmnum + 1);
                  else if (TREE_CODE (type) == REAL_TYPE
                           && TREE_CODE (TREE_TYPE (val)) == COMPLEX_TYPE)
                    warn_for_assignment ("%s as floating rather than complex due to prototype", (char *) 0, name, parmnum + 1);
@@ -1674,8 +1704,10 @@ convert_arguments (typelist, values, name, fundecl)
                      if (formal_prec == TYPE_PRECISION (float_type_node))
                        warn_for_assignment ("%s as `float' rather than `double' due to prototype", (char *) 0, name, parmnum + 1);
                    }
-                 /* Detect integer changing in width or signedness.  */
-                 else if (INTEGRAL_TYPE_P (type)
+                 /* Detect integer changing in width or signedness.
+                    These warnings are only activated with
+                    -Wconversion, not with -Wtraditional.  */
+                 else if (warn_conversion && INTEGRAL_TYPE_P (type)
                           && INTEGRAL_TYPE_P (TREE_TYPE (val)))
                    {
                      tree would_have_been = default_conversion (val);
@@ -1732,8 +1764,7 @@ convert_arguments (typelist, values, name, fundecl)
                                                fundecl, name, parmnum + 1);
              
              if (PROMOTE_PROTOTYPES
-                 && (TREE_CODE (type) == INTEGER_TYPE
-                     || TREE_CODE (type) == ENUMERAL_TYPE)
+                 && INTEGRAL_TYPE_P (type)
                  && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
                parmval = default_conversion (parmval);
            }
@@ -2790,7 +2821,7 @@ build_unary_op (code, xarg, noconvert)
 
   if (typecode == ERROR_MARK)
     return error_mark_node;
-  if (typecode == ENUMERAL_TYPE)
+  if (typecode == ENUMERAL_TYPE || typecode == BOOLEAN_TYPE)
     typecode = INTEGER_TYPE;
 
   switch (code)
@@ -2985,18 +3016,23 @@ build_unary_op (code, xarg, noconvert)
              else
                {
                  tree incremented, modify, value;
-                 arg = stabilize_reference (arg);
-                 if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
-                   value = arg;
+                 if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
+                   value = boolean_increment (code, arg);
                  else
-                   value = save_expr (arg);
-                 incremented = build (((code == PREINCREMENT_EXPR
-                                        || code == POSTINCREMENT_EXPR)
-                                       ? PLUS_EXPR : MINUS_EXPR),
-                                      argtype, value, inc);
-                 TREE_SIDE_EFFECTS (incremented) = 1;
-                 modify = build_modify_expr (arg, NOP_EXPR, incremented);
-                 value = build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value);
+                   {
+                     arg = stabilize_reference (arg);
+                     if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
+                       value = arg;
+                     else
+                       value = save_expr (arg);
+                     incremented = build (((code == PREINCREMENT_EXPR
+                                            || code == POSTINCREMENT_EXPR)
+                                           ? PLUS_EXPR : MINUS_EXPR),
+                                          argtype, value, inc);
+                     TREE_SIDE_EFFECTS (incremented) = 1;
+                     modify = build_modify_expr (arg, NOP_EXPR, incremented);
+                     value = build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value);
+                   }
                  TREE_USED (value) = 1;
                  return value;
                }
@@ -3021,7 +3057,10 @@ build_unary_op (code, xarg, noconvert)
                              || code == POSTINCREMENT_EXPR)
                             ? "increment" : "decrement"));
 
-       val = build (code, TREE_TYPE (arg), arg, inc);
+       if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
+         val = boolean_increment (code, arg);
+       else
+         val = build (code, TREE_TYPE (arg), arg, inc);
        TREE_SIDE_EFFECTS (val) = 1;
        val = convert (result_type, val);
        if (TREE_CODE (val) != code)
@@ -3517,13 +3556,15 @@ build_conditional_expr (ifexp, op1, op2)
        {
          if (pedantic && TREE_CODE (TREE_TYPE (type2)) == FUNCTION_TYPE)
            pedwarn ("ISO C forbids conditional expr between `void *' and function pointer");
-         result_type = qualify_type (type1, type2);
+         result_type = build_pointer_type (qualify_type (TREE_TYPE (type1),
+                                                         TREE_TYPE (type2)));
        }
       else if (VOID_TYPE_P (TREE_TYPE (type2)))
        {
          if (pedantic && TREE_CODE (TREE_TYPE (type1)) == FUNCTION_TYPE)
            pedwarn ("ISO C forbids conditional expr between `void *' and function pointer");
-         result_type = qualify_type (type2, type1);
+         result_type = build_pointer_type (qualify_type (TREE_TYPE (type2),
+                                                         TREE_TYPE (type1)));
        }
       else
        {
@@ -3538,10 +3579,6 @@ build_conditional_expr (ifexp, op1, op2)
       else
        {
          op2 = null_pointer_node;
-#if 0  /* The spec seems to say this is permitted.  */
-         if (pedantic && TREE_CODE (type1) == FUNCTION_TYPE)
-           pedwarn ("ANSI C forbids conditional expr between 0 and function pointer");
-#endif
        }
       result_type = type1;
     }
@@ -3552,10 +3589,6 @@ build_conditional_expr (ifexp, op1, op2)
       else
        {
          op1 = null_pointer_node;
-#if 0  /* The spec seems to say this is permitted.  */
-         if (pedantic && TREE_CODE (type2) == FUNCTION_TYPE)
-           pedwarn ("ANSI C forbids conditional expr between 0 and function pointer");
-#endif
        }
       result_type = type2;
     }
@@ -3607,6 +3640,10 @@ internal_build_compound_expr (list, first_p)
 
   if (TREE_CHAIN (list) == 0)
     {
+      /* Convert arrays to pointers when there really is a comma operator.  */
+      if (!first_p && TREE_CODE (TREE_TYPE (TREE_VALUE (list))) == ARRAY_TYPE)
+       TREE_VALUE (list) = default_conversion (TREE_VALUE (list));
+
 #if 0 /* If something inside inhibited lvalueness, we should not override.  */
       /* Consider (x, y+0), which is not an lvalue since y+0 is not.  */
 
@@ -3621,14 +3658,6 @@ internal_build_compound_expr (list, first_p)
       return TREE_VALUE (list);
     }
 
-  if (TREE_CHAIN (list) != 0 && TREE_CHAIN (TREE_CHAIN (list)) == 0)
-    {
-      /* Convert arrays to pointers when there really is a comma operator.  */
-      if (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (list)))) == ARRAY_TYPE)
-       TREE_VALUE (TREE_CHAIN (list))
-         = default_conversion (TREE_VALUE (TREE_CHAIN (list)));
-    }
-
   rest = internal_build_compound_expr (TREE_CHAIN (list), FALSE);
 
   if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)))
@@ -3688,7 +3717,7 @@ build_c_cast (type, expr)
       return error_mark_node;
     }
 
-  if (type == TREE_TYPE (value))
+  if (type == TYPE_MAIN_VARIANT (TREE_TYPE (value)))
     {
       if (pedantic)
        {
@@ -3834,6 +3863,24 @@ build_c_cast (type, expr)
 
   return value;
 }
+
+/* Interpret a cast of expression EXPR to type TYPE.  */
+tree
+c_cast_expr (type, expr)
+     tree type, expr;
+{
+  int saved_wsp = warn_strict_prototypes;
+
+  /* This avoids warnings about unprototyped casts on
+     integers.  E.g. "#define SIG_DFL (void(*)())0".  */
+  if (TREE_CODE (expr) == INTEGER_CST)
+    warn_strict_prototypes = 0;
+  type = groktypename (type);
+  warn_strict_prototypes = saved_wsp;
+
+  return build_c_cast (type, expr);
+}
+
 \f
 /* Build an assignment expression of lvalue LHS from value RHS.
    MODIFYCODE is the code for a binary operator that we use
@@ -3969,6 +4016,7 @@ build_modify_expr (lhs, modifycode, rhs)
 
   if (TREE_CODE (lhs) == COMPONENT_REF
       && (TREE_CODE (lhstype) == INTEGER_TYPE
+         || TREE_CODE (lhstype) == BOOLEAN_TYPE
          || TREE_CODE (lhstype) == REAL_TYPE
          || TREE_CODE (lhstype) == ENUMERAL_TYPE))
     lhstype = TREE_TYPE (get_unwidened (lhs, 0));
@@ -4084,9 +4132,11 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
     }
   /* Arithmetic types all interconvert, and enum is treated like int.  */
   else if ((codel == INTEGER_TYPE || codel == REAL_TYPE 
-           || codel == ENUMERAL_TYPE || codel == COMPLEX_TYPE)
+           || codel == ENUMERAL_TYPE || codel == COMPLEX_TYPE
+           || codel == BOOLEAN_TYPE)
           && (coder == INTEGER_TYPE || coder == REAL_TYPE 
-              || coder == ENUMERAL_TYPE || coder == COMPLEX_TYPE))
+              || coder == ENUMERAL_TYPE || coder == COMPLEX_TYPE
+              || coder == BOOLEAN_TYPE))
     return convert_and_check (type, rhs);
 
   /* Conversion to a transparent union from its member types.
@@ -4266,6 +4316,8 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
                           errtype, funname, parmnum);
       return convert (type, rhs);
     }
+  else if (codel == BOOLEAN_TYPE && coder == POINTER_TYPE)
+    return convert (type, rhs);
 
   if (!errtype)
     {
@@ -4381,7 +4433,7 @@ store_init_value (decl, init)
   /* Digest the specified initializer into an expression.  */
 
   value = digest_init (type, init, TREE_STATIC (decl),
-                      TREE_STATIC (decl) || pedantic);
+                      TREE_STATIC (decl) || (pedantic && !flag_isoc99));
 
   /* Store the expression if valid; else report error.  */
 
@@ -4638,6 +4690,8 @@ digest_init (type, init, require_constant, constructor_constant)
   if (TREE_CODE (init) == NON_LVALUE_EXPR)
     inside_init = TREE_OPERAND (init, 0);
 
+  inside_init = fold (inside_init);
+
   /* Initialization of an array of chars from a string constant
      optionally enclosed in braces.  */
 
@@ -4733,17 +4787,21 @@ digest_init (type, init, require_constant, constructor_constant)
          if (flag_pedantic_errors)
            inside_init = error_mark_node;
        }
-      else if (require_constant && ! TREE_CONSTANT (inside_init))
+      else if (require_constant 
+              && (!TREE_CONSTANT (inside_init)
+                  /* This test catches things like `7 / 0' which
+                     result in an expression for which TREE_CONSTANT
+                     is true, but which is not actually something
+                     that is a legal constant.  We really should not
+                     be using this function, because it is a part of
+                     the back-end.  Instead, the expression should
+                     already have been turned into ERROR_MARK_NODE.  */
+                  || !initializer_constant_valid_p (inside_init,
+                                                    TREE_TYPE (inside_init))))
        {
          error_init ("initializer element is not constant");
          inside_init = error_mark_node;
        }
-      else if (require_constant
-              && initializer_constant_valid_p (inside_init, TREE_TYPE (inside_init)) == 0)
-       {
-         error_init ("initializer element is not computable at load time");
-         inside_init = error_mark_node;
-       }
 
       return inside_init;
     }
@@ -4751,7 +4809,7 @@ digest_init (type, init, require_constant, constructor_constant)
   /* Handle scalar types, including conversions.  */
 
   if (code == INTEGER_TYPE || code == REAL_TYPE || code == POINTER_TYPE
-      || code == ENUMERAL_TYPE || code == COMPLEX_TYPE)
+      || code == ENUMERAL_TYPE || code == BOOLEAN_TYPE || code == COMPLEX_TYPE)
     {
       /* Note that convert_for_assignment calls default_conversion
         for arrays and functions.  We must not call it in the
@@ -4839,11 +4897,6 @@ static tree constructor_fields;
    at which to store the next element we get.  */
 static tree constructor_index;
 
-/* For an ARRAY_TYPE, this is the end index of the range
-   to initialize with the next element, or NULL in the ordinary case
-   where the element is used just once.  */
-static tree constructor_range_end;
-
 /* For an ARRAY_TYPE, this is the maximum index.  */
 static tree constructor_max_index;
 
@@ -4863,6 +4916,10 @@ static tree constructor_bit_index;
    most recent first).  */
 static tree constructor_elements;
 
+/* 1 if constructor should be incrementally stored into a constructor chain,
+   0 if all the elements should be kept in AVL tree.  */
+static int constructor_incremental;
+
 /* 1 if so far this constructor's elements are all compile-time constants.  */
 static int constructor_constant;
 
@@ -4909,43 +4966,67 @@ static int require_constant_elements;
 static tree constructor_decl;
 
 /* start_init saves the ASMSPEC arg here for really_start_incremental_init.  */
-static char *constructor_asmspec;
+static const char *constructor_asmspec;
 
 /* Nonzero if this is an initializer for a top-level decl.  */
 static int constructor_top_level;
 
+/* Nesting depth of designator list.  */
+static int designator_depth;
+
+/* Nonzero if there were diagnosed errors in this designator list.  */
+static int designator_errorneous;
+
 \f
 /* This stack has a level for each implicit or explicit level of
    structuring in the initializer, including the outermost one.  It
    saves the values of most of the variables above.  */
 
+struct constructor_range_stack;
+
 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;
   struct init_node *pending_elts;
+  int offset;
   int depth;
   /* If nonzero, this value should replace the entire
      constructor at this level.  */
   tree replacement_value;
+  struct constructor_range_stack *range_stack;
   char constant;
   char simple;
   char implicit;
   char erroneous;
   char outer;
+  char incremental;
 };
 
 struct constructor_stack *constructor_stack;
 
+/* This stack represents designators from some range designator up to
+   the last designator in the list.  */
+
+struct constructor_range_stack
+{
+  struct constructor_range_stack *next, *prev;
+  struct constructor_stack *stack;
+  tree range_start;
+  tree index;
+  tree range_end;
+  tree fields;
+};
+
+struct constructor_range_stack *constructor_range_stack;
+
 /* This stack records separate initializers that are nested.
    Nested initializers can't happen in ANSI C, but GNU C allows them
    in cases like { ... (struct foo) { ... } ... }.  */
@@ -4954,8 +5035,9 @@ struct initializer_stack
 {
   struct initializer_stack *next;
   tree decl;
-  char *asmspec;
+  const char *asmspec;
   struct constructor_stack *constructor_stack;
+  struct constructor_range_stack *constructor_range_stack;
   tree elements;
   struct spelling *spelling;
   struct spelling *spelling_base;
@@ -4979,7 +5061,7 @@ start_init (decl, asmspec_tree, top_level)
   const char *locus;
   struct initializer_stack *p
     = (struct initializer_stack *) xmalloc (sizeof (struct initializer_stack));
-  char *asmspec = 0;
+  const char *asmspec = 0;
 
   if (asmspec_tree)
     asmspec = TREE_STRING_POINTER (asmspec_tree);
@@ -4989,6 +5071,7 @@ start_init (decl, asmspec_tree, top_level)
   p->require_constant_value = require_constant_value;
   p->require_constant_elements = require_constant_elements;
   p->constructor_stack = constructor_stack;
+  p->constructor_range_stack = constructor_range_stack;
   p->elements = constructor_elements;
   p->spelling = spelling;
   p->spelling_base = spelling_base;
@@ -5007,7 +5090,7 @@ start_init (decl, asmspec_tree, top_level)
     {
       require_constant_value = TREE_STATIC (decl);
       require_constant_elements
-       = ((TREE_STATIC (decl) || pedantic)
+       = ((TREE_STATIC (decl) || (pedantic && !flag_isoc99))
           /* For a scalar, you can always use any value to initialize,
              even within braces.  */
           && (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
@@ -5024,6 +5107,7 @@ start_init (decl, asmspec_tree, top_level)
     }
 
   constructor_stack = 0;
+  constructor_range_stack = 0;
 
   missing_braces_mentioned = 0;
 
@@ -5054,12 +5138,16 @@ finish_init ()
       free (q);
     }
 
+  if (constructor_range_stack)
+    abort ();
+
   /* Pop back to the data of the outer initializer (if any).  */
   constructor_decl = p->decl;
   constructor_asmspec = p->asmspec;
   require_constant_value = p->require_constant_value;
   require_constant_elements = p->require_constant_elements;
   constructor_stack = p->constructor_stack;
+  constructor_range_stack = p->constructor_range_stack;
   constructor_elements = p->elements;
   spelling = p->spelling;
   spelling_base = p->spelling_base;
@@ -5090,7 +5178,6 @@ really_start_incremental_init (type)
   p->type = constructor_type;
   p->fields = constructor_fields;
   p->index = constructor_index;
-  p->range_end = constructor_range_end;
   p->max_index = constructor_max_index;
   p->unfilled_index = constructor_unfilled_index;
   p->unfilled_fields = constructor_unfilled_fields;
@@ -5103,7 +5190,9 @@ really_start_incremental_init (type)
   p->depth = constructor_depth;
   p->replacement_value = 0;
   p->implicit = 0;
+  p->range_stack = 0;
   p->outer = 0;
+  p->incremental = constructor_incremental;
   p->next = 0;
   constructor_stack = p;
 
@@ -5113,6 +5202,9 @@ really_start_incremental_init (type)
   constructor_elements = 0;
   constructor_pending_elts = 0;
   constructor_type = type;
+  constructor_incremental = 1;
+  designator_depth = 0;
+  designator_errorneous = 0;
 
   if (TREE_CODE (constructor_type) == RECORD_TYPE
       || TREE_CODE (constructor_type) == UNION_TYPE)
@@ -5128,11 +5220,15 @@ really_start_incremental_init (type)
     }
   else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
     {
-      constructor_range_end = 0;
       if (TYPE_DOMAIN (constructor_type))
        {
          constructor_max_index
            = TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type));
+
+         /* Detect non-empty initializations of zero-length arrays.  */
+         if (constructor_max_index == NULL_TREE)
+           constructor_max_index = build_int_2 (-1, -1);
+
          constructor_index
            = convert (bitsizetype,
                       TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type)));
@@ -5153,13 +5249,14 @@ really_start_incremental_init (type)
 /* Push down into a subobject, for initialization.
    If this is for an explicit set of braces, IMPLICIT is 0.
    If it is because the next element belongs at a lower level,
-   IMPLICIT is 1.  */
+   IMPLICIT is 1 (or 2 if the push is because of designator list).  */
 
 void
 push_init_level (implicit)
      int implicit;
 {
   struct constructor_stack *p;
+  tree value = NULL_TREE;
 
   /* If we've exhausted any levels that didn't have braces,
      pop them now.  */
@@ -5176,11 +5273,22 @@ push_init_level (implicit)
        break;
     }
 
+  /* Unless this is an explicit brace, we need to preserve previous
+     content if any.  */
+  if (implicit)
+    {
+      if ((TREE_CODE (constructor_type) == RECORD_TYPE
+          || TREE_CODE (constructor_type) == UNION_TYPE)
+         && constructor_fields)
+       value = find_init_member (constructor_fields);
+      else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+       value = find_init_member (constructor_index);
+    }
+
   p = (struct constructor_stack *) xmalloc (sizeof (struct constructor_stack));
   p->type = constructor_type;
   p->fields = constructor_fields;
   p->index = constructor_index;
-  p->range_end = constructor_range_end;
   p->max_index = constructor_max_index;
   p->unfilled_index = constructor_unfilled_index;
   p->unfilled_fields = constructor_unfilled_fields;
@@ -5194,14 +5302,24 @@ push_init_level (implicit)
   p->replacement_value = 0;
   p->implicit = implicit;
   p->outer = 0;
+  p->incremental = constructor_incremental;
   p->next = constructor_stack;
+  p->range_stack = 0;
   constructor_stack = p;
 
   constructor_constant = 1;
   constructor_simple = 1;
   constructor_depth = SPELLING_DEPTH ();
   constructor_elements = 0;
+  constructor_incremental = 1;
   constructor_pending_elts = 0;
+  if (!implicit)
+    {
+      p->range_stack = constructor_range_stack;
+      constructor_range_stack = 0;
+      designator_depth = 0;
+      designator_errorneous = 0;
+    }
 
   /* Don't die if an entire brace-pair level is superfluous
      in the containing level.  */
@@ -5235,7 +5353,18 @@ push_init_level (implicit)
       return;
     }
 
-  if (implicit && warn_missing_braces && !missing_braces_mentioned)
+  if (value && TREE_CODE (value) == CONSTRUCTOR)
+    {
+      constructor_constant = TREE_CONSTANT (value);
+      constructor_simple = TREE_STATIC (value);
+      constructor_elements = TREE_OPERAND (value, 1);
+      if (constructor_elements
+         && (TREE_CODE (constructor_type) == RECORD_TYPE
+             || TREE_CODE (constructor_type) == ARRAY_TYPE))
+       set_nonincremental_init ();
+    }
+
+  if (implicit == 1 && warn_missing_braces && !missing_braces_mentioned)
     {
       missing_braces_mentioned = 1;
       warning_init ("missing braces around initializer");
@@ -5255,20 +5384,30 @@ push_init_level (implicit)
     }
   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
            = convert (bitsizetype, 
-                                 TYPE_MIN_VALUE
-                                 (TYPE_DOMAIN (constructor_type)));
+                      TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type)));
+
+         /* ??? For GCC 3.1, remove special case initialization of
+            zero-length array members from pop_init_level and set
+            constructor_max_index such that we get the normal
+            "excess elements" warning.  */
        }
       else
        constructor_index = bitsize_zero_node;
 
       constructor_unfilled_index = constructor_index;
+      if (value && TREE_CODE (value) == STRING_CST)
+       {
+         /* We need to split the char/wchar array into individual
+            characters, so that we don't have to special case it
+            everywhere.  */
+         set_nonincremental_init_from_string (value);
+       }
     }
   else
     {
@@ -5300,6 +5439,9 @@ pop_init_level (implicit)
         pop any inner levels that didn't have explicit braces.  */
       while (constructor_stack->implicit)
        process_init_element (pop_init_level (1));
+
+      if (constructor_range_stack)
+       abort ();
     }
 
   p = constructor_stack;
@@ -5307,31 +5449,71 @@ pop_init_level (implicit)
   if (constructor_type != 0)
     size = int_size_in_bytes (constructor_type);
 
+  /* Error for initializing a flexible array member, or a zero-length
+     array member in an inappropriate context.  */
+  if (constructor_type && constructor_fields
+      && TREE_CODE (constructor_type) == ARRAY_TYPE
+      && TYPE_DOMAIN (constructor_type)
+      && ! TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type)))
+    {
+      /* Silently discard empty initializations.  The parser will
+        already have pedwarned for empty brackets.  */
+      if (integer_zerop (constructor_unfilled_index))
+       constructor_type = NULL_TREE;
+      else if (! TYPE_SIZE (constructor_type))
+       {
+         if (constructor_depth > 2)
+           error_init ("initialization of flexible array member in a nested context");
+         else if (pedantic)
+           pedwarn_init ("initialization of a flexible array member");
+
+         /* We have already issued an error message for the existance
+            of a flexible array member not at the end of the structure.
+            Discard the initializer so that we do not abort later.  */
+         if (TREE_CHAIN (constructor_fields) != NULL_TREE)
+           constructor_type = NULL_TREE;
+       }
+      else
+       {
+         warning_init ("deprecated initialization of zero-length array");
+
+         /* We must be initializing the last member of a top-level struct.  */
+         if (TREE_CHAIN (constructor_fields) != NULL_TREE)
+           {
+             error_init ("initialization of zero-length array before end of structure");
+             /* Discard the initializer so that we do not abort later.  */
+             constructor_type = NULL_TREE;
+           }
+         else if (constructor_depth > 2)
+           error_init ("initialization of zero-length array inside a nested context");
+       }
+    }
+
   /* Warn when some struct elements are implicitly initialized to zero.  */
   if (extra_warnings
       && constructor_type
       && TREE_CODE (constructor_type) == RECORD_TYPE
       && constructor_unfilled_fields)
     {
-      push_member_name (constructor_unfilled_fields);
-      warning_init ("missing initializer");
-      RESTORE_SPELLING_DEPTH (constructor_depth);
+       /* Do not warn for flexible array members or zero-length arrays.  */
+       while (constructor_unfilled_fields
+              && (! DECL_SIZE (constructor_unfilled_fields)
+                  || integer_zerop (DECL_SIZE (constructor_unfilled_fields))))
+         constructor_unfilled_fields = TREE_CHAIN (constructor_unfilled_fields);
+
+       if (constructor_unfilled_fields)
+         {
+           push_member_name (constructor_unfilled_fields);
+           warning_init ("missing initializer");
+           RESTORE_SPELLING_DEPTH (constructor_depth);
+         }
     }
 
   /* Now output all pending elements.  */
+  constructor_incremental = 1;
   output_pending_init_elements (1);
 
-#if 0 /* c-parse.in warns about {}.  */
-  /* In ANSI, each brace level must have at least one element.  */
-  if (! implicit && pedantic
-      && (TREE_CODE (constructor_type) == ARRAY_TYPE
-         ? integer_zerop (constructor_unfilled_index)
-         : constructor_unfilled_fields == TYPE_FIELDS (constructor_type)))
-    pedwarn_init ("empty braces in initializer");
-#endif
-
   /* Pad out the end of the structure.  */
-  
   if (p->replacement_value)
     /* If this closes a superfluous brace pair,
        just pass out the element between them.  */
@@ -5346,7 +5528,8 @@ pop_init_level (implicit)
         the element, after verifying there is just one.  */
       if (constructor_elements == 0)
        {
-         error_init ("empty scalar initializer");
+         if (!constructor_erroneous)
+           error_init ("empty scalar initializer");
          constructor = error_mark_node;
        }
       else if (TREE_CHAIN (constructor_elements) != 0)
@@ -5375,7 +5558,6 @@ pop_init_level (implicit)
   constructor_type = p->type;
   constructor_fields = p->fields;
   constructor_index = p->index;
-  constructor_range_end = p->range_end;
   constructor_max_index = p->max_index;
   constructor_unfilled_index = p->unfilled_index;
   constructor_unfilled_fields = p->unfilled_fields;
@@ -5384,8 +5566,11 @@ pop_init_level (implicit)
   constructor_constant = p->constant;
   constructor_simple = p->simple;
   constructor_erroneous = p->erroneous;
+  constructor_incremental = p->incremental;
   constructor_pending_elts = p->pending_elts;
   constructor_depth = p->depth;
+  if (!p->implicit)
+    constructor_range_stack = p->range_stack;
   RESTORE_SPELLING_DEPTH (constructor_depth);
 
   constructor_stack = p->next;
@@ -5400,6 +5585,97 @@ pop_init_level (implicit)
   return constructor;
 }
 
+/* Common handling for both array range and field name designators.
+   ARRAY argument is non-zero for array ranges.  Returns zero for success.  */
+
+static int
+set_designator (array)
+     int array;
+{
+  tree subtype;
+  enum tree_code subcode;
+
+  /* Don't die if an entire brace-pair level is superfluous
+     in the containing level.  */
+  if (constructor_type == 0)
+    return 1;
+
+  /* If there were errors in this designator list already, bail out silently.  */
+  if (designator_errorneous)
+    return 1;
+
+  if (!designator_depth)
+    {
+      if (constructor_range_stack)
+       abort ();
+
+      /* Designator list starts at the level of closest explicit
+        braces.  */
+      while (constructor_stack->implicit)
+       process_init_element (pop_init_level (1));
+      return 0;
+    }
+
+  if (constructor_no_implicit)
+    {
+      error_init ("initialization designators may not nest");
+      return 1;
+    }
+
+  if (TREE_CODE (constructor_type) == RECORD_TYPE
+      || TREE_CODE (constructor_type) == UNION_TYPE)
+    {
+      subtype = TREE_TYPE (constructor_fields);
+      if (subtype != error_mark_node)
+       subtype = TYPE_MAIN_VARIANT (subtype);
+    }
+  else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+    {
+      subtype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type));
+    }
+  else
+    abort ();
+
+  subcode = TREE_CODE (subtype);
+  if (array && subcode != ARRAY_TYPE)
+    {
+      error_init ("array index in non-array initializer");
+      return 1;
+    }
+  else if (!array && subcode != RECORD_TYPE && subcode != UNION_TYPE)
+    {
+      error_init ("field name not in record or union initializer");
+      return 1;
+    }
+
+  push_init_level (2);
+  return 0;
+}
+
+/* If there are range designators in designator list, push a new designator
+   to constructor_range_stack.  RANGE_END is end of such stack range or
+   NULL_TREE if there is no range designator at this level.  */
+
+static void
+push_range_stack (range_end)
+     tree range_end;
+{
+  struct constructor_range_stack *p;
+
+  p = (struct constructor_range_stack *)
+      ggc_alloc (sizeof (struct constructor_range_stack));
+  p->prev = constructor_range_stack;
+  p->next = 0;
+  p->fields = constructor_fields;
+  p->range_start = constructor_index;
+  p->index = constructor_index;
+  p->stack = constructor_stack;
+  p->range_end = range_end;
+  if (constructor_range_stack)
+    constructor_range_stack->next = p;
+  constructor_range_stack = p;
+}
+
 /* Within an array initializer, specify the next index to be initialized.
    FIRST is that index.  If LAST is nonzero, then initialize a range
    of indices, running from FIRST through LAST.  */
@@ -5408,6 +5684,11 @@ void
 set_init_index (first, last)
      tree first, last;
 {
+  if (set_designator (1))
+    return;
+
+  designator_errorneous = 1;
+
   while ((TREE_CODE (first) == NOP_EXPR
          || TREE_CODE (first) == CONVERT_EXPR
          || TREE_CODE (first) == NON_LVALUE_EXPR)
@@ -5427,18 +5708,40 @@ set_init_index (first, last)
     error_init ("nonconstant array index in initializer");
   else if (last != 0 && TREE_CODE (last) != INTEGER_CST)
     error_init ("nonconstant array index in initializer");
-  else if (! constructor_unfilled_index)
+  else if (TREE_CODE (constructor_type) != ARRAY_TYPE)
     error_init ("array index in non-array initializer");
-  else if (tree_int_cst_lt (first, constructor_unfilled_index))
-    error_init ("duplicate array index in initializer");
+  else if (constructor_max_index
+          && tree_int_cst_lt (constructor_max_index, first))
+    error_init ("array index in initializer exceeds array bounds");
   else
     {
       constructor_index = convert (bitsizetype, first);
 
-      if (last != 0 && tree_int_cst_lt (last, first))
-       error_init ("empty index range in initializer");
-      else
-       constructor_range_end = last ? convert (bitsizetype, last) : 0;
+      if (last)
+       {
+         if (tree_int_cst_equal (first, last))
+           last = 0;
+         else if (tree_int_cst_lt (last, first))
+           {
+             error_init ("empty index range in initializer");
+             last = 0;
+           }
+         else
+           {
+             last = convert (bitsizetype, last);
+             if (constructor_max_index != 0
+                 && tree_int_cst_lt (constructor_max_index, last))
+               {
+                 error_init ("array index range in initializer exceeds array bounds");
+                 last = 0;
+               }
+           }
+       }
+
+      designator_depth++;
+      designator_errorneous = 0;
+      if (constructor_range_stack || last)
+       push_range_stack (last);
     }
 }
 
@@ -5449,18 +5752,22 @@ set_init_label (fieldname)
      tree fieldname;
 {
   tree tail;
-  int passed = 0;
 
-  /* Don't die if an entire brace-pair level is superfluous
-     in the containing level.  */
-  if (constructor_type == 0)
+  if (set_designator (0))
     return;
 
+  designator_errorneous = 1;
+
+  if (TREE_CODE (constructor_type) != RECORD_TYPE
+      && TREE_CODE (constructor_type) != UNION_TYPE)
+    {
+      error_init ("field name not in record or union initializer");
+      return;
+    }
+    
   for (tail = TYPE_FIELDS (constructor_type); tail;
        tail = TREE_CHAIN (tail))
     {
-      if (tail == constructor_unfilled_fields)
-       passed = 1;
       if (DECL_NAME (tail) == fieldname)
        break;
     }
@@ -5468,11 +5775,14 @@ set_init_label (fieldname)
   if (tail == 0)
     error ("unknown field `%s' specified in initializer",
           IDENTIFIER_POINTER (fieldname));
-  else if (!passed)
-    error ("field `%s' already initialized",
-          IDENTIFIER_POINTER (fieldname));
   else
-    constructor_fields = tail;
+    {
+      constructor_fields = tail;
+      designator_depth++;
+      designator_errorneous = 0;
+      if (constructor_range_stack)
+       push_range_stack (NULL_TREE);
+    }
 }
 \f
 /* Add a new initializer to the tree of pending initializers.  PURPOSE
@@ -5495,24 +5805,36 @@ add_pending_init (purpose, value)
          p = *q;
          if (tree_int_cst_lt (purpose, p->purpose))
            q = &p->left;
-         else if (p->purpose != purpose)
+         else if (tree_int_cst_lt (p->purpose, purpose))
            q = &p->right;
          else
-           abort ();
+           {
+             if (TREE_SIDE_EFFECTS (p->value))
+               warning_init ("initialized field with side-effects overwritten");
+             p->value = value;
+             return;
+           }
        }
     }
   else
     {
+      tree bitpos;
+
+      bitpos = bit_position (purpose);
       while (*q != NULL)
        {
          p = *q;
-         if (tree_int_cst_lt (bit_position (purpose),
-                              bit_position (p->purpose)))
+         if (tree_int_cst_lt (bitpos, bit_position (p->purpose)))
            q = &p->left;
          else if (p->purpose != purpose)
            q = &p->right;
          else
-           abort ();
+           {
+             if (TREE_SIDE_EFFECTS (p->value))
+               warning_init ("initialized field with side-effects overwritten");
+             p->value = value;
+             return;
+           }
        }
     }
 
@@ -5681,41 +6003,178 @@ add_pending_init (purpose, value)
     }
 }
 
-/* Return nonzero if FIELD is equal to the index of a pending initializer.  */
+/* Build AVL tree from a sorted chain.  */
 
-static int
-pending_init_member (field)
+static void
+set_nonincremental_init ()
+{
+  tree chain;
+
+  if (TREE_CODE (constructor_type) != RECORD_TYPE
+      && TREE_CODE (constructor_type) != ARRAY_TYPE)
+    return;
+
+  for (chain = constructor_elements; chain; chain = TREE_CHAIN (chain))
+    add_pending_init (TREE_PURPOSE (chain), TREE_VALUE (chain));
+  constructor_elements = 0;
+  if (TREE_CODE (constructor_type) == RECORD_TYPE)
+    {
+      constructor_unfilled_fields = TYPE_FIELDS (constructor_type);
+      /* Skip any nameless bit fields at the beginning.  */
+      while (constructor_unfilled_fields != 0
+            && DECL_C_BIT_FIELD (constructor_unfilled_fields)
+            && DECL_NAME (constructor_unfilled_fields) == 0)
+       constructor_unfilled_fields = TREE_CHAIN (constructor_unfilled_fields);
+      
+    }
+  else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+    {
+      if (TYPE_DOMAIN (constructor_type))
+       constructor_unfilled_index
+           = convert (bitsizetype,
+                      TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type)));
+      else
+       constructor_unfilled_index = bitsize_zero_node;
+    }
+  constructor_incremental = 0;
+}
+
+/* Build AVL tree from a string constant.  */
+
+static void
+set_nonincremental_init_from_string (str)
+     tree str;
+{
+  tree value, purpose, type;
+  HOST_WIDE_INT val[2];
+  const char *p, *end;
+  int byte, wchar_bytes, charwidth, bitpos;
+
+  if (TREE_CODE (constructor_type) != ARRAY_TYPE)
+    abort ();
+
+  if (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (str)))
+      == TYPE_PRECISION (char_type_node))
+    wchar_bytes = 1;
+  else if (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (str)))
+          == TYPE_PRECISION (wchar_type_node))
+    wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
+  else
+    abort ();
+
+  charwidth = TYPE_PRECISION (char_type_node);
+  type = TREE_TYPE (constructor_type);
+  p = TREE_STRING_POINTER (str);
+  end = p + TREE_STRING_LENGTH (str);
+
+  for (purpose = bitsize_zero_node;
+       p < end && !tree_int_cst_lt (constructor_max_index, purpose);
+       purpose = size_binop (PLUS_EXPR, purpose, bitsize_one_node))
+    {
+      if (wchar_bytes == 1)
+       {
+         val[1] = (unsigned char) *p++;
+         val[0] = 0;
+       }
+      else
+       {
+         val[0] = 0;
+         val[1] = 0;
+         for (byte = 0; byte < wchar_bytes; byte++)
+           {
+             if (BYTES_BIG_ENDIAN)
+               bitpos = (wchar_bytes - byte - 1) * charwidth;
+             else
+               bitpos = byte * charwidth;
+             val[bitpos < HOST_BITS_PER_WIDE_INT]
+               |= ((unsigned HOST_WIDE_INT) ((unsigned char) *p++))
+                  << (bitpos % HOST_BITS_PER_WIDE_INT);
+           }
+       }
+
+      if (!TREE_UNSIGNED (type))
+       {
+         bitpos = ((wchar_bytes - 1) * charwidth) + HOST_BITS_PER_CHAR;
+         if (bitpos < HOST_BITS_PER_WIDE_INT)
+           {
+             if (val[1] & (((HOST_WIDE_INT) 1) << (bitpos - 1)))
+               {
+                 val[1] |= ((HOST_WIDE_INT) -1) << bitpos;
+                 val[0] = -1;
+               }
+           }
+         else if (bitpos == HOST_BITS_PER_WIDE_INT)
+           {
+             if (val[1] < 0)
+               val[0] = -1;
+           }
+         else if (val[0] & (((HOST_WIDE_INT) 1)
+                            << (bitpos - 1 - HOST_BITS_PER_WIDE_INT)))
+           val[0] |= ((HOST_WIDE_INT) -1)
+                     << (bitpos - HOST_BITS_PER_WIDE_INT);
+       }
+
+      value = build_int_2 (val[1], val[0]);
+      TREE_TYPE (value) = type;
+      add_pending_init (purpose, value);
+    }
+
+  constructor_incremental = 0;
+}
+
+/* Return value of FIELD in pending initializer or zero if the field was
+   not initialized yet.  */
+
+static tree
+find_init_member (field)
      tree field;
 {
   struct init_node *p;
 
-  p = constructor_pending_elts;
   if (TREE_CODE (constructor_type) == ARRAY_TYPE)
     {
+      if (constructor_incremental
+         && tree_int_cst_lt (field, constructor_unfilled_index))
+       set_nonincremental_init ();
+
+      p = constructor_pending_elts;
       while (p)
        {
-         if (field == p->purpose)
-           return 1;
-         else if (tree_int_cst_lt (field, p->purpose))
+         if (tree_int_cst_lt (field, p->purpose))
            p = p->left;
-         else
+         else if (tree_int_cst_lt (p->purpose, field))
            p = p->right;
+         else
+           return p->value;
        }
     }
-  else
+  else if (TREE_CODE (constructor_type) == RECORD_TYPE)
     {
+      tree bitpos = bit_position (field);
+
+      if (constructor_incremental
+         && (!constructor_unfilled_fields
+             || tree_int_cst_lt (bitpos,
+                                 bit_position (constructor_unfilled_fields))))
+       set_nonincremental_init ();
+
+      p = constructor_pending_elts;
       while (p)
        {
          if (field == p->purpose)
-           return 1;
-         else if (tree_int_cst_lt (bit_position (field),
-                                   bit_position (p->purpose)))
+           return p->value;
+         else if (tree_int_cst_lt (bitpos, bit_position (p->purpose)))
            p = p->left;
          else
            p = p->right;
        }
     }
-
+  else if (TREE_CODE (constructor_type) == UNION_TYPE)
+    {
+      if (constructor_elements
+         && TREE_PURPOSE (constructor_elements) == field)
+       return TREE_VALUE (constructor_elements);
+    }
   return 0;
 }
 
@@ -5734,8 +6193,6 @@ output_init_element (value, type, field, pending)
      tree value, type, field;
      int pending;
 {
-  int duplicate = 0;
-
   if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE
       || (TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
          && !(TREE_CODE (value) == STRING_CST
@@ -5763,90 +6220,111 @@ output_init_element (value, type, field, pending)
     }
   else if (require_constant_elements
           && initializer_constant_valid_p (value, TREE_TYPE (value)) == 0)
-    {
-      error_init ("initializer element is not computable at load time");
-      value = error_mark_node;
-    }
+    pedwarn ("initializer element is not computable at load time");
+
+  /* If this field is empty (and not at the end of structure),
+     don't do anything other than checking the initializer.  */
+  if (field
+      && (TREE_TYPE (field) == error_mark_node
+         || (COMPLETE_TYPE_P (TREE_TYPE (field))
+             && integer_zerop (TYPE_SIZE (TREE_TYPE (field)))
+             && (TREE_CODE (constructor_type) == ARRAY_TYPE
+                 || TREE_CHAIN (field)))))
+    return;
 
-  /* If this element duplicates one on constructor_pending_elts,
-     print a message and ignore it.  Don't do this when we're
-     processing elements taken off constructor_pending_elts,
-     because we'd always get spurious errors.  */
-  if (pending)
+  if (value == error_mark_node)
     {
-      if (TREE_CODE (constructor_type) == RECORD_TYPE
-         || TREE_CODE (constructor_type) == UNION_TYPE
-         || TREE_CODE (constructor_type) == ARRAY_TYPE)
-       {
-         if (pending_init_member (field))
-           {
-             error_init ("duplicate initializer");
-             duplicate = 1;
-           }
-       }
+      constructor_erroneous = 1;
+      return;
     }
 
   /* If this element doesn't come next in sequence,
      put it on constructor_pending_elts.  */
   if (TREE_CODE (constructor_type) == ARRAY_TYPE
-      && ! tree_int_cst_equal (field, constructor_unfilled_index))
+      && (!constructor_incremental
+         || !tree_int_cst_equal (field, constructor_unfilled_index)))
     {
-      if (! duplicate)
-       add_pending_init (field,
-                         digest_init (type, value, require_constant_value, 
-                                      require_constant_elements));
+      if (constructor_incremental
+         && tree_int_cst_lt (field, constructor_unfilled_index))
+       set_nonincremental_init ();
+
+      add_pending_init (field,
+                       digest_init (type, value, require_constant_value, 
+                                    require_constant_elements));
+      return;
     }
   else if (TREE_CODE (constructor_type) == RECORD_TYPE
-          && field != constructor_unfilled_fields)
+          && (!constructor_incremental
+              || field != constructor_unfilled_fields))
     {
       /* We do this for records but not for unions.  In a union,
         no matter which field is specified, it can be initialized
         right away since it starts at the beginning of the union.  */
-      if (!duplicate)
-       add_pending_init (field,
-                         digest_init (type, value, require_constant_value, 
-                                      require_constant_elements));
+      if (constructor_incremental)
+       {
+         if (!constructor_unfilled_fields)
+           set_nonincremental_init ();
+         else
+           {
+             tree bitpos, unfillpos;
+
+             bitpos = bit_position (field);
+             unfillpos = bit_position (constructor_unfilled_fields);
+
+             if (tree_int_cst_lt (bitpos, unfillpos))
+               set_nonincremental_init ();
+           }
+       }
+
+      add_pending_init (field,
+                       digest_init (type, value, require_constant_value, 
+                                    require_constant_elements));
+      return;
     }
-  else
+  else if (TREE_CODE (constructor_type) == UNION_TYPE
+          && constructor_elements)
     {
-      /* Otherwise, output this element either to
-        constructor_elements or to the assembler file.  */
+      if (TREE_SIDE_EFFECTS (TREE_VALUE (constructor_elements)))
+       warning_init ("initialized field with side-effects overwritten");
 
-      if (!duplicate)
-       {
-         if (field && TREE_CODE (field) == INTEGER_CST)
-           field = copy_node (field);
-         constructor_elements
-           = tree_cons (field, digest_init (type, value,
-                                            require_constant_value, 
-                                            require_constant_elements),
-                        constructor_elements);
-       }
+      /* We can have just one union field set.  */
+      constructor_elements = 0;
+    }
 
-      /* Advance the variable that indicates sequential elements output.  */
-      if (TREE_CODE (constructor_type) == ARRAY_TYPE)
-       constructor_unfilled_index
-         = size_binop (PLUS_EXPR, constructor_unfilled_index,
-                       bitsize_one_node);
-      else if (TREE_CODE (constructor_type) == RECORD_TYPE)
-       {
-         constructor_unfilled_fields
-           = TREE_CHAIN (constructor_unfilled_fields);
-
-         /* Skip any nameless bit fields.  */
-         while (constructor_unfilled_fields != 0
-                && DECL_C_BIT_FIELD (constructor_unfilled_fields)
-                && DECL_NAME (constructor_unfilled_fields) == 0)
-           constructor_unfilled_fields =
-             TREE_CHAIN (constructor_unfilled_fields);
-       }
-      else if (TREE_CODE (constructor_type) == UNION_TYPE)
-       constructor_unfilled_fields = 0;
+  /* Otherwise, output this element either to
+     constructor_elements or to the assembler file.  */
+
+  if (field && TREE_CODE (field) == INTEGER_CST)
+    field = copy_node (field);
+  constructor_elements
+    = tree_cons (field, digest_init (type, value,
+                                    require_constant_value, 
+                                    require_constant_elements),
+                constructor_elements);
+
+  /* Advance the variable that indicates sequential elements output.  */
+  if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+    constructor_unfilled_index
+      = size_binop (PLUS_EXPR, constructor_unfilled_index,
+                   bitsize_one_node);
+  else if (TREE_CODE (constructor_type) == RECORD_TYPE)
+    {
+      constructor_unfilled_fields
+       = TREE_CHAIN (constructor_unfilled_fields);
 
-      /* Now output any pending elements which have become next.  */
-      if (pending)
-       output_pending_init_elements (0);
+      /* Skip any nameless bit fields.  */
+      while (constructor_unfilled_fields != 0
+            && DECL_C_BIT_FIELD (constructor_unfilled_fields)
+            && DECL_NAME (constructor_unfilled_fields) == 0)
+       constructor_unfilled_fields =
+         TREE_CHAIN (constructor_unfilled_fields);
     }
+  else if (TREE_CODE (constructor_type) == UNION_TYPE)
+    constructor_unfilled_fields = 0;
+
+  /* Now output any pending elements which have become next.  */
+  if (pending)
+    output_pending_init_elements (0);
 }
 
 /* Output any pending elements which have become next.
@@ -5922,18 +6400,23 @@ output_pending_init_elements (all)
       else if (TREE_CODE (constructor_type) == RECORD_TYPE
               || TREE_CODE (constructor_type) == UNION_TYPE)
        {
+         tree ctor_unfilled_bitpos, elt_bitpos;
+
          /* If the current record is complete we are done.  */
          if (constructor_unfilled_fields == 0)
            break;
-         if (elt->purpose == constructor_unfilled_fields)
+
+         ctor_unfilled_bitpos = bit_position (constructor_unfilled_fields);
+         elt_bitpos = bit_position (elt->purpose);
+         /* We can't compare fields here because there might be empty
+            fields in between.  */
+         if (tree_int_cst_equal (elt_bitpos, ctor_unfilled_bitpos))
            {
-             output_init_element (elt->value,
-                                  TREE_TYPE (constructor_unfilled_fields),
-                                  constructor_unfilled_fields,
-                                  0);
+             constructor_unfilled_fields = elt->purpose;
+             output_init_element (elt->value, TREE_TYPE (elt->purpose),
+                                  elt->purpose, 0);
            }
-         else if (tree_int_cst_lt (bit_position (constructor_unfilled_fields),
-                                   bit_position (elt->purpose)))
+         else if (tree_int_cst_lt (ctor_unfilled_bitpos, elt_bitpos))
            {
              /* Advance to the next smaller node.  */
              if (elt->left)
@@ -5959,9 +6442,8 @@ output_pending_init_elements (all)
                    elt = elt->parent;
                  elt = elt->parent;
                  if (elt
-                     && (tree_int_cst_lt
-                         (bit_position (constructor_unfilled_fields),
-                          bit_position (elt->purpose))))
+                     && (tree_int_cst_lt (ctor_unfilled_bitpos,
+                                          bit_position (elt->purpose))))
                    {
                      next = elt->purpose;
                      break;
@@ -6004,6 +6486,9 @@ process_init_element (value)
   tree orig_value = value;
   int string_flag = value != 0 && TREE_CODE (value) == STRING_CST;
 
+  designator_depth = 0;
+  designator_errorneous = 0;
+
   /* Handle superfluous braces around string cst as in
      char x[] = {"foo"}; */
   if (string_flag
@@ -6046,6 +6531,10 @@ process_init_element (value)
        break;
     }
 
+  /* In the case of [LO ... HI] = VALUE, only evaluate VALUE once.  */
+  if (constructor_range_stack)
+    value = save_expr (value);
+
   while (1)
     {
       if (TREE_CODE (constructor_type) == RECORD_TYPE)
@@ -6093,10 +6582,11 @@ process_init_element (value)
               directly output as a constructor.  */
            {
              /* For a record, keep track of end position of last field.  */
-             constructor_bit_index
-               = size_binop (PLUS_EXPR,
-                             bit_position (constructor_fields),
-                             DECL_SIZE (constructor_fields));
+             if (DECL_SIZE (constructor_fields))
+               constructor_bit_index
+                 = size_binop (PLUS_EXPR,
+                               bit_position (constructor_fields),
+                               DECL_SIZE (constructor_fields));
 
              constructor_unfilled_fields = TREE_CHAIN (constructor_fields);
              /* Skip any nameless bit fields.  */
@@ -6113,9 +6603,8 @@ process_init_element (value)
                 && DECL_C_BIT_FIELD (constructor_fields)
                 && DECL_NAME (constructor_fields) == 0)
            constructor_fields = TREE_CHAIN (constructor_fields);
-         break;
        }
-      if (TREE_CODE (constructor_type) == UNION_TYPE)
+      else if (TREE_CODE (constructor_type) == UNION_TYPE)
        {
          tree fieldtype;
          enum tree_code fieldcode;
@@ -6174,9 +6663,8 @@ process_init_element (value)
            }
 
          constructor_fields = 0;
-         break;
        }
-      if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+      else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
        {
          tree elttype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type));
          enum tree_code eltcode = TREE_CODE (elttype);
@@ -6207,98 +6695,159 @@ process_init_element (value)
              break;
            }
 
-         /* In the case of [LO .. HI] = VALUE, only evaluate VALUE once.  */
-         if (constructor_range_end)
+         /* Now output the actual element.  */
+         if (value)
            {
-             if (constructor_max_index != 0
-                 && tree_int_cst_lt (constructor_max_index, 
-                                     constructor_range_end))
-               {
-                 pedwarn_init ("excess elements in array initializer");
-                 constructor_range_end = constructor_max_index;
-               }
-
-             value = save_expr (value);
+             push_array_bounds (tree_low_cst (constructor_index, 0));
+             output_init_element (value, elttype, constructor_index, 1);
+             RESTORE_SPELLING_DEPTH (constructor_depth);
            }
 
-         /* Now output the actual element.
-            Ordinarily, output once.
-            If there is a range, repeat it till we advance past the range.  */
-         do
-           {
-             if (value)
-               {
-                 push_array_bounds (tree_low_cst (constructor_index, 0));
-                 output_init_element (value, elttype, constructor_index, 1);
-                 RESTORE_SPELLING_DEPTH (constructor_depth);
-               }
-
-             constructor_index
-               = size_binop (PLUS_EXPR, constructor_index, bitsize_one_node);
-
-             if (! value)
-               /* If we are doing the bookkeeping for an element that was
-                  directly output as a constructor, we must update
-                  constructor_unfilled_index.  */
-               constructor_unfilled_index = constructor_index;
-           }
-         while (! (constructor_range_end == 0
-                   || tree_int_cst_lt (constructor_range_end,
-                                       constructor_index)));
+         constructor_index
+           = size_binop (PLUS_EXPR, constructor_index, bitsize_one_node);
 
-         break;
+         if (! value)
+           /* If we are doing the bookkeeping for an element that was
+              directly output as a constructor, we must update
+              constructor_unfilled_index.  */
+           constructor_unfilled_index = constructor_index;
        }
 
       /* Handle the sole element allowed in a braced initializer
         for a scalar variable.  */
-      if (constructor_fields == 0)
+      else if (constructor_fields == 0)
        {
          pedwarn_init ("excess elements in scalar initializer");
          break;
        }
+      else
+       {
+         if (value)
+           output_init_element (value, constructor_type, NULL_TREE, 1);
+         constructor_fields = 0;
+       }
+
+      /* Handle range initializers either at this level or anywhere higher
+        in the designator stack.  */
+      if (constructor_range_stack)
+       {
+         struct constructor_range_stack *p, *range_stack;
+         int finish = 0;
+
+         range_stack = constructor_range_stack;
+         constructor_range_stack = 0;
+         while (constructor_stack != range_stack->stack)
+           {
+             if (!constructor_stack->implicit)
+               abort ();
+             process_init_element (pop_init_level (1));
+           }
+         for (p = range_stack;
+              !p->range_end || tree_int_cst_equal (p->index, p->range_end);
+              p = p->prev)
+           {
+             if (!constructor_stack->implicit)
+               abort ();
+             process_init_element (pop_init_level (1));
+           }
+
+         p->index = size_binop (PLUS_EXPR, p->index, bitsize_one_node);
+         if (tree_int_cst_equal (p->index, p->range_end) && !p->prev)
+           finish = 1;
+
+         while (1)
+           {
+             constructor_index = p->index;
+             constructor_fields = p->fields;
+             if (finish && p->range_end && p->index == p->range_start)
+               {
+                 finish = 0;
+                 p->prev = 0;
+               }
+             p = p->next;
+             if (!p)
+               break;
+             push_init_level (2);
+             p->stack = constructor_stack;
+             if (p->range_end && tree_int_cst_equal (p->index, p->range_end))
+               p->index = p->range_start;
+           }
+
+         if (!finish)
+           constructor_range_stack = range_stack;
+         continue;
+       }
 
-      if (value)
-       output_init_element (value, constructor_type, NULL_TREE, 1);
-      constructor_fields = 0;
       break;
     }
+
+  constructor_range_stack = 0;
 }
 \f
-/* Expand an ASM statement with operands, handling output operands
-   that are not variables or INDIRECT_REFS by transforming such
-   cases into cases that expand_asm_operands can handle.
+/* Build a simple asm-statement, from one string literal.  */
+tree
+simple_asm_stmt (expr)
+     tree expr;
+{
+  STRIP_NOPS (expr);
 
-   Arguments are same as for expand_asm_operands.  */
+  if (TREE_CODE (expr) == ADDR_EXPR)
+    expr = TREE_OPERAND (expr, 0);
 
-void
-c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
-     tree string, outputs, inputs, clobbers;
-     int vol;
-     const char *filename;
-     int line;
+  if (TREE_CODE (expr) == STRING_CST)
+    {
+      tree stmt;
+
+      if (TREE_CHAIN (expr))
+       expr = combine_strings (expr);
+      stmt = add_stmt (build_stmt (ASM_STMT, NULL_TREE, expr,
+                                  NULL_TREE, NULL_TREE,
+                                  NULL_TREE));
+      ASM_INPUT_P (stmt) = 1;
+      return stmt;
+    }
+
+  error ("argument of `asm' is not a constant string");
+  return NULL_TREE;
+}
+
+/* Build an asm-statement, whose components are a CV_QUALIFIER, a
+   STRING, some OUTPUTS, some INPUTS, and some CLOBBERS.  */
+
+tree
+build_asm_stmt (cv_qualifier, string, outputs, inputs, clobbers)
+     tree cv_qualifier;
+     tree string;
+     tree outputs;
+     tree inputs;
+     tree clobbers;
 {
-  int noutputs = list_length (outputs);
-  register int i;
-  /* o[I] is the place that output number I should be written.  */
-  register tree *o = (tree *) alloca (noutputs * sizeof (tree));
-  register tree tail;
+  tree tail;
 
-  if (TREE_CODE (string) == ADDR_EXPR)
-    string = TREE_OPERAND (string, 0);
-  if (last_tree && TREE_CODE (string) != STRING_CST)
+  if (TREE_CHAIN (string))
+    string = combine_strings (string);
+  if (TREE_CODE (string) != STRING_CST)
     {
       error ("asm template is not a string constant");
-      return;
+      return NULL_TREE;
     }
 
-  /* Record the contents of OUTPUTS before it is modified.  */
-  for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
+  if (cv_qualifier != NULL_TREE
+      && cv_qualifier != ridpointers[(int) RID_VOLATILE])
+    {
+      warning ("%s qualifier ignored on asm",
+              IDENTIFIER_POINTER (cv_qualifier));
+      cv_qualifier = NULL_TREE;
+    }
+
+  /* We can remove output conversions that change the type,
+     but not the mode.  */
+  for (tail = outputs; tail; tail = TREE_CHAIN (tail))
     {
       tree output = TREE_VALUE (tail);
 
-      /* We can remove conversions that just change the type, not the mode.  */
       STRIP_NOPS (output);
-      o[i] = output;
+      TREE_VALUE (tail) = output;
 
       /* Allow conversions as LHS here.  build_modify_expr as called below
         will do the right thing with them.  */
@@ -6311,29 +6860,54 @@ c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
             || TREE_CODE (output) == FIX_CEIL_EXPR)
        output = TREE_OPERAND (output, 0);
 
-      if (last_tree)
-       lvalue_or_else (o[i], "invalid lvalue in asm statement");
+      lvalue_or_else (TREE_VALUE (tail), "invalid lvalue in asm statement");
+    }
+
+  /* Remove output conversions that change the type but not the mode.  */
+  for (tail = outputs; tail; tail = TREE_CHAIN (tail))
+    {
+      tree output = TREE_VALUE (tail);
+      STRIP_NOPS (output);
+      TREE_VALUE (tail) = output;
     }
 
-  /* Perform default conversions on array and function inputs.  */
-  /* Don't do this for other types--
-     it would screw up operands expected to be in memory.  */
-  for (i = 0, tail = inputs; tail; tail = TREE_CHAIN (tail), i++)
+  /* Perform default conversions on array and function inputs. 
+     Don't do this for other types as it would screw up operands
+     expected to be in memory.  */
+  for (tail = inputs; tail; tail = TREE_CHAIN (tail))
     if (TREE_CODE (TREE_TYPE (TREE_VALUE (tail))) == ARRAY_TYPE
        || TREE_CODE (TREE_TYPE (TREE_VALUE (tail))) == FUNCTION_TYPE)
       TREE_VALUE (tail) = default_conversion (TREE_VALUE (tail));
 
-  if (last_tree)
-    {
-      add_stmt (build_stmt (ASM_STMT, 
-                           vol ? ridpointers[(int) RID_VOLATILE] : NULL_TREE,
-                           string, outputs, inputs, clobbers));
-      return;
-    }
+  return add_stmt (build_stmt (ASM_STMT, cv_qualifier, string,
+                              outputs, inputs, clobbers));
+}
+
+/* Expand an ASM statement with operands, handling output operands
+   that are not variables or INDIRECT_REFS by transforming such
+   cases into cases that expand_asm_operands can handle.
 
-  /* Generate the ASM_OPERANDS insn;
-     store into the TREE_VALUEs of OUTPUTS some trees for
-     where the values were actually stored.  */
+   Arguments are same as for expand_asm_operands.  */
+
+void
+c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
+     tree string, outputs, inputs, clobbers;
+     int vol;
+     const char *filename;
+     int line;
+{
+  int noutputs = list_length (outputs);
+  register int i;
+  /* o[I] is the place that output number I should be written.  */
+  register tree *o = (tree *) alloca (noutputs * sizeof (tree));
+  register tree tail;
+
+  /* Record the contents of OUTPUTS before it is modified.  */
+  for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
+    o[i] = TREE_VALUE (tail);
+
+  /* Generate the ASM_OPERANDS insn; store into the TREE_VALUEs of
+     OUTPUTS some trees for where the values were actually stored.  */
   expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line);
 
   /* Copy all the intermediate outputs into the specified outputs.  */
@@ -6371,7 +6945,7 @@ c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
    RETVAL is the expression for what to return,
    or a null pointer for `return;' with no value.  */
 
-void
+tree
 c_expand_return (retval)
      tree retval;
 {
@@ -6401,7 +6975,7 @@ c_expand_return (retval)
       tree inner;
 
       if (t == error_mark_node)
-       return;
+       return NULL_TREE;
 
       inner = t = convert (TREE_TYPE (res), t);
 
@@ -6460,7 +7034,7 @@ c_expand_return (retval)
       current_function_returns_value = 1;
     }
 
- add_stmt (build_return_stmt (retval));
return add_stmt (build_return_stmt (retval));
 }
 \f
 struct c_switch {
@@ -6500,8 +7074,7 @@ c_start_case (exp)
       code = TREE_CODE (TREE_TYPE (exp));
       type = TREE_TYPE (exp);
 
-      if (code != INTEGER_TYPE 
-         && code != ENUMERAL_TYPE 
+      if (! INTEGRAL_TYPE_P (type)
          && code != ERROR_MARK)
        {
          error ("switch quantity not an integer");
@@ -6542,20 +7115,27 @@ c_start_case (exp)
 
 /* Process a case label.  */
 
-void
+tree
 do_case (low_value, high_value)
      tree low_value;
      tree high_value;
 {
+  tree label = NULL_TREE;
+
   if (switch_stack)
-    c_add_case_label (switch_stack->cases, 
-                     SWITCH_COND (switch_stack->switch_stmt), 
-                     low_value, 
-                     high_value);
+    {
+      label = c_add_case_label (switch_stack->cases, 
+                               SWITCH_COND (switch_stack->switch_stmt), 
+                               low_value, high_value);
+      if (label == error_mark_node)
+       label = NULL_TREE;
+    }
   else if (low_value)
     error ("case label not within a switch statement");
   else
     error ("`default' label not within a switch statement");
+
+  return label;
 }
 
 /* Finish the switch statement.  */