OSDN Git Service

* target.h (invalid_conversion, invalid_unary_op,
[pf3gnuchains/gcc-fork.git] / gcc / c-typeck.c
index 6e7bbfe..34f94d1 100644 (file)
@@ -1,6 +1,6 @@
 /* Build expressions with type checking for C compiler.
-   Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -16,8 +16,8 @@ for more details.
 
 You should have received a copy of the GNU General Public License
 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.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 
 /* This file is part of the C front end.
@@ -43,7 +43,29 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "target.h"
 #include "tree-iterator.h"
 #include "tree-gimple.h"
+#include "tree-flow.h"
+
+/* Possible cases of implicit bad conversions.  Used to select
+   diagnostic messages in convert_for_assignment.  */
+enum impl_conv {
+  ic_argpass,
+  ic_argpass_nonproto,
+  ic_assign,
+  ic_init,
+  ic_return
+};
+
+/* The level of nesting inside "__alignof__".  */
+int in_alignof;
+
+/* The level of nesting inside "sizeof".  */
+int in_sizeof;
 
+/* The level of nesting inside "typeof".  */
+int in_typeof;
+
+struct c_label_context_se *label_context_stack_se;
+struct c_label_context_vm *label_context_stack_vm;
 
 /* Nonzero if we've already printed a "missing braces around initializer"
    message within this initializer.  */
@@ -54,17 +76,15 @@ static int require_constant_elements;
 
 static tree qualify_type (tree, tree);
 static int tagged_types_tu_compatible_p (tree, tree);
-static int comp_target_types (tree, tree, int);
+static int comp_target_types (tree, tree);
 static int function_types_compatible_p (tree, tree);
 static int type_lists_compatible_p (tree, tree);
 static tree decl_constant_value_for_broken_optimization (tree);
-static tree default_function_array_conversion (tree);
 static tree lookup_field (tree, tree);
 static tree convert_arguments (tree, tree, tree, tree);
 static tree pointer_diff (tree, tree);
-static tree convert_for_assignment (tree, tree, const char *, tree, tree,
+static tree convert_for_assignment (tree, tree, enum impl_conv, tree, tree,
                                    int);
-static void warn_for_assignment (const char *, const char *, tree, int);
 static tree valid_compound_expr_initializer (tree, tree);
 static void push_string (const char *);
 static void push_member_name (tree);
@@ -81,7 +101,10 @@ static void add_pending_init (tree, tree);
 static void set_nonincremental_init (void);
 static void set_nonincremental_init_from_string (tree);
 static tree find_init_member (tree);
-static int lvalue_or_else (tree, const char *);
+static void readonly_error (tree, enum lvalue_use);
+static int lvalue_or_else (tree, enum lvalue_use);
+static int lvalue_p (tree);
+static void record_maybe_used_decl (tree);
 \f
 /* Do `exp = require_complete_type (exp);' to make sure exp
    does not have an incomplete type.  (That includes void types.)  */
@@ -117,8 +140,7 @@ c_incomplete_type_error (tree value, tree type)
 
   if (value != 0 && (TREE_CODE (value) == VAR_DECL
                     || TREE_CODE (value) == PARM_DECL))
-    error ("`%s' has an incomplete type",
-          IDENTIFIER_POINTER (DECL_NAME (value)));
+    error ("%qD has an incomplete type", value);
   else
     {
     retry:
@@ -157,16 +179,15 @@ c_incomplete_type_error (tree value, tree type)
          return;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
 
       if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
-       error ("invalid use of undefined type `%s %s'",
-              type_code_string, IDENTIFIER_POINTER (TYPE_NAME (type)));
+       error ("invalid use of undefined type %<%s %E%>",
+              type_code_string, TYPE_NAME (type));
       else
        /* If this type has a typedef-name, the TYPE_NAME is a TYPE_DECL.  */
-       error ("invalid use of incomplete typedef `%s'",
-              IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))));
+       error ("invalid use of incomplete typedef %qD", TYPE_NAME (type));
     }
 }
 
@@ -240,8 +261,7 @@ composite_type (tree t1, tree t2)
   if (code2 == ENUMERAL_TYPE && code1 == INTEGER_TYPE)
     return t2;
 
-  if (code1 != code2)
-    abort ();
+  gcc_assert (code1 == code2);
 
   switch (code1)
     {
@@ -259,10 +279,11 @@ composite_type (tree t1, tree t2)
     case ARRAY_TYPE:
       {
        tree elt = composite_type (TREE_TYPE (t1), TREE_TYPE (t2));
-       
+       int quals;
+       tree unqual_elt;
+
        /* We should not have any type quals on arrays at all.  */
-       if (TYPE_QUALS (t1) || TYPE_QUALS (t2))
-         abort ();
+       gcc_assert (!TYPE_QUALS (t1) && !TYPE_QUALS (t2));
        
        /* Save space: see if the result is identical to one of the args.  */
        if (elt == TREE_TYPE (t1) && TYPE_DOMAIN (t1))
@@ -275,8 +296,16 @@ composite_type (tree t1, tree t2)
        if (elt == TREE_TYPE (t2) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1))
          return build_type_attribute_variant (t2, attributes);
        
-       /* Merge the element types, and have a size if either arg has one.  */
-       t1 = build_array_type (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2));
+       /* Merge the element types, and have a size if either arg has
+          one.  We may have qualifiers on the element types.  To set
+          up TYPE_MAIN_VARIANT correctly, we need to form the
+          composite of the unqualified types and add the qualifiers
+          back at the end.  */
+       quals = TYPE_QUALS (strip_array_types (elt));
+       unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED);
+       t1 = build_array_type (unqual_elt,
+                              TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2));
+       t1 = c_build_qualified_type (t1, quals);
        return build_type_attribute_variant (t1, attributes);
       }
 
@@ -292,9 +321,9 @@ composite_type (tree t1, tree t2)
        int i;
 
        /* Save space: see if the result is identical to one of the args.  */
-       if (valtype == TREE_TYPE (t1) && ! TYPE_ARG_TYPES (t2))
+       if (valtype == TREE_TYPE (t1) && !TYPE_ARG_TYPES (t2))
          return build_type_attribute_variant (t1, attributes);
-       if (valtype == TREE_TYPE (t2) && ! TYPE_ARG_TYPES (t1))
+       if (valtype == TREE_TYPE (t2) && !TYPE_ARG_TYPES (t1))
          return build_type_attribute_variant (t2, attributes);
 
        /* Simple way if one arg fails to specify argument types.  */
@@ -314,7 +343,7 @@ composite_type (tree t1, tree t2)
        /* If both args specify argument types, we must merge the two
           lists, argument by argument.  */
        /* Tell global_bindings_p to return false so that variable_size
-          doesn't abort on VLAs in parameter types.  */
+          doesn't die on VLAs in parameter types.  */
        c_override_global_bindings_to_false = true;
 
        len = list_length (p1);
@@ -348,29 +377,51 @@ composite_type (tree t1, tree t2)
                && TREE_VALUE (p1) != TREE_VALUE (p2))
              {
                tree memb;
+               tree mv2 = TREE_VALUE (p2);
+               if (mv2 && mv2 != error_mark_node
+                   && TREE_CODE (mv2) != ARRAY_TYPE)
+                 mv2 = TYPE_MAIN_VARIANT (mv2);
                for (memb = TYPE_FIELDS (TREE_VALUE (p1));
                     memb; memb = TREE_CHAIN (memb))
-                 if (comptypes (TREE_TYPE (memb), TREE_VALUE (p2)))
-                   {
-                     TREE_VALUE (n) = TREE_VALUE (p2);
-                     if (pedantic)
-                       pedwarn ("function types not truly compatible in ISO C");
-                     goto parm_done;
-                   }
+                 {
+                   tree mv3 = TREE_TYPE (memb);
+                   if (mv3 && mv3 != error_mark_node
+                       && TREE_CODE (mv3) != ARRAY_TYPE)
+                     mv3 = TYPE_MAIN_VARIANT (mv3);
+                   if (comptypes (mv3, mv2))
+                     {
+                       TREE_VALUE (n) = composite_type (TREE_TYPE (memb),
+                                                        TREE_VALUE (p2));
+                       if (pedantic)
+                         pedwarn ("function types not truly compatible in ISO C");
+                       goto parm_done;
+                     }
+                 }
              }
            if (TREE_CODE (TREE_VALUE (p2)) == UNION_TYPE
                && TREE_VALUE (p2) != TREE_VALUE (p1))
              {
                tree memb;
+               tree mv1 = TREE_VALUE (p1);
+               if (mv1 && mv1 != error_mark_node
+                   && TREE_CODE (mv1) != ARRAY_TYPE)
+                 mv1 = TYPE_MAIN_VARIANT (mv1);
                for (memb = TYPE_FIELDS (TREE_VALUE (p2));
                     memb; memb = TREE_CHAIN (memb))
-                 if (comptypes (TREE_TYPE (memb), TREE_VALUE (p1)))
-                   {
-                     TREE_VALUE (n) = TREE_VALUE (p1);
-                     if (pedantic)
-                       pedwarn ("function types not truly compatible in ISO C");
-                     goto parm_done;
-                   }
+                 {
+                   tree mv3 = TREE_TYPE (memb);
+                   if (mv3 && mv3 != error_mark_node
+                       && TREE_CODE (mv3) != ARRAY_TYPE)
+                     mv3 = TYPE_MAIN_VARIANT (mv3);
+                   if (comptypes (mv3, mv1))
+                     {
+                       TREE_VALUE (n) = composite_type (TREE_TYPE (memb),
+                                                        TREE_VALUE (p1));
+                       if (pedantic)
+                         pedwarn ("function types not truly compatible in ISO C");
+                       goto parm_done;
+                     }
+                 }
              }
            TREE_VALUE (n) = composite_type (TREE_VALUE (p1), TREE_VALUE (p2));
          parm_done: ;
