OSDN Git Service

* doc/fragments.texi, doc/trouble.texi: Remove links to old
[pf3gnuchains/gcc-fork.git] / gcc / c-typeck.c
index 3cbf6c6..64f0f07 100644 (file)
@@ -2,22 +2,22 @@
    Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
    1998, 1999, 2000, 2001 Free Software Foundation, Inc.
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
 
 
 /* This file is part of the C front end.
@@ -41,6 +41,7 @@ Boston, MA 02111-1307, USA.  */
 #include "toplev.h"
 #include "intl.h"
 #include "ggc.h"
+#include "target.h"
 
 /* Nonzero if we've already printed a "missing braces around initializer"
    message within this initializer.  */
@@ -54,11 +55,12 @@ static int comp_target_types                PARAMS ((tree, tree));
 static int function_types_compatible_p PARAMS ((tree, tree));
 static int type_lists_compatible_p     PARAMS ((tree, tree));
 static tree decl_constant_value_for_broken_optimization PARAMS ((tree));
-static tree lookup_field               PARAMS ((tree, tree, tree *));
+static tree default_function_array_conversion  PARAMS ((tree));
+static tree lookup_field               PARAMS ((tree, tree));
 static tree convert_arguments          PARAMS ((tree, tree, tree, tree));
 static tree pointer_int_sum            PARAMS ((enum tree_code, tree, tree));
 static tree pointer_diff               PARAMS ((tree, tree));
-static tree unary_complex_lvalue       PARAMS ((enum tree_code, tree));
+static tree unary_complex_lvalue       PARAMS ((enum tree_code, tree, int));
 static void pedantic_lvalue_warning    PARAMS ((enum tree_code));
 static tree internal_build_compound_expr PARAMS ((tree, int));
 static tree convert_for_assignment     PARAMS ((tree, tree, const char *,
@@ -190,8 +192,8 @@ tree
 common_type (t1, t2)
      tree t1, t2;
 {
-  register enum tree_code code1;
-  register enum tree_code code2;
+  enum tree_code code1;
+  enum tree_code code2;
   tree attributes;
 
   /* Save time if the two types are the same.  */
@@ -205,7 +207,7 @@ common_type (t1, t2)
     return t1;
 
   /* Merge the attributes.  */
-  attributes = merge_machine_type_attributes (t1, t2);
+  attributes = (*targetm.merge_type_attributes) (t1, t2);
 
   /* Treat an enum type as the unsigned integer type of the same width.  */
 
@@ -435,8 +437,8 @@ int
 comptypes (type1, type2)
      tree type1, type2;
 {
-  register tree t1 = type1;
-  register tree t2 = type2;
+  tree t1 = type1;
+  tree t2 = type2;
   int attrval, val;
 
   /* Suppress errors caused by previously reported errors.  */
@@ -482,12 +484,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 = (*targetm.comp_type_attributes) (t1, t2)))
      return 0;
 
   /* 1 if no need for warning yet, 2 if warning cause has been seen.  */
@@ -508,6 +506,8 @@ comptypes (type1, type2)
       {
        tree d1 = TYPE_DOMAIN (t1);
        tree d2 = TYPE_DOMAIN (t2);
+       bool d1_variable, d2_variable;
+       bool d1_zero, d2_zero;
        val = 1;
 
        /* Target types must match incl. qualifiers.  */
@@ -516,14 +516,25 @@ comptypes (type1, type2)
          return 0;
 
        /* Sizes must match unless one is missing or variable.  */
-       if (d1 == 0 || d2 == 0 || d1 == d2
-           || TREE_CODE (TYPE_MIN_VALUE (d1)) != INTEGER_CST
-           || TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST
-           || TREE_CODE (TYPE_MAX_VALUE (d1)) != INTEGER_CST
-           || TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST)
+       if (d1 == 0 || d2 == 0 || d1 == d2)
          break;
 
-       if (! tree_int_cst_equal (TYPE_MIN_VALUE (d1), TYPE_MIN_VALUE (d2))
+       d1_zero = ! TYPE_MAX_VALUE (d1);
+       d2_zero = ! TYPE_MAX_VALUE (d2);
+
+       d1_variable = (! d1_zero
+                      && (TREE_CODE (TYPE_MIN_VALUE (d1)) != INTEGER_CST
+                          || TREE_CODE (TYPE_MAX_VALUE (d1)) != INTEGER_CST));
+       d2_variable = (! d2_zero
+                      && (TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST
+                          || TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST));
+
+       if (d1_variable || d2_variable)
+         break;
+       if (d1_zero && d2_zero)
+         break;
+       if (d1_zero || d2_zero
+           || ! tree_int_cst_equal (TYPE_MIN_VALUE (d1), TYPE_MIN_VALUE (d2))
            || ! tree_int_cst_equal (TYPE_MAX_VALUE (d1), TYPE_MAX_VALUE (d2)))
          val = 0;
 
@@ -651,7 +662,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.  */
@@ -785,82 +797,7 @@ c_size_in_bytes (type)
                     size_int (TYPE_PRECISION (char_type_node)
                               / BITS_PER_UNIT));
 }
-
-/* Implement the __alignof keyword: Return the minimum required
-   alignment of TYPE, measured in bytes.  */
-
-tree
-c_alignof (type)
-     tree type;
-{
-  enum tree_code code = TREE_CODE (type);
-  tree t;
-
-  if (code == FUNCTION_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");
-      t = size_zero_node;
-    }
-  else
-    t = 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
-   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;
-{
-  tree t;
-
-  if (TREE_CODE (expr) == VAR_DECL)
-    t = size_int (DECL_ALIGN (expr) / BITS_PER_UNIT);
-  else if (TREE_CODE (expr) == COMPONENT_REF
-          && DECL_C_BIT_FIELD (TREE_OPERAND (expr, 1)))
-    {
-      error ("`__alignof' applied to a bit-field");
-      t = size_one_node;
-    }
-  else if (TREE_CODE (expr) == COMPONENT_REF
-      && TREE_CODE (TREE_OPERAND (expr, 1)) == FIELD_DECL)
-    t = size_int (DECL_ALIGN (TREE_OPERAND (expr, 1)) / BITS_PER_UNIT);
-  else if (TREE_CODE (expr) == INDIRECT_REF)
-    {
-      tree t = TREE_OPERAND (expr, 0);
-      tree best = t;
-      int bestalign = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (t)));
-      while (TREE_CODE (t) == NOP_EXPR
-             && TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == POINTER_TYPE)
-       {
-         int thisalign;
-
-         t = TREE_OPERAND (t, 0);
-         thisalign = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (t)));
-         if (thisalign > bestalign)
-           best = t, bestalign = thisalign;
-       }
-      return c_alignof (TREE_TYPE (TREE_TYPE (best)));
-    }
-  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).  */
 
 tree
@@ -902,6 +839,110 @@ decl_constant_value_for_broken_optimization (decl)
     return decl_constant_value (decl);
 }
 
