OSDN Git Service

(sparc_builtin_saveregs): New function.
[pf3gnuchains/gcc-fork.git] / gcc / c-typeck.c
index 6a52b41..98a3c9e 100644 (file)
@@ -56,6 +56,8 @@ static void pedantic_lvalue_warning ();
 tree truthvalue_conversion ();
 void incomplete_type_error ();
 void readonly_warning ();
+static tree internal_build_compound_expr ();
+
 \f
 /* Do `exp = require_complete_type (exp);' to make sure exp
    does not have an incomplete type.  (That includes void types.)  */
@@ -228,9 +230,11 @@ common_type (t1, t2)
       else return t2;
 
     case POINTER_TYPE:
-#if 0
       /* For two pointers, do this recursively on the target type,
         and combine the qualifiers of the two types' targets.  */
+      /* This code was turned off; I don't know why.
+        But ANSI C specifies doing this with the qualifiers.
+        So I turned it on again.  */
       {
        tree target = common_type (TYPE_MAIN_VARIANT (TREE_TYPE (t1)),
                                   TYPE_MAIN_VARIANT (TREE_TYPE (t2)));
@@ -240,8 +244,9 @@ common_type (t1, t2)
          = TYPE_VOLATILE (TREE_TYPE (t1)) || TYPE_VOLATILE (TREE_TYPE (t2));
        return build_pointer_type (c_build_type_variant (target, constp, volatilep));
       }
-#endif
+#if 0
       return build_pointer_type (common_type (TREE_TYPE (t1), TREE_TYPE (t2)));
+#endif
 
     case ARRAY_TYPE:
       {
@@ -699,6 +704,7 @@ c_sizeof (type)
      tree type;
 {
   enum tree_code code = TREE_CODE (type);
+  tree t;
 
   if (code == FUNCTION_TYPE)
     {
@@ -721,8 +727,12 @@ c_sizeof (type)
     }
 
   /* Convert in case a char is more than one unit.  */
-  return size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type), 
-                    size_int (TYPE_PRECISION (char_type_node)));
+  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)
+    force_fit_type (t);
+  return t;
 }
 
 tree
@@ -730,6 +740,7 @@ c_sizeof_nowarn (type)
      tree type;
 {
   enum tree_code code = TREE_CODE (type);
+  tree t;
 
   if (code == FUNCTION_TYPE
       || code == VOID_TYPE
@@ -739,8 +750,10 @@ c_sizeof_nowarn (type)
     return size_int (0);
 
   /* Convert in case a char is more than one unit.  */
-  return size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type), 
-                    size_int (TYPE_PRECISION (char_type_node)));
+  t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type), 
+                 size_int (TYPE_PRECISION (char_type_node)));
+  force_fit_type (t);
+  return t;
 }
 
 /* Compute the size to increment a pointer by.  */
@@ -750,6 +763,7 @@ c_size_in_bytes (type)
      tree type;
 {
   enum tree_code code = TREE_CODE (type);
+  tree t;
 
   if (code == FUNCTION_TYPE)
     return size_int (1);
@@ -764,8 +778,10 @@ c_size_in_bytes (type)
     }
 
   /* Convert in case a char is more than one unit.  */
-  return size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type), 
+  t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type), 
                     size_int (BITS_PER_UNIT));
+  force_fit_type (t);
+  return t;
 }
 
 /* Implement the __alignof keyword: Return the minimum required
@@ -785,22 +801,12 @@ c_alignof (type)
 
   return size_int (TYPE_ALIGN (type) / BITS_PER_UNIT);
 }
-
-/* Print a warning if a constant expression had overflow in folding.
-   This doesn't really work--it is waiting for changes in fold.  */
-
-void
-constant_expression_warning (value)
-     tree value;
-{
-  if (TREE_CODE (value) == NON_LVALUE_EXPR && TREE_CONSTANT_OVERFLOW (value))
-    pedwarn ("overflow in constant expression");
-}
 \f
 /* Implement the __alignof keyword: Return the minimum required
    alignment of EXPR, measured in bytes.  For VAR_DECL's and
    FIELD_DECL's return DECL_ALIGN (which can be set from an
    "aligned" __attribute__ specification).  */
+
 tree
 c_alignof_expr (expr)
      tree expr;
@@ -1128,8 +1134,9 @@ build_indirect_ref (ptr, errorstring)
        /* A de-reference of a pointer to const is not a const.  It is valid
           to change it via some other pointer.  */
        TREE_READONLY (ref) = TYPE_READONLY (t);