@@ -398,8 +449,8 @@ static tree
 common_pointer_type (tree t1, tree t2)
 {
   tree attributes;
-  tree pointed_to_1;
-  tree pointed_to_2;
+  tree pointed_to_1, mv1;
+  tree pointed_to_2, mv2;
   tree target;
 
   /* Save time if the two types are the same.  */
@@ -412,18 +463,22 @@ common_pointer_type (tree t1, tree t2)
   if (t2 == error_mark_node)
     return t1;
 
-  if (TREE_CODE (t1) != POINTER_TYPE || TREE_CODE (t2) != POINTER_TYPE)
-    abort ();
+  gcc_assert (TREE_CODE (t1) == POINTER_TYPE
+             && TREE_CODE (t2) == POINTER_TYPE);
 
   /* Merge the attributes.  */
   attributes = targetm.merge_type_attributes (t1, t2);
 
   /* Find the composite type of the target types, and combine the
-     qualifiers of the two types' targets.  */
-  pointed_to_1 = TREE_TYPE (t1);
-  pointed_to_2 = TREE_TYPE (t2);
-  target = composite_type (TYPE_MAIN_VARIANT (pointed_to_1),
-                          TYPE_MAIN_VARIANT (pointed_to_2));
+     qualifiers of the two types' targets.  Do not lose qualifiers on
+     array element types by taking the TYPE_MAIN_VARIANT.  */
+  mv1 = pointed_to_1 = TREE_TYPE (t1);
+  mv2 = pointed_to_2 = TREE_TYPE (t2);
+  if (TREE_CODE (mv1) != ARRAY_TYPE)
+    mv1 = TYPE_MAIN_VARIANT (pointed_to_1);
+  if (TREE_CODE (mv2) != ARRAY_TYPE)
+    mv2 = TYPE_MAIN_VARIANT (pointed_to_2);
+  target = composite_type (mv1, mv2);
   t1 = build_pointer_type (c_build_qualified_type
                           (target,
                            TYPE_QUALS (pointed_to_1) |
@@ -439,8 +494,8 @@ common_pointer_type (tree t1, tree t2)
    This is the type for the result of most arithmetic operations
    if the operands have the given two types.  */
 
-tree
-common_type (tree t1, tree t2)
+static tree
+c_common_type (tree t1, tree t2)
 {
   enum tree_code code1;
   enum tree_code code2;
@@ -470,13 +525,10 @@ common_type (tree t1, tree t2)
   code1 = TREE_CODE (t1);
   code2 = TREE_CODE (t2);
 
-  if (code1 != VECTOR_TYPE && code1 != COMPLEX_TYPE
-      && code1 != REAL_TYPE && code1 != INTEGER_TYPE)
-    abort ();
-
-  if (code2 != VECTOR_TYPE && code2 != COMPLEX_TYPE
-      && code2 != REAL_TYPE && code2 != INTEGER_TYPE)
-    abort ();
+  gcc_assert (code1 == VECTOR_TYPE || code1 == COMPLEX_TYPE
+             || code1 == REAL_TYPE || code1 == INTEGER_TYPE);
+  gcc_assert (code2 == VECTOR_TYPE || code2 == COMPLEX_TYPE
+             || code2 == REAL_TYPE || code2 == INTEGER_TYPE);
 
   /* If one type is a vector type, return that type.  (How the usual
      arithmetic conversions apply to the vector types extension is not
@@ -494,7 +546,7 @@ common_type (tree t1, tree t2)
     {
       tree subtype1 = code1 == COMPLEX_TYPE ? TREE_TYPE (t1) : t1;
       tree subtype2 = code2 == COMPLEX_TYPE ? TREE_TYPE (t2) : t2;
-      tree subtype = common_type (subtype1, subtype2);
+      tree subtype = c_common_type (subtype1, subtype2);
 
       if (code1 == COMPLEX_TYPE && TREE_TYPE (t1) == subtype)
        return t1;
@@ -564,6 +616,32 @@ common_type (tree t1, tree t2)
     return t2;
 }
 \f
+/* Wrapper around c_common_type that is used by c-common.c.  ENUMERAL_TYPEs
+   are allowed here and are converted to their compatible integer types.
+   BOOLEAN_TYPEs are allowed here and return either boolean_type_node or
+   preferably a non-Boolean type as the common type.  */
+tree
+common_type (tree t1, tree t2)
+{
+  if (TREE_CODE (t1) == ENUMERAL_TYPE)
+    t1 = c_common_type_for_size (TYPE_PRECISION (t1), 1);
+  if (TREE_CODE (t2) == ENUMERAL_TYPE)
+    t2 = c_common_type_for_size (TYPE_PRECISION (t2), 1);
+
+  /* If both types are BOOLEAN_TYPE, then return boolean_type_node.  */
+  if (TREE_CODE (t1) == BOOLEAN_TYPE
+      && TREE_CODE (t2) == BOOLEAN_TYPE)
+    return boolean_type_node;
+
+  /* If either type is BOOLEAN_TYPE, then return the other.  */
+  if (TREE_CODE (t1) == BOOLEAN_TYPE)
+    return t2;
+  if (TREE_CODE (t2) == BOOLEAN_TYPE)
+    return t1;
+
+  return c_common_type (t1, t2);
+}
+\f
 /* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
    or various other operations.  Return 2 if they are compatible
    but a warning may be needed if you use them together.  */
@@ -618,11 +696,12 @@ comptypes (tree type1, tree type2)
      definition.  Note that we already checked for equality of the type
      qualifiers (just above).  */
 
-  if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
+  if (TREE_CODE (t1) != ARRAY_TYPE
+      && TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
     return 1;
 
   /* 1 if no need for warning yet, 2 if warning cause has been seen.  */
-  if (! (attrval = targetm.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.  */
@@ -631,9 +710,9 @@ comptypes (tree type1, tree type2)
   switch (TREE_CODE (t1))
     {
     case POINTER_TYPE:
-      /* We must give ObjC the first crack at comparing pointers, since
-          protocol qualifiers may be involved.  */
-      if (c_dialect_objc () && (val = objc_comptypes (t1, t2, 0)) >= 0)
+      /* Do not remove mode or aliasing information.  */
+      if (TYPE_MODE (t1) != TYPE_MODE (t2)
+         || TYPE_REF_CAN_ALIAS_ALL (t1) != TYPE_REF_CAN_ALIAS_ALL (t2))
        break;
       val = (TREE_TYPE (t1) == TREE_TYPE (t2)
             ? 1 : comptypes (TREE_TYPE (t1), TREE_TYPE (t2)));
@@ -660,13 +739,13 @@ comptypes (tree type1, tree type2)
        if (d1 == 0 || d2 == 0 || d1 == d2)
          break;
 
-       d1_zero = ! TYPE_MAX_VALUE (d1);
-       d2_zero = ! TYPE_MAX_VALUE (d2);
+       d1_zero = !TYPE_MAX_VALUE (d1);
+       d2_zero = !TYPE_MAX_VALUE (d2);
 
-       d1_variable = (! d1_zero
+       d1_variable = (!d1_zero
                       && (TREE_CODE (TYPE_MIN_VALUE (d1)) != INTEGER_CST
                           || TREE_CODE (TYPE_MAX_VALUE (d1)) != INTEGER_CST));
-       d2_variable = (! d2_zero
+       d2_variable = (!d2_zero
                       && (TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST
                           || TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST));
 
@@ -675,20 +754,15 @@ comptypes (tree type1, tree type2)
        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)))
+           || !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;
 
         break;
       }
 
-    case RECORD_TYPE:
-      /* We are dealing with two distinct structs.  In assorted Objective-C
-        corner cases, however, these can still be deemed equivalent.  */
-      if (c_dialect_objc () && objc_comptypes (t1, t2, 0) == 1)
-       val = 1;
-
     case ENUMERAL_TYPE:
+    case RECORD_TYPE:
     case UNION_TYPE:
       if (val != 1 && !same_translation_unit_p (t1, t2))
        val = tagged_types_tu_compatible_p (t1, t2);
@@ -706,23 +780,23 @@ comptypes (tree type1, tree type2)
 }
 
 /* Return 1 if TTL and TTR are pointers to types that are equivalent,
-   ignoring their qualifiers.  REFLEXIVE is only used by ObjC - set it
-   to 1 or 0 depending if the check of the pointer types is meant to
-   be reflexive or not (typically, assignments are not reflexive,
-   while comparisons are reflexive).
-*/
+   ignoring their qualifiers.  */
 
 static int
-comp_target_types (tree ttl, tree ttr, int reflexive)
+comp_target_types (tree ttl, tree ttr)
 {
   int val;
-
-  /* Give objc_comptypes a crack at letting these types through.  */
-  if ((val = objc_comptypes (ttl, ttr, reflexive)) >= 0)
-    return val;
-
-  val = comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (ttl)),
-                  TYPE_MAIN_VARIANT (TREE_TYPE (ttr)));
+  tree mvl, mvr;
+
+  /* Do not lose qualifiers on element types of array types that are
+     pointer targets by taking their TYPE_MAIN_VARIANT.  */
+  mvl = TREE_TYPE (ttl);
+  mvr = TREE_TYPE (ttr);
+  if (TREE_CODE (mvl) != ARRAY_TYPE)
+    mvl = TYPE_MAIN_VARIANT (mvl);
+  if (TREE_CODE (mvr) != ARRAY_TYPE)
+    mvr = TYPE_MAIN_VARIANT (mvr);
+  val = comptypes (mvl, mvr);
 
   if (val == 2 && pedantic)
     pedwarn ("types are not quite compatible");
@@ -741,19 +815,25 @@ same_translation_unit_p (tree t1, tree t2)
   while (t1 && TREE_CODE (t1) != TRANSLATION_UNIT_DECL)
     switch (TREE_CODE_CLASS (TREE_CODE (t1)))
       {
-      case 'd': t1 = DECL_CONTEXT (t1); break;
-      case 't': t1 = TYPE_CONTEXT (t1); break;
-      case 'x': t1 = BLOCK_SUPERCONTEXT (t1); break;  /* assume block */
-      default: abort ();
+      case tcc_declaration:
+       t1 = DECL_CONTEXT (t1); break;
+      case tcc_type:
+       t1 = TYPE_CONTEXT (t1); break;
+      case tcc_exceptional:
+       t1 = BLOCK_SUPERCONTEXT (t1); break;  /* assume block */
+      default: gcc_unreachable ();
       }
 
   while (t2 && TREE_CODE (t2) != TRANSLATION_UNIT_DECL)
     switch (TREE_CODE_CLASS (TREE_CODE (t2)))
       {
-      case 'd': t2 = DECL_CONTEXT (t2); break;
-      case 't': t2 = TYPE_CONTEXT (t2); break;
-      case 'x': t2 = BLOCK_SUPERCONTEXT (t2); break;  /* assume block */
-      default: abort ();
+      case tcc_declaration:
+       t2 = DECL_CONTEXT (t2); break;
+      case tcc_type:
+       t2 = TYPE_CONTEXT (t2); break;
+      case tcc_exceptional:
+       t2 = BLOCK_SUPERCONTEXT (t2); break;  /* assume block */
+      default: gcc_unreachable ();
       }
 
   return t1 == t2;
@@ -894,7 +974,7 @@ tagged_types_tu_compatible_p (tree t1, tree t2)
                    break;
                  }
            tagged_tu_seen_base = tts.next;
-           if (! ok)
+           if (!ok)
              return 0;
          }
        return needs_warning ? 2 : 1;
@@ -935,7 +1015,7 @@ tagged_types_tu_compatible_p (tree t1, tree t2)
       }
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 
@@ -961,7 +1041,7 @@ function_types_compatible_p (tree f1, tree f2)
   /* 'volatile' qualifiers on a function's return type used to mean
      the function is noreturn.  */
   if (TYPE_VOLATILE (ret1) != TYPE_VOLATILE (ret2))
-    pedwarn ("function return types not compatible due to `volatile'");
+    pedwarn ("function return types not compatible due to %<volatile%>");
   if (TYPE_VOLATILE (ret1))
     ret1 = build_qualified_type (TYPE_MAIN_VARIANT (ret1),
                                 TYPE_QUALS (ret1) & ~TYPE_QUAL_VOLATILE);
@@ -1018,62 +1098,80 @@ type_lists_compatible_p (tree args1, tree args2)
 
   while (1)
     {
+      tree a1, mv1, a2, mv2;
       if (args1 == 0 && args2 == 0)
        return val;
       /* If one list is shorter than the other,
         they fail to match.  */
       if (args1 == 0 || args2 == 0)
        return 0;
+      mv1 = a1 = TREE_VALUE (args1);
+      mv2 = a2 = TREE_VALUE (args2);
+      if (mv1 && mv1 != error_mark_node && TREE_CODE (mv1) != ARRAY_TYPE)
+       mv1 = TYPE_MAIN_VARIANT (mv1);
+      if (mv2 && mv2 != error_mark_node && TREE_CODE (mv2) != ARRAY_TYPE)
+       mv2 = TYPE_MAIN_VARIANT (mv2);
       /* A null pointer instead of a type
         means there is supposed to be an argument
         but nothing is specified about what type it has.
         So match anything that self-promotes.  */
-      if (TREE_VALUE (args1) == 0)
+      if (a1 == 0)
        {
-         if (c_type_promotes_to (TREE_VALUE (args2)) != TREE_VALUE (args2))
+         if (c_type_promotes_to (a2) != a2)
            return 0;
        }
-      else if (TREE_VALUE (args2) == 0)
+      else if (a2 == 0)
        {
-         if (c_type_promotes_to (TREE_VALUE (args1)) != TREE_VALUE (args1))
+         if (c_type_promotes_to (a1) != a1)
            return 0;
        }
       /* If one of the lists has an error marker, ignore this arg.  */
-      else if (TREE_CODE (TREE_VALUE (args1)) == ERROR_MARK
-              || TREE_CODE (TREE_VALUE (args2)) == ERROR_MARK)
+      else if (TREE_CODE (a1) == ERROR_MARK
+              || TREE_CODE (a2) == ERROR_MARK)
        ;
-      else if (! (newval = comptypes (TYPE_MAIN_VARIANT (TREE_VALUE (args1)),
-                                     TYPE_MAIN_VARIANT (TREE_VALUE (args2)))))
+      else if (!(newval = comptypes (mv1, mv2)))
        {
          /* Allow  wait (union {union wait *u; int *i} *)
             and  wait (union wait *)  to be compatible.  */
-         if (TREE_CODE (TREE_VALUE (args1)) == UNION_TYPE
-             && (TYPE_NAME (TREE_VALUE (args1)) == 0
-                 || TYPE_TRANSPARENT_UNION (TREE_VALUE (args1)))
-             && TREE_CODE (TYPE_SIZE (TREE_VALUE (args1))) == INTEGER_CST
-             && tree_int_cst_equal (TYPE_SIZE (TREE_VALUE (args1)),
-                                    TYPE_SIZE (TREE_VALUE (args2))))
+         if (TREE_CODE (a1) == UNION_TYPE
+             && (TYPE_NAME (a1) == 0
+                 || TYPE_TRANSPARENT_UNION (a1))
+             && TREE_CODE (TYPE_SIZE (a1)) == INTEGER_CST
+             && tree_int_cst_equal (TYPE_SIZE (a1),
+                                    TYPE_SIZE (a2)))
            {
              tree memb;
-             for (memb = TYPE_FIELDS (TREE_VALUE (args1));
+             for (memb = TYPE_FIELDS (a1);
                   memb; memb = TREE_CHAIN (memb))
-               if (comptypes (TREE_TYPE (memb), TREE_VALUE (args2)))
-                 break;
+               {
+                 tree mv3 = TREE_TYPE (memb);
+                 if (mv3 && mv3 != error_mark_node
+                     && TREE_CODE (mv3) != ARRAY_TYPE)
+                   mv3 = TYPE_MAIN_VARIANT (mv3);
+                 if (comptypes (mv3, mv2))
+                   break;
+               }
              if (memb == 0)
                return 0;
            }
-         else if (TREE_CODE (TREE_VALUE (args2)) == UNION_TYPE
-                  && (TYPE_NAME (TREE_VALUE (args2)) == 0
-                      || TYPE_TRANSPARENT_UNION (TREE_VALUE (args2)))
-                  && TREE_CODE (TYPE_SIZE (TREE_VALUE (args2))) == INTEGER_CST
-                  && tree_int_cst_equal (TYPE_SIZE (TREE_VALUE (args2)),
-                                         TYPE_SIZE (TREE_VALUE (args1))))
+         else if (TREE_CODE (a2) == UNION_TYPE
+                  && (TYPE_NAME (a2) == 0
+                      || TYPE_TRANSPARENT_UNION (a2))
+                  && TREE_CODE (TYPE_SIZE (a2)) == INTEGER_CST
+                  && tree_int_cst_equal (TYPE_SIZE (a2),
+                                         TYPE_SIZE (a1)))
            {
              tree memb;
-             for (memb = TYPE_FIELDS (TREE_VALUE (args2));
+             for (memb = TYPE_FIELDS (a2);
                   memb; memb = TREE_CHAIN (memb))
-               if (comptypes (TREE_TYPE (memb), TREE_VALUE (args1)))
-                 break;
+               {
+                 tree mv3 = TREE_TYPE (memb);
+                 if (mv3 && mv3 != error_mark_node
+                     && TREE_CODE (mv3) != ARRAY_TYPE)
+                   mv3 = TYPE_MAIN_VARIANT (mv3);
+                 if (comptypes (mv3, mv1))
+                   break;
+               }
              if (memb == 0)
                return 0;
            }
@@ -1092,7 +1190,7 @@ type_lists_compatible_p (tree args1, tree args2)
 \f
 /* Compute the size to increment a pointer by.  */
 
-tree
+static tree
 c_size_in_bytes (tree type)
 {
   enum tree_code code = TREE_CODE (type);
@@ -1122,7 +1220,7 @@ decl_constant_value (tree decl)
         isn't valid for a PARM_DECL.  */
       current_function_decl != 0
       && TREE_CODE (decl) != PARM_DECL
-      && ! TREE_THIS_VOLATILE (decl)
+      && !TREE_THIS_VOLATILE (decl)
       && TREE_READONLY (decl)
       && DECL_INITIAL (decl) != 0
       && TREE_CODE (DECL_INITIAL (decl)) != ERROR_MARK
@@ -1147,18 +1245,26 @@ decl_constant_value (tree decl)
 static tree
 decl_constant_value_for_broken_optimization (tree decl)
 {
+  tree ret;
+
   if (pedantic || DECL_MODE (decl) == BLKmode)
     return decl;
-  else
-    return decl_constant_value (decl);
+
+  ret = decl_constant_value (decl);
+  /* Avoid unwanted tree sharing between the initializer and current
+     function's body where the tree can be modified e.g. by the
+     gimplifier.  */
+  if (ret != decl && TREE_STATIC (decl))
+    ret = unshare_expr (ret);
+  return ret;
 }
 
 
 /* Perform the default conversion of arrays and functions to pointers.
    Return the result of converting EXP.  For any other expression, just
-   return EXP.  */
+   return EXP after removing NOPs.  */
 
-static tree
+tree
 default_function_array_conversion (tree exp)
 {
   tree orig_exp;
@@ -1197,7 +1303,7 @@ default_function_array_conversion (tree exp)
       int volatilep = 0;
       int lvalue_array_p;
 
-      if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'r' || DECL_P (exp))
+      if (REFERENCE_CLASS_P (exp) || DECL_P (exp))
        {
          constp = TREE_READONLY (exp);
          volatilep = TREE_THIS_VOLATILE (exp);
@@ -1253,47 +1359,17 @@ default_function_array_conversion (tree exp)
   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.
-   In addition, manifest constants symbols are replaced by their values.  */
+
+/* EXP is an expression of integer type.  Apply the integer promotions
+   to it and return the promoted value.  */
 
 tree
-default_conversion (tree exp)
+perform_integral_promotions (tree exp)
 {
-  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)
-    exp = DECL_INITIAL (exp);
-
-  /* Replace a nonvolatile const static variable with its value unless
-     it is an array, in which case we must be sure that taking the
-     address of the array produces consistent results.  */
-  else if (optimize && TREE_CODE (exp) == VAR_DECL && code != ARRAY_TYPE)
-    {
-      exp = decl_constant_value_for_broken_optimization (exp);
-      type = TREE_TYPE (exp);
-    }
-
-  /* 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)))
-    exp = TREE_OPERAND (exp, 0);
-
-  if (TREE_NO_WARNING (orig_exp))
-    TREE_NO_WARNING (exp) = 1;
+  gcc_assert (INTEGRAL_TYPE_P (type));
 
   /* Normally convert enums to int,
      but convert wide enums to something wider.  */
@@ -1308,6 +1384,8 @@ default_conversion (tree exp)
       return convert (type, exp);
     }
 
+  /* ??? This should no longer be needed now bit-fields have their
+     proper types.  */
   if (TREE_CODE (exp) == COMPONENT_REF
       && DECL_C_BIT_FIELD (TREE_OPERAND (exp, 1))
       /* If it's thinner than an int, promote it like a
@@ -1326,6 +1404,49 @@ default_conversion (tree exp)
       return convert (integer_type_node, exp);
     }
 
+  return exp;
+}
+
+
+/* Perform default promotions for C data used in expressions.
+   Enumeral types or short or char are converted to int.
+   In addition, manifest constants symbols are replaced by their values.  */
+
+tree
+default_conversion (tree exp)
+{
+  tree orig_exp;
+  tree type = TREE_TYPE (exp);
+  enum tree_code code = TREE_CODE (type);
+
+  /* Functions and arrays have been converted during parsing.  */
+  gcc_assert (code != FUNCTION_TYPE);
+  if (code == ARRAY_TYPE)
+    return exp;
+
+  /* Constants can be used directly unless they're not loadable.  */
+  if (TREE_CODE (exp) == CONST_DECL)
+    exp = DECL_INITIAL (exp);
+
+  /* Replace a nonvolatile const static variable with its value unless
+     it is an array, in which case we must be sure that taking the
+     address of the array produces consistent results.  */
+  else if (optimize && TREE_CODE (exp) == VAR_DECL && code != ARRAY_TYPE)
+    {
+      exp = decl_constant_value_for_broken_optimization (exp);
+      type = TREE_TYPE (exp);
+    }
+
+  /* Strip no-op conversions.  */
+  orig_exp = exp;
+  STRIP_TYPE_NOPS (exp);
+
+  if (TREE_NO_WARNING (orig_exp))
+    TREE_NO_WARNING (exp) = 1;
+
+  if (INTEGRAL_TYPE_P (type))
+    return perform_integral_promotions (exp);
+
   if (code == VOID_TYPE)
     {
       error ("void value not ignored as it ought to be");
@@ -1354,7 +1475,7 @@ lookup_field (tree decl, tree component)
      find the element.  Otherwise, do a linear search.  TYPE_LANG_SPECIFIC
      will always be set for structures which have many elements.  */
 
-  if (TYPE_LANG_SPECIFIC (type))
+  if (TYPE_LANG_SPECIFIC (type) && TYPE_LANG_SPECIFIC (type)->s)
     {
       int bot, top, half;
       tree *field_array = &TYPE_LANG_SPECIFIC (type)->s->elts[0];
@@ -1443,26 +1564,6 @@ build_component_ref (tree datum, tree component)
   if (!objc_is_public (datum, component))
     return error_mark_node;
 
-  /* If DATUM is a COMPOUND_EXPR, move our reference inside it.
-     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 build2 (COMPOUND_EXPR, TREE_TYPE (value),
-                      TREE_OPERAND (datum, 0), non_lvalue (value));
-      }
-    default:
-      break;
-    }
-
   /* See if there is a field or component with name COMPONENT.  */
 
   if (code == RECORD_TYPE || code == UNION_TYPE)
@@ -1477,9 +1578,7 @@ build_component_ref (tree datum, tree component)
 
       if (!field)
        {
-         error ("%s has no member named `%s'",
-                code == RECORD_TYPE ? "structure" : "union",
-                IDENTIFIER_POINTER (component));
+         error ("%qT has no member named %qE", type, component);
          return error_mark_node;
        }
 
@@ -1514,8 +1613,8 @@ build_component_ref (tree datum, tree component)
       return ref;
     }
   else if (code != ERROR_MARK)
-    error ("request for member `%s' in something not a structure or union",
-           IDENTIFIER_POINTER (component));
+    error ("request for member %qE in something not a structure or union",
+          component);
 
   return error_mark_node;
 }
@@ -1539,7 +1638,9 @@ build_indirect_ref (tree ptr, const char *errorstring)
       else
        {
          tree t = TREE_TYPE (type);
-         tree ref = build1 (INDIRECT_REF, TYPE_MAIN_VARIANT (t), pointer);
+         tree ref;
+
+         ref = build1 (INDIRECT_REF, t, pointer);
 
          if (!COMPLETE_OR_VOID_TYPE_P (t) && TREE_CODE (t) != ARRAY_TYPE)
            {
@@ -1547,7 +1648,7 @@ build_indirect_ref (tree ptr, const char *errorstring)
              return error_mark_node;
            }
          if (VOID_TYPE_P (t) && skip_evaluation == 0)
-           warning ("dereferencing `void *' pointer");
+           warning (0, "dereferencing %<void *%> pointer");
 
          /* We *must* set TREE_READONLY when dereferencing a pointer to const,
             so that we get the proper error message if the result is used
@@ -1564,7 +1665,7 @@ build_indirect_ref (tree ptr, const char *errorstring)
        }
     }
   else if (TREE_CODE (pointer) != ERROR_MARK)
-    error ("invalid type argument of `%s'", errorstring);
+    error ("invalid type argument of %qs", errorstring);
   return error_mark_node;
 }
 
@@ -1580,39 +1681,58 @@ build_indirect_ref (tree ptr, const char *errorstring)
 tree
 build_array_ref (tree array, tree index)
 {
-  if (index == 0)
-    {
-      error ("subscript missing in array reference");
-      return error_mark_node;
-    }
-
+  bool swapped = false;
   if (TREE_TYPE (array) == error_mark_node
       || TREE_TYPE (index) == error_mark_node)
     return error_mark_node;
 
-  if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE)
+  if (TREE_CODE (TREE_TYPE (array)) != ARRAY_TYPE
+      && TREE_CODE (TREE_TYPE (array)) != POINTER_TYPE)
     {
-      tree rval, type;
-
-      /* Subscripting with type char is likely to lose
-        on a machine where chars are signed.
-        So warn on any machine, but optionally.
-        Don't warn for unsigned char since that type is safe.
-        Don't warn for signed char because anyone who uses that
-        must have done so deliberately.  */
-      if (warn_char_subscripts
-         && TYPE_MAIN_VARIANT (TREE_TYPE (index)) == char_type_node)
-       warning ("array subscript has type `char'");
-
-      /* Apply default promotions *after* noticing character types.  */
-      index = default_conversion (index);
-
-      /* Require integer *after* promotion, for sake of enums.  */
-      if (TREE_CODE (TREE_TYPE (index)) != INTEGER_TYPE)
+      tree temp;
+      if (TREE_CODE (TREE_TYPE (index)) != ARRAY_TYPE
+         && TREE_CODE (TREE_TYPE (index)) != POINTER_TYPE)
        {
-         error ("array subscript is not an integer");
+         error ("subscripted value is neither array nor pointer");
          return error_mark_node;
        }
+      temp = array;
+      array = index;
+      index = temp;
+      swapped = true;
+    }
+
+  if (!INTEGRAL_TYPE_P (TREE_TYPE (index)))
+    {
+      error ("array subscript is not an integer");
+      return error_mark_node;
+    }
+
+  if (TREE_CODE (TREE_TYPE (TREE_TYPE (array))) == FUNCTION_TYPE)
+    {
+      error ("subscripted value is pointer to function");
+      return error_mark_node;
+    }
+
+  /* Subscripting with type char is likely to lose on a machine where
+     chars are signed.  So warn on any machine, but optionally.  Don't
+     warn for unsigned char since that type is safe.  Don't warn for
+     signed char because anyone who uses that must have done so
+     deliberately.  ??? Existing practice has also been to warn only
+     when the char index is syntactically the index, not for
+     char[array].  */
+  if (!swapped
+      && TYPE_MAIN_VARIANT (TREE_TYPE (index)) == char_type_node)
+    warning (OPT_Wchar_subscripts, "array subscript has type %<char%>");
+
+  /* Apply default promotions *after* noticing character types.  */
+  index = default_conversion (index);
+
+  gcc_assert (TREE_CODE (TREE_TYPE (index)) == INTEGER_TYPE);
+
+  if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE)
+    {
+      tree rval, type;
 
       /* An array that is indexed by a non-constant
         cannot be stored in a register; we must be able to do
@@ -1631,7 +1751,7 @@ build_array_ref (tree array, tree index)
         to access a non-existent part of the register.  */
       if (TREE_CODE (index) == INTEGER_CST
          && TYPE_DOMAIN (TREE_TYPE (array))
-         && ! int_fits_type_p (index, TYPE_DOMAIN (TREE_TYPE (array))))
+         && !int_fits_type_p (index, TYPE_DOMAIN (TREE_TYPE (array))))
        {
          if (!c_mark_addressable (array))
            return error_mark_node;
@@ -1643,12 +1763,14 @@ build_array_ref (tree array, tree index)
          while (TREE_CODE (foo) == COMPONENT_REF)
            foo = TREE_OPERAND (foo, 0);
          if (TREE_CODE (foo) == VAR_DECL && C_DECL_REGISTER (foo))
-           pedwarn ("ISO C forbids subscripting `register' array");
-         else if (! flag_isoc99 && ! lvalue_p (foo))
+           pedwarn ("ISO C forbids subscripting %<register%> array");
+         else if (!flag_isoc99 && !lvalue_p (foo))
            pedwarn ("ISO C90 forbids subscripting non-lvalue array");
        }
 
-      type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (array)));
+      type = TREE_TYPE (TREE_TYPE (array));
+      if (TREE_CODE (type) != ARRAY_TYPE)
+       type = TYPE_MAIN_VARIANT (type);
       rval = build4 (ARRAY_REF, type, array, index, NULL_TREE, NULL_TREE);
       /* Array ref is const/volatile if the array elements are
          or if the array is.  */
@@ -1667,72 +1789,36 @@ build_array_ref (tree array, tree index)
            | TREE_THIS_VOLATILE (array));
       return require_complete_type (fold (rval));
     }
+  else
+    {
+      tree ar = default_conversion (array);
 
-  {
-    tree ar = default_conversion (array);
-    tree ind = default_conversion (index);
-
-    /* Do the same warning check as above, but only on the part that's
-       syntactically the index and only if it is also semantically
-       the index.  */
-    if (warn_char_subscripts
-       && TREE_CODE (TREE_TYPE (index)) == INTEGER_TYPE
-       && TYPE_MAIN_VARIANT (TREE_TYPE (index)) == char_type_node)
-      warning ("subscript has type `char'");
-
-    /* Put the integer in IND to simplify error checking.  */
-    if (TREE_CODE (TREE_TYPE (ar)) == INTEGER_TYPE)
-      {
-       tree temp = ar;
-       ar = ind;
-       ind = temp;
-      }
-
-    if (ar == error_mark_node)
-      return ar;
+      if (ar == error_mark_node)
+       return ar;
 
-    if (TREE_CODE (TREE_TYPE (ar)) != POINTER_TYPE
-       || TREE_CODE (TREE_TYPE (TREE_TYPE (ar))) == FUNCTION_TYPE)
-      {
-       error ("subscripted value is neither array nor pointer");
-       return error_mark_node;
-      }
-    if (TREE_CODE (TREE_TYPE (ind)) != INTEGER_TYPE)
-      {
-       error ("array subscript is not an integer");
-       return error_mark_node;
-      }
+      gcc_assert (TREE_CODE (TREE_TYPE (ar)) == POINTER_TYPE);
+      gcc_assert (TREE_CODE (TREE_TYPE (TREE_TYPE (ar))) != FUNCTION_TYPE);
 
-    return build_indirect_ref (build_binary_op (PLUS_EXPR, ar, ind, 0),
-                              "array indexing");
-  }
+      return build_indirect_ref (build_binary_op (PLUS_EXPR, ar, index, 0),
+                                "array indexing");
+    }
 }
 \f
 /* Build an external reference to identifier ID.  FUN indicates
-   whether this will be used for a function call.  */
+   whether this will be used for a function call.  LOC is the source
+   location of the identifier.  */
 tree
-build_external_ref (tree id, int fun)
+build_external_ref (tree id, int fun, location_t loc)
 {
   tree ref;
   tree decl = lookup_name (id);
-  tree objc_ivar = lookup_objc_ivar (id);
+
+  /* In Objective-C, an instance variable (ivar) may be preferred to
+     whatever lookup_name() found.  */
+  decl = objc_lookup_ivar (decl, id);
 
   if (decl && decl != error_mark_node)
-    {
-      /* Properly declared variable or function reference.  */
-      if (!objc_ivar)
-       ref = decl;
-      else if (decl != objc_ivar && !DECL_FILE_SCOPE_P (decl))
-       {
-         warning ("local declaration of `%s' hides instance variable",
-                  IDENTIFIER_POINTER (id));
-         ref = decl;
-       }
-      else
-       ref = objc_ivar;
-    }
-  else if (objc_ivar)
-    ref = objc_ivar;
+    ref = decl;
   else if (fun)
     /* Implicit function declaration.  */
     ref = implicitly_declare (id);
@@ -1742,7 +1828,7 @@ build_external_ref (tree id, int fun)
     return error_mark_node;
   else
     {
-      undeclared_variable (id);
+      undeclared_variable (id, loc);
       return error_mark_node;
     }
 
@@ -1756,6 +1842,16 @@ build_external_ref (tree id, int fun)
     assemble_external (ref);
   TREE_USED (ref) = 1;
 
+  if (TREE_CODE (ref) == FUNCTION_DECL && !in_alignof)
+    {
+      if (!in_sizeof && !in_typeof)
+       C_DECL_USED (ref) = 1;
+      else if (DECL_INITIAL (ref) == 0
+              && DECL_EXTERNAL (ref)
+              && !TREE_PUBLIC (ref))
+       record_maybe_used_decl (ref);
+    }
+
   if (TREE_CODE (ref) == CONST_DECL)
     {
       ref = DECL_INITIAL (ref);
@@ -1777,6 +1873,95 @@ build_external_ref (tree id, int fun)
   return ref;
 }
 
+/* Record details of decls possibly used inside sizeof or typeof.  */
+struct maybe_used_decl
+{
+  /* The decl.  */
+  tree decl;
+  /* The level seen at (in_sizeof + in_typeof).  */
+  int level;
+  /* The next one at this level or above, or NULL.  */
+  struct maybe_used_decl *next;
+};
+
+static struct maybe_used_decl *maybe_used_decls;
+
+/* Record that DECL, an undefined static function reference seen
+   inside sizeof or typeof, might be used if the operand of sizeof is
+   a VLA type or the operand of typeof is a variably modified
+   type.  */
+
+static void
+record_maybe_used_decl (tree decl)
+{
+  struct maybe_used_decl *t = XOBNEW (&parser_obstack, struct maybe_used_decl);
+  t->decl = decl;
+  t->level = in_sizeof + in_typeof;
+  t->next = maybe_used_decls;
+  maybe_used_decls = t;
+}
+
+/* Pop the stack of decls possibly used inside sizeof or typeof.  If
+   USED is false, just discard them.  If it is true, mark them used
+   (if no longer inside sizeof or typeof) or move them to the next
+   level up (if still inside sizeof or typeof).  */
+
+void
+pop_maybe_used (bool used)
+{
+  struct maybe_used_decl *p = maybe_used_decls;
+  int cur_level = in_sizeof + in_typeof;
+  while (p && p->level > cur_level)
+    {
+      if (used)
+       {
+         if (cur_level == 0)
+           C_DECL_USED (p->decl) = 1;
+         else
+           p->level = cur_level;
+       }
+      p = p->next;
+    }
+  if (!used || cur_level == 0)
+    maybe_used_decls = p;
+}
+
+/* Return the result of sizeof applied to EXPR.  */
+
+struct c_expr
+c_expr_sizeof_expr (struct c_expr expr)
+{
+  struct c_expr ret;
+  if (expr.value == error_mark_node)
+    {
+      ret.value = error_mark_node;
+      ret.original_code = ERROR_MARK;
+      pop_maybe_used (false);
+    }
+  else
+    {
+      ret.value = c_sizeof (TREE_TYPE (expr.value));
+      ret.original_code = ERROR_MARK;
+      pop_maybe_used (C_TYPE_VARIABLE_SIZE (TREE_TYPE (expr.value)));
+    }
+  return ret;
+}
+
+/* Return the result of sizeof applied to T, a structure for the type
+   name passed to sizeof (rather than the type itself).  */
+
+struct c_expr
+c_expr_sizeof_type (struct c_type_name *t)
+{
+  tree type;
+  struct c_expr ret;
+  type = groktypename (t);
+  ret.value = c_sizeof (type);
+  ret.original_code = ERROR_MARK;
+  pop_maybe_used (C_TYPE_VARIABLE_SIZE (type));
+  return ret;
+}
+
 /* Build a function call to function FUNCTION with parameters PARAMS.
    PARAMS is a list--a chain of TREE_LIST nodes--in which the
    TREE_VALUE of each node is a parameter-expression.
@@ -1796,19 +1981,22 @@ build_function_call (tree function, tree params)
   /* Convert anything with function type to a pointer-to-function.  */
   if (TREE_CODE (function) == FUNCTION_DECL)
     {
-      name = DECL_NAME (function);
+      /* Implement type-directed function overloading for builtins.
+        resolve_overloaded_builtin and targetm.resolve_overloaded_builtin
+        handle all the type checking.  The result is a complete expression
+        that implements this function call.  */
+      tem = resolve_overloaded_builtin (function, params);
+      if (tem)
+       return tem;
 
-      /* Differs from default_conversion by not setting TREE_ADDRESSABLE
-        (because calling an inline function does not mean the function
-        needs to be separately compiled).  */
-      fntype = build_type_variant (TREE_TYPE (function),
-                                  TREE_READONLY (function),
-                                  TREE_THIS_VOLATILE (function));
+      name = DECL_NAME (function);
       fundecl = function;
-      function = build1 (ADDR_EXPR, build_pointer_type (fntype), function);
     }
-  else
-    function = default_conversion (function);
+  function = default_function_array_conversion (function);
+
+  /* For Objective-C, convert any calls via a cast to OBJC_TYPE_REF
+     expressions, like those used for ObjC messenger dispatches.  */
+  function = objc_rewrite_function_call (function, params);
 
   fntype = TREE_TYPE (function);
 
@@ -1818,7 +2006,7 @@ build_function_call (tree function, tree params)
   if (!(TREE_CODE (fntype) == POINTER_TYPE
        && TREE_CODE (TREE_TYPE (fntype)) == FUNCTION_TYPE))
     {
-      error ("called object is not a function");
+      error ("called object %qE is not a function", function);
       return error_mark_node;
     }
 
@@ -1832,16 +2020,11 @@ build_function_call (tree function, tree params)
      If it is not, replace the call by a trap, wrapped up in a compound
      expression if necessary.  This has the nice side-effect to prevent
      the tree-inliner from generating invalid assignment trees which may
-     blow up in the RTL expander later.
-
-     ??? This doesn't work for Objective-C because objc_comptypes
-     refuses to compare function prototypes, yet the compiler appears
-     to build calls that are flagged as invalid by C's comptypes.  */
-  if (! c_dialect_objc ()
-      && TREE_CODE (function) == NOP_EXPR
+     blow up in the RTL expander later.  */
+  if (TREE_CODE (function) == NOP_EXPR
       && TREE_CODE (tem = TREE_OPERAND (function, 0)) == ADDR_EXPR
       && TREE_CODE (tem = TREE_OPERAND (tem, 0)) == FUNCTION_DECL
-      && ! comptypes (fntype, TREE_TYPE (tem)))
+      && !comptypes (fntype, TREE_TYPE (tem)))
     {
       tree return_type = TREE_TYPE (fntype);
       tree trap = build_function_call (built_in_decls[BUILT_IN_TRAP],
@@ -1850,7 +2033,7 @@ build_function_call (tree function, tree params)
       /* This situation leads to run-time undefined behavior.  We can't,
         therefore, simply error unless we can prove that all possible
         executions of the program must execute the code.  */
-      warning ("function called through a non-compatible type");
+      warning (0, "function called through a non-compatible type");
 
       /* We can, however, treat "undefined" any way we please.
         Call abort to encourage the user to fix the program.  */
@@ -1867,7 +2050,7 @@ build_function_call (tree function, tree params)
                                          build_constructor (return_type,
                                                             NULL_TREE));
          else
-           rhs = fold (build1 (NOP_EXPR, return_type, integer_zero_node));
+           rhs = fold_build1 (NOP_EXPR, return_type, integer_zero_node);
 
          return build2 (COMPOUND_EXPR, return_type, trap, rhs);
        }
@@ -1877,11 +2060,15 @@ build_function_call (tree function, tree params)
      function prototype, or apply default promotions.  */
 
   coerced_params
-    = convert_arguments (TYPE_ARG_TYPES (fntype), params, name, fundecl);
+    = convert_arguments (TYPE_ARG_TYPES (fntype), params, function, fundecl);
+
+  if (coerced_params == error_mark_node)
+    return error_mark_node;
 
   /* Check that the arguments to the function are valid.  */
 
-  check_function_arguments (TYPE_ATTRIBUTES (fntype), coerced_params);
+  check_function_arguments (TYPE_ATTRIBUTES (fntype), coerced_params,
+                           TYPE_ARG_TYPES (fntype));
 
   result = build3 (CALL_EXPR, TREE_TYPE (fntype),
                   function, coerced_params, NULL_TREE);
@@ -1906,7 +2093,8 @@ build_function_call (tree function, tree params)
 \f
 /* Convert the argument expressions in the list VALUES
    to the types in the list TYPELIST.  The result is a list of converted
-   argument expressions.
+   argument expressions, unless there are too few arguments in which
+   case it is error_mark_node.
 
    If TYPELIST is exhausted, or when an element has NULL as its type,
    perform the default conversions.
@@ -1915,7 +2103,8 @@ build_function_call (tree function, tree params)
    It may be 0, if that info is not available.
    It is used only for generating error messages.
 
-   NAME is an IDENTIFIER_NODE or 0.  It is used only for error messages.
+   FUNCTION is a tree for the called function.  It is used only for
+   error messages, where it is formatted with %qE.
 
    This is also where warnings about wrong number of args are generated.
 
@@ -1923,11 +2112,21 @@ build_function_call (tree function, tree params)
    with the elements of the list in the TREE_VALUE slots of those nodes.  */
 
 static tree
-convert_arguments (tree typelist, tree values, tree name, tree fundecl)
+convert_arguments (tree typelist, tree values, tree function, tree fundecl)
 {
   tree typetail, valtail;
   tree result = NULL;
   int parmnum;
+  tree selector;
+
+  /* Change pointer to function to the function itself for
+     diagnostics.  */
+  if (TREE_CODE (function) == ADDR_EXPR
+      && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL)
+    function = TREE_OPERAND (function, 0);
+
+  /* Handle an ObjC selector specially for diagnostics.  */
+  selector = objc_message_selector ();
 
   /* Scan the given expressions and types, producing individual
      converted arguments and pushing them on RESULT in reverse order.  */
@@ -1938,24 +2137,23 @@ convert_arguments (tree typelist, tree values, tree name, tree fundecl)
     {
       tree type = typetail ? TREE_VALUE (typetail) : 0;
       tree val = TREE_VALUE (valtail);
+      tree rname = function;
+      int argnum = parmnum + 1;
+      const char *invalid_func_diag;
 
       if (type == void_type_node)
        {
-         if (name)
-           error ("too many arguments to function `%s'",
-                  IDENTIFIER_POINTER (name));
-         else
-           error ("too many arguments to function");
+         error ("too many arguments to function %qE", function);
          break;
        }
 
-      /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue.  */
-      /* Do not use STRIP_NOPS here!  We do not want an enumerator with value 0
-        to convert automatically to a pointer.  */
-      if (TREE_CODE (val) == NON_LVALUE_EXPR)
-       val = TREE_OPERAND (val, 0);
+      if (selector && argnum > 2)
+       {
+         rname = selector;
+         argnum -= 2;
+       }
 
-      val = default_function_array_conversion (val);
+      STRIP_TYPE_NOPS (val);
 
       val = require_complete_type (val);
 
@@ -1964,7 +2162,7 @@ convert_arguments (tree typelist, tree values, tree name, tree fundecl)
          /* Formal parm type is specified by a function prototype.  */
          tree parmval;
 
-         if (!COMPLETE_TYPE_P (type))
+         if (type == error_mark_node || !COMPLETE_TYPE_P (type))
            {
              error ("type of formal parameter %d is incomplete", parmnum + 1);
              parmval = val;
@@ -1979,22 +2177,34 @@ convert_arguments (tree typelist, tree values, tree name, tree fundecl)
 
                  if (INTEGRAL_TYPE_P (type)
                      && TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
-                   warn_for_assignment ("%s as integer rather than floating due to prototype", (char *) 0, name, parmnum + 1);
+                   warning (0, "passing argument %d of %qE as integer "
+                            "rather than floating due to prototype",
+                            argnum, rname);
                  if (INTEGRAL_TYPE_P (type)
                      && TREE_CODE (TREE_TYPE (val)) == COMPLEX_TYPE)
-                   warn_for_assignment ("%s as integer rather than complex due to prototype", (char *) 0, name, parmnum + 1);
+                   warning (0, "passing argument %d of %qE as integer "
+                            "rather than complex due to prototype",
+                            argnum, rname);
                  else if (TREE_CODE (type) == COMPLEX_TYPE
                           && TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
-                   warn_for_assignment ("%s as complex rather than floating due to prototype", (char *) 0, name, parmnum + 1);
+                   warning (0, "passing argument %d of %qE as complex "
+                            "rather than floating due to prototype",
+                            argnum, rname);
                  else if (TREE_CODE (type) == REAL_TYPE
                           && INTEGRAL_TYPE_P (TREE_TYPE (val)))
-                   warn_for_assignment ("%s as floating rather than integer due to prototype", (char *) 0, name, parmnum + 1);
+                   warning (0, "passing argument %d of %qE as floating "
+                            "rather than integer due to prototype",
+                            argnum, rname);
                  else if (TREE_CODE (type) == COMPLEX_TYPE
                           && INTEGRAL_TYPE_P (TREE_TYPE (val)))
-                   warn_for_assignment ("%s as complex rather than integer due to prototype", (char *) 0, name, parmnum + 1);
+                   warning (0, "passing argument %d of %qE as complex "
+                            "rather than integer due to prototype",
+                            argnum, rname);
                  else if (TREE_CODE (type) == REAL_TYPE
                           && TREE_CODE (TREE_TYPE (val)) == COMPLEX_TYPE)
-                   warn_for_assignment ("%s as floating rather than complex due to prototype", (char *) 0, name, parmnum + 1);
+                   warning (0, "passing argument %d of %qE as floating "
+                            "rather than complex due to prototype",
+                            argnum, rname);
                  /* ??? At some point, messages should be written about
                     conversions between complex types, but that's too messy
                     to do now.  */
@@ -2004,7 +2214,9 @@ convert_arguments (tree typelist, tree values, tree name, tree fundecl)
                      /* Warn if any argument is passed as `float',
                         since without a prototype it would be `double'.  */
                      if (formal_prec == TYPE_PRECISION (float_type_node))
-                       warn_for_assignment ("%s as `float' rather than `double' due to prototype", (char *) 0, name, parmnum + 1);
+                       warning (0, "passing argument %d of %qE as %<float%> "
+                                "rather than %<double%> due to prototype",
+                                argnum, rname);
                    }
                  /* Detect integer changing in width or signedness.
                     These warnings are only activated with
@@ -2022,7 +2234,9 @@ convert_arguments (tree typelist, tree values, tree name, tree fundecl)
                           and the actual arg is that enum type.  */
                        ;
                      else if (formal_prec != TYPE_PRECISION (type1))
-                       warn_for_assignment ("%s with different width due to prototype", (char *) 0, name, parmnum + 1);
+                       warning (OPT_Wconversion, "passing argument %d of %qE "
+                                "with different width due to prototype",
+                                argnum, rname);
                      else if (TYPE_UNSIGNED (type) == TYPE_UNSIGNED (type1))
                        ;
                      /* Don't complain if the formal parameter type
@@ -2035,11 +2249,6 @@ convert_arguments (tree typelist, tree values, tree name, tree fundecl)
                        /* Change in signedness doesn't matter
                           if a constant value is unaffected.  */
                        ;
-                     /* Likewise for a constant in a NOP_EXPR.  */
-                     else if (TREE_CODE (val) == NOP_EXPR
-                              && TREE_CODE (TREE_OPERAND (val, 0)) == INTEGER_CST
-                              && int_fits_type_p (TREE_OPERAND (val, 0), type))
-                       ;
                      /* If the value is extended from a narrower
                         unsigned type, it doesn't matter whether we
                         pass it as signed or unsigned; the value
@@ -2048,15 +2257,18 @@ convert_arguments (tree typelist, tree values, tree name, tree fundecl)
                               && TYPE_UNSIGNED (TREE_TYPE (val)))
                        ;
                      else if (TYPE_UNSIGNED (type))
-                       warn_for_assignment ("%s as unsigned due to prototype", (char *) 0, name, parmnum + 1);
+                       warning (OPT_Wconversion, "passing argument %d of %qE "
+                                "as unsigned due to prototype",
+                                argnum, rname);
                      else
-                       warn_for_assignment ("%s as signed due to prototype", (char *) 0, name, parmnum + 1);
+                       warning (OPT_Wconversion, "passing argument %d of %qE "
+                                "as signed due to prototype", argnum, rname);
                    }
                }
 
-             parmval = convert_for_assignment (type, val,
-                                               (char *) 0, /* arg passing  */
-                                               fundecl, name, parmnum + 1);
+             parmval = convert_for_assignment (type, val, ic_argpass,
+                                               fundecl, function,
+                                               parmnum + 1);
 
              if (targetm.calls.promote_prototypes (fundecl ? TREE_TYPE (fundecl) : 0)
                  && INTEGRAL_TYPE_P (type)
@@ -2070,6 +2282,12 @@ convert_arguments (tree typelist, tree values, tree name, tree fundecl)
                   < TYPE_PRECISION (double_type_node)))
        /* Convert `float' to `double'.  */
        result = tree_cons (NULL_TREE, convert (double_type_node, val), result);
+      else if ((invalid_func_diag = 
+               targetm.calls.invalid_arg_for_unprototyped_fn (typelist, fundecl, val)))
+       {
+         error (invalid_func_diag);
+         return error_mark_node; 
+       }
       else
        /* Convert `short' and `char' to full-size `int'.  */
        result = tree_cons (NULL_TREE, default_conversion (val), result);
@@ -2080,21 +2298,34 @@ convert_arguments (tree typelist, tree values, tree name, tree fundecl)
 
   if (typetail != 0 && TREE_VALUE (typetail) != void_type_node)
     {
-      if (name)
-       error ("too few arguments to function `%s'",
-              IDENTIFIER_POINTER (name));
-      else
-       error ("too few arguments to function");
+      error ("too few arguments to function %qE", function);
+      return error_mark_node;
     }
 
   return nreverse (result);
 }
 \f
-/* This is the entry point used by the parser
-   for binary operators in the input.
-   In addition to constructing the expression,
-   we check for operands that were written with other binary operators
-   in a way that is likely to confuse the user.  */
+/* This is the entry point used by the parser to build unary operators
+   in the input.  CODE, a tree_code, specifies the unary operator, and
+   ARG is the operand.  For unary plus, the C parser currently uses
+   CONVERT_EXPR for code.  */
+
+struct c_expr
+parser_build_unary_op (enum tree_code code, struct c_expr arg)
+{
+  struct c_expr result;
+
+  result.original_code = ERROR_MARK;
+  result.value = build_unary_op (code, arg.value, 0);
+  overflow_warning (result.value);
+  return result;
+}
+
+/* This is the entry point used by the parser to build binary operators
+   in the input.  CODE, a tree_code, specifies the binary operator, and
+   ARG1 and ARG2 are the operands.  In addition to constructing the
+   expression, we check for operands that were written with other binary
+   operators in a way that is likely to confuse the user.  */
 
 struct c_expr
 parser_build_binary_op (enum tree_code code, struct c_expr arg1,
@@ -2119,14 +2350,14 @@ parser_build_binary_op (enum tree_code code, struct c_expr arg1,
        {
          if (code1 == PLUS_EXPR || code1 == MINUS_EXPR
              || code2 == PLUS_EXPR || code2 == MINUS_EXPR)
-           warning ("suggest parentheses around + or - inside shift");
+           warning (0, "suggest parentheses around + or - inside shift");
        }
 
       if (code == TRUTH_ORIF_EXPR)
        {
          if (code1 == TRUTH_ANDIF_EXPR
              || code2 == TRUTH_ANDIF_EXPR)
-           warning ("suggest parentheses around && within ||");
+           warning (0, "suggest parentheses around && within ||");
        }
 
       if (code == BIT_IOR_EXPR)
@@ -2135,10 +2366,11 @@ parser_build_binary_op (enum tree_code code, struct c_expr arg1,
              || code1 == PLUS_EXPR || code1 == MINUS_EXPR
              || code2 == BIT_AND_EXPR || code2 == BIT_XOR_EXPR
              || code2 == PLUS_EXPR || code2 == MINUS_EXPR)
-           warning ("suggest parentheses around arithmetic in operand of |");
+           warning (0, "suggest parentheses around arithmetic in operand of |");
          /* Check cases like x|y==z */
-         if (TREE_CODE_CLASS (code1) == '<' || TREE_CODE_CLASS (code2) == '<')
-           warning ("suggest parentheses around comparison in operand of |");
+         if (TREE_CODE_CLASS (code1) == tcc_comparison
+             || TREE_CODE_CLASS (code2) == tcc_comparison)
+           warning (0, "suggest parentheses around comparison in operand of |");
        }
 
       if (code == BIT_XOR_EXPR)
@@ -2147,26 +2379,28 @@ parser_build_binary_op (enum tree_code code, struct c_expr arg1,
              || code1 == PLUS_EXPR || code1 == MINUS_EXPR
              || code2 == BIT_AND_EXPR
              || code2 == PLUS_EXPR || code2 == MINUS_EXPR)
-           warning ("suggest parentheses around arithmetic in operand of ^");
+           warning (0, "suggest parentheses around arithmetic in operand of ^");
          /* Check cases like x^y==z */
-         if (TREE_CODE_CLASS (code1) == '<' || TREE_CODE_CLASS (code2) == '<')
-           warning ("suggest parentheses around comparison in operand of ^");
+         if (TREE_CODE_CLASS (code1) == tcc_comparison
+             || TREE_CODE_CLASS (code2) == tcc_comparison)
+           warning (0, "suggest parentheses around comparison in operand of ^");
        }
 
       if (code == BIT_AND_EXPR)
        {
          if (code1 == PLUS_EXPR || code1 == MINUS_EXPR
              || code2 == PLUS_EXPR || code2 == MINUS_EXPR)
-           warning ("suggest parentheses around + or - in operand of &");
+           warning (0, "suggest parentheses around + or - in operand of &");
          /* Check cases like x&y==z */
-         if (TREE_CODE_CLASS (code1) == '<' || TREE_CODE_CLASS (code2) == '<')
-           warning ("suggest parentheses around comparison in operand of &");
+         if (TREE_CODE_CLASS (code1) == tcc_comparison
+             || TREE_CODE_CLASS (code2) == tcc_comparison)
+           warning (0, "suggest parentheses around comparison in operand of &");
        }
       /* Similarly, check for cases like 1<=i<=10 that are probably errors.  */
-      if (TREE_CODE_CLASS (code) == '<'
-         && (TREE_CODE_CLASS (code1) == '<'
-             || TREE_CODE_CLASS (code2) == '<'))
-       warning ("comparisons like X<=Y<=Z do not have their mathematical meaning");
+      if (TREE_CODE_CLASS (code) == tcc_comparison
+         && (TREE_CODE_CLASS (code1) == tcc_comparison
+             || TREE_CODE_CLASS (code2) == tcc_comparison))
+       warning (0, "comparisons like X<=Y<=Z do not have their mathematical meaning");
 
     }
 
@@ -2192,7 +2426,7 @@ pointer_diff (tree op0, tree op1)
   if (pedantic || warn_pointer_arith)
     {
       if (TREE_CODE (target_type) == VOID_TYPE)
-       pedwarn ("pointer of type `void *' used in subtraction");
+       pedwarn ("pointer of type %<void *%> used in subtraction");
       if (TREE_CODE (target_type) == FUNCTION_TYPE)
        pedwarn ("pointer to a function used in subtraction");
     }
@@ -2246,7 +2480,7 @@ pointer_diff (tree op0, tree op1)
   op1 = c_size_in_bytes (target_type);
 
   /* Divide by the size, in easiest possible way.  */
-  return fold (build2 (EXACT_DIV_EXPR, restype, op0, convert (restype, op1)));
+  return fold_build2 (EXACT_DIV_EXPR, restype, op0, convert (restype, op1));
 }
 \f
 /* Construct and perhaps optimize a tree representation
@@ -2267,12 +2501,20 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
   enum tree_code typecode = TREE_CODE (TREE_TYPE (arg));
   tree val;
   int noconvert = flag;
+  const char *invalid_op_diag;
 
   if (typecode == ERROR_MARK)
     return error_mark_node;
   if (typecode == ENUMERAL_TYPE || typecode == BOOLEAN_TYPE)
     typecode = INTEGER_TYPE;
 
+  if ((invalid_op_diag
+       = targetm.invalid_unary_op (code, TREE_TYPE (xarg))))
+    {
+      error (invalid_op_diag);
+      return error_mark_node;
+    }
+
   switch (code)
     {
     case CONVERT_EXPR:
@@ -2313,7 +2555,7 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
        {
          code = CONJ_EXPR;
          if (pedantic)
-           pedwarn ("ISO C does not support `~' for complex conjugation");
+           pedwarn ("ISO C does not support %<~%> for complex conjugation");
          if (!noconvert)
            arg = default_conversion (arg);
        }
@@ -2349,14 +2591,12 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
     case TRUTH_NOT_EXPR:
       if (typecode != INTEGER_TYPE
          && typecode != REAL_TYPE && typecode != POINTER_TYPE
-         && typecode != COMPLEX_TYPE
-         /* These will convert to a pointer.  */
-         && typecode != ARRAY_TYPE && typecode != FUNCTION_TYPE)
+         && typecode != COMPLEX_TYPE)
        {
          error ("wrong type argument to unary exclamation mark");
          return error_mark_node;
        }
