OSDN Git Service

PR c++/21853
[pf3gnuchains/gcc-fork.git] / gcc / cp / typeck.c
index 77fd20a..624f145 100644 (file)
@@ -1,6 +1,6 @@
 /* Build expressions with type checking for C++ compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GCC.
@@ -52,27 +52,12 @@ static bool comp_except_types (tree, tree, bool);
 static bool comp_array_types (tree, tree, bool);
 static tree common_base_type (tree, tree);
 static tree pointer_diff (tree, tree, tree);
-static tree get_delta_difference (tree, tree, int);
+static tree get_delta_difference (tree, tree, bool, bool);
 static void casts_away_constness_r (tree *, tree *);
 static bool casts_away_constness (tree, tree);
 static void maybe_warn_about_returning_address_of_local (tree);
 static tree lookup_destructor (tree, tree, tree);
-
-/* Return the target type of TYPE, which means return T for:
-   T*, T&, T[], T (...), and otherwise, just T.  */
-
-tree
-target_type (tree type)
-{
-  type = non_reference (type);
-  while (TREE_CODE (type) == POINTER_TYPE
-        || TREE_CODE (type) == ARRAY_TYPE
-        || TREE_CODE (type) == FUNCTION_TYPE
-        || TREE_CODE (type) == METHOD_TYPE
-        || TYPE_PTRMEM_P (type))
-    type = TREE_TYPE (type);
-  return type;
-}
+static tree convert_arguments (tree, tree, tree, int);
 
 /* Do `exp = require_complete_type (exp);' to make sure exp
    does not have an incomplete type.  (That includes void types.)
@@ -137,12 +122,11 @@ complete_type (tree type)
 }
 
 /* Like complete_type, but issue an error if the TYPE cannot be completed.
-   VALUE is used for informative diagnostics.  DIAG_TYPE indicates the type
-   of diagnostic: 0 for an error, 1 for a warning, 2 for a pedwarn.
+   VALUE is used for informative diagnostics.
    Returns NULL_TREE if the type cannot be made complete.  */
 
 tree
-complete_type_or_diagnostic (tree type, tree value, int diag_type)
+complete_type_or_else (tree type, tree value)
 {
   type = complete_type (type);
   if (type == error_mark_node)
@@ -150,7 +134,7 @@ complete_type_or_diagnostic (tree type, tree value, int diag_type)
     return NULL_TREE;
   else if (!COMPLETE_TYPE_P (type))
     {
-      cxx_incomplete_type_diagnostic (value, type, diag_type);
+      cxx_incomplete_type_diagnostic (value, type, 0);
       return NULL_TREE;
     }
   else
@@ -174,7 +158,7 @@ type_unknown_p (tree exp)
    As an optimization, free the space we allocate if the parameter
    lists are already common.  */
 
-tree
+static tree
 commonparms (tree p1, tree p2)
 {
   tree oldargs = p1, newargs, n;
@@ -431,7 +415,7 @@ composite_pointer_type_r (tree t1, tree t2, const char* location)
     result_type = composite_pointer_type_r (pointee1, pointee2, location);
   else
     {
-      pedwarn ("%s between distinct pointer types `%T' and `%T' "
+      pedwarn ("%s between distinct pointer types %qT and %qT "
               "lacks a cast",
               location, t1, t2);
       result_type = void_type_node;
@@ -445,7 +429,7 @@ composite_pointer_type_r (tree t1, tree t2, const char* location)
     {
       if (!same_type_p (TYPE_PTRMEM_CLASS_TYPE (t1),
                        TYPE_PTRMEM_CLASS_TYPE (t2)))
-       pedwarn ("%s between distinct pointer types `%T' and `%T' "
+       pedwarn ("%s between distinct pointer types %qT and %qT "
                 "lacks a cast",
                 location, t1, t2);
       result_type = build_ptrmem_type (TYPE_PTRMEM_CLASS_TYPE (t1),
@@ -507,7 +491,8 @@ composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2,
       tree result_type;
 
       if (pedantic && TYPE_PTRFN_P (t2))
-       pedwarn ("ISO C++ forbids %s between pointer of type `void *' and pointer-to-function", location);
+       pedwarn ("ISO C++ forbids %s between pointer of type %<void *%> "
+                 "and pointer-to-function", location);
       result_type 
        = cp_build_qualified_type (void_type_node,
                                   (cp_type_quals (TREE_TYPE (t1))
@@ -518,6 +503,13 @@ composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2,
       return build_type_attribute_variant (result_type, attributes);
     }
 
+  if (c_dialect_objc () && TREE_CODE (t1) == POINTER_TYPE
+      && TREE_CODE (t2) == POINTER_TYPE)
+    {
+      if (objc_compare_types (t1, t2, -3, NULL_TREE))
+       return t1;
+    }
+
   /* [expr.eq] permits the application of a pointer conversion to
      bring the pointers to a common type.  */
   if (TREE_CODE (t1) == POINTER_TYPE && TREE_CODE (t2) == POINTER_TYPE
@@ -537,7 +529,7 @@ composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2,
              (cp_build_qualified_type (class2, TYPE_QUALS (class1))));
       else
        {
-         error ("%s between distinct pointer types `%T' and `%T' "
+         error ("%s between distinct pointer types %qT and %qT "
                 "lacks a cast", location, t1, t2);
          return error_mark_node;
        }
@@ -557,7 +549,7 @@ composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2,
        t2 = build_ptrmem_type (class1, TYPE_PTRMEM_POINTED_TO_TYPE (t2));
       else
        {
-         error ("%s between distinct pointer-to-member types `%T' and `%T' "
+         error ("%s between distinct pointer-to-member types %qT and %qT "
                 "lacks a cast", location, t1, t2);
          return error_mark_node;
        }
@@ -796,7 +788,7 @@ comp_except_types (tree a, tree b, bool exact)
           || TREE_CODE (b) != RECORD_TYPE)
         return false;
       
-      if (ACCESSIBLY_UNIQUELY_DERIVED_P (a, b))
+      if (PUBLICLY_UNIQUELY_DERIVED_P (a, b))
         return true;
     }
   return false;
@@ -920,8 +912,6 @@ comp_array_types (tree t1, tree t2, bool allow_redeclaration)
 bool
 comptypes (tree t1, tree t2, int strict)
 {
-  int retval;
-
   if (t1 == t2)
     return true;
 
@@ -984,9 +974,7 @@ comptypes (tree t1, tree t2, int strict)
       && TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
     return true;
 
-  if (!(*targetm.comp_type_attributes) (t1, t2))
-    return false;
-
+  /* Compare the types.  Break out if they could be the same.  */
   switch (TREE_CODE (t1))
     {
     case TEMPLATE_TEMPLATE_PARM:
@@ -999,7 +987,7 @@ comptypes (tree t1, tree t2, int strict)
           DECL_TEMPLATE_PARMS (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t2))))
        return false;
       if (TREE_CODE (t1) == TEMPLATE_TEMPLATE_PARM)
-       return true;
+       break;
       /* Don't check inheritance.  */
       strict = COMPARE_STRICT;
       /* Fall through.  */
@@ -1010,68 +998,85 @@ comptypes (tree t1, tree t2, int strict)
          && (TYPE_TI_TEMPLATE (t1) == TYPE_TI_TEMPLATE (t2)
              || TREE_CODE (t1) == BOUND_TEMPLATE_TEMPLATE_PARM)
          && comp_template_args (TYPE_TI_ARGS (t1), TYPE_TI_ARGS (t2)))
-       return true;
+       break;
       
       if ((strict & COMPARE_BASE) && DERIVED_FROM_P (t1, t2))
-       return true;
+       break;
       else if ((strict & COMPARE_DERIVED) && DERIVED_FROM_P (t2, t1))
-       return true;
+       break;
       
-      /* We may be dealing with Objective-C instances...  */
-      if (TREE_CODE (t1) == RECORD_TYPE
-         && (retval = objc_comptypes (t1, t2, 0) >= 0))
-         return retval;
-      /* ...but fall through if we are not.  */
-
       return false;
 
     case OFFSET_TYPE:
       if (!comptypes (TYPE_OFFSET_BASETYPE (t1), TYPE_OFFSET_BASETYPE (t2),
                      strict & ~COMPARE_REDECLARATION))
        return false;
-      /* Fall through.  */
+      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+       return false;
+      break;
 
     case POINTER_TYPE:
     case REFERENCE_TYPE:
-      return same_type_p (TREE_TYPE (t1), TREE_TYPE (t2));
+      if (TYPE_MODE (t1) != TYPE_MODE (t2)
+         || TYPE_REF_CAN_ALIAS_ALL (t1) != TYPE_REF_CAN_ALIAS_ALL (t2)
+         || !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+       return false;
+      break;
 
     case METHOD_TYPE:
     case FUNCTION_TYPE:
       if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
        return false;
-      return compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2));
+      if (!compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2)))
+       return false;
+      break;
 
     case ARRAY_TYPE:
       /* Target types must match incl. qualifiers.  */
-      return comp_array_types (t1, t2, !!(strict & COMPARE_REDECLARATION));
+      if (!comp_array_types (t1, t2, !!(strict & COMPARE_REDECLARATION)))
+       return false;
+      break;
 
     case TEMPLATE_TYPE_PARM:
-      return (TEMPLATE_TYPE_IDX (t1) == TEMPLATE_TYPE_IDX (t2)
-             && TEMPLATE_TYPE_LEVEL (t1) == TEMPLATE_TYPE_LEVEL (t2));
+      if (TEMPLATE_TYPE_IDX (t1) != TEMPLATE_TYPE_IDX (t2)
+         || TEMPLATE_TYPE_LEVEL (t1) != TEMPLATE_TYPE_LEVEL (t2))
+       return false;
+      break;
 
     case TYPENAME_TYPE:
       if (!cp_tree_equal (TYPENAME_TYPE_FULLNAME (t1),
                          TYPENAME_TYPE_FULLNAME (t2)))
         return false;
-      return same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2));
+      if (!same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2)))
+       return false;
+      break;
 
     case UNBOUND_CLASS_TEMPLATE:
       if (!cp_tree_equal (TYPE_IDENTIFIER (t1), TYPE_IDENTIFIER (t2)))
         return false;
-      return same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2));
+      if (!same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2)))
+       return false;
+      break;
 
     case COMPLEX_TYPE:
-      return same_type_p (TREE_TYPE (t1), TREE_TYPE (t2));
+      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+       return false;
+      break;
 
     case VECTOR_TYPE:
-      return TYPE_VECTOR_SUBPARTS (t1) == TYPE_VECTOR_SUBPARTS (t2)
-            && same_type_p (TREE_TYPE (t1), TREE_TYPE (t2));
+      if (TYPE_VECTOR_SUBPARTS (t1) != TYPE_VECTOR_SUBPARTS (t2)
+         || !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+       return false;
       break;
 
     default:
-      break;
+      return false;
     }
-  return false;
+
+  /* If we get here, we know that from a target independent POV the
+     types are the same.  Make sure the target attributes are also
+     the same.  */
+  return targetm.comp_type_attributes (t1, t2);
 }
 
 /* Returns 1 if TYPE1 is at least as qualified as TYPE2.  */
@@ -1086,17 +1091,6 @@ at_least_as_qualified_p (tree type1, tree type2)
   return (q1 & q2) == q2;
 }
 
-/* Returns 1 if TYPE1 is more qualified than TYPE2.  */
-
-bool
-more_qualified_p (tree type1, tree type2)
-{
-  int q1 = cp_type_quals (type1);
-  int q2 = cp_type_quals (type2);
-
-  return q1 != q2 && (q1 & q2) == q2;
-}
-
 /* Returns 1 if TYPE1 is more cv-qualified than TYPE2, -1 if TYPE2 is
    more cv-qualified that TYPE1, and 0 otherwise.  */
 
@@ -1229,7 +1223,7 @@ cxx_sizeof_or_alignof_type (tree type, enum tree_code op, bool complain)
   if (type == error_mark_node)
     return error_mark_node;
   
-  if (processing_template_decl)
+  if (dependent_type_p (type))
     {
       value = build_min (op, size_type_node, type);
       TREE_READONLY (value) = 1;
@@ -1244,11 +1238,13 @@ cxx_sizeof_or_alignof_type (tree type, enum tree_code op, bool complain)
   if (type_code == METHOD_TYPE)
     {
       if (complain && (pedantic || warn_pointer_arith))
-       pedwarn ("invalid application of `%s' to a member function", op_name);
+       pedwarn ("invalid application of %qs to a member function", op_name);
       value = size_one_node;
     }
   else
-    value = c_sizeof_or_alignof_type (complete_type (type), op, complain);
+    value = c_sizeof_or_alignof_type (complete_type (type),
+                                     op == SIZEOF_EXPR,
+                                     complain);
 
   return value;
 }
@@ -1277,12 +1273,13 @@ cxx_sizeof_or_alignof_expr (tree e, enum tree_code op)
       && TREE_CODE (TREE_OPERAND (e, 1)) == FIELD_DECL
       && DECL_C_BIT_FIELD (TREE_OPERAND (e, 1)))
     {
-      error ("invalid application of `%s' to a bit-field", op_name);
+      error ("invalid application of %qs to a bit-field", op_name);
       e = char_type_node;
     }
   else if (is_overloaded_fn (e))
     {
-      pedwarn ("ISO C++ forbids applying `%s' to an expression of function type", op_name);
+      pedwarn ("ISO C++ forbids applying %qs to an expression of "
+               "function type", op_name);
       e = char_type_node;
     }
   else if (type_unknown_p (e))
@@ -1339,13 +1336,6 @@ decay_conversion (tree exp)
   type = TREE_TYPE (exp);
   code = TREE_CODE (type);
 
-  if (code == REFERENCE_TYPE)
-    {
-      exp = convert_from_reference (exp);
-      type = TREE_TYPE (exp);
-      code = TREE_CODE (type);
-    }
-
   if (type == error_mark_node)
     return error_mark_node;
 
@@ -1354,20 +1344,9 @@ decay_conversion (tree exp)
       cxx_incomplete_type_error (exp, TREE_TYPE (exp));
       return error_mark_node;
     }
-  
-  /* 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.  We
-     don't do this for arrays, though; we want the address of the
-     first element of the array, not the address of the first element
-     of its initializing constant.  */
-  else if (code != ARRAY_TYPE)
-    {
-      exp = decl_constant_value (exp);
-      type = TREE_TYPE (exp);
-    }
 
+  exp = integral_constant_value (exp);
+  
   /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
      Leave such NOP_EXPRs, since RHS is being used in non-lvalue context.  */
 
@@ -1503,7 +1482,7 @@ string_conv_p (tree totype, tree exp, int warn)
 
   /* This warning is not very useful, as it complains about printf.  */
   if (warn && warn_write_strings)
-    warning ("deprecated conversion from string constant to `%T'", totype);
+    warning (0, "deprecated conversion from string constant to %qT'", totype);
 
   return 1;
 }
