OSDN Git Service

91th Cygnus<->FSF quick merge
[pf3gnuchains/gcc-fork.git] / gcc / cp / typeck.c
index 6642316..4aee8a6 100644 (file)
@@ -1,5 +1,5 @@
 /* Build expressions with type checking for C++ compiler.
-   Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
@@ -16,7 +16,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 /* This file is part of the C++ front end.
@@ -37,20 +38,23 @@ extern void warning ();
 #include "rtl.h"
 #include "cp-tree.h"
 #include "flags.h"
+#include "output.h"
 
-int mark_addressable ();
-static tree convert_for_assignment ();
-/* static */ tree convert_for_initialization ();
+int mark_addressable PROTO((tree));
+static tree convert_for_assignment PROTO((tree, tree, char*, tree, int));
+/* static */ tree convert_for_initialization PROTO((tree, tree, tree, int, char*, tree, int));
 extern tree shorten_compare ();
-extern void binary_op_error ();
-static tree pointer_int_sum ();
-static tree pointer_diff ();
+static tree pointer_int_sum PROTO((enum tree_code, register tree, register tree));
+static tree pointer_diff PROTO((register tree, register tree));
+static int comp_target_parms PROTO((tree, tree, int));
+static int comp_ptr_ttypes_const PROTO((tree, tree));
+static int comp_ptr_ttypes_reinterpret PROTO((tree, tree));
+#if 0
 static tree convert_sequence ();
-/* static */ tree unary_complex_lvalue ();
+#endif
+/* static */ tree unary_complex_lvalue PROTO((enum tree_code, tree));
 static tree get_delta_difference PROTO((tree, tree, int));
 
-extern rtx original_result_rtx;
-
 /* Return the target type of TYPE, which meas return T for:
    T*, T&, T[], T (...), and otherwise, just T.  */
 
@@ -76,7 +80,12 @@ tree
 require_complete_type (value)
      tree value;
 {
-  tree type = TREE_TYPE (value);
+  tree type;
+
+  if (processing_template_decl)
+    return value;
+
+  type = TREE_TYPE (value);
 
   /* First, detect a valid value with a complete type.  */
   if (TYPE_SIZE (type) != 0
@@ -90,23 +99,53 @@ require_complete_type (value)
      not been laid out.  Try to avoid an error by interpreting
      it as this->X::Y, if reasonable.  */
   if (TREE_CODE (value) == OFFSET_REF
-      && C_C_D != 0
-      && TREE_OPERAND (value, 0) == C_C_D)
+      && current_class_ref != 0
+      && TREE_OPERAND (value, 0) == current_class_ref)
     {
       tree base, member = TREE_OPERAND (value, 1);
       tree basetype = TYPE_OFFSET_BASETYPE (type);
       my_friendly_assert (TREE_CODE (member) == FIELD_DECL, 305);
-      base = convert_pointer_to (basetype, current_class_decl);
+      base = convert_pointer_to (basetype, current_class_ptr);
       value = build (COMPONENT_REF, TREE_TYPE (member),
                     build_indirect_ref (base, NULL_PTR), member);
       return require_complete_type (value);
     }
 
+  if (IS_AGGR_TYPE (type) && CLASSTYPE_TEMPLATE_INSTANTIATION (type))
+    {
+      instantiate_class_template (TYPE_MAIN_VARIANT (type));
+      if (TYPE_SIZE (type) != 0)
+       return value;
+    }
+
   incomplete_type_error (value, type);
   return error_mark_node;
 }
 
+tree
+complete_type (type)
+     tree type;
+{
+  if (type == error_mark_node || TYPE_SIZE (type) != NULL_TREE)
+    ;
+  else if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
+    {
+      tree t = complete_type (TREE_TYPE (type));
+      if (TYPE_SIZE (t) != NULL_TREE && ! processing_template_decl)
+       layout_type (type);
+      TYPE_NEEDS_CONSTRUCTING (type)
+       = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (t));
+      TYPE_NEEDS_DESTRUCTOR (type)
+       = TYPE_NEEDS_DESTRUCTOR (TYPE_MAIN_VARIANT (t));
+    }
+  else if (IS_AGGR_TYPE (type) && CLASSTYPE_TEMPLATE_INSTANTIATION (type))
+    instantiate_class_template (TYPE_MAIN_VARIANT (type));
+
+  return type;
+}
+
 /* Return truthvalue of whether type of EXP is instantiated.  */
+
 int
 type_unknown_p (exp)
      tree exp;
@@ -118,6 +157,7 @@ type_unknown_p (exp)
 }
 
 /* Return truthvalue of whether T is function (or pfn) type.  */
+
 int
 fntype_p (t)
      tree t;
@@ -131,6 +171,7 @@ fntype_p (t)
 /* Do `exp = require_instantiated_type (type, exp);' to make sure EXP
    does not have an uninstantiated type.
    TYPE is type to instantiate with, if uninstantiated.  */
+
 tree
 require_instantiated_type (type, exp, errval)
      tree type, exp, errval;
@@ -215,10 +256,7 @@ commonparms (p1, p2)
        }
       else
        {
-         int cmp = simple_cst_equal (TREE_PURPOSE (p1), TREE_PURPOSE (p2));
-         if (cmp < 0)
-           my_friendly_abort (111);
-         if (cmp == 0)
+         if (1 != simple_cst_equal (TREE_PURPOSE (p1), TREE_PURPOSE (p2)))
            any_change = 1;
          TREE_PURPOSE (n) = TREE_PURPOSE (p2);
        }
@@ -285,14 +323,15 @@ common_type (t1, t2)
          attributes = a2;
        else
        {
-         /* Pick the longest list, and hang on the other
-            list.  */
+         /* Pick the longest list, and hang on the other list.  */
+         /* ??? For the moment we punt on the issue of attrs with args.  */
        
          if (list_length (a1) < list_length (a2))
             attributes = a2, a2 = a1;
 
          for (; a2; a2 = TREE_CHAIN (a2))
-            if (!value_member (attributes, a2))
+           if (lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)),
+                                 attributes) == NULL_TREE)
              {
                a1 = copy_node (a2);
                TREE_CHAIN (a1) = attributes;
@@ -308,6 +347,11 @@ common_type (t1, t2)
   if (TREE_CODE (t2) == ENUMERAL_TYPE)
     t2 = type_for_size (TYPE_PRECISION (t2), 1);
 
+  if (TYPE_PTRMEMFUNC_P (t1))
+    t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1);
+  if (TYPE_PTRMEMFUNC_P (t2))
+    t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2);
+
   code1 = TREE_CODE (t1);
   code2 = TREE_CODE (t2);
 
@@ -369,28 +413,33 @@ common_type (t1, t2)
         But ANSI C++ specifies doing this with the qualifiers.
         So I turned it on again.  */
       {
-       tree target = common_type (TYPE_MAIN_VARIANT (TREE_TYPE (t1)),
-                                  TYPE_MAIN_VARIANT (TREE_TYPE (t2)));
+       tree tt1 = TYPE_MAIN_VARIANT (TREE_TYPE (t1));
+       tree tt2 = TYPE_MAIN_VARIANT (TREE_TYPE (t2));
        int constp
          = TYPE_READONLY (TREE_TYPE (t1)) || TYPE_READONLY (TREE_TYPE (t2));
        int volatilep
          = TYPE_VOLATILE (TREE_TYPE (t1)) || TYPE_VOLATILE (TREE_TYPE (t2));
+       tree target;
+
+       if (tt1 == tt2)
+         target = tt1;
+       else if (tt1 == void_type_node || tt2 == void_type_node)
+         target = void_type_node;
+       else
+         target = common_type (tt1, tt2);
+
        target = cp_build_type_variant (target, constp, volatilep);
        if (code1 == POINTER_TYPE)
          t1 = build_pointer_type (target);
        else
          t1 = build_reference_type (target);
-       return build_type_attribute_variant (t1, attributes);
-      }
-#if 0
-    case POINTER_TYPE:
-      t1 = build_pointer_type (common_type (TREE_TYPE (t1), TREE_TYPE (t2)));
-      return build_type_attribute_variant (t1, attributes);
+       t1 = build_type_attribute_variant (t1, attributes);
 
-    case REFERENCE_TYPE:
-      t1 = build_reference_type (common_type (TREE_TYPE (t1), TREE_TYPE (t2)));
-      return build_type_attribute_variant (t1, attributes);
-#endif
+       if (TREE_CODE (target) == METHOD_TYPE)
+         t1 = build_ptrmemfunc_type (t1);
+
+       return t1;
+      }
 
     case ARRAY_TYPE:
       {
@@ -401,7 +450,8 @@ common_type (t1, t2)
        if (elt == TREE_TYPE (t2) && TYPE_DOMAIN (t2))
          return build_type_attribute_variant (t2, attributes);
        /* Merge the element types, and have a size if either arg has one.  */
-       t1 = build_array_type (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2));
+       t1 = build_cplus_array_type
+         (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2));
        return build_type_attribute_variant (t1, attributes);
       }
 
@@ -425,7 +475,7 @@ common_type (t1, t2)
          {
            rval = build_function_type (valtype, p2);
            if ((raises = TYPE_RAISES_EXCEPTIONS (t2)))
-             rval = build_exception_variant (NULL_TREE, rval, raises);
+             rval = build_exception_variant (rval, raises);
            return build_type_attribute_variant (rval, attributes);
          }
        raises = TYPE_RAISES_EXCEPTIONS (t1);
@@ -433,12 +483,12 @@ common_type (t1, t2)
          {
            rval = build_function_type (valtype, p1);
            if (raises)
-             rval = build_exception_variant (NULL_TREE, rval, raises);
+             rval = build_exception_variant (rval, raises);
            return build_type_attribute_variant (rval, attributes);
          }
 
        rval = build_function_type (valtype, commonparms (p1, p2));
-       rval = build_exception_variant (NULL_TREE, rval, raises);
+       rval = build_exception_variant (rval, raises);
        return build_type_attribute_variant (rval, attributes);
       }
 
@@ -455,14 +505,26 @@ common_type (t1, t2)
        compiler_error ("common_type called with uncommon aggregate types");
 
     case METHOD_TYPE:
-      if (comptypes (TYPE_METHOD_BASETYPE (t1), TYPE_METHOD_BASETYPE (t2), 1)
-         && TREE_CODE (TREE_TYPE (t1)) == TREE_CODE (TREE_TYPE (t2)))
+      if (TREE_CODE (TREE_TYPE (t1)) == TREE_CODE (TREE_TYPE (t2)))
        {
          /* Get this value the long way, since TYPE_METHOD_BASETYPE
             is just the main variant of this.  */
-         tree basetype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t1)));
+         tree basetype;
          tree raises, t3;
 
+         tree b1 = TYPE_OFFSET_BASETYPE (t1);
+         tree b2 = TYPE_OFFSET_BASETYPE (t2);
+
+         if (comptypes (b1, b2, 1)
+             || (DERIVED_FROM_P (b1, b2) && binfo_or_else (b1, b2)))
+           basetype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t2)));
+         else
+           {
+             if (binfo_or_else (b2, b1) == NULL_TREE)
+               compiler_error ("common_type called with uncommon method types");
+             basetype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t1)));
+           }
+
          raises = TYPE_RAISES_EXCEPTIONS (t1);
 
          /* If this was a member function type, get back to the
@@ -472,7 +534,7 @@ common_type (t1, t2)
          t2 = build_function_type (TREE_TYPE (t2), TREE_CHAIN (TYPE_ARG_TYPES (t2)));
          t3 = common_type (t1, t2);
          t3 = build_cplus_method_type (basetype, TREE_TYPE (t3), TYPE_ARG_TYPES (t3));
-         t1 = build_exception_variant (basetype, t3, raises);
+         t1 = build_exception_variant (t3, raises);
        }
       else
         compiler_error ("common_type called with uncommon method types");
@@ -480,17 +542,18 @@ common_type (t1, t2)
       return build_type_attribute_variant (t1, attributes);
 
     case OFFSET_TYPE:
-      if (TYPE_OFFSET_BASETYPE (t1) == TYPE_OFFSET_BASETYPE (t2)
-         && TREE_CODE (TREE_TYPE (t1)) == TREE_CODE (TREE_TYPE (t2)))
+      if (TREE_TYPE (t1) == TREE_TYPE (t2))
        {
-         tree basetype = TYPE_OFFSET_BASETYPE (t1);
-         t1 = build_offset_type (basetype,
-                                   common_type (TREE_TYPE (t1), TREE_TYPE (t2)));
-       }
-      else
-        compiler_error ("common_type called with uncommon member types");
+         tree b1 = TYPE_OFFSET_BASETYPE (t1);
+         tree b2 = TYPE_OFFSET_BASETYPE (t2);
 
-      /* ... falls through ... */
+         if (comptypes (b1, b2, 1)
+             || (DERIVED_FROM_P (b1, b2) && binfo_or_else (b1, b2)))
+           return build_type_attribute_variant (t2, attributes);
+         else if (binfo_or_else (b2, b1))
+           return build_type_attribute_variant (t1, attributes);
+       }
+      compiler_error ("common_type called with uncommon member types");
 
     default:
       return build_type_attribute_variant (t1, attributes);
@@ -498,10 +561,10 @@ common_type (t1, t2)
 }
 \f
 /* Return 1 if TYPE1 and TYPE2 raise the same exceptions.  */
+
 int
-compexcepttypes (t1, t2, strict)
+compexcepttypes (t1, t2)
      tree t1, t2;
-     int strict;
 {
   return TYPE_RAISES_EXCEPTIONS (t1) == TYPE_RAISES_EXCEPTIONS (t2);
 }
@@ -561,6 +624,7 @@ comp_array_types (cmp, t1, t2, strict)
    pointer to a base classes. These allowances do not commute. In this
    case, TYPE1 is assumed to be the base class, and TYPE2 is assumed to
    be the derived class.  */
+
 int
 comptypes (type1, type2, strict)
      tree type1, type2;
@@ -594,6 +658,11 @@ comptypes (type1, type2, strict)
        return 1;
     }
 
+  if (TYPE_PTRMEMFUNC_P (t1))
+    t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1);
+  if (TYPE_PTRMEMFUNC_P (t2))
+    t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2);
+
   /* Different classes of types can't be compatible.  */
 
   if (TREE_CODE (t1) != TREE_CODE (t2))
@@ -626,13 +695,15 @@ comptypes (type1, type2, strict)
   if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
     return 1;
 
-#ifdef COMP_TYPE_ATTRIBUTES
+  /* ??? COMP_TYPE_ATTRIBUTES is currently useless for variables as each
+     attribute is its own main variant (`val' will remain 0).  */
+#ifndef COMP_TYPE_ATTRIBUTES
+#define COMP_TYPE_ATTRIBUTES(t1,t2)    1
+#endif
+
+  /* 1 if no need for warning yet, 2 if warning cause has been seen.  */
   if (! (attrval = COMP_TYPE_ATTRIBUTES (t1, t2)))
      return 0;
-#else
-  /* 1 if no need for warning yet, 2 if warning cause has been seen.  */
-  attrval = 1;
-#endif
 
   /* 1 if no need for warning yet, 2 if warning cause has been seen.  */
   val = 0;
@@ -641,18 +712,40 @@ comptypes (type1, type2, strict)
     {
     case RECORD_TYPE:
     case UNION_TYPE:
+      if (CLASSTYPE_TEMPLATE_INFO (t1) && CLASSTYPE_TEMPLATE_INFO (t2)
+         && CLASSTYPE_TI_TEMPLATE (t1) == CLASSTYPE_TI_TEMPLATE (t2))
+       {
+         int i = TREE_VEC_LENGTH (CLASSTYPE_TI_ARGS (t1));
+         tree *p1 = &TREE_VEC_ELT (CLASSTYPE_TI_ARGS (t1), 0);
+         tree *p2 = &TREE_VEC_ELT (CLASSTYPE_TI_ARGS (t2), 0);
+       
+         while (i--)
+           {
+             if (TREE_CODE_CLASS (TREE_CODE (p1[i])) == 't')
+               {
+                 if (! comptypes (p1[i], p2[i], 1))
+                   return 0;
+               }
+             else
+               {
+                 if (simple_cst_equal (p1[i], p2[i]) <= 0)
+                   return 0;
+               }
+           }
+         return 1;
+       }
       if (strict <= 0)
        goto look_hard;
       return 0;
 
     case OFFSET_TYPE:
-      val = (comptypes (TYPE_POINTER_TO (TYPE_OFFSET_BASETYPE (t1)),
-                        TYPE_POINTER_TO (TYPE_OFFSET_BASETYPE (t2)), strict)
-             && comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict));
+      val = (comptypes (build_pointer_type (TYPE_OFFSET_BASETYPE (t1)),
+                       build_pointer_type (TYPE_OFFSET_BASETYPE (t2)), strict)
+            && comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict));
       break;
 
     case METHOD_TYPE:
-      if (! compexcepttypes (t1, t2, strict))
+      if (! compexcepttypes (t1, t2))
        return 0;
 
       /* This case is anti-symmetrical!
@@ -660,11 +753,9 @@ comptypes (type1, type2, strict)
         to something expecting a derived member (or member function),
         but not vice-versa!  */
 
-      val = (comptypes (TYPE_POINTER_TO (TYPE_METHOD_BASETYPE (t2)),
-                        TYPE_POINTER_TO (TYPE_METHOD_BASETYPE (t1)), strict)
-             && comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict)
-             && compparms (TREE_CHAIN (TYPE_ARG_TYPES (t1)),
-                           TREE_CHAIN (TYPE_ARG_TYPES (t2)), strict));
+      val = (comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict)
+            && compparms (TYPE_ARG_TYPES (t1),
+                          TYPE_ARG_TYPES (t2), strict));
       break;
 
     case POINTER_TYPE:
@@ -682,7 +773,7 @@ comptypes (type1, type2, strict)
            {
              int rval;
            look_hard:
-             rval = t1 == t2 || UNIQUELY_DERIVED_FROM_P (t1, t2);
+             rval = t1 == t2 || DERIVED_FROM_P (t1, t2);
 
              if (rval)
                {
@@ -691,7 +782,7 @@ comptypes (type1, type2, strict)
                }
              if (strict < 0)
                {
-                 val = UNIQUELY_DERIVED_FROM_P (t2, t1);
+                 val = DERIVED_FROM_P (t2, t1);
                  break;
                }
            }
@@ -702,7 +793,7 @@ comptypes (type1, type2, strict)
       break;
 
     case FUNCTION_TYPE:
-      if (! compexcepttypes (t1, t2, strict))
+      if (! compexcepttypes (t1, t2))
        return 0;
 
       val = ((TREE_TYPE (t1) == TREE_TYPE (t2)
@@ -716,10 +807,12 @@ comptypes (type1, type2, strict)
       break;
 
     case TEMPLATE_TYPE_PARM:
-      return 1;
+      return TEMPLATE_TYPE_IDX (t1) == TEMPLATE_TYPE_IDX (t2);
 
-    case UNINSTANTIATED_P_TYPE:
-      return UPT_TEMPLATE (t1) == UPT_TEMPLATE (t2);
+    case TYPENAME_TYPE:
+      if (TYPE_IDENTIFIER (t1) != TYPE_IDENTIFIER (t2))
+       return 0;
+      return comptypes (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2), 1);
     }
   return attrval == 2 && val == 1 ? 2 : val;
 }
@@ -746,11 +839,56 @@ comp_target_types (ttl, ttr, nptrs)
 
   if (TREE_CODE (ttr) == POINTER_TYPE)
     {
-      if (TREE_CODE (TREE_TYPE (ttl)) == POINTER_TYPE
-         || TREE_CODE (TREE_TYPE (ttl)) == ARRAY_TYPE)
-       return comp_ptr_ttypes (TREE_TYPE (ttl), TREE_TYPE (ttr));
-      else
-       return comp_target_types (TREE_TYPE (ttl), TREE_TYPE (ttr), nptrs - 1);
+      ttl = TREE_TYPE (ttl);
+      ttr = TREE_TYPE (ttr);
+
+      if (nptrs > 0)
+       {
+         if (TREE_CODE (ttl) == VOID_TYPE
+                  && TREE_CODE (ttr) != FUNCTION_TYPE
+                  && TREE_CODE (ttr) != METHOD_TYPE
+                  && TREE_CODE (ttr) != OFFSET_TYPE)
+           return 1;
+         else if (TREE_CODE (ttr) == VOID_TYPE
+                  && TREE_CODE (ttl) != FUNCTION_TYPE
+                  && TREE_CODE (ttl) != METHOD_TYPE
+                  && TREE_CODE (ttl) != OFFSET_TYPE)
+           return -1;
+         else if (TREE_CODE (ttl) == POINTER_TYPE
+                  || TREE_CODE (ttl) == ARRAY_TYPE)
+           {
+             if (comp_ptr_ttypes (ttl, ttr))
+               return 1;
+             else if (comp_ptr_ttypes (ttr, ttl))
+               return -1;
+             return 0;
+           }
+       }
+
+      /* Const and volatile mean something different for function types,
+        so the usual checks are not appropriate.  */
+      if (TREE_CODE (ttl) == FUNCTION_TYPE || TREE_CODE (ttl) == METHOD_TYPE)
+       return comp_target_types (ttl, ttr, nptrs - 1);
+
+      /* Make sure that the cv-quals change only in the same direction as
+        the target type.  */
+      {
+       int t;
+       int c = TYPE_READONLY (ttl) - TYPE_READONLY (ttr);
+       int v = TYPE_VOLATILE (ttl) - TYPE_VOLATILE (ttr);
+
+       if ((c > 0 && v < 0) || (c < 0 && v > 0))
+         return 0;
+
+       if (TYPE_MAIN_VARIANT (ttl) == TYPE_MAIN_VARIANT (ttr))
+         return (c + v < 0) ? -1 : 1;
+
+       t = comp_target_types (ttl, ttr, nptrs - 1);
+       if ((t == 1 && c + v >= 0) || (t == -1 && c + v <= 0))
+         return t;
+
+       return 0;
+      }
     }
 
   if (TREE_CODE (ttr) == REFERENCE_TYPE)
@@ -789,9 +927,9 @@ comp_target_types (ttl, ttr, nptrs)
     {
       if (nptrs < 0)
        return 0;
-      if (comptypes (TYPE_POINTER_TO (ttl), TYPE_POINTER_TO (ttr), 0))
+      if (comptypes (build_pointer_type (ttl), build_pointer_type (ttr), 0))
        return 1;
-      if (comptypes (TYPE_POINTER_TO (ttr), TYPE_POINTER_TO (ttl), 0))
+      if (comptypes (build_pointer_type (ttr), build_pointer_type (ttl), 0))
        return -1;
       return 0;
     }
@@ -802,11 +940,12 @@ comp_target_types (ttl, ttr, nptrs)
 /* If two types share a common base type, return that basetype.
    If there is not a unique most-derived base type, this function
    returns ERROR_MARK_NODE.  */
-tree
+
+static tree
 common_base_type (tt1, tt2)
      tree tt1, tt2;
 {
-  tree best = NULL_TREE, tmp;
+  tree best = NULL_TREE;
   int i;
 
   /* If one is a baseclass of another, that's good enough.  */
@@ -815,15 +954,6 @@ common_base_type (tt1, tt2)
   if (UNIQUELY_DERIVED_FROM_P (tt2, tt1))
     return tt2;
 
-#if 0
-  /* If they share a virtual baseclass, that's good enough.  */
-  for (tmp = CLASSTYPE_VBASECLASSES (tt1); tmp; tmp = TREE_CHAIN (tmp))
-    {
-      if (binfo_member (BINFO_TYPE (tmp), CLASSTYPE_VBASECLASSES (tt2)))
-       return BINFO_TYPE (tmp);
-    }
-#endif
-
   /* Otherwise, try to find a unique baseclass of TT1
      that is shared by TT2, and follow that down.  */
   for (i = CLASSTYPE_N_BASECLASSES (tt1)-1; i >= 0; i--)
@@ -870,6 +1000,7 @@ common_base_type (tt1, tt2)
    C++: See comment above about TYPE1, TYPE2, STRICT.
    If STRICT == 3, it means checking is strict, but do not compare
    default parameter values.  */
+
 int
 compparms (parms1, parms2, strict)
      tree parms1, parms2;
@@ -908,17 +1039,6 @@ compparms (parms1, parms2, strict)
            return t2 == void_list_node && TREE_PURPOSE (t1);
          return TREE_PURPOSE (t1) || TREE_PURPOSE (t2);
        }
-#if 0
-      /* Default parms are not part of the type of a function.  */
-      if (strict != 3 && TREE_PURPOSE (t1) && TREE_PURPOSE (t2))
-       {
-         int cmp = simple_cst_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2));
-         if (cmp < 0)
-           my_friendly_abort (113);
-         if (cmp == 0)
-           return 0;
-       }
-#endif
 
       t1 = TREE_CHAIN (t1);
       t2 = TREE_CHAIN (t2);
@@ -927,7 +1047,8 @@ compparms (parms1, parms2, strict)
 
 /* This really wants return whether or not parameter type lists
    would make their owning functions assignment compatible or not.  */
-int
+
+static int
 comp_target_parms (parms1, parms2, strict)
      tree parms1, parms2;
      int strict;
@@ -1006,12 +1127,6 @@ comp_target_parms (parms1, parms2, strict)
            }
          if (strict != 0)
            return 0;
-#if 0
-         /* What good do these cases do?  */
-         if (strict == 0)
-           return p2 == void_type_node && TREE_PURPOSE (t1);
-         return TREE_PURPOSE (t1) || TREE_PURPOSE (t2);
-#endif
        }
       /* Target types are compatible--just make sure that if
         we use parameter lists, that they are ok as well.  */
@@ -1055,10 +1170,10 @@ self_promoting_args_p (parms)
       if (TREE_CHAIN (t) == 0 && type != void_type_node)
        return 0;
 
-      if (TYPE_MAIN_VARIANT (type) == float_type_node)
+      if (type == 0)
        return 0;
 
-      if (type == 0)
+      if (TYPE_MAIN_VARIANT (type) == float_type_node)
        return 0;
 
       if (C_PROMOTING_INTEGER_TYPE_P (type))
@@ -1086,7 +1201,16 @@ unsigned_type (type)
     return long_unsigned_type_node;
   if (type1 == long_long_integer_type_node)
     return long_long_unsigned_type_node;
-  return type;
+  if (type1 == intDI_type_node)
+    return unsigned_intDI_type_node;
+  if (type1 == intSI_type_node)
+    return unsigned_intSI_type_node;
+  if (type1 == intHI_type_node)
+    return unsigned_intHI_type_node;
+  if (type1 == intQI_type_node)
+    return unsigned_intQI_type_node;
+
+  return signed_or_unsigned_type (1, type);
 }
 
 /* Return a signed type the same as TYPE in other respects.  */
@@ -1106,7 +1230,16 @@ signed_type (type)
     return long_integer_type_node;
   if (type1 == long_long_unsigned_type_node)
     return long_long_integer_type_node;
-  return type;
+  if (type1 == unsigned_intDI_type_node)
+    return intDI_type_node;
+  if (type1 == unsigned_intSI_type_node)
+    return intSI_type_node;
+  if (type1 == unsigned_intHI_type_node)
+    return intHI_type_node;
+  if (type1 == unsigned_intQI_type_node)
+    return intQI_type_node;
+
+  return signed_or_unsigned_type (0, type);
 }
 
 /* Return a type the same as TYPE except unsigned or
@@ -1117,8 +1250,10 @@ signed_or_unsigned_type (unsignedp, type)
      int unsignedp;
      tree type;
 {
-  if (! INTEGRAL_TYPE_P (type))
+  if (! INTEGRAL_TYPE_P (type)
+      || TREE_UNSIGNED (type) == unsignedp)
     return type;
+
   if (TYPE_PRECISION (type) == TYPE_PRECISION (signed_char_type_node))
     return unsignedp ? unsigned_char_type_node : signed_char_type_node;
   if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)) 
@@ -1133,6 +1268,8 @@ signed_or_unsigned_type (unsignedp, type)
   return type;
 }
 
+/* Compute the value of the `sizeof' operator.  */
+
 tree
 c_sizeof (type)
      tree type;
@@ -1140,6 +1277,9 @@ c_sizeof (type)
   enum tree_code code = TREE_CODE (type);
   tree t;
 
+  if (processing_template_decl)
+    return build_min (SIZEOF_EXPR, sizetype, type);
+
   if (code == FUNCTION_TYPE)
     {
       if (pedantic || warn_pointer_arith)
@@ -1184,9 +1324,9 @@ c_sizeof (type)
       return size_int (0);
     }
 
-  if (TYPE_SIZE (type) == 0)
+  if (TYPE_SIZE (complete_type (type)) == 0)
     {
-      error ("`sizeof' applied to an incomplete type");
+      cp_error ("`sizeof' applied to incomplete type `%T'", type);
       return size_int (0);
     }
 