-      arg = lang_hooks.truthvalue_conversion (arg);
+      arg = c_objc_common_truthvalue_conversion (arg);
       return invert_truthvalue (arg);
 
     case NOP_EXPR:
@@ -2366,7 +2606,7 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
       if (TREE_CODE (arg) == COMPLEX_CST)
        return TREE_REALPART (arg);
       else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
-       return fold (build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
+       return fold_build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
       else
        return arg;
 
@@ -2374,7 +2614,7 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
       if (TREE_CODE (arg) == COMPLEX_CST)
        return TREE_IMAGPART (arg);
       else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
-       return fold (build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
+       return fold_build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
       else
        return convert (TREE_TYPE (arg), integer_zero_node);
 
@@ -2390,7 +2630,8 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
          tree real, imag;
 
          if (pedantic)
-           pedwarn ("ISO C does not support `++' and `--' on complex types");
+           pedwarn ("ISO C does not support %<++%> and %<--%>"
+                    " on complex types");
 
          arg = stabilize_reference (arg);
          real = build_unary_op (REALPART_EXPR, arg, 1);
@@ -2452,8 +2693,8 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
        /* Complain about anything else that is not a true lvalue.  */
        if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
                                    || code == POSTINCREMENT_EXPR)
-                                  ? "invalid lvalue in increment"
-                                  : "invalid lvalue in decrement")))
+                                  ? lv_increment
+                                  : lv_decrement)))
          return error_mark_node;
 
        /* Report a read-only lvalue.  */