@@ -1524,6 +1503,9 @@ rationalize_conditional_expr (enum tree_code code, tree t)
      are equal, so we know what conditional expression this used to be.  */
   if (TREE_CODE (t) == MIN_EXPR || TREE_CODE (t) == MAX_EXPR)
     {
+      /* The following code is incorrect if either operand side-effects.  */
+      gcc_assert (!TREE_SIDE_EFFECTS (TREE_OPERAND (t, 0))
+                 && !TREE_SIDE_EFFECTS (TREE_OPERAND (t, 1)));
       return
        build_conditional_expr (build_x_binary_op ((TREE_CODE (t) == MIN_EXPR
                                                    ? LE_EXPR : GE_EXPR),
@@ -1599,9 +1581,6 @@ build_class_member_access_expr (tree object, tree member,
   if (object == error_mark_node || member == error_mark_node)
     return error_mark_node;
 
-  if (TREE_CODE (member) == PSEUDO_DTOR_EXPR)
-    return member;
-
   gcc_assert (DECL_P (member) || BASELINK_P (member));
 
   /* [expr.ref]
@@ -1614,7 +1593,7 @@ build_class_member_access_expr (tree object, tree member,
     return error_mark_node;
   if (!CLASS_TYPE_P (object_type))
     {
-      error ("request for member `%D' in `%E', which is of non-class type `%T'", 
+      error ("request for member %qD in %qE, which is of non-class type %qT", 
             member, object, object_type);
       return error_mark_node;
     }
@@ -1641,9 +1620,9 @@ build_class_member_access_expr (tree object, tree member,
   if (!member_scope || !DERIVED_FROM_P (member_scope, object_type))
     {
       if (TREE_CODE (member) == FIELD_DECL)
-        error ("invalid use of nonstatic data member '%E'", member);
+        error ("invalid use of nonstatic data member %qE", member);
       else
-        error ("`%D' is not a member of `%T'", member, object_type);
+        error ("%qD is not a member of %qT", member, object_type);
       return error_mark_node;
     }
 
@@ -1684,7 +1663,7 @@ build_class_member_access_expr (tree object, tree member,
          base_kind kind;
 
          binfo = lookup_base (access_path ? access_path : object_type,
-                              member_scope, ba_ignore,  &kind);
+                              member_scope, ba_unique,  &kind);
          if (binfo == error_mark_node)
            return error_mark_node;
 
@@ -1693,9 +1672,10 @@ build_class_member_access_expr (tree object, tree member,
             offsetof macro.  */
          if (null_object_p && kind == bk_via_virtual)
            {
-             error ("invalid access to non-static data member `%D' of NULL object",
+             error ("invalid access to non-static data member %qD of "
+                     "NULL object",
                     member);
-             error ("(perhaps the `offsetof' macro was used incorrectly)");
+             error ("(perhaps the %<offsetof%> macro was used incorrectly)");
              return error_mark_node;
            }
 
@@ -1720,9 +1700,9 @@ build_class_member_access_expr (tree object, tree member,
          && !DECL_FIELD_IS_BASE (member)
          && !skip_evaluation)
        {
-         warning ("invalid access to non-static data member `%D' of NULL object", 
+         warning (0, "invalid access to non-static data member %qD of NULL object", 
                   member);
-         warning  ("(perhaps the `offsetof' macro was used incorrectly)");
+         warning (0, "(perhaps the %<offsetof%> macro was used incorrectly)");
        }
 
       /* If MEMBER is from an anonymous aggregate, we have converted
@@ -1765,15 +1745,16 @@ build_class_member_access_expr (tree object, tree member,
          member_type = cp_build_qualified_type (member_type, type_quals);
        }
 
-      result = fold (build3 (COMPONENT_REF, member_type, object, member,
-                            NULL_TREE));
+      result = build3 (COMPONENT_REF, member_type, object, member,
+                      NULL_TREE);
+      result = fold_if_not_in_template (result);
 
       /* Mark the expression const or volatile, as appropriate.  Even
         though we've dealt with the type above, we still have to mark the
         expression itself.  */
       if (type_quals & TYPE_QUAL_CONST)
        TREE_READONLY (result) = 1;
-      else if (type_quals & TYPE_QUAL_VOLATILE)
+      if (type_quals & TYPE_QUAL_VOLATILE)
        TREE_THIS_VOLATILE (result) = 1;
     }
   else if (BASELINK_P (member))
@@ -1806,7 +1787,7 @@ build_class_member_access_expr (tree object, tree member,
     }
   else
     {
-      error ("invalid use of `%D'", member);
+      error ("invalid use of %qD", member);
       return error_mark_node;
     }
 
@@ -1832,19 +1813,16 @@ lookup_destructor (tree object, tree scope, tree dtor_name)
 
   if (scope && !check_dtor_name (scope, dtor_name))
     {
-      error ("qualified type `%T' does not match destructor name `~%T'",
+      error ("qualified type %qT does not match destructor name ~%qT",
             scope, dtor_type);
       return error_mark_node;
     }
   if (!DERIVED_FROM_P (dtor_type, TYPE_MAIN_VARIANT (object_type)))
     {
-      error ("the type being destroyed is `%T', but the destructor refers to `%T'",
+      error ("the type being destroyed is %qT, but the destructor refers to %qT",
             TYPE_MAIN_VARIANT (object_type), dtor_type);
       return error_mark_node;
     }
-  if (!TYPE_HAS_DESTRUCTOR (dtor_type))
-    return build3 (PSEUDO_DTOR_EXPR, void_type_node, object, scope,
-                  dtor_type);
   expr = lookup_member (dtor_type, complete_dtor_identifier,
                        /*protect=*/1, /*want_type=*/false);
   expr = (adjust_result_of_qualified_name_lookup
@@ -1873,6 +1851,10 @@ finish_class_member_access_expr (tree object, tree name)
   if (object == error_mark_node || name == error_mark_node)
     return error_mark_node;
 
+  /* If OBJECT is an ObjC class instance, we must obey ObjC access rules.  */
+  if (!objc_is_public (object, name))
+    return error_mark_node;
+
   object_type = TREE_TYPE (object);
 
   if (processing_template_decl)
@@ -1896,12 +1878,6 @@ finish_class_member_access_expr (tree object, tree name)
       object = build_non_dependent_expr (object);
     }
   
-  if (TREE_CODE (object_type) == REFERENCE_TYPE)
-    {
-      object = convert_from_reference (object);
-      object_type = TREE_TYPE (object);
-    }
-
   /* [expr.ref]
 
      The type of the first expression shall be "class object" (of a
@@ -1911,7 +1887,7 @@ finish_class_member_access_expr (tree object, tree name)
     return error_mark_node;
   if (!CLASS_TYPE_P (object_type))
     {
-      error ("request for member `%D' in `%E', which is of non-class type `%T'", 
+      error ("request for member %qD in %qE, which is of non-class type %qT", 
             name, object, object_type);
       return error_mark_node;
     }
@@ -1957,7 +1933,7 @@ finish_class_member_access_expr (tree object, tree name)
             name a member of OBJECT_TYPE.  */
          if (TREE_CODE (scope) == NAMESPACE_DECL)
            {
-             error ("`%D::%D' is not a member of `%T'", 
+             error ("%<%D::%D%> is not a member of %qT", 
                     scope, name, object_type);
              return error_mark_node;
            }
@@ -1968,7 +1944,7 @@ finish_class_member_access_expr (tree object, tree name)
            return error_mark_node;
          if (!access_path)
            {
-             error ("`%T' is not a base of `%T'", scope, object_type);
+             error ("%qT is not a base of %qT", scope, object_type);
              return error_mark_node;
            }
        }
@@ -1987,7 +1963,7 @@ finish_class_member_access_expr (tree object, tree name)
                                  /*want_type=*/false);
          if (member == NULL_TREE)
            {
-             error ("'%D' has no member named '%E'", object_type, name);
+             error ("%qD has no member named %qE", object_type, name);
              return error_mark_node;
            }
          if (member == error_mark_node)
@@ -2002,7 +1978,7 @@ finish_class_member_access_expr (tree object, tree name)
            template = lookup_template_function (template, template_args);
          else
            {
-             error ("`%D' is not a member template function", name);
+             error ("%qD is not a member template function", name);
              return error_mark_node;
            }
        }
@@ -2043,8 +2019,8 @@ build_ptrmemfunc_access_expr (tree ptrmem, tree member_name)
                          /*want_type=*/false);
   member_type = cp_build_qualified_type (TREE_TYPE (member),
                                         cp_type_quals (ptrmem_type));
-  return fold (build3 (COMPONENT_REF, member_type,
-                      ptrmem, member, NULL_TREE));
+  return fold_build3 (COMPONENT_REF, member_type,
+                     ptrmem, member, NULL_TREE);
 }
 
 /* Given an expression PTR for a pointer, return an expression
@@ -2093,7 +2069,7 @@ build_indirect_ref (tree ptr, const char *errorstring)
             ? ptr : decay_conversion (ptr));
   type = TREE_TYPE (pointer);
 
-  if (TYPE_PTR_P (type) || TREE_CODE (type) == REFERENCE_TYPE)
+  if (POINTER_TYPE_P (type))
     {
       /* [expr.unary.op]
         
@@ -2109,7 +2085,7 @@ build_indirect_ref (tree ptr, const char *errorstring)
         {
           /* A pointer to incomplete type (other than cv void) can be
              dereferenced [expr.unary.op]/1  */
-          error ("`%T' is not a pointer-to-object type", type);
+          error ("%qT is not a pointer-to-object type", type);
           return error_mark_node;
         }
       else if (TREE_CODE (pointer) == ADDR_EXPR
@@ -2134,11 +2110,11 @@ build_indirect_ref (tree ptr, const char *errorstring)
   /* `pointer' won't be an error_mark_node if we were given a
      pointer to member, so it's cool to check for this here.  */
   else if (TYPE_PTR_TO_MEMBER_P (type))
-    error ("invalid use of `%s' on pointer to member", errorstring);
+    error ("invalid use of %qs on pointer to member", errorstring);
   else if (pointer != error_mark_node)
     {
       if (errorstring)
-       error ("invalid type argument of `%s'", errorstring);
+       error ("invalid type argument of %qs", errorstring);
       else
        error ("invalid type argument");
     }
@@ -2204,7 +2180,7 @@ build_array_ref (tree array, tree idx)
         must have done so deliberately.  */
       if (warn_char_subscripts
          && TYPE_MAIN_VARIANT (TREE_TYPE (idx)) == char_type_node)
-       warning ("array subscript has type `char'");
+       warning (0, "array subscript has type %<char%>");
 
       if (!INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (idx)))
        {
@@ -2214,7 +2190,7 @@ build_array_ref (tree array, tree idx)
 
       /* Apply integral promotions *after* noticing character types.
         (It is unclear why we do these promotions -- the standard
-        does not say that we should.  In fact, the natual thing would
+        does not say that we should.  In fact, the natural thing would
         seem to be to convert IDX to ptrdiff_t; we're performing
         pointer arithmetic.)  */
       idx = perform_integral_promotions (idx);
@@ -2256,7 +2232,7 @@ build_array_ref (tree array, tree idx)
          while (TREE_CODE (foo) == COMPONENT_REF)
            foo = TREE_OPERAND (foo, 0);
          if (TREE_CODE (foo) == VAR_DECL && DECL_REGISTER (foo))
-           warning ("subscripting array declared `register'");
+           warning (0, "subscripting array declared %<register%>");
        }
 
       type = TREE_TYPE (TREE_TYPE (array));
@@ -2269,7 +2245,7 @@ build_array_ref (tree array, tree idx)
        |= (CP_TYPE_VOLATILE_P (type) | TREE_SIDE_EFFECTS (array));
       TREE_THIS_VOLATILE (rval)
        |= (CP_TYPE_VOLATILE_P (type) | TREE_THIS_VOLATILE (array));
-      return require_complete_type (fold (rval));
+      return require_complete_type (fold_if_not_in_template (rval));
     }
 
   {
@@ -2339,7 +2315,7 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function)
            }
          else
            {
-             error ("object missing in use of `%E'", function);
+             error ("object missing in use of %qE", function);
              return error_mark_node;
            }
        }
@@ -2351,7 +2327,7 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function)
        function = save_expr (function);
 
       /* Start by extracting all the information from the PMF itself.  */
-      e3 = PFN_FROM_PTRMEMFUNC (function);
+      e3 = pfn_from_ptrmemfunc (function);
       delta = build_ptrmemfunc_access_expr (function, delta_identifier);
       idx = build1 (NOP_EXPR, vtable_index_type, e3);
       switch (TARGET_PTRMEMFUNC_VBIT_LOCATION)
@@ -2370,14 +2346,23 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function)
          gcc_unreachable ();
        }
 
-      /* Convert down to the right base before using the instance.  First
-         use the type...  */
+      /* Convert down to the right base before using the instance.  A
+        special case is that in a pointer to member of class C, C may
+        be incomplete.  In that case, the function will of course be
+        a member of C, and no conversion is required.  In fact,
+        lookup_base will fail in that case, because incomplete
+        classes do not have BINFOs.  */ 
       basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (fntype));
-      basetype = lookup_base (TREE_TYPE (TREE_TYPE (instance_ptr)),
-                             basetype, ba_check, NULL);
-      instance_ptr = build_base_path (PLUS_EXPR, instance_ptr, basetype, 1);
-      if (instance_ptr == error_mark_node)
-       return error_mark_node;
+      if (!same_type_ignoring_top_level_qualifiers_p 
+         (basetype, TREE_TYPE (TREE_TYPE (instance_ptr))))
+       {
+         basetype = lookup_base (TREE_TYPE (TREE_TYPE (instance_ptr)),
+                                 basetype, ba_check, NULL);
+         instance_ptr = build_base_path (PLUS_EXPR, instance_ptr, basetype, 
+                                         1);
+         if (instance_ptr == error_mark_node)
+           return error_mark_node;
+       }
       /* ...and then the delta in the PMF.  */
       instance_ptr = build2 (PLUS_EXPR, TREE_TYPE (instance_ptr),
                             instance_ptr, delta);
@@ -2391,7 +2376,7 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function)
       vtbl = build_indirect_ref (vtbl, NULL);
 
       /* Finally, extract the function pointer from the vtable.  */
-      e2 = fold (build2 (PLUS_EXPR, TREE_TYPE (vtbl), vtbl, idx));
+      e2 = fold_build2 (PLUS_EXPR, TREE_TYPE (vtbl), vtbl, idx);
       e2 = build_indirect_ref (e2, NULL);
       TREE_CONSTANT (e2) = 1;
       TREE_INVARIANT (e2) = 1;
@@ -2425,6 +2410,10 @@ build_function_call (tree function, tree params)
   int is_method;
   tree original = 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);