@@ -1200,6 +1340,36 @@ c_sizeof (type)
 }
 
 tree
+expr_sizeof (e)
+     tree e;
+{
+  if (processing_template_decl)
+    return build_min (SIZEOF_EXPR, sizetype, e);
+
+  if (TREE_CODE (e) == COMPONENT_REF
+      && DECL_BIT_FIELD (TREE_OPERAND (e, 1)))
+    error ("sizeof applied to a bit-field");
+  /* ANSI says arrays and functions are converted inside comma.
+     But we can't really convert them in build_compound_expr
+     because that would break commas in lvalues.
+     So do the conversion here if operand was a comma.  */
+  if (TREE_CODE (e) == COMPOUND_EXPR
+      && (TREE_CODE (TREE_TYPE (e)) == ARRAY_TYPE
+         || TREE_CODE (TREE_TYPE (e)) == FUNCTION_TYPE))
+    e = default_conversion (e);
+  else if (TREE_CODE (e) == TREE_LIST)
+    {
+      tree t = TREE_VALUE (e);
+      if (t != NULL_TREE
+         && ((TREE_TYPE (t)
+              && TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE)
+             || is_overloaded_fn (t)))
+       pedwarn ("ANSI C++ forbids taking the sizeof a function type");
+    }
+  return c_sizeof (TREE_TYPE (e));
+}
+  
+tree
 c_sizeof_nowarn (type)
      tree type;
 {
@@ -1215,14 +1385,7 @@ c_sizeof_nowarn (type)
     type = TREE_TYPE (type);
 
   if (TYPE_SIZE (type) == 0)
-    {
-#if 0
-      /* ??? Tiemann, why have any diagnostic here?
-        There is none in the corresponding function for C.  */
-      warning ("sizeof applied to an incomplete type");
-#endif
-      return size_int (0);
-    }
+    return size_int (0);
 
   /* Convert in case a char is more than one unit.  */
   t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type), 
@@ -1272,19 +1435,25 @@ c_alignof (type)
    C++: this will automatically bash references to their target type.  */
 
 tree
-default_conversion (exp)
+decay_conversion (exp)
      tree exp;
 {
   register tree type = TREE_TYPE (exp);
   register enum tree_code code = TREE_CODE (type);
 
-  if (code == OFFSET_TYPE /* || TREE_CODE (exp) == OFFSET_REF */ )
+  if (code == OFFSET_TYPE)
     {
       if (TREE_CODE (exp) == OFFSET_REF)
-       return default_conversion (resolve_offset_ref (exp));
+       return decay_conversion (resolve_offset_ref (exp));
 
       type = TREE_TYPE (type);
       code = TREE_CODE (type);
+
+      if (type == unknown_type_node)
+       {
+         cp_pedwarn ("assuming & on overloaded member function");
+         return build_unary_op (ADDR_EXPR, exp, 0);
+       }
     }
 
   if (code == REFERENCE_TYPE)
@@ -1298,7 +1467,7 @@ default_conversion (exp)
   if (TREE_CODE (exp) == CONST_DECL)
     exp = DECL_INITIAL (exp);
   /* Replace a nonvolatile const static variable with its value.  */
-  else if (TREE_READONLY_DECL_P (exp) && DECL_MODE (exp) != BLKmode)
+  else if (TREE_READONLY_DECL_P (exp))
     {
       exp = decl_constant_value (exp);
       type = TREE_TYPE (exp);
@@ -1307,15 +1476,6 @@ default_conversion (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.  */
 
-  if (INTEGRAL_CODE_P (code))
-    {
-      tree t = type_promotes_to (type);
-      if (t != type)
-       return convert (t, exp);
-    }
-  if (flag_traditional
-      && TYPE_MAIN_VARIANT (type) == float_type_node)
-    return convert (double_type_node, exp);
   if (code == VOID_TYPE)
     {
       error ("void value not ignored as it ought to be");
@@ -1327,12 +1487,7 @@ default_conversion (exp)
     }
   if (code == METHOD_TYPE)
     {
-      if (TREE_CODE (exp) == OFFSET_REF)
-       {
-         my_friendly_assert (TREE_CODE (TREE_OPERAND (exp, 1)) == FUNCTION_DECL,
-                             308);
-         return build_unary_op (ADDR_EXPR, TREE_OPERAND (exp, 1), 0);
-       }
+      cp_pedwarn ("assuming & on `%E'", exp);
       return build_unary_op (ADDR_EXPR, exp, 0);
     }
   if (code == ARRAY_TYPE)
@@ -1352,14 +1507,14 @@ default_conversion (exp)
              inner = build1 (CONVERT_EXPR,
                              build_pointer_type (TREE_TYPE (TREE_TYPE (inner))),
                              inner);
-             TREE_REFERENCE_EXPR (inner) = 1;
+             TREE_CONSTANT (inner) = TREE_CONSTANT (TREE_OPERAND (inner, 0));
            }
-         return convert (TYPE_POINTER_TO (TREE_TYPE (type)), inner);
+         return convert (build_pointer_type (TREE_TYPE (type)), inner);
        }
 
       if (TREE_CODE (exp) == COMPOUND_EXPR)
        {
-         tree op1 = default_conversion (TREE_OPERAND (exp, 1));
+         tree op1 = decay_conversion (TREE_OPERAND (exp, 1));
          return build (COMPOUND_EXPR, TREE_TYPE (op1),
                        TREE_OPERAND (exp, 0), op1);
        }
@@ -1405,6 +1560,45 @@ default_conversion (exp)
       adr = build_unary_op (ADDR_EXPR, exp, 1);
       return convert (ptrtype, adr);
     }
+
+  return exp;
+}
+
+tree
+default_conversion (exp)
+     tree exp;
+{
+  tree type;
+  enum tree_code code;
+
+  exp = decay_conversion (exp);
+
+  type = TREE_TYPE (exp);
+  code = TREE_CODE (type);
+
+  if (INTEGRAL_CODE_P (code))
+    {
+      tree t = type_promotes_to (type);
+      if (t != type)
+       return convert (t, exp);
+    }
+
+  return exp;
+}
+
+/* Take the address of an inline function without setting TREE_ADDRESSABLE
+   or TREE_USED.  */
+
+tree
+inline_conversion (exp)
+     tree exp;
+{
+  if (TREE_CODE (exp) == FUNCTION_DECL)
+    {
+      tree type = build_type_variant
+       (TREE_TYPE (exp), TREE_READONLY (exp), TREE_THIS_VOLATILE (exp));
+      exp = build1 (ADDR_EXPR, build_pointer_type (type), exp);
+    }
   return exp;
 }
 \f
@@ -1425,89 +1619,30 @@ build_object_ref (datum, basetype, field)
                basetype, field, dtype);
       return error_mark_node;
     }
-  else if (IS_SIGNATURE (IDENTIFIER_TYPE_VALUE (basetype)))
+  else if (IS_SIGNATURE (basetype))
     {
       warning ("signature name in scope resolution ignored");
       return build_component_ref (datum, field, NULL_TREE, 1);
     }
-  else if (is_aggr_typedef (basetype, 1))
+  else if (is_aggr_type (basetype, 1))
     {
-      tree real_basetype = IDENTIFIER_TYPE_VALUE (basetype);
-      tree binfo = binfo_or_else (real_basetype, TREE_TYPE (datum));
+      tree binfo = binfo_or_else (basetype, dtype);
       if (binfo)
-       return build_component_ref (build_scoped_ref (datum, basetype),
-                                   field, binfo, 1);
+       return build_x_component_ref (build_scoped_ref (datum, basetype),
+                                     field, binfo, 1);
     }
   return error_mark_node;
 }
 
 /* Like `build_component_ref, but uses an already found field.
-   Must compute access for C_C_D.  Otherwise, ok.  */
+   Must compute access for current_class_ref.  Otherwise, ok.  */
+
 tree
 build_component_ref_1 (datum, field, protect)
      tree datum, field;
      int protect;
 {
-  register tree basetype = TREE_TYPE (datum);
-  register enum tree_code code = TREE_CODE (basetype);
-  register tree ref;
-
-  if (code == REFERENCE_TYPE)
-    {
-      datum = convert_from_reference (datum);
-      basetype = TREE_TYPE (datum);
-      code = TREE_CODE (basetype);
-    }
-
-  if (! IS_AGGR_TYPE_CODE (code))
-    {
-      if (code != ERROR_MARK)
-       cp_error ("request for member `%D' in `%E', which is of non-aggregate type `%T'",
-                 field, datum, basetype);
-      return error_mark_node;
-    }
-
-  if (TYPE_SIZE (basetype) == 0)
-    {
-      incomplete_type_error (0, basetype);
-      return error_mark_node;
-    }
-
-  /* Look up component name in the structure type definition.  */
-
-  if (field == error_mark_node)
-    my_friendly_abort (115);
-
-  if (TREE_STATIC (field))
-    return field;
-
-  if (datum == C_C_D)
-    {
-      enum access_type access
-       = compute_access (TYPE_BINFO (current_class_type), field);
-
-      if (access == access_private)
-       {
-         cp_error ("field `%D' is private", field);
-         return error_mark_node;
-       }
-      else if (access == access_protected)
-       {
-         cp_error ("field `%D' is protected", field);
-         return error_mark_node;
-       }
-    }
-
-  ref = build (COMPONENT_REF, TREE_TYPE (field), datum, field);
-
-  if (TREE_READONLY (datum) || TREE_READONLY (field))
-    TREE_READONLY (ref) = 1;
-  if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (field))
-    TREE_THIS_VOLATILE (ref) = 1;
-  if (DECL_MUTABLE_P (field))
-    TREE_READONLY (ref) = 0;
-
-  return ref;
+  return build_component_ref (datum, field, NULL_TREE, protect);
 }
 
 /* Given a COND_EXPR in T, return it in a form that we can, for
@@ -1516,6 +1651,7 @@ build_component_ref_1 (datum, field, protect)
    we're dealing with aggregates.  So, we now call this in unary_complex_lvalue,
    and in build_modify_expr.  The case (in particular) that led to this was
    with CODE == ADDR_EXPR, since it's not an lvalue when we'd get it there.  */
+
 static tree
 rationalize_conditional_expr (code, t)
      enum tree_code code;
@@ -1527,17 +1663,62 @@ rationalize_conditional_expr (code, t)
                            build_unary_op (code, TREE_OPERAND (t, 2), 0));
 }
 
+/* Given the TYPE of an anonymous union field inside T, return the
+   FIELD_DECL for the field.  If not found return NULL_TREE.  Because
+   anonymous unions can nest, we must also search all anonymous unions
+   that are directly reachable.  */
+
+static tree
+lookup_anon_field (t, type)
+     tree t, type;
+{
+  tree field;
+
+  for (field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field))
+    {
+      if (TREE_STATIC (field))
+       continue;
+      if (TREE_CODE (field) != FIELD_DECL)
+       continue;
+
+      /* If we find it directly, return the field.  */
+      if (DECL_NAME (field) == NULL_TREE
+         && type == TREE_TYPE (field))
+       {
+         return field;
+       }
+
+      /* Otherwise, it could be nested, search harder.  */
+      if (DECL_NAME (field) == NULL_TREE
+         && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
+       {
+         tree subfield = lookup_anon_field (TREE_TYPE (field), type);
+         if (subfield)
+           return subfield;
+       }
+    }
+  return NULL_TREE;
+}
+
+/* Build a COMPONENT_REF for a given DATUM, and it's member COMPONENT.
+   COMPONENT can be an IDENTIFIER_NODE that is the name of the member
+   that we are interested in, or it can be a FIELD_DECL.  */
+
 tree
 build_component_ref (datum, component, basetype_path, protect)
      tree datum, component, basetype_path;
      int protect;
 {
   register tree basetype = TREE_TYPE (datum);
-  register enum tree_code code = TREE_CODE (basetype);
+  register enum tree_code code;
   register tree field = NULL;
   register tree ref;
 
-  /* If DATUM is a COMPOUND_EXPR or COND_EXPR, move our reference inside it. */
+  if (processing_template_decl)
+    return build_min_nt (COMPONENT_REF, datum, component);
+
+  /* If DATUM is a COMPOUND_EXPR or COND_EXPR, move our reference
+     inside it.  */
   switch (TREE_CODE (datum))
     {
     case COMPOUND_EXPR:
@@ -1556,31 +1737,28 @@ build_component_ref (datum, component, basetype_path, protect)
                              basetype_path, protect));
     }
 
+  code = TREE_CODE (basetype);
+
   if (code == REFERENCE_TYPE)
     {
-#if 0
-      /* TREE_REFERENCE_EXPRs are not converted by `convert_from_reference'.
-        @@ Maybe that is not right.  */
-      if (TREE_REFERENCE_EXPR (datum))
-       datum = build1 (INDIRECT_REF, TREE_TYPE (basetype), datum);
-      else
-#endif
-       datum = convert_from_reference (datum);
+      datum = convert_from_reference (datum);
+      basetype = TREE_TYPE (datum);
+      code = TREE_CODE (basetype);
+    }
+  if (TREE_CODE (datum) == OFFSET_REF)
+    {
+      datum = resolve_offset_ref (datum);
       basetype = TREE_TYPE (datum);
       code = TREE_CODE (basetype);
     }
 
-  /* First, see if there is a field or component with name COMPONENT. */
+  /* First, see if there is a field or component with name COMPONENT.  */
   if (TREE_CODE (component) == TREE_LIST)
     {
       my_friendly_assert (!(TREE_CHAIN (component) == NULL_TREE
                && DECL_CHAIN (TREE_VALUE (component)) == NULL_TREE), 309);
       return build (COMPONENT_REF, TREE_TYPE (component), datum, component);
     }
-#if 0
-  if (TREE_CODE (component) == TYPE_EXPR)
-    return build_component_type_expr (datum, component, NULL_TREE, protect);
-#endif
 
   if (! IS_AGGR_TYPE_CODE (code))
     {
@@ -1590,7 +1768,7 @@ build_component_ref (datum, component, basetype_path, protect)
       return error_mark_node;
     }
 
-  if (TYPE_SIZE (basetype) == 0)
+  if (TYPE_SIZE (complete_type (basetype)) == 0)
     {
       incomplete_type_error (0, basetype);
       return error_mark_node;
@@ -1609,7 +1787,7 @@ build_component_ref (datum, component, basetype_path, protect)
          cp_error ("type `%T' has no destructor", basetype);
          return error_mark_node;
        }
-      return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0);
+      return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 1);
     }
 
   /* Look up component name in the structure type definition.  */
@@ -1619,12 +1797,20 @@ build_component_ref (datum, component, basetype_path, protect)
        hierarchy, the compiler will abort (because vptr lookups are
        not supposed to be ambiguous.  */
     field = CLASSTYPE_VFIELD (basetype);
+  else if (TREE_CODE (component) == FIELD_DECL
+          || TREE_CODE (component) == TYPE_DECL)
+    {
+      field = component;
+    }
   else
     {
+      tree name = component;
+      if (TREE_CODE (component) == VAR_DECL)
+       name = DECL_NAME (component);
       if (basetype_path == NULL_TREE)
        basetype_path = TYPE_BINFO (basetype);
-      field = lookup_field (basetype_path, component,
-                           protect && ! VFIELD_NAME_P (component), 0);
+      field = lookup_field (basetype_path, name,
+                           protect && !VFIELD_NAME_P (name), 0);
       if (field == error_mark_node)
        return error_mark_node;
 
@@ -1633,7 +1819,7 @@ build_component_ref (datum, component, basetype_path, protect)
          /* Not found as a data field, look for it as a method.  If found,
             then if this is the only possible one, return it, else
             report ambiguity error.  */
-         tree fndecls = lookup_fnfields (basetype_path, component, 1);
+         tree fndecls = lookup_fnfields (basetype_path, name, 1);
          if (fndecls == error_mark_node)
            return error_mark_node;
          if (fndecls)
@@ -1641,27 +1827,30 @@ build_component_ref (datum, component, basetype_path, protect)
              if (TREE_CHAIN (fndecls) == NULL_TREE
                  && DECL_CHAIN (TREE_VALUE (fndecls)) == NULL_TREE)
                {
-                 enum access_type access;
-                 tree fndecl;
+                 tree access, fndecl;
 
                  /* Unique, so use this one now.  */
                  basetype = TREE_PURPOSE (fndecls);
                  fndecl = TREE_VALUE (fndecls);
                  access = compute_access (TREE_PURPOSE (fndecls), fndecl);
-                 if (access == access_public)
+                 if (access == access_public_node)
                    {
                      if (DECL_VINDEX (fndecl)
                          && ! resolves_to_fixed_type_p (datum, 0))
                        {
                          tree addr = build_unary_op (ADDR_EXPR, datum, 0);
+                         tree fntype = TREE_TYPE (fndecl);
+
                          addr = convert_pointer_to (DECL_CONTEXT (fndecl), addr);
                          datum = build_indirect_ref (addr, NULL_PTR);
                          my_friendly_assert (datum != error_mark_node, 310);
                          fndecl = build_vfn_ref (&addr, datum, DECL_VINDEX (fndecl));
+                         TREE_TYPE (fndecl) = build_pointer_type (fntype);
                        }
-                     return fndecl;
+                     mark_used (fndecl);
+                     return build (OFFSET_REF, TREE_TYPE (fndecl), datum, fndecl);
                    }
-                 if (access == access_protected)
+                 if (access == access_protected_node)
                    cp_error ("member function `%D' is protected", fndecl);
                  else
                    cp_error ("member function `%D' is private", fndecl);
@@ -1671,19 +1860,16 @@ build_component_ref (datum, component, basetype_path, protect)
                {
                  /* Just act like build_offset_ref, since the object does
                      not matter unless we're actually calling the function.  */
-                 tree t = build_tree_list (error_mark_node, fndecls);
+                 tree t;
+
+                 t = build_tree_list (error_mark_node, fndecls);
                  TREE_TYPE (t) = build_offset_type (basetype,
                                                     unknown_type_node);
                  return t;
                }
            }
 
-#if 0
-         if (component == ansi_opname[(int) TYPE_EXPR])
-           cp_error ("`%#T' has no such type conversion operator", basetype);
-         else
-#endif
-           cp_error ("`%#T' has no member named `%D'", basetype, component);
+         cp_error ("`%#T' has no member named `%D'", basetype, name);
          return error_mark_node;
        }
       else if (TREE_TYPE (field) == error_mark_node)
@@ -1696,26 +1882,60 @@ build_component_ref (datum, component, basetype_path, protect)
              cp_error ("invalid use of type decl `%#D' as expression", field);
              return error_mark_node;
            }
-         if (DECL_RTL (field) != 0)
-           assemble_external (field);
-         TREE_USED (field) = 1;
+         else if (DECL_RTL (field) != 0)
+           mark_used (field);
+         else
+           TREE_USED (field) = 1;
          return field;
        }
     }
 
-  if (DECL_FIELD_CONTEXT (field) != basetype
-      && TYPE_USES_COMPLEX_INHERITANCE (basetype))
+  /* See if we have to do any conversions so that we pick up the field from the
+     right context.  */
+  if (DECL_FIELD_CONTEXT (field) != basetype)
     {
-      tree addr = build_unary_op (ADDR_EXPR, datum, 0);
-      if (integer_zerop (addr))
+      tree context = DECL_FIELD_CONTEXT (field);
+      tree base = context;
+      while (base != basetype && TYPE_NAME (base)
+            && ANON_AGGRNAME_P (TYPE_IDENTIFIER (base)))
        {
-         error ("invalid reference to NULL ptr, use ptr-to-member instead");
-         return error_mark_node;
+         base = TYPE_CONTEXT (base);
+       }
+
+      /* Handle base classes here...  */
+      if (base != basetype && TYPE_USES_COMPLEX_INHERITANCE (basetype))
+       {
+         tree addr = build_unary_op (ADDR_EXPR, datum, 0);
+         if (integer_zerop (addr))
+           {
+             error ("invalid reference to NULL ptr, use ptr-to-member instead");
+             return error_mark_node;
+           }
+         if (VBASE_NAME_P (DECL_NAME (field)))
+           {
+             /* It doesn't matter which vbase pointer we grab, just
+                find one of them.  */
+             tree binfo = get_binfo (base,
+                                     TREE_TYPE (TREE_TYPE (addr)), 0);
+             addr = convert_pointer_to_real (binfo, addr);
+           }
+         else
+           addr = convert_pointer_to (base, addr);
+         datum = build_indirect_ref (addr, NULL_PTR);
+         my_friendly_assert (datum != error_mark_node, 311);
+       }
+      basetype = base;
+      /* Handle things from anon unions here...  */
+      if (TYPE_NAME (context) && ANON_AGGRNAME_P (TYPE_IDENTIFIER (context)))
+       {
+         tree subfield = lookup_anon_field (basetype, context);
+         tree subdatum = build_component_ref (datum, subfield,
+                                              basetype_path, protect);
+         return build_component_ref (subdatum, field, basetype_path, protect);
        }
-      addr = convert_pointer_to (DECL_FIELD_CONTEXT (field), addr);
-      datum = build_indirect_ref (addr, NULL_PTR);
-      my_friendly_assert (datum != error_mark_node, 311);
     }
+
   ref = fold (build (COMPONENT_REF, TREE_TYPE (field),
                     break_out_cleanups (datum), field));
 
@@ -1728,6 +1948,22 @@ build_component_ref (datum, component, basetype_path, protect)
 
   return ref;
 }
+
+/* Variant of build_component_ref for use in expressions, which should
+   never have REFERENCE_TYPE.  */
+
+tree
+build_x_component_ref (datum, component, basetype_path, protect)
+     tree datum, component, basetype_path;
+     int protect;
+{
+  tree t = build_component_ref (datum, component, basetype_path, protect);
+
+  if (! processing_template_decl)
+    t = convert_from_reference (t);
+
+  return t;
+}
 \f
 /* Given an expression PTR for a pointer, return an expression
    for the value pointed to.
@@ -1741,7 +1977,12 @@ build_x_indirect_ref (ptr, errorstring)
      tree ptr;
      char *errorstring;
 {
-  tree rval = build_opfncall (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE, NULL_TREE);
+  tree rval;
+
+  if (processing_template_decl)
+    return build_min_nt (INDIRECT_REF, ptr);
+
+  rval = build_opfncall (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE, NULL_TREE);
   if (rval)
     return rval;
   return build_indirect_ref (ptr, errorstring);
@@ -1752,17 +1993,38 @@ build_indirect_ref (ptr, errorstring)
      tree ptr;
      char *errorstring;
 {
-  register tree pointer = default_conversion (ptr);
-  register tree type = TREE_TYPE (pointer);
+  register tree pointer, type;
+
+  if (ptr == error_mark_node)
+    return error_mark_node;
+
+  pointer = (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE
+            ? ptr : default_conversion (ptr));
+  type = TREE_TYPE (pointer);
+
+  if (ptr == current_class_ptr)
+    return current_class_ref;
+
+  if (IS_AGGR_TYPE (type))
+    {
+      ptr = build_expr_type_conversion (WANT_POINTER, pointer, 1);
 
-  if (ptr == current_class_decl)
-    return C_C_D;
+      if (ptr)
+       {
+         pointer = ptr;
+         type = TREE_TYPE (pointer);
+       }
+    }
 
   if (TREE_CODE (type) == POINTER_TYPE || TREE_CODE (type) == REFERENCE_TYPE)
     {
       if (TREE_CODE (pointer) == ADDR_EXPR
-         && (TREE_TYPE (TREE_OPERAND (pointer, 0))
-             == TREE_TYPE (type)))
+         && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (pointer, 0)))
+             == TYPE_MAIN_VARIANT (TREE_TYPE (type)))
+         && (TREE_READONLY (TREE_OPERAND (pointer, 0))
+             == TYPE_READONLY (TREE_TYPE (type)))
+         && (TREE_THIS_VOLATILE (TREE_OPERAND (pointer, 0))
+             == TYPE_VOLATILE (TREE_TYPE (type))))
        return TREE_OPERAND (pointer, 0);
       else
        {
@@ -1808,21 +2070,9 @@ build_indirect_ref (ptr, errorstring)
    will inherit the type of the array, which will be some pointer type.  */
 
 tree
-build_x_array_ref (array, index)
-     tree array, index;
-{
-  tree rval = build_opfncall (ARRAY_REF, LOOKUP_NORMAL, array, index, NULL_TREE);
-  if (rval)
-    return rval;
-  return build_array_ref (array, index);
-}
-
-tree
 build_array_ref (array, idx)
      tree array, idx;
 {
-  tree itype;
-
   if (idx == 0)
     {
       error ("subscript missing in array reference");
@@ -1833,28 +2083,6 @@ build_array_ref (array, idx)
       || TREE_TYPE (idx) == error_mark_node)
     return error_mark_node;
 
-  itype = TREE_TYPE (idx);
-  /* We must check here for the reference, so we can do the possible
-     conversions immediately afterwards.  */
-  if (TREE_CODE (itype) == REFERENCE_TYPE)
-    {
-      idx = convert_from_reference (idx);
-      itype = TREE_TYPE (idx);
-    }
-
-  if (IS_AGGR_TYPE (itype))
-    {
-      if (TYPE_HAS_INT_CONVERSION (itype))
-       idx = build_type_conversion (CONVERT_EXPR,
-                                    integer_type_node, idx, 1);
-      else
-       {
-         error_with_aggr_type (itype,
-                               "type `%s' requires integer conversion for array indexing");
-         return error_mark_node;
-       }
-    }
-
   if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE
       && TREE_CODE (array) != INDIRECT_REF)
     {
@@ -1902,19 +2130,19 @@ build_array_ref (array, idx)
            return error_mark_node;
        }
 
-      /* Note in C++ we don't bother warning about subscripting a
-        `register' array, since it's valid in C++ to take the address
-        of something with that storage specification.  */
       if (pedantic && !lvalue_p (array))
        pedwarn ("ANSI C++ forbids subscripting non-lvalue array");
 
-      if (pedantic)
+      /* Note in C++ it is valid to subscript a `register' array, since
+        it is valid to take the address of something with that
+        storage specification.  */
+      if (extra_warnings)
        {
          tree foo = array;
          while (TREE_CODE (foo) == COMPONENT_REF)
            foo = TREE_OPERAND (foo, 0);
          if (TREE_CODE (foo) == VAR_DECL && DECL_REGISTER (foo))
-           pedwarn ("ANSI C++ forbids subscripting non-lvalue array");
+           warning ("subscripting array declared `register'");
        }
 
       type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (array)));
@@ -1970,8 +2198,9 @@ build_array_ref (array, idx)
 \f
 /* Build a function call to function FUNCTION with parameters PARAMS.
    PARAMS is a list--a chain of TREE_LIST nodes--in which the
-   TREE_VALUE of each node is a parameter-expression.
-   FUNCTION's data type may be a function type or a pointer-to-function.
+   TREE_VALUE of each node is a parameter-expression.  The PARAMS do
+   not include any object pointer that may be required.  FUNCTION's
+   data type may be a function type or a pointer-to-function.
 
    For C++: If FUNCTION's data type is a TREE_LIST, then the tree list
    is the list of possible methods that FUNCTION could conceivably
@@ -1986,12 +2215,11 @@ build_array_ref (array, idx)
    In the second case, TREE_PURPOSE (function) is the function's
    name directly.
 
-   DECL is the class instance variable, usually CURRENT_CLASS_DECL.  */
+   DECL is the class instance variable, usually CURRENT_CLASS_REF.
+
+   When calling a TEMPLATE_DECL, we don't require a complete return
+   type.  */
 
-/*
- * [eichin:19911015.1726EST] actually return a possibly incomplete
- * type
- */
 tree
 build_x_function_call (function, params, decl)
      tree function, params, decl;
@@ -2002,7 +2230,27 @@ build_x_function_call (function, params, decl)
   if (function == error_mark_node)
     return error_mark_node;
 
+  if (processing_template_decl)
+    return build_min_nt (CALL_EXPR, function, params, NULL_TREE);
+
   type = TREE_TYPE (function);
+
+  if (TREE_CODE (type) == OFFSET_TYPE
+      && TREE_TYPE (type) == unknown_type_node
+      && TREE_CODE (function) == TREE_LIST
+      && TREE_CHAIN (function) == NULL_TREE)
+    {
+      /* Undo (Foo:bar)()...  */
+      type = TYPE_OFFSET_BASETYPE (type);
+      function = TREE_VALUE (function);
+      my_friendly_assert (TREE_CODE (function) == TREE_LIST, 999);
+      my_friendly_assert (TREE_CHAIN (function) == NULL_TREE, 999);
+      function = TREE_VALUE (function);
+      my_friendly_assert (TREE_CODE (function) == FUNCTION_DECL, 999);
+      function = DECL_NAME (function);
+      return build_method_call (decl, function, params, TYPE_BINFO (type), LOOKUP_NORMAL);
+    }
+    
   is_method = ((TREE_CODE (function) == TREE_LIST
                && current_class_type != NULL_TREE
                && IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (function)) == function)