+
+/* Perform the default conversion of arrays and functions to pointers.
+   Return the result of converting EXP.  For any other expression, just
+   return EXP.  */
+
+static tree
+default_function_array_conversion (exp)
+     tree exp;
+{
+  tree orig_exp;
+  tree type = TREE_TYPE (exp);
+  enum tree_code code = TREE_CODE (type);
+  int not_lvalue = 0;
+
+  /* Strip NON_LVALUE_EXPRs and no-op conversions, since we aren't using as
+     an lvalue. 
+
+     Do not use STRIP_NOPS here!  It will remove conversions from pointer
+     to integer and cause infinite recursion.  */
+  orig_exp = exp;
+  while (TREE_CODE (exp) == NON_LVALUE_EXPR
+        || (TREE_CODE (exp) == NOP_EXPR
+            && TREE_TYPE (TREE_OPERAND (exp, 0)) == TREE_TYPE (exp)))
+    {
+      if (TREE_CODE (exp) == NON_LVALUE_EXPR)
+       not_lvalue = 1;
+      exp = TREE_OPERAND (exp, 0);
+    }
+
+  /* Preserve the original expression code.  */
+  if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (exp))))
+    C_SET_EXP_ORIGINAL_CODE (exp, C_EXP_ORIGINAL_CODE (orig_exp));
+
+  if (code == FUNCTION_TYPE)
+    {
+      return build_unary_op (ADDR_EXPR, exp, 0);
+    }
+  if (code == ARRAY_TYPE)
+    {
+      tree adr;
+      tree restype = TREE_TYPE (type);
+      tree ptrtype;
+      int constp = 0;
+      int volatilep = 0;
+      int lvalue_array_p;
+
+      if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'r' || DECL_P (exp))
+       {
+         constp = TREE_READONLY (exp);
+         volatilep = TREE_THIS_VOLATILE (exp);
+       }
+
+      if (TYPE_QUALS (type) || constp || volatilep)
+       restype 
+         = c_build_qualified_type (restype,
+                                   TYPE_QUALS (type) 
+                                   | (constp * TYPE_QUAL_CONST)
+                                   | (volatilep * TYPE_QUAL_VOLATILE));
+
+      if (TREE_CODE (exp) == INDIRECT_REF)
+       return convert (TYPE_POINTER_TO (restype),
+                       TREE_OPERAND (exp, 0));
+
+      if (TREE_CODE (exp) == COMPOUND_EXPR)
+       {
+         tree op1 = default_conversion (TREE_OPERAND (exp, 1));
+         return build (COMPOUND_EXPR, TREE_TYPE (op1),
+                       TREE_OPERAND (exp, 0), op1);
+       }
+
+      lvalue_array_p = !not_lvalue && lvalue_p (exp);
+      if (!flag_isoc99 && !lvalue_array_p
+         && !(TREE_CODE (exp) == CONSTRUCTOR && TREE_STATIC (exp)))
+       {
+         /* Before C99, non-lvalue arrays do not decay to pointers.
+            Normally, using such an array would be invalid; but it can
+            be used correctly inside sizeof or as a statement expression.
+            Thus, do not give an error here; an error will result later.  */
+         return exp;
+       }
+
+      ptrtype = build_pointer_type (restype);
+
+      if (TREE_CODE (exp) == VAR_DECL)
+       {
+         /* ??? This is not really quite correct
+            in that the type of the operand of ADDR_EXPR
+            is not the target type of the type of the ADDR_EXPR itself.
+            Question is, can this lossage be avoided?  */
+         adr = build1 (ADDR_EXPR, ptrtype, exp);
+         if (mark_addressable (exp) == 0)
+           return error_mark_node;
+         TREE_CONSTANT (adr) = staticp (exp);
+         TREE_SIDE_EFFECTS (adr) = 0;   /* Default would be, same as EXP.  */
+         return adr;
+       }
+      /* This way is better for a COMPONENT_REF since it can
+        simplify the offset for a component.  */
+      adr = build_unary_op (ADDR_EXPR, exp, 1);
+      return convert (ptrtype, adr);
+    }
+  return exp;
+}
+
 /* Perform default promotions for C data used in expressions.
    Arrays and functions are converted to pointers;
    enumeral types or short or char, to int.
@@ -911,8 +952,12 @@ tree
 default_conversion (exp)
      tree exp;
 {
-  register tree type = TREE_TYPE (exp);
-  register enum tree_code code = TREE_CODE (type);
+  tree orig_exp;
+  tree type = TREE_TYPE (exp);
+  enum tree_code code = TREE_CODE (type);
+
+  if (code == FUNCTION_TYPE || code == ARRAY_TYPE)
+    return default_function_array_conversion (exp);
 
   /* Constants can be used directly unless they're not loadable.  */
   if (TREE_CODE (exp) == CONST_DECL)
@@ -932,11 +977,16 @@ default_conversion (exp)
 
      Do not use STRIP_NOPS here!  It will remove conversions from pointer
      to integer and cause infinite recursion.  */
+  orig_exp = exp;
   while (TREE_CODE (exp) == NON_LVALUE_EXPR
         || (TREE_CODE (exp) == NOP_EXPR
             && TREE_TYPE (TREE_OPERAND (exp, 0)) == TREE_TYPE (exp)))
     exp = TREE_OPERAND (exp, 0);
 
+  /* Preserve the original expression code.  */
+  if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (exp))))
+    C_SET_EXP_ORIGINAL_CODE (exp, C_EXP_ORIGINAL_CODE (orig_exp));
+
   /* Normally convert enums to int,
      but convert wide enums to something wider.  */
   if (code == ENUMERAL_TYPE)
@@ -982,83 +1032,23 @@ default_conversion (exp)
       error ("void value not ignored as it ought to be");
       return error_mark_node;
     }
-  if (code == FUNCTION_TYPE)
-    {
-      return build_unary_op (ADDR_EXPR, exp, 0);
-    }
-  if (code == ARRAY_TYPE)
-    {
-      register tree adr;
-      tree restype = TREE_TYPE (type);
-      tree ptrtype;
-      int constp = 0;
-      int volatilep = 0;
-
-      if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'r' || DECL_P (exp))
-       {
-         constp = TREE_READONLY (exp);
-         volatilep = TREE_THIS_VOLATILE (exp);
-       }
-
-      if (TYPE_QUALS (type) || constp || volatilep)
-       restype 
-         = c_build_qualified_type (restype,
-                                   TYPE_QUALS (type) 
-                                   | (constp * TYPE_QUAL_CONST)
-                                   | (volatilep * TYPE_QUAL_VOLATILE));
-
-      if (TREE_CODE (exp) == INDIRECT_REF)
-       return convert (TYPE_POINTER_TO (restype),
-                       TREE_OPERAND (exp, 0));
-
-      if (TREE_CODE (exp) == COMPOUND_EXPR)
-       {
-         tree op1 = default_conversion (TREE_OPERAND (exp, 1));
-         return build (COMPOUND_EXPR, TREE_TYPE (op1),
-                       TREE_OPERAND (exp, 0), op1);
-       }
-
-      if (! lvalue_p (exp)
-         && ! (TREE_CODE (exp) == CONSTRUCTOR && TREE_STATIC (exp)))
-       {
-         error ("invalid use of non-lvalue array");
-         return error_mark_node;
-       }
-
-      ptrtype = build_pointer_type (restype);
-
-      if (TREE_CODE (exp) == VAR_DECL)
-       {
-         /* ??? This is not really quite correct
-            in that the type of the operand of ADDR_EXPR
-            is not the target type of the type of the ADDR_EXPR itself.
-            Question is, can this lossage be avoided?  */
-         adr = build1 (ADDR_EXPR, ptrtype, exp);
-         if (mark_addressable (exp) == 0)
-           return error_mark_node;
-         TREE_CONSTANT (adr) = staticp (exp);
-         TREE_SIDE_EFFECTS (adr) = 0;   /* Default would be, same as EXP.  */
-         return adr;
-       }
-      /* This way is better for a COMPONENT_REF since it can
-        simplify the offset for a component.  */
-      adr = build_unary_op (ADDR_EXPR, exp, 1);
-      return convert (ptrtype, adr);
-    }
   return exp;
 }
 \f