+
   /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
      Strip such NOP_EXPRs, since FUNCTION is used in non-lvalue context.  */
   if (TREE_CODE (function) == NOP_EXPR
@@ -2440,7 +2429,7 @@ build_function_call (tree function, tree params)
 
       /* Convert anything with function type to a pointer-to-function.  */
       if (pedantic && DECL_MAIN_P (function))
-       pedwarn ("ISO C++ forbids calling `::main' from within program");
+       pedwarn ("ISO C++ forbids calling %<::main%> from within program");
 
       /* Differs from default_conversion by not setting TREE_ADDRESSABLE
         (because calling an inline function does not mean the function
@@ -2465,8 +2454,9 @@ build_function_call (tree function, tree params)
 
   if (TYPE_PTRMEMFUNC_P (fntype))
     {
-      error ("must use .* or ->* to call pointer-to-member function in `%E (...)'",
-               original);
+      error ("must use %<.*%> or %<->*%> to call pointer-to-member "
+             "function in %<%E (...)%>",
+             original);
       return error_mark_node;
     }
 
@@ -2478,7 +2468,7 @@ build_function_call (tree function, tree params)
        || is_method
        || TREE_CODE (function) == TEMPLATE_ID_EXPR))
     {
-      error ("`%E' cannot be used as a function", original);
+      error ("%qE cannot be used as a function", original);
       return error_mark_node;
     }
 
@@ -2518,7 +2508,7 @@ build_function_call (tree function, tree params)
    In C++, unspecified trailing parameters can be filled in with their
    default arguments, if such were specified.  Do so here.  */
 
-tree
+static tree
 convert_arguments (tree typelist, tree values, tree fndecl, int flags)
 {
   tree typetail, valtail;
@@ -2557,7 +2547,7 @@ convert_arguments (tree typelist, tree values, tree fndecl, int flags)
        {
          if (fndecl)
            {
-             cp_error_at ("too many arguments to %s `%+#D'", called_thing,
+             cp_error_at ("too many arguments to %s %q+#D", called_thing,
                           fndecl);
              error ("at this point in file");
            }
@@ -2596,10 +2586,10 @@ convert_arguments (tree typelist, tree values, tree fndecl, int flags)
          if (!COMPLETE_TYPE_P (complete_type (type)))
            {
              if (fndecl)
-               error ("parameter %P of `%D' has incomplete type `%T'",
+               error ("parameter %P of %qD has incomplete type %qT",
                       i, fndecl, type);
              else
-               error ("parameter %P has incomplete type `%T'", i, type);
+               error ("parameter %P has incomplete type %qT", i, type);
              parmval = error_mark_node;
            }
          else
@@ -2617,9 +2607,6 @@ convert_arguments (tree typelist, tree values, tree fndecl, int flags)
        }
       else
        {
-         if (TREE_CODE (TREE_TYPE (val)) == REFERENCE_TYPE)
-           val = convert_from_reference (val);
-
          if (fndecl && DECL_BUILT_IN (fndecl)
              && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CONSTANT_P)
            /* Don't do ellipsis conversion for __built_in_constant_p
@@ -2663,7 +2650,7 @@ convert_arguments (tree typelist, tree values, tree fndecl, int flags)
        {
          if (fndecl)
            {
-             cp_error_at ("too few arguments to %s `%+#D'",
+             cp_error_at ("too few arguments to %s %q+#D",
                           called_thing, fndecl);
              error ("at this point in file");
            }
@@ -2759,6 +2746,8 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
      convert it to this type.  */
   tree final_type = 0;
 
+  tree result;
+
   /* Nonzero if this is an operation like MIN or MAX which can
      safely be computed in short if both args are promoted shorts.
      Also implies COMMON.
@@ -2779,6 +2768,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 if both operands have arithmetic type.  */
+  bool arithmetic_types_p;
+
   /* Apply default conversions.  */
   op0 = orig_op0;
   op1 = orig_op1;
@@ -2810,8 +2802,8 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
       tree t = instantiate_type (TREE_TYPE (op1), op0, tf_none);
       if (t != error_mark_node)
        {
-         pedwarn ("assuming cast to type `%T' from overloaded function",
-                     TREE_TYPE (t));
+         pedwarn ("assuming cast to type %qT from overloaded function",
+                   TREE_TYPE (t));
          op0 = t;
        }
     }
@@ -2820,8 +2812,8 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
       tree t = instantiate_type (TREE_TYPE (op0), op1, tf_none);
       if (t != error_mark_node)
        {
-         pedwarn ("assuming cast to type `%T' from overloaded function",
-                     TREE_TYPE (t));
+         pedwarn ("assuming cast to type %qT from overloaded function",
+                   TREE_TYPE (t));
          op1 = t;
        }
     }
@@ -2881,9 +2873,9 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
              || code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE))
        {
          if (TREE_CODE (op1) == INTEGER_CST && integer_zerop (op1))
-           warning ("division by zero in `%E / 0'", op0);
+           warning (0, "division by zero in %<%E / 0%>", op0);
          else if (TREE_CODE (op1) == REAL_CST && real_zerop (op1))
-           warning ("division by zero in `%E / 0.'", op0);
+           warning (0, "division by zero in %<%E / 0.%>", op0);
              
          if (code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE)
            code0 = TREE_CODE (TREE_TYPE (TREE_TYPE (op0)));
@@ -2917,9 +2909,9 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
     case TRUNC_MOD_EXPR:
     case FLOOR_MOD_EXPR:
       if (code1 == INTEGER_TYPE && integer_zerop (op1))
-       warning ("division by zero in `%E %% 0'", op0);
+       warning (0, "division by zero in %<%E %% 0%>", op0);
       else if (code1 == REAL_TYPE && real_zerop (op1))
-       warning ("division by zero in `%E %% 0.'", op0);
+       warning (0, "division by zero in %<%E %% 0.%>", op0);
       
       if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
        {
@@ -2953,13 +2945,13 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
          if (TREE_CODE (op1) == INTEGER_CST)
            {
              if (tree_int_cst_lt (op1, integer_zero_node))
-               warning ("right shift count is negative");
+               warning (0, "right shift count is negative");
              else
                {
                  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");
                }
            }
          /* Convert the shift-count to an integer, regardless of
@@ -2978,9 +2970,9 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
          if (TREE_CODE (op1) == INTEGER_CST)
            {
              if (tree_int_cst_lt (op1, integer_zero_node))
-               warning ("left shift count is negative");
+               warning (0, "left shift count is negative");
              else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
-               warning ("left shift count >= width of type");
+               warning (0, "left shift count >= width of type");
            }
          /* Convert the shift-count to an integer, regardless of
             size of value being shifted.  */
@@ -2999,10 +2991,10 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
          if (TREE_CODE (op1) == INTEGER_CST)
            {
              if (tree_int_cst_lt (op1, integer_zero_node))
-               warning ("%s rotate count is negative",
+               warning (0, "%s rotate count is negative",
                         (code == LROTATE_EXPR) ? "left" : "right");
              else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
-               warning ("%s rotate count >= width of type",
+               warning (0, "%s rotate count >= width of type",
                         (code == LROTATE_EXPR) ? "left" : "right");
            }
          /* Convert the shift-count to an integer, regardless of
@@ -3015,7 +3007,7 @@ 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");
+       warning (0, "comparing floating point with == or != is unsafe");
 
       build_type = boolean_type_node; 
       if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
@@ -3166,14 +3158,33 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
       break;
     }
 
-  if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE)
-      &&
-      (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE))
+  arithmetic_types_p = 
+    ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE)
+     && (code1 == INTEGER_TYPE || code1 == REAL_TYPE 
+        || code1 == COMPLEX_TYPE));
+  /* Determine the RESULT_TYPE, if it is not already known.  */
+  if (!result_type
+      && arithmetic_types_p 
+      && (shorten || common || short_compare))
+    result_type = common_type (type0, type1);
+
+  if (!result_type)
     {
-      int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE);
+      error ("invalid operands of types %qT and %qT to binary %qO",
+            TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), code);
+      return error_mark_node;
+    }
 
-      if (shorten || common || short_compare)
-       result_type = common_type (type0, type1);
+  /* If we're in a template, the only thing we need to know is the
+     RESULT_TYPE.  */
+  if (processing_template_decl)
+    return build2 (resultcode, 
+                  build_type ? build_type : result_type, 
+                  op0, op1);
+
+  if (arithmetic_types_p)
+    {
+      int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE);
 
       /* For certain operations (which identify themselves by shorten != 0)
         if both args were extended from the same smaller type,
@@ -3323,8 +3334,8 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
              && TYPE_MAIN_VARIANT (TREE_TYPE (orig_op0))
                 != TYPE_MAIN_VARIANT (TREE_TYPE (orig_op1)))
            {
-             warning ("comparison between types `%#T' and `%#T'", 
-                         TREE_TYPE (orig_op0), TREE_TYPE (orig_op1));
+             warning (0, "comparison between types %q#T and %q#T", 
+                       TREE_TYPE (orig_op0), TREE_TYPE (orig_op1));
            }
 
          /* Give warnings for comparisons between signed and unsigned
@@ -3359,7 +3370,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
                                                (result_type)))))
            /* OK */;
          else
-           warning ("comparison between signed and unsigned integer expressions");
+           warning (0, "comparison between signed and unsigned integer expressions");
 
          /* Warn if two unsigned values are being compared in a size
             larger than their original size, and one (and only one) is the
@@ -3403,7 +3414,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
                    {
                      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
@@ -3411,24 +3422,16 @@ 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");
            }
        }
     }
 
-  /* At this point, RESULT_TYPE must be nonzero to avoid an error message.
-     If CONVERTED is zero, both args will be converted to type RESULT_TYPE.
+  /* If CONVERTED is zero, both args will be converted to type RESULT_TYPE.
      Then the expression will be built.
      It will be given type FINAL_TYPE if that is nonzero;
      otherwise, it will be given type RESULT_TYPE.  */
 
-  if (!result_type)
-    {
-      error ("invalid operands of types `%T' and `%T' to binary `%O'",
-               TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), code);
-      return error_mark_node;
-    }
-
   /* Issue warnings about peculiar, but valid, uses of NULL.  */
   if (/* It's reasonable to use pointer values as operands of &&
         and ||, so NULL is no exception.  */
@@ -3446,7 +3449,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
        performed.  Note that pointer-difference and pointer-addition
        have already been handled above, and so we don't end up here in
        that case.  */
-    warning ("NULL used in arithmetic");
+    warning (0, "NULL used in arithmetic");
 
   if (! converted)
     {
@@ -3462,12 +3465,11 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
   if (build_type == NULL_TREE)
     build_type = result_type;
 
-  {
-    tree result = fold (build2 (resultcode, build_type, op0, op1));
-    if (final_type != 0)
-      result = cp_convert (final_type, result);
-    return result;
-  }
+  result = build2 (resultcode, build_type, op0, op1);
+  result = fold_if_not_in_template (result);
+  if (final_type != 0)
+    result = cp_convert (final_type, result);
+  return result;
 }
 \f
 /* Return a tree for the sum or difference (RESULTCODE says which)
@@ -3485,7 +3487,8 @@ cp_pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop)
      pointer_int_sum() anyway.  */
   complete_type (TREE_TYPE (res_type));
 
-  return pointer_int_sum (resultcode, ptrop, fold (intop));
+  return pointer_int_sum (resultcode, ptrop,
+                         fold_if_not_in_template (intop));
 }
 
 /* Return a tree for the difference of pointers OP0 and OP1.
@@ -3504,7 +3507,7 @@ pointer_diff (tree op0, tree op1, tree ptrtype)
   if (pedantic || warn_pointer_arith)
     {
       if (TREE_CODE (target_type) == VOID_TYPE)
-       pedwarn ("ISO C++ forbids using pointer of type `void *' in subtraction");
+       pedwarn ("ISO C++ forbids using pointer of type %<void *%> in subtraction");
       if (TREE_CODE (target_type) == FUNCTION_TYPE)
        pedwarn ("ISO C++ forbids using pointer to a function in subtraction");
       if (TREE_CODE (target_type) == METHOD_TYPE)
@@ -3529,7 +3532,7 @@ pointer_diff (tree op0, tree op1, tree ptrtype)
   /* Do the division.  */
 
   result = build2 (EXACT_DIV_EXPR, restype, op0, cp_convert (restype, op1));
-  return fold (result);
+  return fold_if_not_in_template (result);
 }
 \f
 /* Construct and perhaps optimize a tree representation
@@ -3548,23 +3551,6 @@ build_x_unary_op (enum tree_code code, tree xarg)
       if (type_dependent_expression_p (xarg))
        return build_min_nt (code, xarg, NULL_TREE);
 
-      /* For non-dependent pointer-to-member, the SCOPE_REF will be
-        processed during template substitution.  Just compute the
-        right type here and build an ADDR_EXPR around it for
-        diagnostics.  */
-      if (code == ADDR_EXPR && TREE_CODE (xarg) == SCOPE_REF)
-       {
-         tree type;
-         if (TREE_TYPE (xarg) == unknown_type_node)
-           type = unknown_type_node;
-         else if (TREE_CODE (TREE_TYPE (xarg)) == FUNCTION_TYPE)
-           type = build_pointer_type (TREE_TYPE (xarg));
-         else
-           type = build_ptrmem_type (TREE_OPERAND (xarg, 0),
-                                     TREE_TYPE (xarg));
-         return build_min (code, type, xarg, NULL_TREE);
-       }
-
       xarg = build_non_dependent_expr (xarg);
     }
 
@@ -3596,13 +3582,15 @@ build_x_unary_op (enum tree_code code, tree xarg)
        {
          if (TREE_CODE (xarg) != OFFSET_REF)
            {
-             error ("invalid use of '%E' to form a pointer-to-member-function.  Use a qualified-id.",
+             error ("invalid use of %qE to form a pointer-to-member-function."
+                     "  Use a qualified-id.",
                     xarg);
              return error_mark_node;
            }
          else
            {
-             error ("parenthesis around '%E' cannot be used to form a pointer-to-member-function",
+             error ("parenthesis around %qE cannot be used to form a"
+                     " pointer-to-member-function",
                     xarg);
              PTRMEM_OK_P (xarg) = 1;
            }
@@ -3624,15 +3612,15 @@ build_x_unary_op (enum tree_code code, tree xarg)
            }         
         }
       else if (TREE_CODE (xarg) == TARGET_EXPR)
-       warning ("taking address of temporary");
+       warning (0, "taking address of temporary");
       exp = build_unary_op (ADDR_EXPR, xarg, 0);
-      if (TREE_CODE (exp) == ADDR_EXPR)
-       PTRMEM_OK_P (exp) = ptrmem;
     }
 
   if (processing_template_decl && exp != error_mark_node)
-    return build_min_non_dep (code, exp, orig_expr,
-                             /*For {PRE,POST}{INC,DEC}REMENT_EXPR*/NULL_TREE);
+    exp = build_min_non_dep (code, exp, orig_expr,
+                            /*For {PRE,POST}{INC,DEC}REMENT_EXPR*/NULL_TREE);
+  if (TREE_CODE (exp) == ADDR_EXPR)
+    PTRMEM_OK_P (exp) = ptrmem;
   return exp;
 }
 
@@ -3659,7 +3647,7 @@ condition_conversion (tree expr)
   if (processing_template_decl)
     return expr;
   t = perform_implicit_conversion (boolean_type_node, expr);
-  t = fold (build1 (CLEANUP_POINT_EXPR, boolean_type_node, t));
+  t = fold_build_cleanup_point_expr (boolean_type_node, t);
   return t;
 }
                