@@ -2010,11 +2258,20 @@ build_x_function_call (function, params, decl)
               || TREE_CODE (type) == METHOD_TYPE
               || TYPE_PTRMEMFUNC_P (type));
 
+  if (TREE_CODE (function) == FUNCTION_DECL
+      && DECL_STATIC_FUNCTION_P (function))
+    return build_member_call
+      (DECL_CONTEXT (function), DECL_NAME (function), params);
+
   /* Handle methods, friends, and overloaded functions, respectively.  */
   if (is_method)
     {
+      tree basetype = NULL_TREE;
+
       if (TREE_CODE (function) == FUNCTION_DECL)
        {
+         basetype = DECL_CLASS_CONTEXT (function);
+
          if (DECL_NAME (function))
            function = DECL_NAME (function);
          else
@@ -2022,15 +2279,9 @@ build_x_function_call (function, params, decl)
        }
       else if (TREE_CODE (function) == TREE_LIST)
        {
-#if 0
-         if (TREE_CODE (TREE_VALUE (function)) == TREE_LIST)
-           function = TREE_PURPOSE (TREE_VALUE (function));
-         else
-           function = TREE_PURPOSE (function);
-#else
          my_friendly_assert (TREE_CODE (TREE_VALUE (function)) == FUNCTION_DECL, 312);
+         basetype = DECL_CLASS_CONTEXT (TREE_VALUE (function));
          function = TREE_PURPOSE (function);
-#endif
        }
       else if (TREE_CODE (function) != IDENTIFIER_NODE)
        {
@@ -2057,6 +2308,10 @@ build_x_function_call (function, params, decl)
          must go through here in case it is a virtual function.
         @@ Perhaps this could be optimized.  */
 
+      if (basetype && (! current_class_type
+                      || ! DERIVED_FROM_P (basetype, current_class_type)))
+       return build_member_call (basetype, function, params);
+
       if (decl == NULL_TREE)
        {
          if (current_class_type == NULL_TREE)
@@ -2066,7 +2321,7 @@ build_x_function_call (function, params, decl)
              return error_mark_node;
            }
          /* Yow: call from a static member function.  */
-         decl = build1 (NOP_EXPR, TYPE_POINTER_TO (current_class_type),
+         decl = build1 (NOP_EXPR, build_pointer_type (current_class_type),
                         error_mark_node);
          decl = build_indirect_ref (decl, NULL_PTR);
        }
@@ -2079,7 +2334,7 @@ build_x_function_call (function, params, decl)
     {
       /* Should we undo what was done in build_component_ref? */
       if (TREE_CODE (TREE_PURPOSE (TREE_OPERAND (function, 1))) == TREE_VEC)
-       /* Get the name that build_component_ref hid. */
+       /* Get the name that build_component_ref hid.  */
        function = DECL_NAME (TREE_VALUE (TREE_OPERAND (function, 1)));
       else
        function = TREE_PURPOSE (TREE_OPERAND (function, 1));
@@ -2098,12 +2353,15 @@ build_x_function_call (function, params, decl)
        {
          tree val = TREE_VALUE (function);
 
+         if (flag_ansi_overloading)
+           return build_new_function_call (function, params, NULL_TREE);
+
          if (TREE_CODE (val) == TEMPLATE_DECL)
-           return build_overload_call_maybe
-             (function, params, LOOKUP_COMPLAIN, (struct candidate *)0);
+           return build_overload_call_real
+             (function, params, LOOKUP_COMPLAIN, (struct candidate *)0, 0);
          else if (DECL_CHAIN (val) != NULL_TREE)
            return build_overload_call
-             (function, params, LOOKUP_COMPLAIN, (struct candidate *)0);
+             (function, params, LOOKUP_COMPLAIN);
          else
            my_friendly_abort (360);
        }
@@ -2119,10 +2377,10 @@ build_x_function_call (function, params, decl)
       if (TREE_OPERAND (function, 0))
        decl = TREE_OPERAND (function, 0);
       else
-       decl = C_C_D;
+       decl = current_class_ref;
 
       decl_addr = build_unary_op (ADDR_EXPR, decl, 0);
-      function = get_member_function_from_ptrfunc (&decl_addr, decl,
+      function = get_member_function_from_ptrfunc (&decl_addr,
                                                   TREE_OPERAND (function, 1));
       params = tree_cons (NULL_TREE, decl_addr, params);
       return build_function_call (function, params);
@@ -2134,7 +2392,7 @@ build_x_function_call (function, params, decl)
       if (TREE_CODE (type) == REFERENCE_TYPE)
        type = TREE_TYPE (type);
 
-      if (TYPE_LANG_SPECIFIC (type) && TYPE_OVERLOADS_CALL_EXPR (type))
+      if (IS_AGGR_TYPE (type))
        return build_opfncall (CALL_EXPR, LOOKUP_NORMAL, function, params, NULL_TREE);
     }
 
@@ -2145,14 +2403,14 @@ build_x_function_call (function, params, decl)
 
       /* Explicitly named method?  */
       if (TREE_CODE (function) == FUNCTION_DECL)
-       ctypeptr = TYPE_POINTER_TO (DECL_CLASS_CONTEXT (function));
+       ctypeptr = build_pointer_type (DECL_CLASS_CONTEXT (function));
       /* Expression with ptr-to-method type?  It could either be a plain
         usage, or it might be a case where the ptr-to-method is being
         passed in as an argument.  */
       else if (TYPE_PTRMEMFUNC_P (fntype))
        {
          tree rec = TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (fntype)));
-         ctypeptr = TYPE_POINTER_TO (rec);
+         ctypeptr = build_pointer_type (rec);
        }
       /* Unexpected node type?  */
       else
@@ -2173,7 +2431,7 @@ build_x_function_call (function, params, decl)
          decl = convert_pointer_to (TREE_TYPE (ctypeptr), decl);
        }
       else
-       decl = build_c_cast (ctypeptr, decl, 0);
+       decl = build_c_cast (ctypeptr, decl);
       params = tree_cons (NULL_TREE, decl, params);
     }
 
@@ -2184,9 +2442,8 @@ build_x_function_call (function, params, decl)
    instance to use, if the member points to a virtual member.  */
 
 tree
-get_member_function_from_ptrfunc (instance_ptrptr, instance, function)
+get_member_function_from_ptrfunc (instance_ptrptr, function)
      tree *instance_ptrptr;
-     tree instance;
      tree function;
 {
   if (TREE_CODE (function) == OFFSET_REF)
@@ -2196,23 +2453,32 @@ get_member_function_from_ptrfunc (instance_ptrptr, instance, function)
 
   if (TYPE_PTRMEMFUNC_P (TREE_TYPE (function)))
     {
-      tree fntype = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function));
-      tree index = save_expr (build_component_ref (function,
-                                                  index_identifier,
-                                                  0, 0));
-      tree e1 = build (GT_EXPR, delta_type_node, index,
-                      convert (delta_type_node, integer_zero_node));
-      tree delta = convert (ptrdiff_type_node,
-                           build_component_ref (function, delta_identifier, 0, 0));
-      tree delta2 = DELTA2_FROM_PTRMEMFUNC (function);
-      tree e2;
-      tree e3;
-      tree aref, vtbl;
-
-      /* convert down to the right base, before using the instance. */
-      instance = convert_pointer_to_real (TYPE_METHOD_BASETYPE (TREE_TYPE (fntype)),
-                                         build_unary_op (ADDR_EXPR, instance, 0));
-      if (instance == error_mark_node)
+      tree fntype, idx, e1, delta, delta2, e2, e3, aref, vtbl;
+      tree instance;
+
+      tree instance_ptr = *instance_ptrptr;
+
+      if (TREE_SIDE_EFFECTS (instance_ptr))
+       instance_ptr = save_expr (instance_ptr);
+
+      if (TREE_SIDE_EFFECTS (function))
+       function = save_expr (function);
+
+      fntype = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function));
+      idx = save_expr (build_component_ref (function,
+                                           index_identifier,
+                                           NULL_TREE, 0));
+      e1 = fold (build (GT_EXPR, boolean_type_node, idx,
+                       convert (delta_type_node, integer_zero_node)));
+      delta = convert (ptrdiff_type_node,
+                      build_component_ref (function, delta_identifier, NULL_TREE, 0));
+      delta2 = DELTA2_FROM_PTRMEMFUNC (function);
+
+      /* convert down to the right base, before using the instance.  */
+      instance
+       = convert_pointer_to_real (TYPE_METHOD_BASETYPE (TREE_TYPE (fntype)),
+                                  instance_ptr);
+      if (instance == error_mark_node && instance_ptr != error_mark_node)
        return instance;
 
       vtbl = convert_pointer_to (ptr_type_node, instance);
@@ -2222,33 +2488,40 @@ get_member_function_from_ptrfunc (instance_ptrptr, instance, function)
                 vtbl, convert (ptrdiff_type_node, delta2));
       vtbl = build_indirect_ref (vtbl, NULL_PTR);
       aref = build_array_ref (vtbl, build_binary_op (MINUS_EXPR,
-                                                    index,
+                                                    idx,
                                                     integer_one_node, 1));
       if (! flag_vtable_thunks)
        {
          aref = save_expr (aref);
 
-         /* Save the intermediate result in a SAVE_EXPR so we don't have to
-            compute each component of the virtual function pointer twice.  */ 
-         if (/* !building_cleanup && */ TREE_CODE (aref) == INDIRECT_REF)
-           TREE_OPERAND (aref, 0) = save_expr (TREE_OPERAND (aref, 0));
-      
          delta = build_binary_op (PLUS_EXPR,
-                                  build_conditional_expr (e1, build_component_ref (aref, delta_identifier, 0, 0), integer_zero_node),
+                                  build_conditional_expr (e1, build_component_ref (aref, delta_identifier, NULL_TREE, 0), integer_zero_node),
                                   delta, 1);
        }
 
-      *instance_ptrptr = build (PLUS_EXPR, TREE_TYPE (*instance_ptrptr),
-                               *instance_ptrptr,
-                               delta);
+      *instance_ptrptr = build (PLUS_EXPR, TREE_TYPE (instance_ptr),
+                               instance_ptr, delta);
       if (flag_vtable_thunks)
        e2 = aref;
       else
-       e2 = build_component_ref (aref, pfn_identifier, 0, 0);
+       e2 = build_component_ref (aref, pfn_identifier, NULL_TREE, 0);
 
       e3 = PFN_FROM_PTRMEMFUNC (function);
       TREE_TYPE (e2) = TREE_TYPE (e3);
-      function = build_conditional_expr (e1, e2, e3);
+      e1 = build_conditional_expr (e1, e2, e3);
+
+      if (instance_ptr == error_mark_node
+         && TREE_CODE (e1) != ADDR_EXPR
+         && TREE_CODE (TREE_OPERAND (e1, 0)) != FUNCTION_DECL)
+       cp_error ("object missing in `%E'", function);
+
+      function = e1;
+
+      /* Make sure this doesn't get evaluated first inside one of the
+         branches of the COND_EXPR.  */
+      if (TREE_CODE (instance_ptr) == SAVE_EXPR)
+       function = build (COMPOUND_EXPR, TREE_TYPE (function),
+                         instance_ptr, function);
     }
   return function;
 }
@@ -2278,7 +2551,7 @@ build_function_call_real (function, params, require_complete, flags)
       GNU_xref_call (current_function_decl,
                     IDENTIFIER_POINTER (name ? name
                                         : TYPE_IDENTIFIER (DECL_CLASS_CONTEXT (function))));
-      assemble_external (function);
+      mark_used (function);
       fndecl = function;
 
       /* Convert anything with function type to a pointer-to-function.  */
@@ -2291,41 +2564,38 @@ build_function_call_real (function, params, require_complete, flags)
          pedwarn ("ANSI C++ forbids calling `main' from within program");
        }
 
+      if (pedantic && DECL_THIS_INLINE (function) && ! DECL_INITIAL (function)
+         && ! DECL_ARTIFICIAL (function)
+         && ! DECL_PENDING_INLINE_INFO (function))
+       cp_pedwarn ("inline function `%#D' called before definition",
+                   function);
+
       /* Differs from default_conversion by not setting TREE_ADDRESSABLE
         (because calling an inline function does not mean the function
         needs to be separately compiled).  */
 
       if (DECL_INLINE (function))
-       {
-         fntype = build_type_variant (TREE_TYPE (function),
-                                      TREE_READONLY (function),
-                                      TREE_THIS_VOLATILE (function));
-         function = build1 (ADDR_EXPR, build_pointer_type (fntype), function);
-       }
+       function = inline_conversion (function);
       else
-       {
-         assemble_external (function);
-         TREE_USED (function) = 1;
-         function = default_conversion (function);
-       }
+       function = build_addr_func (function);
     }
   else
     {
       fndecl = NULL_TREE;
 
-      /* Convert anything with function type to a pointer-to-function.  */
-      if (function == error_mark_node)
-       return error_mark_node;
-      function = default_conversion (function);
+      function = build_addr_func (function);
     }
 
+  if (function == error_mark_node)
+    return error_mark_node;
+
   fntype = TREE_TYPE (function);
 
   if (TYPE_PTRMEMFUNC_P (fntype))
     {
-      tree instance_ptr = build_unary_op (ADDR_EXPR, C_C_D, 0);
-      fntype = TYPE_PTRMEMFUNC_FN_TYPE (fntype);
-      function = get_member_function_from_ptrfunc (&instance_ptr, C_C_D, function);
+      cp_error ("must use .* or ->* to call pointer-to-member function in `%E (...)'",
+               function);
+      return error_mark_node;
     }
 
   is_method = (TREE_CODE (fntype) == POINTER_TYPE
@@ -2335,7 +2605,7 @@ build_function_call_real (function, params, require_complete, flags)
         && TREE_CODE (TREE_TYPE (fntype)) == FUNCTION_TYPE)
        || is_method))
     {
-      error ("called object is not a function");
+      cp_error ("`%E' cannot be used as a function", function);
       return error_mark_node;
     }
 
@@ -2352,6 +2622,12 @@ build_function_call_real (function, params, require_complete, flags)
     coerced_params = convert_arguments (NULL_TREE, TYPE_ARG_TYPES (fntype),
                                        params, fndecl, 0);
 
+  if (coerced_params == error_mark_node)
+    if (flags & LOOKUP_SPECULATIVELY)
+      return NULL_TREE;
+    else
+      return error_mark_node;
+
   /* Check for errors in format strings.  */
 
   if (warn_format && (name || assembler_name))
@@ -2377,16 +2653,18 @@ build_function_call_real (function, params, require_complete, flags)
   /* C++ */
   value_type = TREE_TYPE (fntype) ? TREE_TYPE (fntype) : void_type_node;
   {
-    register tree result = 
-      build (CALL_EXPR, value_type,
-            function, coerced_params, NULL_TREE);
+    register tree result
+      = build_call (function, value_type, coerced_params);
 
-    TREE_SIDE_EFFECTS (result) = 1;
-    if (! require_complete)
-      return result;
-    if (value_type == void_type_node)
-      return result;
-    return require_complete_type (result);
+    if (require_complete)
+      {
+       if (value_type == void_type_node)
+         return result;
+       result = require_complete_type (result);
+      }
+    if (IS_AGGR_TYPE (value_type))
+      result = build_cplus_new (value_type, result);
+    return convert_from_reference (result);
   }
 }
 
@@ -2396,14 +2674,6 @@ build_function_call (function, params)
 {
   return build_function_call_real (function, params, 1, LOOKUP_NORMAL);
 }
-     
-tree
-build_function_call_maybe (function, params)
-     tree function, params;
-{
-  return build_function_call_real (function, params, 0, 0);
-}
-
 \f
 /* Convert the actual parameter expressions in the list VALUES
    to the types in the list TYPELIST.
@@ -2433,7 +2703,6 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
      tree return_loc, typelist, values, fndecl;
      int flags;
 {
-  extern tree gc_protect_fndecl;
   register tree typetail, valtail;
   register tree result = NULL_TREE;
   char *called_thing;
@@ -2442,6 +2711,9 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
   if (! flag_elide_constructors)
     return_loc = 0;
 
+  /* Argument passing is always copy-initialization.  */
+  flags |= LOOKUP_ONLYCONVERTING;
+
   if (fndecl)
     {
       if (TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE)
@@ -2463,13 +2735,15 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
       register tree type = typetail ? TREE_VALUE (typetail) : 0;
       register tree val = TREE_VALUE (valtail);
 
+      if (val == error_mark_node)
+       return error_mark_node;
+
       if (type == void_type_node)
        {
          if (fndecl)
            {
-             char *buf = (char *)alloca (40 + strlen (called_thing));
-             sprintf (buf, "too many arguments to %s `%%s'", called_thing);
-             error_with_decl (fndecl, buf);
+             cp_error_at ("too many arguments to %s `%+D'", called_thing,
+                          fndecl);
              error ("at this point in file");
            }
          else
@@ -2508,28 +2782,12 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
       else if (TREE_CODE (val) == OFFSET_REF
            && TREE_CODE (TREE_TYPE (val)) == METHOD_TYPE)
        {
-         /* This is unclean.  Should be handled elsewhere. */
+         /* This is unclean.  Should be handled elsewhere.  */
          val = build_unary_op (ADDR_EXPR, val, 0);
        }
       else if (TREE_CODE (val) == OFFSET_REF)
        val = resolve_offset_ref (val);
 
-      {
-#if 0
-       /* This code forces the assumption that if we have a ptr-to-func
-          type in an arglist, that every routine that wants to check
-          its validity has done so, and thus we need not do any
-          more conversion.  I don't remember why this is necessary.  */
-       else if (TREE_CODE (ttype) == FUNCTION_TYPE
-                && (type == NULL
-                    || TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
-                    || TREE_CODE (TREE_TYPE (type)) == VOID_TYPE))
-         {
-           type = build_pointer_type (ttype);
-         }
-#endif
-      }
-
       /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
         Strip such NOP_EXPRs, since VAL is used in non-lvalue context.  */
       if (TREE_CODE (val) == NOP_EXPR
@@ -2548,32 +2806,23 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
        }
 
       if (val == error_mark_node)
-       continue;
+       return error_mark_node;
 
       if (type != 0)
        {
          /* Formal parm type is specified by a function prototype.  */
          tree parmval;
 
-         if (TYPE_SIZE (type) == 0)
+         if (TYPE_SIZE (complete_type (type)) == 0)
            {
              error ("parameter type of called function is incomplete");
              parmval = val;
            }
          else
            {
-#if 0 && defined (PROMOTE_PROTOTYPES)
-             /* This breaks user-defined conversions.  */
-             /* Rather than truncating and then reextending,
-                convert directly to int, if that's the type we will want.  */
-             if (! flag_traditional
-                 && (TREE_CODE (type) == INTEGER_TYPE
-                     || TREE_CODE (type) == ENUMERAL_TYPE)
-                 && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
-               type = integer_type_node;
-#endif
-             parmval = convert_for_initialization (return_loc, type, val, flags,
-                                                   "argument passing", fndecl, i);
+             parmval = convert_for_initialization
+               (return_loc, type, val, flags,
+                "argument passing", fndecl, i);
 #ifdef PROMOTE_PROTOTYPES
              if ((TREE_CODE (type) == INTEGER_TYPE
                   || TREE_CODE (type) == ENUMERAL_TYPE)
@@ -2581,6 +2830,10 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
                parmval = default_conversion (parmval);
 #endif
            }
+
+         if (parmval == error_mark_node)
+           return error_mark_node;
+
          result = tree_cons (NULL_TREE, parmval, result);
        }
       else
@@ -2594,8 +2847,7 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
            /* Convert `float' to `double'.  */
            result = tree_cons (NULL_TREE, convert (double_type_node, val), result);
          else if (TYPE_LANG_SPECIFIC (TREE_TYPE (val))
-                  && (TYPE_HAS_INIT_REF (TREE_TYPE (val))
-                      || TYPE_HAS_ASSIGN_REF (TREE_TYPE (val))))
+                  && ! TYPE_HAS_TRIVIAL_INIT_REF (TREE_TYPE (val)))
            {
              cp_warning ("cannot pass objects of type `%T' through `...'",
                          TREE_TYPE (val));
@@ -2606,17 +2858,6 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
            result = tree_cons (NULL_TREE, default_conversion (val), result);
        }
 
-      if (flag_gc
-         /* There are certain functions for which we don't need
-            to protect our arguments.  GC_PROTECT_FNDECL is one.  */
-         && fndecl != gc_protect_fndecl
-         && type_needs_gc_entry (TREE_TYPE (TREE_VALUE (result)))
-         && ! value_safe_from_gc (NULL_TREE, TREE_VALUE (result)))
-       /* This will build a temporary variable whose cleanup is
-          to clear the obstack entry.  */
-       TREE_VALUE (result) = protect_value_from_gc (NULL_TREE,
-                                                    TREE_VALUE (result));
-
       if (typetail)
        typetail = TREE_CHAIN (typetail);
     }
@@ -2629,7 +2870,7 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
          for (; typetail != void_list_node; ++i)
            {
              tree type = TREE_VALUE (typetail);
-             tree val = TREE_PURPOSE (typetail);
+             tree val = break_out_target_exprs (TREE_PURPOSE (typetail));
              tree parmval;
 
              if (val == NULL_TREE)
@@ -2656,10 +2897,8 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
 #endif
                }
 
-             if (flag_gc
-                 && type_needs_gc_entry (TREE_TYPE (parmval))
-                 && ! value_safe_from_gc (NULL_TREE, parmval))
-               parmval = protect_value_from_gc (NULL_TREE, parmval);
+             if (parmval == error_mark_node)
+               return error_mark_node;
 
              result = tree_cons (0, parmval, result);
              typetail = TREE_CHAIN (typetail);
@@ -2694,8 +2933,16 @@ build_x_binary_op (code, arg1, arg2)
      enum tree_code code;
      tree arg1, arg2;
 {
-  tree rval = build_opfncall (code, LOOKUP_SPECULATIVELY,
-                             arg1, arg2, NULL_TREE);
+  tree rval;
+
+  if (processing_template_decl)
+    return build_min_nt (code, arg1, arg2);
+
+  if (flag_ansi_overloading)
+    return build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE);
+
+  rval = build_opfncall (code, LOOKUP_SPECULATIVELY,
+                        arg1, arg2, NULL_TREE);
   if (rval)
     return build_opfncall (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE);
   if (code == MEMBER_REF)
@@ -2710,7 +2957,6 @@ build_binary_op (code, arg1, arg2, convert_p)
      tree arg1, arg2;
      int convert_p;
 {
-  tree type1, type2;
   tree args[2];
 
   args[0] = arg1;
@@ -2718,62 +2964,37 @@ build_binary_op (code, arg1, arg2, convert_p)
 
   if (convert_p)
     {
-      args[0] = default_conversion (args[0]);
-      args[1] = default_conversion (args[1]);
+      tree type0, type1;
+      args[0] = decay_conversion (args[0]);
+      args[1] = decay_conversion (args[1]);
+
+      if (args[0] == error_mark_node || args[1] == error_mark_node)
+       return error_mark_node;
+
+      type0 = TREE_TYPE (args[0]);
+      type1 = TREE_TYPE (args[1]);
 
       if (type_unknown_p (args[0]))
        {
-         args[0] = instantiate_type (TREE_TYPE (args[1]), args[0], 1);
-         args[0] = default_conversion (args[0]);
+         args[0] = instantiate_type (type1, args[0], 1);
+         args[0] = decay_conversion (args[0]);
        }
       else if (type_unknown_p (args[1]))
        {
-         args[1] = require_instantiated_type (TREE_TYPE (args[0]),
-                                              args[1],
+         args[1] = require_instantiated_type (type0, args[1],
                                               error_mark_node);
-         args[1] = default_conversion (args[1]);
+         args[1] = decay_conversion (args[1]);
        }
 
-      type1 = TREE_TYPE (args[0]);
-      type2 = TREE_TYPE (args[1]);
-
-      if (IS_AGGR_TYPE_2 (type1, type2))
+      if (IS_AGGR_TYPE (type0) || IS_AGGR_TYPE (type1))
        {
          /* Try to convert this to something reasonable.  */
          if (! build_default_binary_type_conversion(code, &args[0], &args[1]))
-           return error_mark_node;
-       }
-      else if (IS_AGGR_TYPE (type1) || IS_AGGR_TYPE (type2))
-       {
-         int convert_index = IS_AGGR_TYPE (type2);
-         /* Avoid being tripped up by things like (ARG1 != 0).  */
-         tree types[2], try;
-         
-         types[0] = type1; types[1] = type2;
-         if (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)
-           try = build_type_conversion (code, boolean_type_node,
-                                        args[convert_index], 1);
-         else
-           {
-             try = build_type_conversion (code, types[convert_index ^ 1],
-                                          args[convert_index], 1);
-         
-             if (try == 0
-                 && args[1] == integer_zero_node
-                 && (code == NE_EXPR || code == EQ_EXPR))
-               try = build_type_conversion (code, ptr_type_node,
-                                            args[convert_index], 1);
-           }
-
-         if (try == 0)
            {
              cp_error ("no match for `%O(%#T, %#T)'", code,
                        TREE_TYPE (arg1), TREE_TYPE (arg2));
              return error_mark_node;
            }
-         if (try == error_mark_node)
-           error ("ambiguous pointer conversion");
-         args[convert_index] = try;
        }
     }
   return build_binary_op_nodefault (code, args[0], args[1], code);
@@ -2824,8 +3045,12 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
      Zero means they need to be converted to RESULT_TYPE.  */
   int converted = 0;
 
+  /* Nonzero means create the expression with this type, rather than
+     RESULT_TYPE.  */
+  tree build_type = 0;
+
   /* Nonzero means after finally constructing the expression
-     give it this type.  Otherwise, give it type RESULT_TYPE.  */
+     convert it to this type.  */
   tree final_type = 0;
 
   /* Nonzero if this is an operation like MIN or MAX which can
@@ -2849,8 +3074,18 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
   int common = 0;
 
   /* Apply default conversions.  */
-  op0 = default_conversion (orig_op0);
-  op1 = default_conversion (orig_op1);
+  if (code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR
+      || code == TRUTH_OR_EXPR || code == TRUTH_ORIF_EXPR
+      || code == TRUTH_XOR_EXPR)
+    {
+      op0 = decay_conversion (orig_op0);
+      op1 = decay_conversion (orig_op1);
+    }
+  else
+    {
+      op0 = default_conversion (orig_op0);
+      op1 = default_conversion (orig_op1);
+    }
 
   type0 = TREE_TYPE (op0);
   type1 = TREE_TYPE (op1);
@@ -2916,7 +3151,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
            resultcode = RDIV_EXPR;
          else
            /* When dividing two signed integers, we have to promote to int.
-              unless we divide by a conatant != -1.  Note that default
+              unless we divide by a constant != -1.  Note that default
               conversion will have been performed on the operands at this
               point, so we have to dig out the original type to find out if
               it was unsigned.  */
@@ -2987,9 +3222,6 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
     case TRUTH_AND_EXPR:
     case TRUTH_OR_EXPR:
       result_type = boolean_type_node;
-      op0 = bool_truthvalue_conversion (op0);
-      op1 = bool_truthvalue_conversion (op1);
-      converted = 1;
       break;
 
       /* Shift operations: result has same type as first operand;
@@ -3070,8 +3302,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
 
     case EQ_EXPR:
     case NE_EXPR:
-      result_type = boolean_type_node;
-      converted = 1;
+      build_type = boolean_type_node; 
       if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
          && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
        short_compare = 1;
@@ -3079,38 +3310,16 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
        {
          register tree tt0 = TYPE_MAIN_VARIANT (TREE_TYPE (type0));
          register tree tt1 = TYPE_MAIN_VARIANT (TREE_TYPE (type1));
-         /* Anything compares with void *.  void * compares with anything.
-            Otherwise, the targets must be the same.  */
-         if (tt0 != tt1 && TREE_CODE (tt0) == RECORD_TYPE
-             && TREE_CODE (tt1) == RECORD_TYPE)
-           {
-             tree base = common_base_type (tt0, tt1);
-             if (base == NULL_TREE)
-               cp_warning ("comparison of distinct object pointer types `%T' and `%T'", type0, type1);
-             else if (base == error_mark_node)
-               {
-                 cp_error ("comparison of pointer types `%T' and `%T' requires conversion to ambiguous supertype", type0, type1);
-                 return error_mark_node;
-               }
-             else
-               {
-                 if (integer_zerop (op0))
-                   op0 = null_pointer_node;
-                 else
-                   op0 = convert_pointer_to (base, op0);
-                 if (integer_zerop (op1))
-                   op1 = null_pointer_node;
-                 else
-                   op1 = convert_pointer_to (base, op1);
-               }
-           }
-         else if (comp_target_types (type0, type1, 1))
-           ;
+
+         if (comp_target_types (type0, type1, 1))
+           result_type = common_type (type0, type1);
          else if (tt0 == void_type_node)
            {
              if (pedantic && TREE_CODE (tt1) == FUNCTION_TYPE
                  && tree_int_cst_lt (TYPE_SIZE (type0), TYPE_SIZE (type1)))
                pedwarn ("ANSI C++ forbids comparison of `void *' with function pointer");
+             else if (TREE_CODE (tt1) == OFFSET_TYPE)
+               pedwarn ("ANSI C++ forbids conversion of a pointer to member to `void *'");
            }
          else if (tt1 == void_type_node)
            {
@@ -3118,42 +3327,42 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
                  && tree_int_cst_lt (TYPE_SIZE (type1), TYPE_SIZE (type0)))
                pedwarn ("ANSI C++ forbids comparison of `void *' with function pointer");
            }
-         else if ((TYPE_SIZE (tt0) != 0) != (TYPE_SIZE (tt1) != 0))
-           cp_pedwarn ("comparison of %scomplete and %scomplete pointers `%T' and `%T'",
-                       TYPE_SIZE (tt0) == 0 ? "in" : "",
-                       TYPE_SIZE (tt1) == 0 ? "in" : "",
-                       type0, type1);
          else
            cp_pedwarn ("comparison of distinct pointer types `%T' and `%T' lacks a cast",
                        type0, type1);
+
+         if (result_type == NULL_TREE)
+           result_type = ptr_type_node;
        }
       else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
               && integer_zerop (op1))
-       op1 = null_pointer_node;
+       result_type = type0;
       else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
               && integer_zerop (op0))