@@ -2461,7 +2702,7 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
          readonly_error (arg,
                          ((code == PREINCREMENT_EXPR
                            || code == POSTINCREMENT_EXPR)
-                          ? "increment" : "decrement"));
+                          ? lv_increment : lv_decrement));
 
        if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
          val = boolean_increment (code, arg);
@@ -2491,14 +2732,16 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
        {
          if (!c_mark_addressable (TREE_OPERAND (arg, 0)))
            return error_mark_node;
-         return build_binary_op (PLUS_EXPR, TREE_OPERAND (arg, 0),
+         return build_binary_op (PLUS_EXPR,
+                                 default_function_array_conversion
+                                   (TREE_OPERAND (arg, 0)),
                                  TREE_OPERAND (arg, 1), 1);
        }
 
       /* Anything not already handled and not a true memory reference
         or a non-lvalue array is an error.  */
       else if (typecode != FUNCTION_TYPE && !flag
-              && !lvalue_or_else (arg, "invalid lvalue in unary `&'"))
+              && !lvalue_or_else (arg, lv_addressof))
        return error_mark_node;
 
       /* Ordinary case; arg is a COMPONENT_REF or a decl.  */
@@ -2508,7 +2751,7 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
          to which the address will point.  Note that you can't get a
         restricted pointer by taking the address of something, so we
         only have to deal with `const' and `volatile' here.  */
-      if ((DECL_P (arg) || TREE_CODE_CLASS (TREE_CODE (arg)) == 'r')
+      if ((DECL_P (arg) || REFERENCE_CLASS_P (arg))
          && (TREE_READONLY (arg) || TREE_THIS_VOLATILE (arg)))
          argtype = c_build_type_variant (argtype,
                                          TREE_READONLY (arg),
@@ -2517,15 +2760,18 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
       if (!c_mark_addressable (arg))
        return error_mark_node;
 
-      if (TREE_CODE (arg) == COMPONENT_REF
-         && DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1)))
-       {
-         error ("attempt to take address of bit-field structure member `%D'",
-                TREE_OPERAND (arg, 1));
-         return error_mark_node;
-       }
+      gcc_assert (TREE_CODE (arg) != COMPONENT_REF
+                 || !DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1)));
 
       argtype = build_pointer_type (argtype);
+
+      /* ??? Cope with user tricks that amount to offsetof.  Delete this
+        when we have proper support for integer constant expressions.  */
+      val = get_base_address (arg);
+      if (val && TREE_CODE (val) == INDIRECT_REF
+         && integer_zerop (TREE_OPERAND (val, 0)))
+       return fold_convert (argtype, fold_offsetof (arg));
+
       val = build1 (ADDR_EXPR, argtype, arg);
 
       if (TREE_CODE (arg) == COMPOUND_LITERAL_EXPR)
@@ -2547,7 +2793,7 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
    Lvalues can be assigned, unless their type has TYPE_READONLY.
    Lvalues can have their address taken, unless they have C_DECL_REGISTER.  */
 
-int
+static int
 lvalue_p (tree ref)
 {
   enum tree_code code = TREE_CODE (ref);
@@ -2579,40 +2825,54 @@ lvalue_p (tree ref)
       return 0;
     }
 }
-
-/* Return nonzero if REF is an lvalue valid for this language;
-   otherwise, print an error message and return zero.  */
-
-static int
-lvalue_or_else (tree ref, const char *msgid)
-{
-  int win = lvalue_p (ref);
-
-  if (! win)
-    error ("%s", msgid);
-
-  return win;
-}
-
 \f
-/* Warn about storing in something that is `const'.  */
+/* Give an error for storing in something that is 'const'.  */
 
-void
-readonly_error (tree arg, const char *msgid)
+static void
+readonly_error (tree arg, enum lvalue_use use)
 {
+  gcc_assert (use == lv_assign || use == lv_increment || use == lv_decrement);
+  /* Using this macro rather than (for example) arrays of messages
+     ensures that all the format strings are checked at compile
+     time.  */
+#define READONLY_MSG(A, I, D) (use == lv_assign                                \
+                              ? (A)                                    \
+                              : (use == lv_increment ? (I) : (D)))
   if (TREE_CODE (arg) == COMPONENT_REF)
     {
       if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0))))
-       readonly_error (TREE_OPERAND (arg, 0), msgid);
+       readonly_error (TREE_OPERAND (arg, 0), use);
       else
-       error ("%s of read-only member `%s'", _(msgid),
-              IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (arg, 1))));
+       error (READONLY_MSG (G_("assignment of read-only member %qD"),
+                            G_("increment of read-only member %qD"),
+                            G_("decrement of read-only member %qD")),
+              TREE_OPERAND (arg, 1));
     }
   else if (TREE_CODE (arg) == VAR_DECL)
-    error ("%s of read-only variable `%s'", _(msgid),
-          IDENTIFIER_POINTER (DECL_NAME (arg)));
+    error (READONLY_MSG (G_("assignment of read-only variable %qD"),
+                        G_("increment of read-only variable %qD"),
+                        G_("decrement of read-only variable %qD")),
+          arg);
   else
-    error ("%s of read-only location", _(msgid));
+    error (READONLY_MSG (G_("assignment of read-only location"),
+                        G_("increment of read-only location"),
+                        G_("decrement of read-only location")));
+}
+
+
+/* Return nonzero if REF is an lvalue valid for this language;
+   otherwise, print an error message and return zero.  USE says
+   how the lvalue is being used and so selects the error message.  */
+
+static int
+lvalue_or_else (tree ref, enum lvalue_use use)
+{
+  int win = lvalue_p (ref);
+
+  if (!win)
+    lvalue_error (use);
+
+  return win;
 }
 \f
 /* Mark EXP saying that we need to be able to take the
@@ -2630,8 +2890,8 @@ c_mark_addressable (tree exp)
       case COMPONENT_REF:
        if (DECL_C_BIT_FIELD (TREE_OPERAND (x, 1)))
          {
-           error ("cannot take address of bit-field `%s'",
-                  IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (x, 1))));
+           error
+             ("cannot take address of bit-field %qD", TREE_OPERAND (x, 1));
            return false;
          }
 
@@ -2658,24 +2918,19 @@ c_mark_addressable (tree exp)
          {
            if (TREE_PUBLIC (x) || TREE_STATIC (x) || DECL_EXTERNAL (x))
              {
-               error ("global register variable `%s' used in nested function",
-                      IDENTIFIER_POINTER (DECL_NAME (x)));
+               error
+                 ("global register variable %qD used in nested function", x);
                return false;
              }
-           pedwarn ("register variable `%s' used in nested function",
-                    IDENTIFIER_POINTER (DECL_NAME (x)));
+           pedwarn ("register variable %qD used in nested function", x);
          }
        else if (C_DECL_REGISTER (x))
          {
            if (TREE_PUBLIC (x) || TREE_STATIC (x) || DECL_EXTERNAL (x))
-             {
-               error ("address of global register variable `%s' requested",
-                      IDENTIFIER_POINTER (DECL_NAME (x)));
-               return false;
-             }
-
-           pedwarn ("address of register variable `%s' requested",
-                    IDENTIFIER_POINTER (DECL_NAME (x)));
+             error ("address of global register variable %qD requested", x);
+           else
+             error ("address of register variable %qD requested", x);
+           return false;
          }
 
        /* drops in */
@@ -2699,8 +2954,6 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
   tree result_type = NULL;
   tree orig_op1 = op1, orig_op2 = op2;
 
-  ifexp = lang_hooks.truthvalue_conversion (default_conversion (ifexp));
-
   /* Promote both alternatives.  */
 
   if (TREE_CODE (TREE_TYPE (op1)) != VOID_TYPE)
@@ -2740,7 +2993,7 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
            && (code2 == INTEGER_TYPE || code2 == REAL_TYPE
                || code2 == COMPLEX_TYPE))
     {
-      result_type = common_type (type1, type2);
+      result_type = c_common_type (type1, type2);
 
       /* If -Wsign-compare, warn here if type1 and type2 have
         different signedness.  We'll promote the signed to unsigned
@@ -2757,7 +3010,7 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
              /* Do not warn if the result type is signed, since the
                 signed type will only be chosen if it can represent
                 all the values of the unsigned type.  */
-             if (! TYPE_UNSIGNED (result_type))
+             if (!TYPE_UNSIGNED (result_type))
                /* OK */;
              /* Do not warn if the signed quantity is an unsuffixed
                 integer literal (or some static constant expression
@@ -2766,7 +3019,7 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
                       || (unsigned_op1 && tree_expr_nonnegative_p (op2)))
                /* OK */;
              else
-               warning ("signed and unsigned type in conditional expression");
+               warning (0, "signed and unsigned type in conditional expression");
            }
        }
     }
@@ -2778,7 +3031,7 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
     }
   else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE)
     {
-      if (comp_target_types (type1, type2, 1))
+      if (comp_target_types (type1, type2))
        result_type = common_pointer_type (type1, type2);
       else if (integer_zerop (op1) && TREE_TYPE (type1) == void_type_node
               && TREE_CODE (orig_op1) != NOP_EXPR)
@@ -2789,14 +3042,16 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
       else if (VOID_TYPE_P (TREE_TYPE (type1)))
        {
          if (pedantic && TREE_CODE (TREE_TYPE (type2)) == FUNCTION_TYPE)
-           pedwarn ("ISO C forbids conditional expr between `void *' and function pointer");
+           pedwarn ("ISO C forbids conditional expr between "
+                    "%<void *%> and function pointer");
          result_type = build_pointer_type (qualify_type (TREE_TYPE (type1),
                                                          TREE_TYPE (type2)));
        }
       else if (VOID_TYPE_P (TREE_TYPE (type2)))
        {
          if (pedantic && TREE_CODE (TREE_TYPE (type1)) == FUNCTION_TYPE)
-           pedwarn ("ISO C forbids conditional expr between `void *' and function pointer");
+           pedwarn ("ISO C forbids conditional expr between "
+                    "%<void *%> and function pointer");
          result_type = build_pointer_type (qualify_type (TREE_TYPE (type2),
                                                          TREE_TYPE (type1)));
        }
@@ -2808,7 +3063,7 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
     }
   else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE)
     {
-      if (! integer_zerop (op2))
+      if (!integer_zerop (op2))
        pedwarn ("pointer/integer type mismatch in conditional expression");
       else
        {
@@ -2849,10 +3104,7 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
   if (result_type != TREE_TYPE (op2))
     op2 = convert_and_check (result_type, op2);
 
-  if (TREE_CODE (ifexp) == INTEGER_CST)
-    return non_lvalue (integer_zerop (ifexp) ? op2 : op1);
-
-  return fold (build3 (COND_EXPR, result_type, ifexp, op1, op2));
+  return fold_build3 (COND_EXPR, result_type, ifexp, op1, op2);
 }
 \f
 /* Return a compound expression that performs two expressions and
@@ -2861,22 +3113,23 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
 tree
 build_compound_expr (tree expr1, tree expr2)
 {
-  /* Convert arrays and functions to pointers.  */
-  expr2 = default_function_array_conversion (expr2);
-
-  /* Don't let (0, 0) be null pointer constant.  */
-  if (integer_zerop (expr2))
-    expr2 = non_lvalue (expr2);
-
-  if (! TREE_SIDE_EFFECTS (expr1))
+  if (!TREE_SIDE_EFFECTS (expr1))
     {
       /* The left-hand operand of a comma expression is like an expression
          statement: with -Wextra or -Wunused, we should warn if it doesn't have
         any side-effects, unless it was explicitly cast to (void).  */
-      if (warn_unused_value
-           && ! (TREE_CODE (expr1) == CONVERT_EXPR
-                && VOID_TYPE_P (TREE_TYPE (expr1))))
-        warning ("left-hand operand of comma expression has no effect");
+      if (warn_unused_value)
+       {
+         if (VOID_TYPE_P (TREE_TYPE (expr1))
+             && TREE_CODE (expr1) == CONVERT_EXPR)
+           ; /* (void) a, b */
+         else if (VOID_TYPE_P (TREE_TYPE (expr1))
+                  && TREE_CODE (expr1) == COMPOUND_EXPR
+                  && TREE_CODE (TREE_OPERAND (expr1, 1)) == CONVERT_EXPR)
+           ; /* (void) a, (void) b, c */
+         else
+           warning (0, "left-hand operand of comma expression has no effect");
+       }
     }
 
   /* With -Wunused, we should also warn if the left-hand operand does have
@@ -2931,7 +3184,6 @@ build_c_cast (tree type, tree expr)
   else if (TREE_CODE (type) == UNION_TYPE)
     {
       tree field;
-      value = default_function_array_conversion (value);
 
       for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
        if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)),
@@ -2959,14 +3211,9 @@ build_c_cast (tree type, tree expr)
     {
       tree otype, ovalue;
 
-      /* If casting to void, avoid the error that would come
-        from default_conversion in the case of a non-lvalue array.  */
       if (type == void_type_node)
        return build1 (CONVERT_EXPR, type, value);
 
-      /* Convert functions and arrays to pointers,
-        but don't convert any other types.  */
-      value = default_function_array_conversion (value);
       otype = TREE_TYPE (value);
 
       /* Optionally warn about potentially worrisome casts.  */
@@ -3003,16 +3250,16 @@ build_c_cast (tree type, tree expr)
                 && TREE_CODE (in_otype) == POINTER_TYPE);
 
          if (added)
-           warning ("cast adds new qualifiers to function type");
+           warning (0, "cast adds new qualifiers to function type");
 
          if (discarded)
            /* There are qualifiers present in IN_OTYPE that are not
               present in IN_TYPE.  */
-           warning ("cast discards qualifiers from pointer target type");
+           warning (0, "cast discards qualifiers from pointer target type");
        }
 
       /* Warn about possible alignment problems.  */
-      if (STRICT_ALIGNMENT && warn_cast_align
+      if (STRICT_ALIGNMENT
          && TREE_CODE (type) == POINTER_TYPE
          && TREE_CODE (otype) == POINTER_TYPE
          && TREE_CODE (TREE_TYPE (otype)) != VOID_TYPE
@@ -3023,47 +3270,54 @@ build_c_cast (tree type, tree expr)
                || TREE_CODE (TREE_TYPE (otype)) == RECORD_TYPE)
               && TYPE_MODE (TREE_TYPE (otype)) == VOIDmode)
          && TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (otype)))
-       warning ("cast increases required alignment of target type");
+       warning (OPT_Wcast_align,
+                "cast increases required alignment of target type");
 
       if (TREE_CODE (type) == INTEGER_TYPE
          && TREE_CODE (otype) == POINTER_TYPE
          && TYPE_PRECISION (type) != TYPE_PRECISION (otype)
          && !TREE_CONSTANT (value))
-       warning ("cast from pointer to integer of different size");
+       warning (OPT_Wpointer_to_int_cast,
+                "cast from pointer to integer of different size");
 
-      if (warn_bad_function_cast
-         && TREE_CODE (value) == CALL_EXPR
+      if (TREE_CODE (value) == CALL_EXPR
          && TREE_CODE (type) != TREE_CODE (otype))
-       warning ("cast does not match function type");
+       warning (OPT_Wbad_function_cast, "cast from function call of type %qT "
+                "to non-matching type %qT", otype, type);
 
       if (TREE_CODE (type) == POINTER_TYPE
          && TREE_CODE (otype) == INTEGER_TYPE
          && TYPE_PRECISION (type) != TYPE_PRECISION (otype)
          /* Don't warn about converting any constant.  */
          && !TREE_CONSTANT (value))
-       warning ("cast to pointer from integer of different size");
+       warning (OPT_Wint_to_pointer_cast, "cast to pointer from integer "
+                "of different size");
 
-      if (TREE_CODE (type) == POINTER_TYPE
+      if (flag_strict_aliasing && warn_strict_aliasing
+         && TREE_CODE (type) == POINTER_TYPE
          && TREE_CODE (otype) == POINTER_TYPE
          && TREE_CODE (expr) == ADDR_EXPR
-         && DECL_P (TREE_OPERAND (expr, 0))
-         && flag_strict_aliasing && warn_strict_aliasing
+         && (DECL_P (TREE_OPERAND (expr, 0))
+             || TREE_CODE (TREE_OPERAND (expr, 0)) == COMPONENT_REF)
          && !VOID_TYPE_P (TREE_TYPE (type)))
        {
-         /* Casting the address of a decl to non void pointer. Warn
+         /* Casting the address of an object to non void pointer. Warn
             if the cast breaks type based aliasing.  */
          if (!COMPLETE_TYPE_P (TREE_TYPE (type)))
-           warning ("type-punning to incomplete type might break strict-aliasing rules");
+           warning (OPT_Wstrict_aliasing, "type-punning to incomplete type "
+                    "might break strict-aliasing rules");
          else
            {
              HOST_WIDE_INT set1 = get_alias_set (TREE_TYPE (TREE_OPERAND (expr, 0)));
              HOST_WIDE_INT set2 = get_alias_set (TREE_TYPE (type));
 
              if (!alias_sets_conflict_p (set1, set2))
-               warning ("dereferencing type-punned pointer will break strict-aliasing rules");
+               warning (OPT_Wstrict_aliasing, "dereferencing type-punned "
+                        "pointer will break strict-aliasing rules");
              else if (warn_strict_aliasing > 1
                       && !alias_sets_might_conflict_p (set1, set2))
-               warning ("dereferencing type-punned pointer might break strict-aliasing rules");
+               warning (OPT_Wstrict_aliasing, "dereferencing type-punned "
+                        "pointer might break strict-aliasing rules");
            }
        }
 
@@ -3087,34 +3341,24 @@ build_c_cast (tree type, tree expr)
        pedwarn ("ISO C forbids conversion of object pointer to function pointer type");
 
       ovalue = value;
-      /* Replace a nonvolatile const static variable with its value.  */
-      if (optimize && TREE_CODE (value) == VAR_DECL)
-       value = decl_constant_value (value);
       value = convert (type, value);
 
       /* Ignore any integer overflow caused by the cast.  */
       if (TREE_CODE (value) == INTEGER_CST)
        {
-         if (EXPR_P (ovalue))
-           /* If OVALUE had overflow set, then so will VALUE, so it
-              is safe to overwrite.  */
-           TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue);
+         /* If OVALUE had overflow set, then so will VALUE, so it
+            is safe to overwrite.  */
+         if (CONSTANT_CLASS_P (ovalue))
+           {
+             TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue);
+             /* Similarly, constant_overflow cannot have become cleared.  */
+             TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_OVERFLOW (ovalue);
+           }
          else
            TREE_OVERFLOW (value) = 0;
-         
-         if (TREE_CODE_CLASS (TREE_CODE (ovalue)) == 'c')
-           /* Similarly, constant_overflow cannot have become
-              cleared.  */
-           TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_OVERFLOW (ovalue);
        }
     }
 