@@ -3713,26 +3701,29 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
 
   switch (code)
     {
-    case CONVERT_EXPR:
-      /* This is used for unary plus, because a CONVERT_EXPR
-        is enough to prevent anybody from looking inside for
-        associativity, but won't generate any code.  */
-      if (!(arg = build_expr_type_conversion
-           (WANT_ARITH | WANT_ENUM | WANT_POINTER, arg, true)))
-       errstring = "wrong type argument to unary plus";
-      else
-       {
-         if (!noconvert)
-           arg = default_conversion (arg);
-         arg = build1 (NON_LVALUE_EXPR, TREE_TYPE (arg), arg);
-       }
-      break;
-
+    case UNARY_PLUS_EXPR:
     case NEGATE_EXPR:
-      if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, true)))
-       errstring = "wrong type argument to unary minus";
-      else if (!noconvert && CP_INTEGRAL_TYPE_P (TREE_TYPE (arg)))
-       arg = perform_integral_promotions (arg);
+      {
+       int flags = WANT_ARITH | WANT_ENUM;
+       /* Unary plus (but not unary minus) is allowed on pointers.  */
+       if (code == UNARY_PLUS_EXPR)
+         flags |= WANT_POINTER;
+       arg = build_expr_type_conversion (flags, arg, true);
+       if (!arg)
+         errstring = (code == NEGATE_EXPR
+                      ? "wrong type argument to unary minus"
+                      : "wrong type argument to unary plus");
+       else
+         {
+           if (!noconvert && CP_INTEGRAL_TYPE_P (TREE_TYPE (arg)))
+             arg = perform_integral_promotions (arg);
+
+           /* Make sure the result is not a lvalue: a unary plus or minus
+              expression is always a rvalue.  */
+           if (real_lvalue_p (arg))
+             arg = build1 (NON_LVALUE_EXPR, TREE_TYPE (arg), arg);
+         }
+      }
       break;
 
     case BIT_NOT_EXPR:
@@ -3779,7 +3770,10 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
       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));
+       {
+         arg = build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
+         return fold_if_not_in_template (arg);
+       }
       else
        return arg;
 
@@ -3787,7 +3781,10 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
       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));
+       {
+         arg = build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
+         return fold_if_not_in_template (arg);
+       }
       else
        return cp_convert (TREE_TYPE (arg), integer_zero_node);
       
@@ -3860,16 +3857,16 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
            tree type = complete_type (TREE_TYPE (argtype));
            
            if (!COMPLETE_OR_VOID_TYPE_P (type))
-             error ("cannot %s a pointer to incomplete type `%T'",
-                       ((code == PREINCREMENT_EXPR
-                         || code == POSTINCREMENT_EXPR)
-                        ? "increment" : "decrement"), TREE_TYPE (argtype));
+             error ("cannot %s a pointer to incomplete type %qT",
+                     ((code == PREINCREMENT_EXPR
+                       || code == POSTINCREMENT_EXPR)
+                      ? "increment" : "decrement"), TREE_TYPE (argtype));
            else if ((pedantic || warn_pointer_arith)
                     && !TYPE_PTROB_P (argtype))
-             pedwarn ("ISO C++ forbids %sing a pointer of type `%T'",
-                         ((code == PREINCREMENT_EXPR
-                           || code == POSTINCREMENT_EXPR)
-                          ? "increment" : "decrement"), argtype);
+             pedwarn ("ISO C++ forbids %sing a pointer of type %qT",
+                       ((code == PREINCREMENT_EXPR
+                         || code == POSTINCREMENT_EXPR)
+                        ? "increment" : "decrement"), argtype);
            inc = cxx_sizeof_nowarn (TREE_TYPE (argtype));
          }
        else
@@ -3918,7 +3915,7 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
        /* Complain about anything else that is not a true lvalue.  */
        if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
                                    || code == POSTINCREMENT_EXPR)
-                                  ? "increment" : "decrement")))
+                                  ? lv_increment : lv_decrement)))
          return error_mark_node;
 
        /* Forbid using -- on `bool'.  */
@@ -3926,7 +3923,7 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
          {
            if (code == POSTDECREMENT_EXPR || code == PREDECREMENT_EXPR)
              {
-               error ("invalid use of `--' on bool variable `%D'", arg);
+               error ("invalid use of %<--%> on bool variable %qD", arg);
                return error_mark_node;
              }
            val = boolean_increment (code, arg);
@@ -3955,7 +3952,7 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
        }
       else if (pedantic && DECL_MAIN_P (arg))
        /* ARM $3.4 */
-       pedwarn ("ISO C++ forbids taking address of function `::main'");
+       pedwarn ("ISO C++ forbids taking address of function %<::main%>");
 
       /* Let &* cancel out to simplify resulting code.  */
       if (TREE_CODE (arg) == INDIRECT_REF)
@@ -4011,12 +4008,12 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
                /* An expression like &memfn.  */
                pedwarn ("ISO C++ forbids taking the address of an unqualified"
                         " or parenthesized non-static member function to form"
-                        " a pointer to member function.  Say `&%T::%D'",
+                        " a pointer to member function.  Say %<&%T::%D%>",
                         base, name);
              else
                pedwarn ("ISO C++ forbids taking the address of a bound member"
                         " function to form a pointer to member function."
-                        "  Say `&%T::%D'",
+                        "  Say %<&%T::%D%>",
                         base, name);
            }
          arg = build_offset_ref (base, name, /*address_p=*/true);
@@ -4049,6 +4046,29 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
          arg = OVL_CURRENT (arg);
          break;
 
+       case OFFSET_REF:
+         /* Turn a reference to a non-static data member into a
+            pointer-to-member.  */
+         {
+           tree type;
+           tree t;
+
+           if (!PTRMEM_OK_P (arg))
+             return build_unary_op (code, arg, 0);
+           
+           t = TREE_OPERAND (arg, 1);
+           if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
+             {
+               error ("cannot create pointer to reference member %qD", t);
+               return error_mark_node;
+             }
+           
+           type = build_ptrmem_type (context_for_name_lookup (t), 
+                                     TREE_TYPE (t));
+           t = make_ptrmem_cst (type, TREE_OPERAND (arg, 1));
+           return t;
+         }
+
        default:
          break;
        }
@@ -4062,7 +4082,8 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
         is an error.  */
       else if (TREE_CODE (argtype) != FUNCTION_TYPE
               && TREE_CODE (argtype) != METHOD_TYPE
-              && !lvalue_or_else (arg, "unary `&'"))
+              && TREE_CODE (arg) != OFFSET_REF
+              && !lvalue_or_else (arg, lv_addressof))
        return error_mark_node;
 
       if (argtype != error_mark_node)
@@ -4076,7 +4097,11 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
               expression so we can just form an ADDR_EXPR with the
               correct type.  */
            || processing_template_decl)
-         addr = build_address (arg);
+         {
+           addr = build_address (arg);
+           if (TREE_CODE (arg) == OFFSET_REF)
+             PTRMEM_OK_P (addr) = PTRMEM_OK_P (arg);
+         }
        else if (TREE_CODE (TREE_OPERAND (arg, 1)) == BASELINK)
          {
            tree fn = BASELINK_FUNCTIONS (TREE_OPERAND (arg, 1));
@@ -4094,21 +4119,16 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
          }
        else if (DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1)))
          {
-           error ("attempt to take address of bit-field structure member `%D'",
+           error ("attempt to take address of bit-field structure member %qD",
                   TREE_OPERAND (arg, 1));
            return error_mark_node;
          }
        else
          {
+           tree object = TREE_OPERAND (arg, 0);
            tree field = TREE_OPERAND (arg, 1);
-           tree rval = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), 0);
-           tree binfo = lookup_base (TREE_TYPE (TREE_TYPE (rval)),
-                                     decl_type_context (field),
-                                     ba_check, NULL);
-           
-           rval = build_base_path (PLUS_EXPR, rval, binfo, 1);
-
-           TREE_OPERAND (arg, 0) = build_indirect_ref (rval, NULL);
+           gcc_assert (same_type_ignoring_top_level_qualifiers_p
+                       (TREE_TYPE (object), decl_type_context (field)));
            addr = build_address (arg);
          }
 
@@ -4116,7 +4136,8 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
            && TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE)
          {
            build_ptrmemfunc_type (argtype);
-           addr = build_ptrmemfunc (argtype, addr, 0);
+           addr = build_ptrmemfunc (argtype, addr, 0,
+                                    /*c_cast_p=*/false);
          }
 
        return addr;
@@ -4130,7 +4151,7 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
     {
       if (argtype == 0)
        argtype = TREE_TYPE (arg);
-      return fold (build1 (code, argtype, arg));
+      return fold_if_not_in_template (build1 (code, argtype, arg));
     }
 
   error ("%s", errstring);
@@ -4141,11 +4162,18 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
    for certain kinds of expressions which are not really lvalues
    but which we can accept as lvalues.
 
-   If ARG is not a kind of expression we can handle, return zero.  */
+   If ARG is not a kind of expression we can handle, return
+   NULL_TREE.  */
    
 tree
 unary_complex_lvalue (enum tree_code code, tree arg)
 {
+  /* Inside a template, making these kinds of adjustments is
+     pointless; we are only concerned with the type of the
+     expression.  */
+  if (processing_template_decl)
+    return NULL_TREE;
+
   /* Handle (a, b) used as an "lvalue".  */
   if (TREE_CODE (arg) == COMPOUND_EXPR)
     {
@@ -4192,52 +4220,7 @@ unary_complex_lvalue (enum tree_code code, tree arg)
   if (TREE_CODE (TREE_TYPE (arg)) == FUNCTION_TYPE
       || TREE_CODE (TREE_TYPE (arg)) == METHOD_TYPE
       || TREE_CODE (arg) == OFFSET_REF)
-    {
-      tree t;
-
-      gcc_assert (TREE_CODE (arg) != SCOPE_REF);
-
-      if (TREE_CODE (arg) != OFFSET_REF)
-       return 0;
-
-      t = TREE_OPERAND (arg, 1);
-
-      /* Check all this code for right semantics.  */  
-      if (TREE_CODE (t) == FUNCTION_DECL)
-       {
-         if (DECL_DESTRUCTOR_P (t))
-           error ("taking address of destructor");
-         return build_unary_op (ADDR_EXPR, t, 0);
-       }
-      if (TREE_CODE (t) == VAR_DECL)
-       return build_unary_op (ADDR_EXPR, t, 0);
-      else
-       {
-         tree type;
-
-         if (TREE_OPERAND (arg, 0)
-             && ! is_dummy_object (TREE_OPERAND (arg, 0))
-             && TREE_CODE (t) != FIELD_DECL)
-           {
-             error ("taking address of bound pointer-to-member expression");
-             return error_mark_node;
-           }
-         if (!PTRMEM_OK_P (arg))
-           return build_unary_op (code, arg, 0);
-         
-         if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
-           {
-             error ("cannot create pointer to reference member `%D'", t);
-             return error_mark_node;
-           }
-
-         type = build_ptrmem_type (context_for_name_lookup (t), 
-                                   TREE_TYPE (t));
-         t = make_ptrmem_cst (type, TREE_OPERAND (arg, 1));
-         return t;
-       }
-    }
-
+    return NULL_TREE;
   
   /* We permit compiler to make function calls returning
      objects of aggregate type look like lvalues.  */
@@ -4290,7 +4273,7 @@ cxx_mark_addressable (tree exp)
       case PARM_DECL:
        if (x == current_class_ptr)
          {
-            error ("cannot take the address of `this', which is an rvalue expression");
+            error ("cannot take the address of %<this%>, which is an rvalue expression");
            TREE_ADDRESSABLE (x) = 1; /* so compiler doesn't die later.  */
            return true;
          }
@@ -4308,9 +4291,18 @@ cxx_mark_addressable (tree exp)
       case CONST_DECL:
       case RESULT_DECL:
        if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x)
-           && !DECL_ARTIFICIAL (x) && extra_warnings)
-         warning ("address requested for `%D', which is declared `register'",
-                     x);
+           && !DECL_ARTIFICIAL (x))
+         {
+           if (DECL_HARD_REGISTER (x) != 0)
+             {
+               error
+                 ("address of explicit register variable %qD requested", x);
+               return false;
+             }
+           else if (extra_warnings)
+             warning
+               (0, "address requested for %qD, which is declared %<register%>", x);
+         }
        TREE_ADDRESSABLE (x) = 1;
        return true;
 
@@ -4418,7 +4410,6 @@ build_x_compound_expr (tree op1, tree op2)
 tree
 build_compound_expr (tree lhs, tree rhs)
 {
-  lhs = decl_constant_value (lhs);
   lhs = convert_to_void (lhs, "left-hand operand of comma");
   
   if (lhs == error_mark_node || rhs == error_mark_node)
@@ -4440,47 +4431,90 @@ build_compound_expr (tree lhs, tree rhs)
   return build2 (COMPOUND_EXPR, TREE_TYPE (rhs), lhs, rhs);
 }
 
-/* Issue an error message if casting from SRC_TYPE to DEST_TYPE casts
-   away constness.  DESCRIPTION explains what operation is taking
-   place.  */
+/* Issue a diagnostic message if casting from SRC_TYPE to DEST_TYPE
+   casts away constness.  DIAG_FN gives the function to call if we
+   need to issue a diagnostic; if it is NULL, no diagnostic will be
+   issued.  DESCRIPTION explains what operation is taking place.  */
 
 static void
 check_for_casting_away_constness (tree src_type, tree dest_type,
+                                 void (*diag_fn)(const char *, ...),
                                  const char *description)
 {
-  if (casts_away_constness (src_type, dest_type))
-    error ("%s from type `%T' to type `%T' casts away constness",
+  if (diag_fn && casts_away_constness (src_type, dest_type))
+    error ("%s from type %qT to type %qT casts away constness",
           description, src_type, dest_type);
 }
 
-/* Return an expression representing static_cast<TYPE>(EXPR).  */
+/* Convert EXPR (an expression with pointer-to-member type) to TYPE
+   (another pointer-to-member type in the same hierarchy) and return
+   the converted expression.  If ALLOW_INVERSE_P is permitted, a
+   pointer-to-derived may be converted to pointer-to-base; otherwise,
+   only the other direction is permitted.  If C_CAST_P is true, this
+   conversion is taking place as part of a C-style cast.  */
 
-tree
-build_static_cast (tree type, tree expr)
+tree 
+convert_ptrmem (tree type, tree expr, bool allow_inverse_p,
+               bool c_cast_p)
 {
-  tree intype;
-  tree result;
-
-  if (type == error_mark_node || expr == error_mark_node)
-    return error_mark_node;
-
-  if (processing_template_decl)
+  if (TYPE_PTRMEM_P (type))
     {
-      expr = build_min (STATIC_CAST_EXPR, type, expr);
-      /* We don't know if it will or will not have side effects.  */
-      TREE_SIDE_EFFECTS (expr) = 1;
-      return expr;
+      tree delta;
+
+      if (TREE_CODE (expr) == PTRMEM_CST)
+       expr = cplus_expand_constant (expr);
+      delta = get_delta_difference (TYPE_PTRMEM_CLASS_TYPE (TREE_TYPE (expr)),
+                                   TYPE_PTRMEM_CLASS_TYPE (type), 
+                                   allow_inverse_p,
+                                   c_cast_p);
+      if (!integer_zerop (delta))
+       expr = cp_build_binary_op (PLUS_EXPR, 
+                                  build_nop (ptrdiff_type_node, expr),
+                                  delta);
+      return build_nop (type, expr);
     }
+  else
+    return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 
+                            allow_inverse_p, c_cast_p);
+}
 