-       TREE_SIDE_EFFECTS (ref) = TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer);
-       TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t);
+       TREE_SIDE_EFFECTS (ref)
+         = TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer) || flag_volatile;
+       TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t) || flag_volatile;
        return ref;
       }
   else if (TREE_CODE (pointer) != ERROR_MARK)
@@ -1280,6 +1287,7 @@ build_array_ref (array, index)
 #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
 {
@@ -1306,8 +1314,10 @@ static format_char_info print_table[]
       { "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,   NULL,   NULL,   "-w" },
-      { "s",           1,      T_C,    NULL,   NULL,   NULL,   "-wp" },
+      { "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 }
@@ -1318,7 +1328,10 @@ 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,   "*" },
-      { "s[c",         1,      T_C,    NULL,   NULL,   NULL,   "*" },
+      { "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 }
@@ -1557,11 +1570,6 @@ check_format (info, params)
          if (*format_chars == '.')
            {
              precise = TRUE;
-             /* "For d, i, o, u, x, and X conversions,
-                if a precision is specified, the 0 flag will be ignored.
-                For other conversions, the behavior is undefined."  */
-             if (index (flag_chars, '0') != 0)
-               warning ("precision and `0' flag both used in one %%-sequence");
              ++format_chars;
              if (*format_chars != '*' && !ISDIGIT (*format_chars))
                warning ("`.' not followed by `*' or digit in format");
@@ -1625,7 +1633,7 @@ check_format (info, params)
        }
       if (fci->format_chars == 0)
        {
-         if (format_char >= 040 && format_char <= 0177)
+         if (format_char >= 040 && format_char < 0177)
            sprintf (message,
                     "unknown conversion type character `%c' in format",
                     format_char);
@@ -1668,6 +1676,16 @@ check_format (info, params)
              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;
@@ -2335,6 +2353,7 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
     case TRUTH_ORIF_EXPR:
     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))
        {
@@ -2357,12 +2376,17 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
        {
          if (TREE_CODE (op1) == INTEGER_CST)
            {
-             if (TREE_INT_CST_LOW (op1) > 0)
-               short_shift = 1;
-             else if (TREE_INT_CST_LOW (op1) < 0)
-               warning ("shift count is negative");
-             if (TREE_INT_CST_LOW (op1) >= TYPE_PRECISION (type0))
-               warning ("shift count >= width of type");
+             if (tree_int_cst_lt (op1, integer_zero_node))
+               warning ("right shift count is negative");
+             else
+               {
+                 if (TREE_INT_CST_LOW (op1) | TREE_INT_CST_HIGH (op1))
+                   short_shift = 1;
+                 if (TREE_INT_CST_HIGH (op1) != 0
+                     || ((unsigned HOST_WIDE_INT) TREE_INT_CST_LOW (op1)
+                         >= TYPE_PRECISION (type0)))
+                   warning ("right shift count >= width of type");
+               }
            }
          /* Use the type of the value to be shifted.
             This is what most traditional C compilers do.  */
@@ -2382,12 +2406,15 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
     case LSHIFT_EXPR:
       if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
        {
-         if (TREE_CODE (op1) == INTEGER_CST
-             && TREE_INT_CST_LOW (op1) < 0)
-           warning ("shift count is negative");
-         if (TREE_CODE (op1) == INTEGER_CST
-             && TREE_INT_CST_LOW (op1) >= TYPE_PRECISION (type0))
-           warning ("shift count >= width of type");
+         if (TREE_CODE (op1) == INTEGER_CST)
+           {
+             if (tree_int_cst_lt (op1, integer_zero_node))
+               warning ("left shift count is negative");
+             else if (TREE_INT_CST_HIGH (op1) != 0
+                      || ((unsigned HOST_WIDE_INT) TREE_INT_CST_LOW (op1)
+                          >= TYPE_PRECISION (type0)))
+               warning ("left shift count >= width of type");
+           }
          /* Use the type of the value to be shifted.
             This is what most traditional C compilers do.  */
          result_type = type0;
@@ -2407,12 +2434,15 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
     case LROTATE_EXPR:
       if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
        {
-         if (TREE_CODE (op1) == INTEGER_CST
-             && TREE_INT_CST_LOW (op1) < 0)
-           warning ("shift count is negative");
-         if (TREE_CODE (op1) == INTEGER_CST
-             && TREE_INT_CST_LOW (op1) >= TYPE_PRECISION (type0))
-           warning ("shift count >= width of type");
+         if (TREE_CODE (op1) == INTEGER_CST)
+           {
+             if (tree_int_cst_lt (op1, integer_zero_node))
+               warning ("shift count is negative");
+             else if (TREE_INT_CST_HIGH (op1) != 0
+                      || ((unsigned HOST_WIDE_INT) TREE_INT_CST_LOW (op1)
+                          >= TYPE_PRECISION (type0)))
+               warning ("shift count >= width of type");
+           }
          /* Use the type of the value to be shifted.
             This is what most traditional C compilers do.  */
          result_type = type0;
@@ -3001,6 +3031,7 @@ build_unary_op (code, xarg, noconvert)
            case FIX_FLOOR_EXPR:
            case FIX_ROUND_EXPR:
            case FIX_CEIL_EXPR:
+             pedantic_lvalue_warning (CONVERT_EXPR);
              /* If the real type has the same machine representation
                 as the type it is cast to, we can make better output
                 by adding directly to the inside of the cast.  */
@@ -3012,7 +3043,6 @@ build_unary_op (code, xarg, noconvert)
              else
                {
                  tree incremented, modify, value;
-                 pedantic_lvalue_warning (CONVERT_EXPR);
                  arg = stabilize_reference (arg);
                  if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
                    value = arg;
@@ -3166,8 +3196,11 @@ build_unary_op (code, xarg, noconvert)
          addr = build1 (code, argtype, arg);
 
        /* Address of a static or external variable or
-          function counts as a constant */
-       TREE_CONSTANT (addr) = staticp (arg);
+          file-scope function counts as a constant.  */
+       if (staticp (arg)
+           && ! (TREE_CODE (arg) == FUNCTION_DECL
+                 && DECL_CONTEXT (arg) != 0))
+         TREE_CONSTANT (addr) = 1;
        return addr;
       }
     }
@@ -3545,8 +3578,8 @@ build_conditional_expr (ifexp, op1, op2)
   /* Merge const and volatile flags of the incoming types.  */
   result_type
     = build_type_variant (result_type,
-                         TYPE_READONLY (op1) || TYPE_READONLY (op2),
-                         TYPE_VOLATILE (op1) || TYPE_VOLATILE (op2));
+                         TREE_READONLY (op1) || TREE_READONLY (op2),
+                         TREE_THIS_VOLATILE (op1) || TREE_THIS_VOLATILE (op2));
     
   if (result_type != TREE_TYPE (op1))
     op1 = convert (result_type, op1);
@@ -3602,6 +3635,14 @@ tree
 build_compound_expr (list)
      tree list;
 {
+  internal_build_compound_expr (list, TRUE);
+}
+
+static tree
+internal_build_compound_expr (list, first_p)
+     tree list;
+     int first_p;
+{
   register tree rest;
 
   if (TREE_CHAIN (list) == 0)
@@ -3614,7 +3655,10 @@ build_compound_expr (list)
        list = TREE_OPERAND (list, 0);
 #endif
 
-       return TREE_VALUE (list);
+      /* Don't let (0, 0) be null pointer constant.  */
+      if (!first_p && integer_zerop (TREE_VALUE (list)))
+       return non_lvalue (TREE_VALUE (list));
+      return TREE_VALUE (list);
     }
 
   if (TREE_CHAIN (list) != 0 && TREE_CHAIN (TREE_CHAIN (list)) == 0)
@@ -3625,7 +3669,7 @@ build_compound_expr (list)
          = default_conversion (TREE_VALUE (TREE_CHAIN (list)));
     }
 
-  rest = build_compound_expr (TREE_CHAIN (list));
+  rest = internal_build_compound_expr (TREE_CHAIN (list), FALSE);
 
   if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)))
     return rest;