-       op0 = null_pointer_node;
+       result_type = type1;
       else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
        {
+         result_type = type0;
          error ("ANSI C++ forbids comparison between pointer and integer");
-         op1 = convert (TREE_TYPE (op0), op1);
        }
       else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
        {
+         result_type = type1;
          error ("ANSI C++ forbids comparison between pointer and integer");
-         op0 = convert (TREE_TYPE (op1), op0);
        }
       else if (TYPE_PTRMEMFUNC_P (type0) && TREE_CODE (op1) == INTEGER_CST
               && integer_zerop (op1))
        {
-         op0 = build_component_ref (op0, index_identifier, 0, 0);
+         op0 = build_component_ref (op0, index_identifier, NULL_TREE, 0);
          op1 = integer_zero_node;
+         result_type = TREE_TYPE (op0);
        }
       else if (TYPE_PTRMEMFUNC_P (type1) && TREE_CODE (op0) == INTEGER_CST
               && integer_zerop (op0))
        {
-         op0 = build_component_ref (op1, index_identifier, 0, 0);
+         op0 = build_component_ref (op1, index_identifier, NULL_TREE, 0);
          op1 = integer_zero_node;
+         result_type = TREE_TYPE (op0);
        }
       else if (TYPE_PTRMEMFUNC_P (type0) && TYPE_PTRMEMFUNC_P (type1)
               && (TYPE_PTRMEMFUNC_FN_TYPE (type0)
@@ -3165,8 +3374,8 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
           && ((op1.index != -1 && op0.delta2 == op1.delta2)
               || op0.pfn == op1.pfn)) */
 
-         tree index0 = build_component_ref (op0, index_identifier, 0, 0);
-         tree index1 = save_expr (build_component_ref (op1, index_identifier, 0, 0));
+         tree index0 = build_component_ref (op0, index_identifier, NULL_TREE, 0);
+         tree index1 = save_expr (build_component_ref (op1, index_identifier, NULL_TREE, 0));
          tree pfn0 = PFN_FROM_PTRMEMFUNC (op0);
          tree pfn1 = PFN_FROM_PTRMEMFUNC (op1);
          tree delta20 = DELTA2_FROM_PTRMEMFUNC (op0);
@@ -3187,7 +3396,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
       else if (TYPE_PTRMEMFUNC_P (type0)
               && TYPE_PTRMEMFUNC_FN_TYPE (type0) == type1)
        {
-         tree index0 = build_component_ref (op0, index_identifier, 0, 0);
+         tree index0 = build_component_ref (op0, index_identifier, NULL_TREE, 0);
          tree index1;
          tree pfn0 = PFN_FROM_PTRMEMFUNC (op0);
          tree delta20 = DELTA2_FROM_PTRMEMFUNC (op0);
@@ -3229,10 +3438,6 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
        {
          return build_binary_op (code, op1, op0, 1);
        }
-      else
-       /* If args are not valid, clear out RESULT_TYPE
-          to cause an error message later.  */
-       result_type = 0;
       break;
 
     case MAX_EXPR:
@@ -3242,19 +3447,14 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
        shorten = 1;
       else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
        {
-         if (! comp_target_types (type0, type1, 1))
-           cp_pedwarn ("comparison of distinct pointer types `%T' and `%T' lacks a cast",
-                       type0, type1);
-         else if ((TYPE_SIZE (TREE_TYPE (type0)) != 0)
-                  != (TYPE_SIZE (TREE_TYPE (type1)) != 0))
-           cp_pedwarn ("comparison of %scomplete and %scomplete pointers",
-                       TYPE_SIZE (TREE_TYPE (type0)) == 0 ? "in" : "",
-                       TYPE_SIZE (TREE_TYPE (type1)) == 0 ? "in" : "",
-                       type0, type1);
-         else if (pedantic
-                  && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
-           pedwarn ("ANSI C++ forbids ordered comparisons of pointers to functions");
-         result_type = common_type (type0, type1);
+         if (comp_target_types (type0, type1, 1))
+           result_type = common_type (type0, type1);
+         else
+           {
+             cp_pedwarn ("comparison of distinct pointer types `%T' and `%T' lacks a cast",
+                         type0, type1);
+             result_type = ptr_type_node;
+           }
        }
       break;
 
@@ -3262,58 +3462,37 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
     case GE_EXPR:
     case LT_EXPR:
     case GT_EXPR:
-      result_type = boolean_type_node;
+      build_type = boolean_type_node;
       if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
           && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
        short_compare = 1;
       else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
        {
-         if (! comp_target_types (type0, type1, 1))
-           cp_pedwarn ("comparison of distinct pointer types `%T' and `%T' lacks a cast",
-                       type0, type1);
-         else if ((TYPE_SIZE (TREE_TYPE (type0)) != 0)
-                  != (TYPE_SIZE (TREE_TYPE (type1)) != 0))
-           cp_pedwarn ("comparison of %scomplete and %scomplete pointers",
-                       TYPE_SIZE (TREE_TYPE (type0)) == 0 ? "in" : "",
-                       TYPE_SIZE (TREE_TYPE (type1)) == 0 ? "in" : "",
-                       type0, type1);
-         else if (pedantic 
-                  && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
-           pedwarn ("ANSI C++ forbids ordered comparisons of pointers to functions");
+         if (comp_target_types (type0, type1, 1))
+           result_type = common_type (type0, type1);
+         else
+           {
+             cp_pedwarn ("comparison of distinct pointer types `%T' and `%T' lacks a cast",
+                         type0, type1);
+             result_type = ptr_type_node;
+           }
        }
       else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
               && integer_zerop (op1))
-       {
-         op1 = null_pointer_node;
-         if (pedantic)
-           pedwarn ("ordered comparison of pointer with integer zero");
-       }
+       result_type = type0;
       else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
               && integer_zerop (op0))
-       {
-         op0 = null_pointer_node;
-         if (pedantic)
-           pedwarn ("ANSI C++ forbids ordered comparison of pointer with integer zero");
-       }
+       result_type = type1;
       else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
        {
-         if (pedantic)
-           pedwarn ("ANSI C++ forbids comparison between pointer and integer");
-         else if (! flag_traditional)
-           warning ("comparison between pointer and integer");
-         op1 = convert (TREE_TYPE (op0), op1);
+         result_type = type0;
+         pedwarn ("ANSI C++ forbids comparison between pointer and integer");
        }
       else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
        {
-         if (pedantic)
-           pedwarn ("ANSI C++ forbids comparison between pointer and integer");
-         else if (! flag_traditional)
-           warning ("comparison between pointer and integer");
-         op0 = convert (TREE_TYPE (op1), op0);
+         result_type = type1;
+         pedwarn ("ANSI C++ forbids comparison between pointer and integer");
        }
-      else
-       result_type = 0;
-      converted = 1;
       break;
     }
 
@@ -3420,7 +3599,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
                 it never happens because available widths are 2**N.  */
              && (!TREE_UNSIGNED (final_type)
                  || unsigned_arg
-                 || ((unsigned) 2 * TYPE_PRECISION (TREE_TYPE (arg0))
+                 || (((unsigned) 2 * TYPE_PRECISION (TREE_TYPE (arg0)))
                      <= TYPE_PRECISION (result_type))))
            {
              /* Do an unsigned shift if the operand was zero-extended.  */
@@ -3449,25 +3628,63 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
            = shorten_compare (&xop0, &xop1, &xresult_type, &xresultcode);
          if (val != 0)
            return convert (boolean_type_node, val);
-         op0 = xop0, op1 = xop1, result_type = boolean_type_node;
+         op0 = xop0, op1 = xop1;
+         converted = 1;
          resultcode = xresultcode;
        }
 
-      if (short_compare && extra_warnings)
+      if (short_compare && warn_sign_compare)
        {
+         int op0_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op0));
+         int op1_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op1));
+
          int unsignedp0, unsignedp1;
          tree primop0 = get_narrower (op0, &unsignedp0);
          tree primop1 = get_narrower (op1, &unsignedp1);
 
-         /* Warn if signed and unsigned are being compared in a size larger
-            than their original size, as this will always fail.  */
+         /* Check for comparison of different enum types.  */
+         if (flag_int_enum_equivalence == 0 
+             && TREE_CODE (TREE_TYPE (orig_op0)) == ENUMERAL_TYPE 
+             && TREE_CODE (TREE_TYPE (orig_op1)) == ENUMERAL_TYPE 
+             && TYPE_MAIN_VARIANT (TREE_TYPE (orig_op0))
+                != TYPE_MAIN_VARIANT (TREE_TYPE (orig_op1)))
+           {
+             cp_warning ("comparison between `%#T' and `%#T'", 
+                         TREE_TYPE (orig_op0), TREE_TYPE (orig_op1));
+           }
 
-         if (unsignedp0 != unsignedp1
-             && (TYPE_PRECISION (TREE_TYPE (primop0))
-                 < TYPE_PRECISION (result_type))
-             && (TYPE_PRECISION (TREE_TYPE (primop1))
-                 < TYPE_PRECISION (result_type)))
-           warning ("comparison between promoted unsigned and signed");
+         /* Give warnings for comparisons between signed and unsigned
+            quantities that may fail.  */
+         /* Do the checking based on the original operand trees, so that
+            casts will be considered, but default promotions won't be.  */
+
+         /* Do not warn if the comparison is being done in a signed type,
+            since the signed type will only be chosen if it can represent
+            all the values of the unsigned type.  */
+         if (! TREE_UNSIGNED (result_type))
+           /* OK */;
+         /* Do not warn if both operands are unsigned.  */
+         else if (op0_signed == op1_signed)
+           /* OK */;
+         /* Do not warn if the signed quantity is an unsuffixed
+            integer literal (or some static constant expression
+            involving such literals) and it is non-negative.  */
+         else if ((op0_signed && TREE_CODE (orig_op0) == INTEGER_CST
+                   && tree_int_cst_sgn (orig_op0) >= 0)
+                  || (op1_signed && TREE_CODE (orig_op1) == INTEGER_CST
+                      && tree_int_cst_sgn (orig_op1) >= 0))
+           /* OK */;
+         /* Do not warn if the comparison is an equality operation,
+            the unsigned quantity is an integral constant and it does
+            not use the most significant bit of result_type.  */
+         else if ((resultcode == EQ_EXPR || resultcode == NE_EXPR)
+                  && ((op0_signed && TREE_CODE (orig_op1) == INTEGER_CST
+                       && int_fits_type_p (orig_op1, signed_type (result_type))
+                       || (op1_signed && TREE_CODE (orig_op0) == INTEGER_CST
+                           && int_fits_type_p (orig_op0, signed_type (result_type))))))
+           /* OK */;
+         else
+           warning ("comparison between signed and unsigned");
 
          /* Warn if two unsigned values are being compared in a size
             larger than their original size, and one (and only one) is the
@@ -3477,8 +3694,8 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
             have all bits set that are set in the ~ operand when it is
             extended.  */
 
-         else if (TREE_CODE (primop0) == BIT_NOT_EXPR
-                  ^ TREE_CODE (primop1) == BIT_NOT_EXPR)
+         if ((TREE_CODE (primop0) == BIT_NOT_EXPR)
+             ^ (TREE_CODE (primop1) == BIT_NOT_EXPR))
            {
              if (TREE_CODE (primop0) == BIT_NOT_EXPR)
                primop0 = get_narrower (TREE_OPERAND (op0, 0), &unsignedp0);
@@ -3533,7 +3750,8 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
 
   if (!result_type)
     {
-      binary_op_error (error_code);
+      cp_error ("invalid operands `%T' and `%T' to binary `%O'",
+               TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), error_code);
       return error_mark_node;
     }
 
@@ -3545,8 +3763,11 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
        op1 = convert (result_type, op1); 
     }
 
+  if (build_type == NULL_TREE)
+    build_type = result_type;
+
   {
-    register tree result = build (resultcode, result_type, op0, op1);
+    register tree result = build (resultcode, build_type, op0, op1);
     register tree folded;
 
     folded = fold (result);
@@ -3595,12 +3816,12 @@ pointer_int_sum (resultcode, ptrop, intop)
     }
   else if (TREE_CODE (TREE_TYPE (result_type)) == OFFSET_TYPE)
     {
-      if (pedantic)
+      if (pedantic || warn_pointer_arith)
        pedwarn ("ANSI C++ forbids using pointer to a member in arithmetic");
       size_exp = integer_one_node;
     }
   else
-    size_exp = size_in_bytes (TREE_TYPE (result_type));
+    size_exp = size_in_bytes (complete_type (TREE_TYPE (result_type)));
 
   /* Needed to make OOPS V2R3 work.  */
   intop = folded;
@@ -3626,11 +3847,11 @@ pointer_int_sum (resultcode, ptrop, intop)
       intop = TREE_OPERAND (intop, 0);
     }
 
-  /* Convert the integer argument to a type the same size as a pointer
+  /* Convert the integer argument to a type the same size as sizetype
      so the multiply won't overflow spuriously.  */
 
-  if (TYPE_PRECISION (TREE_TYPE (intop)) != POINTER_SIZE)
-    intop = convert (type_for_size (POINTER_SIZE, 0), intop);
+  if (TYPE_PRECISION (TREE_TYPE (intop)) != TYPE_PRECISION (sizetype))
+    intop = convert (type_for_size (TYPE_PRECISION (sizetype), 0), intop);
 
   /* Replace the integer argument with a suitable product by the object size.
      Do this multiplication as signed, then convert to the appropriate
@@ -3661,7 +3882,7 @@ pointer_diff (op0, op1)
   tree restype = ptrdiff_type_node;
   tree target_type = TREE_TYPE (TREE_TYPE (op0));
 
-  if (pedantic)
+  if (pedantic || warn_pointer_arith)
     {
       if (TREE_CODE (target_type) == VOID_TYPE)
        pedwarn ("ANSI C++ forbids using pointer of type `void *' in subtraction");
@@ -3723,9 +3944,6 @@ build_component_addr (arg, argtype, msg)
       return error_mark_node;
     }
 
-  if (flag_gc)
-    cp_warning ("address of `%T::%D' taken", basetype, field);
-
   if (TREE_CODE (field) == FIELD_DECL
       && TYPE_USES_COMPLEX_INHERITANCE (basetype))
     {
@@ -3761,8 +3979,11 @@ build_x_unary_op (code, xarg)
      enum tree_code code;
      tree xarg;
 {
+  if (processing_template_decl)
+    return build_min_nt (code, xarg, NULL_TREE);
+
   /* & rec, on incomplete RECORD_TYPEs is the simple opr &, not an
-     error message. */
+     error message.  */
   if (code == ADDR_EXPR
       && ((IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (xarg)))
           && TYPE_SIZE (TREE_TYPE (xarg)) == NULL_TREE)
@@ -3770,26 +3991,48 @@ build_x_unary_op (code, xarg)
     /* don't look for a function */;
   else
     {
-      tree rval = build_opfncall (code, LOOKUP_SPECULATIVELY, xarg,
-                                 NULL_TREE, NULL_TREE);
-      if (rval)
-       return build_opfncall (code, LOOKUP_NORMAL, xarg,
+      tree rval;
+
+      if (flag_ansi_overloading)
+       {
+         rval = build_new_op (code, LOOKUP_NORMAL, xarg,
                               NULL_TREE, NULL_TREE);
+         if (rval || code != ADDR_EXPR)
+           return rval;
+       }
+      else
+       {
+         rval = build_opfncall (code, LOOKUP_SPECULATIVELY, xarg,
+                                NULL_TREE, NULL_TREE);
+         if (rval)
+           return build_opfncall (code, LOOKUP_NORMAL, xarg,
+                                  NULL_TREE, NULL_TREE);
+       }
+    }
+
+  if (code == ADDR_EXPR)
+    {
+      if (TREE_CODE (xarg) == TARGET_EXPR)
+       warning ("taking address of temporary");
     }
+
   return build_unary_op (code, xarg, 0);
 }
 
-/* Just like truthvalue_conversion, but we want a BOOLEAN_TYPE */
+/* Just like truthvalue_conversion, but we want a CLEANUP_POINT_EXPR.  */
+   
 tree
-bool_truthvalue_conversion (expr)
+condition_conversion (expr)
      tree expr;
 {
-  /* We really want to preform the optimizations in truthvalue_conversion
-     but, not this way. */
-  /* expr = truthvalue_conversion (expr); */
-  return convert (boolean_type_node, expr);
+  tree t;
+  if (processing_template_decl)
+    return expr;
+  t = convert (boolean_type_node, expr);
+  t = fold (build1 (CLEANUP_POINT_EXPR, boolean_type_node, t));
+  return t;
 }
-
+                              
 /* C++: Must handle pointers to members.
 
    Perhaps type instantiation should be extended to handle conversion
@@ -3798,6 +4041,7 @@ bool_truthvalue_conversion (expr)
 
    NOCONVERT nonzero suppresses the default promotions
    (such as from short to int).  */
+
 tree
 build_unary_op (code, xarg, noconvert)
      enum tree_code code;
@@ -3807,127 +4051,52 @@ build_unary_op (code, xarg, noconvert)
   /* No default_conversion here.  It causes trouble for ADDR_EXPR.  */
   register tree arg = xarg;
   register tree argtype = 0;
-  register enum tree_code typecode = TREE_CODE (TREE_TYPE (arg));
   char *errstring = NULL;
   tree val;
-  int isaggrtype;
 
-  if (typecode == ERROR_MARK)
+  if (arg == error_mark_node)
     return error_mark_node;
 
-  if (typecode == REFERENCE_TYPE && code != ADDR_EXPR && ! noconvert)
-    {
-      arg = convert_from_reference (arg);
-      typecode = TREE_CODE (TREE_TYPE (arg));
-    }
-
-  if (typecode == ENUMERAL_TYPE)
-    typecode = INTEGER_TYPE;
-
-  if (typecode == BOOLEAN_TYPE && ! noconvert)
-    typecode = INTEGER_TYPE;
-
-  isaggrtype = IS_AGGR_TYPE_CODE (typecode);
-
   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 (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE))
-        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 NEGATE_EXPR:
-      if (typecode == OFFSET_TYPE)
-       {
-         arg = resolve_offset_ref (arg);
-         typecode = TREE_CODE (TREE_TYPE (arg));
-         isaggrtype = IS_AGGR_TYPE_CODE (typecode);
-       }
-
-      if (isaggrtype)
+      if (!(arg = build_expr_type_conversion
+           (WANT_ARITH | WANT_ENUM | WANT_POINTER, arg, 1)))
+       errstring = "wrong type argument to unary plus";
+      else
        {
          if (!noconvert)
-           arg = default_conversion (arg);
-         else
-           {
-             cp_error ("type conversion for type `%T' not allowed",
-                         TREE_TYPE (arg));
-             return error_mark_node;
-           }
-         typecode = TREE_CODE (TREE_TYPE (arg));
-         noconvert = 1;
+          arg = default_conversion (arg);
+         arg = build1 (NON_LVALUE_EXPR, TREE_TYPE (arg), arg);
        }
+      break;
 
-      if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE))
-        errstring = "wrong type argument to unary minus";
+    case NEGATE_EXPR:
+      if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, 1)))
+       errstring = "wrong type argument to unary minus";
       else if (!noconvert)
        arg = default_conversion (arg);
       break;
 
     case BIT_NOT_EXPR:
-      if (typecode == OFFSET_TYPE)
-       {
-         arg = resolve_offset_ref (arg);
-         typecode = TREE_CODE (TREE_TYPE (arg));
-         isaggrtype = IS_AGGR_TYPE_CODE (typecode);
-       }
-
-      if (isaggrtype)
-       {
-         if (!noconvert)
-           arg = default_conversion (arg);
-         else
-           {
-             cp_error ("type conversion for type `%T' not allowed",
-                         TREE_TYPE (arg));
-             return error_mark_node;
-           }
-         typecode = TREE_CODE (TREE_TYPE (arg));
-         noconvert = 1;
-       }
-
-      if (typecode != INTEGER_TYPE)
-        errstring = "wrong type argument to bit-complement";
+      if (!(arg = build_expr_type_conversion (WANT_INT | WANT_ENUM, arg, 1)))
+       errstring = "wrong type argument to bit-complement";
       else if (!noconvert)
        arg = default_conversion (arg);
       break;
 
     case ABS_EXPR:
-      if (typecode == OFFSET_TYPE)
-       {
-         arg = resolve_offset_ref (arg);
-         typecode = TREE_CODE (TREE_TYPE (arg));
-         isaggrtype = IS_AGGR_TYPE_CODE (typecode);
-       }
-
-      if (isaggrtype)
-       {
-         if (!noconvert)
-           arg = default_conversion (arg);
-         else
-           {
-             cp_error ("type conversion for type `%T' not allowed",
-                         TREE_TYPE (arg));
-             return error_mark_node;
-           }
-         typecode = TREE_CODE (TREE_TYPE (arg));
-         noconvert = 1;
-       }
-
-      if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE))
-        errstring = "wrong type argument to abs";
+      if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, 1)))
+       errstring = "wrong type argument to abs";
       else if (!noconvert)
        arg = default_conversion (arg);
       break;
 
     case TRUTH_NOT_EXPR:
-      arg = bool_truthvalue_conversion (arg);
+      arg = convert (boolean_type_node, arg);
       val = invert_truthvalue (arg);
       if (arg != error_mark_node)
        return val;
@@ -3950,21 +4119,8 @@ build_unary_op (code, xarg, noconvert)
 
       /* Report invalid types.  */
 
-      if (typecode == OFFSET_TYPE)
-       {
-         arg = resolve_offset_ref (arg);
-         typecode = TREE_CODE (TREE_TYPE (arg));
-         isaggrtype = IS_AGGR_TYPE_CODE (typecode);
-       }
-
-      if (isaggrtype)
-       {
-         arg = default_conversion (arg);
-         typecode = TREE_CODE (TREE_TYPE (arg));
-       }
-
-      if (typecode != POINTER_TYPE
-         && typecode != INTEGER_TYPE && typecode != REAL_TYPE)
+      if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_POINTER,
+                                             arg, 1)))
        {
          if (code == PREINCREMENT_EXPR)
            errstring ="no pre-increment operator for type";
@@ -4001,10 +4157,10 @@ build_unary_op (code, xarg, noconvert)
            
        /* Compute the increment.  */
 
-       if (typecode == POINTER_TYPE)
+       if (TREE_CODE (argtype) == POINTER_TYPE)
          {
            enum tree_code tmp = TREE_CODE (TREE_TYPE (argtype));
-           if (TYPE_SIZE (TREE_TYPE (argtype)) == 0)
+           if (TYPE_SIZE (complete_type (TREE_TYPE (argtype))) == 0)
              cp_error ("cannot %s a pointer to incomplete type `%T'",
                        ((code == PREINCREMENT_EXPR
                          || code == POSTINCREMENT_EXPR)
@@ -4034,7 +4190,7 @@ build_unary_op (code, xarg, noconvert)
          case FIX_ROUND_EXPR:
          case FIX_CEIL_EXPR:
            {
-             tree incremented, modify, value;
+             tree incremented, modify, value, compound;
              if (! lvalue_p (arg) && pedantic)
                pedwarn ("cast to non-reference type used as lvalue");
              arg = stabilize_reference (arg);
@@ -4047,8 +4203,13 @@ build_unary_op (code, xarg, noconvert)
                                    ? PLUS_EXPR : MINUS_EXPR),
                                   argtype, value, inc);
              TREE_SIDE_EFFECTS (incremented) = 1;
+
              modify = build_modify_expr (arg, NOP_EXPR, incremented);
-             return build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value);
+             compound = build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value);
+
+             /* Eliminate warning about unused result of + or -.  */
+             TREE_NO_UNUSED_WARNING (compound) = 1;
+             return compound;
            }
          }
 
@@ -4058,7 +4219,37 @@ build_unary_op (code, xarg, noconvert)
                                   ? "increment" : "decrement")))
          return error_mark_node;
 
-       val = build (code, TREE_TYPE (arg), arg, inc);
+       /* Forbid using -- on `bool'.  */
+       if (TREE_TYPE (arg) == boolean_type_node)
+         {
+           if (code == POSTDECREMENT_EXPR || code == PREDECREMENT_EXPR)
+             {
+               cp_error ("invalid use of `--' on bool variable `%D'", arg);
+               return error_mark_node;
+             }
+#if 0
+           /* This will only work if someone can convince Kenner to accept
+              my patch to expand_increment. (jason)  */
+           val = build (code, TREE_TYPE (arg), arg, inc);
+#else
+           if (code == POSTINCREMENT_EXPR)
+             {
+               arg = stabilize_reference (arg);
+               val = build (MODIFY_EXPR, TREE_TYPE (arg), arg,
+                            boolean_true_node);
+               TREE_SIDE_EFFECTS (val) = 1;
+               arg = save_expr (arg);
+               val = build (COMPOUND_EXPR, TREE_TYPE (arg), val, arg);
+               val = build (COMPOUND_EXPR, TREE_TYPE (arg), arg, val);
+             }
+           else
+             val = build (MODIFY_EXPR, TREE_TYPE (arg), arg,
+                          boolean_true_node);
+#endif
+         }
+       else
+         val = build (code, TREE_TYPE (arg), arg, inc);
+
        TREE_SIDE_EFFECTS (val) = 1;
        return convert (result_type, val);
       }
@@ -4067,10 +4258,13 @@ build_unary_op (code, xarg, noconvert)
       /* Note that this operation never does default_conversion
         regardless of NOCONVERT.  */
 
-      if (typecode == REFERENCE_TYPE)
+      argtype = TREE_TYPE (arg);
+      if (TREE_CODE (argtype) == REFERENCE_TYPE)
        {
-         arg = build1 (CONVERT_EXPR, build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg);
-         TREE_REFERENCE_EXPR (arg) = 1;
+         arg = build1
+           (CONVERT_EXPR,
+            build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg);
+         TREE_CONSTANT (arg) = TREE_CONSTANT (TREE_OPERAND (arg, 0));
          return arg;
        }
       else if (pedantic
@@ -4086,21 +4280,17 @@ build_unary_op (code, xarg, noconvert)
       /* Let &* cancel out to simplify resulting code.  */
       if (TREE_CODE (arg) == INDIRECT_REF)
        {
-         /* We don't need to have `current_class_decl' wrapped in a
+         /* We don't need to have `current_class_ptr' wrapped in a
             NON_LVALUE_EXPR node.  */
-         if (arg == C_C_D)
-           return current_class_decl;
+         if (arg == current_class_ref)
+           return current_class_ptr;
 
-         /* Keep `default_conversion' from converting if
-            ARG is of REFERENCE_TYPE.  */
          arg = TREE_OPERAND (arg, 0);
          if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE)
            {
-             if (TREE_CODE (arg) == VAR_DECL && DECL_INITIAL (arg)
-                 && !TREE_SIDE_EFFECTS (DECL_INITIAL (arg)))
-               arg = DECL_INITIAL (arg);
-             arg = build1 (CONVERT_EXPR, build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg);
-             TREE_REFERENCE_EXPR (arg) = 1;
+             arg = build1
+               (CONVERT_EXPR,
+                build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg);
              TREE_CONSTANT (arg) = TREE_CONSTANT (TREE_OPERAND (arg, 0));
            }
          else if (lvalue_p (arg))
@@ -4118,15 +4308,6 @@ build_unary_op (code, xarg, noconvert)
                                  TREE_OPERAND (arg, 1), 1);
        }
 