-  /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
-     Strip such NOP_EXPRs if VALUE is being used in non-lvalue context.  */
-  if (TREE_CODE (type) != REFERENCE_TYPE
-      && TREE_CODE (expr) == NOP_EXPR
-      && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
-    expr = TREE_OPERAND (expr, 0);
+/* Perform a static_cast from EXPR to TYPE.  When C_CAST_P is true,
+   this static_cast is being attempted as one of the possible casts
+   allowed by a C-style cast.  (In that case, accessibility of base
+   classes is not considered, and it is OK to cast away
+   constness.)  Return the result of the cast.  *VALID_P is set to
+   indicate whether or not the cast was valid.  */
+
+static tree
+build_static_cast_1 (tree type, tree expr, bool c_cast_p,
+                    bool *valid_p)
+{
+  tree intype;
+  tree result;
+  tree orig;
+  void (*diag_fn)(const char*, ...);
+  const char *desc;
+
+  /* Assume the cast is valid.  */
+  *valid_p = true;
 
   intype = TREE_TYPE (expr);
 
+  /* Determine what to do when casting away constness.  */
+  if (c_cast_p)
+    {
+      /* C-style casts are allowed to cast away constness.  With
+        WARN_CAST_QUAL, we still want to issue a warning.  */ 
+      diag_fn = warn_cast_qual ? warning0 : NULL;
+      desc = "cast";
+    }
+  else
+    {
+      /* A static_cast may not cast away constness.  */
+      diag_fn = error;
+      desc = "static_cast";
+    }
+      
   /* [expr.static.cast]
 
      An lvalue of type "cv1 B", where B is a class type, can be cast
@@ -4508,12 +4542,20 @@ build_static_cast (tree type, tree expr)
       && can_convert (build_pointer_type (TYPE_MAIN_VARIANT (intype)),
                      build_pointer_type (TYPE_MAIN_VARIANT 
                                          (TREE_TYPE (type))))
-      && at_least_as_qualified_p (TREE_TYPE (type), intype))
+      && (c_cast_p
+         || at_least_as_qualified_p (TREE_TYPE (type), intype)))
     {
+      tree base;
+
       /* There is a standard conversion from "D*" to "B*" even if "B"
-        is ambiguous or inaccessible.  Therefore, we ask lookup_base
-        to check these conditions.  */
-      tree base = lookup_base (TREE_TYPE (type), intype, ba_check, NULL);
+        is ambiguous or inaccessible.  If this is really a
+        static_cast, then we check both for inaccessibility and
+        ambiguity.  However, if this is a static_cast being performed
+        because the user wrote a C-style cast, then accessibility is
+        not considered.  */
+      base = lookup_base (TREE_TYPE (type), intype, 
+                         c_cast_p ? ba_unique : ba_check, 
+                         NULL);
 
       /* Convert from "B*" to "D*".  This function will check that "B"
         is not a virtual base of "D".  */
@@ -4524,16 +4566,28 @@ build_static_cast (tree type, tree expr)
       return convert_from_reference (build_nop (type, expr));
     }
 
+  orig = expr;
+
   /* [expr.static.cast]
 
      An expression e can be explicitly converted to a type T using a
      static_cast of the form static_cast<T>(e) if the declaration T
      t(e);" is well-formed, for some invented temporary variable
      t.  */
-  result = perform_direct_initialization_if_possible (type, expr);
+  result = perform_direct_initialization_if_possible (type, expr,
+                                                     c_cast_p);
   if (result)
     {
       result = convert_from_reference (result);
+
+      /* Ignore any integer overflow caused by the cast.  */
+      if (TREE_CODE (result) == INTEGER_CST
+         && CONSTANT_CLASS_P (orig))
+       {
+         TREE_OVERFLOW (result) = TREE_OVERFLOW (orig);
+         TREE_CONSTANT_OVERFLOW (result)
+           = TREE_CONSTANT_OVERFLOW (orig);
+       }
       /* [expr.static.cast]
 
          If T is a reference type, the result is an lvalue; otherwise,
@@ -4563,17 +4617,28 @@ build_static_cast (tree type, tree expr)
      promotions, floating point promotion, integral conversions,
      floating point conversions, floating-integral conversions,
      pointer conversions, and pointer to member conversions.  */
-  if ((ARITHMETIC_TYPE_P (type) && ARITHMETIC_TYPE_P (intype))
-      /* DR 128
-
-         A value of integral _or enumeration_ type can be explicitly
-        converted to an enumeration type.  */
-      || (INTEGRAL_OR_ENUMERATION_TYPE_P (type)
-         && INTEGRAL_OR_ENUMERATION_TYPE_P (intype)))
-    /* Really, build_c_cast should defer to this function rather
-       than the other way around.  */
-    return build_c_cast (type, expr);
-  
+  /* DR 128
+     
+     A value of integral _or enumeration_ type can be explicitly
+     converted to an enumeration type.  */
+  /* The effect of all that is that any conversion between any two
+     types which are integral, floating, or enumeration types can be
+     performed.  */
+  if ((INTEGRAL_TYPE_P (type) || SCALAR_FLOAT_TYPE_P (type))
+      && (INTEGRAL_TYPE_P (intype) || SCALAR_FLOAT_TYPE_P (intype)))
+    {
+      expr = ocp_convert (type, expr, CONV_C_CAST, LOOKUP_NORMAL);
+
+      /* Ignore any integer overflow caused by the cast.  */
+      if (TREE_CODE (expr) == INTEGER_CST
+         && CONSTANT_CLASS_P (orig))
+       {
+         TREE_OVERFLOW (expr) = TREE_OVERFLOW (orig);
+         TREE_CONSTANT_OVERFLOW (expr) = TREE_CONSTANT_OVERFLOW (orig);
+       }
+      return expr;
+    }
+
   if (TYPE_PTR_P (type) && TYPE_PTR_P (intype)
       && CLASS_TYPE_P (TREE_TYPE (type))
       && CLASS_TYPE_P (TREE_TYPE (intype))
@@ -4584,8 +4649,10 @@ build_static_cast (tree type, tree expr)
     {
       tree base;
 
-      check_for_casting_away_constness (intype, type, "static_cast");
-      base = lookup_base (TREE_TYPE (type), TREE_TYPE (intype), ba_check, 
+      if (!c_cast_p)
+       check_for_casting_away_constness (intype, type, diag_fn, desc);
+      base = lookup_base (TREE_TYPE (type), TREE_TYPE (intype), 
+                         c_cast_p ? ba_unique : ba_check, 
                          NULL);
       return build_base_path (MINUS_EXPR, expr, base, /*nonnull=*/false);
     }
@@ -4617,23 +4684,11 @@ build_static_cast (tree type, tree expr)
        }
       if (can_convert (t1, t2))
        {
-         check_for_casting_away_constness (intype, type, "static_cast");
-         if (TYPE_PTRMEM_P (type))
-           {
-             tree delta;
-
-             if (TREE_CODE (expr) == PTRMEM_CST)
-               expr = cplus_expand_constant (expr);
-             delta = get_delta_difference (c1, c2, /*force=*/1);
-             if (!integer_zerop (delta))
-               expr = cp_build_binary_op (PLUS_EXPR, 
-                                          build_nop (ptrdiff_type_node, expr),
-                                          delta);
-             return build_nop (type, expr);
-           }
-         else
-           return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 
-                                    /*force=*/1);
+         if (!c_cast_p)
+           check_for_casting_away_constness (intype, type, diag_fn, 
+                                             desc);
+         return convert_ptrmem (type, expr, /*allow_inverse_p=*/1,
+                                c_cast_p);
        }
     }
     
@@ -4647,97 +4702,222 @@ build_static_cast (tree type, tree expr)
       && VOID_TYPE_P (TREE_TYPE (intype))
       && TYPE_PTROB_P (type))
     {
-      check_for_casting_away_constness (intype, type, "static_cast");
+      if (!c_cast_p)
+       check_for_casting_away_constness (intype, type, diag_fn, desc);
       return build_nop (type, expr);
     }
 
-  error ("invalid static_cast from type `%T' to type `%T'", intype, type);
+  *valid_p = false;
   return error_mark_node;
 }
 
+/* Return an expression representing static_cast<TYPE>(EXPR).  */
+
 tree
-build_reinterpret_cast (tree type, tree expr)
+build_static_cast (tree type, tree expr)
 {
-  tree intype;
+  tree result;
+  bool valid_p;
 
   if (type == error_mark_node || expr == error_mark_node)
     return error_mark_node;
 
   if (processing_template_decl)
     {
-      tree t = build_min (REINTERPRET_CAST_EXPR, type, expr);
-      
-      if (!TREE_SIDE_EFFECTS (t)
-         && type_dependent_expression_p (expr))
-       /* There might turn out to be side effects inside expr.  */
-       TREE_SIDE_EFFECTS (t) = 1;
-      return t;
+      expr = build_min (STATIC_CAST_EXPR, type, expr);
+      /* We don't know if it will or will not have side effects.  */
+      TREE_SIDE_EFFECTS (expr) = 1;
+      return convert_from_reference (expr);
     }
 
-  if (TREE_CODE (type) != REFERENCE_TYPE)
-    {
-      expr = decay_conversion (expr);
+  /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
+     Strip such NOP_EXPRs if VALUE is being used in non-lvalue context.  */
+  if (TREE_CODE (type) != REFERENCE_TYPE
+      && TREE_CODE (expr) == NOP_EXPR
+      && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
+    expr = TREE_OPERAND (expr, 0);
 
-      /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
-        Strip such NOP_EXPRs if VALUE is being used in non-lvalue context.  */
-      if (TREE_CODE (expr) == NOP_EXPR
-         && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
-       expr = TREE_OPERAND (expr, 0);
+  result = build_static_cast_1 (type, expr, /*c_cast_p=*/false, &valid_p);
+  if (valid_p)
+    return result;
+
+  error ("invalid static_cast from type %qT to type %qT", 
+        TREE_TYPE (expr), type);
+  return error_mark_node;
+}
+
+/* EXPR is an expression with member function or pointer-to-member
+   function type.  TYPE is a pointer type.  Converting EXPR to TYPE is
+   not permitted by ISO C++, but we accept it in some modes.  If we
+   are not in one of those modes, issue a diagnostic.  Return the
+   converted expression.  */
+
+tree
+convert_member_func_to_ptr (tree type, tree expr)
+{
+  tree intype;
+  tree decl;
+
+  intype = TREE_TYPE (expr);
+  gcc_assert (TYPE_PTRMEMFUNC_P (intype)
+             || TREE_CODE (intype) == METHOD_TYPE);
+
+  if (pedantic || warn_pmf2ptr)
+    pedwarn ("converting from %qT to %qT", intype, type);
+    
+  if (TREE_CODE (intype) == METHOD_TYPE)
+    expr = build_addr_func (expr);
+  else if (TREE_CODE (expr) == PTRMEM_CST)
+    expr = build_address (PTRMEM_CST_MEMBER (expr));
+  else
+    {
+      decl = maybe_dummy_object (TYPE_PTRMEM_CLASS_TYPE (intype), 0);
+      decl = build_address (decl);
+      expr = get_member_function_from_ptrfunc (&decl, expr);
     }
 
+  return build_nop (type, expr);
+}
+
+/* Return a representation for a reinterpret_cast from EXPR to TYPE.
+   If C_CAST_P is true, this reinterpret cast is being done as part of
+   a C-style cast.  If VALID_P is non-NULL, *VALID_P is set to
+   indicate whether or not reinterpret_cast was valid.  */
+
+static tree
+build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
+                         bool *valid_p)
+{
+  tree intype;
+
+  /* Assume the cast is invalid.  */
+  if (valid_p)
+    *valid_p = true;
+
+  if (type == error_mark_node || error_operand_p (expr))
+    return error_mark_node;
+
   intype = TREE_TYPE (expr);
 
+  /* [expr.reinterpret.cast]
+     An lvalue expression of type T1 can be cast to the type
+     "reference to T2" if an expression of type "pointer to T1" can be
+     explicitly converted to the type "pointer to T2" using a
+     reinterpret_cast.  */
   if (TREE_CODE (type) == REFERENCE_TYPE)
     {
       if (! real_lvalue_p (expr))
        {
-         error ("invalid reinterpret_cast of an rvalue expression of type `%T' to type `%T'", intype, type);
+         error ("invalid cast of an rvalue expression of type "
+                 "%qT to type %qT", 
+                intype, type);
          return error_mark_node;
        }
+
+      /* Warn about a reinterpret_cast from "A*" to "B&" if "A" and
+        "B" are related class types; the reinterpret_cast does not
+        adjust the pointer.  */
+      if (TYPE_PTR_P (intype)
+         && (comptypes (TREE_TYPE (intype), TREE_TYPE (type),
+                        COMPARE_BASE | COMPARE_DERIVED)))
+       warning (0, "casting %qT to %qT does not dereference pointer",
+                intype, type);
+
       expr = build_unary_op (ADDR_EXPR, expr, 0);
       if (expr != error_mark_node)
-       expr = build_reinterpret_cast
-         (build_pointer_type (TREE_TYPE (type)), expr);
+       expr = build_reinterpret_cast_1
+         (build_pointer_type (TREE_TYPE (type)), expr, c_cast_p,
+          valid_p);
       if (expr != error_mark_node)
        expr = build_indirect_ref (expr, 0);
       return expr;
     }
-  else if (same_type_ignoring_top_level_qualifiers_p (intype, type))
-    return build_static_cast (type, expr);
 
-  if (TYPE_PTR_P (type) && (TREE_CODE (intype) == INTEGER_TYPE
-                           || TREE_CODE (intype) == ENUMERAL_TYPE))
-    /* OK */;
-  else if (TREE_CODE (type) == INTEGER_TYPE && TYPE_PTR_P (intype))
+  /* As a G++ extension, we consider conversions from member
+     functions, and pointers to member functions to
+     pointer-to-function and pointer-to-void types.  If
+     -Wno-pmf-conversions has not been specified,
+     convert_member_func_to_ptr will issue an error message.  */
+  if ((TYPE_PTRMEMFUNC_P (intype) 
+       || TREE_CODE (intype) == METHOD_TYPE)
+      && TYPE_PTR_P (type)
+      && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
+         || VOID_TYPE_P (TREE_TYPE (type))))
+    return convert_member_func_to_ptr (type, expr);
+
+  /* If the cast is not to a reference type, the lvalue-to-rvalue,
+     array-to-pointer, and function-to-pointer conversions are
+     performed.  */
+  expr = decay_conversion (expr);
+  
+  /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
+     Strip such NOP_EXPRs if VALUE is being used in non-lvalue context.  */
+  if (TREE_CODE (expr) == NOP_EXPR
+      && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
+    expr = TREE_OPERAND (expr, 0);
+
+  if (error_operand_p (expr))
+    return error_mark_node;
+
+  intype = TREE_TYPE (expr);
+
+  /* [expr.reinterpret.cast]
+     A pointer can be converted to any integral type large enough to
+     hold it.  */
+  if (CP_INTEGRAL_TYPE_P (type) && TYPE_PTR_P (intype))
     {
       if (TYPE_PRECISION (type) < TYPE_PRECISION (intype))
-       pedwarn ("reinterpret_cast from `%T' to `%T' loses precision",
-                   intype, type);
-    }
+       pedwarn ("cast from %qT to %qT loses precision",
+                 intype, type);
+    }
+  /* [expr.reinterpret.cast]
+     A value of integral or enumeration type can be explicitly
+     converted to a pointer.  */
+  else if (TYPE_PTR_P (type) && INTEGRAL_OR_ENUMERATION_TYPE_P (intype))
+    /* OK */
+    ;
   else if ((TYPE_PTRFN_P (type) && TYPE_PTRFN_P (intype))
           || (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
-    {
-      expr = decl_constant_value (expr);
-      return fold (build1 (NOP_EXPR, type, expr));
-    }
+    return fold_if_not_in_template (build_nop (type, expr));
   else if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
           || (TYPE_PTROBV_P (type) && TYPE_PTROBV_P (intype)))
     {
-      check_for_casting_away_constness (intype, type, "reinterpret_cast");
-      expr = decl_constant_value (expr);
-      return fold (build1 (NOP_EXPR, type, expr));
+      if (!c_cast_p)
+       check_for_casting_away_constness (intype, type, error, 
+                                         "reinterpret_cast");
+      /* Warn about possible alignment problems.  */
+      if (STRICT_ALIGNMENT && warn_cast_align
+         && !VOID_TYPE_P (type)
+         && TREE_CODE (TREE_TYPE (intype)) != FUNCTION_TYPE
+         && COMPLETE_TYPE_P (TREE_TYPE (type))
+         && COMPLETE_TYPE_P (TREE_TYPE (intype))
+         && TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (intype)))
+       warning (0, "cast from %qT to %qT increases required alignment of "
+                "target type",
+                intype, type);
+      
+      return fold_if_not_in_template (build_nop (type, expr));
     }
   else if ((TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype))
           || (TYPE_PTRFN_P (intype) && TYPE_PTROBV_P (type)))
     {
-      pedwarn ("ISO C++ forbids casting between pointer-to-function and pointer-to-object");
-      expr = decl_constant_value (expr);
-      return fold (build1 (NOP_EXPR, type, expr));
-    }
+      if (pedantic)
+       /* Only issue a warning, as we have always supported this
+          where possible, and it is necessary in some cases.  DR 195
+          addresses this issue, but as of 2004/10/26 is still in
+          drafting.  */
+       warning (0, "ISO C++ forbids casting between pointer-to-function and pointer-to-object");
+      return fold_if_not_in_template (build_nop (type, expr));
+    }
+  else if (TREE_CODE (type) == VECTOR_TYPE)
+    return fold_if_not_in_template (convert_to_vector (type, expr));
+  else if (TREE_CODE (intype) == VECTOR_TYPE)
+    return fold_if_not_in_template (convert_to_integer (type, expr));
   else
     {
-      error ("invalid reinterpret_cast from type `%T' to type `%T'",
-                intype, type);
+      if (valid_p)
+       *valid_p = false;
+      error ("invalid cast from type %qT to type %qT", intype, type);
       return error_mark_node;
     }
       