-/* Look up component name in the structure type definition.
-
-   If this component name is found indirectly within an anonymous union,
-   store in *INDIRECT the component which directly contains
-   that anonymous union.  Otherwise, set *INDIRECT to 0.  */
+/* Look up COMPONENT in a structure or union DECL.
+
+   If the component name is not found, returns NULL_TREE.  Otherwise,
+   the return value is a TREE_LIST, with each TREE_VALUE a FIELD_DECL
+   stepping down the chain to the component, which is in the last
+   TREE_VALUE of the list.  Normally the list is of length one, but if
+   the component is embedded within (nested) anonymous structures or
+   unions, the list steps down the chain to the component.  */
      
 static tree
-lookup_field (type, component, indirect)
-     tree type, component;
-     tree *indirect;
+lookup_field (decl, component)
+     tree decl, component;
 {
+  tree type = TREE_TYPE (decl);
   tree field;
 
   /* If TYPE_LANG_SPECIFIC is set, then it is a sorted array of pointers
@@ -1084,18 +1074,15 @@ lookup_field (type, component, indirect)
              /* Step through all anon unions in linear fashion.  */
              while (DECL_NAME (field_array[bot]) == NULL_TREE)
                {
-                 tree anon = 0, junk;
-
                  field = field_array[bot++];
                  if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
                      || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
-                   anon = lookup_field (TREE_TYPE (field), component, &junk);
-
-                 if (anon != NULL_TREE)
                    {
-                     *indirect = field;
-                     return anon;
-                   }
+                     tree anon = lookup_field (field, component);
+
+                     if (anon)
+                       return tree_cons (NULL_TREE, field, anon);
+                   } 
                }
 
              /* Entire record is only anon unions.  */
@@ -1117,35 +1104,31 @@ lookup_field (type, component, indirect)
       if (DECL_NAME (field_array[bot]) == component)
        field = field_array[bot];
       else if (DECL_NAME (field) != component)
-       field = 0;
+       return NULL_TREE;
     }
   else
     {
       for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
        {
-         if (DECL_NAME (field) == NULL_TREE)
+         if (DECL_NAME (field) == NULL_TREE
+             && (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
+                 || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE))
            {
-             tree junk;
-             tree anon = 0;
+             tree anon = lookup_field (field, component);
 
-             if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
-                 || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
-               anon = lookup_field (TREE_TYPE (field), component, &junk);
-
-             if (anon != NULL_TREE)
-               {
-                 *indirect = field;
-                 return anon;
-               }
+             if (anon)
+               return tree_cons (NULL_TREE, field, anon);
            }
 
          if (DECL_NAME (field) == component)
            break;
        }
+
+      if (field == NULL_TREE)
+       return NULL_TREE;
     }
 
-  *indirect = NULL_TREE;
-  return field;
+  return tree_cons (NULL_TREE, field, NULL_TREE);
 }
 
 /* Make an expression to refer to the COMPONENT field of
@@ -1155,27 +1138,27 @@ tree
 build_component_ref (datum, component)
      tree datum, component;
 {
-  register tree type = TREE_TYPE (datum);
-  register enum tree_code code = TREE_CODE (type);
-  register tree field = NULL;
-  register tree ref;
+  tree type = TREE_TYPE (datum);
+  enum tree_code code = TREE_CODE (type);
+  tree field = NULL;
+  tree ref;
 
-  /* If DATUM is a COMPOUND_EXPR or COND_EXPR, move our reference inside it
-     unless we are not to support things not strictly ANSI.  */
+  /* If DATUM is a COMPOUND_EXPR, move our reference inside it.
+     If pedantic ensure that the arguments are not lvalues; otherwise,
+     if the component is an array, it would wrongly decay to a pointer in
+     C89 mode.
+     We cannot do this with a COND_EXPR, because in a conditional expression
+     the default promotions are applied to both sides, and this would yield
+     the wrong type of the result; for example, if the components have
+     type "char".  */
   switch (TREE_CODE (datum))
     {
     case COMPOUND_EXPR:
       {
        tree value = build_component_ref (TREE_OPERAND (datum, 1), component);
        return build (COMPOUND_EXPR, TREE_TYPE (value),
-                     TREE_OPERAND (datum, 0), value);
+                     TREE_OPERAND (datum, 0), pedantic_non_lvalue (value));
       }
-    case COND_EXPR:
-      return build_conditional_expr
-       (TREE_OPERAND (datum, 0),
-        build_component_ref (TREE_OPERAND (datum, 1), component),
-        build_component_ref (TREE_OPERAND (datum, 2), component));
-
     default:
       break;
     }
@@ -1184,15 +1167,13 @@ build_component_ref (datum, component)
 
   if (code == RECORD_TYPE || code == UNION_TYPE)
     {
-      tree indirect = 0;
-
       if (!COMPLETE_TYPE_P (type))
        {
          incomplete_type_error (NULL_TREE, type);
          return error_mark_node;
        }
 
-      field = lookup_field (type, component, &indirect);
+      field = lookup_field (datum, component);
 
       if (!field)
        {
@@ -1201,29 +1182,27 @@ build_component_ref (datum, component)
                 IDENTIFIER_POINTER (component));
          return error_mark_node;
        }
-      if (TREE_TYPE (field) == error_mark_node)
-       return error_mark_node;
 
-      /* If FIELD was found buried within an anonymous union,
-        make one COMPONENT_REF to get that anonymous union,
-        then fall thru to make a second COMPONENT_REF to get FIELD.  */
-      if (indirect != 0)
+      /* Chain the COMPONENT_REFs if necessary down to the FIELD.
+        This might be better solved in future the way the C++ front
+        end does it - by giving the anonymous entities each a
+        separate name and type, and then have build_component_ref
+        recursively call itself.  We can't do that here.  */
+      for (; field; field = TREE_CHAIN (field))
        {
-         ref = build (COMPONENT_REF, TREE_TYPE (indirect), datum, indirect);
-         if (TREE_READONLY (datum) || TREE_READONLY (indirect))
+         tree subdatum = TREE_VALUE (field);
+
+         if (TREE_TYPE (subdatum) == error_mark_node)
+           return error_mark_node;
+
+         ref = build (COMPONENT_REF, TREE_TYPE (subdatum), datum, subdatum);
+         if (TREE_READONLY (datum) || TREE_READONLY (subdatum))
            TREE_READONLY (ref) = 1;
-         if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (indirect))
+         if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (subdatum))
            TREE_THIS_VOLATILE (ref) = 1;
          datum = ref;
        }
 
-      ref = build (COMPONENT_REF, TREE_TYPE (field), datum, field);
-
-      if (TREE_READONLY (datum) || TREE_READONLY (field))
-       TREE_READONLY (ref) = 1;
-      if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (field))
-       TREE_THIS_VOLATILE (ref) = 1;
-
       return ref;
     }
   else if (code != ERROR_MARK)