@@ -3739,15 +3783,20 @@ build_c_cast (type, expr)
 
       if (TREE_CODE (type) == INTEGER_TYPE
          && TREE_CODE (otype) == POINTER_TYPE
-         && TYPE_PRECISION (type) != TYPE_PRECISION (otype))
+         && TYPE_PRECISION (type) != TYPE_PRECISION (otype)
+         && !TREE_CONSTANT (value))
        warning ("cast from pointer to integer of different size");
 
       if (TREE_CODE (type) == POINTER_TYPE
          && TREE_CODE (otype) == INTEGER_TYPE
          && TYPE_PRECISION (type) != TYPE_PRECISION (otype)
+#if 0
          /* Don't warn about converting 0 to pointer,
             provided the 0 was explicit--not cast or made by folding.  */
-         && !(TREE_CODE (value) == INTEGER_CST && integer_zerop (value)))
+         && !(TREE_CODE (value) == INTEGER_CST && integer_zerop (value))
+#endif
+         /* Don't warn about converting any constant.  */
+         && !TREE_CONSTANT (value))
        warning ("cast to pointer from integer of different size");
 
       value = convert (type, value);
@@ -4123,8 +4172,9 @@ warn_for_assignment (msg, opname, function, argnum)
    arithmetic-combinations of integers.  */
 
 static tree