@@ -4745,84 +4925,165 @@ build_reinterpret_cast (tree type, tree expr)
 }
 
 tree
-build_const_cast (tree type, tree expr)
+build_reinterpret_cast (tree type, tree expr)
 {
-  tree intype;
-
   if (type == error_mark_node || expr == error_mark_node)
     return error_mark_node;
 
   if (processing_template_decl)
     {
-      tree t = build_min (CONST_CAST_EXPR, type, expr);
+      tree t = build_min (REINTERPRET_CAST_EXPR, type, expr);
       
       if (!TREE_SIDE_EFFECTS (t)
          && type_dependent_expression_p (expr))
        /* There might turn out to be side effects inside expr.  */
        TREE_SIDE_EFFECTS (t) = 1;
-      return t;
+      return convert_from_reference (t);
     }
 
-  if (!POINTER_TYPE_P (type) && !TYPE_PTRMEM_P (type))
-    error ("invalid use of const_cast with type `%T', which is not a pointer, reference, nor a pointer-to-data-member type", type);
-  else if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
-    {
-      error ("invalid use of const_cast with type `%T', which is a pointer or reference to a function type", type);
+  return build_reinterpret_cast_1 (type, expr, /*c_cast_p=*/false,
+                                  /*valid_p=*/NULL);
+}
+
+/* Perform a const_cast from EXPR to TYPE.  If the cast is valid,
+   return an appropriate expression.  Otherwise, return
+   error_mark_node.  If the cast is not valid, and COMPLAIN is true,
+   then a diagnostic will be issued.  If VALID_P is non-NULL, its
+   value upon return will indicate whether or not the conversion
+   succeeded.  */
+
+static tree
+build_const_cast_1 (tree dst_type, tree expr, bool complain,
+                   bool *valid_p)
+{
+  tree src_type;
+  tree reference_type;
+
+  /* Callers are responsible for handling error_mark_node as a
+     destination type.  */
+  gcc_assert (dst_type != error_mark_node);
+  /* In a template, callers should be building syntactic
+     representations of casts, not using this machinery.  */
+  gcc_assert (!processing_template_decl);
+
+  /* Assume the conversion is invalid.  */
+  if (valid_p)
+    *valid_p = false;
+
+  if (!POINTER_TYPE_P (dst_type) && !TYPE_PTRMEM_P (dst_type))
+    {
+      if (complain)
+       error ("invalid use of const_cast with type %qT, "
+              "which is not a pointer, "
+              "reference, nor a pointer-to-data-member type", dst_type);
       return error_mark_node;
     }
 
-  if (TREE_CODE (type) != REFERENCE_TYPE)
+  if (TREE_CODE (TREE_TYPE (dst_type)) == FUNCTION_TYPE)
     {
-      expr = decay_conversion (expr);
-
-      /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
-        Strip such NOP_EXPRs if VALUE is being used in non-lvalue context.  */
-      if (TREE_CODE (expr) == NOP_EXPR
-         && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
-       expr = TREE_OPERAND (expr, 0);
+      if (complain)
+       error ("invalid use of const_cast with type %qT, which is a pointer "
+              "or reference to a function type", dst_type);
+      return error_mark_node;
     }
 
-  intype = TREE_TYPE (expr);
-  
-  if (same_type_ignoring_top_level_qualifiers_p (intype, type))
-    return build_static_cast (type, expr);
-  else if (TREE_CODE (type) == REFERENCE_TYPE)
+  src_type = TREE_TYPE (expr);
+  /* Expressions do not really have reference types.  */
+  if (TREE_CODE (src_type) == REFERENCE_TYPE)
+    src_type = TREE_TYPE (src_type);
+
+  /* [expr.const.cast]
+
+     An lvalue of type T1 can be explicitly converted to an lvalue of
+     type T2 using the cast const_cast<T2&> (where T1 and T2 are object
+     types) if a pointer to T1 can be explicitly converted to the type
+     pointer to T2 using a const_cast.  */
+  if (TREE_CODE (dst_type) == REFERENCE_TYPE)
     {
+      reference_type = dst_type;
       if (! real_lvalue_p (expr))
        {
-         error ("invalid const_cast of an rvalue of type `%T' to type `%T'", intype, type);
+         if (complain)
+           error ("invalid const_cast of an rvalue of type %qT to type %qT",
+                  src_type, dst_type);
          return error_mark_node;
        }
+      dst_type = build_pointer_type (TREE_TYPE (dst_type));
+      src_type = build_pointer_type (src_type);
+    }
+  else
+    {
+      reference_type = NULL_TREE;
+      /* If the destination type is not a reference type, the
+        lvalue-to-rvalue, array-to-pointer, and function-to-pointer
+        conversions are performed.  */
+      src_type = type_decays_to (src_type);
+      if (src_type == error_mark_node)
+       return error_mark_node;
+    }
 
-      if (comp_ptr_ttypes_const (TREE_TYPE (type), intype))
+  if ((TYPE_PTR_P (src_type) || TYPE_PTRMEM_P (src_type))
+      && comp_ptr_ttypes_const (dst_type, src_type))
+    {
+      if (valid_p)
+       *valid_p = true;
+      if (reference_type)
        {
          expr = build_unary_op (ADDR_EXPR, expr, 0);
-         expr = build1 (NOP_EXPR, type, expr);
+         expr = build_nop (reference_type, expr);
          return convert_from_reference (expr);
        }
+      else
+       {
+         expr = decay_conversion (expr);
+         /* build_c_cast puts on a NOP_EXPR to make the result not an
+            lvalue.  Strip such NOP_EXPRs if VALUE is being used in
+            non-lvalue context.  */
+         if (TREE_CODE (expr) == NOP_EXPR
+             && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
+           expr = TREE_OPERAND (expr, 0);
+         return build_nop (dst_type, expr);
+       }
     }
-  else if (((TREE_CODE (type) == POINTER_TYPE
-            && TREE_CODE (intype) == POINTER_TYPE)
-           || (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype)))
-          && comp_ptr_ttypes_const (TREE_TYPE (type), TREE_TYPE (intype)))
-    return cp_convert (type, expr);
 
-  error ("invalid const_cast from type `%T' to type `%T'", intype, type);
+  if (complain)
+    error ("invalid const_cast from type %qT to type %qT", 
+          src_type, dst_type);
   return error_mark_node;
 }
 
-/* Build an expression representing a cast to type TYPE of expression EXPR.
+tree
+build_const_cast (tree type, tree expr)
+{
+  if (type == error_mark_node || error_operand_p (expr))
+    return error_mark_node;
 
-   ALLOW_NONCONVERTING is true if we should allow non-converting constructors
-   when doing the cast.  */
+  if (processing_template_decl)
+    {
+      tree t = build_min (CONST_CAST_EXPR, type, expr);
+      
+      if (!TREE_SIDE_EFFECTS (t)
+         && type_dependent_expression_p (expr))
+       /* There might turn out to be side effects inside expr.  */
+       TREE_SIDE_EFFECTS (t) = 1;
+      return convert_from_reference (t);
+    }
+
+  return build_const_cast_1 (type, expr, /*complain=*/true,
+                            /*valid_p=*/NULL);
+}
+
+/* Build an expression representing an explicit C-style cast to type
+   TYPE of expression EXPR.  */
 
 tree
 build_c_cast (tree type, tree expr)
 {
   tree value = expr;
-  tree otype;
+  tree result;
+  bool valid_p;
 
-  if (type == error_mark_node || expr == error_mark_node)
+  if (type == error_mark_node || error_operand_p (expr))
     return error_mark_node;
 
   if (processing_template_decl)
@@ -4831,7 +5092,7 @@ build_c_cast (tree type, tree expr)
                          tree_cons (NULL_TREE, value, NULL_TREE));
       /* We don't know if it will or will not have side effects.  */
       TREE_SIDE_EFFECTS (t) = 1;
-      return t;
+      return convert_from_reference (t);
     }
 
   /* Casts to a (pointer to a) specific ObjC class (or 'id' or
@@ -4854,12 +5115,12 @@ build_c_cast (tree type, tree expr)
         NIHCL uses it. It is not valid ISO C++ however.  */
       if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE)
        {
-         pedwarn ("ISO C++ forbids casting to an array type `%T'", type);
+         pedwarn ("ISO C++ forbids casting to an array type %qT", type);
          type = build_pointer_type (TREE_TYPE (type));
        }
       else
        {
-         error ("ISO C++ forbids casting to an array type `%T'", type);
+         error ("ISO C++ forbids casting to an array type %qT", type);
          return error_mark_node;
        }
     }
@@ -4867,120 +5128,52 @@ build_c_cast (tree type, tree expr)
   if (TREE_CODE (type) == FUNCTION_TYPE
       || TREE_CODE (type) == METHOD_TYPE)
     {
-      error ("invalid cast to function type `%T'", type);
+      error ("invalid cast to function type %qT", type);
       return error_mark_node;
     }
 