@@ -1242,8 +1221,8 @@ build_indirect_ref (ptr, errorstring)
      tree ptr;
      const char *errorstring;
 {
-  register tree pointer = default_conversion (ptr);
-  register tree type = TREE_TYPE (pointer);
+  tree pointer = default_conversion (ptr);
+  tree type = TREE_TYPE (pointer);
 
   if (TREE_CODE (type) == POINTER_TYPE)
     {
@@ -1255,8 +1234,7 @@ build_indirect_ref (ptr, errorstring)
       else
        {
          tree t = TREE_TYPE (type);
-         register tree ref = build1 (INDIRECT_REF,
-                                     TYPE_MAIN_VARIANT (t), pointer);
+         tree ref = build1 (INDIRECT_REF, TYPE_MAIN_VARIANT (t), pointer);
 
          if (!COMPLETE_OR_VOID_TYPE_P (t) && TREE_CODE (t) != ARRAY_TYPE)
            {
@@ -1526,8 +1504,8 @@ tree
 build_function_call (function, params)
      tree function, params;
 {
-  register tree fntype, fundecl = 0;
-  register tree coerced_params;
+  tree fntype, fundecl = 0;
+  tree coerced_params;
   tree name = NULL_TREE, assembler_name = NULL_TREE, result;
 
   /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue.  */
@@ -1574,8 +1552,8 @@ build_function_call (function, params)
 
   /* Check for errors in format strings.  */
 
-  if (warn_format && (name || assembler_name))
-    check_function_format (NULL, name, assembler_name, coerced_params);
+  if (warn_format)
+    check_function_format (NULL, TYPE_ATTRIBUTES (fntype), coerced_params);
 
   /* Recognize certain built-in functions so we can make tree-codes
      other than CALL_EXPR.  We do this when it enables fold-const.c
@@ -1623,8 +1601,8 @@ static tree
 convert_arguments (typelist, values, name, fundecl)
      tree typelist, values, name, fundecl;
 {
-  register tree typetail, valtail;
-  register tree result = NULL;
+  tree typetail, valtail;
+  tree result = NULL;
   int parmnum;
 
   /* Scan the given expressions and types, producing individual
@@ -1634,8 +1612,8 @@ convert_arguments (typelist, values, name, fundecl)
        valtail;
        valtail = TREE_CHAIN (valtail), parmnum++)
     {
-      register tree type = typetail ? TREE_VALUE (typetail) : 0;
-      register tree val = TREE_VALUE (valtail);
+      tree type = typetail ? TREE_VALUE (typetail) : 0;
+      tree val = TREE_VALUE (valtail);
 
       if (type == void_type_node)
        {
@@ -1653,9 +1631,7 @@ convert_arguments (typelist, values, name, fundecl)
       if (TREE_CODE (val) == NON_LVALUE_EXPR)
        val = TREE_OPERAND (val, 0);
 
-      if (TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE
-         || TREE_CODE (TREE_TYPE (val)) == FUNCTION_TYPE)
-       val = default_conversion (val);
+      val = default_function_array_conversion (val);
 
       val = require_complete_type (val);
 
@@ -1716,7 +1692,8 @@ convert_arguments (typelist, values, name, fundecl)
                      tree type1 = TREE_TYPE (would_have_been);
 
                      if (TREE_CODE (type) == ENUMERAL_TYPE
-                         && type == TREE_TYPE (val))
+                         && (TYPE_MAIN_VARIANT (type)
+                             == TYPE_MAIN_VARIANT (TREE_TYPE (val))))
                        /* No warning if function asks for enum
                           and the actual arg is that enum type.  */
                        ;
@@ -1766,9 +1743,7 @@ convert_arguments (typelist, values, name, fundecl)
                                                fundecl, name, parmnum + 1);
              
              if (PROMOTE_PROTOTYPES
-                 && (TREE_CODE (type) == INTEGER_TYPE
-                     || TREE_CODE (type) == ENUMERAL_TYPE
-                     || TREE_CODE (type) == BOOLEAN_TYPE)
+                 && INTEGRAL_TYPE_P (type)
                  && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
                parmval = default_conversion (parmval);
            }
@@ -1818,11 +1793,9 @@ parser_build_binary_op (code, arg1, arg2)
   enum tree_code code1 = ERROR_MARK;
   enum tree_code code2 = ERROR_MARK;
 
-  if (class1 == 'e' || class1 == '1'
-      || class1 == '2' || class1 == '<')
+  if (IS_EXPR_CODE_CLASS (class1))
     code1 = C_EXP_ORIGINAL_CODE (arg1);
-  if (class2 == 'e' || class2 == '1'
-      || class2 == '2' || class2 == '<')
+  if (IS_EXPR_CODE_CLASS (class2))
     code2 = C_EXP_ORIGINAL_CODE (arg2);
 
   /* Check for cases such as x+y<<z which users are likely
@@ -1892,8 +1865,7 @@ parser_build_binary_op (code, arg1, arg2)
 
   /* Record the code that was specified in the source,
      for the sake of warnings about confusing nesting.  */
-  if (class == 'e' || class == '1'
-      || class == '2' || class == '<')
+  if (IS_EXPR_CODE_CLASS (class))
     C_SET_EXP_ORIGINAL_CODE (result, code);
   else
     {
@@ -1932,17 +1904,17 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
      int convert_p;
 {
   tree type0, type1;
-  register enum tree_code code0, code1;
+  enum tree_code code0, code1;
   tree op0, op1;
 
   /* Expression code to give to the expression when it is built.
      Normally this is CODE, which is what the caller asked for,
      but in some special cases we change it.  */
-  register enum tree_code resultcode = code;
+  enum tree_code resultcode = code;
 
   /* Data type in which the computation is to be performed.
      In the simplest cases this is the common type of the arguments.  */
-  register tree result_type = NULL;
+  tree result_type = NULL;
 
   /* Nonzero means operands have already been type-converted
      in whatever way is necessary.
@@ -2040,6 +2012,11 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
     case FLOOR_DIV_EXPR:
     case ROUND_DIV_EXPR:
     case EXACT_DIV_EXPR:
+      /* Floating point division by zero is a legitimate way to obtain
+        infinities and NaNs.  */
+      if (warn_div_by_zero && skip_evaluation == 0 && integer_zerop (op1))
+       warning ("division by zero");
+
       if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
           || code0 == COMPLEX_TYPE)
          && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
@@ -2093,6 +2070,9 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
 
     case TRUNC_MOD_EXPR:
     case FLOOR_MOD_EXPR:
+      if (warn_div_by_zero && skip_evaluation == 0 && integer_zerop (op1))
+       warning ("division by zero");
+
       if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
        {
          /* Although it would be tempting to shorten always here, that loses
@@ -2230,8 +2210,8 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
        short_compare = 1;
       else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
        {
-         register tree tt0 = TREE_TYPE (type0);
-         register tree tt1 = TREE_TYPE (type1);
+         tree tt0 = TREE_TYPE (type0);
+         tree tt1 = TREE_TYPE (type1);
          /* Anything compares with void *.  void * compares with anything.
             Otherwise, the targets must be compatible
             and both must be object or both incomplete.  */
@@ -2473,22 +2453,12 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
              /* We can shorten only if the shift count is less than the
                 number of bits in the smaller type size.  */
              && compare_tree_int (op1, TYPE_PRECISION (TREE_TYPE (arg0))) < 0
-             /* If arg is sign-extended and then unsigned-shifted,
-                we can simulate this with a signed shift in arg's type
-                only if the extended result is at least twice as wide
-                as the arg.  Otherwise, the shift could use up all the
-                ones made by sign-extension and bring in zeros.
-                We can't optimize that case at all, but in most machines
-                it never happens because available widths are 2**N.  */
-             && (!TREE_UNSIGNED (final_type)
-                 || unsigned_arg
-                 || (2 * TYPE_PRECISION (TREE_TYPE (arg0))
-                     <= TYPE_PRECISION (result_type))))
+             /* We cannot drop an unsigned shift after sign-extension.  */
+             && (!TREE_UNSIGNED (final_type) || unsigned_arg))
            {
              /* Do an unsigned shift if the operand was zero-extended.  */
              result_type
-               = signed_or_unsigned_type (unsigned_arg,
-                                          TREE_TYPE (arg0));
+               = signed_or_unsigned_type (unsigned_arg, TREE_TYPE (arg0));
              /* Convert value-to-be-shifted to that type.  */
              if (TREE_TYPE (op0) != result_type)
                op0 = convert (result_type, op0);
@@ -2661,8 +2631,8 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
     build_type = result_type;
 
   {
-    register tree result = build (resultcode, build_type, op0, op1);
-    register tree folded;
+    tree result = build (resultcode, build_type, op0, op1);
+    tree folded;
 
     folded = fold (result);
     if (folded == result)
@@ -2679,16 +2649,16 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
 static tree
 pointer_int_sum (resultcode, ptrop, intop)
      enum tree_code resultcode;
-     register tree ptrop, intop;
+     tree ptrop, intop;
 {
   tree size_exp;
 
-  register tree result;
-  register tree folded;
+  tree result;
+  tree folded;
 
   /* The result is a pointer of the same type that is being added.  */
 
-  register tree result_type = TREE_TYPE (ptrop);
+  tree result_type = TREE_TYPE (ptrop);
 
   if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE)
     {
@@ -2767,12 +2737,14 @@ pointer_int_sum (resultcode, ptrop, intop)
 
 static tree
 pointer_diff (op0, op1)
-     register tree op0, op1;
+     tree op0, op1;
 {
-  register tree result, folded;
+  tree result, folded;
   tree restype = ptrdiff_type_node;
 
   tree target_type = TREE_TYPE (TREE_TYPE (op0));
+  tree con0, con1, lit0, lit1;
+  tree orig_op1 = op1;
 
   if (pedantic || warn_pointer_arith)
     {
@@ -2782,6 +2754,40 @@ pointer_diff (op0, op1)
        pedwarn ("pointer to a function used in subtraction");
     }
 
+  /* If the conversion to ptrdiff_type does anything like widening or
+     converting a partial to an integral mode, we get a convert_expression
+     that is in the way to do any simplifications.
+     (fold-const.c doesn't know that the extra bits won't be needed.
+     split_tree uses STRIP_SIGN_NOPS, which leaves conversions to a
+     different mode in place.)
+     So first try to find a common term here 'by hand'; we want to cover
+     at least the cases that occur in legal static initializers.  */
+  con0 = TREE_CODE (op0) == NOP_EXPR ? TREE_OPERAND (op0, 0) : op0;
+  con1 = TREE_CODE (op1) == NOP_EXPR ? TREE_OPERAND (op1, 0) : op1;
+
+  if (TREE_CODE (con0) == PLUS_EXPR)
+    {
+      lit0 = TREE_OPERAND (con0, 1);
+      con0 = TREE_OPERAND (con0, 0);
+    }
+  else
+    lit0 = integer_zero_node;
+
+  if (TREE_CODE (con1) == PLUS_EXPR)
+    {
+      lit1 = TREE_OPERAND (con1, 1);
+      con1 = TREE_OPERAND (con1, 0);
+    }
+  else
+    lit1 = integer_zero_node;
+
+  if (operand_equal_p (con0, con1, 0))
+    {
+      op0 = lit0;
+      op1 = lit1;
+    }
+
+
   /* First do the subtraction as integers;
      then drop through to build the divide operator.
      Do not do default conversions on the minus operator
@@ -2790,7 +2796,7 @@ pointer_diff (op0, op1)
   op0 = build_binary_op (MINUS_EXPR, convert (restype, op0),
                         convert (restype, op1), 0);
   /* This generates an error if op1 is pointer to incomplete type.  */
-  if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (op1))))
+  if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (orig_op1))))
     error ("arithmetic on pointer to an incomplete type");
 
   /* This generates an error if op0 is pointer to incomplete type.  */
@@ -2808,20 +2814,25 @@ pointer_diff (op0, op1)
 \f
 /* Construct and perhaps optimize a tree representation
    for a unary operation.  CODE, a tree_code, specifies the operation
-   and XARG is the operand.  NOCONVERT nonzero suppresses
-   the default promotions (such as from short to int).  */
+   and XARG is the operand.
+   For any CODE other than ADDR_EXPR, FLAG nonzero suppresses
+   the default promotions (such as from short to int).
+   For ADDR_EXPR, the default promotions are not applied; FLAG nonzero
+   allows non-lvalues; this is only used to handle conversion of non-lvalue
+   arrays to pointers in C99.  */
 
 tree
-build_unary_op (code, xarg, noconvert)
+build_unary_op (code, xarg, flag)
      enum tree_code code;
      tree xarg;
-     int noconvert;
+     int flag;
 {
   /* No default_conversion here.  It causes trouble for ADDR_EXPR.  */
-  register tree arg = xarg;
-  register tree argtype = 0;
-  register enum tree_code typecode = TREE_CODE (TREE_TYPE (arg));
+  tree arg = xarg;
+  tree argtype = 0;
+  enum tree_code typecode = TREE_CODE (TREE_TYPE (arg));
   tree val;
+  int noconvert = flag;
 
   if (typecode == ERROR_MARK)
     return error_mark_node;
@@ -2935,7 +2946,7 @@ build_unary_op (code, xarg, noconvert)
       /* Handle complex lvalues (when permitted)
         by reduction to simpler cases.  */
 
-      val = unary_complex_lvalue (code, arg);
+      val = unary_complex_lvalue (code, arg, 0);
       if (val != 0)
        return val;
 
@@ -2960,14 +2971,16 @@ build_unary_op (code, xarg, noconvert)
       if (typecode != POINTER_TYPE
          && typecode != INTEGER_TYPE && typecode != REAL_TYPE)
        {
-         error ("wrong type argument to %s",
-                code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR
-                ? "increment" : "decrement");
+         if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
+            error ("wrong type argument to increment");
+          else
+            error ("wrong type argument to decrement");
+
          return error_mark_node;
        }
 
       {
-       register tree inc;
+       tree inc;
        tree result_type = TREE_TYPE (arg);
 
        arg = get_unwidened (arg, 0);
@@ -2980,15 +2993,22 @@ build_unary_op (code, xarg, noconvert)
            /* If pointer target is an undefined struct,
               we just cannot know how to do the arithmetic.  */
            if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (result_type)))
-             error ("%s of pointer to unknown structure",
-                    code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR
-                    ? "increment" : "decrement");
+             {
+               if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
+                 error ("increment of pointer to unknown structure");
+               else
+                 error ("decrement of pointer to unknown structure");
+             }
            else if ((pedantic || warn_pointer_arith)
                     && (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE
                         || TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE))
-             pedwarn ("wrong type argument to %s",
-                      code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR
-                      ? "increment" : "decrement");
+              {
+               if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
+                 pedwarn ("wrong type argument to increment");
+               else
+                 pedwarn ("wrong type argument to decrement");
+             }
+
            inc = c_size_in_bytes (TREE_TYPE (result_type));
          }
        else
@@ -3059,7 +3079,7 @@ build_unary_op (code, xarg, noconvert)
          readonly_warning (arg, 
                            ((code == PREINCREMENT_EXPR
                              || code == POSTINCREMENT_EXPR)
-                            ? "increment" : "decrement"));
+                            ? _("increment") : _("decrement")));
 
        if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
          val = boolean_increment (code, arg);