-  /* Don't let (void *) (FOO *) 0 be a null pointer constant.  */
-  if (TREE_CODE (value) == INTEGER_CST
-      && TREE_CODE (expr) == INTEGER_CST
-      && TREE_CODE (TREE_TYPE (expr)) != INTEGER_TYPE)
-    value = non_lvalue (value);
-
   /* Don't let a cast be an lvalue.  */
   if (value == expr)
     value = non_lvalue (value);
@@ -3124,15 +3368,16 @@ build_c_cast (tree type, tree expr)
 
 /* Interpret a cast of expression EXPR to type TYPE.  */
 tree
-c_cast_expr (tree type, tree expr)
+c_cast_expr (struct c_type_name *type_name, tree expr)
 {
+  tree type;
   int saved_wsp = warn_strict_prototypes;
 
   /* This avoids warnings about unprototyped casts on
      integers.  E.g. "#define SIG_DFL (void(*)())0".  */
   if (TREE_CODE (expr) == INTEGER_CST)
     warn_strict_prototypes = 0;
-  type = groktypename (type);
+  type = groktypename (type_name);
   warn_strict_prototypes = saved_wsp;
 
   return build_c_cast (type, expr);
@@ -3159,11 +3404,7 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
   if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
     return error_mark_node;
 
-  /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue.  */
-  /* Do not use STRIP_NOPS here.  We do not want an enumerator
-     whose value is 0 to count as a null pointer constant.  */
-  if (TREE_CODE (rhs) == NON_LVALUE_EXPR)
-    rhs = TREE_OPERAND (rhs, 0);
+  STRIP_TYPE_NOPS (rhs);
 
   newrhs = rhs;
 
@@ -3176,16 +3417,16 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
       newrhs = build_binary_op (modifycode, lhs, rhs, 1);
     }
 
-  if (!lvalue_or_else (lhs, "invalid lvalue in assignment"))
+  if (!lvalue_or_else (lhs, lv_assign))
     return error_mark_node;
 
-  /* Warn about storing in something that is `const'.  */
+  /* Give an error for storing in something that is 'const'.  */
 
   if (TREE_READONLY (lhs) || TYPE_READONLY (lhstype)
       || ((TREE_CODE (lhstype) == RECORD_TYPE
           || TREE_CODE (lhstype) == UNION_TYPE)
          && C_TYPE_FIELDS_READONLY (lhstype)))
-    readonly_error (lhs, "assignment");
+    readonly_error (lhs, lv_assign);
 
   /* If storing into a structure or union member,
      it has probably been given type `int'.
@@ -3210,12 +3451,20 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
 
   /* Convert new value to destination type.  */
 
-  newrhs = convert_for_assignment (lhstype, newrhs, _("assignment"),
+  newrhs = convert_for_assignment (lhstype, newrhs, ic_assign,
                                   NULL_TREE, NULL_TREE, 0);
   if (TREE_CODE (newrhs) == ERROR_MARK)
     return error_mark_node;
 
-  /* Scan operands */
+  /* Emit ObjC write barrier, if necessary.  */
+  if (c_dialect_objc () && flag_objc_gc)
+    {
+      result = objc_generate_write_barrier (lhs, modifycode, newrhs);
+      if (result)
+       return result;
+    }
+
+  /* Scan operands.  */
 
   result = build2 (MODIFY_EXPR, lhstype, lhs, newrhs);
   TREE_SIDE_EFFECTS (result) = 1;
@@ -3227,7 +3476,7 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
 
   if (olhstype == TREE_TYPE (result))
     return result;
-  return convert_for_assignment (olhstype, result, _("assignment"),
+  return convert_for_assignment (olhstype, result, ic_assign,
                                 NULL_TREE, NULL_TREE, 0);
 }
 \f
@@ -3236,32 +3485,72 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
    The real work of conversion is done by `convert'.
    The purpose of this function is to generate error messages
    for assignments that are not allowed in C.
-   ERRTYPE is a string to use in error messages:
-   "assignment", "return", etc.  If it is null, this is parameter passing
-   for a function call (and different error messages are output).
+   ERRTYPE says whether it is argument passing, assignment,
+   initialization or return.
 
-   FUNNAME is the name of the function being called,
-   as an IDENTIFIER_NODE, or null.
+   FUNCTION is a tree for the function being called.
    PARMNUM is the number of the argument, for printing in error messages.  */
 
 static tree
-convert_for_assignment (tree type, tree rhs, const char *errtype,
-                       tree fundecl, tree funname, int parmnum)
+convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
+                       tree fundecl, tree function, int parmnum)
 {
   enum tree_code codel = TREE_CODE (type);
   tree rhstype;
   enum tree_code coder;
+  tree rname = NULL_TREE;
+  bool objc_ok = false;
+
+  if (errtype == ic_argpass || errtype == ic_argpass_nonproto)
+    {
+      tree selector;
+      /* Change pointer to function to the function itself for
+        diagnostics.  */
+      if (TREE_CODE (function) == ADDR_EXPR
+         && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL)
+       function = TREE_OPERAND (function, 0);
+
+      /* Handle an ObjC selector specially for diagnostics.  */
+      selector = objc_message_selector ();
+      rname = function;
+      if (selector && parmnum > 2)
+       {
+         rname = selector;
+         parmnum -= 2;
+       }
+    }
 
-  /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue.  */
-  /* Do not use STRIP_NOPS here.  We do not want an enumerator
-     whose value is 0 to count as a null pointer constant.  */
-  if (TREE_CODE (rhs) == NON_LVALUE_EXPR)
-    rhs = TREE_OPERAND (rhs, 0);
-
-  if (TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE
-      || TREE_CODE (TREE_TYPE (rhs)) == FUNCTION_TYPE)
-    rhs = default_conversion (rhs);
-  else if (optimize && TREE_CODE (rhs) == VAR_DECL)
+  /* This macro is used to emit diagnostics to ensure that all format
+     strings are complete sentences, visible to gettext and checked at
+     compile time.  */
+#define WARN_FOR_ASSIGNMENT(AR, AS, IN, RE)    \
+  do {                                         \
+    switch (errtype)                           \
+      {                                                \
+      case ic_argpass:                         \
+       pedwarn (AR, parmnum, rname);           \
+       break;                                  \
+      case ic_argpass_nonproto:                        \
+       warning (0, AR, parmnum, rname);                \
+       break;                                  \
+      case ic_assign:                          \
+       pedwarn (AS);                           \
+       break;                                  \
+      case ic_init:                            \
+       pedwarn (IN);                           \
+       break;                                  \
+      case ic_return:                          \
+       pedwarn (RE);                           \
+       break;                                  \
+      default:                                 \
+       gcc_unreachable ();                     \
+      }                                                \
+  } while (0)
+
+  STRIP_TYPE_NOPS (rhs);
+
+  if (optimize && TREE_CODE (rhs) == VAR_DECL
+          && TREE_CODE (TREE_TYPE (rhs)) != ARRAY_TYPE)
     rhs = decl_constant_value_for_broken_optimization (rhs);
 
   rhstype = TREE_TYPE (rhs);
@@ -3270,19 +3559,45 @@ convert_for_assignment (tree type, tree rhs, const char *errtype,
   if (coder == ERROR_MARK)
     return error_mark_node;
 
+  if (c_dialect_objc ())
+    {
+      int parmno;
+
+      switch (errtype)
+       {
+       case ic_return:
+         parmno = 0;
+         break;
+
+       case ic_assign:
+         parmno = -1;
+         break;
+
+       case ic_init:
+         parmno = -2;
+         break;
+
+       default:
+         parmno = parmnum;
+         break;
+       }
+
+      objc_ok = objc_compare_types (type, rhstype, parmno, rname);
+    }
+
   if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
     {
       overflow_warning (rhs);
-      /* Check for Objective-C protocols.  This will automatically
-        issue a warning if there are protocol violations.  No need to
-        use the return value.  */
-      if (c_dialect_objc ())
-       objc_comptypes (type, rhstype, 0);
       return rhs;
     }
 
   if (coder == VOID_TYPE)
     {
+      /* Except for passing an argument to an unprototyped function,
+        this is a constraint violation.  When passing an argument to
+        an unprototyped function, it is compile-time undefined;
+        making it a constraint in that case was rejected in
+        DR#252.  */
       error ("void value not ignored as it ought to be");
       return error_mark_node;
     }
@@ -3313,7 +3628,7 @@ convert_for_assignment (tree type, tree rhs, const char *errtype,
       return rhs;
     }
   /* Some types can interconvert without explicit casts.  */
-  else if (codel == VECTOR_TYPE
+  else if (codel == VECTOR_TYPE && coder == VECTOR_TYPE
            && vector_types_convertible_p (type, TREE_TYPE (rhs)))
     return convert (type, rhs);
   /* Arithmetic types all interconvert, and enum is treated like int.  */
@@ -3327,7 +3642,8 @@ convert_for_assignment (tree type, tree rhs, const char *errtype,
 
   /* Conversion to a transparent union from its member types.
      This applies only to function arguments.  */
-  else if (codel == UNION_TYPE && TYPE_TRANSPARENT_UNION (type) && ! errtype)
+  else if (codel == UNION_TYPE && TYPE_TRANSPARENT_UNION (type)
+          && (errtype == ic_argpass || errtype == ic_argpass_nonproto))
     {
       tree memb_types;
       tree marginal_memb_type = 0;
@@ -3354,7 +3670,7 @@ convert_for_assignment (tree type, tree rhs, const char *errtype,
                 Meanwhile, the lhs target must have all the qualifiers of
                 the rhs.  */
              if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
-                 || comp_target_types (memb_type, rhstype, 0))
+                 || comp_target_types (memb_type, rhstype))
                {
                  /* If this type won't generate any warnings, use it.  */
                  if (TYPE_QUALS (ttl) == TYPE_QUALS (ttr)
@@ -3367,7 +3683,7 @@ convert_for_assignment (tree type, tree rhs, const char *errtype,
                    break;
 
                  /* Keep looking for a better type, but remember this one.  */
-                 if (! marginal_memb_type)
+                 if (!marginal_memb_type)
                    marginal_memb_type = memb_type;
                }
            }
@@ -3384,7 +3700,7 @@ convert_for_assignment (tree type, tree rhs, const char *errtype,
 
       if (memb_types || marginal_memb_type)
        {
-         if (! memb_types)
+         if (!memb_types)
            {
              /* We have only a marginally acceptable member type;
                 it needs a warning.  */
@@ -3402,16 +3718,30 @@ convert_for_assignment (tree type, tree rhs, const char *errtype,
                     function where an ordinary one is wanted, but not
                     vice-versa.  */
                  if (TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr))
-                   warn_for_assignment ("%s makes qualified function pointer from unqualified",
-                                        errtype, funname, parmnum);
+                   WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE "
+                                           "makes qualified function "
+                                           "pointer from unqualified"),
+                                        G_("assignment makes qualified "
+                                           "function pointer from "
+                                           "unqualified"),
+                                        G_("initialization makes qualified "
+                                           "function pointer from "
+                                           "unqualified"),
+                                        G_("return makes qualified function "
+                                           "pointer from unqualified"));
                }
              else if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl))
-               warn_for_assignment ("%s discards qualifiers from pointer target type",
-                                    errtype, funname,
-                                    parmnum);
+               WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE discards "
+                                       "qualifiers from pointer target type"),
+                                    G_("assignment discards qualifiers "
+                                       "from pointer target type"),
+                                    G_("initialization discards qualifiers "
+                                       "from pointer target type"),
+                                    G_("return discards qualifiers from "
+                                       "pointer target type"));
            }
 
-         if (pedantic && ! DECL_IN_SYSTEM_HEADER (fundecl))
+         if (pedantic && !DECL_IN_SYSTEM_HEADER (fundecl))
            pedwarn ("ISO C prohibits argument conversion to union type");
 
          return build1 (NOP_EXPR, type, rhs);
@@ -3424,23 +3754,40 @@ convert_for_assignment (tree type, tree rhs, const char *errtype,
     {
       tree ttl = TREE_TYPE (type);
       tree ttr = TREE_TYPE (rhstype);
+      tree mvl = ttl;
+      tree mvr = ttr;
       bool is_opaque_pointer;
       int target_cmp = 0;   /* Cache comp_target_types () result.  */
 
+      if (TREE_CODE (mvl) != ARRAY_TYPE)
+       mvl = TYPE_MAIN_VARIANT (mvl);
+      if (TREE_CODE (mvr) != ARRAY_TYPE)
+       mvr = TYPE_MAIN_VARIANT (mvr);
       /* Opaque pointers are treated like void pointers.  */
       is_opaque_pointer = (targetm.vector_opaque_p (type)
                            || targetm.vector_opaque_p (rhstype))
         && TREE_CODE (ttl) == VECTOR_TYPE
         && TREE_CODE (ttr) == VECTOR_TYPE;
+      
+      /* C++ does not allow the implicit conversion void* -> T*.  However,
+         for the purpose of reducing the number of false positives, we
+         tolerate the special case of
+
+                int *p = NULL;
+
+         where NULL is typically defined in C to be '(void *) 0'.  */
+      if (VOID_TYPE_P (ttr) && rhs != null_pointer_node && !VOID_TYPE_P (ttl))
+        warning (OPT_Wc___compat, "request for implicit conversion from "
+                 "%qT to %qT not permitted in C++", rhstype, type);
 
       /* Any non-function converts to a [const][volatile] void *
         and vice versa; otherwise, targets must be the same.
         Meanwhile, the lhs target must have all the qualifiers of the rhs.  */
       if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
-         || (target_cmp = comp_target_types (type, rhstype, 0))
+         || (target_cmp = comp_target_types (type, rhstype))
          || is_opaque_pointer
-         || (c_common_unsigned_type (TYPE_MAIN_VARIANT (ttl))
-             == c_common_unsigned_type (TYPE_MAIN_VARIANT (ttr))))
+         || (c_common_unsigned_type (mvl)
+             == c_common_unsigned_type (mvr)))
        {
          if (pedantic
              && ((VOID_TYPE_P (ttl) && TREE_CODE (ttr) == FUNCTION_TYPE)
@@ -3450,25 +3797,50 @@ convert_for_assignment (tree type, tree rhs, const char *errtype,
                      which are not ANSI null ptr constants.  */
                   && (!integer_zerop (rhs) || TREE_CODE (rhs) == NOP_EXPR)
                   && TREE_CODE (ttl) == FUNCTION_TYPE)))
-           warn_for_assignment ("ISO C forbids %s between function pointer and `void *'",
-                                errtype, funname, parmnum);
+           WARN_FOR_ASSIGNMENT (G_("ISO C forbids passing argument %d of "
+                                   "%qE between function pointer "
+                                   "and %<void *%>"),
+                                G_("ISO C forbids assignment between "
+                                   "function pointer and %<void *%>"),
+                                G_("ISO C forbids initialization between "
+                                   "function pointer and %<void *%>"),
+                                G_("ISO C forbids return between function "
+                                   "pointer and %<void *%>"));
          /* Const and volatile mean something different for function types,
             so the usual warnings are not appropriate.  */
          else if (TREE_CODE (ttr) != FUNCTION_TYPE
                   && TREE_CODE (ttl) != FUNCTION_TYPE)
            {
              if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl))
-               warn_for_assignment ("%s discards qualifiers from pointer target type",
-                                    errtype, funname, parmnum);
+               {
+                 /* Types differing only by the presence of the 'volatile'
+                    qualifier are acceptable if the 'volatile' has been added
+                    in by the Objective-C EH machinery.  */
+                 if (!objc_type_quals_match (ttl, ttr))
+                   WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE discards "
+                                           "qualifiers from pointer target type"),
+                                        G_("assignment discards qualifiers "
+                                           "from pointer target type"),
+                                        G_("initialization discards qualifiers "
+                                           "from pointer target type"),
+                                        G_("return discards qualifiers from "
+                                           "pointer target type"));
+               }
              /* If this is not a case of ignoring a mismatch in signedness,
                 no warning.  */
              else if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
                       || target_cmp)
                ;
              /* If there is a mismatch, do warn.  */
-             else
-               warn_for_assignment ("pointer targets in %s differ in signedness",
-                                    errtype, funname, parmnum);
+             else if (warn_pointer_sign)
+               WARN_FOR_ASSIGNMENT (G_("pointer targets in passing argument "
+                                       "%d of %qE differ in signedness"),
+                                    G_("pointer targets in assignment "
+                                       "differ in signedness"),
+                                    G_("pointer targets in initialization "
+                                       "differ in signedness"),
+                                    G_("pointer targets in return differ "
+                                       "in signedness"));
            }
          else if (TREE_CODE (ttl) == FUNCTION_TYPE
                   && TREE_CODE (ttr) == FUNCTION_TYPE)
@@ -3478,17 +3850,33 @@ convert_for_assignment (tree type, tree rhs, const char *errtype,
                 it is okay to use a const or volatile function
                 where an ordinary one is wanted, but not vice-versa.  */
              if (TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr))
-               warn_for_assignment ("%s makes qualified function pointer from unqualified",
-                                    errtype, funname, parmnum);
+               WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE makes "
+                                       "qualified function pointer "
+                                       "from unqualified"),
+                                    G_("assignment makes qualified function "
+                                       "pointer from unqualified"),
+                                    G_("initialization makes qualified "
+                                       "function pointer from unqualified"),
+                                    G_("return makes qualified function "
+                                       "pointer from unqualified"));
            }
        }
       else
-       warn_for_assignment ("%s from incompatible pointer type",
-                            errtype, funname, parmnum);
+       /* Avoid warning about the volatile ObjC EH puts on decls.  */
+       if (!objc_ok)
+         WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE from "
+                                 "incompatible pointer type"),
+                              G_("assignment from incompatible pointer type"),
+                              G_("initialization from incompatible "
+                                 "pointer type"),
+                              G_("return from incompatible pointer type"));
+
       return convert (type, rhs);
     }
   else if (codel == POINTER_TYPE && coder == ARRAY_TYPE)
     {
+      /* ??? This should not be an error when inlining calls to
+        unprototyped functions.  */
       error ("invalid use of non-lvalue array");
       return error_mark_node;
     }
@@ -3497,45 +3885,58 @@ convert_for_assignment (tree type, tree rhs, const char *errtype,
       /* An explicit constant 0 can convert to a pointer,
         or one that results from arithmetic, even including
         a cast to integer type.  */
-      if (! (TREE_CODE (rhs) == INTEGER_CST && integer_zerop (rhs))
+      if (!(TREE_CODE (rhs) == INTEGER_CST && integer_zerop (rhs))
          &&
-         ! (TREE_CODE (rhs) == NOP_EXPR
-            && TREE_CODE (TREE_TYPE (rhs)) == INTEGER_TYPE
-            && TREE_CODE (TREE_OPERAND (rhs, 0)) == INTEGER_CST
-            && integer_zerop (TREE_OPERAND (rhs, 0))))
-         warn_for_assignment ("%s makes pointer from integer without a cast",
-                              errtype, funname, parmnum);
+         !(TREE_CODE (rhs) == NOP_EXPR
+           && TREE_CODE (TREE_TYPE (rhs)) == INTEGER_TYPE
+           && TREE_CODE (TREE_OPERAND (rhs, 0)) == INTEGER_CST
+           && integer_zerop (TREE_OPERAND (rhs, 0))))
+       WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE makes "
+                               "pointer from integer without a cast"),
+                            G_("assignment makes pointer from integer "
+                               "without a cast"),
+                            G_("initialization makes pointer from "
+                               "integer without a cast"),
+                            G_("return makes pointer from integer "
+                               "without a cast"));
 
       return convert (type, rhs);
     }
   else if (codel == INTEGER_TYPE && coder == POINTER_TYPE)
     {
-      warn_for_assignment ("%s makes integer from pointer without a cast",
-                          errtype, funname, parmnum);
+      WARN_FOR_ASSIGNMENT (G_("passing argument %d of %qE makes integer "
+                             "from pointer without a cast"),
+                          G_("assignment makes integer from pointer "
+                             "without a cast"),
+                          G_("initialization makes integer from pointer "
+                             "without a cast"),
+                          G_("return makes integer from pointer "
+                             "without a cast"));
       return convert (type, rhs);
     }
   else if (codel == BOOLEAN_TYPE && coder == POINTER_TYPE)
     return convert (type, rhs);
 
-  if (!errtype)
+  switch (errtype)
     {
-      if (funname)
-       {
-         tree selector = objc_message_selector ();
-
-         if (selector && parmnum > 2)
-           error ("incompatible type for argument %d of `%s'",
-                  parmnum - 2, IDENTIFIER_POINTER (selector));
-         else
-           error ("incompatible type for argument %d of `%s'",
-                  parmnum, IDENTIFIER_POINTER (funname));
-       }
-      else
-       error ("incompatible type for argument %d of indirect function call",
-              parmnum);
+    case ic_argpass:
+    case ic_argpass_nonproto:
+      /* ??? This should not be an error when inlining calls to
+        unprototyped functions.  */
+      error ("incompatible type for argument %d of %qE", parmnum, rname);
+      break;
+    case ic_assign:
+      error ("incompatible types in assignment");
+      break;
+    case ic_init:
+      error ("incompatible types in initialization");
+      break;
+    case ic_return:
+      error ("incompatible types in return");
+      break;
+    default:
+      gcc_unreachable ();
     }