-  if (TREE_CODE (type) == VOID_TYPE)
-    {
-      /* Conversion to void does not cause any of the normal function to
-       * pointer, array to pointer and lvalue to rvalue decays.  */
-      
-      value = convert_to_void (value, /*implicit=*/NULL);
-      return value;
-    }
-
-  if (!complete_type_or_else (type, NULL_TREE))
-    return error_mark_node;
-
-  /* Convert functions and arrays to pointers and
-     convert references to their expanded types,
-     but don't convert any other types.  If, however, we are
-     casting to a class type, there's no reason to do this: the
-     cast will only succeed if there is a converting constructor,
-     and the default conversions will be done at that point.  In
-     fact, doing the default conversion here is actually harmful
-     in cases like this:
-
-     typedef int A[2];
-     struct S { S(const A&); };
-
-     since we don't want the array-to-pointer conversion done.  */
-  if (!IS_AGGR_TYPE (type))
-    {
-      if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE
-         || (TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE
-             /* Don't do the default conversion on a ->* expression.  */
-             && ! (TREE_CODE (type) == POINTER_TYPE
-                   && bound_pmf_p (value)))
-         || TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
-         || TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE)
-       value = decay_conversion (value);
-    }
-  else if (TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE)
-    /* However, even for class types, we still need to strip away
-       the reference type, since the call to convert_force below
-       does not expect the input expression to be of reference
-       type.  */
-    value = convert_from_reference (value);
-       
-  otype = TREE_TYPE (value);
-
-  /* Optionally warn about potentially worrisome casts.  */
-
-  if (warn_cast_qual
-      && TREE_CODE (type) == POINTER_TYPE
-      && TREE_CODE (otype) == POINTER_TYPE
-      && !at_least_as_qualified_p (TREE_TYPE (type),
-                                  TREE_TYPE (otype)))
-    warning ("cast from `%T' to `%T' discards qualifiers from pointer target type",
-                otype, type);
-
-  if (TREE_CODE (type) == INTEGER_TYPE
-      && TYPE_PTR_P (otype)
-      && TYPE_PRECISION (type) != TYPE_PRECISION (otype))
-    warning ("cast from pointer to integer of different size");
-
-  if (TYPE_PTR_P (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");
+  /* A C-style cast can be a const_cast.  */
+  result = build_const_cast_1 (type, value, /*complain=*/false,
+                              &valid_p);
+  if (valid_p)
+    return result;
 
-  if (TREE_CODE (type) == REFERENCE_TYPE)
-    value = (convert_from_reference
-            (convert_to_reference (type, value, CONV_C_CAST,
-                                   LOOKUP_COMPLAIN, NULL_TREE)));
-  else
+  /* Or a static cast.  */
+  result = build_static_cast_1 (type, value, /*c_cast_p=*/true,
+                               &valid_p);
+  /* Or a reinterpret_cast.  */
+  if (!valid_p)
+    result = build_reinterpret_cast_1 (type, value, /*c_cast_p=*/true,
+                                      &valid_p);
+  /* The static_cast or reinterpret_cast may be followed by a
+     const_cast.  */
+  if (valid_p 
+      /* A valid cast may result in errors if, for example, a
+        conversion to am ambiguous base class is required.  */
+      && !error_operand_p (result))
     {
-      tree ovalue;
-
-      value = decl_constant_value (value);
-
-      ovalue = value;
-      value = convert_force (type, value, CONV_C_CAST);
+      tree result_type;
 
-      /* Ignore any integer overflow caused by the cast.  */
-      if (TREE_CODE (value) == INTEGER_CST)
+      /* Non-class rvalues always have cv-unqualified type.  */
+      if (!CLASS_TYPE_P (type))
+       type = TYPE_MAIN_VARIANT (type);
+      result_type = TREE_TYPE (result);
+      if (!CLASS_TYPE_P (result_type))
+       result_type = TYPE_MAIN_VARIANT (result_type);
+      /* If the type of RESULT does not match TYPE, perform a
+        const_cast to make it match.  If the static_cast or
+        reinterpret_cast succeeded, we will differ by at most
+        cv-qualification, so the follow-on const_cast is guaranteed
+        to succeed.  */
+      if (!same_type_p (non_reference (type), non_reference (result_type)))
        {
-         TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue);
-
-         if (TREE_CODE_CLASS (TREE_CODE (ovalue)) == 'c')
-           TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_OVERFLOW (ovalue);
+         result = build_const_cast_1 (type, result, false, &valid_p);
+         gcc_assert (valid_p);
        }
+      return result;
     }
 
-  /* Warn about possible alignment problems.  Do this here when we will have
-     instantiated any necessary template types.  */
-  if (STRICT_ALIGNMENT && warn_cast_align
-      && TREE_CODE (type) == POINTER_TYPE
-      && TREE_CODE (otype) == POINTER_TYPE
-      && TREE_CODE (TREE_TYPE (otype)) != VOID_TYPE
-      && TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE
-      && COMPLETE_TYPE_P (TREE_TYPE (otype))
-      && COMPLETE_TYPE_P (TREE_TYPE (type))
-      && TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (otype)))
-    warning ("cast from `%T' to `%T' increases required alignment of target type",
-                otype, type);
-
-    /* Always produce some operator for an explicit cast,
-       so we can tell (for -pedantic) that the cast is no lvalue.  */
-  if (TREE_CODE (type) != REFERENCE_TYPE && value == expr
-      && real_lvalue_p (value))
-    value = non_lvalue (value);
-
-  return value;
+  return error_mark_node;
 }
 \f
 /* Build an assignment expression of lvalue LHS from value RHS.
@@ -5038,6 +5231,25 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
        return error_mark_node;
       return build2 (COMPOUND_EXPR, lhstype, lhs, newrhs);
 
+    case MIN_EXPR:
+    case MAX_EXPR:
+      /* MIN_EXPR and MAX_EXPR are currently only permitted as lvalues,
+        when neither operand has side-effects.  */
+      if (!lvalue_or_else (lhs, lv_assign))
+       return error_mark_node;
+
+      gcc_assert (!TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0))
+                 && !TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 1)));
+
+      lhs = build3 (COND_EXPR, TREE_TYPE (lhs),
+                   build2 (TREE_CODE (lhs) == MIN_EXPR ? LE_EXPR : GE_EXPR,
+                           boolean_type_node,
+                           TREE_OPERAND (lhs, 0),
+                           TREE_OPERAND (lhs, 1)),
+                   TREE_OPERAND (lhs, 0),
+                   TREE_OPERAND (lhs, 1));
+      /* Fall through.  */
+
       /* Handle (a ? b : c) used as an "lvalue".  */
     case COND_EXPR:
       {
@@ -5051,7 +5263,7 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
        
        /* Check this here to avoid odd errors when trying to convert
           a throw to the type of the COND_EXPR.  */
-       if (!lvalue_or_else (lhs, "assignment"))
+       if (!lvalue_or_else (lhs, lv_assign))
          return error_mark_node;
 
        cond = build_conditional_expr
@@ -5101,11 +5313,6 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
     }
   else
     {
-      if (TREE_CODE (lhstype) == REFERENCE_TYPE)
-       {
-         lhs = convert_from_reference (lhs);
-         olhstype = lhstype = TREE_TYPE (lhs);
-       }
       lhs = require_complete_type (lhs);
       if (lhs == error_mark_node)
        return error_mark_node;
@@ -5137,7 +5344,7 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
          newrhs = cp_build_binary_op (modifycode, lhs, rhs);
          if (newrhs == error_mark_node)
            {
-             error ("  in evaluation of `%Q(%#T, %#T)'", modifycode,
+             error ("  in evaluation of %<%Q(%#T, %#T)%>", modifycode,
                     TREE_TYPE (lhs), TREE_TYPE (rhs));
              return error_mark_node;
            }
@@ -5150,7 +5357,7 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
     }
 
   /* The left-hand side must be an lvalue.  */
-  if (!lvalue_or_else (lhs, "assignment"))
+  if (!lvalue_or_else (lhs, lv_assign))
     return error_mark_node;
 
   /* Warn about modifying something that is `const'.  Don't warn if
@@ -5206,7 +5413,7 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
       if (!same_or_base_type_p (TYPE_MAIN_VARIANT (lhstype),
                                TYPE_MAIN_VARIANT (TREE_TYPE (rhs))))
        {
-         error ("incompatible types in assignment of `%T' to `%T'",
+         error ("incompatible types in assignment of %qT to %qT",
                 TREE_TYPE (rhs), lhstype);
          return error_mark_node;
        }
@@ -5252,6 +5459,14 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
   if (newrhs == error_mark_node)
     return error_mark_node;
 
+  if (c_dialect_objc () && flag_objc_gc)
+    {
+      result = objc_generate_write_barrier (lhs, modifycode, newrhs);
+
+      if (result)
+       return result;
+    }
+
   result = build2 (modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR,
                   lhstype, lhs, newrhs);
 
@@ -5300,8 +5515,10 @@ build_x_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
 \f
 /* Get difference in deltas for different pointer to member function
    types.  Returns an integer constant of type PTRDIFF_TYPE_NODE.  If
-   the conversion is invalid, the constant is zero.  If FORCE is true,
-   then allow reverse conversions as well.
+   the conversion is invalid, the constant is zero.  If
+   ALLOW_INVERSE_P is true, then allow reverse conversions as well.
+   If C_CAST_P is true this conversion is taking place as part of a
+   C-style cast.
 
    Note that the naming of FROM and TO is kind of backwards; the return
    value is what we add to a TO in order to get a FROM.  They are named
@@ -5309,58 +5526,63 @@ build_x_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
    a pointer to member of FROM to a pointer to member of TO.  */
 
 static tree
-get_delta_difference (tree from, tree to, int force)
+get_delta_difference (tree from, tree to, 
+                     bool allow_inverse_p,
+                     bool c_cast_p)
 {
   tree binfo;
-  tree virt_binfo;
   base_kind kind;
   tree result;
 
   /* Assume no conversion is required.  */
   result = integer_zero_node;
-  binfo = lookup_base (to, from, ba_check, &kind);
+  binfo = lookup_base (to, from, c_cast_p ? ba_unique : ba_check, &kind);
   if (kind == bk_inaccessible || kind == bk_ambig)
     error ("   in pointer to member function conversion");
-  else if (!binfo)
+  else if (binfo)
     {
-      if (!force)
-       {
-         error_not_base_type (from, to);
-         error ("   in pointer to member conversion");
-       }
+      if (kind != bk_via_virtual)
+       result = BINFO_OFFSET (binfo);
       else
        {
-         binfo = lookup_base (from, to, ba_check, &kind);
-         if (binfo)
-           {
-             virt_binfo = binfo_from_vbase (binfo);
-             if (virt_binfo)
-               /* This is a reinterpret cast, we choose to do nothing.  */
-               warning ("pointer to member cast via virtual base `%T'",
-                        BINFO_TYPE (virt_binfo));
-             else
-               result = size_diffop (size_zero_node, BINFO_OFFSET (binfo));
-           }
+         tree virt_binfo = binfo_from_vbase (binfo);
+         
+         /* This is a reinterpret cast, we choose to do nothing.  */
+         if (allow_inverse_p)
+           warning (0, "pointer to member cast via virtual base %qT",
+                    BINFO_TYPE (virt_binfo));
+         else
+           error ("pointer to member conversion via virtual base %qT",
+                  BINFO_TYPE (virt_binfo));
        }
     }
+  else if (same_type_ignoring_top_level_qualifiers_p (from, to))
+    /* Pointer to member of incomplete class is permitted*/;
+  else if (!allow_inverse_p)
+    {
+      error_not_base_type (from, to);
+      error ("   in pointer to member conversion");
+    }
   else
     {
-      virt_binfo = binfo_from_vbase (binfo);
-      if (!virt_binfo)
-       result = BINFO_OFFSET (binfo);
-      else
+      binfo = lookup_base (from, to, c_cast_p ? ba_unique : ba_check, &kind);
+      if (binfo)
        {
-         /* This is a reinterpret cast, we choose to do nothing.  */
-         if (force)
-           warning ("pointer to member cast via virtual base `%T'",
-                    BINFO_TYPE (virt_binfo));
+         if (kind != bk_via_virtual)
+           result = size_diffop (size_zero_node, BINFO_OFFSET (binfo));
          else
-           error ("pointer to member conversion via virtual base `%T'",
-                  BINFO_TYPE (virt_binfo));
+           {
+             /* This is a reinterpret cast, we choose to do nothing.  */
+             tree virt_binfo = binfo_from_vbase (binfo);
+         
+             warning (0, "pointer to member cast via virtual base %qT",
+                      BINFO_TYPE (virt_binfo));
+           }
        }
     }
 
-  return fold (convert_to_integer (ptrdiff_type_node, result));
+  return fold_if_not_in_template (convert_to_integer (ptrdiff_type_node, 
+                                                     result));
 }
 
 /* Return a constructor for the pointer-to-member-function TYPE using
@@ -5401,12 +5623,12 @@ build_ptrmemfunc1 (tree type, tree delta, tree pfn)
 
    If FORCE is nonzero, then force this conversion, even if
    we would rather not do it.  Usually set when using an explicit
-   cast.
+   cast.  A C-style cast is being processed iff C_CAST_P is true.
 
    Return error_mark_node, if something goes wrong.  */
 
 tree
-build_ptrmemfunc (tree type, tree pfn, int force)
+build_ptrmemfunc (tree type, tree pfn, int force, bool c_cast_p)
 {
   tree fn;
   tree pfn_type;
@@ -5427,12 +5649,13 @@ build_ptrmemfunc (tree type, tree pfn, int force)
 
       if (!force 
          && !can_convert_arg (to_type, TREE_TYPE (pfn), pfn))
-       error ("invalid conversion to type `%T' from type `%T'", 
-                 to_type, pfn_type);
+       error ("invalid conversion to type %qT from type %qT", 
+               to_type, pfn_type);
 
       n = get_delta_difference (TYPE_PTRMEMFUNC_OBJECT_TYPE (pfn_type),
                                TYPE_PTRMEMFUNC_OBJECT_TYPE (to_type),
-                               force);
+                               force,
+                               c_cast_p);
 
       /* We don't have to do any conversion to convert a
         pointer-to-member to its own type.  But, we don't want to
@@ -5480,7 +5703,10 @@ build_ptrmemfunc (tree type, tree pfn, int force)
     return instantiate_type (type, pfn, tf_error | tf_warning);
 
   fn = TREE_OPERAND (pfn, 0);
-  gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
+  gcc_assert (TREE_CODE (fn) == FUNCTION_DECL
+             /* In a template, we will have preserved the
+                OFFSET_REF.  */
+             || (processing_template_decl && TREE_CODE (fn) == OFFSET_REF));
   return make_ptrmem_cst (to_type, fn);
 }
 
@@ -5507,7 +5733,8 @@ expand_ptrmemfunc_cst (tree cst, tree *delta, tree *pfn)
   ptr_class = TYPE_PTRMEMFUNC_OBJECT_TYPE (type);
 
   /* First, calculate the adjustment to the function's class.  */
-  *delta = get_delta_difference (fn_class, ptr_class, /*force=*/0);
+  *delta = get_delta_difference (fn_class, ptr_class, /*force=*/0,
+                                /*c_cast_p=*/0);
 
   if (!DECL_VIRTUAL_P (fn))
     *pfn = convert (TYPE_PTRMEMFUNC_FN_TYPE (type), build_addr_func (fn));
@@ -5518,36 +5745,41 @@ expand_ptrmemfunc_cst (tree cst, tree *delta, tree *pfn)
          fn; the call will do the opposite adjustment.  */
       tree orig_class = DECL_CONTEXT (fn);
       tree binfo = binfo_or_else (orig_class, fn_class);
-      *delta = fold (build2 (PLUS_EXPR, TREE_TYPE (*delta),
-                            *delta, BINFO_OFFSET (binfo)));
+      *delta = build2 (PLUS_EXPR, TREE_TYPE (*delta),
+                      *delta, BINFO_OFFSET (binfo));
+      *delta = fold_if_not_in_template (*delta);
 
       /* We set PFN to the vtable offset at which the function can be
         found, plus one (unless ptrmemfunc_vbit_in_delta, in which
         case delta is shifted left, and then incremented).  */
       *pfn = DECL_VINDEX (fn);
-      *pfn = fold (build2 (MULT_EXPR, integer_type_node, *pfn,
-                          TYPE_SIZE_UNIT (vtable_entry_type)));
+      *pfn = build2 (MULT_EXPR, integer_type_node, *pfn,
+                    TYPE_SIZE_UNIT (vtable_entry_type));
+      *pfn = fold_if_not_in_template (*pfn);
 
       switch (TARGET_PTRMEMFUNC_VBIT_LOCATION)
        {
        case ptrmemfunc_vbit_in_pfn:
-         *pfn = fold (build2 (PLUS_EXPR, integer_type_node, *pfn,
-                              integer_one_node));
+         *pfn = build2 (PLUS_EXPR, integer_type_node, *pfn,
+                        integer_one_node);
+         *pfn = fold_if_not_in_template (*pfn);
          break;
 
        case ptrmemfunc_vbit_in_delta:
-         *delta = fold (build2 (LSHIFT_EXPR, TREE_TYPE (*delta),
-                                *delta, integer_one_node));
-         *delta = fold (build2 (PLUS_EXPR, TREE_TYPE (*delta),
-                                *delta, integer_one_node));
+         *delta = build2 (LSHIFT_EXPR, TREE_TYPE (*delta),
+                          *delta, integer_one_node);
+         *delta = fold_if_not_in_template (*delta);
+         *delta = build2 (PLUS_EXPR, TREE_TYPE (*delta),
+                          *delta, integer_one_node);
+         *delta = fold_if_not_in_template (*delta);
          break;
 
        default:
          gcc_unreachable ();
        }
 
-      *pfn = fold (build1 (NOP_EXPR, TYPE_PTRMEMFUNC_FN_TYPE (type),
-                          *pfn));
+      *pfn = build_nop (TYPE_PTRMEMFUNC_FN_TYPE (type), *pfn);
+      *pfn = fold_if_not_in_template (*pfn);
     }
 }
 