-      /* For &(++foo), we are really taking the address of the variable
-        being acted upon by the increment/decrement operator.  ARM $5.3.1
-        However, according to ARM $5.2.5, we don't allow postfix ++ and
-        --, since the prefix operators return lvalues, but the postfix
-        operators do not.  */
-      if (TREE_CODE (arg) == PREINCREMENT_EXPR
-         || TREE_CODE (arg) == PREDECREMENT_EXPR)
-       arg = TREE_OPERAND (arg, 0);
-
       /* Uninstantiated types are all functions.  Taking the
         address of a function is a no-op, so just return the
         argument.  */
@@ -4180,13 +4361,12 @@ build_unary_op (code, xarg, noconvert)
        ;
       /* Anything not already handled and not a true memory reference
         is an error.  */
-      else if (typecode != FUNCTION_TYPE
-              && typecode != METHOD_TYPE
+      else if (TREE_CODE (argtype) != FUNCTION_TYPE
+              && TREE_CODE (argtype) != METHOD_TYPE
               && !lvalue_or_else (arg, "unary `&'"))
        return error_mark_node;
 
       /* Ordinary case; arg is a COMPONENT_REF or a decl.  */
-      argtype = TREE_TYPE (arg);
       /* If the lvalue is const or volatile,
         merge that into the type that the address will point to.  */
       if (TREE_CODE_CLASS (TREE_CODE (arg)) == 'd'
@@ -4216,6 +4396,14 @@ build_unary_op (code, xarg, noconvert)
           function counts as a constant */
        if (staticp (arg))
          TREE_CONSTANT (addr) = 1;
+
+       if (TREE_CODE (argtype) == POINTER_TYPE &&
+           TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE)
+         {
+           build_ptrmemfunc_type (argtype);
+           addr = build_ptrmemfunc (argtype, addr, 0);
+         }
+
        return addr;
       }
     }
@@ -4231,6 +4419,7 @@ build_unary_op (code, xarg, noconvert)
   return error_mark_node;
 }
 
+#if 0
 /* If CONVERSIONS is a conversion expression or a nested sequence of such,
    convert ARG with the same conversions in the same order
    and return the result.  */
@@ -4257,6 +4446,7 @@ convert_sequence (conversions, arg)
       return arg;
     }
 }
+#endif
 
 /* Apply unary lvalue-demanding operator CODE to the expression ARG
    for certain kinds of expressions which are not really lvalues
@@ -4296,15 +4486,9 @@ unary_complex_lvalue (code, arg)
       || TREE_CODE (arg) == INIT_EXPR)
     {
       tree real_result = build_unary_op (code, TREE_OPERAND (arg, 0), 0);
-      return build (COMPOUND_EXPR, TREE_TYPE (real_result), arg, real_result);
-    }
-
-  if (TREE_CODE (arg) == WITH_CLEANUP_EXPR)
-    {
-      tree real_result = build_unary_op (code, TREE_OPERAND (arg, 0), 0);
-      real_result = build (WITH_CLEANUP_EXPR, TREE_TYPE (real_result),
-                          real_result, 0, TREE_OPERAND (arg, 2));
-      return real_result;
+      arg = build (COMPOUND_EXPR, TREE_TYPE (real_result), arg, real_result);
+      TREE_NO_UNUSED_WARNING (arg) = 1;
+      return arg;
     }
 
   if (TREE_CODE (TREE_TYPE (arg)) == FUNCTION_TYPE
@@ -4315,7 +4499,6 @@ unary_complex_lvalue (code, arg)
         is really the representation of a pointer to it.
         Here give the representation its true type.  */
       tree t;
-      tree offset;
 
       my_friendly_assert (TREE_CODE (arg) != SCOPE_REF, 313);
 
@@ -4324,12 +4507,15 @@ unary_complex_lvalue (code, arg)
 
       t = TREE_OPERAND (arg, 1);
 
-      if (TREE_CODE (t) == FUNCTION_DECL) /* Check all this code for right semantics. */
+      if (TREE_CODE (t) == FUNCTION_DECL) /* Check all this code for right semantics.  */
        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;
+         tree offset = integer_zero_node;
+
          if (TREE_OPERAND (arg, 0)
              && (TREE_CODE (TREE_OPERAND (arg, 0)) != NOP_EXPR
                  || TREE_OPERAND (TREE_OPERAND (arg, 0), 0) != error_mark_node))
@@ -4341,38 +4527,40 @@ unary_complex_lvalue (code, arg)
                return error_mark_node;
              }
 
-         offset = get_delta_difference (DECL_FIELD_CONTEXT (t), 
-                                        TREE_TYPE (TREE_OPERAND (arg, 0)),
-                                        0);
+         type = TREE_TYPE (TREE_OPERAND (arg, 0));
+
+         if (TREE_CODE (TREE_TYPE (arg)) == OFFSET_TYPE)
+           {
+             /* Add in the offset to the intermediate subobject, if any.  */
+             offset = get_delta_difference (TYPE_OFFSET_BASETYPE (TREE_TYPE (arg)),
+                                            type,
+                                            0);
+             type = TYPE_OFFSET_BASETYPE (TREE_TYPE (arg));
+           }
+
+         /* Now in the offset to the final subobject.  */
+         offset = size_binop (PLUS_EXPR,
+                              offset,
+                              get_delta_difference (DECL_FIELD_CONTEXT (t), 
+                                                    type,
+                                                    0));
+
+         /* Add in the offset to the field.  */
          offset = size_binop (PLUS_EXPR, offset,
                               size_binop (EASY_DIV_EXPR,
                                           DECL_FIELD_BITPOS (t),
                                           size_int (BITS_PER_UNIT)));
-         return convert (build_pointer_type (TREE_TYPE (arg)), offset);
-       }
-    }
 
-  if (TREE_CODE (arg) == OFFSET_REF)
-    {
-      tree left = TREE_OPERAND (arg, 0), left_addr;
-      tree right_addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 1), 0);
-
-      if (left == 0)
-       if (current_class_decl)
-         left_addr = current_class_decl;
-       else
-         {
-           error ("no `this' for pointer to member");
-           return error_mark_node;
-         }
-      else
-       left_addr = build_unary_op (ADDR_EXPR, left, 0);
+         /* We offset all pointer to data memebers by 1 so that we can
+            distinguish between a null pointer to data member and the first
+            data member of a structure.  */
+         offset = size_binop (PLUS_EXPR, offset, size_int (1));
 
-      return build (PLUS_EXPR, build_pointer_type (TREE_TYPE (arg)),
-                   build1 (NOP_EXPR, integer_type_node, left_addr),
-                   build1 (NOP_EXPR, integer_type_node, right_addr));
+         return convert (build_pointer_type (TREE_TYPE (arg)), offset);
+       }
     }
 
+  
   /* We permit compiler to make function calls returning
      objects of aggregate type look like lvalues.  */
   {
@@ -4386,24 +4574,13 @@ unary_complex_lvalue (code, arg)
        if (TREE_CODE (arg) == SAVE_EXPR)
          targ = arg;
        else
-         targ = build_cplus_new (TREE_TYPE (arg), arg, 1);
-       return build1 (ADDR_EXPR, TYPE_POINTER_TO (TREE_TYPE (arg)), targ);
+         targ = build_cplus_new (TREE_TYPE (arg), arg);
+       return build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (arg)), targ);
       }
 
     if (TREE_CODE (arg) == SAVE_EXPR && TREE_CODE (targ) == INDIRECT_REF)
-      return build (SAVE_EXPR, TYPE_POINTER_TO (TREE_TYPE (arg)),
+      return build (SAVE_EXPR, build_pointer_type (TREE_TYPE (arg)),
                     TREE_OPERAND (targ, 0), current_function_decl, NULL);
-
-    /* We shouldn't wrap WITH_CLEANUP_EXPRs inside of SAVE_EXPRs, but in case
-       we do, here's how to handle it.  */
-    if (TREE_CODE (arg) == SAVE_EXPR && TREE_CODE (targ) == WITH_CLEANUP_EXPR)
-      {
-#if 0
-       /* Not really a bug, but something to turn on when testing.  */
-       compiler_error ("WITH_CLEANUP_EXPR wrapped in SAVE_EXPR");
-#endif
-       return unary_complex_lvalue (ADDR_EXPR, targ);
-      }
   }
 
   /* Don't let anything else be handled specially.  */
@@ -4414,7 +4591,7 @@ unary_complex_lvalue (code, arg)
    address of it; it should not be allocated in a register.
    Value is 1 if successful.
 
-   C++: we do not allow `current_class_decl' to be addressable.  */
+   C++: we do not allow `current_class_ptr' to be addressable.  */
 
 int
 mark_addressable (exp)
@@ -4435,18 +4612,18 @@ mark_addressable (exp)
        break;
 
       case PARM_DECL:
-       if (x == current_class_decl)
+       if (x == current_class_ptr)
          {
-           error ("address of `this' not available");
+           if (! flag_this_is_variable)
+             error ("address of `this' not available");
            TREE_ADDRESSABLE (x) = 1; /* so compiler doesn't die later */
            put_var_into_stack (x);
            return 1;
          }
       case VAR_DECL:
-       if (TREE_STATIC (x)
-           && TREE_READONLY (x)
+       if (TREE_STATIC (x) && TREE_READONLY (x)
            && DECL_RTL (x) != 0
-           && ! decl_in_memory_p (x))
+           && ! DECL_IN_MEMORY_P (x))
          {
            /* We thought this would make a good constant variable,
               but we were wrong.  */
@@ -4471,8 +4648,10 @@ mark_addressable (exp)
 
       case CONST_DECL:
       case RESULT_DECL:
-       /* For C++, we don't warn about taking the address of a register
-          variable for CONST_DECLs; ARM p97 explicitly says it's okay.  */
+       if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x)
+           && !DECL_ARTIFICIAL (x) && extra_warnings)
+         cp_warning ("address requested for `%D', which is declared `register'",
+                     x);
        put_var_into_stack (x);
        TREE_ADDRESSABLE (x) = 1;
        return 1;
@@ -4482,7 +4661,7 @@ mark_addressable (exp)
           be non-zero in the case of processing a default function.
           The second may be non-zero in the case of a template function.  */
        x = DECL_MAIN_VARIANT (x);
-       if ((DECL_INLINE (x) || DECL_PENDING_INLINE_INFO (x))
+       if ((DECL_THIS_INLINE (x) || DECL_PENDING_INLINE_INFO (x))
            && (DECL_CONTEXT (x) == NULL_TREE
                || TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (x))) != 't'
                || ! CLASSTYPE_INTERFACE_ONLY (DECL_CONTEXT (x))))
@@ -4496,6 +4675,15 @@ mark_addressable (exp)
        TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (x)) = 1;
        return 1;
 
+      case CONSTRUCTOR:
+       TREE_ADDRESSABLE (x) = 1;
+       return 1;
+
+      case TARGET_EXPR:
+       TREE_ADDRESSABLE (x) = 1;
+       mark_addressable (TREE_OPERAND (x, 0));
+       return 1;
+
       default:
        return 1;
     }
@@ -4509,6 +4697,12 @@ build_x_conditional_expr (ifexp, op1, op2)
 {
   tree rval = NULL_TREE;
 
+  if (processing_template_decl)
+    return build_min_nt (COND_EXPR, ifexp, op1, op2);
+
+  if (flag_ansi_overloading)
+    return build_new_op (COND_EXPR, LOOKUP_NORMAL, ifexp, op1, op2);
+
   /* See comments in `build_x_binary_op'.  */
   if (op1 != 0)
     rval = build_opfncall (COND_EXPR, LOOKUP_SPECULATIVELY, ifexp, op1, op2);
@@ -4527,7 +4721,6 @@ build_conditional_expr (ifexp, op1, op2)
   register enum tree_code code1;
   register enum tree_code code2;
   register tree result_type = NULL_TREE;
-  tree orig_op1 = op1, orig_op2 = op2;
 
   /* If second operand is omitted, it is the same as the first one;
      make sure it is calculated only once.  */
@@ -4538,7 +4731,7 @@ build_conditional_expr (ifexp, op1, op2)
       ifexp = op1 = save_expr (ifexp);
     }
 
-  ifexp = bool_truthvalue_conversion (ifexp);
+  ifexp = convert (boolean_type_node, ifexp);
 
   if (TREE_CODE (ifexp) == ERROR_MARK)
     return error_mark_node;
@@ -4569,17 +4762,12 @@ build_conditional_expr (ifexp, op1, op2)
       code2 = TREE_CODE (type2);
     }
 
-#if 1 /* Produces wrong result if within sizeof.  Sorry.  */
   /* Don't promote the operands separately if they promote
      the same way.  Return the unpromoted type and let the combined
      value get promoted if necessary.  */
 
   if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2)
       && code2 != ARRAY_TYPE
-#if 0
-      /* For C++, let the enumeral type come through.  */
-      && code2 != ENUMERAL_TYPE
-#endif
       && code2 != FUNCTION_TYPE
       && code2 != METHOD_TYPE)
     {
@@ -4608,9 +4796,17 @@ build_conditional_expr (ifexp, op1, op2)
       result = fold (build (COND_EXPR, type1, ifexp, op1, op2));
       if (TREE_TYPE (result) != type1)
        result = build1 (NOP_EXPR, type1, result);
+      /* Expand both sides into the same slot,
+        hopefully the target of the ?: expression.  */
+      if (TREE_CODE (op1) == TARGET_EXPR && TREE_CODE (op2) == TARGET_EXPR)
+       {
+         tree slot = build (VAR_DECL, TREE_TYPE (result));
+         layout_decl (slot, 0);
+         result = build (TARGET_EXPR, TREE_TYPE (result),
+                         slot, result, NULL_TREE, NULL_TREE);
+       }
       return result;
     }
-#endif
 
   /* They don't match; promote them both and then try to reconcile them.
      But don't permit mismatching enum types.  */
@@ -4618,32 +4814,50 @@ build_conditional_expr (ifexp, op1, op2)
     {
       if (code2 == ENUMERAL_TYPE)
        {
-         message_2_types (error, "enumeral mismatch in conditional expression: `%s' vs `%s'", type1, type2);
+         cp_error ("enumeral mismatch in conditional expression: `%T' vs `%T'", type1, type2);
          return error_mark_node;
        }
-      else if (extra_warnings && ! IS_AGGR_TYPE_CODE (code2))
+      else if (extra_warnings && ! IS_AGGR_TYPE_CODE (code2)
+              && type2 != type_promotes_to (type1))
        warning ("enumeral and non-enumeral type in conditional expression");
     }
   else if (extra_warnings
-          && code2 == ENUMERAL_TYPE && ! IS_AGGR_TYPE_CODE (code1))
+          && code2 == ENUMERAL_TYPE && ! IS_AGGR_TYPE_CODE (code1)
+          && type1 != type_promotes_to (type2))
     warning ("enumeral and non-enumeral type in conditional expression");
 
   if (code1 != VOID_TYPE)
     {
       op1 = default_conversion (op1);
       type1 = TREE_TYPE (op1);
+      if (TYPE_PTRMEMFUNC_P (type1))
+       type1 = TYPE_PTRMEMFUNC_FN_TYPE (type1);
       code1 = TREE_CODE (type1);
     }
   if (code2 != VOID_TYPE)
     {
       op2 = default_conversion (op2);
       type2 = TREE_TYPE (op2);
+      if (TYPE_PTRMEMFUNC_P (type2))
+       type2 = TYPE_PTRMEMFUNC_FN_TYPE (type2);
       code2 = TREE_CODE (type2);
     }
 
+  if (code1 == RECORD_TYPE && code2 == RECORD_TYPE
+      && real_lvalue_p (op1) && real_lvalue_p (op2)
+      && comptypes (type1, type2, -1))
+    {
+      type1 = build_reference_type (type1);
+      type2 = build_reference_type (type2);
+      result_type = common_type (type1, type2);
+      op1 = convert_to_reference (result_type, op1, CONV_IMPLICIT,
+                                 LOOKUP_NORMAL, NULL_TREE);
+      op2 = convert_to_reference (result_type, op2, CONV_IMPLICIT,
+                                 LOOKUP_NORMAL, NULL_TREE);
+    }
   /* Quickly detect the usual case where op1 and op2 have the same type
      after promotion.  */
-  if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2))
+  else if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2))
     {
       if (type1 == type2)
        result_type = type1;
@@ -4664,16 +4878,14 @@ build_conditional_expr (ifexp, op1, op2)
        pedwarn ("ANSI C++ forbids conditional expr with only one void side");
       result_type = void_type_node;
     }
+  else if (code1 == POINTER_TYPE && null_ptr_cst_p (op2))
+    result_type = qualify_type (type1, type2);
+  else if (code2 == POINTER_TYPE && null_ptr_cst_p (op1))
+    result_type = qualify_type (type2, type1);
   else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE)
     {
       if (comp_target_types (type1, type2, 1))
        result_type = common_type (type1, type2);
-      else if (integer_zerop (op1) && TREE_TYPE (type1) == void_type_node
-              && TREE_CODE (orig_op1) != NOP_EXPR)
-       result_type = qualify_type (type2, type1);
-      else if (integer_zerop (op2) && TREE_TYPE (type2) == void_type_node
-              && TREE_CODE (orig_op2) != NOP_EXPR)
-       result_type = qualify_type (type1, type2);
       else if (TYPE_MAIN_VARIANT (TREE_TYPE (type1)) == void_type_node)
        {
          if (pedantic && TREE_CODE (type2) == FUNCTION_TYPE)
@@ -4707,7 +4919,7 @@ build_conditional_expr (ifexp, op1, op2)
                cp_pedwarn ("`%T' and `%T' converted to `%T *' in conditional expression",
                            type1, type2, result_type);
 
-             result_type = TYPE_POINTER_TO (result_type);
+             result_type = build_pointer_type (result_type);
            }
        }
       else
@@ -4718,30 +4930,12 @@ build_conditional_expr (ifexp, op1, op2)
     }
   else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE)
     {
-      if (!integer_zerop (op2))
-       pedwarn ("pointer/integer type mismatch in conditional expression");
-      else
-       {
-         op2 = null_pointer_node;
-#if 0                          /* Sez who? */
-         if (pedantic && TREE_CODE (type1) == FUNCTION_TYPE)
-           pedwarn ("ANSI C++ forbids conditional expr between 0 and function pointer");
-#endif
-       }
+      pedwarn ("pointer/integer type mismatch in conditional expression");
       result_type = type1;
     }
   else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE)
     {
-      if (!integer_zerop (op1))
-       pedwarn ("pointer/integer type mismatch in conditional expression");
-      else
-       {
-         op1 = null_pointer_node;
-#if 0                          /* Sez who? */
-         if (pedantic && TREE_CODE (type2) == FUNCTION_TYPE)
-           pedwarn ("ANSI C++ forbids conditional expr between 0 and function pointer");
-#endif
-       }
+      pedwarn ("pointer/integer type mismatch in conditional expression");
       result_type = type2;
     }
 
@@ -4751,33 +4945,55 @@ build_conditional_expr (ifexp, op1, op2)
         an aggregate value, try converting to a scalar type.  */
       if (code1 == RECORD_TYPE && code2 == RECORD_TYPE)
        {
-         message_2_types (error, "aggregate mismatch in conditional expression: `%s' vs `%s'", type1, type2);
+         cp_error ("aggregate mismatch in conditional expression: `%T' vs `%T'", type1, type2);
          return error_mark_node;
        }
+      /* Warning: this code assumes that conversion between cv-variants of
+         a type is done using NOP_EXPRs.  */
       if (code1 == RECORD_TYPE && TYPE_HAS_CONVERSION (type1))
        {
-         tree tmp = build_type_conversion (CONVERT_EXPR, type2, op1, 0);
+         /* There are other types besides pointers and records.  */
+         tree tmp;
+         if (code2 == POINTER_TYPE)
+             tmp = build_pointer_type
+               (build_type_variant (TREE_TYPE (type2), 1, 1));
+         else
+           tmp = type2;
+         tmp = build_type_conversion (CONVERT_EXPR, tmp, op1, 0);
          if (tmp == NULL_TREE)
            {
-             cp_error ("aggregate type `%T' could not convert on lhs of `:'", type1);
+             cp_error ("incompatible types `%T' and `%T' in `?:'",
+                       type1, type2);
              return error_mark_node;
            }
          if (tmp == error_mark_node)
            error ("ambiguous pointer conversion");
-         result_type = type2;
+         else
+           STRIP_NOPS (tmp);
+         result_type = common_type (type2, TREE_TYPE (tmp));
          op1 = tmp;
        }
       else if (code2 == RECORD_TYPE && TYPE_HAS_CONVERSION (type2))
        {
-         tree tmp = build_type_conversion (CONVERT_EXPR, type1, op2, 0);
+         tree tmp;
+         if (code1 == POINTER_TYPE)
+           tmp = build_pointer_type
+             (build_type_variant (TREE_TYPE (type1), 1, 1));
+         else
+           tmp = type1;
+
+         tmp = build_type_conversion (CONVERT_EXPR, tmp, op2, 0);
          if (tmp == NULL_TREE)
            {
-             cp_error ("aggregate type `%T' could not convert on rhs of `:'", type2);
+             cp_error ("incompatible types `%T' and `%T' in `?:'",
+                       type1, type2);
              return error_mark_node;
            }
          if (tmp == error_mark_node)
            error ("ambiguous pointer conversion");
-         result_type = type1;
+         else
+           STRIP_NOPS (tmp);
+         result_type = common_type (type1, TREE_TYPE (tmp));
          op2 = tmp;
        }
       else if (flag_cond_mismatch)
@@ -4789,56 +5005,25 @@ build_conditional_expr (ifexp, op1, op2)
        }
     }
 
+  if (TREE_CODE (result_type) == POINTER_TYPE
+      && TREE_CODE (TREE_TYPE (result_type)) == METHOD_TYPE)
+    result_type = build_ptrmemfunc_type (result_type);
+
   if (result_type != TREE_TYPE (op1))
     op1 = convert_and_check (result_type, op1);
   if (result_type != TREE_TYPE (op2))
     op2 = convert_and_check (result_type, op2);
 
-#if 0
-  /* XXX delete me, I've been here for years.  */
-  if (IS_AGGR_TYPE_CODE (code1))
-    {
-      result_type = TREE_TYPE (op1);
-      if (TREE_CONSTANT (ifexp))
-       return (integer_zerop (ifexp) ? op2 : op1);
-
-      if (TYPE_MODE (result_type) == BLKmode)
-       {
-         register tree tempvar
-           = build_decl (VAR_DECL, NULL_TREE, result_type);
-         register tree xop1 = build_modify_expr (tempvar, NOP_EXPR, op1);
-         register tree xop2 = build_modify_expr (tempvar, NOP_EXPR, op2);
-         register tree result = fold (build (COND_EXPR, result_type,
-                                             ifexp, xop1, xop2));
-
-         layout_decl (tempvar, 0);
-         /* No way to handle variable-sized objects here.
-            I fear that the entire handling of BLKmode conditional exprs
-            needs to be redone.  */
-         my_friendly_assert (TREE_CONSTANT (DECL_SIZE (tempvar)), 315);
-         DECL_RTL (tempvar)
-           = assign_stack_local (DECL_MODE (tempvar),
-                                 (TREE_INT_CST_LOW (DECL_SIZE (tempvar))
-                                  + BITS_PER_UNIT - 1)
-                                 / BITS_PER_UNIT,
-                                 0);
-
-         TREE_SIDE_EFFECTS (result)
-           = TREE_SIDE_EFFECTS (ifexp) | TREE_SIDE_EFFECTS (op1)
-             | TREE_SIDE_EFFECTS (op2);
-         return build (COMPOUND_EXPR, result_type, result, tempvar);
-       }
-    }
-#endif /* 0 */
-
   if (TREE_CONSTANT (ifexp))
     return integer_zerop (ifexp) ? op2 : op1;
 
-  return fold (build (COND_EXPR, result_type, ifexp, op1, op2));
+  return convert_from_reference
+    (fold (build (COND_EXPR, result_type, ifexp, op1, op2)));
 }
 \f
 /* Handle overloading of the ',' operator when needed.  Otherwise,
    this function just builds an expression list.  */
+
 tree
 build_x_compound_expr (list)
      tree list;
@@ -4846,6 +5031,9 @@ build_x_compound_expr (list)
   tree rest = TREE_CHAIN (list);
   tree result;
 
+  if (processing_template_decl)
+    return build_min_nt (COMPOUND_EXPR, list, NULL_TREE);
+
   if (rest == NULL_TREE)
     return build_compound_expr (list);
 
@@ -4853,6 +5041,22 @@ build_x_compound_expr (list)
                           TREE_VALUE (list), TREE_VALUE (rest), NULL_TREE);
   if (result)
     return build_x_compound_expr (tree_cons (NULL_TREE, result, TREE_CHAIN (rest)));
+
+  if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)))
+    {
+      /* the left-hand operand of a comma expression is like an expression
+         statement: we should warn if it doesn't have any side-effects,
+         unless it was explicitly cast to (void).  */
+      if ((extra_warnings || warn_unused)
+           && !(TREE_CODE (TREE_VALUE(list)) == CONVERT_EXPR
+                && TREE_TYPE (TREE_VALUE(list)) == void_type_node))
+        warning("left-hand operand of comma expression has no effect");
+    }
+#if 0 /* this requires a gcc backend patch to export warn_if_unused_value */
+  else if (warn_unused)
+    warn_if_unused_value (TREE_VALUE(list));
+#endif
+
   return build_compound_expr (tree_cons (NULL_TREE, TREE_VALUE (list),
                                         build_tree_list (NULL_TREE, build_x_compound_expr (rest))));
 }
@@ -4886,8 +5090,7 @@ build_compound_expr (list)
 
   rest = build_compound_expr (TREE_CHAIN (list));
 
-  /* When pedantic, a compound expression can be neither an lvalue
-     nor an integer constant expression.  */
+  /* When pedantic, a compound expression cannot be a constant expression.  */
   if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)) && ! pedantic)
     return rest;
 
@@ -4895,22 +5098,251 @@ build_compound_expr (list)
                break_out_cleanups (TREE_VALUE (list)), rest);
 }
 
-tree build_static_cast (type, expr)
+tree
+build_static_cast (type, expr)
    tree type, expr;
 {
-  return build_c_cast (type, expr, 0);
+  tree intype, binfo;
+  int ok;
+
+  if (type == error_mark_node || expr == error_mark_node)
+    return error_mark_node;
+
+  if (TREE_CODE (expr) == OFFSET_REF)
+    expr = resolve_offset_ref (expr);
+
+  if (processing_template_decl)
+    {
+      tree t = build_min (STATIC_CAST_EXPR, type, expr);
+      return t;
+    }
+
+  /* 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);
+
+  if (TREE_CODE (type) == VOID_TYPE)
+    return build1 (CONVERT_EXPR, type, expr);
+
+  if (type_unknown_p (expr))
+    {
+      expr = instantiate_type (type, expr, 1);
+      if (expr == error_mark_node)
+       return error_mark_node;
+    }
+
+  if (TREE_CODE (type) == REFERENCE_TYPE)
+    return (convert_from_reference
+           (convert_to_reference (type, expr, CONV_STATIC|CONV_IMPLICIT,
+                                  LOOKUP_COMPLAIN, NULL_TREE)));
+
+  if (IS_AGGR_TYPE (type))
+    return build_cplus_new
+      (type, (build_method_call
+             (NULL_TREE, ctor_identifier, build_tree_list (NULL_TREE, expr),
+              TYPE_BINFO (type), LOOKUP_NORMAL)));
+
+  expr = decay_conversion (expr);
+  intype = TREE_TYPE (expr);
+
+  /* FIXME handle casting to array type.  */
+
+  ok = 0;
+  if (can_convert_arg (type, intype, expr))
+    ok = 1;
+  else if (TYPE_PTROB_P (type) && TYPE_PTROB_P (intype))
+    {
+      tree binfo;
+      if (IS_AGGR_TYPE (TREE_TYPE (type)) && IS_AGGR_TYPE (TREE_TYPE (intype))
+         && (TYPE_READONLY (TREE_TYPE (type))
+             >= TYPE_READONLY (TREE_TYPE (intype)))
+         && (TYPE_VOLATILE (TREE_TYPE (type))
+             >= TYPE_VOLATILE (TREE_TYPE (intype)))
+         && (binfo = get_binfo (TREE_TYPE (intype), TREE_TYPE (type), 0))
+         && ! TREE_VIA_VIRTUAL (binfo))
+       ok = 1;
+    }
+  else if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
+    {
+      if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type))),
+                    TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (intype))), 1)
+         && (TYPE_READONLY (TREE_TYPE (TREE_TYPE (type)))
+             >= TYPE_READONLY (TREE_TYPE (TREE_TYPE (intype))))
+         && (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (type)))
+             >= TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (intype))))
+         && (binfo = get_binfo (TYPE_OFFSET_BASETYPE (intype),
+                                TYPE_OFFSET_BASETYPE (type), 0))
+         && ! TREE_VIA_VIRTUAL (binfo))
+       ok = 1;
+    }
+  else if (TREE_CODE (intype) != BOOLEAN_TYPE
+          && TREE_CODE (type) != ARRAY_TYPE
+          && TREE_CODE (type) != FUNCTION_TYPE
+          && can_convert (intype, type))
+    ok = 1;
+
+  if (ok)
+    return build_c_cast (type, expr);
+
+  cp_error ("static_cast from `%T' to `%T'", intype, type);
+  return error_mark_node;
 }
 