@@ -3073,8 +3093,7 @@ build_unary_op (code, xarg, noconvert)
       }
 
     case ADDR_EXPR:
-      /* Note that this operation never does default_conversion
-        regardless of NOCONVERT.  */
+      /* Note that this operation never does default_conversion.  */
 
       /* Let &* cancel out to simplify resulting code.  */
       if (TREE_CODE (arg) == INDIRECT_REF)
@@ -3096,7 +3115,7 @@ build_unary_op (code, xarg, noconvert)
 
       /* Handle complex lvalues (when permitted)
         by reduction to simpler cases.  */
-      val = unary_complex_lvalue (code, arg);
+      val = unary_complex_lvalue (code, arg, flag);
       if (val != 0)
        return val;
 
@@ -3127,8 +3146,8 @@ build_unary_op (code, xarg, noconvert)
       if (TREE_CODE (arg) == CONSTRUCTOR && TREE_CONSTANT (arg))
        ;
       /* Anything not already handled and not a true memory reference
-        is an error.  */
-      else if (typecode != FUNCTION_TYPE
+        or a non-lvalue array is an error.  */
+      else if (typecode != FUNCTION_TYPE && !flag
               && !lvalue_or_else (arg, "invalid lvalue in unary `&'"))
        return error_mark_node;
 
@@ -3157,7 +3176,7 @@ build_unary_op (code, xarg, noconvert)
          {
            tree field = TREE_OPERAND (arg, 1);
 
-           addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), 0);
+           addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), flag);
 
            if (DECL_C_BIT_FIELD (field))
              {
@@ -3228,7 +3247,7 @@ int
 lvalue_p (ref)
      tree ref;
 {
-  register enum tree_code code = TREE_CODE (ref);
+  enum tree_code code = TREE_CODE (ref);
 
   switch (code)
     {
@@ -3276,14 +3295,17 @@ lvalue_or_else (ref, msgid)
 
 /* Apply unary lvalue-demanding operator CODE to the expression ARG
    for certain kinds of expressions which are not really lvalues
-   but which we can accept as lvalues.
+   but which we can accept as lvalues.  If FLAG is nonzero, then
+   non-lvalues are OK since we may be converting a non-lvalue array to
+   a pointer in C99.
 
    If ARG is not a kind of expression we can handle, return zero.  */
    
 static tree
-unary_complex_lvalue (code, arg)
+unary_complex_lvalue (code, arg, flag)
      enum tree_code code;
      tree arg;
+     int flag;
 {
   /* Handle (a, b) used as an "lvalue".  */
   if (TREE_CODE (arg) == COMPOUND_EXPR)
@@ -3292,7 +3314,7 @@ unary_complex_lvalue (code, arg)
 
       /* If this returns a function type, it isn't really being used as
         an lvalue, so don't issue a warning about it.  */
-      if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE)
+      if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE && !flag)
        pedantic_lvalue_warning (COMPOUND_EXPR);
 
       return build (COMPOUND_EXPR, TREE_TYPE (real_result),
@@ -3302,14 +3324,15 @@ unary_complex_lvalue (code, arg)
   /* Handle (a ? b : c) used as an "lvalue".  */
   if (TREE_CODE (arg) == COND_EXPR)
     {
-      pedantic_lvalue_warning (COND_EXPR);
-      if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE)
+      if (!flag)
+       pedantic_lvalue_warning (COND_EXPR);
+      if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE && !flag)
        pedantic_lvalue_warning (COMPOUND_EXPR);
 
       return (build_conditional_expr
              (TREE_OPERAND (arg, 0),
-              build_unary_op (code, TREE_OPERAND (arg, 1), 0),
-              build_unary_op (code, TREE_OPERAND (arg, 2), 0)));
+              build_unary_op (code, TREE_OPERAND (arg, 1), flag),
+              build_unary_op (code, TREE_OPERAND (arg, 2), flag)));
     }
 
   return 0;
