OSDN Git Service

PR c++/21853
[pf3gnuchains/gcc-fork.git] / gcc / cp / typeck.c
index cb5a254..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;
@@ -519,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
@@ -921,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;
 
@@ -985,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:
@@ -1000,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.  */
@@ -1011,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.  */
@@ -1087,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.  */
 
@@ -1230,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;
@@ -1249,7 +1242,9 @@ cxx_sizeof_or_alignof_type (tree type, enum tree_code op, bool complain)
       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;
 }
@@ -1341,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;
 
@@ -1356,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.  */
 
@@ -1505,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 %qT'", totype);
+    warning (0, "deprecated conversion from string constant to %qT'", totype);
 
   return 1;
 }
@@ -1604,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]
@@ -1726,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 %qD 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
@@ -1780,7 +1754,7 @@ build_class_member_access_expr (tree object, tree member,
         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))
@@ -1849,9 +1823,6 @@ lookup_destructor (tree object, tree scope, tree dtor_name)
             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
@@ -1880,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)
@@ -1903,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
@@ -2050,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
@@ -2100,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]
         
@@ -2211,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)))
        {
@@ -2221,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);
@@ -2263,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));
@@ -2358,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)
@@ -2377,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);
@@ -2398,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;
@@ -2432,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
@@ -2526,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;
@@ -2625,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
@@ -2894,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)));
@@ -2930,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)
        {
@@ -2966,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
@@ -2991,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.  */
@@ -3012,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
@@ -3028,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
@@ -3199,7 +3178,9 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
   /* If we're in a template, the only thing we need to know is the
      RESULT_TYPE.  */
   if (processing_template_decl)
-    return build2 (resultcode, result_type, op0, op1);
+    return build2 (resultcode, 
+                  build_type ? build_type : result_type, 
+                  op0, op1);
 
   if (arithmetic_types_p)
     {
@@ -3353,7 +3334,7 @@ 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 %q#T and %q#T", 
+             warning (0, "comparison between types %q#T and %q#T", 
                        TREE_TYPE (orig_op0), TREE_TYPE (orig_op1));
            }
 
@@ -3389,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
@@ -3433,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
@@ -3441,7 +3422,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
                           < TYPE_PRECISION (result_type))
                       && (TYPE_PRECISION (TREE_TYPE (primop1))
                           < TYPE_PRECISION (result_type)))
-               warning ("comparison of promoted ~unsigned with unsigned");
+               warning (0, "comparison of promoted ~unsigned with unsigned");
            }
        }
     }
@@ -3468,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)
     {
@@ -3570,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);
     }
 
@@ -3618,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;
            }
@@ -3646,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;
 }
 
@@ -3735,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:
@@ -3946,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'.  */
@@ -4077,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;
        }
@@ -4090,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)
@@ -4104,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));
@@ -4128,15 +4125,10 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
          }
        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);
          }
 
@@ -4144,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;
@@ -4169,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)
     {
@@ -4220,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 %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;
-       }
-    }
-
+    return NULL_TREE;
   
   /* We permit compiler to make function calls returning
      objects of aggregate type look like lvalues.  */
@@ -4318,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;
          }
@@ -4336,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 %qD, 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;
 
@@ -4446,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)
@@ -4468,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))
+  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
@@ -4536,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".  */
@@ -4552,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,
@@ -4591,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))
@@ -4612,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);
     }
@@ -4645,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);
        }
     }
     
@@ -4675,101 +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 %qT to type %qT", 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 (intype == error_mark_node)
+  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 "
-                 "%qT to type %qT", 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 %qT to %qT loses precision",
+       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_if_not_in_template (build_nop (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);
+      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);
+      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 %qT to type %qT",
-             intype, type);
+      if (valid_p)
+       *valid_p = false;
+      error ("invalid cast from type %qT to type %qT", intype, type);
       return error_mark_node;
     }
       
@@ -4777,87 +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 %qT, 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 %qT, 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 %qT to type %qT",
-                 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 %qT to type %qT", 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)
@@ -4866,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
@@ -4906,118 +5132,48 @@ build_c_cast (tree type, tree expr)
       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 %qT to %qT 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 (CONSTANT_CLASS_P (ovalue))
-           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 %qT to %qT 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.
@@ -5079,7 +5235,7 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
     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, "assignment"))
+      if (!lvalue_or_else (lhs, lv_assign))
        return error_mark_node;
 
       gcc_assert (!TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0))
@@ -5107,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
@@ -5157,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;
@@ -5206,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
@@ -5308,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);
 
@@ -5356,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
@@ -5365,56 +5526,60 @@ 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");
-       }
-      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));
-           }
-       }
-    }
-  else
-    {
-      virt_binfo = binfo_from_vbase (binfo);
-      if (!virt_binfo)
+      if (kind != bk_via_virtual)
        result = BINFO_OFFSET (binfo);
       else
        {
+         tree virt_binfo = binfo_from_vbase (binfo);
+         
          /* This is a reinterpret cast, we choose to do nothing.  */
-         if (force)
-           warning ("pointer to member cast via virtual base %qT",
+         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
+    {
+      binfo = lookup_base (from, to, c_cast_p ? ba_unique : ba_check, &kind);
+      if (binfo)
+       {
+         if (kind != bk_via_virtual)
+           result = size_diffop (size_zero_node, BINFO_OFFSET (binfo));
+         else
+           {
+             /* 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_if_not_in_template (convert_to_integer (ptrdiff_type_node, 
                                                      result));
@@ -5458,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;
@@ -5489,7 +5654,8 @@ build_ptrmemfunc (tree type, tree pfn, int force)
 
       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
@@ -5537,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);
 }
 
@@ -5564,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));
@@ -5632,57 +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 %qD",
-                 errtype, parmnum, fndecl);
-      else
-        warning ("%s to non-pointer type %qT 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 %qT for %s %P of %qD",
-                 TREE_TYPE (expr), errtype, parmnum, fndecl);
-      else
-       warning ("%s to %qT from %qT", 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 %qE for %s %P of %qD",
-                     expr, errtype, parmnum, fndecl);
-         else
-           warning ("%s of negative value %qE to %qT", errtype, expr, type);
-       }
-
-      overflow_warning (expr);
-
-      if (TREE_CONSTANT (expr))
-       expr = fold_if_not_in_template (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
@@ -5722,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]
 
@@ -5803,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
@@ -5889,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;
        }
     }
@@ -5935,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))
@@ -5975,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
@@ -6008,13 +6140,22 @@ 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 "
+    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.  */
@@ -6040,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:
@@ -6083,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))
@@ -6151,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;
@@ -6203,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;
@@ -6259,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
@@ -6275,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:
@@ -6297,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));
@@ -6310,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);
@@ -6376,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;
+}