-tree build_reinterpret_cast (type, expr)
+tree
+build_reinterpret_cast (type, expr)
    tree type, expr;
 {
-  return build_c_cast (type, expr, 0);
+  tree intype;
+
+  if (type == error_mark_node || expr == error_mark_node)
+    return error_mark_node;
+
+  if (TREE_CODE (expr) == OFFSET_REF)
+    expr = resolve_offset_ref (expr);
+
+  if (processing_template_decl)
+    {
+      tree t = build_min (REINTERPRET_CAST_EXPR, type, expr);
+      return t;
+    }
+
+  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 (expr) == NOP_EXPR
+         && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
+       expr = TREE_OPERAND (expr, 0);
+    }
+
+  if (type_unknown_p (expr))
+    {
+      expr = instantiate_type (type, expr, 1);
+      if (expr == error_mark_node)
+       return error_mark_node;
+    }
+
+  intype = TREE_TYPE (expr);
+
+  if (TREE_CODE (type) == REFERENCE_TYPE)
+    {
+      if (! real_lvalue_p (expr))
+       {
+         cp_error ("reinterpret_cast from `%T' rvalue to `%T'", intype, type);
+         return error_mark_node;
+       }
+      expr = build_unary_op (ADDR_EXPR, expr, 0);
+      if (expr != error_mark_node)
+       expr = build_reinterpret_cast
+         (build_pointer_type (TREE_TYPE (type)), expr);
+      if (expr != error_mark_node)
+       expr = build_indirect_ref (expr, 0);
+      return expr;
+    }
+  else if (comptypes (TYPE_MAIN_VARIANT (intype), TYPE_MAIN_VARIANT (type), 1))
+    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))
+    {
+      if (TYPE_PRECISION (type) < TYPE_PRECISION (intype))
+       cp_pedwarn ("reinterpret_cast from `%T' to `%T' loses precision",
+                   intype, type);
+    }
+  else if ((TYPE_PTRFN_P (type) && TYPE_PTRFN_P (intype))
+          || (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
+    {
+      if (TREE_READONLY_DECL_P (expr))
+       expr = decl_constant_value (expr);
+      return fold (build1 (NOP_EXPR, type, expr));
+    }
+  else if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
+          || (TYPE_PTROBV_P (type) && TYPE_PTROBV_P (intype)))
+    {
+      if (! comp_ptr_ttypes_reinterpret (TREE_TYPE (type), TREE_TYPE (intype)))
+       cp_pedwarn ("reinterpret_cast from `%T' to `%T' casts away const (or volatile)",
+                   intype, type);
+
+      if (TREE_READONLY_DECL_P (expr))
+       expr = decl_constant_value (expr);
+      return fold (build1 (NOP_EXPR, type, expr));
+    }
+  else
+    {
+      cp_error ("reinterpret_cast from `%T' to `%T'", intype, type);
+      return error_mark_node;
+    }
+      
+  return convert (type, expr);
 }
 
-tree build_const_cast (type, expr)
+tree
+build_const_cast (type, expr)
    tree type, expr;
 {
-  return build_c_cast (type, expr, 0);
+  tree intype;
+
+  if (type == error_mark_node || expr == error_mark_node)
+    return error_mark_node;
+
+  if (TREE_CODE (expr) == OFFSET_REF)
+    expr = resolve_offset_ref (expr);
+
+  if (processing_template_decl)
+    {
+      tree t = build_min (CONST_CAST_EXPR, type, expr);
+      return t;
+    }
+
+  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 (expr) == NOP_EXPR
+         && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
+       expr = TREE_OPERAND (expr, 0);
+    }
+
+  if (type_unknown_p (expr))
+    {
+      expr = instantiate_type (type, expr, 1);
+      if (expr == error_mark_node)
+       return error_mark_node;
+    }
+
+  intype = TREE_TYPE (expr);
+
+  if (comptypes (TYPE_MAIN_VARIANT (intype), TYPE_MAIN_VARIANT (type), 1))
+    return build_static_cast (type, expr);
+  else if (TREE_CODE (type) == REFERENCE_TYPE)
+    {
+      if (! real_lvalue_p (expr))
+       {
+         cp_error ("const_cast from `%T' rvalue to `%T'", intype, type);
+         return error_mark_node;
+       }
+
+      if (comp_ptr_ttypes_const (TREE_TYPE (type), intype))
+       return (convert_from_reference
+               (convert_to_reference (type, expr, CONV_CONST|CONV_IMPLICIT,
+                                      LOOKUP_COMPLAIN, NULL_TREE)));
+    }
+  else if (TREE_CODE (type) == POINTER_TYPE
+          && TREE_CODE (intype) == POINTER_TYPE
+          && comp_ptr_ttypes_const (TREE_TYPE (type), TREE_TYPE (intype)))
+    return convert (type, expr);
+
+  cp_error ("const_cast from `%T' to `%T'", intype, type);
+  return error_mark_node;
 }
 
 /* Build an expression representing a cast to type TYPE of expression EXPR.
@@ -4919,10 +5351,8 @@ tree build_const_cast (type, expr)
    when doing the cast.  */
 
 tree
-build_c_cast (type, expr, allow_nonconverting)
-     register tree type;
-     tree expr;
-     int allow_nonconverting;
+build_c_cast (type, expr)
+     tree type, expr;
 {
   register tree value = expr;
 
@@ -4930,8 +5360,9 @@ build_c_cast (type, expr, allow_nonconverting)
     return error_mark_node;
 
   /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
-     Strip such NOP_EXPRs, since VALUE is being used in non-lvalue context.  */
-  if (TREE_CODE (value) == NOP_EXPR
+     Strip such NOP_EXPRs if VALUE is being used in non-lvalue context.  */
+  if (TREE_CODE (type) != REFERENCE_TYPE
+      && TREE_CODE (value) == NOP_EXPR
       && TREE_TYPE (value) == TREE_TYPE (TREE_OPERAND (value, 0)))
     value = TREE_OPERAND (value, 0);
 
@@ -4971,11 +5402,12 @@ build_c_cast (type, expr, allow_nonconverting)
       return error_mark_node;
     }
 
-  /* If there's only one function in the overloaded space,
-     just take it.  */
-  if (TREE_CODE (value) == TREE_LIST
-      && TREE_CHAIN (value) == NULL_TREE)
-    value = TREE_VALUE (value);
+  if (processing_template_decl)
+    {
+      tree t = build_min (CAST_EXPR, type,
+                         min_tree_cons (NULL_TREE, value, NULL_TREE));
+      return t;
+    }
 
   if (TREE_CODE (type) == VOID_TYPE)
     value = build1 (CONVERT_EXPR, type, value);
@@ -4989,13 +5421,17 @@ build_c_cast (type, expr, allow_nonconverting)
     }
   else
     {
-      tree otype, ovalue;
+      tree otype;
 
       /* Convert functions and arrays to pointers and
         convert references to their expanded types,
         but don't convert any other types.  */
       if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE
-         || TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE
+         || (TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE
+             /* Don't do the default conversion if we want a
+                pointer to a function.  */
+             && TREE_CODE (type) != POINTER_TYPE
+             && TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE)
          || TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
          || TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE)
        value = default_conversion (value);
@@ -5027,6 +5463,8 @@ build_c_cast (type, expr, allow_nonconverting)
        warning ("cast increases required alignment of target type");
 
 #if 0
+      /* We should see about re-enabling these, they seem useful to
+         me.  */
       if (TREE_CODE (type) == INTEGER_TYPE
          && TREE_CODE (otype) == POINTER_TYPE
          && TYPE_PRECISION (type) != TYPE_PRECISION (otype))
@@ -5041,312 +5479,70 @@ build_c_cast (type, expr, allow_nonconverting)
        warning ("cast to pointer from integer of different size");
 #endif
 
-      if (TREE_READONLY_DECL_P (value))
-       value = decl_constant_value (value);
-
-      ovalue = value;
-      value = convert_force (type, value, allow_nonconverting?CONV_NONCONVERTING:0);
-
-      /* Ignore any integer overflow caused by the cast.  */
-      if (TREE_CODE (value) == INTEGER_CST)
-       {
-         TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue);
-         TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_OVERFLOW (ovalue);
-       }
-    }
-
-    /* Always produce some operator for an explicit cast,
-       so we can tell (for -pedantic) that the cast is no lvalue.
-       Also, pedantically, don't let (void *) (FOO *) 0 be a null
-       pointer constant.  */
-  if (value == expr
-      || (pedantic
-         && TREE_CODE (value) == INTEGER_CST
-         && TREE_CODE (expr) == INTEGER_CST
-         && TREE_CODE (TREE_TYPE (expr)) != INTEGER_TYPE))
-    {
-      tree nvalue = build1 (NOP_EXPR, type, value);
-      TREE_CONSTANT (nvalue) = TREE_CONSTANT (value);
-      return nvalue;
-    }
-
-  return value;
-}
-\f
-#if 0
-/* Build an assignment expression of lvalue LHS from value RHS.
-
-   In C++, if the left hand side of the assignment is a REFERENCE_TYPE,
-   that reference becomes deferenced down to it base type. */
-
-/* Return a reference to the BASE_INDEX part of EXPR.  TYPE is
-   the type to which BASE_INDEX applies.  */
-static tree
-get_base_ref (type, base_index, expr)
-     tree type;
-     int base_index;
-     tree expr;
-{
-  tree binfos = TYPE_BINFO_BASETYPES (type);
-  tree base_binfo = TREE_VEC_ELT (binfos, base_index);
-  tree ref;
-
-  if (TREE_CODE (expr) == ARRAY_REF
-      || ! BINFO_OFFSET_ZEROP (base_binfo)
-      || TREE_VIA_VIRTUAL (base_binfo)
-      || TYPE_MODE (type) != TYPE_MODE (BINFO_TYPE (base_binfo)))
-    {
-      tree addr = build_unary_op (ADDR_EXPR, expr, 0);
-      ref = build_indirect_ref (convert_pointer_to (base_binfo, addr),
-                               NULL_PTR);
-    }
-  else
-    {
-      ref = copy_node (expr);
-      TREE_TYPE (ref) = BINFO_TYPE (base_binfo);
-    }
-  return ref;
-}
-
-/* Build an assignment expression of lvalue LHS from value RHS.
-   MODIFYCODE is the code for a binary operator that we use
-   to combine the old value of LHS with RHS to get the new value.
-   Or else MODIFYCODE is NOP_EXPR meaning do a simple assignment.
-
-   C++: If MODIFYCODE is INIT_EXPR, then leave references unbashed.
-
-   `build_modify_expr_1' implements recursive part of memberwise
-   assignment operation.  */
-static tree
-build_modify_expr_1 (lhs, modifycode, rhs, basetype_path)
-     tree lhs, rhs;
-     enum tree_code modifycode;
-     tree basetype_path;
-{
-  register tree result;
-  tree newrhs = rhs;
-  tree lhstype = TREE_TYPE (lhs);
-  tree olhstype = lhstype;
-
-  /* Avoid duplicate error messages from operands that had errors.  */
-  if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
-    return error_mark_node;
-
-  /* If a binary op has been requested, combine the old LHS value with the RHS
-     producing the value we should actually store into the LHS.  */
-
-  if (modifycode == INIT_EXPR)
-    ;
-  else if (modifycode == NOP_EXPR)
-    {
-      /* must deal with overloading of `operator=' here.  */
-      if (TREE_CODE (lhstype) == REFERENCE_TYPE)
-       lhstype = TREE_TYPE (lhstype);
+      if (TREE_CODE (type) == REFERENCE_TYPE)
+       value = (convert_from_reference
+                (convert_to_reference (type, value, CONV_C_CAST,
+                                       LOOKUP_COMPLAIN, NULL_TREE)));
       else
-       lhstype = olhstype;
-    }
-  else
-    {
-      lhs = stabilize_reference (lhs);
-      newrhs = build_binary_op (modifycode, lhs, rhs, 1);
-      modifycode = NOP_EXPR;
-    }
-
-  /* If storing into a structure or union member,
-     it has probably been given type `int'.
-     Compute the type that would go with
-     the actual amount of storage the member occupies.  */
-
-  if (TREE_CODE (lhs) == COMPONENT_REF
-      && (TREE_CODE (lhstype) == INTEGER_TYPE
-         || TREE_CODE (lhstype) == REAL_TYPE
-         || TREE_CODE (lhstype) == ENUMERAL_TYPE))
-    lhstype = TREE_TYPE (get_unwidened (lhs, 0));
-
-  /* C++: The semantics of C++ differ from those of C when an
-     assignment of an aggregate is desired.  Assignment in C++ is
-     now defined as memberwise assignment of non-static members
-     and base class objects.  This rule applies recursively
-     until a member of a built-in type is found.
-
-     Also, we cannot do a bit-wise copy of aggregates which
-     contain virtual function table pointers.  Those
-     pointer values must be preserved through the copy.
-     However, this is handled in expand_expr, and not here.
-     This is because much better code can be generated at
-     that stage than this one.  */
-  if (TREE_CODE (lhstype) == RECORD_TYPE
-      && TYPE_LANG_SPECIFIC (lhstype)
-      && TYPE_MAIN_VARIANT (lhstype) == TYPE_MAIN_VARIANT (TREE_TYPE (newrhs)))
-    {
-      register tree elt;
-      int i;
-
-      /* Perform operation on object.  */
-      if (modifycode == INIT_EXPR && TYPE_HAS_INIT_REF (lhstype))
-       {
-         result = build_method_call (lhs, constructor_name_full (lhstype),
-                                     build_tree_list (NULL_TREE, rhs),
-                                     basetype_path, LOOKUP_NORMAL);
-         return build_indirect_ref (result, NULL_PTR);
-       }
-      else if (modifycode == NOP_EXPR)
        {
-         /* `operator=' is not an inheritable operator; see 13.4.3.  */
-         if (TYPE_LANG_SPECIFIC (lhstype) && TYPE_HAS_ASSIGNMENT (lhstype))
-           {
-             result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
-                                      lhs, rhs, make_node (NOP_EXPR));
-             if (result == NULL_TREE)
-               return error_mark_node;
-             return result;
-           }
-       }
+         tree ovalue;
 
-      if (TYPE_USES_VIRTUAL_BASECLASSES (lhstype)
-         || (modifycode == NOP_EXPR && TYPE_GETS_ASSIGNMENT (lhstype))
-         || (modifycode == INIT_EXPR && TYPE_GETS_INIT_REF (lhstype)))
-       {
-         tree binfos = BINFO_BASETYPES (TYPE_BINFO (lhstype));
-         result = NULL_TREE;
+         if (TREE_READONLY_DECL_P (value))
+           value = decl_constant_value (value);
 
-         if (binfos != NULL_TREE)
-           /* Perform operation on each member, depth-first, left-right.  */
-           for (i = 0; i <= TREE_VEC_LENGTH (binfos)-1; i++)
-             {
-               tree base_binfo = TREE_VEC_ELT (binfos, i);
-               tree base_lhs, base_rhs;
-               tree new_result;
-
-               /* Assignments from virtual baseclasses handled elsewhere.  */
-               if (TREE_VIA_VIRTUAL (base_binfo))
-                 continue;
-
-               base_lhs = get_base_ref (lhstype, i, lhs);
-               base_rhs = get_base_ref (lhstype, i, newrhs);
-
-               BINFO_INHERITANCE_CHAIN (base_binfo) = basetype_path;
-               new_result
-                 = build_modify_expr_1 (base_lhs, modifycode, base_rhs,
-                                        base_binfo);
-
-               /* We either get back a compound stmt, or a simple one.  */
-               if (new_result && TREE_CODE (new_result) == TREE_LIST)
-                 new_result = build_compound_expr (new_result);
-               result = tree_cons (NULL_TREE, new_result, result);
-             }
+         ovalue = value;
+         value = convert_force (type, value, CONV_C_CAST);
 
-         for (elt = TYPE_FIELDS (lhstype); elt; elt = TREE_CHAIN (elt))
+         /* Ignore any integer overflow caused by the cast.  */
+         if (TREE_CODE (value) == INTEGER_CST)
            {
-             tree vbases = NULL_TREE;
-             tree elt_lhs, elt_rhs;
-
-             if (TREE_CODE (elt) != FIELD_DECL)
-               continue;
-             if (DECL_NAME (elt)
-                 && (VFIELD_NAME_P (DECL_NAME (elt))
-                     || VBASE_NAME_P (DECL_NAME (elt))))
-               continue;
-
-             if (TREE_READONLY (elt)
-                 || TREE_CODE (TREE_TYPE (elt)) == REFERENCE_TYPE)
-               {
-                 cp_error ("cannot generate default `%T::operator ='",
-                           lhstype);
-                 if (TREE_CODE (TREE_TYPE (elt)) == REFERENCE_TYPE)
-                   cp_error_at ("because member `%#D' is a reference", elt);
-                 else
-                   cp_error_at ("because member `%#D' is const", elt);
-
-                 return error_mark_node;
-               }
-
-             if (IS_AGGR_TYPE (TREE_TYPE (elt))
-                 && TYPE_LANG_SPECIFIC (TREE_TYPE (elt)))
-               vbases = CLASSTYPE_VBASECLASSES (TREE_TYPE (elt));
-
-             elt_lhs = build (COMPONENT_REF, TREE_TYPE (elt), lhs, elt);
-             elt_rhs = build (COMPONENT_REF, TREE_TYPE (elt), newrhs, elt);
-             /* It is not always safe to go through `build_modify_expr_1'
-                when performing element-wise copying.  This is because
-                an element may be of ARRAY_TYPE, which will not
-                be properly copied as a naked element.  */
-             if (TREE_CODE (TREE_TYPE (elt)) == RECORD_TYPE
-                 && TYPE_LANG_SPECIFIC (TREE_TYPE (elt)))
-               basetype_path = TYPE_BINFO (TREE_TYPE (elt));
-
-             while (vbases)
-               {
-                 tree elt_lhs_addr = build_unary_op (ADDR_EXPR, elt_lhs, 0);
-                 tree elt_rhs_addr = build_unary_op (ADDR_EXPR, elt_rhs, 0);
-
-                 elt_lhs_addr = convert_pointer_to (vbases, elt_lhs_addr);
-                 elt_rhs_addr = convert_pointer_to (vbases, elt_rhs_addr);
-                 result
-                   = tree_cons (NULL_TREE,
-                                build_modify_expr_1
-                                (build_indirect_ref (elt_lhs_addr, NULL_PTR),
-                                 modifycode,
-                                 build_indirect_ref (elt_rhs_addr, NULL_PTR),
-                                 basetype_path),
-                                result);
-                 if (TREE_VALUE (result) == error_mark_node)
-                   return error_mark_node;
-                 vbases = TREE_CHAIN (vbases);
-               }
-             elt_lhs = build_modify_expr_1 (elt_lhs, modifycode, elt_rhs,
-                                            basetype_path);
-             result = tree_cons (NULL_TREE, elt_lhs, result);
+             TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue);
+             TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_OVERFLOW (ovalue);
            }
-
-         if (result)
-           return build_compound_expr (result);
-         /* No fields to move.  */
-         return integer_zero_node;
-       }
-      else
-       {
-         result = build (modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR,
-                         void_type_node, lhs, rhs);
-         TREE_SIDE_EFFECTS (result) = 1;
-         return result;
        }
     }
 
-  result = build_modify_expr (lhs, modifycode, newrhs);
-  /* ARRAY_TYPEs cannot be converted to anything meaningful,
-     and leaving it there screws up `build_compound_expr' when
-     it tries to defaultly convert everything.  */
-  if (TREE_CODE (TREE_TYPE (result)) == ARRAY_TYPE)
-    TREE_TYPE (result) = void_type_node;
-  return result;
-}
-#endif
-
-/* Taken from expr.c:
-   Subroutine of expand_expr:
-   record the non-copied parts (LIST) of an expr (LHS), and return a list
-   which specifies the initial values of these parts.  */
+    /* 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);
 
-static tree
-init_noncopied_parts (lhs, list)
-     tree lhs;
-     tree list;
+  return value;
+}
+\f
+tree
+expand_target_expr (t)
+     tree t;
 {
-  tree tail;
-  tree parts = 0;
-
-  for (tail = list; tail; tail = TREE_CHAIN (tail))
-    if (TREE_CODE (TREE_VALUE (tail)) == TREE_LIST)
-      parts = chainon (parts, init_noncopied_parts (lhs, TREE_VALUE (tail)));
-    else
-      {
-       tree part = TREE_VALUE (tail);
-       tree part_type = TREE_TYPE (part);
-       tree to_be_initialized = build (COMPONENT_REF, part_type, lhs, part);
-       parts = tree_cons (TREE_PURPOSE (tail), to_be_initialized, parts);
-      }
-  return parts;
+  extern int temp_slot_level;
+  extern int target_temp_slot_level;
+  int old_temp_level = target_temp_slot_level;
+
+  tree xval = make_node (RTL_EXPR);
+  rtx rtxval;
+
+  /* Any TARGET_EXPR temps live only as long as the outer temp level.
+     Since they are preserved in this new inner level, we know they
+     will make it into the outer level.  */
+  push_temp_slots ();
+  target_temp_slot_level = temp_slot_level;
+
+  do_pending_stack_adjust ();
+  start_sequence_for_rtl_expr (xval);
+  emit_note (0, -1);
+  rtxval = expand_expr (t, NULL_RTX, VOIDmode, 0);
+  do_pending_stack_adjust ();
+  TREE_SIDE_EFFECTS (xval) = 1;
+  RTL_EXPR_SEQUENCE (xval) = get_insns ();
+  end_sequence ();
+  RTL_EXPR_RTL (xval) = rtxval;
+  TREE_TYPE (xval) = TREE_TYPE (t);
+
+  pop_temp_slots ();
+  target_temp_slot_level = old_temp_level;
+
+  return xval;
 }
 
 /* Build an assignment expression of lvalue LHS from value RHS.
@@ -5354,8 +5550,8 @@ init_noncopied_parts (lhs, list)
    to combine the old value of LHS with RHS to get the new value.
    Or else MODIFYCODE is NOP_EXPR meaning do a simple assignment.
 
-   C++: If MODIFYCODE is INIT_EXPR, then leave references unbashed.
-*/
+   C++: If MODIFYCODE is INIT_EXPR, then leave references unbashed.  */
+
 tree
 build_modify_expr (lhs, modifycode, rhs)
      tree lhs;
@@ -5369,18 +5565,12 @@ build_modify_expr (lhs, modifycode, rhs)
   tree olhs = lhs;
 
   /* Avoid duplicate error messages from operands that had errors.  */
-  if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
+  if (lhs == error_mark_node || rhs == error_mark_node)
     return error_mark_node;
 
   /* Types that aren't fully specified cannot be used in assignments.  */
   lhs = require_complete_type (lhs);
 
-  /* Decide early if we are going to protect RHS from GC
-     before assigning it to LHS.  */
-  if (type_needs_gc_entry (TREE_TYPE (rhs))
-      && ! value_safe_from_gc (lhs, rhs))
-    rhs = protect_value_from_gc (lhs, rhs);
-
   newrhs = rhs;
 
   /* Handle assignment to signature pointers/refs.  */
@@ -5400,7 +5590,8 @@ build_modify_expr (lhs, modifycode, rhs)
     case PREINCREMENT_EXPR:
       if (TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0)))
        lhs = build (TREE_CODE (lhs), TREE_TYPE (lhs),
-                    stabilize_reference (TREE_OPERAND (lhs, 0)));
+                    stabilize_reference (TREE_OPERAND (lhs, 0)),
+                    TREE_OPERAND (lhs, 1));
       return build (COMPOUND_EXPR, lhstype,
                    lhs,
                    build_modify_expr (TREE_OPERAND (lhs, 0),
@@ -5410,14 +5601,14 @@ build_modify_expr (lhs, modifycode, rhs)
     case COMPOUND_EXPR:
       newrhs = build_modify_expr (TREE_OPERAND (lhs, 1),
                                  modifycode, rhs);
-      if (TREE_CODE (newrhs) == ERROR_MARK)
+      if (newrhs == error_mark_node)
        return error_mark_node;
       return build (COMPOUND_EXPR, lhstype,
                    TREE_OPERAND (lhs, 0), newrhs);
 
     case MODIFY_EXPR:
       newrhs = build_modify_expr (TREE_OPERAND (lhs, 0), modifycode, rhs);
-      if (TREE_CODE (newrhs) == ERROR_MARK)
+      if (newrhs == error_mark_node)
        return error_mark_node;
       return build (COMPOUND_EXPR, lhstype, lhs, newrhs);
 
@@ -5434,7 +5625,7 @@ build_modify_expr (lhs, modifycode, rhs)
                                                       modifycode, rhs),
                                    build_modify_expr (convert (TREE_TYPE (lhs), TREE_OPERAND (lhs, 2)),
                                                       modifycode, rhs));
-       if (TREE_CODE (cond) == ERROR_MARK)
+       if (cond == error_mark_node)
          return cond;
        /* Make sure the code to compute the rhs comes out
           before the split.  */
@@ -5480,15 +5671,18 @@ build_modify_expr (lhs, modifycode, rhs)
       if (! IS_AGGR_TYPE (lhstype))
        /* Do the default thing */;
       else if (! TYPE_HAS_CONSTRUCTOR (lhstype))
-       cp_error ("`%T' has no constructors", lhstype);
-      else if (! TYPE_NEEDS_CONSTRUCTING (lhstype)
+       {
+         cp_error ("`%T' has no constructors", lhstype);
+         return error_mark_node;
+       }
+      else if (TYPE_HAS_TRIVIAL_INIT_REF (lhstype)
               && TYPE_MAIN_VARIANT (lhstype) == TYPE_MAIN_VARIANT (TREE_TYPE (newrhs)))
        /* Do the default thing */;
       else
        {
-         result = build_method_call (lhs, constructor_name_full (lhstype),
+         result = build_method_call (lhs, ctor_identifier,
                                      build_tree_list (NULL_TREE, rhs),
-                                     NULL_TREE, LOOKUP_NORMAL);
+                                     TYPE_BINFO (lhstype), LOOKUP_NORMAL);
          if (result == NULL_TREE)
            return error_mark_node;
          return result;
@@ -5496,66 +5690,30 @@ build_modify_expr (lhs, modifycode, rhs)
     }
   else if (modifycode == NOP_EXPR)
     {
-#if 1
       /* `operator=' is not an inheritable operator.  */
       if (! IS_AGGR_TYPE (lhstype))
        /* Do the default thing */;
       else if (! TYPE_HAS_ASSIGNMENT (lhstype))
-       cp_error ("`%T' does not define operator=", lhstype);
-      else if (! TYPE_HAS_REAL_ASSIGNMENT (lhstype)
-              && ! TYPE_HAS_COMPLEX_ASSIGN_REF (lhstype)
-              /* FIXME find some way to deal with TARGET_EXPRs here.  */
-              && TREE_CODE (newrhs) != TARGET_EXPR
+       {
+         cp_error ("`%T' does not define operator=", lhstype);
+         return error_mark_node;
+       }
+      else if (TYPE_HAS_TRIVIAL_ASSIGN_REF (lhstype)
               && TYPE_MAIN_VARIANT (lhstype) == TYPE_MAIN_VARIANT (TREE_TYPE (newrhs)))
-       /* Do the default thing */;
-      else
        {
-         result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
-                                  lhs, rhs, make_node (NOP_EXPR));
-         if (result == NULL_TREE)
-           return error_mark_node;
-         return result;
+         build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
+                         lhs, rhs, make_node (NOP_EXPR));
+
+         /* Do the default thing */;
        }
-#else
-      /* Treat `operator=' as an inheritable operator.  */
-      if (TYPE_LANG_SPECIFIC (lhstype) && TYPE_GETS_ASSIGNMENT (lhstype))
+      else
        {
-         tree orig_lhstype = lhstype;
-         while (! TYPE_HAS_ASSIGNMENT (lhstype))
-           {
-             int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (lhstype);
-             tree basetype = NULL_TREE;
-             for (i = 0; i < n_baseclasses; i++)
-               if (TYPE_GETS_ASSIGNMENT (TYPE_BINFO_BASETYPE (lhstype, i)))
-                 {
-                   if (basetype != NULL_TREE)
-                     {
-                       message_2_types (error, "base classes `%s' and `%s' both have operator ='",
-                                        basetype,
-                                        TYPE_BINFO_BASETYPE (lhstype, i));
-                       return error_mark_node;
-                     }
-                   basetype = TYPE_BINFO_BASETYPE (lhstype, i);
-                 }
-             lhstype = basetype;
-           }
-         if (orig_lhstype != lhstype)
-           {
-             lhs = build_indirect_ref (convert_pointer_to (lhstype,
-                                                           build_unary_op (ADDR_EXPR, lhs, 0)), NULL_PTR);
-             if (lhs == error_mark_node)
-               {
-                 cp_error ("conversion to private basetype `%T'", lhstype);
-                 return error_mark_node;
-               }
-           }
          result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
                                   lhs, rhs, make_node (NOP_EXPR));
          if (result == NULL_TREE)
            return error_mark_node;
          return result;
        }