-initializer_constant_valid_p (value)
+initializer_constant_valid_p (value, endtype)
      tree value;
+     tree endtype;
 {
   switch (TREE_CODE (value))
     {
@@ -4140,29 +4190,30 @@ initializer_constant_valid_p (value)
       return TREE_OPERAND (value, 0);
 
     case NON_LVALUE_EXPR:
-      return initializer_constant_valid_p (TREE_OPERAND (value, 0));
+      return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
 
     case CONVERT_EXPR:
     case NOP_EXPR:
       /* Allow conversions between pointer types.  */
       if (TREE_CODE (TREE_TYPE (value)) == POINTER_TYPE
          && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == POINTER_TYPE)
-       return initializer_constant_valid_p (TREE_OPERAND (value, 0));
+       return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
       /* Allow conversions between real types.  */
       if (TREE_CODE (TREE_TYPE (value)) == REAL_TYPE
          && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == REAL_TYPE)
-       return initializer_constant_valid_p (TREE_OPERAND (value, 0));
+       return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
       /* Allow length-preserving conversions between integer types.  */
       if (TREE_CODE (TREE_TYPE (value)) == INTEGER_TYPE
          && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == INTEGER_TYPE
          && tree_int_cst_equal (TYPE_SIZE (TREE_TYPE (value)),
                                 TYPE_SIZE (TREE_TYPE (TREE_OPERAND (value, 0)))))
-       return initializer_constant_valid_p (TREE_OPERAND (value, 0));
+       return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
       /* Allow conversions between integer types only if explicit value.  */
       if (TREE_CODE (TREE_TYPE (value)) == INTEGER_TYPE
          && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == INTEGER_TYPE)
        {
-         tree inner = initializer_constant_valid_p (TREE_OPERAND (value, 0));
+         tree inner = initializer_constant_valid_p (TREE_OPERAND (value, 0),
+                                                    endtype);
          if (inner == null_pointer_node)
            return null_pointer_node;
          return 0;
@@ -4172,16 +4223,23 @@ initializer_constant_valid_p (value)
          && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == POINTER_TYPE
          && tree_int_cst_equal (TYPE_SIZE (TREE_TYPE (value)),
                                 TYPE_SIZE (TREE_TYPE (TREE_OPERAND (value, 0)))))
-       return initializer_constant_valid_p (TREE_OPERAND (value, 0));
+       return initializer_constant_valid_p (TREE_OPERAND (value, 0),
+                                            endtype);
       /* Allow conversions to union types if the value inside is okay.  */
       if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE)
-       return initializer_constant_valid_p (TREE_OPERAND (value, 0));
+       return initializer_constant_valid_p (TREE_OPERAND (value, 0),
+                                            endtype);
       return 0;
 
     case PLUS_EXPR:
+      if (TREE_CODE (endtype) == INTEGER_TYPE
+         && TYPE_PRECISION (endtype) < POINTER_SIZE)
+       return 0;
       {
-       tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0));
-       tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1));
+       tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
+                                                   endtype);
+       tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
+                                                   endtype);
        /* If either term is absolute, use the other terms relocation.  */
        if (valid0 == null_pointer_node)
          return valid1;
@@ -4191,9 +4249,14 @@ initializer_constant_valid_p (value)
       }
 
     case MINUS_EXPR:
+      if (TREE_CODE (endtype) == INTEGER_TYPE
+         && TYPE_PRECISION (endtype) < POINTER_SIZE)
+       return 0;
       {
-       tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0));
-       tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1));
+       tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
+                                                   endtype);
+       tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
+                                                   endtype);
        /* Win if second argument is absolute.  */
        if (valid1 == null_pointer_node)
          return valid0;
@@ -4245,7 +4308,7 @@ store_init_value (decl, init)
       value = error_mark_node;
     }
   else if (TREE_STATIC (decl)
-          && initializer_constant_valid_p (value) == 0)
+          && initializer_constant_valid_p (value, TREE_TYPE (value)) == 0)
     {
       error ("initializer for static variable uses complicated arithmetic");
       value = error_mark_node;
@@ -4635,7 +4698,8 @@ digest_init (type, init, tail, require_constant, constructor_constant, ofwhat)
                      " for `%s'", ofwhat);
          inside_init = error_mark_node;
        }