@@ -3367,7 +3390,7 @@ int
 mark_addressable (exp)
      tree exp;
 {
-  register tree x = exp;
+  tree x = exp;
   while (1)
     switch (TREE_CODE (x))
       {
@@ -3452,11 +3475,11 @@ tree
 build_conditional_expr (ifexp, op1, op2)
      tree ifexp, op1, op2;
 {
-  register tree type1;
-  register tree type2;
-  register enum tree_code code1;
-  register enum tree_code code2;
-  register tree result_type = NULL;
+  tree type1;
+  tree type2;
+  enum tree_code code1;
+  enum tree_code code2;
+  tree result_type = NULL;
   tree orig_op1 = op1, orig_op2 = op2;
 
   ifexp = truthvalue_conversion (default_conversion (ifexp));
@@ -3640,13 +3663,15 @@ internal_build_compound_expr (list, first_p)
      tree list;
      int first_p;
 {
-  register tree rest;
+  tree rest;
 
   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));
+      /* Convert arrays and functions to pointers when there
+        really is a comma operator.  */
+      if (!first_p)
+       TREE_VALUE (list)
+         = default_function_array_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.  */
@@ -3694,10 +3719,10 @@ internal_build_compound_expr (list, first_p)
 
 tree
 build_c_cast (type, expr)
-     register tree type;
+     tree type;
      tree expr;
 {
-  register tree value = expr;
+  tree value = expr;
   
   if (type == error_mark_node || expr == error_mark_node)
     return error_mark_node;
@@ -3721,7 +3746,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)
        {
@@ -3733,9 +3758,7 @@ build_c_cast (type, expr)
   else if (TREE_CODE (type) == UNION_TYPE)
     {
       tree field;
-      if (TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
-         || TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE)
-       value = default_conversion (value);
+      value = default_function_array_conversion (value);
 
       for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
        if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)),
@@ -3778,9 +3801,7 @@ build_c_cast (type, expr)
 
       /* Convert functions and arrays to pointers,
         but don't convert any other types.  */
-      if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE
-         || TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE)
-       value = default_conversion (value);
+      value = default_function_array_conversion (value);
       otype = TREE_TYPE (value);
 
       /* Optionally warn about potentially worrisome casts.  */
@@ -3855,7 +3876,7 @@ build_c_cast (type, expr)
        }
     }
 
-  /* Pedantically, don't ley (void *) (FOO *) 0 be a null pointer constant.  */
+  /* Pedantically, don't let (void *) (FOO *) 0 be a null pointer constant.  */
   if (pedantic && TREE_CODE (value) == INTEGER_CST
       && TREE_CODE (expr) == INTEGER_CST
       && TREE_CODE (TREE_TYPE (expr)) != INTEGER_TYPE)