-#endif
       lhstype = olhstype;
     }
   else if (PROMOTES_TO_AGGR_TYPE (lhstype, REFERENCE_TYPE))
@@ -5567,17 +5725,27 @@ build_modify_expr (lhs, modifycode, rhs)
       if (build_default_binary_type_conversion (modifycode, &lhs_tmp, &rhs_tmp))
        {
          lhs = stabilize_reference (lhs_tmp);
-         /* Forget is was ever anything else.  */
+         /* Forget it was ever anything else.  */
          olhstype = lhstype = TREE_TYPE (lhs);
          newrhs = build_binary_op (modifycode, lhs, rhs_tmp, 1);
        }
       else
-       return error_mark_node;
+       {
+         cp_error ("no match for `%Q(%#T, %#T)'", modifycode,
+                   TREE_TYPE (lhs), TREE_TYPE (rhs));
+         return error_mark_node;
+       }
     }
   else
     {
       lhs = stabilize_reference (lhs);
       newrhs = build_binary_op (modifycode, lhs, rhs, 1);
+      if (newrhs == error_mark_node)
+       {
+         cp_error ("  in evaluation of `%Q(%#T, %#T)'", modifycode,
+                   TREE_TYPE (lhs), TREE_TYPE (rhs));
+         return error_mark_node;
+       }
     }
 
   /* Handle a cast used as an "lvalue".
@@ -5604,13 +5772,16 @@ build_modify_expr (lhs, modifycode, rhs)
       {
        tree inner_lhs = TREE_OPERAND (lhs, 0);
        tree result;
-       if (! lvalue_p (lhs) && pedantic)
-         pedwarn ("cast to non-reference type used as lvalue");
+
+       /* WP 5.4.1:  The result is an lvalue if T is a reference type,
+          otherwise the result is an rvalue.   */
+       if (! lvalue_p (lhs))
+         pedwarn ("ANSI C++ forbids cast to non-reference type used as lvalue");
 
        result = build_modify_expr (inner_lhs, NOP_EXPR,
                                    convert (TREE_TYPE (inner_lhs),
                                             convert (lhstype, newrhs)));
-       if (TREE_CODE (result) == ERROR_MARK)
+       if (result == error_mark_node)
          return result;
        return convert (TREE_TYPE (lhs), result);
       }
@@ -5663,11 +5834,12 @@ build_modify_expr (lhs, modifycode, rhs)
     }
 
   /* check to see if there is an assignment to `this' */
-  if (lhs == current_class_decl)
+  if (lhs == current_class_ptr)
     {
       if (flag_this_is_variable > 0
          && DECL_NAME (current_function_decl) != NULL_TREE
-         && current_class_name != DECL_NAME (current_function_decl))
+         && (DECL_NAME (current_function_decl)
+             != constructor_name (current_class_type)))
        warning ("assignment to `this' not in constructor or destructor");
       current_function_just_assigned_this = 1;
     }
@@ -5704,113 +5876,15 @@ build_modify_expr (lhs, modifycode, rhs)
            {
              incomplete_type_error (newrhs, TREE_TYPE (tmp));
              return error_mark_node;
-           }
-         newrhs = tmp;
-       }
-    }
-
-  if (TREE_SIDE_EFFECTS (lhs))
-    lhs = stabilize_reference (lhs);
-  if (TREE_SIDE_EFFECTS (newrhs))
-    newrhs = stabilize_reference (newrhs);
-
-#if 0
-  /* This is now done by generating X(X&) and operator=(X&). */
-  /* C++: The semantics of C++ differ from those of C when an
-     assignment of an aggregate is desired.  Assignment in C++ is
-     now defined as memberwise assignment of non-static members
-     and base class objects.  This rule applies recursively
-     until a member of a built-in type is found.
-
-     Also, we cannot do a bit-wise copy of aggregates which
-     contain virtual function table pointers.  Those
-     pointer values must be preserved through the copy.
-     However, this is handled in expand_expr, and not here.
-     This is because much better code can be generated at
-     that stage than this one.  */
-  if (TREE_CODE (lhstype) == RECORD_TYPE
-      && ! TYPE_PTRMEMFUNC_P (lhstype)
-      && (TYPE_MAIN_VARIANT (lhstype) == TYPE_MAIN_VARIANT (TREE_TYPE (newrhs))
-         || (TREE_CODE (TREE_TYPE (newrhs)) == RECORD_TYPE
-             && UNIQUELY_DERIVED_FROM_P (lhstype, TREE_TYPE (newrhs)))))
-    {
-      tree vbases = CLASSTYPE_VBASECLASSES (lhstype);
-      tree lhs_addr = build_unary_op (ADDR_EXPR, lhs, 0);
-      tree rhs_addr;
-         
-      /* Memberwise assignment would cause NEWRHS to be
-        evaluated for every member that gets assigned.
-        By wrapping side-effecting exprs in a SAVE_EXPR,
-        NEWRHS will only be evaluated once.  */
-      if (IS_AGGR_TYPE (TREE_TYPE (newrhs))
-         && TREE_SIDE_EFFECTS (newrhs)
-         /* This are things we don't have to save.  */
-         && TREE_CODE (newrhs) != COND_EXPR
-         && TREE_CODE (newrhs) != TARGET_EXPR
-         && TREE_CODE (newrhs) != WITH_CLEANUP_EXPR)
-       /* Call `break_out_cleanups' on NEWRHS in case there are cleanups.
-          If NEWRHS is a CALL_EXPR that needs a cleanup, failure to do so
-          will result in expand_expr expanding the call without knowing
-          that it should run the cleanup.  */
-       newrhs = save_expr (break_out_cleanups (newrhs));
-         
-      if (TREE_CODE (newrhs) == COND_EXPR)
-       rhs_addr = rationalize_conditional_expr (ADDR_EXPR, newrhs);
-      else
-       rhs_addr = build_unary_op (ADDR_EXPR, newrhs, 0);
-
-      result = tree_cons (NULL_TREE,
-                         convert (build_reference_type (lhstype), lhs),
-                         NULL_TREE);
-
-      if (! comptypes (TREE_TYPE (lhs_addr), TREE_TYPE (rhs_addr), 1))
-       rhs_addr = convert_pointer_to (TREE_TYPE (TREE_TYPE (lhs_addr)), rhs_addr);
-      {
-       tree noncopied_parts = NULL_TREE;
-
-       if (TYPE_NONCOPIED_PARTS (lhstype) != 0)
-         noncopied_parts = init_noncopied_parts (lhs,
-                                                 TYPE_NONCOPIED_PARTS (lhstype));
-       while (noncopied_parts != 0)
-         {
-           result = tree_cons (NULL_TREE,
-                               build_modify_expr (convert (ptr_type_node, TREE_VALUE (noncopied_parts)),
-                                                  NOP_EXPR,
-                                                  TREE_PURPOSE (noncopied_parts)),
-                               result);
-           noncopied_parts = TREE_CHAIN (noncopied_parts);
-         }
-      }
-      /* Once we have our hands on an address, we must change NEWRHS
-        to work from there.  Otherwise we can get multiple evaluations
-        of NEWRHS.  */
-      if (TREE_CODE (newrhs) != SAVE_EXPR)
-       newrhs = build_indirect_ref (rhs_addr, NULL_PTR);
-
-      while (vbases)
-       {
-         tree elt_lhs = convert_pointer_to (vbases, lhs_addr);
-         tree elt_rhs = convert_pointer_to (vbases, rhs_addr);
-         result
-           = tree_cons (NULL_TREE,
-                        build_modify_expr_1 (build_indirect_ref (elt_lhs, NULL_PTR),
-                                             modifycode,
-                                             build_indirect_ref (elt_rhs, NULL_PTR),
-                                             TYPE_BINFO (lhstype)),
-                        result);
-         if (TREE_VALUE (result) == error_mark_node)
-           return error_mark_node;
-         vbases = TREE_CHAIN (vbases);
+           }
+         newrhs = tmp;
        }
-      result = tree_cons (NULL_TREE,
-                         build_modify_expr_1 (lhs,
-                                              modifycode,
-                                              newrhs,
-                                              TYPE_BINFO (lhstype)),
-                         result);
-      return build_compound_expr (result);
     }
-#endif
+
+  if (TREE_SIDE_EFFECTS (lhs))
+    lhs = stabilize_reference (lhs);
+  if (TREE_SIDE_EFFECTS (newrhs))
+    newrhs = stabilize_reference (newrhs);
 
   /* Convert new value to destination type.  */
 
@@ -5818,6 +5892,13 @@ build_modify_expr (lhs, modifycode, rhs)
     {
       int from_array;
       
+      if (! comptypes (lhstype, TREE_TYPE (rhs), 0))
+       {
+         cp_error ("incompatible types in assignment of `%T' to `%T'",
+                   TREE_TYPE (rhs), lhstype);
+         return error_mark_node;
+       }
+
       /* Allow array assignment in compiler-generated code.  */
       if (pedantic && ! DECL_ARTIFICIAL (current_function_decl))
        pedwarn ("ANSI C++ forbids assignment of arrays");
@@ -5863,16 +5944,7 @@ build_modify_expr (lhs, modifycode, rhs)
     }
   else
     {
-#if 0
-      if (IS_AGGR_TYPE (lhstype))
-       {
-         if (result = build_opfncall (MODIFY_EXPR,
-                                      LOOKUP_NORMAL, lhs, newrhs,
-                                      make_node (NOP_EXPR)))
-           return result;
-       }
-#endif
-      /* Avoid warnings on enum bit fields. */
+      /* Avoid warnings on enum bit fields.  */
       if (TREE_CODE (olhstype) == ENUMERAL_TYPE
          && TREE_CODE (lhstype) == INTEGER_TYPE)
        {
@@ -5882,22 +5954,21 @@ build_modify_expr (lhs, modifycode, rhs)
        }
       else
        newrhs = convert_for_assignment (lhstype, newrhs, "assignment",
-                                      NULL_TREE, 0);
-      if (flag_elide_constructors == 0
-         && TREE_CODE (newrhs) == CALL_EXPR
-         && TREE_ADDRESSABLE (lhstype))
-       {
-         /* Can't initialized directly from a CALL_EXPR, since
-            we don't know about what doesn't alias what.  */
-
-         tree temp = get_temp_name (lhstype, 0);
-         newrhs = build (COMPOUND_EXPR, lhstype,
-                         build_modify_expr (temp, INIT_EXPR, newrhs),
-                         temp);
-       }
+                                        NULL_TREE, 0);
+      if (TREE_CODE (newrhs) == CALL_EXPR
+         && TYPE_NEEDS_CONSTRUCTING (lhstype))
+       newrhs = build_cplus_new (lhstype, newrhs);
+
+      /* Can't initialize directly from a TARGET_EXPR, since that would
+        cause the lhs to be constructed twice, and possibly result in
+        accidental self-initialization.  So we force the TARGET_EXPR to be
+        expanded without a target.  */
+      if (TREE_CODE (newrhs) == TARGET_EXPR)
+       newrhs = build (COMPOUND_EXPR, TREE_TYPE (newrhs), newrhs,
+                       TREE_OPERAND (newrhs, 0));
     }
 
-  if (TREE_CODE (newrhs) == ERROR_MARK)
+  if (newrhs == error_mark_node)
     return error_mark_node;
 
   if (TREE_CODE (newrhs) == COND_EXPR)
@@ -5935,38 +6006,10 @@ build_modify_expr (lhs, modifycode, rhs)
                                                 TREE_OPERAND (newrhs, 2))));
        }
     }
-  else if (modifycode != INIT_EXPR && TREE_CODE (newrhs) == WITH_CLEANUP_EXPR)
-    {
-      tree cleanup = TREE_OPERAND (newrhs, 2);
-      tree slot;
-
-      /* Finish up by running cleanups and having the "value" of the lhs.  */
-      tree exprlist = tree_cons (NULL_TREE, cleanup,
-                                build_tree_list (NULL_TREE, lhs));
-      newrhs = TREE_OPERAND (newrhs, 0);
-      if (TREE_CODE (newrhs) == TARGET_EXPR)
-         slot = TREE_OPERAND (newrhs, 0);
-      else if (TREE_CODE (newrhs) == ADDR_EXPR)
-       {
-         /* Bad but valid.  */
-         slot = newrhs;
-         warning ("address taken of temporary object");
-       }
-      else
-       my_friendly_abort (118);
-
-      /* Copy the value computed in SLOT into LHS.  */
-      exprlist = tree_cons (NULL_TREE,
-                           build_modify_expr (lhs, modifycode, slot),
-                           exprlist);
-      /* Evaluate the expression that needs CLEANUP.  This will
-        compute the value into SLOT.  */
-      exprlist = tree_cons (NULL_TREE, newrhs, exprlist);
-      result = convert (lhstype, build_compound_expr (exprlist));
-    }
   else
     result = build (modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR,
                    lhstype, lhs, newrhs);
+
   TREE_SIDE_EFFECTS (result) = 1;
 
   /* If we got the LHS in a different type for storing in,
@@ -5977,7 +6020,7 @@ build_modify_expr (lhs, modifycode, rhs)
   if (olhstype == TREE_TYPE (result))
     return result;
   /* Avoid warnings converting integral types back into enums
-     for enum bit fields. */
+     for enum bit fields.  */
   if (TREE_CODE (TREE_TYPE (result)) == INTEGER_TYPE
       && TREE_CODE (olhstype) == ENUMERAL_TYPE)
     {
@@ -5989,6 +6032,25 @@ build_modify_expr (lhs, modifycode, rhs)
                                 NULL_TREE, 0);
 }
 
+tree
+build_x_modify_expr (lhs, modifycode, rhs)
+     tree lhs;
+     enum tree_code modifycode;
+     tree rhs;
+{
+  if (processing_template_decl)
+    return build_min_nt (MODOP_EXPR, lhs,
+                        build_min_nt (modifycode, NULL_TREE, NULL_TREE), rhs);
+
+  if (modifycode != NOP_EXPR)
+    {
+      tree rval = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs,
+                                 make_node (modifycode));
+      if (rval)
+       return rval;
+    }
+  return build_modify_expr (lhs, modifycode, rhs);
+}
 
 /* Return 0 if EXP is not a valid lvalue in this language
    even though `lvalue_or_else' would accept it.  */
@@ -6000,9 +6062,10 @@ language_lvalue_valid (exp)
   return 1;
 }
 \f
-/* Get differnce in deltas for different pointer to member function
-   types.  Return inetger_zero_node, if FROM cannot be converted to a
+/* Get difference in deltas for different pointer to member function
+   types.  Return integer_zero_node, if FROM cannot be converted to a
    TO type.  If FORCE is true, then allow reverse conversions as well.  */
+
 static tree
 get_delta_difference (from, to, force)
      tree from, to;
@@ -6022,7 +6085,7 @@ get_delta_difference (from, to, force)
   binfo = get_binfo (from, to, 1);
   if (binfo == error_mark_node)
     {
-      error ("   in pointer to member function conversion");
+      error ("   in pointer to member function conversiona");
       return delta;
     }
   if (binfo == 0)
@@ -6030,35 +6093,115 @@ get_delta_difference (from, to, force)
       if (!force)
        {
          error_not_base_type (from, to);
-         error ("   in pointer to member function conversion");
+         error ("   in pointer to member conversion");
          return delta;
        }
       binfo = get_binfo (to, from, 1);
       if (binfo == error_mark_node)
        {
-         error ("   in pointer to member function conversion");
+         if (!force)
+           error ("   in pointer to member conversion");
          return delta;
        }
       if (binfo == 0)
        {
-         error ("cannot convert pointer to member of type %T to unrelated pointer to member of type %T", from, to);
+         if (!force)
+           cp_error ("cannot convert pointer to member of type %T to unrelated pointer to member of type %T", from, to);
          return delta;
        }
       if (TREE_VIA_VIRTUAL (binfo))
        {
-         warning ("pointer to member conversion to virtual base class will only work if your very careful");
+         binfo = binfo_member (BINFO_TYPE (binfo),
+                               CLASSTYPE_VBASECLASSES (from));
+         warning ("pointer to member conversion to virtual base class will only work if you are very careful");
        }
+      delta = BINFO_OFFSET (binfo);
+      delta = convert (ptrdiff_type_node, delta);
+      
       return build_binary_op (MINUS_EXPR,
                              integer_zero_node,
-                             BINFO_OFFSET (binfo), 1);
+                             delta, 1);
     }
   if (TREE_VIA_VIRTUAL (binfo))
     {
-      warning ("pointer to member conversion from virtual base class will only work if your very careful");
+      warning ("pointer to member conversion from virtual base class will only work if you are very careful");
     }
   return BINFO_OFFSET (binfo);
 }
 
+static tree
+build_ptrmemfunc1 (type, delta, idx, pfn, delta2)
+     tree type, delta, idx, pfn, delta2;
+{
+  tree u;
+
+#if 0
+  /* This is the old way we did it.  We want to avoid calling
+     digest_init, so that it can give an error if we use { } when
+     initializing a pointer to member function.  */
+
+  if (pfn)
+    {
+      u = build_nt (CONSTRUCTOR, NULL_TREE,
+                   tree_cons (pfn_identifier, pfn, NULL_TREE));
+    }
+  else
+    {
+      u = build_nt (CONSTRUCTOR, NULL_TREE,
+                   tree_cons (delta2_identifier, delta2, NULL_TREE));
+    }
+
+  u = build_nt (CONSTRUCTOR, NULL_TREE,
+               tree_cons (NULL_TREE, delta,
+                          tree_cons (NULL_TREE, idx,
+                                     tree_cons (NULL_TREE, u, NULL_TREE))));
+
+  return digest_init (type, u, (tree*)0);
+#else
+  tree delta_field, idx_field, pfn_or_delta2_field, pfn_field, delta2_field;
+  tree subtype;
+  int allconstant, allsimple;
+
+  delta_field = TYPE_FIELDS (type);
+  idx_field = TREE_CHAIN (delta_field);
+  pfn_or_delta2_field = TREE_CHAIN (idx_field);
+  subtype = TREE_TYPE (pfn_or_delta2_field);
+  pfn_field = TYPE_FIELDS (subtype);
+  delta2_field = TREE_CHAIN (pfn_field);
+
+  if (pfn)
+    {
+      allconstant = TREE_CONSTANT (pfn);
+      allsimple = initializer_constant_valid_p (pfn, TREE_TYPE (pfn));
+      u = tree_cons (pfn_field, pfn, NULL_TREE);
+    }
+  else
+    {
+      delta2 = convert_and_check (delta_type_node, delta2);
+      allconstant = TREE_CONSTANT (delta2);
+      allsimple = initializer_constant_valid_p (delta2, TREE_TYPE (delta2));
+      u = tree_cons (delta2_field, delta2, NULL_TREE);
+    }
+
+  delta = convert_and_check (delta_type_node, delta);
+  idx = convert_and_check (delta_type_node, idx);
+
+  allconstant = allconstant && TREE_CONSTANT (delta) && TREE_CONSTANT (idx);
+  allsimple = allsimple
+    && initializer_constant_valid_p (delta, TREE_TYPE (delta))
+      && initializer_constant_valid_p (idx, TREE_TYPE (idx));
+
+  u = build (CONSTRUCTOR, subtype, NULL_TREE, u);
+  u = tree_cons (delta_field, delta,
+                tree_cons (idx_field, idx,
+                           tree_cons (pfn_or_delta2_field, u, NULL_TREE)));
+  u = build (CONSTRUCTOR, type, NULL_TREE, u);
+  TREE_CONSTANT (u) = allconstant;
+  TREE_STATIC (u) = allconstant && allsimple;
+  return u;
+#endif
+}
+
 /* Build a constructor for a pointer to member function.  It can be
    used to initialize global variables, local variable, or used
    as a value in expressions.  TYPE is the POINTER to METHOD_TYPE we
@@ -6075,114 +6218,81 @@ build_ptrmemfunc (type, pfn, force)
      tree type, pfn;
      int force;
 {
-  tree index = integer_zero_node;
+  tree idx = integer_zero_node;
   tree delta = integer_zero_node;
   tree delta2 = integer_zero_node;
   tree vfield_offset;
-  tree npfn;
-  tree u;
+  tree npfn = NULL_TREE;
 
-  /* Handle multiple conversions of pointer to member fucntions. */
+  /* Handle multiple conversions of pointer to member functions.  */
   if (TYPE_PTRMEMFUNC_P (TREE_TYPE (pfn)))
     {
-      tree ndelta, ndelta2, nindex;
+      tree ndelta, ndelta2;
+      tree e1, e2, e3, n;
+
       /* Is is already the right type? */
-#if 0
-      /* Sorry, can't do this, the backend is too stupid. */
-      if (TYPE_METHOD_BASETYPE (TREE_TYPE (type))
-         == TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))))
-       {
-         if (type != TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))
-           {
-             npfn = build1 (NOP_EXPR, TYPE_GET_PTRMEMFUNC_TYPE (type), pfn);
-             TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
-           }
-         return pfn;
-       }
-#else
       if (type == TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))
        return pfn;
-#endif
 
-      if (TREE_CODE (pfn) != CONSTRUCTOR)
-       {
-         tree e1, e2, e3;
-         ndelta = convert (ptrdiff_type_node, build_component_ref (pfn, delta_identifier, 0, 0));
-         ndelta2 = convert (ptrdiff_type_node, DELTA2_FROM_PTRMEMFUNC (pfn));
-         index = build_component_ref (pfn, index_identifier, 0, 0);
-         delta = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))),
-                                       TYPE_METHOD_BASETYPE (TREE_TYPE (type)),
-                                       force);
-         delta = build_binary_op (PLUS_EXPR, delta, ndelta, 1);
-         delta2 = build_binary_op (PLUS_EXPR, ndelta2, delta2, 1);
-         e1 = fold (build (GT_EXPR, integer_type_node, index, integer_zero_node));
-         
-         u = build_nt (CONSTRUCTOR, 0, tree_cons (delta2_identifier, delta2, NULL_TREE));
-         u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, delta,
-                                                  tree_cons (NULL_TREE, index,
-                                                             tree_cons (NULL_TREE, u, NULL_TREE))));
-         e2 = digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0);
+      ndelta = convert (ptrdiff_type_node, build_component_ref (pfn, delta_identifier, NULL_TREE, 0));
+      ndelta2 = convert (ptrdiff_type_node, DELTA2_FROM_PTRMEMFUNC (pfn));
+      idx = build_component_ref (pfn, index_identifier, NULL_TREE, 0);
 
-         pfn = PFN_FROM_PTRMEMFUNC (pfn);
-         npfn = build1 (NOP_EXPR, type, pfn);
-         TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
+      n = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))),
+                               TYPE_METHOD_BASETYPE (TREE_TYPE (type)),
+                               force);
 
-         u = build_nt (CONSTRUCTOR, 0, tree_cons (pfn_identifier, npfn, NULL_TREE));
-         u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, delta,
-                                                  tree_cons (NULL_TREE, index,
-                                                             tree_cons (NULL_TREE, u, NULL_TREE))));
-         e3 = digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0);
-         return build_conditional_expr (e1, e2, e3);
-       }
+      delta = build_binary_op (PLUS_EXPR, ndelta, n, 1);
+      delta2 = build_binary_op (PLUS_EXPR, ndelta2, n, 1);
+      e1 = fold (build (GT_EXPR, boolean_type_node, idx, integer_zero_node));
+         
+      e2 = build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx,
+                             NULL_TREE, delta2);
 
-      ndelta = TREE_VALUE (CONSTRUCTOR_ELTS (pfn));
-      nindex = TREE_VALUE (TREE_CHAIN (CONSTRUCTOR_ELTS (pfn)));
-      npfn = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (CONSTRUCTOR_ELTS (pfn))));
-      npfn = TREE_VALUE (CONSTRUCTOR_ELTS (npfn));
-      if (integer_zerop (nindex))
-       pfn = integer_zero_node;
-      else
-       {
-         sorry ("value casting of varible nonnull pointer to member functions not supported");
-         return error_mark_node;
-       }
+      pfn = PFN_FROM_PTRMEMFUNC (pfn);
+      npfn = build1 (NOP_EXPR, type, pfn);
+      TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
+
+      e3 = build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx, npfn,
+                             NULL_TREE);
+      return build_conditional_expr (e1, e2, e3);
     }
 
-  /* Handle null pointer to member function conversions. */
+  /* Handle null pointer to member function conversions.  */
   if (integer_zerop (pfn))
     {
-      pfn = build_c_cast (type, integer_zero_node, 0);
-      u = build_nt (CONSTRUCTOR, 0, tree_cons (pfn_identifier, pfn, NULL_TREE));
-      u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, integer_zero_node,
-                                              tree_cons (NULL_TREE, integer_zero_node,
-                                                         tree_cons (NULL_TREE, u, NULL_TREE))));
-      return digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0);
+      pfn = build_c_cast (type, integer_zero_node);
+      return build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type),
+                               integer_zero_node, integer_zero_node,
+                               pfn, NULL_TREE);
     }
 
   if (TREE_CODE (pfn) == TREE_LIST
       || (TREE_CODE (pfn) == ADDR_EXPR
          && TREE_CODE (TREE_OPERAND (pfn, 0)) == TREE_LIST))
-    {
-      pfn = instantiate_type (type, pfn, 1);
-      if (pfn == error_mark_node)
-       return error_mark_node;
-      if (TREE_CODE (pfn) != ADDR_EXPR)
-       pfn = build_unary_op (ADDR_EXPR, pfn, 0);
-    }
+    return instantiate_type (type, pfn, 1);
 
-  /* Allow pointer to member conversions here. */
+  /* Allow pointer to member conversions here.  */
   delta = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (TREE_TYPE (pfn))),
                                TYPE_METHOD_BASETYPE (TREE_TYPE (type)),
                                force);
   delta2 = build_binary_op (PLUS_EXPR, delta2, delta, 1);
 
+#if 0
+  /* We need to check the argument types to see if they are compatible
+     (any const or volatile violations.  */
+  something like this:
+  comptype (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (type))),
+           TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (TREE_TYPE (pfn)))), ?);
+#endif
+
   if (TREE_CODE (TREE_OPERAND (pfn, 0)) != FUNCTION_DECL)
     warning ("assuming pointer to member function is non-virtual");
 
   if (TREE_CODE (TREE_OPERAND (pfn, 0)) == FUNCTION_DECL
       && DECL_VINDEX (TREE_OPERAND (pfn, 0)))
     {
-      /* Find the offset to the vfield pointer in the object. */
+      /* Find the offset to the vfield pointer in the object.  */
       vfield_offset = get_binfo (DECL_CONTEXT (TREE_OPERAND (pfn, 0)),
                                 DECL_CLASS_CONTEXT (TREE_OPERAND (pfn, 0)),
                                 0);
@@ -6190,25 +6300,26 @@ build_ptrmemfunc (type, pfn, force)
       delta2 = size_binop (PLUS_EXPR, vfield_offset, delta2);
 
       /* Map everything down one to make room for the null pointer to member.  */
-      index = size_binop (PLUS_EXPR,
-                         DECL_VINDEX (TREE_OPERAND (pfn, 0)),
-                         integer_one_node);
-      u = build_nt (CONSTRUCTOR, 0, tree_cons (delta2_identifier, delta2, NULL_TREE));
+      idx = size_binop (PLUS_EXPR,
+                       DECL_VINDEX (TREE_OPERAND (pfn, 0)),
+                       integer_one_node);
     }
   else
     {
-      index = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node);
-
-      npfn = build1 (NOP_EXPR, type, pfn);
-      TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
+      idx = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node);
 