-  else
-    error ("incompatible types in %s", errtype);
 
   return error_mark_node;
 }
@@ -3551,80 +3952,19 @@ c_convert_parm_for_inlining (tree parm, tree value, tree fn, int argnum)
 
   /* If FN was prototyped, the value has been converted already
      in convert_arguments.  */
-  if (! value || TYPE_ARG_TYPES (TREE_TYPE (fn)))
+  if (!value || TYPE_ARG_TYPES (TREE_TYPE (fn)))
     return value;
 
   type = TREE_TYPE (parm);
   ret = convert_for_assignment (type, value,
-                               (char *) 0 /* arg passing  */, fn,
-                               DECL_NAME (fn), argnum);
+                               ic_argpass_nonproto, fn,
+                               fn, argnum);
   if (targetm.calls.promote_prototypes (TREE_TYPE (fn))
       && INTEGRAL_TYPE_P (type)
       && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
     ret = default_conversion (ret);
   return ret;
 }
-
-/* Print a warning using MSGID.
-   It gets OPNAME as its one parameter.
-   if OPNAME is null and ARGNUM is 0, it is replaced by "passing arg of `FUNCTION'".
-   Otherwise if OPNAME is null, it is replaced by "passing arg ARGNUM of `FUNCTION'".
-   FUNCTION and ARGNUM are handled specially if we are building an
-   Objective-C selector.  */
-
-static void
-warn_for_assignment (const char *msgid, const char *opname, tree function,
-                    int argnum)
-{
-  if (opname == 0)
-    {
-      tree selector = objc_message_selector ();
-      char * new_opname;
-
-      if (selector && argnum > 2)
-       {
-         function = selector;
-         argnum -= 2;
-       }
-      if (argnum == 0)
-       {
-         if (function)
-           {
-             /* Function name is known; supply it.  */
-             const char *const argstring = _("passing arg of `%s'");
-             new_opname = (char *) alloca (IDENTIFIER_LENGTH (function)
-                                  + strlen (argstring) + 1 + 1);
-             sprintf (new_opname, argstring,
-                      IDENTIFIER_POINTER (function));
-           }
-         else
-           {
-             /* Function name unknown (call through ptr).  */
-             const char *const argnofun = _("passing arg of pointer to function");
-             new_opname = (char *) alloca (strlen (argnofun) + 1 + 1);
-             sprintf (new_opname, argnofun);
-           }
-       }
-      else if (function)
-       {
-         /* Function name is known; supply it.  */
-         const char *const argstring = _("passing arg %d of `%s'");
-         new_opname = (char *) alloca (IDENTIFIER_LENGTH (function)
-                              + strlen (argstring) + 1 + 25 /*%d*/ + 1);
-         sprintf (new_opname, argstring, argnum,
-                  IDENTIFIER_POINTER (function));
-       }
-      else
-       {
-         /* Function name unknown (call through ptr); just give arg number.  */
-         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);
-       }
-      opname = new_opname;
-    }
-  pedwarn (msgid, opname);
-}
 \f
 /* If VALUE is a compound expr all of whose expressions are constant, then
    return its value.  Otherwise, return error_mark_node.
@@ -3643,8 +3983,7 @@ valid_compound_expr_initializer (tree value, tree endtype)
       return valid_compound_expr_initializer (TREE_OPERAND (value, 1),
                                              endtype);
     }
-  else if (! TREE_CONSTANT (value)
-          && ! initializer_constant_valid_p (value, endtype))
+  else if (!initializer_constant_valid_p (value, endtype))
     return error_mark_node;
   else
     return value;
@@ -3672,9 +4011,10 @@ store_init_value (tree decl, tree init)
 
   /* Store the expression if valid; else report error.  */
 
-  if (warn_traditional && !in_system_header
-      && AGGREGATE_TYPE_P (TREE_TYPE (decl)) && ! TREE_STATIC (decl))
-    warning ("traditional C rejects automatic aggregate initialization");
+  if (!in_system_header
+      && AGGREGATE_TYPE_P (TREE_TYPE (decl)) && !TREE_STATIC (decl))
+    warning (OPT_Wtraditional, "traditional C rejects automatic "
+            "aggregate initialization");
 
   DECL_INITIAL (decl) = value;
 
@@ -3689,8 +4029,7 @@ store_init_value (tree decl, tree init)
     {
       tree inside_init = init;
 
-      if (TREE_CODE (init) == NON_LVALUE_EXPR)
-       inside_init = TREE_OPERAND (init, 0);
+      STRIP_TYPE_NOPS (inside_init);
       inside_init = fold (inside_init);
 
       if (TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR)
@@ -3842,7 +4181,7 @@ error_init (const char *msgid)
   error ("%s", _(msgid));
   ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
   if (*ofwhat)
-    error ("(near initialization for `%s')", ofwhat);
+    error ("(near initialization for %qs)", ofwhat);
 }
 
 /* Issue a pedantic warning for a bad initializer component.
@@ -3857,7 +4196,7 @@ pedwarn_init (const char *msgid)
   pedwarn ("%s", _(msgid));
   ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
   if (*ofwhat)
-    pedwarn ("(near initialization for `%s')", ofwhat);
+    pedwarn ("(near initialization for %qs)", ofwhat);
 }
 
 /* Issue a warning for a bad initializer component.
@@ -3869,10 +4208,10 @@ warning_init (const char *msgid)
 {
   char *ofwhat;
 
-  warning ("%s", _(msgid));
+  warning (0, "%s", _(msgid));
   ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
   if (*ofwhat)
-    warning ("(near initialization for `%s')", ofwhat);
+    warning (0, "(near initialization for %qs)", ofwhat);
 }
 \f
 /* If TYPE is an array type and EXPR is a parenthesized string
@@ -3910,11 +4249,7 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
       || TREE_TYPE (init) == error_mark_node)
     return error_mark_node;
 
-  /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue.  */
-  /* Do not use STRIP_NOPS here.  We do not want an enumerator
-     whose value is 0 to count as a null pointer constant.  */
-  if (TREE_CODE (init) == NON_LVALUE_EXPR)
-    inside_init = TREE_OPERAND (init, 0);
+  STRIP_TYPE_NOPS (inside_init);
 
   inside_init = fold (inside_init);
 
@@ -3988,17 +4323,32 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
   /* Build a VECTOR_CST from a *constant* vector constructor.  If the
      vector constructor is not constant (e.g. {1,2,3,foo()}) then punt
      below and handle as a constructor.  */
-    if (code == VECTOR_TYPE
-        && vector_types_convertible_p (TREE_TYPE (inside_init), type)
-        && TREE_CONSTANT (inside_init))
-      {
-       if (TREE_CODE (inside_init) == VECTOR_CST
-            && comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
-                         TYPE_MAIN_VARIANT (type)))
-         return inside_init;
-       else
-         return build_vector (type, CONSTRUCTOR_ELTS (inside_init));
-      }
+  if (code == VECTOR_TYPE
+      && TREE_CODE (TREE_TYPE (inside_init)) == VECTOR_TYPE
+      && vector_types_convertible_p (TREE_TYPE (inside_init), type)
+      && TREE_CONSTANT (inside_init))
+    {
+      if (TREE_CODE (inside_init) == VECTOR_CST
+         && comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
+                       TYPE_MAIN_VARIANT (type)))
+       return inside_init;
+
+      if (TREE_CODE (inside_init) == CONSTRUCTOR)
+       {
+         tree link;
+
+         /* Iterate through elements and check if all constructor
+            elements are *_CSTs.  */
+         for (link = CONSTRUCTOR_ELTS (inside_init);
+              link;
+              link = TREE_CHAIN (link))
+           if (! CONSTANT_CLASS_P (TREE_VALUE (link)))
+             break;
+
+         if (link == NULL)
+           return build_vector (type, CONSTRUCTOR_ELTS (inside_init));
+       }
+    }
 
   /* Any type can be initialized
      from an expression of the same type, optionally with braces.  */
@@ -4013,15 +4363,13 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
          || (code == POINTER_TYPE
              && TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE
              && comptypes (TREE_TYPE (TREE_TYPE (inside_init)),
-                           TREE_TYPE (type)))
-         || (code == POINTER_TYPE
-             && TREE_CODE (TREE_TYPE (inside_init)) == FUNCTION_TYPE
-             && comptypes (TREE_TYPE (inside_init),
                            TREE_TYPE (type)))))
     {
       if (code == POINTER_TYPE)
        {
-         inside_init = default_function_array_conversion (inside_init);
+         if (TREE_CODE (inside_init) == STRING_CST
+             || TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR)
+           inside_init = default_function_array_conversion (inside_init);
 
          if (TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE)
            {
@@ -4072,16 +4420,8 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
            inside_init = error_mark_node;
        }
       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))))
+              && !initializer_constant_valid_p (inside_init,
+                                                TREE_TYPE (inside_init)))
        {
          error_init ("initializer element is not constant");
          inside_init = error_mark_node;
@@ -4096,20 +4436,24 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
       || code == ENUMERAL_TYPE || code == BOOLEAN_TYPE || code == COMPLEX_TYPE
       || code == VECTOR_TYPE)
     {
-      /* Note that convert_for_assignment calls default_conversion
-        for arrays and functions.  We must not call it in the
-        case where inside_init is a null pointer constant.  */
+      if (TREE_CODE (init) == STRING_CST
+         || TREE_CODE (init) == COMPOUND_LITERAL_EXPR)
+       init = default_function_array_conversion (init);
       inside_init
-       = convert_for_assignment (type, init, _("initialization"),
+       = convert_for_assignment (type, init, ic_init,
                                  NULL_TREE, NULL_TREE, 0);
 
-      if (require_constant && ! TREE_CONSTANT (inside_init))
+      /* Check to see if we have already given an error message.  */
+      if (inside_init == error_mark_node)
+       ;
+      else if (require_constant && !TREE_CONSTANT (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)
+              && !initializer_constant_valid_p (inside_init,
+                                                TREE_TYPE (inside_init)))
        {
          error_init ("initializer element is not computable at load time");
          inside_init = error_mark_node;
@@ -4198,17 +4542,11 @@ static struct init_node *constructor_pending_elts;
 /* The SPELLING_DEPTH of this constructor.  */
 static int constructor_depth;
 
-/* 0 if implicitly pushing constructor levels is allowed.  */
-int constructor_no_implicit = 0; /* 0 for C; 1 for some other languages.  */
-
 /* DECL node for which an initializer is being read.
    0 means we are reading a constructor expression
    such as (struct foo) {...}.  */
 static tree constructor_decl;
 
-/* start_init saves the ASMSPEC arg here for really_start_incremental_init.  */
-static const char *constructor_asmspec;
-
 /* Nonzero if this is an initializer for a top-level decl.  */
 static int constructor_top_level;
 
@@ -4255,7 +4593,7 @@ struct constructor_stack
   char designated;
 };
 
-struct constructor_stack *constructor_stack;
+static struct constructor_stack *constructor_stack;
 
 /* This stack represents designators from some range designator up to
    the last designator in the list.  */
@@ -4270,7 +4608,7 @@ struct constructor_range_stack
   tree fields;
 };
 
-struct constructor_range_stack *constructor_range_stack;
+static struct constructor_range_stack *constructor_range_stack;
 
 /* This stack records separate initializers that are nested.
    Nested initializers can't happen in ANSI C, but GNU C allows them
@@ -4280,7 +4618,6 @@ struct initializer_stack
 {
   struct initializer_stack *next;
   tree decl;
-  const char *asmspec;
   struct constructor_stack *constructor_stack;
   struct constructor_range_stack *constructor_range_stack;
   tree elements;
@@ -4292,22 +4629,17 @@ struct initializer_stack
   char require_constant_elements;
 };
 
-struct initializer_stack *initializer_stack;
+static struct initializer_stack *initializer_stack;
 \f
 /* Prepare to parse and output the initializer for variable DECL.  */
 
 void
-start_init (tree decl, tree asmspec_tree, int top_level)
+start_init (tree decl, tree asmspec_tree ATTRIBUTE_UNUSED, int top_level)
 {
   const char *locus;
-  struct initializer_stack *p = XNEW (struct initializer_stack);
-  const char *asmspec = 0;
-
-  if (asmspec_tree)
-    asmspec = TREE_STRING_POINTER (asmspec_tree);
+  struct initializer_stack *p = xmalloc (sizeof (struct initializer_stack));
 
   p->decl = constructor_decl;
-  p->asmspec = constructor_asmspec;
   p->require_constant_value = require_constant_value;
   p->require_constant_elements = require_constant_elements;
   p->constructor_stack = constructor_stack;
@@ -4321,11 +4653,10 @@ start_init (tree decl, tree asmspec_tree, int top_level)
   initializer_stack = p;
 
   constructor_decl = decl;
-  constructor_asmspec = asmspec;
   constructor_designated = 0;
   constructor_top_level = top_level;
 
-  if (decl != 0)
+  if (decl != 0 && decl != error_mark_node)
     {
       require_constant_value = TREE_STATIC (decl);
       require_constant_elements
@@ -4371,14 +4702,12 @@ finish_init (void)
       free (q);
     }
 
-  if (constructor_range_stack)
-    abort ();
+  gcc_assert (!constructor_range_stack);
 
   /* Pop back to the data of the outer initializer (if any).  */
   free (spelling_base);
 
   constructor_decl = p->decl;
-  constructor_asmspec = p->asmspec;
   require_constant_value = p->require_constant_value;
   require_constant_elements = p->require_constant_elements;
   constructor_stack = p->constructor_stack;
@@ -4480,7 +4809,10 @@ really_start_incremental_init (tree type)
                       TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type)));
        }
       else
-       constructor_index = bitsize_zero_node;
+       {
+         constructor_index = bitsize_zero_node;
+         constructor_max_index = NULL_TREE;
+       }
 
       constructor_unfilled_index = constructor_index;
     }
@@ -4512,19 +4844,27 @@ push_init_level (int implicit)
   tree value = NULL_TREE;
 
   /* If we've exhausted any levels that didn't have braces,
-     pop them now.  */
-  while (constructor_stack->implicit)
+     pop them now.  If implicit == 1, this will have been done in
+     process_init_element; do not repeat it here because in the case
+     of excess initializers for an empty aggregate this leads to an
+     infinite cycle of popping a level and immediately recreating
+     it.  */
+  if (implicit != 1)
     {
-      if ((TREE_CODE (constructor_type) == RECORD_TYPE
-          || TREE_CODE (constructor_type) == UNION_TYPE)
-         && constructor_fields == 0)
-       process_init_element (pop_init_level (1));
-      else if (TREE_CODE (constructor_type) == ARRAY_TYPE
-              && constructor_max_index
-              && tree_int_cst_lt (constructor_max_index, constructor_index))
-       process_init_element (pop_init_level (1));
-      else
-       break;
+      while (constructor_stack->implicit)
+       {
+         if ((TREE_CODE (constructor_type) == RECORD_TYPE
+              || TREE_CODE (constructor_type) == UNION_TYPE)
+             && constructor_fields == 0)
+           process_init_element (pop_init_level (1));
+         else if (TREE_CODE (constructor_type) == ARRAY_TYPE
+                  && constructor_max_index
+                  && tree_int_cst_lt (constructor_max_index,
+                                      constructor_index))
+           process_init_element (pop_init_level (1));
+         else
+           break;
+       }
     }
 
   /* Unless this is an explicit brace, we need to preserve previous
@@ -4684,7 +5024,8 @@ push_init_level (int implicit)
     }
   else
     {
-      warning_init ("braces around scalar initializer");
+      if (constructor_type != error_mark_node)
+       warning_init ("braces around scalar initializer");
       constructor_fields = constructor_type;
       constructor_unfilled_fields = constructor_type;
     }
@@ -4716,8 +5057,7 @@ pop_init_level (int implicit)
       while (constructor_stack->implicit)
        process_init_element (pop_init_level (1));
 
-      if (constructor_range_stack)
-       abort ();
+      gcc_assert (!constructor_range_stack);
     }
 
   /* Now output all pending elements.  */
@@ -4731,14 +5071,16 @@ pop_init_level (int implicit)
   if (constructor_type && constructor_fields
       && TREE_CODE (constructor_type) == ARRAY_TYPE
       && TYPE_DOMAIN (constructor_type)
-      && ! TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type)))
+      && !TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type)))
     {
       /* Silently discard empty initializations.  The parser will
         already have pedwarned for empty brackets.  */
       if (integer_zerop (constructor_unfilled_index))
        constructor_type = NULL_TREE;
-      else if (! TYPE_SIZE (constructor_type))
+      else
        {
+         gcc_assert (!TYPE_SIZE (constructor_type));
+         
          if (constructor_depth > 2)
            error_init ("initialization of flexible array member in a nested context");
          else if (pedantic)
@@ -4746,14 +5088,10 @@ pop_init_level (int implicit)
 
          /* 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.  */
+            Discard the initializer so that we do not die later.  */
          if (TREE_CHAIN (constructor_fields) != NULL_TREE)
            constructor_type = NULL_TREE;
        }
-      else
-       /* 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.  */
@@ -4764,7 +5102,7 @@ pop_init_level (int implicit)
     {
        /* Do not warn for flexible array members or zero-length arrays.  */
        while (constructor_unfilled_fields
-              && (! DECL_SIZE (constructor_unfilled_fields)
+              && (!DECL_SIZE (constructor_unfilled_fields)
                   || integer_zerop (DECL_SIZE (constructor_unfilled_fields))))
          constructor_unfilled_fields = TREE_CHAIN (constructor_unfilled_fields);
 
@@ -4869,14 +5207,14 @@ set_designator (int array)
   if (constructor_type == 0)
     return 1;
 
-  /* If there were errors in this designator list already, bail out silently.  */
+  /* If there were errors in this designator list already, bail out
+     silently.  */
   if (designator_errorneous)
     return 1;
 
   if (!designator_depth)
     {
-      if (constructor_range_stack)
-       abort ();
+      gcc_assert (!constructor_range_stack);
 
       /* Designator list starts at the level of closest explicit
         braces.  */
@@ -4886,25 +5224,20 @@ set_designator (int array)
       return 0;
     }
 
-  if (constructor_no_implicit)
-    {
-      error_init ("initialization designators may not nest");
-      return 1;
-    }
-
-  if (TREE_CODE (constructor_type) == RECORD_TYPE
-      || TREE_CODE (constructor_type) == UNION_TYPE)
+  switch (TREE_CODE (constructor_type))
     {
+    case  RECORD_TYPE:
+    case  UNION_TYPE:
       subtype = TREE_TYPE (constructor_fields);
       if (subtype != error_mark_node)
        subtype = TYPE_MAIN_VARIANT (subtype);
-    }
-  else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
-    {
+      break;
+    case ARRAY_TYPE:
       subtype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type));
+      break;
+    default:
+      gcc_unreachable ();
     }
-  else
-    abort ();
 
   subcode = TREE_CODE (subtype);
   if (array && subcode != ARRAY_TYPE)
@@ -4964,21 +5297,6 @@ set_init_index (tree first, tree last)
       return;
     }
 
-  while ((TREE_CODE (first) == NOP_EXPR
-         || TREE_CODE (first) == CONVERT_EXPR
-         || TREE_CODE (first) == NON_LVALUE_EXPR)
-        && (TYPE_MODE (TREE_TYPE (first))
-            == TYPE_MODE (TREE_TYPE (TREE_OPERAND (first, 0)))))
-    first = TREE_OPERAND (first, 0);
-
-  if (last)
-    while ((TREE_CODE (last) == NOP_EXPR
-           || TREE_CODE (last) == CONVERT_EXPR
-           || TREE_CODE (last) == NON_LVALUE_EXPR)
-          && (TYPE_MODE (TREE_TYPE (last))
-              == TYPE_MODE (TREE_TYPE (TREE_OPERAND (last, 0)))))
-      last = TREE_OPERAND (last, 0);
-
   if (TREE_CODE (first) != INTEGER_CST)
     error_init ("nonconstant array index in initializer");
   else if (last != 0 && TREE_CODE (last) != INTEGER_CST)
@@ -5049,8 +5367,7 @@ set_init_label (tree fieldname)
     }
 
   if (tail == 0)
-    error ("unknown field `%s' specified in initializer",
-          IDENTIFIER_POINTER (fieldname));
+    error ("unknown field %qE specified in initializer", fieldname);
   else
     {
       constructor_fields = tail;
@@ -5324,18 +5641,17 @@ set_nonincremental_init_from_string (tree str)
   const char *p, *end;
   int byte, wchar_bytes, charwidth, bitpos;
 
-  if (TREE_CODE (constructor_type) != ARRAY_TYPE)
-    abort ();
+  gcc_assert (TREE_CODE (constructor_type) == ARRAY_TYPE);
 
   if (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (str)))
       == TYPE_PRECISION (char_type_node))
     wchar_bytes = 1;
-  else if (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (str)))
-          == TYPE_PRECISION (wchar_type_node))
-    wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
   else
-    abort ();
-
+    {
+      gcc_assert (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (str)))
+                 == TYPE_PRECISION (wchar_type_node));
+      wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
+    }
   charwidth = TYPE_PRECISION (char_type_node);
   type = TREE_TYPE (constructor_type);
   p = TREE_STRING_POINTER (str);