@@ -5570,58 +5802,6 @@ pfn_from_ptrmemfunc (tree t)
   return build_ptrmemfunc_access_expr (t, pfn_identifier);
 }
 
-/* Expression EXPR is about to be implicitly converted to TYPE.  Warn
-   if this is a potentially dangerous thing to do.  Returns a possibly
-   marked EXPR.  */
-
-tree
-dubious_conversion_warnings (tree type, tree expr,
-                            const char *errtype, tree fndecl, int parmnum)
-{
-  type = non_reference (type);
-  
-  /* Issue warnings about peculiar, but valid, uses of NULL.  */
-  if (ARITHMETIC_TYPE_P (type) && expr == null_node)
-    {
-      if (fndecl)
-        warning ("passing NULL used for non-pointer %s %P of `%D'",
-                    errtype, parmnum, fndecl);
-      else
-        warning ("%s to non-pointer type `%T' from NULL", errtype, type);
-    }
-  
-  /* Warn about assigning a floating-point type to an integer type.  */
-  if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE
-      && TREE_CODE (type) == INTEGER_TYPE)
-    {
-      if (fndecl)
-       warning ("passing `%T' for %s %P of `%D'",
-                   TREE_TYPE (expr), errtype, parmnum, fndecl);
-      else
-       warning ("%s to `%T' from `%T'", errtype, type, TREE_TYPE (expr));
-    }
-  /* And warn about assigning a negative value to an unsigned
-     variable.  */
-  else if (TYPE_UNSIGNED (type) && TREE_CODE (type) != BOOLEAN_TYPE)
-    {
-      if (TREE_CODE (expr) == INTEGER_CST && TREE_NEGATED_INT (expr))
-       {
-         if (fndecl)
-           warning ("passing negative value `%E' for %s %P of `%D'",
-                       expr, errtype, parmnum, fndecl);
-         else
-           warning ("%s of negative value `%E' to `%T'",
-                       errtype, expr, type);
-       }
-
-      overflow_warning (expr);
-
-      if (TREE_CONSTANT (expr))
-       expr = fold (expr);
-    }
-  return expr;
-}
-
 /* Convert value RHS to type TYPE as preparation for an assignment to
    an lvalue of type TYPE.  ERRTYPE is a string to use in error
    messages: "assignment", "return", etc.  If FNDECL is non-NULL, we
@@ -5661,16 +5841,32 @@ convert_for_assignment (tree type, tree rhs,
   /* Simplify the RHS if possible.  */
   if (TREE_CODE (rhs) == CONST_DECL)
     rhs = DECL_INITIAL (rhs);
-  
-  /* We do not use decl_constant_value here because of this case:
 
-       const char* const s = "s";
-     The conversion rules for a string literal are more lax than for a
-     variable; in particular, a string literal can be converted to a
-     "char *" but the variable "s" cannot be converted in the same
-     way.  If the conversion is allowed, the optimization should be
-     performed while creating the converted expression.  */
+  if (c_dialect_objc ())
+    {
+      int parmno;
+      tree rname = fndecl;
+
+      if (!strcmp (errtype, "assignment"))
+       parmno = -1;
+      else if (!strcmp (errtype, "initialization"))
+       parmno = -2;
+      else
+       {
+         tree selector = objc_message_selector ();
+
+         parmno = parmnum;
+
+         if (selector && parmno > 1)
+           {
+             rname = selector;
+             parmno -= 1;
+           }
+       }
+
+      if (objc_compare_types (type, rhstype, parmno, rname))
+       return convert (type, rhs);
+    }
 
   /* [expr.ass]
 
@@ -5697,11 +5893,10 @@ convert_for_assignment (tree type, tree rhs,
          if (rhstype == unknown_type_node)
            instantiate_type (type, rhs, tf_error | tf_warning);
          else if (fndecl)
-           error ("cannot convert `%T' to `%T' for argument `%P' to `%D'",
-                     rhstype, type, parmnum, fndecl);
+           error ("cannot convert %qT to %qT for argument %qP to %qD",
+                   rhstype, type, parmnum, fndecl);
          else
-           error ("cannot convert `%T' to `%T' in %s", rhstype, type, 
-                     errtype);
+           error ("cannot convert %qT to %qT in %s", rhstype, type, errtype);
          return error_mark_node;
        }
     }
@@ -5743,9 +5938,6 @@ convert_for_initialization (tree exp, tree type, tree rhs, int flags,
       || (TREE_CODE (rhs) == TREE_LIST && TREE_VALUE (rhs) == error_mark_node))
     return error_mark_node;
 
-  if (TREE_CODE (TREE_TYPE (rhs)) == REFERENCE_TYPE)
-    rhs = convert_from_reference (rhs);
-
   if ((TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE
        && TREE_CODE (type) != ARRAY_TYPE
        && (TREE_CODE (type) != REFERENCE_TYPE
@@ -5777,9 +5969,9 @@ convert_for_initialization (tree exp, tree type, tree rhs, int flags,
       if (fndecl)
        {
          if (warningcount > savew)
-           cp_warning_at ("in passing argument %P of `%+D'", parmnum, fndecl);
+           cp_warning_at ("in passing argument %P of %q+D", parmnum, fndecl);
          else if (errorcount > savee)
-           cp_error_at ("in passing argument %P of `%+D'", parmnum, fndecl);
+           cp_error_at ("in passing argument %P of %q+D", parmnum, fndecl);
        }
       return rhs;
     }      
@@ -5829,14 +6021,14 @@ maybe_warn_about_returning_address_of_local (tree retval)
       if (TREE_CODE (whats_returned) == AGGR_INIT_EXPR
          || TREE_CODE (whats_returned) == TARGET_EXPR)
        {
-         warning ("returning reference to temporary");
+         warning (0, "returning reference to temporary");
          return;
        }
       if (TREE_CODE (whats_returned) == VAR_DECL 
          && DECL_NAME (whats_returned)
          && TEMP_NAME_P (DECL_NAME (whats_returned)))
        {
-         warning ("reference to non-lvalue returned");
+         warning (0, "reference to non-lvalue returned");
          return;
        }
     }
@@ -5848,10 +6040,10 @@ maybe_warn_about_returning_address_of_local (tree retval)
           || TREE_PUBLIC (whats_returned)))
     {
       if (TREE_CODE (valtype) == REFERENCE_TYPE)
-       cp_warning_at ("reference to local variable `%D' returned", 
+       cp_warning_at ("reference to local variable %qD returned", 
                       whats_returned);
       else
-       cp_warning_at ("address of local variable `%D' returned", 
+       cp_warning_at ("address of local variable %qD returned", 
                       whats_returned);
       return;
     }
@@ -5875,7 +6067,7 @@ check_return_expr (tree retval)
      (This is a G++ extension, used to get better code for functions
      that call the `volatile' function.)  */
   if (TREE_THIS_VOLATILE (current_function_decl))
-    warning ("function declared `noreturn' has a `return' statement");
+    warning (0, "function declared %<noreturn%> has a %<return%> statement");
 
   /* Check for various simple errors.  */
   if (DECL_DESTRUCTOR_P (current_function_decl))
@@ -5915,7 +6107,7 @@ check_return_expr (tree retval)
      that's supposed to return a value.  */
   if (!retval && fn_returns_value_p)
     {
-      pedwarn ("return-statement with no value, in function returning '%T'",
+      pedwarn ("return-statement with no value, in function returning %qT",
               valtype);
       /* Clear this, so finish_function won't say that we reach the
         end of a non-void function (which we don't, we gave a
@@ -5948,13 +6140,23 @@ check_return_expr (tree retval)
     /* Remember that this function did return a value.  */
     current_function_returns_value = 1;
 
+  /* Check for erroneous operands -- but after giving ourselves a
+     chance to provide an error about returning a value from a void
+     function.  */
+  if (error_operand_p (retval))
+    {
+      current_function_return_value = error_mark_node;
+      return error_mark_node;
+    }
+
   /* Only operator new(...) throw(), can return NULL [expr.new/13].  */
   if ((DECL_OVERLOADED_OPERATOR_P (current_function_decl) == NEW_EXPR
        || DECL_OVERLOADED_OPERATOR_P (current_function_decl) == VEC_NEW_EXPR)
       && !TYPE_NOTHROW_P (TREE_TYPE (current_function_decl))
       && ! flag_check_new
       && null_ptr_cst_p (retval))
-    warning ("`operator new' must not return NULL unless it is declared `throw()' (or -fcheck-new is in effect)");
+    warning (0, "%<operator new%> must not return NULL unless it is "
+             "declared %<throw()%> (or -fcheck-new is in effect)");
 
   /* Effective C++ rule 15.  See also start_function.  */
   if (warn_ecpp
@@ -5979,7 +6181,7 @@ check_return_expr (tree retval)
        }
 
       if (warn)
-       warning ("`operator=' should return a reference to `*this'");
+       warning (0, "%<operator=%> should return a reference to %<*this%>");
     }
 
   /* The fabled Named Return Value optimization, as per [class.copy]/15:
@@ -6022,8 +6224,8 @@ check_return_expr (tree retval)
 
   /* We don't need to do any conversions when there's nothing being
      returned.  */
-  if (!retval || retval == error_mark_node)
-    return retval;
+  if (!retval)
+    return NULL_TREE;
 
   /* Do any required conversions.  */
   if (retval == result || DECL_CONSTRUCTOR_P (current_function_decl))
@@ -6090,10 +6292,15 @@ comp_ptr_ttypes_real (tree to, tree from, int constp)
         so the usual checks are not appropriate.  */
       if (TREE_CODE (to) != FUNCTION_TYPE && TREE_CODE (to) != METHOD_TYPE)
        {
-         if (!at_least_as_qualified_p (to, from))
+         /* In Objective-C++, some types may have been 'volatilized' by
+            the compiler for EH; when comparing them here, the volatile
+            qualification must be ignored.  */
+         bool objc_quals_match = objc_type_quals_match (to, from);
+
+         if (!at_least_as_qualified_p (to, from) && !objc_quals_match)
            return 0;
 
-         if (!at_least_as_qualified_p (from, to))
+         if (!at_least_as_qualified_p (from, to) && !objc_quals_match)
            {
              if (constp == 0)
                return 0;
@@ -6142,6 +6349,10 @@ ptr_reasonably_similar (tree to, tree from)
                        COMPARE_BASE | COMPARE_DERIVED))
        continue;
 
+      if (TREE_CODE (to) == VECTOR_TYPE
+         && vector_types_convertible_p (to, from))
+       return 1;
+
       if (TREE_CODE (to) == INTEGER_TYPE
          && TYPE_PRECISION (to) == TYPE_PRECISION (from))
        return 1;
@@ -6198,8 +6409,49 @@ cp_has_mutable_p (tree type)
   return CLASS_TYPE_P (type) && CLASSTYPE_HAS_MUTABLE (type);
 }
 
+/* Apply the TYPE_QUALS to the new DECL.  */
+void
+cp_apply_type_quals_to_decl (int type_quals, tree decl)
+{
+  tree type = TREE_TYPE (decl);
+
+  if (type == error_mark_node)
+    return;
+
+  if (TREE_CODE (type) == FUNCTION_TYPE 
+      && type_quals != TYPE_UNQUALIFIED)
+    {
+      /* This was an error in C++98 (cv-qualifiers cannot be added to
+         a function type), but DR 295 makes the code well-formed by
+         dropping the extra qualifiers. */
+      if (pedantic)
+        {
+          tree bad_type = build_qualified_type (type, type_quals);
+          pedwarn ("ignoring %qV qualifiers added to function type %qT",
+                   bad_type, type);
+        }
+
+      TREE_TYPE (decl) = TYPE_MAIN_VARIANT (type);
+      return;
+    }
+
+  /* Avoid setting TREE_READONLY incorrectly.  */
+  if (/* If the object has a constructor, the constructor may modify
+        the object.  */
+      TYPE_NEEDS_CONSTRUCTING (type)
+      /* If the type isn't complete, we don't know yet if it will need
+        constructing.  */
+      || !COMPLETE_TYPE_P (type) 
+      /* If the type has a mutable component, that component might be
+        modified.  */
+      || TYPE_HAS_MUTABLE_P (type))
+    type_quals &= ~TYPE_QUAL_CONST;
+
+  c_apply_type_quals_to_decl (type_quals, decl);
+}
+
 /* Subroutine of casts_away_constness.  Make T1 and T2 point at
-   exemplar types such that casting T1 to T2 is casting away castness
+   exemplar types such that casting T1 to T2 is casting away constness
    if and only if there is no implicit conversion from T1 to T2.  */
 
 static void
@@ -6214,11 +6466,6 @@ casts_away_constness_r (tree *t1, tree *t2)
      and pointers to members (conv.qual), the "member" aspect of a
      pointer to member level is ignored when determining if a const
      cv-qualifier has been cast away.  */
-  if (TYPE_PTRMEM_P (*t1))
-    *t1 = build_pointer_type (TYPE_PTRMEM_POINTED_TO_TYPE (*t1));
-  if (TYPE_PTRMEM_P (*t2))
-    *t2 = build_pointer_type (TYPE_PTRMEM_POINTED_TO_TYPE (*t2));
-
   /* [expr.const.cast]
 
      For  two  pointer types:
@@ -6236,9 +6483,8 @@ casts_away_constness_r (tree *t1, tree *t2)
      to
 
             Tcv2,(M-K+1) * cv2,(M-K+2) * ... cv2,M *.  */
-
-  if (TREE_CODE (*t1) != POINTER_TYPE
-      || TREE_CODE (*t2) != POINTER_TYPE)
+  if ((!TYPE_PTR_P (*t1) && !TYPE_PTRMEM_P (*t1))
+      || (!TYPE_PTR_P (*t2) && !TYPE_PTRMEM_P (*t2)))
     {
       *t1 = cp_build_qualified_type (void_type_node,
                                     cp_type_quals (*t1));
@@ -6249,8 +6495,16 @@ casts_away_constness_r (tree *t1, tree *t2)
   
   quals1 = cp_type_quals (*t1);
   quals2 = cp_type_quals (*t2);
-  *t1 = TREE_TYPE (*t1);
-  *t2 = TREE_TYPE (*t2);
+
+  if (TYPE_PTRMEM_P (*t1))
+    *t1 = TYPE_PTRMEM_POINTED_TO_TYPE (*t1);
+  else
+    *t1 = TREE_TYPE (*t1);
+  if (TYPE_PTRMEM_P (*t2))
+    *t2 = TYPE_PTRMEM_POINTED_TO_TYPE (*t2);
+  else
+    *t2 = TREE_TYPE (*t2);
+
   casts_away_constness_r (t1, t2);
   *t1 = build_pointer_type (*t1);
   *t2 = build_pointer_type (*t2);
@@ -6315,3 +6569,19 @@ non_reference (tree t)
     t = TREE_TYPE (t);
   return t;
 }
+
+
+/* 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.  */
+
+int
+lvalue_or_else (tree ref, enum lvalue_use use)
+{
+  int win = lvalue_p (ref);
+
+  if (!win)
+    lvalue_error (use);
+
+  return win;
+}