-      u = build_nt (CONSTRUCTOR, 0, tree_cons (pfn_identifier, npfn, NULL_TREE));
+      if (type == TREE_TYPE (pfn))
+       {
+         npfn = pfn;
+       }
+      else
+       {
+         npfn = build1 (NOP_EXPR, type, pfn);
+         TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
+       }
     }
 
-  u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, delta,
-                                          tree_cons (NULL_TREE, index,
-                                                     tree_cons (NULL_TREE, u, NULL_TREE))));
-  return digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0);
+  return build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx, npfn, delta2);
 }
 
 /* Convert value RHS to type TYPE as preparation for an assignment
@@ -6333,7 +6444,7 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
           || (coder == ENUMERAL_TYPE
               && (INTEGRAL_CODE_P (codel) || codel == REAL_TYPE)))
     {
-      return cp_convert (type, rhs, CONV_IMPLICIT, 0);
+      return cp_convert (type, rhs, CONV_IMPLICIT, LOOKUP_NORMAL);
     }
   /* Conversions among pointers */
   else if (codel == POINTER_TYPE
@@ -6409,13 +6520,13 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
              return error_mark_node;
            }
 
-         if (ctt < 0)
+         if (ctt < 0 && TYPE_MAIN_VARIANT (ttl) != TYPE_MAIN_VARIANT (ttr))
            cp_pedwarn ("converting `%T' to `%T' is a contravariance violation",
-                       ttr, ttl);
+                       rhstype, type);
 
          if (TYPE_MAIN_VARIANT (ttl) != void_type_node
              && TYPE_MAIN_VARIANT (ttr) == void_type_node
-             && rhs != null_pointer_node)
+             && ! null_ptr_cst_p (rhs))
            {
              if (coder == RECORD_TYPE)
                cp_pedwarn ("implicit conversion of signature pointer to type `%T'",
@@ -6466,31 +6577,6 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
                }
            }
        }
-      else if (TREE_CODE (ttr) == OFFSET_TYPE
-              && TREE_CODE (ttl) != OFFSET_TYPE)
-       {
-         /* Normally, pointers to different type codes (other
-            than void) are not compatible, but we perform
-            some type instantiation if that resolves the
-            ambiguity of (X Y::*) and (X *).  */
-
-         if (current_class_decl)
-           {
-             if (TREE_CODE (rhs) == INTEGER_CST)
-               {
-                 rhs = build (PLUS_EXPR, build_pointer_type (TREE_TYPE (ttr)),
-                              current_class_decl, rhs);
-                 return convert_for_assignment (type, rhs,
-                                                errtype, fndecl, parmnum);
-               }
-           }
-         if (TREE_CODE (ttl) == METHOD_TYPE)
-           error ("%s between pointer-to-method and pointer-to-member types",
-                  errtype);
-         else
-           error ("%s between pointer and pointer-to-member types", errtype);
-         return error_mark_node;
-       }
       else
        {
          int add_quals = 0, const_parity = 0, volatile_parity = 0;
@@ -6502,8 +6588,8 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
          for (; ; ttl = TREE_TYPE (ttl), ttr = TREE_TYPE (ttr))
            {
              nptrs -= 1;
-             const_parity |= TYPE_READONLY (ttl) < TYPE_READONLY (ttr);
-             volatile_parity |= TYPE_VOLATILE (ttl) < TYPE_VOLATILE (ttr);
+             const_parity |= (TYPE_READONLY (ttl) < TYPE_READONLY (ttr));
+             volatile_parity |= (TYPE_VOLATILE (ttl) < TYPE_VOLATILE (ttr));
 
              if (! left_const
                  && (TYPE_READONLY (ttl) > TYPE_READONLY (ttr)
@@ -6582,24 +6668,6 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
                    cp_warning ("\t`%T' != `%T'", type, rhstype);
                  }
            }
-         else if (TREE_CODE (TREE_TYPE (rhs)) == METHOD_TYPE)
-           {
-             /* When does this happen?  */
-             my_friendly_abort (119);
-             /* Conversion of a pointer-to-member type to void *.  */
-             rhs = build_unary_op (ADDR_EXPR, rhs, 0);
-             TREE_TYPE (rhs) = type;
-             return rhs;
-           }
-         else if (TREE_CODE (TREE_TYPE (rhs)) == OFFSET_TYPE)
-           {
-             /* When does this happen?  */
-             my_friendly_abort (120);
-             /* Conversion of a pointer-to-member type to void *.  */
-             rhs = build_unary_op (ADDR_EXPR, rhs, 0);
-             TREE_TYPE (rhs) = type;
-             return rhs;
-           }
          else
            {
              if (fndecl)
@@ -6624,9 +6692,8 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
          else
            cp_pedwarn ("%s to `%T' from `%T' lacks a cast",
                        errtype, type, rhstype);
-         return convert (type, rhs);
        }
-      return null_pointer_node;
+      return convert (type, rhs);
     }
   else if (codel == INTEGER_TYPE
           && (coder == POINTER_TYPE
@@ -6652,15 +6719,25 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
     return convert (type, rhs);
 
   /* C++ */
-  else if (((coder == POINTER_TYPE && TREE_CODE (rhs) == ADDR_EXPR
-            && TREE_CODE (rhstype) == POINTER_TYPE
+  else if (((coder == POINTER_TYPE
             && TREE_CODE (TREE_TYPE (rhstype)) == METHOD_TYPE)
            || integer_zerop (rhs)
-           || TYPE_PTRMEMFUNC_P (TREE_TYPE (rhs)))
+           || TYPE_PTRMEMFUNC_P (rhstype))
           && TYPE_PTRMEMFUNC_P (type))
     {
-      /* compatible pointer to member functions. */
-      return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), rhs, 0);
+      tree ttl = TYPE_PTRMEMFUNC_FN_TYPE (type);
+      tree ttr = (TREE_CODE (rhstype) == POINTER_TYPE ? rhstype
+                   : TYPE_PTRMEMFUNC_FN_TYPE (type));
+      int ctt = comp_target_types (ttl, ttr, 1);
+
+      if (ctt < 0)
+       cp_pedwarn ("converting `%T' to `%T' is a contravariance violation",
+                   ttr, ttl);
+      else if (ctt == 0)
+       cp_error ("%s to `%T' from `%T'", errtype, ttl, ttr);
+
+      /* compatible pointer to member functions.  */
+      return build_ptrmemfunc (ttl, rhs, 0);
     }
   else if (codel == ERROR_MARK || coder == ERROR_MARK)
     return error_mark_node;
@@ -6678,6 +6755,13 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
     }
   else if (TYPE_HAS_CONSTRUCTOR (type) || IS_AGGR_TYPE (TREE_TYPE (rhs)))
     return convert (type, rhs);
+  /* Handle anachronistic conversions from (::*)() to cv void* or (*)().  */
+  else if (TREE_CODE (type) == POINTER_TYPE
+          && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
+              || TYPE_MAIN_VARIANT (TREE_TYPE (type)) == void_type_node)
+          && TREE_TYPE (rhs)
+          && TYPE_PTRMEMFUNC_P (TREE_TYPE (rhs)))
+    return convert (type, rhs);
 
   cp_error ("%s to `%T' from `%T'", errtype, type, rhstype);
   return error_mark_node;
@@ -6695,7 +6779,10 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
    latter (X(X&)).
 
    If using constructor make sure no conversion operator exists, if one does
-   exist, an ambiguity exists.  */
+   exist, an ambiguity exists.
+
+   If flags doesn't include LOOKUP_COMPLAIN, don't complain about anything.  */
+
 tree
 convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
      tree exp, type, rhs;
@@ -6724,12 +6811,15 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
       rhs = resolve_offset_ref (rhs);
       if (rhs == error_mark_node)
        return error_mark_node;
-      rhstype = TREE_TYPE (rhs);
-      coder = TREE_CODE (rhstype);
     }
 
+  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)
+       && TREE_CODE (type) != ARRAY_TYPE
+       && (TREE_CODE (type) != REFERENCE_TYPE
+          || TREE_CODE (TREE_TYPE (type)) != ARRAY_TYPE))
       || TREE_CODE (TREE_TYPE (rhs)) == FUNCTION_TYPE
       || TREE_CODE (TREE_TYPE (rhs)) == METHOD_TYPE)
     rhs = default_conversion (rhs);
@@ -6747,12 +6837,6 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
   if (coder == ERROR_MARK)
     return error_mark_node;
 
-#if 0
-  /* This is *not* the quick way out!  It is the way to disaster.  */
-  if (type == rhstype)
-    goto converted;
-#endif
-
   /* We accept references to incomplete types, so we can
      return here before checking if RHS is of complete type.  */
      
@@ -6787,6 +6871,8 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
   if (TREE_CODE (rhstype) == REFERENCE_TYPE)
     rhstype = TREE_TYPE (rhstype);
 
+  type = complete_type (type);
+
   if (TYPE_LANG_SPECIFIC (type)
       && (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type)))
     return build_signature_pointer_constructor (type, rhs);
@@ -6794,6 +6880,9 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
   if (IS_AGGR_TYPE (type)
       && (TYPE_NEEDS_CONSTRUCTING (type) || TREE_HAS_CONSTRUCTOR (rhs)))
     {
+      if (flag_ansi_overloading)
+       return cp_convert (type, rhs, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
+
       if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
        {
          /* This is sufficient to perform initialization.  No need,
@@ -6802,7 +6891,7 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
             cleanups if it is used.  */
          if (TREE_CODE (rhs) == CALL_EXPR)
            {
-             rhs = build_cplus_new (type, rhs, 0);
+             rhs = build_cplus_new (type, rhs);
              return rhs;
            }
          /* Handle the case of default parameter initialization and
@@ -6819,16 +6908,18 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
                    = build_unary_op (ADDR_EXPR, exp, 0);
                }
              else
-               rhs = build_cplus_new (type, TREE_OPERAND (rhs, 0), 0);
+               rhs = build_cplus_new (type, TREE_OPERAND (rhs, 0));
              return rhs;
            }
+         else if (TYPE_HAS_TRIVIAL_INIT_REF (type))
+           return rhs;
        }
       if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype)
          || (IS_AGGR_TYPE (rhstype) && UNIQUELY_DERIVED_FROM_P (type, rhstype)))
        {
          if (TYPE_HAS_INIT_REF (type))
            {
-             tree init = build_method_call (exp, constructor_name_full (type),
+             tree init = build_method_call (exp, ctor_identifier,
                                             build_tree_list (NULL_TREE, rhs),
                                             TYPE_BINFO (type), LOOKUP_NORMAL);
 
@@ -6837,7 +6928,7 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
 
              if (exp == 0)
                {
-                 exp = build_cplus_new (type, init, 0);
+                 exp = build_cplus_new (type, init);
                  return exp;
                }
 
@@ -6861,7 +6952,8 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
          return rhs;
        }
 
-      return convert (type, rhs);
+      return cp_convert (type, rhs, CONV_OLD_CONVERT,
+                        flags | LOOKUP_NO_CONVERSION);
     }
 
   if (type == TREE_TYPE (rhs))
@@ -6950,8 +7042,6 @@ c_expand_return (retval)
   extern tree dtor_label, ctor_label;
   tree result = DECL_RESULT (current_function_decl);
   tree valtype = TREE_TYPE (result);
-  register int use_temp = 0;
-  int returns_value = 1;
 
   if (TREE_THIS_VOLATILE (current_function_decl))
     warning ("function declared `noreturn' has a `return' statement");
@@ -6962,6 +7052,12 @@ c_expand_return (retval)
       return;
     }
 
+  if (processing_template_decl)
+    {
+      add_tree (build_min_nt (RETURN_STMT, retval));
+      return;
+    }
+
   if (retval == NULL_TREE)
     {
       /* A non-named return value does not count.  */
@@ -6974,7 +7070,7 @@ c_expand_return (retval)
        }
 
       if (DECL_CONSTRUCTOR_P (current_function_decl))
-       retval = current_class_decl;
+       retval = current_class_ptr;
       else if (DECL_NAME (result) != NULL_TREE
               && TREE_CODE (valtype) != VOID_TYPE)
        retval = result;
@@ -6999,22 +7095,29 @@ c_expand_return (retval)
        }
     }
   else if (DECL_CONSTRUCTOR_P (current_function_decl)
-          && retval != current_class_decl)
+          && retval != current_class_ptr)
     {
-      error ("return from a constructor: use `this = ...' instead");
-      retval = current_class_decl;
+      if (flag_this_is_variable)
+       error ("return from a constructor: use `this = ...' instead");
+      else
+       error ("return from a constructor");
+      retval = current_class_ptr;
     }
 
+  /* Effective C++ rule 15.  See also start_function.  */
+  if (warn_ecpp
+      && DECL_NAME (current_function_decl) == ansi_opname[(int) MODIFY_EXPR]
+      && retval != current_class_ref)
+    cp_warning ("`operator=' should return a reference to `*this'");
+
   if (valtype == NULL_TREE || TREE_CODE (valtype) == VOID_TYPE)
     {
       current_function_returns_null = 1;
-      /* We do this here so we'll avoid a warning about how the function
-        "may or may not return a value" in finish_function.  */
-      returns_value = 0;
-
-      if (retval)
+      if ((pedantic && ! DECL_ARTIFICIAL (current_function_decl))
+         || TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
        pedwarn ("`return' with a value, in function returning void");
       expand_return (retval);
+      return;
     }
   /* Add some useful error checking for C++.  */
   else if (TREE_CODE (valtype) == REFERENCE_TYPE)
@@ -7031,9 +7134,9 @@ c_expand_return (retval)
 
       /* convert to reference now, so we can give error if we
         return an reference to a non-lvalue.  */
-      retval = convert_for_initialization (tmp_result, valtype, retval,
-                                          LOOKUP_NORMAL, "return",
-                                          NULL_TREE, 0);
+      retval = convert_for_initialization
+       (tmp_result, valtype, retval, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
+        "return", NULL_TREE, 0);
 
       /* Sort through common things to see what it is
         we are returning.  */
@@ -7044,12 +7147,13 @@ c_expand_return (retval)
          if (TREE_CODE (whats_returned) == ADDR_EXPR)
            whats_returned = TREE_OPERAND (whats_returned, 0);
        }
+      if (TREE_CODE (whats_returned) == CONVERT_EXPR)
+       whats_returned = TREE_OPERAND (whats_returned, 0);
       if (TREE_CODE (whats_returned) == ADDR_EXPR)
        {
          whats_returned = TREE_OPERAND (whats_returned, 0);
          while (TREE_CODE (whats_returned) == NEW_EXPR
-                || TREE_CODE (whats_returned) == TARGET_EXPR
-                || TREE_CODE (whats_returned) == WITH_CLEANUP_EXPR)
+                || TREE_CODE (whats_returned) == TARGET_EXPR)
            {
              /* Get the target.  */
              whats_returned = TREE_OPERAND (whats_returned, 0);
@@ -7062,7 +7166,8 @@ c_expand_return (retval)
          if (TEMP_NAME_P (DECL_NAME (whats_returned)))
            warning ("reference to non-lvalue returned");
          else if (! TREE_STATIC (whats_returned)
-                  && IDENTIFIER_LOCAL_VALUE (DECL_NAME (whats_returned)))
+                  && IDENTIFIER_LOCAL_VALUE (DECL_NAME (whats_returned))
+                  && !TREE_PUBLIC (whats_returned))
            cp_warning_at ("reference to local variable `%D' returned", whats_returned);
        }
     }
@@ -7073,9 +7178,19 @@ c_expand_return (retval)
       if (TREE_CODE (whats_returned) == VAR_DECL
          && DECL_NAME (whats_returned)
          && IDENTIFIER_LOCAL_VALUE (DECL_NAME (whats_returned))
-         && !TREE_STATIC (whats_returned))
+         && !TREE_STATIC (whats_returned)
+         && !TREE_PUBLIC (whats_returned))
        cp_warning_at ("address of local variable `%D' returned", whats_returned);
     }
+  else if (TREE_CODE (retval) == VAR_DECL)
+    {
+      if (TREE_CODE (TREE_TYPE (retval)) == ARRAY_TYPE
+         && DECL_NAME (retval)
+         && IDENTIFIER_LOCAL_VALUE (DECL_NAME (retval))
+         && !TREE_STATIC (retval)
+         && !TREE_PUBLIC (retval))
+       cp_warning_at ("address of local array `%D' returned", retval);
+    }
   
   /* Now deal with possible C++ hair:
      (1) Compute the return value.
@@ -7086,149 +7201,55 @@ c_expand_return (retval)
      value must be returned via that.  */
 
   if (retval == result
-      /* Watch out for constructors, which "return" aggregates
-        via initialization, but which otherwise "return" a pointer.  */
       || DECL_CONSTRUCTOR_P (current_function_decl))
+    /* It's already done for us.  */;
+  else if (TREE_TYPE (retval) == void_type_node)
     {
-      /* This is just an error--it's already been reported.  */
-      if (TYPE_SIZE (valtype) == NULL_TREE)
-       return;
-
-      if (TYPE_MODE (valtype) != BLKmode
-         && any_pending_cleanups (1))
-       {
-         retval = get_temp_regvar (valtype, retval);
-         use_temp = obey_regdecls;
-       }
-    }
-  else if (IS_AGGR_TYPE (valtype) && TYPE_NEEDS_CONSTRUCTING (valtype))
-    {
-      /* Throw away the cleanup that `build_functional_cast' gave us.  */
-      if (TREE_CODE (retval) == WITH_CLEANUP_EXPR
-         && TREE_CODE (TREE_OPERAND (retval, 0)) == TARGET_EXPR)
-       retval = TREE_OPERAND (retval, 0);
-      expand_aggr_init (result, retval, 0, LOOKUP_ONLYCONVERTING);
-      expand_cleanups_to (NULL_TREE);
-      DECL_INITIAL (result) = NULL_TREE;
+      pedwarn ("return of void value in function returning non-void");
+      expand_expr_stmt (retval);
       retval = 0;
     }
   else
     {
-      if (TYPE_MODE (valtype) == VOIDmode)
-       {
-         if (TYPE_MODE (TREE_TYPE (result)) != VOIDmode
-             && warn_return_type)
-           warning ("return of void value in function returning non-void");
-         expand_expr_stmt (retval);
-         retval = 0;
-         result = 0;
-       }
-      else if (TYPE_MODE (valtype) != BLKmode
-              && any_pending_cleanups (1))
-       {
-         retval = get_temp_regvar (valtype, retval);
-         expand_cleanups_to (NULL_TREE);
-         use_temp = obey_regdecls;
-         result = 0;
-       }
-      else
+      /* We already did this above for refs, don't do it again.  */
+      if (TREE_CODE (valtype) != REFERENCE_TYPE)
+       retval = convert_for_initialization
+         (NULL_TREE, valtype, retval, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
+          "return", NULL_TREE, 0);
+
+      /* We can't initialize a register from a NEW_EXPR.  */
+      if (! current_function_returns_struct
+         && TREE_CODE (retval) == TARGET_EXPR
+         && TREE_CODE (TREE_OPERAND (retval, 1)) == NEW_EXPR)
+       retval = build (COMPOUND_EXPR, TREE_TYPE (retval), retval,
+                       TREE_OPERAND (retval, 0));
+
+      if (retval == error_mark_node)
        {
-         retval = convert_for_initialization (result, valtype, retval,
-                                              LOOKUP_NORMAL,
-                                              "return", NULL_TREE, 0);
-         DECL_INITIAL (result) = NULL_TREE;
+         /* Avoid warning about control reaching end of function.  */
+         expand_null_return ();
+         return;
        }
-      if (retval == error_mark_node)
-       return;
     }
 
-  emit_queue ();
-
   if (retval != NULL_TREE
       && TREE_CODE_CLASS (TREE_CODE (retval)) == 'd'
       && cond_stack == 0 && loop_stack == 0 && case_stack == 0)
     current_function_return_value = retval;
 
-  if (result)
+  if (ctor_label && TREE_CODE (ctor_label) != ERROR_MARK)
     {
-      /* Everything's great--RETVAL is in RESULT.  */
-      if (original_result_rtx)
-       {
-         store_expr (result, original_result_rtx, 0);
-         expand_cleanups_to (NULL_TREE);
-       }
-      else if (retval && retval != result)
-       {
-         /* Clear this out so the later call to decl_function_context
-            won't end up bombing on us.  */
-         if (DECL_CONTEXT (result) == error_mark_node)
-           DECL_CONTEXT (result) = NULL_TREE;
-         /* Here is where we finally get RETVAL into RESULT.
-            `expand_return' does the magic of protecting
-            RESULT from cleanups.  */
-         retval = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (result), retval);
-         /* This part _must_ come second, because expand_return looks for
-            the INIT_EXPR as the toplevel node only.  :-( */
-         retval = build (INIT_EXPR, TREE_TYPE (result), result, retval);
-         TREE_SIDE_EFFECTS (retval) = 1;
-         expand_return (retval);
-       }
-      else
-       expand_return (result);
-
-      use_variable (DECL_RTL (result));
-      if (ctor_label  && TREE_CODE (ctor_label) != ERROR_MARK)
-       expand_goto (ctor_label);
-      else
-       expand_null_return ();
+      /* Here RETVAL is CURRENT_CLASS_PTR, so there's nothing to do.  */
+      expand_goto (ctor_label);
     }
-  else
+
+  if (retval && retval != result)
     {
-      /* We may still need to put RETVAL into RESULT.  */
-      result = DECL_RESULT (current_function_decl);
-      if (original_result_rtx)
-       {
-         /* Here we have a named return value that went
-            into memory.  We can compute RETVAL into that.  */
-         if (retval)
-           expand_assignment (result, retval, 0, 0);
-         else
-           store_expr (result, original_result_rtx, 0);
-         result = make_tree (TREE_TYPE (result), original_result_rtx);
-       }
-      else if (ctor_label && TREE_CODE (ctor_label) != ERROR_MARK)
-       {
-         /* Here RETVAL is CURRENT_CLASS_DECL, so there's nothing to do.  */
-         expand_goto (ctor_label);
-       }
-      else if (retval)
-       {
-         /* Here is where we finally get RETVAL into RESULT.
-            `expand_return' does the magic of protecting
-            RESULT from cleanups.  */
-         result = build (INIT_EXPR, TREE_TYPE (result), result, retval);
-         TREE_SIDE_EFFECTS (result) = 1;
-         expand_return (result);
-       }
-      else if (TYPE_MODE (TREE_TYPE (result)) != VOIDmode)
-       expand_return (result);
+      result = build (INIT_EXPR, TREE_TYPE (result), result, retval);
+      TREE_SIDE_EFFECTS (result) = 1;
     }
-
-  current_function_returns_value = returns_value;
-#if 0
-  /* These wind up after the BARRIER, which causes problems for
-     expand_end_binding.  What purpose were they supposed to serve?  */
-  if (original_result_rtx)
-    use_variable (original_result_rtx);
-  if (use_temp)
-    use_variable (DECL_RTL (DECL_RESULT (current_function_decl)));
-#endif
-
-  /* One way to clear out cleanups that EXPR might
-     generate.  Note that this code will really be
-     dead code, but that is ok--cleanups that were
-     needed were handled by the magic of `return'.  */
-  expand_cleanups_to (NULL_TREE);
+  expand_return (result);
+  current_function_returns_value = 1;
 }
 \f
 /* Start a C switch statement, testing expression EXP.
@@ -7264,29 +7285,31 @@ c_expand_start_case (exp)
     }
   else
     {
-      tree index;
+      tree idx;
 
       exp = default_conversion (exp);
       type = TREE_TYPE (exp);
-      index = get_unwidened (exp, 0);
+      idx = get_unwidened (exp, 0);
       /* We can't strip a conversion from a signed type to an unsigned,
         because if we did, int_fits_type_p would do the wrong thing
         when checking case values for being in range,
         and it's too hard to do the right thing.  */
       if (TREE_UNSIGNED (TREE_TYPE (exp))
-         == TREE_UNSIGNED (TREE_TYPE (index)))
-       exp = index;
+         == TREE_UNSIGNED (TREE_TYPE (idx)))
+       exp = idx;
     }
 
-  expand_start_case (1, build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp),
-                    type, "switch statement");
+  expand_start_case
+    (1, fold (build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp)),
+     type, "switch statement");
 
   return exp;
 }
 
 /* CONSTP remembers whether or not all the intervening pointers in the `to'
    type have been const.  */
-int
+
+static int
 comp_ptr_ttypes_real (to, from, constp)
      tree to, from;
      int constp;
@@ -7296,15 +7319,25 @@ comp_ptr_ttypes_real (to, from, constp)
       if (TREE_CODE (to) != TREE_CODE (from))
        return 0;
 
-      if (TYPE_READONLY (from) > TYPE_READONLY (to)
-         || TYPE_VOLATILE (from) > TYPE_VOLATILE (to))
-       return 0;
+      if (TREE_CODE (from) == OFFSET_TYPE
+         && comptypes (TYPE_OFFSET_BASETYPE (from),
+                       TYPE_OFFSET_BASETYPE (to), 1))
+         continue;
 
-      if (! constp
-         && (TYPE_READONLY (to) > TYPE_READONLY (from)
-             || TYPE_VOLATILE (to) > TYPE_READONLY (from)))
-       return 0;
-      constp &= TYPE_READONLY (to);
+      /* Const and volatile mean something different for function types,
+        so the usual checks are not appropriate.  */
+      if (TREE_CODE (to) != FUNCTION_TYPE && TREE_CODE (to) != METHOD_TYPE)
+       {
+         if (TYPE_READONLY (from) > TYPE_READONLY (to)
+             || TYPE_VOLATILE (from) > TYPE_VOLATILE (to))
+           return 0;
+
+         if (! constp
+             && (TYPE_READONLY (to) > TYPE_READONLY (from)
+                 || TYPE_VOLATILE (to) > TYPE_READONLY (from)))
+           return 0;
+         constp &= TYPE_READONLY (to);
+       }
 
       if (TREE_CODE (to) != POINTER_TYPE)
        return comptypes (TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from), 1);
@@ -7314,9 +7347,92 @@ comp_ptr_ttypes_real (to, from, constp)
 /* When comparing, say, char ** to char const **, this function takes the
    'char *' and 'char const *'.  Do not pass non-pointer types to this
    function.  */
+
 int
 comp_ptr_ttypes (to, from)
      tree to, from;
 {
   return comp_ptr_ttypes_real (to, from, 1);
 }
+
+/* Returns 1 if to and from are (possibly multi-level) pointers to the same
+   type or inheritance-related types, regardless of cv-quals.  */
+
+int
+ptr_reasonably_similar (to, from)
+     tree to, from;
+{
+  for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
+    {
+      if (TREE_CODE (to) != TREE_CODE (from))
+       return 0;
+
+      if (TREE_CODE (from) == OFFSET_TYPE
+         && comptypes (TYPE_OFFSET_BASETYPE (to),
+                       TYPE_OFFSET_BASETYPE (from), -1))
+       continue;
+
+      if (TREE_CODE (to) != POINTER_TYPE)
+       return comptypes
+         (TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from), -1);
+    }
+}
+
+/* Like comp_ptr_ttypes, for const_cast.  */
+
+static int
+comp_ptr_ttypes_const (to, from)
+     tree to, from;
+{
+  for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
+    {
+      if (TREE_CODE (to) != TREE_CODE (from))
+       return 0;
+
+      if (TREE_CODE (from) == OFFSET_TYPE
+         && comptypes (TYPE_OFFSET_BASETYPE (from),
+                       TYPE_OFFSET_BASETYPE (to), 1))
+         continue;
+
+      if (TREE_CODE (to) != POINTER_TYPE)
+       return comptypes (TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from), 1);
+    }
+}
+
+/* Like comp_ptr_ttypes, for reinterpret_cast.  */
+
+static int
+comp_ptr_ttypes_reinterpret (to, from)
+     tree to, from;
+{
+  int constp = 1;
+
+  for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
+    {
+      if (TREE_CODE (from) == OFFSET_TYPE)
+       from = TREE_TYPE (from);
+      if (TREE_CODE (to) == OFFSET_TYPE)
+       to = TREE_TYPE (to);
+
+      if (TREE_CODE (to) != TREE_CODE (from))
+       return 1;
+
+      /* Const and volatile mean something different for function types,
+        so the usual checks are not appropriate.  */
+      if (TREE_CODE (to) != FUNCTION_TYPE && TREE_CODE (to) != METHOD_TYPE)
+       {
+         if (TYPE_READONLY (from) > TYPE_READONLY (to)
+             || TYPE_VOLATILE (from) > TYPE_VOLATILE (to))
+           return 0;
+
+         if (! constp
+             && (TYPE_READONLY (to) > TYPE_READONLY (from)
+                 || TYPE_VOLATILE (to) > TYPE_READONLY (from)))
+           return 0;
+         constp &= TYPE_READONLY (to);
+       }
+
+      if (TREE_CODE (to) != POINTER_TYPE)
+       return 1;
+    }
+}