-      else if (require_constant && initializer_constant_valid_p (inside_init) == 0)
+      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);
@@ -4666,7 +4730,8 @@ digest_init (type, init, tail, require_constant, constructor_constant, ofwhat)
                      " for `%s'", ofwhat);
          element = error_mark_node;
        }
-      else if (require_constant && initializer_constant_valid_p (element) == 0)
+      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);
@@ -4770,7 +4835,8 @@ digest_init (type, init, tail, require_constant, constructor_constant, ofwhat)
                      " for `%s'", ofwhat);
          inside_init = error_mark_node;
        }
-      else if (require_constant && initializer_constant_valid_p (inside_init) == 0)
+      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);
@@ -4885,6 +4951,10 @@ process_init_constructor (type, init, elts, constant_value, constant_element,
       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
@@ -4907,23 +4977,82 @@ process_init_constructor (type, init, elts, constant_value, constant_element,
       /* Don't leave the loop based on index if the next item has an explicit
         index value that will override it. */
 
-      for (current_index = min_index; tail != 0;
+      for (current_index = min_index; tail != 0 || end_index;
           current_index = fold (build (PLUS_EXPR, bound_type,
                                        current_index, one)))
        {
-         register tree next1;
+         register tree next1 = 0;
+
+         /* 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;
+           }
 
          /* If this element specifies an index,
             move to that index before storing it in the new list.  */
-         if (TREE_PURPOSE (tail) != 0)
+         else if (TREE_PURPOSE (tail) != 0)
            {
              int win = 0;
              tree index = TREE_PURPOSE (tail);
 
-             if (index && TREE_CODE (index) == NON_LVALUE_EXPR)
+             if (index && (TREE_CODE (index) == NON_LVALUE_EXPR
+                           || TREE_CODE (index) == NOP_EXPR))
                index = TREE_OPERAND (index, 0);
 
-             if (TREE_CODE (index) == IDENTIFIER_NODE)
+             /* 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);
+
+                 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 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");
@@ -4934,14 +5063,20 @@ process_init_constructor (type, init, elts, constant_value, constant_element,
                current_index = index, win = 1;
 
              if (!win)
-               TREE_VALUE (tail) = error_mark_node;
+               {
+                 /* If there was an error, end the current range.  */
+                 end_index = 0;
+                 TREE_VALUE (tail) = error_mark_node;
+               }
            }
 
          if (max_index && tree_int_cst_lt (max_index, current_index))
            break;  /* Stop if we've indeed run out of elements. */
 
          /* Now digest the value specified.  */
-         if (TREE_VALUE (tail) != 0)
+         if (next1 != 0)
+           ;
+         else if (TREE_VALUE (tail) != 0)
            {
              tree tail1 = tail;
 
@@ -4977,11 +5112,14 @@ process_init_constructor (type, init, elts, constant_value, constant_element,
              tail = TREE_CHAIN (tail);
            }
 
+         if (end_index != 0)
+           range_val = next1;
+
          if (next1 == error_mark_node)
            erroneous = 1;
          else if (!TREE_CONSTANT (next1))
            allconstant = 0;
-         else if (initializer_constant_valid_p (next1) == 0)
+         else if (initializer_constant_valid_p (next1, TREE_TYPE (next1)) == 0)
            allsimple = 0;
 
          /* Now store NEXT1 in the list, I elements from the *end*.
@@ -5082,7 +5220,7 @@ process_init_constructor (type, init, elts, constant_value, constant_element,
            erroneous = 1;
          else if (!TREE_CONSTANT (next1))
            allconstant = 0;
-         else if (initializer_constant_valid_p (next1) == 0)
+         else if (initializer_constant_valid_p (next1, TREE_TYPE (next1)) == 0)
            allsimple = 0;
 
          /* Now store NEXT1 in the list, I elements from the *end*.
@@ -5116,6 +5254,12 @@ process_init_constructor (type, init, elts, constant_value, constant_element,
 
       /* For a union, get the initializer for 1 fld.  */
 
+      if (tail == 0)
+       {
+         error ("empty initializer for union");
+         tail = build_tree_list (0, 0);
+       }
+
       /* If this element specifies a field, initialize via that field.  */
       if (TREE_PURPOSE (tail) != 0)
        {
@@ -5170,7 +5314,7 @@ process_init_constructor (type, init, elts, constant_value, constant_element,
        erroneous = 1;
       else if (!TREE_CONSTANT (next1))
        allconstant = 0;
-      else if (initializer_constant_valid_p (next1) == 0)
+      else if (initializer_constant_valid_p (next1, TREE_TYPE (next1)) == 0)
        allsimple = 0;
       members = tree_cons (field, next1, members);
     }