@@ -3896,7 +3917,7 @@ build_modify_expr (lhs, modifycode, rhs)
      tree lhs, rhs;
      enum tree_code modifycode;
 {
-  register tree result;
+  tree result;
   tree newrhs;
   tree lhstype = TREE_TYPE (lhs);
   tree olhstype = lhstype;
@@ -3980,9 +4001,7 @@ build_modify_expr (lhs, modifycode, rhs)
     case FIX_FLOOR_EXPR:
     case FIX_ROUND_EXPR:
     case FIX_CEIL_EXPR:
-      if (TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE
-         || TREE_CODE (TREE_TYPE (newrhs)) == FUNCTION_TYPE)
-       newrhs = default_conversion (newrhs);
+      newrhs = default_function_array_conversion (newrhs);
       {
        tree inner_lhs = TREE_OPERAND (lhs, 0);
        tree result;
@@ -4077,9 +4096,9 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
      tree fundecl, funname;
      int parmnum;
 {
-  register enum tree_code codel = TREE_CODE (type);
-  register tree rhstype;
-  register enum tree_code coder;
+  enum tree_code codel = TREE_CODE (type);
+  tree rhstype;
+  enum tree_code coder;
 
   /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue.  */
   /* Do not use STRIP_NOPS here.  We do not want an enumerator
@@ -4164,8 +4183,8 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
 
          if (coder == POINTER_TYPE)
            {
-             register tree ttl = TREE_TYPE (memb_type);
-             register tree ttr = TREE_TYPE (rhstype);
+             tree ttl = TREE_TYPE (memb_type);
+             tree ttr = TREE_TYPE (rhstype);
 
              /* Any non-function converts to a [const][volatile] void *
                 and vice versa; otherwise, targets must be the same.
@@ -4206,8 +4225,8 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
            {
              /* We have only a marginally acceptable member type;
                 it needs a warning.  */
-             register tree ttl = TREE_TYPE (marginal_memb_type);
-             register tree ttr = TREE_TYPE (rhstype);
+             tree ttl = TREE_TYPE (marginal_memb_type);
+             tree ttr = TREE_TYPE (rhstype);
 
              /* Const and volatile mean something different for function
                 types, so the usual warnings are not appropriate.  */
@@ -4240,8 +4259,8 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
   else if ((codel == POINTER_TYPE || codel == REFERENCE_TYPE)
           && (coder == POINTER_TYPE || coder == REFERENCE_TYPE))
     {
-      register tree ttl = TREE_TYPE (type);
-      register tree ttr = TREE_TYPE (rhstype);
+      tree ttl = TREE_TYPE (type);
+      tree ttr = TREE_TYPE (rhstype);
 
       /* Any non-function converts to a [const][volatile] void *
         and vice versa; otherwise, targets must be the same.
@@ -4372,7 +4391,7 @@ warn_for_assignment (msgid, opname, function, argnum)
       if (function)
        {
          /* Function name is known; supply it.  */
-         const char *argstring = _("passing arg %d of `%s'");
+         const char *const argstring = _("passing arg %d of `%s'");
          new_opname = (char *) alloca (IDENTIFIER_LENGTH (function)
                                        + strlen (argstring) + 1 + 25
                                        /*%d*/ + 1);
@@ -4382,7 +4401,7 @@ warn_for_assignment (msgid, opname, function, argnum)
       else
        {
          /* Function name unknown (call through ptr); just give arg number.*/
-         const char *argnofun = _("passing arg %d of pointer to function");
+         const char *const argnofun = _("passing arg %d of pointer to function");
          new_opname = (char *) alloca (strlen (argnofun) + 1 + 25 /*%d*/ + 1);
          sprintf (new_opname, argnofun, argnum);
        }
@@ -4426,7 +4445,7 @@ void
 store_init_value (decl, init)
      tree decl, init;
 {
-  register tree value, type;
+  tree value, type;
 
   /* If variable's type was invalidly declared, just ignore it.  */
 
@@ -4508,7 +4527,7 @@ static int spelling_size;         /* Size of the spelling stack.  */
    Alternative to SAVE_SPELLING_STACK.  */
 
 #define SPELLING_DEPTH() (spelling - spelling_base)
-#define RESTORE_SPELLING_DEPTH(depth) (spelling = spelling_base + depth)
+#define RESTORE_SPELLING_DEPTH(DEPTH) (spelling = spelling_base + (DEPTH))
 
 /* Save and restore the spelling stack around arbitrary C code.  */
 
@@ -4560,7 +4579,7 @@ push_member_name (decl)
      tree decl;
      
 {
-  const char *string
+  const char *const string
     = DECL_NAME (decl) ? IDENTIFIER_POINTER (DECL_NAME (decl)) : "<anonymous>";
   PUSH_SPELLING (SPELLING_MEMBER, string, u.s);
 }
@@ -4579,8 +4598,8 @@ push_array_bounds (bounds)
 static int
 spelling_length ()
 {
-  register int size = 0;
-  register struct spelling *p;
+  int size = 0;
+  struct spelling *p;
 
   for (p = spelling_base; p < spelling; p++)
     {
@@ -4597,10 +4616,10 @@ spelling_length ()
 
 static char *
 print_spelling (buffer)
-     register char *buffer;
+     char *buffer;
 {
-  register char *d = buffer;
-  register struct spelling *p;
+  char *d = buffer;
+  struct spelling *p;
 
   for (p = spelling_base; p < spelling; p++)
     if (p->kind == SPELLING_BOUNDS)
@@ -4610,7 +4629,7 @@ print_spelling (buffer)
       }
     else
       {
-       register const char *s;
+       const char *s;
        if (p->kind == SPELLING_MEMBER)
          *d++ = '.';
        for (s = p->u.s; (*d = *s++); d++)
@@ -4730,6 +4749,7 @@ digest_init (type, init, require_constant, constructor_constant)
 
          TREE_TYPE (inside_init) = type;
          if (TYPE_DOMAIN (type) != 0
+             && TYPE_SIZE (type) != 0
              && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
              /* Subtract 1 (or sizeof (wchar_t))
                 because it's ok to ignore the terminating null char
@@ -4761,10 +4781,8 @@ digest_init (type, init, require_constant, constructor_constant)
              && comptypes (TREE_TYPE (TREE_TYPE (inside_init)),
                            TREE_TYPE (type)))))
     {
-      if (code == POINTER_TYPE
-         && (TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE
-             || TREE_CODE (TREE_TYPE (inside_init)) == FUNCTION_TYPE))
-       inside_init = default_conversion (inside_init);
+      if (code == POINTER_TYPE)
+       inside_init = default_function_array_conversion (inside_init);
       else if (code == ARRAY_TYPE && TREE_CODE (inside_init) != STRING_CST
               && TREE_CODE (inside_init) != CONSTRUCTOR)
        {
@@ -4791,14 +4809,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)
-       pedwarn ("initializer element is not computable at load time");
 
       return inside_init;
     }
@@ -4968,6 +4993,9 @@ static const char *constructor_asmspec;
 /* Nonzero if this is an initializer for a top-level decl.  */
 static int constructor_top_level;
 
+/* Nonzero if there were any member designators in this initializer.  */
+static int constructor_designated;
+
 /* Nesting depth of designator list.  */
 static int designator_depth;
 
@@ -5005,6 +5033,7 @@ struct constructor_stack
   char erroneous;
   char outer;
   char incremental;
+  char designated;
 };
 
 struct constructor_stack *constructor_stack;
@@ -5081,6 +5110,7 @@ start_init (decl, asmspec_tree, top_level)
   constructor_decl = decl;
   constructor_asmspec = asmspec;
   constructor_subconstants_deferred = 0;
+  constructor_designated = 0;
   constructor_top_level = top_level;
 
   if (decl != 0)
@@ -5190,6 +5220,7 @@ really_start_incremental_init (type)
   p->range_stack = 0;
   p->outer = 0;
   p->incremental = constructor_incremental;
+  p->designated = constructor_designated;
   p->next = 0;
   constructor_stack = p;
 
@@ -5200,6 +5231,7 @@ really_start_incremental_init (type)
   constructor_pending_elts = 0;
   constructor_type = type;
   constructor_incremental = 1;
+  constructor_designated = 0;
   designator_depth = 0;
   designator_errorneous = 0;
 
@@ -5223,7 +5255,8 @@ really_start_incremental_init (type)
            = TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type));
 
          /* Detect non-empty initializations of zero-length arrays.  */
-         if (constructor_max_index == NULL_TREE)
+         if (constructor_max_index == NULL_TREE
+             && TYPE_SIZE (constructor_type))
            constructor_max_index = build_int_2 (-1, -1);
 
          constructor_index
@@ -5300,6 +5333,7 @@ push_init_level (implicit)
   p->implicit = implicit;
   p->outer = 0;
   p->incremental = constructor_incremental;
+  p->designated = constructor_designated;
   p->next = constructor_stack;
   p->range_stack = 0;
   constructor_stack = p;
@@ -5309,6 +5343,7 @@ push_init_level (implicit)
   constructor_depth = SPELLING_DEPTH ();
   constructor_elements = 0;
   constructor_incremental = 1;
+  constructor_designated = 0;
   constructor_pending_elts = 0;
   if (!implicit)
     {
@@ -5385,14 +5420,15 @@ push_init_level (implicit)
        {
          constructor_max_index
            = TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type));
+
+         /* Detect non-empty initializations of zero-length arrays.  */
+         if (constructor_max_index == NULL_TREE
+             && TYPE_SIZE (constructor_type))
+           constructor_max_index = build_int_2 (-1, -1);
+
          constructor_index
            = convert (bitsizetype, 
                       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;
@@ -5427,7 +5463,6 @@ pop_init_level (implicit)
      int implicit;
 {
   struct constructor_stack *p;
-  HOST_WIDE_INT size = 0;
   tree constructor = 0;
 
   if (implicit == 0)
@@ -5443,9 +5478,6 @@ pop_init_level (implicit)
 
   p = constructor_stack;
 
-  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
@@ -5464,26 +5496,16 @@ pop_init_level (implicit)
          else if (pedantic)
            pedwarn_init ("initialization of a flexible array member");
 
-         /* We have already issued an error message for the existance
+         /* We have already issued an error message for the existence
             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");
-       }
+       /* Zero-length arrays are no longer special, so we should no longer
+          get here.  */
+       abort();
     }
 
   /* Warn when some struct elements are implicitly initialized to zero.  */
@@ -5498,7 +5520,9 @@ pop_init_level (implicit)
                   || integer_zerop (DECL_SIZE (constructor_unfilled_fields))))
          constructor_unfilled_fields = TREE_CHAIN (constructor_unfilled_fields);
 
-       if (constructor_unfilled_fields)
+       /* Do not warn if this level of the initializer uses member
+          designators; it is likely to be deliberate.  */
+       if (constructor_unfilled_fields && !constructor_designated)
          {
            push_member_name (constructor_unfilled_fields);
            warning_init ("missing initializer");
@@ -5564,6 +5588,7 @@ pop_init_level (implicit)
   constructor_simple = p->simple;
   constructor_erroneous = p->erroneous;
   constructor_incremental = p->incremental;
+  constructor_designated = p->designated;
   constructor_pending_elts = p->pending_elts;
   constructor_depth = p->depth;
   if (!p->implicit)
@@ -5610,6 +5635,7 @@ set_designator (array)
         braces.  */
       while (constructor_stack->implicit)
        process_init_element (pop_init_level (1));
+      constructor_designated = 1;
       return 0;
     }
 
@@ -5645,6 +5671,7 @@ set_designator (array)
       return 1;
     }
 
+  constructor_designated = 1;
   push_init_level (2);
   return 0;
 }
@@ -5783,7 +5810,7 @@ set_init_label (fieldname)
 }
 \f
 /* Add a new initializer to the tree of pending initializers.  PURPOSE
-   indentifies the initializer, either array index or field in a structure. 
+   identifies the initializer, either array index or field in a structure. 
    VALUE is the value of that index or field.  */
 
 static void
@@ -5857,7 +5884,7 @@ add_pending_init (purpose, value)
            {
              if (r->balance < 0)
                {
-                 /* L rotation. */
+                 /* L rotation.  */
                  p->left = r->right;
                  if (p->left)
                    p->left->parent = p;
@@ -5881,7 +5908,7 @@ add_pending_init (purpose, value)
                }
              else
                {
-                 /* LR rotation. */
+                 /* LR rotation.  */
                  struct init_node *t = r->right;
 
                  r->right = t->left;
@@ -5930,7 +5957,7 @@ add_pending_init (purpose, value)
            {
              if (r->balance > 0)
                {
-                 /* R rotation. */
+                 /* R rotation.  */
                  p->right = r->left;
                  if (p->right)
                    p->right->parent = p;
@@ -5989,7 +6016,7 @@ add_pending_init (purpose, value)
            }
          else
            {
-             /* p->balance == -1; growth of right side balances the node. */
+             /* p->balance == -1; growth of right side balances the node.  */
              p->balance = 0;
              break;
            }
@@ -6622,8 +6649,12 @@ process_init_element (value)
             under the assumption that the zero initializer in user
             code appears conditioned on e.g. __STDC__ to avoid
             "missing initializer" warnings and relies on default
-            initialization to zero in the traditional C case.  */
-         if (warn_traditional && !in_system_header
+            initialization to zero in the traditional C case.
+            We also skip the warning if the initializer is designated,
+            again on the assumption that this must be conditional on
+            __STDC__ anyway (and we've already complained about the
+            member-designator already).  */
+         if (warn_traditional && !in_system_header && !constructor_designated
              && !(value && (integer_zerop (value) || real_zerop (value))))
            warning ("traditional C rejects initialization of unions");
 
@@ -6872,9 +6903,7 @@ build_asm_stmt (cv_qualifier, string, outputs, inputs, clobbers)
      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));
+    TREE_VALUE (tail) = default_function_array_conversion (TREE_VALUE (tail));
 
   return add_stmt (build_stmt (ASM_STMT, cv_qualifier, string,
                               outputs, inputs, clobbers));
@@ -6894,10 +6923,10 @@ c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
      int line;
 {
   int noutputs = list_length (outputs);
-  register int i;
+  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 *o = (tree *) alloca (noutputs * sizeof (tree));
+  tree tail;
 
   /* Record the contents of OUTPUTS before it is modified.  */
   for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
@@ -7062,7 +7091,7 @@ tree
 c_start_case (exp)
      tree exp;
 {
-  register enum tree_code code;
+  enum tree_code code;
   tree type;
   struct c_switch *cs;
 
@@ -7071,8 +7100,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");