@@ -5467,19 +5783,20 @@ static void
 output_init_element (tree value, bool strict_string, tree type, tree field,
                     int pending)
 {
-  if (type == error_mark_node)
+  if (type == error_mark_node || value == error_mark_node)
     {
       constructor_erroneous = 1;
       return;
     }
-  if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE
-      || (TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
-         && !(TREE_CODE (value) == STRING_CST
-              && TREE_CODE (type) == ARRAY_TYPE
-              && INTEGRAL_TYPE_P (TREE_TYPE (type)))
-         && !comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (value)),
-                        TYPE_MAIN_VARIANT (type))))
-    value = default_conversion (value);
+  if (TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
+      && (TREE_CODE (value) == STRING_CST
+         || TREE_CODE (value) == COMPOUND_LITERAL_EXPR)
+      && !(TREE_CODE (value) == STRING_CST
+          && TREE_CODE (type) == ARRAY_TYPE
+          && INTEGRAL_TYPE_P (TREE_TYPE (type)))
+      && !comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (value)),
+                    TYPE_MAIN_VARIANT (type)))
+    value = default_function_array_conversion (value);
 
   if (TREE_CODE (value) == COMPOUND_LITERAL_EXPR
       && require_constant_value && !flag_isoc99 && pending)
@@ -5495,21 +5812,23 @@ output_init_element (tree value, bool strict_string, tree type, tree field,
     constructor_erroneous = 1;
   else if (!TREE_CONSTANT (value))
     constructor_constant = 0;
-  else if (initializer_constant_valid_p (value, TREE_TYPE (value)) == 0
+  else if (!initializer_constant_valid_p (value, TREE_TYPE (value))
           || ((TREE_CODE (constructor_type) == RECORD_TYPE
                || TREE_CODE (constructor_type) == UNION_TYPE)
               && DECL_C_BIT_FIELD (field)
               && TREE_CODE (value) != INTEGER_CST))
     constructor_simple = 0;
 
-  if (require_constant_value && ! TREE_CONSTANT (value))
+  if (!initializer_constant_valid_p (value, TREE_TYPE (value)))
     {
-      error_init ("initializer element is not constant");
-      value = error_mark_node;
+      if (require_constant_value)
+       {
+         error_init ("initializer element is not constant");
+         value = error_mark_node;
+       }
+      else if (require_constant_elements)
+       pedwarn ("initializer element is not computable at load time");
     }
-  else if (require_constant_elements
-          && initializer_constant_valid_p (value, TREE_TYPE (value)) == 0)
-    pedwarn ("initializer element is not computable at load time");
 
   /* If this field is empty (and not at the end of structure),
      don't do anything other than checking the initializer.  */
@@ -5737,7 +6056,7 @@ output_pending_init_elements (int all)
 
   /* Ordinarily return, but not if we want to output all
      and there are elements left.  */
-  if (! (all && next != 0))
+  if (!(all && next != 0))
     return;
 
   /* If it's not incremental, just skip over the gap, so that after
@@ -5860,7 +6179,7 @@ process_init_element (struct c_expr value)
            value.value = orig_value;
          /* Otherwise, if we have come to a subaggregate,
             and we don't have an element of its type, push into it.  */
-         else if (value.value != 0 && !constructor_no_implicit
+         else if (value.value != 0
                   && value.value != error_mark_node
                   && TYPE_MAIN_VARIANT (TREE_TYPE (value.value)) != fieldtype
                   && (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE
@@ -5935,10 +6254,11 @@ process_init_element (struct c_expr value)
             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
+         if (!in_system_header && !constructor_designated
              && !(value.value && (integer_zerop (value.value)
                                   || real_zerop (value.value))))
-           warning ("traditional C rejects initialization of unions");
+           warning (OPT_Wtraditional, "traditional C rejects initialization "
+                    "of unions");
 
          /* Accept a string constant to initialize a subarray.  */
          if (value.value != 0
@@ -5948,7 +6268,7 @@ process_init_element (struct c_expr value)
            value.value = orig_value;
          /* Otherwise, if we have come to a subaggregate,
             and we don't have an element of its type, push into it.  */
-         else if (value.value != 0 && !constructor_no_implicit
+         else if (value.value != 0
                   && value.value != error_mark_node
                   && TYPE_MAIN_VARIANT (TREE_TYPE (value.value)) != fieldtype
                   && (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE
@@ -5988,7 +6308,7 @@ process_init_element (struct c_expr value)
            value.value = orig_value;
          /* Otherwise, if we have come to a subaggregate,
             and we don't have an element of its type, push into it.  */
-         else if (value.value != 0 && !constructor_no_implicit
+         else if (value.value != 0
                   && value.value != error_mark_node
                   && TYPE_MAIN_VARIANT (TREE_TYPE (value.value)) != elttype
                   && (eltcode == RECORD_TYPE || eltcode == ARRAY_TYPE
@@ -6053,7 +6373,8 @@ process_init_element (struct c_expr value)
 
       /* Handle the sole element allowed in a braced initializer
         for a scalar variable.  */
-      else if (constructor_fields == 0)
+      else if (constructor_type != error_mark_node
+              && constructor_fields == 0)
        {
          pedwarn_init ("excess elements in scalar initializer");
          break;
@@ -6077,16 +6398,14 @@ process_init_element (struct c_expr value)
          constructor_range_stack = 0;
          while (constructor_stack != range_stack->stack)
            {
-             if (!constructor_stack->implicit)
-               abort ();
+             gcc_assert (constructor_stack->implicit);
              process_init_element (pop_init_level (1));
            }
          for (p = range_stack;
               !p->range_end || tree_int_cst_equal (p->index, p->range_end);
               p = p->prev)
            {
-             if (!constructor_stack->implicit)
-               abort ();
+             gcc_assert (constructor_stack->implicit);
              process_init_element (pop_init_level (1));
            }
 
@@ -6147,47 +6466,75 @@ build_asm_expr (tree string, tree outputs, tree inputs, tree clobbers,
   tree args;
   int i;
   const char *constraint;
+  const char **oconstraints;
   bool allows_mem, allows_reg, is_inout;
-  int ninputs;
-  int noutputs;
+  int ninputs, noutputs;
 
   ninputs = list_length (inputs);
   noutputs = list_length (outputs);
+  oconstraints = (const char **) alloca (noutputs * sizeof (const char *));
+
+  string = resolve_asm_operand_names (string, outputs, inputs);
 
   /* Remove output conversions that change the type but not the mode.  */
   for (i = 0, tail = outputs; tail; ++i, tail = TREE_CHAIN (tail))
     {
       tree output = TREE_VALUE (tail);
+
+      /* ??? Really, this should not be here.  Users should be using a
+        proper lvalue, dammit.  But there's a long history of using casts
+        in the output operands.  In cases like longlong.h, this becomes a
+        primitive form of typechecking -- if the cast can be removed, then
+        the output operand had a type of the proper width; otherwise we'll
+        get an error.  Gross, but ...  */
       STRIP_NOPS (output);
-      TREE_VALUE (tail) = output;
-      lvalue_or_else (output, "invalid lvalue in asm statement");
+
+      if (!lvalue_or_else (output, lv_asm))
+       output = error_mark_node;
 
       constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail)));
+      oconstraints[i] = constraint;
 
-      if (!parse_output_constraint (&constraint, i, ninputs, noutputs,
-                                    &allows_mem, &allows_reg, &is_inout))
-        {
-          /* By marking this operand as erroneous, we will not try
-          to process this operand again in expand_asm_operands.  */
-          TREE_VALUE (tail) = error_mark_node;
-          continue;
-        }
+      if (parse_output_constraint (&constraint, i, ninputs, noutputs,
+                                  &allows_mem, &allows_reg, &is_inout))
+       {
+         /* If the operand is going to end up in memory,
+            mark it addressable.  */
+         if (!allows_reg && !c_mark_addressable (output))
+           output = error_mark_node;
+       }
+      else
+        output = error_mark_node;
 
-      /* If the operand is a DECL that is going to end up in
-        memory, assume it is addressable.  This is a bit more
-        conservative than it would ideally be; the exact test is
-        buried deep in expand_asm_operands and depends on the
-        DECL_RTL for the OPERAND -- which we don't have at this
-        point.  */
-      if (!allows_reg && DECL_P (output))
-        c_mark_addressable (output);
+      TREE_VALUE (tail) = output;
     }
 
-  /* Perform default conversions on array and function inputs.
-     Don't do this for other types as it would screw up operands
-     expected to be in memory.  */
-  for (tail = inputs; tail; tail = TREE_CHAIN (tail))
-    TREE_VALUE (tail) = default_function_array_conversion (TREE_VALUE (tail));
+  for (i = 0, tail = inputs; tail; ++i, tail = TREE_CHAIN (tail))
+    {
+      tree input;
+
+      constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail)));
+      input = TREE_VALUE (tail);
+
+      if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
+                                 oconstraints, &allows_mem, &allows_reg))
+       {
+         /* If the operand is going to end up in memory,
+            mark it addressable.  */
+         if (!allows_reg && allows_mem)
+           {
+             /* Strip the nops as we allow this case.  FIXME, this really
+                should be rejected or made deprecated.  */
+             STRIP_NOPS (input);
+             if (!c_mark_addressable (input))
+               input = error_mark_node;
+         }
+       }
+      else
+       input = error_mark_node;
+
+      TREE_VALUE (tail) = input;
+    }
 
   args = build_stmt (ASM_EXPR, string, outputs, inputs, clobbers);
 
@@ -6197,6 +6544,7 @@ build_asm_expr (tree string, tree outputs, tree inputs, tree clobbers,
       ASM_VOLATILE_P (args) = 1;
       ASM_INPUT_P (args) = 1;
     }
+
   return args;
 }
 \f
@@ -6209,6 +6557,41 @@ c_finish_goto_label (tree label)
   if (!decl)
     return NULL_TREE;
 
+  if (C_DECL_UNJUMPABLE_STMT_EXPR (decl))
+    {
+      error ("jump into statement expression");
+      return NULL_TREE;
+    }
+
+  if (C_DECL_UNJUMPABLE_VM (decl))
+    {
+      error ("jump into scope of identifier with variably modified type");
+      return NULL_TREE;
+    }
+
+  if (!C_DECL_UNDEFINABLE_STMT_EXPR (decl))
+    {
+      /* No jump from outside this statement expression context, so
+        record that there is a jump from within this context.  */
+      struct c_label_list *nlist;
+      nlist = XOBNEW (&parser_obstack, struct c_label_list);
+      nlist->next = label_context_stack_se->labels_used;
+      nlist->label = decl;
+      label_context_stack_se->labels_used = nlist;
+    }
+
+  if (!C_DECL_UNDEFINABLE_VM (decl))
+    {
+      /* No jump from outside this context context of identifiers with
+        variably modified type, so record that there is a jump from
+        within this context.  */
+      struct c_label_list *nlist;
+      nlist = XOBNEW (&parser_obstack, struct c_label_list);
+      nlist->next = label_context_stack_vm->labels_used;
+      nlist->label = decl;
+      label_context_stack_vm->labels_used = nlist;
+    }
+
   TREE_USED (decl) = 1;
   return add_stmt (build1 (GOTO_EXPR, void_type_node, decl));
 }
@@ -6219,7 +6602,7 @@ tree
 c_finish_goto_ptr (tree expr)
 {
   if (pedantic)
-    pedwarn ("ISO C forbids `goto *expr;'");
+    pedwarn ("ISO C forbids %<goto *expr;%>");
   expr = convert (ptr_type_node, expr);
   return add_stmt (build1 (GOTO_EXPR, void_type_node, expr));
 }
@@ -6233,24 +6616,25 @@ c_finish_return (tree retval)
   tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl));
 
   if (TREE_THIS_VOLATILE (current_function_decl))
-    warning ("function declared `noreturn' has a `return' statement");
+    warning (0, "function declared %<noreturn%> has a %<return%> statement");
 
   if (!retval)
     {
       current_function_returns_null = 1;
       if ((warn_return_type || flag_isoc99)
          && valtype != 0 && TREE_CODE (valtype) != VOID_TYPE)
-       pedwarn_c99 ("`return' with no value, in function returning non-void");
+       pedwarn_c99 ("%<return%> with no value, in "
+                    "function returning non-void");
     }
   else if (valtype == 0 || TREE_CODE (valtype) == VOID_TYPE)
     {
       current_function_returns_null = 1;
       if (pedantic || TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
-       pedwarn ("`return' with a value, in function returning void");
+       pedwarn ("%<return%> with a value, in function returning void");
     }
   else
     {
-      tree t = convert_for_assignment (valtype, retval, _("return"),
+      tree t = convert_for_assignment (valtype, retval, ic_return,
                                       NULL_TREE, NULL_TREE, 0);
       tree res = DECL_RESULT (current_function_decl);
       tree inner;
@@ -6279,7 +6663,7 @@ c_finish_return (tree retval)
              {
                tree op1 = TREE_OPERAND (inner, 1);
 
-               while (! POINTER_TYPE_P (TREE_TYPE (op1))
+               while (!POINTER_TYPE_P (TREE_TYPE (op1))
                       && (TREE_CODE (op1) == NOP_EXPR
                           || TREE_CODE (op1) == NON_LVALUE_EXPR
                           || TREE_CODE (op1) == CONVERT_EXPR))
@@ -6295,15 +6679,15 @@ c_finish_return (tree retval)
            case ADDR_EXPR:
              inner = TREE_OPERAND (inner, 0);
 
-             while (TREE_CODE_CLASS (TREE_CODE (inner)) == 'r'
+             while (REFERENCE_CLASS_P (inner)
                     && TREE_CODE (inner) != INDIRECT_REF)
                inner = TREE_OPERAND (inner, 0);
 
              if (DECL_P (inner)
-                 && ! DECL_EXTERNAL (inner)
-                 && ! TREE_STATIC (inner)
+                 && !DECL_EXTERNAL (inner)
+                 && !TREE_STATIC (inner)
                  && DECL_CONTEXT (inner) == current_function_decl)
-               warning ("function returns address of local variable");
+               warning (0, "function returns address of local variable");
              break;
 
            default:
@@ -6320,10 +6704,10 @@ c_finish_return (tree retval)
 }
 \f
 struct c_switch {
-  /* The SWITCH_STMT being built.  */
-  tree switch_stmt;
+  /* The SWITCH_EXPR being built.  */
+  tree switch_expr;
 
-  /* The original type of the testing expression, ie. before the
+  /* The original type of the testing expression, i.e. before the
      default conversion is applied.  */
   tree orig_type;
 
@@ -6334,6 +6718,16 @@ struct c_switch {
      of the GNU case range extension.  */
   splay_tree cases;
 
+  /* Number of nested statement expressions within this switch
+     statement; if nonzero, case and default labels may not
+     appear.  */
+  unsigned int blocked_stmt_expr;
+
+  /* Scope of outermost declarations of identifiers with variably
+     modified type within this switch statement; if nonzero, case and
+     default labels may not appear.  */
+  unsigned int blocked_vm;
+
   /* The next node on the stack.  */
   struct c_switch *next;
 };
@@ -6347,7 +6741,7 @@ struct c_switch {
 struct c_switch *c_switch_stack;
 
 /* Start a C switch statement, testing expression EXP.  Return the new
-   SWITCH_STMT.  */
+   SWITCH_EXPR.  */
 
 tree
 c_start_case (tree exp)
@@ -6361,36 +6755,39 @@ c_start_case (tree exp)
       code = TREE_CODE (TREE_TYPE (exp));
       orig_type = TREE_TYPE (exp);
 
-      if (! INTEGRAL_TYPE_P (orig_type)
+      if (!INTEGRAL_TYPE_P (orig_type)
          && code != ERROR_MARK)
        {
          error ("switch quantity not an integer");
          exp = integer_zero_node;
+         orig_type = error_mark_node;
        }
       else
        {
          type = TYPE_MAIN_VARIANT (TREE_TYPE (exp));
 
-         if (warn_traditional && !in_system_header
+         if (!in_system_header
              && (type == long_integer_type_node
                  || type == long_unsigned_type_node))
-           warning ("`long' switch expression not converted to `int' in ISO C");
+           warning (OPT_Wtraditional, "%<long%> switch expression not "
+                    "converted to %<int%> in ISO C");
 
          exp = default_conversion (exp);
          type = TREE_TYPE (exp);
        }
     }
 
-  /* Add this new SWITCH_STMT to the stack.  */
+  /* Add this new SWITCH_EXPR to the stack.  */
   cs = XNEW (struct c_switch);
-  cs->switch_stmt = build_stmt ((enum tree_code) SWITCH_STMT, exp, NULL_TREE,
-                               orig_type);
+  cs->switch_expr = build3 (SWITCH_EXPR, orig_type, exp, NULL_TREE, NULL_TREE);
   cs->orig_type = orig_type;
   cs->cases = splay_tree_new (case_compare, NULL, NULL);
+  cs->blocked_stmt_expr = 0;
+  cs->blocked_vm = 0;
   cs->next = c_switch_stack;
   c_switch_stack = cs;
 
-  return add_stmt (cs->switch_stmt);
+  return add_stmt (cs->switch_expr);
 }
 
 /* Process a case label.  */
@@ -6400,19 +6797,38 @@ do_case (tree low_value, tree high_value)
 {
   tree label = NULL_TREE;
 
-  if (c_switch_stack)
+  if (c_switch_stack && !c_switch_stack->blocked_stmt_expr
+      && !c_switch_stack->blocked_vm)
     {
       label = c_add_case_label (c_switch_stack->cases,
-                               SWITCH_COND (c_switch_stack->switch_stmt),
+                               SWITCH_COND (c_switch_stack->switch_expr),
                                c_switch_stack->orig_type,
                                low_value, high_value);
       if (label == error_mark_node)
        label = NULL_TREE;
     }
+  else if (c_switch_stack && c_switch_stack->blocked_stmt_expr)
+    {
+      if (low_value)
+       error ("case label in statement expression not containing "
+              "enclosing switch statement");
+      else
+       error ("%<default%> label in statement expression not containing "
+              "enclosing switch statement");
+    }
+  else if (c_switch_stack && c_switch_stack->blocked_vm)
+    {
+      if (low_value)
+       error ("case label in scope of identifier with variably modified "
+              "type not containing enclosing switch statement");
+      else
+       error ("%<default%> label in scope of identifier with variably "
+              "modified type not containing enclosing switch statement");
+    }
   else if (low_value)
     error ("case label not within a switch statement");
   else
-    error ("`default' label not within a switch statement");
+    error ("%<default%> label not within a switch statement");
 
   return label;
 }
@@ -6423,11 +6839,23 @@ void
 c_finish_case (tree body)
 {
   struct c_switch *cs = c_switch_stack;
+  location_t switch_location;
 
-  SWITCH_BODY (cs->switch_stmt) = body;
+  SWITCH_BODY (cs->switch_expr) = body;
+
+  /* We must not be within a statement expression nested in the switch
+     at this point; we might, however, be within the scope of an
+     identifier with variably modified type nested in the switch.  */
+  gcc_assert (!cs->blocked_stmt_expr);
 
   /* Emit warnings as needed.  */
-  c_do_switch_warnings (cs->cases, cs->switch_stmt);
+  if (EXPR_HAS_LOCATION (cs->switch_expr))
+    switch_location = EXPR_LOCATION (cs->switch_expr);
+  else
+    switch_location = input_location;
+  c_do_switch_warnings (cs->cases, switch_location,
+                       TREE_TYPE (cs->switch_expr),
+                       SWITCH_COND (cs->switch_expr));
 
   /* Pop the stack.  */
   c_switch_stack = cs->next;
@@ -6471,12 +6899,12 @@ c_finish_if_stmt (location_t if_locus, tree cond, tree then_block,
            inner_if = TREE_OPERAND (inner_if, 0);
            break;
          default:
-           abort ();
+           gcc_unreachable ();
          }
     found:
 
       if (COND_EXPR_ELSE (inner_if))
-        warning ("%Hsuggest explicit braces to avoid ambiguous `else'",
+        warning (0, "%Hsuggest explicit braces to avoid ambiguous %<else%>",
                  &if_locus);
     }
 
@@ -6486,7 +6914,7 @@ c_finish_if_stmt (location_t if_locus, tree cond, tree then_block,
       if (TREE_CODE (then_block) == NOP_EXPR && !TREE_TYPE (then_block))
        {
          if (!else_block)
-           warning ("%Hempty body in an if-statement",
+           warning (0, "%Hempty body in an if-statement",
                     EXPR_LOCUS (then_block));
          then_block = alloc_stmt_list ();
        }
@@ -6494,13 +6922,13 @@ c_finish_if_stmt (location_t if_locus, tree cond, tree then_block,
          && TREE_CODE (else_block) == NOP_EXPR
          && !TREE_TYPE (else_block))
        {
-         warning ("%Hempty body in an else-statement",
+         warning (0, "%Hempty body in an else-statement",
                   EXPR_LOCUS (else_block));
          else_block = alloc_stmt_list ();
        }
     }
 
-  stmt = build3 (COND_EXPR, NULL_TREE, cond, then_block, else_block);
+  stmt = build3 (COND_EXPR, void_type_node, cond, then_block, else_block);
   SET_EXPR_LOCATION (stmt, if_locus);
   add_stmt (stmt);
 }
@@ -6517,10 +6945,17 @@ c_finish_loop (location_t start_locus, tree cond, tree incr, tree body,
 {
   tree entry = NULL, exit = NULL, t;
 
-  /* Detect do { ... } while (0) and don't generate loop construct.  */
-  if (cond && !cond_is_first && integer_zerop (cond))
-    cond = NULL;
-  if (cond_is_first || cond)
+  /* If the condition is zero don't generate a loop construct.  */
+  if (cond && integer_zerop (cond))
+    {
+      if (cond_is_first)
+       {
+         t = build_and_jump (&blab);
+         SET_EXPR_LOCATION (t, start_locus);
+         add_stmt (t);
+       }
+    }
+  else
     {
       tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
  
@@ -6529,7 +6964,7 @@ c_finish_loop (location_t start_locus, tree cond, tree incr, tree body,
          then we just build a jump back to the top.  */
       exit = build_and_jump (&LABEL_EXPR_LABEL (top));
  
-      if (cond)
+      if (cond && !integer_nonzerop (cond))
         {
           /* Canonicalize the loop condition to the end.  This means
              generating a branch to the loop condition.  Reuse the
@@ -6576,10 +7011,23 @@ c_finish_loop (location_t start_locus, tree cond, tree incr, tree body,
 tree
 c_finish_bc_stmt (tree *label_p, bool is_break)
 {
+  bool skip;
   tree label = *label_p;
 
+  /* In switch statements break is sometimes stylistically used after
+     a return statement.  This can lead to spurious warnings about
+     control reaching the end of a non-void function when it is
+     inlined.  Note that we are calling block_may_fallthru with
+     language specific tree nodes; this works because
+     block_may_fallthru returns true when given something it does not
+     understand.  */
+  skip = !block_may_fallthru (cur_stmt_list);
+
   if (!label)
-    *label_p = label = create_artificial_label ();
+    {
+      if (!skip)
+       *label_p = label = create_artificial_label ();
+    }
   else if (TREE_CODE (label) != LABEL_DECL)
     {
       if (is_break)
@@ -6589,6 +7037,9 @@ c_finish_bc_stmt (tree *label_p, bool is_break)
       return NULL_TREE;
     }
 
+  if (skip)
+    return NULL_TREE;
+
   return add_stmt (build1 (GOTO_EXPR, void_type_node, label));
 }
 
@@ -6602,7 +7053,7 @@ emit_side_effect_warnings (tree expr)
   else if (!TREE_SIDE_EFFECTS (expr))
     {
       if (!VOID_TYPE_P (TREE_TYPE (expr)) && !TREE_NO_WARNING (expr))
-       warning ("%Hstatement with no effect",
+       warning (0, "%Hstatement with no effect",
                 EXPR_HAS_LOCATION (expr) ? EXPR_LOCUS (expr) : &input_location);
     }
   else if (warn_unused_value)
@@ -6618,13 +7069,6 @@ c_process_expr_stmt (tree expr)
   if (!expr)
     return NULL_TREE;
 
-  /* Do default conversion if safe and possibly important,
-     in case within ({...}).  */
-  if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
-       && (flag_isoc99 || lvalue_p (expr)))
-      || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)
-    expr = default_conversion (expr);
-
   if (warn_sequence_point)
     verify_sequence_points (expr);
 
@@ -6642,7 +7086,7 @@ c_process_expr_stmt (tree expr)
 
   /* If the expression is not of a type to which we cannot assign a line
      number, wrap the thing in a no-op NOP_EXPR.  */
-  if (DECL_P (expr) || TREE_CODE_CLASS (TREE_CODE (expr)) == 'c')
+  if (DECL_P (expr) || CONSTANT_CLASS_P (expr))
     expr = build1 (NOP_EXPR, TREE_TYPE (expr), expr);
 
   if (EXPR_P (expr))
@@ -6669,12 +7113,30 @@ tree
 c_begin_stmt_expr (void)
 {
   tree ret;
+  struct c_label_context_se *nstack;
+  struct c_label_list *glist;
 
   /* We must force a BLOCK for this level so that, if it is not expanded
      later, there is a way to turn off the entire subtree of blocks that
      are contained in it.  */
   keep_next_level ();
   ret = c_begin_compound_stmt (true);
+  if (c_switch_stack)
+    {
+      c_switch_stack->blocked_stmt_expr++;
+      gcc_assert (c_switch_stack->blocked_stmt_expr != 0);
+    }
+  for (glist = label_context_stack_se->labels_used;
+       glist != NULL;
+       glist = glist->next)
+    {
+      C_DECL_UNDEFINABLE_STMT_EXPR (glist->label) = 1;
+    }
+  nstack = XOBNEW (&parser_obstack, struct c_label_context_se);
+  nstack->labels_def = NULL;
+  nstack->labels_used = NULL;
+  nstack->next = label_context_stack_se;
+  label_context_stack_se = nstack;
 
   /* Mark the current statement list as belonging to a statement list.  */
   STATEMENT_LIST_STMT_EXPR (ret) = 1;
@@ -6687,8 +7149,37 @@ c_finish_stmt_expr (tree body)
 {
   tree last, type, tmp, val;
   tree *last_p;
+  struct c_label_list *dlist, *glist, *glist_prev = NULL;
 
   body = c_end_compound_stmt (body, true);
+  if (c_switch_stack)
+    {
+      gcc_assert (c_switch_stack->blocked_stmt_expr != 0);
+      c_switch_stack->blocked_stmt_expr--;
+    }
+  /* It is no longer possible to jump to labels defined within this
+     statement expression.  */
+  for (dlist = label_context_stack_se->labels_def;
+       dlist != NULL;
+       dlist = dlist->next)
+    {
+      C_DECL_UNJUMPABLE_STMT_EXPR (dlist->label) = 1;
+    }
+  /* It is again possible to define labels with a goto just outside
+     this statement expression.  */
+  for (glist = label_context_stack_se->next->labels_used;
+       glist != NULL;
+       glist = glist->next)
+    {
+      C_DECL_UNDEFINABLE_STMT_EXPR (glist->label) = 0;
+      glist_prev = glist;
+    }
+  if (glist_prev != NULL)
+    glist_prev->next = label_context_stack_se->labels_used;
+  else
+    label_context_stack_se->next->labels_used
+      = label_context_stack_se->labels_used;
+  label_context_stack_se = label_context_stack_se->next;
 
   /* Locate the last statement in BODY.  See c_end_compound_stmt
      about always returning a BIND_EXPR.  */
@@ -6759,6 +7250,75 @@ c_finish_stmt_expr (tree body)
 
   return build4 (TARGET_EXPR, type, tmp, body, NULL_TREE, NULL_TREE);
 }
+
+/* Begin the scope of an identifier of variably modified type, scope
+   number SCOPE.  Jumping from outside this scope to inside it is not
+   permitted.  */
+
+void
+c_begin_vm_scope (unsigned int scope)
+{
+  struct c_label_context_vm *nstack;
+  struct c_label_list *glist;
+
+  gcc_assert (scope > 0);
+  if (c_switch_stack && !c_switch_stack->blocked_vm)
+    c_switch_stack->blocked_vm = scope;
+  for (glist = label_context_stack_vm->labels_used;
+       glist != NULL;
+       glist = glist->next)
+    {
+      C_DECL_UNDEFINABLE_VM (glist->label) = 1;
+    }
+  nstack = XOBNEW (&parser_obstack, struct c_label_context_vm);
+  nstack->labels_def = NULL;
+  nstack->labels_used = NULL;
+  nstack->scope = scope;
+  nstack->next = label_context_stack_vm;
+  label_context_stack_vm = nstack;
+}
+
+/* End a scope which may contain identifiers of variably modified
+   type, scope number SCOPE.  */
+
+void
+c_end_vm_scope (unsigned int scope)
+{
+  if (label_context_stack_vm == NULL)
+    return;
+  if (c_switch_stack && c_switch_stack->blocked_vm == scope)
+    c_switch_stack->blocked_vm = 0;
+  /* We may have a number of nested scopes of identifiers with
+     variably modified type, all at this depth.  Pop each in turn.  */
+  while (label_context_stack_vm->scope == scope)
+    {
+      struct c_label_list *dlist, *glist, *glist_prev = NULL;
+
+      /* It is no longer possible to jump to labels defined within this
+        scope.  */
+      for (dlist = label_context_stack_vm->labels_def;
+          dlist != NULL;
+          dlist = dlist->next)
+       {
+         C_DECL_UNJUMPABLE_VM (dlist->label) = 1;
+       }
+      /* It is again possible to define labels with a goto just outside
+        this scope.  */
+      for (glist = label_context_stack_vm->next->labels_used;
+          glist != NULL;
+          glist = glist->next)
+       {
+         C_DECL_UNDEFINABLE_VM (glist->label) = 0;
+         glist_prev = glist;
+       }
+      if (glist_prev != NULL)
+       glist_prev->next = label_context_stack_vm->labels_used;
+      else
+       label_context_stack_vm->next->labels_used
+         = label_context_stack_vm->labels_used;
+      label_context_stack_vm = label_context_stack_vm->next;
+    }
+}
 \f
 /* Begin and end compound statements.  This is as simple as pushing
    and popping new statement lists from the tree.  */
@@ -6845,6 +7405,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
   tree type0, type1;
   enum tree_code code0, code1;
   tree op0, op1;
+  const char *invalid_op_diag;
 
   /* Expression code to give to the expression when it is built.
      Normally this is CODE, which is what the caller asked for,
@@ -6888,6 +7449,9 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
   /* Nonzero means set RESULT_TYPE to the common type of the args.  */
   int common = 0;
 
+  /* True means types are compatible as far as ObjC is concerned.  */
+  bool objc_ok;
+
   if (convert_p)
     {
       op0 = default_conversion (orig_op0);
@@ -6917,6 +7481,15 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
   if (code0 == ERROR_MARK || code1 == ERROR_MARK)
     return error_mark_node;
 
+  if ((invalid_op_diag
+       = targetm.invalid_binary_op (code, type0, type1)))
+    {
+      error (invalid_op_diag);
+      return error_mark_node;
+    }
+
+  objc_ok = objc_compare_types (type0, type1, -3, NULL_TREE);
+
   switch (code)
     {
     case PLUS_EXPR:
@@ -6933,7 +7506,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
       /* Subtraction of two similar pointers.
         We must subtract them as integers, then divide by object size.  */
       if (code0 == POINTER_TYPE && code1 == POINTER_TYPE
-         && comp_target_types (type0, type1, 1))
+         && comp_target_types (type0, type1))
        return pointer_diff (op0, op1);
       /* Handle pointer minus int.  Just like pointer plus int.  */
       else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
@@ -6953,20 +7526,22 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
     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 (skip_evaluation == 0 && integer_zerop (op1))
+       warning (OPT_Wdiv_by_zero, "division by zero");
 
       if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
           || code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE)
          && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
              || code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE))
        {
+         enum tree_code tcode0 = code0, tcode1 = code1;
+
          if (code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE)
-           code0 = TREE_CODE (TREE_TYPE (TREE_TYPE (op0)));
+           tcode0 = TREE_CODE (TREE_TYPE (TREE_TYPE (op0)));
          if (code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE)
-           code1 = TREE_CODE (TREE_TYPE (TREE_TYPE (op1)));
+           tcode1 = TREE_CODE (TREE_TYPE (TREE_TYPE (op1)));
 
-         if (!(code0 == INTEGER_TYPE && code1 == INTEGER_TYPE))
+         if (!(tcode0 == INTEGER_TYPE && tcode1 == INTEGER_TYPE))
            resultcode = RDIV_EXPR;
          else
            /* Although it would be tempting to shorten always here, that
@@ -6976,7 +7551,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
               dividing by something we know != -1.  */
            shorten = (TYPE_UNSIGNED (TREE_TYPE (orig_op0))
                       || (TREE_CODE (op1) == INTEGER_CST
-                          && ! integer_all_onesp (op1)));
+                          && !integer_all_onesp (op1)));
          common = 1;
        }
       break;
@@ -6992,8 +7567,8 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
 
     case TRUNC_MOD_EXPR:
     case FLOOR_MOD_EXPR:
-      if (warn_div_by_zero && skip_evaluation == 0 && integer_zerop (op1))
-       warning ("division by zero");
+      if (skip_evaluation == 0 && integer_zerop (op1))
+       warning (OPT_Wdiv_by_zero, "division by zero");
 
       if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
        {
@@ -7003,7 +7578,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
             only if unsigned or if dividing by something we know != -1.  */
          shorten = (TYPE_UNSIGNED (TREE_TYPE (orig_op0))
                     || (TREE_CODE (op1) == INTEGER_CST
-                        && ! integer_all_onesp (op1)));
+                        && !integer_all_onesp (op1)));
          common = 1;
        }
       break;
@@ -7022,8 +7597,8 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
             but that does not mean the operands should be
             converted to ints!  */
          result_type = integer_type_node;
-         op0 = lang_hooks.truthvalue_conversion (op0);
-         op1 = lang_hooks.truthvalue_conversion (op1);
+         op0 = c_common_truthvalue_conversion (op0);
+         op1 = c_common_truthvalue_conversion (op1);
          converted = 1;
        }
       break;
@@ -7038,14 +7613,14 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
          if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
            {
              if (tree_int_cst_sgn (op1) < 0)
-               warning ("right shift count is negative");
+               warning (0, "right shift count is negative");
              else
                {
-                 if (! integer_zerop (op1))
+                 if (!integer_zerop (op1))
                    short_shift = 1;
 
                  if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
-                   warning ("right shift count >= width of type");
+                   warning (0, "right shift count >= width of type");
                }
            }
 
@@ -7066,33 +7641,10 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
          if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
            {
              if (tree_int_cst_sgn (op1) < 0)
-               warning ("left shift count is negative");
-
-             else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
-               warning ("left shift count >= width of type");
-           }
-
-         /* Use the type of the value to be shifted.  */
-         result_type = type0;
-         /* Convert the shift-count to an integer, regardless of size
-            of value being shifted.  */
-         if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
-           op1 = convert (integer_type_node, op1);
-         /* Avoid converting op1 to result_type later.  */
-         converted = 1;
-       }
-      break;
+               warning (0, "left shift count is negative");
 
-    case RROTATE_EXPR:
-    case LROTATE_EXPR:
-      if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
-       {
-         if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
-           {
-             if (tree_int_cst_sgn (op1) < 0)
-               warning ("shift count is negative");
              else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
-               warning ("shift count >= width of type");
+               warning (0, "left shift count >= width of type");
            }
 
          /* Use the type of the value to be shifted.  */
@@ -7108,8 +7660,9 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
 
     case EQ_EXPR:
     case NE_EXPR:
-      if (warn_float_equal && (code0 == REAL_TYPE || code1 == REAL_TYPE))
-       warning ("comparing floating point with == or != is unsafe");
+      if (code0 == REAL_TYPE || code1 == REAL_TYPE)
+       warning (OPT_Wfloat_equal,
+                "comparing floating point with == or != is unsafe");
       /* Result of comparison is always int,
         but don't convert the args to int!  */
       build_type = integer_type_node;
@@ -7125,7 +7678,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
          /* Anything compares with void *.  void * compares with anything.
             Otherwise, the targets must be compatible
             and both must be object or both incomplete.  */
-         if (comp_target_types (type0, type1, 1))
+         if (comp_target_types (type0, type1))
            result_type = common_pointer_type (type0, type1);
          else if (VOID_TYPE_P (tt0))
            {
@@ -7133,16 +7686,20 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
                 whose value is 0 but which isn't a valid null ptr const.  */
              if (pedantic && (!integer_zerop (op0) || op0 != orig_op0)
                  && TREE_CODE (tt1) == FUNCTION_TYPE)
-               pedwarn ("ISO C forbids comparison of `void *' with function pointer");
+               pedwarn ("ISO C forbids comparison of %<void *%>"
+                        " with function pointer");
            }
          else if (VOID_TYPE_P (tt1))
            {
              if (pedantic && (!integer_zerop (op1) || op1 != orig_op1)
                  && TREE_CODE (tt0) == FUNCTION_TYPE)
-               pedwarn ("ISO C forbids comparison of `void *' with function pointer");
+               pedwarn ("ISO C forbids comparison of %<void *%>"
+                        " with function pointer");
            }
          else
-           pedwarn ("comparison of distinct pointer types lacks a cast");
+           /* Avoid warning about the volatile ObjC EH puts on decls.  */
+           if (!objc_ok)
+             pedwarn ("comparison of distinct pointer types lacks a cast");
 
          if (result_type == NULL_TREE)
            result_type = ptr_type_node;
@@ -7165,28 +7722,6 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
        }
       break;
 
-    case MAX_EXPR:
-    case MIN_EXPR:
-      if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
-         && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
-       shorten = 1;
-      else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
-       {
-         if (comp_target_types (type0, type1, 1))
-           {
-             result_type = common_pointer_type (type0, type1);
-             if (pedantic
-                 && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
-               pedwarn ("ISO C forbids ordered comparisons of pointers to functions");
-           }
-         else
-           {
-             result_type = ptr_type_node;
-             pedwarn ("comparison of distinct pointer types lacks a cast");
-           }
-       }
-      break;
-
     case LE_EXPR:
     case GE_EXPR:
     case LT_EXPR:
@@ -7197,7 +7732,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
        short_compare = 1;
       else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
        {
-         if (comp_target_types (type0, type1, 1))
+         if (comp_target_types (type0, type1))
            {
              result_type = common_pointer_type (type0, type1);
              if (!COMPLETE_TYPE_P (TREE_TYPE (type0))
@@ -7239,30 +7774,22 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
        }
       break;
 
-    case UNORDERED_EXPR:
-    case ORDERED_EXPR:
-    case UNLT_EXPR:
-    case UNLE_EXPR:
-    case UNGT_EXPR:
-    case UNGE_EXPR:
-    case UNEQ_EXPR:
-    case LTGT_EXPR:
-      build_type = integer_type_node;
-      if (code0 != REAL_TYPE || code1 != REAL_TYPE)
-       {
-         error ("unordered comparison on non-floating point argument");
-         return error_mark_node;
-       }
-      common = 1;
-      break;
-
     default:
-      break;
+      gcc_unreachable ();
     }
 
   if (code0 == ERROR_MARK || code1 == ERROR_MARK)
     return error_mark_node;
 
+  if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE
+      && (!tree_int_cst_equal (TYPE_SIZE (type0), TYPE_SIZE (type1))
+         || !same_scalar_type_ignoring_signedness (TREE_TYPE (type0),
+                                                   TREE_TYPE (type1))))
+    {
+      binary_op_error (code);
+      return error_mark_node;
+    }
+
   if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE
        || code0 == VECTOR_TYPE)
       &&
@@ -7272,7 +7799,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
       int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE);
 
       if (shorten || common || short_compare)
-       result_type = common_type (type0, type1);
+       result_type = c_common_type (type0, type1);
 
       /* For certain operations (which identify themselves by shorten != 0)
         if both args were extended from the same smaller type,
@@ -7330,7 +7857,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
              && (unsigned0 || !uns))
            result_type
              = c_common_signed_or_unsigned_type
-             (unsigned0, common_type (TREE_TYPE (arg0), TREE_TYPE (arg1)));
+             (unsigned0, c_common_type (TREE_TYPE (arg0), TREE_TYPE (arg1)));
          else if (TREE_CODE (arg0) == INTEGER_CST
                   && (unsigned1 || !uns)
                   && (TYPE_PRECISION (TREE_TYPE (arg1))
@@ -7404,8 +7931,8 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
 
          if (warn_sign_compare && skip_evaluation == 0)
            {
-             int op0_signed = ! TYPE_UNSIGNED (TREE_TYPE (orig_op0));
-             int op1_signed = ! TYPE_UNSIGNED (TREE_TYPE (orig_op1));
+             int op0_signed = !TYPE_UNSIGNED (TREE_TYPE (orig_op0));
+             int op1_signed = !TYPE_UNSIGNED (TREE_TYPE (orig_op1));
              int unsignedp0, unsignedp1;
              tree primop0 = get_narrower (op0, &unsignedp0);
              tree primop1 = get_narrower (op1, &unsignedp1);
@@ -7424,7 +7951,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
                 Do not warn if the comparison is being done in a signed type,
                 since the signed type will only be chosen if it can represent
                 all the values of the unsigned type.  */
-             if (! TYPE_UNSIGNED (result_type))
+             if (!TYPE_UNSIGNED (result_type))
                /* OK */;
               /* Do not warn if both operands are the same signedness.  */
               else if (op0_signed == op1_signed)
@@ -7459,11 +7986,11 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
                  else if (TREE_CODE (uop) == INTEGER_CST
                           && TREE_CODE (TREE_TYPE (uop)) == ENUMERAL_TYPE
                           && int_fits_type_p
-                          (TYPE_MAX_VALUE (TREE_TYPE(uop)),
+                          (TYPE_MAX_VALUE (TREE_TYPE (uop)),
                            c_common_signed_type (result_type)))
                    /* OK */;
                  else
-                   warning ("comparison between signed and unsigned");
+                   warning (0, "comparison between signed and unsigned");
                }
 
              /* Warn if two unsigned values are being compared in a size
@@ -7507,9 +8034,9 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
                      if (bits < TYPE_PRECISION (result_type)
                          && bits < HOST_BITS_PER_WIDE_INT && unsignedp)
                        {
-                         mask = (~ (HOST_WIDE_INT) 0) << bits;
+                         mask = (~(HOST_WIDE_INT) 0) << bits;
                          if ((mask & constant) != mask)
-                           warning ("comparison of promoted ~unsigned with constant");
+                           warning (0, "comparison of promoted ~unsigned with constant");
                        }
                    }
                  else if (unsignedp0 && unsignedp1
@@ -7517,7 +8044,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
                               < TYPE_PRECISION (result_type))
                           && (TYPE_PRECISION (TREE_TYPE (primop1))
                               < TYPE_PRECISION (result_type)))
-                   warning ("comparison of promoted ~unsigned with unsigned");
+                   warning (0, "comparison of promoted ~unsigned with unsigned");
                }
            }
        }
@@ -7535,7 +8062,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
       return error_mark_node;
     }
 
-  if (! converted)
+  if (!converted)
     {
       if (TREE_TYPE (op0) != result_type)
        op0 = convert (result_type, op0);
@@ -7563,3 +8090,36 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
     return result;
   }
 }
+
+
+/* Convert EXPR to be a truth-value, validating its type for this
+   purpose.  */
+
+tree
+c_objc_common_truthvalue_conversion (tree expr)
+{
+  switch (TREE_CODE (TREE_TYPE (expr)))
+    {
+    case ARRAY_TYPE:
+      error ("used array that cannot be converted to pointer where scalar is required");
+      return error_mark_node;
+
+    case RECORD_TYPE:
+      error ("used struct type value where scalar is required");
+      return error_mark_node;
+
+    case UNION_TYPE:
+      error ("used union type value where scalar is required");
+      return error_mark_node;
+
+    case FUNCTION_TYPE:
+      gcc_unreachable ();
+
+    default:
+      break;
+    }
+
+  /* ??? Should we also give an error for void and vectors rather than
+     leaving those to give errors later?  */
+  return c_common_truthvalue_conversion (expr);
+}