OSDN Git Service

* g++.old-deja/g++.benjamin/16077.C: Adjust warnings.
[pf3gnuchains/gcc-fork.git] / gcc / cp / typeck.c
index 17b75cc..0cbff77 100644 (file)
@@ -1,22 +1,22 @@
 /* Build expressions with type checking for C++ compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
+GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2, or (at your option)
 any later version.
 
-GNU CC is distributed in the hope that it will be useful,
+GCC is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
+along with GCC; see the file COPYING.  If not, write to
 the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
@@ -32,6 +32,8 @@ Boston, MA 02111-1307, USA.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "tree.h"
 #include "rtl.h"
 #include "expr.h"
@@ -45,7 +47,7 @@ Boston, MA 02111-1307, USA.  */
 
 static tree convert_for_assignment PARAMS ((tree, tree, const char *, tree,
                                          int));
-static tree pointer_int_sum PARAMS ((enum tree_code, tree, tree));
+static tree cp_pointer_int_sum PARAMS ((enum tree_code, tree, tree));
 static tree rationalize_conditional_expr PARAMS ((enum tree_code, tree));
 static int comp_target_parms PARAMS ((tree, tree));
 static int comp_ptr_ttypes_real PARAMS ((tree, tree, int));
@@ -57,7 +59,6 @@ static int comp_array_types PARAMS ((int (*) (tree, tree, int), tree,
 static tree common_base_type PARAMS ((tree, tree));
 static tree lookup_anon_field PARAMS ((tree, tree));
 static tree pointer_diff PARAMS ((tree, tree, tree));
-static tree build_component_addr PARAMS ((tree, tree));
 static tree qualify_type_recursive PARAMS ((tree, tree));
 static tree get_delta_difference PARAMS ((tree, tree, int));
 static int comp_cv_target_types PARAMS ((tree, tree, int));
@@ -65,6 +66,7 @@ static void casts_away_constness_r PARAMS ((tree *, tree *));
 static int casts_away_constness PARAMS ((tree, tree));
 static void maybe_warn_about_returning_address_of_local PARAMS ((tree));
 static tree strip_all_pointer_quals PARAMS ((tree));
+static tree lookup_destructor (tree, tree, tree);
 
 /* Return the target type of TYPE, which means return T for:
    T*, T&, T[], T (...), and otherwise, just T.  */
@@ -114,12 +116,7 @@ require_complete_type (value)
       && 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_ptr);
-      value = build (COMPONENT_REF, TREE_TYPE (member),
-                    build_indirect_ref (base, NULL), member);
+      value = resolve_offset_ref (value);
       return require_complete_type (value);
     }
 
@@ -161,14 +158,16 @@ complete_type (type)
   return type;
 }
 
-/* Like complete_type, but issue an error if the TYPE cannot be
-   completed.  VALUE is used for informative diagnostics.
+/* Like complete_type, but issue an error if the TYPE cannot be completed.
+   VALUE is used for informative diagnostics.  DIAG_TYPE indicates the type
+   of diagnostic: 0 for an error, 1 for a warning, 2 for a pedwarn.
    Returns NULL_TREE if the type cannot be made complete.  */
 
 tree
-complete_type_or_else (type, value)
+complete_type_or_diagnostic (type, value, diag_type)
      tree type;
      tree value;
+     int diag_type;
 {
   type = complete_type (type);
   if (type == error_mark_node)
@@ -176,7 +175,7 @@ complete_type_or_else (type, value)
     return NULL_TREE;
   else if (!COMPLETE_TYPE_P (type))
     {
-      incomplete_type_error (value, type);
+      cxx_incomplete_type_diagnostic (value, type, diag_type);
       return NULL_TREE;
     }
   else
@@ -207,28 +206,33 @@ qualify_type_recursive (t1, t2)
   if ((TYPE_PTR_P (t1) && TYPE_PTR_P (t2))
       || (TYPE_PTRMEM_P (t1) && TYPE_PTRMEM_P (t2)))
     {
-      tree tt1 = TREE_TYPE (t1);
-      tree tt2 = TREE_TYPE (t2);
+      tree tt1;
+      tree tt2;
       tree b1;
       int type_quals;
       tree tgt;
       tree attributes = (*targetm.merge_type_attributes) (t1, t2);
 
-      if (TREE_CODE (tt1) == OFFSET_TYPE)
+      if (TYPE_PTRMEM_P (t1))
        {
-         b1 = TYPE_OFFSET_BASETYPE (tt1);
-         tt1 = TREE_TYPE (tt1);
-         tt2 = TREE_TYPE (tt2);
+         b1 = TYPE_PTRMEM_CLASS_TYPE (t1);
+         tt1 = TYPE_PTRMEM_POINTED_TO_TYPE (t1);
+         tt2 = TYPE_PTRMEM_POINTED_TO_TYPE (t2);
        }
       else
-       b1 = NULL_TREE;
+       {
+         b1 = NULL_TREE;
+         tt1 = TREE_TYPE (t1);
+         tt2 = TREE_TYPE (t2);
+       }
 
-      type_quals = (CP_TYPE_QUALS (tt1) | CP_TYPE_QUALS (tt2));
+      type_quals = (cp_type_quals (tt1) | cp_type_quals (tt2));
       tgt = qualify_type_recursive (tt1, tt2);
       tgt = cp_build_qualified_type (tgt, type_quals);
       if (b1)
-       tgt = build_offset_type (b1, tgt);
-      t1 = build_pointer_type (tgt);
+       t1 = build_ptrmem_type (b1, tgt);
+      else
+       t1 = build_pointer_type (tgt);
       t1 = build_type_attribute_variant (t1, attributes);
     }
   return t1;
@@ -290,7 +294,7 @@ commonparms (p1, p2)
       if (TREE_VALUE (p1) != TREE_VALUE (p2))
        {
          any_change = 1;
-         TREE_VALUE (n) = common_type (TREE_VALUE (p1), TREE_VALUE (p2));
+         TREE_VALUE (n) = merge_types (TREE_VALUE (p1), TREE_VALUE (p2));
        }
       else
        TREE_VALUE (n) = TREE_VALUE (p1);
@@ -321,7 +325,7 @@ original_type (t)
 }
 
 /* T1 and T2 are arithmetic or enumeration types.  Return the type
-   that will result from the "usual arithmetic converions" on T1 and
+   that will result from the "usual arithmetic conversions" on T1 and
    T2 as described in [expr].  */
 
 tree
@@ -335,16 +339,38 @@ type_after_usual_arithmetic_conversions (t1, t2)
 
   /* FIXME: Attributes.  */
   my_friendly_assert (ARITHMETIC_TYPE_P (t1) 
+                     || TREE_CODE (t1) == COMPLEX_TYPE
                      || TREE_CODE (t1) == ENUMERAL_TYPE,
                      19990725);
   my_friendly_assert (ARITHMETIC_TYPE_P (t2) 
+                     || TREE_CODE (t2) == COMPLEX_TYPE
                      || TREE_CODE (t2) == ENUMERAL_TYPE,
                      19990725);
 
-  /* In what follows, we slightly generalize the rules given in [expr]
-     so as to deal with `long long'.  First, merge the attributes.  */
+  /* In what follows, we slightly generalize the rules given in [expr] so
+     as to deal with `long long' and `complex'.  First, merge the
+     attributes.  */
   attributes = (*targetm.merge_type_attributes) (t1, t2);
 
+  /* If one type is complex, form the common type of the non-complex
+     components, then make that complex.  Use T1 or T2 if it is the
+     required type.  */
+  if (code1 == COMPLEX_TYPE || code2 == COMPLEX_TYPE)
+    {
+      tree subtype1 = code1 == COMPLEX_TYPE ? TREE_TYPE (t1) : t1;
+      tree subtype2 = code2 == COMPLEX_TYPE ? TREE_TYPE (t2) : t2;
+      tree subtype
+       = type_after_usual_arithmetic_conversions (subtype1, subtype2);
+
+      if (code1 == COMPLEX_TYPE && TREE_TYPE (t1) == subtype)
+       return build_type_attribute_variant (t1, attributes);
+      else if (code2 == COMPLEX_TYPE && TREE_TYPE (t2) == subtype)
+       return build_type_attribute_variant (t2, attributes);
+      else
+       return build_type_attribute_variant (build_complex_type (subtype),
+                                            attributes);
+    }
+
   /* If only one is real, use it as the result.  */
   if (code1 == REAL_TYPE && code2 != REAL_TYPE)
     return build_type_attribute_variant (t1, attributes);
@@ -364,6 +390,10 @@ type_after_usual_arithmetic_conversions (t1, t2)
   else if (TYPE_PRECISION (t2) > TYPE_PRECISION (t1))
     return build_type_attribute_variant (t2, attributes);
 
+  /* The types are the same; no need to do anything fancy.  */
+  if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
+    return build_type_attribute_variant (t1, attributes);
+
   if (code1 != REAL_TYPE)
     {
       /* If one is a sizetype, use it so size_binop doesn't blow up.  */
@@ -425,9 +455,17 @@ type_after_usual_arithmetic_conversions (t1, t2)
          || same_type_p (TYPE_MAIN_VARIANT (t2), double_type_node))
        return build_type_attribute_variant (double_type_node,
                                             attributes);
-      else 
+      if (same_type_p (TYPE_MAIN_VARIANT (t1), float_type_node)
+         || same_type_p (TYPE_MAIN_VARIANT (t2), float_type_node))
        return build_type_attribute_variant (float_type_node,
                                             attributes);
+      
+      /* Two floating-point types whose TYPE_MAIN_VARIANTs are none of
+         the standard C++ floating-point types.  Logic earlier in this
+         function has already eliminated the possibility that
+         TYPE_PRECISION (t2) != TYPE_PRECISION (t1), so there's no
+         compelling reason to choose one or the other.  */
+      return build_type_attribute_variant (t1, attributes);
     }
 }
 
@@ -444,6 +482,7 @@ composite_pointer_type (t1, t2, arg1, arg2, location)
      const char* location;
 {
   tree result_type;
+  tree attributes;
 
   /* [expr.rel]
 
@@ -455,12 +494,15 @@ composite_pointer_type (t1, t2, arg1, arg2, location)
     return t1;
  
   /* Deal with pointer-to-member functions in the same way as we deal
-     with pointers to functions. */
+     with pointers to functions.  */
   if (TYPE_PTRMEMFUNC_P (t1))
     t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1);
   if (TYPE_PTRMEMFUNC_P (t2))
     t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2);
   
+  /* Merge the attributes.  */
+  attributes = (*targetm.merge_type_attributes) (t1, t2);
+
   /* We have:
 
        [expr.rel]
@@ -486,8 +528,8 @@ composite_pointer_type (t1, t2, arg1, arg2, location)
       t1 = TREE_TYPE (t1);
       t2 = TREE_TYPE (t2);
       result_type = cp_build_qualified_type (void_type_node,
-                                            (CP_TYPE_QUALS (t1)
-                                             | CP_TYPE_QUALS (t2)));
+                                            (cp_type_quals (t1)
+                                             | cp_type_quals (t2)));
       result_type = build_pointer_type (result_type);
     }
   else
@@ -503,27 +545,24 @@ composite_pointer_type (t1, t2, arg1, arg2, location)
        result_type = full2;
       else
        {
-         cp_pedwarn ("%s between distinct pointer types `%T' and `%T' lacks a cast",
+         pedwarn ("%s between distinct pointer types `%T' and `%T' lacks a cast",
                      location, t1, t2);
          result_type = ptr_type_node;
        }
     }
 
-  return result_type;
+  return build_type_attribute_variant (result_type, attributes);
 }
 
-/* Return the common type of two types.
+/* Return the merged type of two types.
    We assume that comptypes has already been done and returned 1;
    if that isn't so, this may crash.
 
-   This is the type for the result of most arithmetic operations
-   if the operands have the given two types.
-
-   We do not deal with enumeral types here because they have already been
-   converted to integer types.  */
+   This just combines attributes and default arguments; any other
+   differences would cause the two types to compare unalike.  */
 
 tree
-common_type (t1, t2)
+merge_types (t1, t2)
      tree t1, t2;
 {
   register enum tree_code code1;
@@ -533,9 +572,7 @@ common_type (t1, t2)
   /* Save time if the two types are the same.  */
   if (t1 == t2)
     return t1;
-  t1 = original_type (t1);
-  t2 = original_type (t2);
-  if (t1 == t2)
+  if (original_type (t1) == original_type (t2))
     return t1;
 
   /* If one type is nonsense, use the other.  */
@@ -544,20 +581,11 @@ common_type (t1, t2)
   if (t2 == error_mark_node)
     return t1;
 
-  if ((ARITHMETIC_TYPE_P (t1) || TREE_CODE (t1) == ENUMERAL_TYPE)
-      && (ARITHMETIC_TYPE_P (t2) || TREE_CODE (t2) == ENUMERAL_TYPE))
-    return type_after_usual_arithmetic_conversions (t1, t2);
-
   /* Merge the attributes.  */
   attributes = (*targetm.merge_type_attributes) (t1, t2);
 
   /* Treat an enum type as the unsigned integer type of the same width.  */
 
-  if (TREE_CODE (t1) == ENUMERAL_TYPE)
-    t1 = type_for_size (TYPE_PRECISION (t1), 1);
-  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))
@@ -566,88 +594,21 @@ common_type (t1, t2)
   code1 = TREE_CODE (t1);
   code2 = TREE_CODE (t2);
 
-  /* If one type is complex, form the common type of the non-complex
-     components, then make that complex.  Use T1 or T2 if it is the
-     required type.  */
-  if (code1 == COMPLEX_TYPE || code2 == COMPLEX_TYPE)
-    {
-      tree subtype1 = code1 == COMPLEX_TYPE ? TREE_TYPE (t1) : t1;
-      tree subtype2 = code2 == COMPLEX_TYPE ? TREE_TYPE (t2) : t2;
-      tree subtype = common_type (subtype1, subtype2);
-
-      if (code1 == COMPLEX_TYPE && TREE_TYPE (t1) == subtype)
-       return build_type_attribute_variant (t1, attributes);
-      else if (code2 == COMPLEX_TYPE && TREE_TYPE (t2) == subtype)
-       return build_type_attribute_variant (t2, attributes);
-      else
-       return build_type_attribute_variant (build_complex_type (subtype),
-                                            attributes);
-    }
-
   switch (code1)
     {
-    case INTEGER_TYPE:
-    case REAL_TYPE:
-      /* We should have called type_after_usual_arithmetic_conversions
-        above.  */
-      my_friendly_abort (19990725);
-      break;
-
     case POINTER_TYPE:
     case REFERENCE_TYPE:
-      /* For two pointers, do this recursively on the target type,
-        and combine the qualifiers of the two types' targets.  */
-      /* This code was turned off; I don't know why.
-        But ISO C++ specifies doing this with the qualifiers.
-        So I turned it on again.  */
+      /* For two pointers, do this recursively on the target type.  */
       {
-       tree tt1 = TREE_TYPE (t1);
-       tree tt2 = TREE_TYPE (t2);
-       tree b1, b2;
-       int type_quals;
-       tree target;
-
-       if (TREE_CODE (tt1) == OFFSET_TYPE)
-         {
-           b1 = TYPE_OFFSET_BASETYPE (tt1);
-           b2 = TYPE_OFFSET_BASETYPE (tt2);
-           tt1 = TREE_TYPE (tt1);
-           tt2 = TREE_TYPE (tt2);
-         }
-       else
-         b1 = b2 = NULL_TREE;
-
-       type_quals = (CP_TYPE_QUALS (tt1) | CP_TYPE_QUALS (tt2));
-       tt1 = TYPE_MAIN_VARIANT (tt1);
-       tt2 = TYPE_MAIN_VARIANT (tt2);
-
-       if (tt1 == tt2)
-         target = tt1;
-       else if (VOID_TYPE_P (tt1) || VOID_TYPE_P (tt2))
-         target = void_type_node;
-       else if (tt1 == unknown_type_node)
-         target = tt2;
-       else if (tt2 == unknown_type_node)
-         target = tt1;
-       else
-         target = common_type (tt1, tt2);
-
-       target = cp_build_qualified_type (target, type_quals);
-
-       if (b1)
-         {
-           if (same_type_p (b1, b2)
-               || (DERIVED_FROM_P (b1, b2) && binfo_or_else (b1, b2)))
-             target = build_offset_type (b2, target);
-           else if (binfo_or_else (b2, b1))
-             target = build_offset_type (b1, target);
-         }
+       tree target = merge_types (TREE_TYPE (t1), TREE_TYPE (t2));
+       int quals = cp_type_quals (t1);
 
        if (code1 == POINTER_TYPE)
          t1 = build_pointer_type (target);
        else
          t1 = build_reference_type (target);
        t1 = build_type_attribute_variant (t1, attributes);
+       t1 = cp_build_qualified_type (t1, quals);
 
        if (TREE_CODE (target) == METHOD_TYPE)
          t1 = build_ptrmemfunc_type (t1);
@@ -655,9 +616,17 @@ common_type (t1, t2)
        return t1;
       }
 
+    case OFFSET_TYPE:
+      {
+       tree base = TYPE_OFFSET_BASETYPE (t1);
+       tree target = merge_types (TREE_TYPE (t1), TREE_TYPE (t2));
+       t1 = build_offset_type (base, target);
+       break;
+      }
+
     case ARRAY_TYPE:
       {
-       tree elt = common_type (TREE_TYPE (t1), TREE_TYPE (t2));
+       tree elt = merge_types (TREE_TYPE (t1), TREE_TYPE (t2));
        /* Save space: see if the result is identical to one of the args.  */
        if (elt == TREE_TYPE (t1) && TYPE_DOMAIN (t1))
          return build_type_attribute_variant (t1, attributes);
@@ -666,14 +635,14 @@ common_type (t1, t2)
        /* Merge the element types, and have a size if either arg has one.  */
        t1 = build_cplus_array_type
          (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2));
-       return build_type_attribute_variant (t1, attributes);
+       break;
       }
 
     case FUNCTION_TYPE:
       /* Function types: prefer the one that specified arg types.
         If both do, merge the arg types.  Also merge the return types.  */
       {
-       tree valtype = common_type (TREE_TYPE (t1), TREE_TYPE (t2));
+       tree valtype = merge_types (TREE_TYPE (t1), TREE_TYPE (t2));
        tree p1 = TYPE_ARG_TYPES (t1);
        tree p2 = TYPE_ARG_TYPES (t2);
        tree rval, raises;
@@ -702,73 +671,72 @@ common_type (t1, t2)
          }
 
        rval = build_function_type (valtype, commonparms (p1, p2));
-       rval = build_exception_variant (rval, raises);
-       return build_type_attribute_variant (rval, attributes);
+       t1 = build_exception_variant (rval, raises);
+       break;
       }
 
-    case RECORD_TYPE:
-    case UNION_TYPE:
-      t1 = TYPE_MAIN_VARIANT (t1);
-      t2 = TYPE_MAIN_VARIANT (t2);
+    case METHOD_TYPE:
+      {
+       /* 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 (t2)));
+       tree raises = TYPE_RAISES_EXCEPTIONS (t1);
+       tree t3;
+
+       /* If this was a member function type, get back to the
+          original type of type member function (i.e., without
+          the class instance variable up front.  */
+       t1 = build_function_type (TREE_TYPE (t1),
+                                 TREE_CHAIN (TYPE_ARG_TYPES (t1)));
+       t2 = build_function_type (TREE_TYPE (t2),
+                                 TREE_CHAIN (TYPE_ARG_TYPES (t2)));
+       t3 = merge_types (t1, t2);
+       t3 = build_cplus_method_type (basetype, TREE_TYPE (t3),
+                                     TYPE_ARG_TYPES (t3));
+       t1 = build_exception_variant (t3, raises);
+       break;
+      }
 
-      if (DERIVED_FROM_P (t1, t2) && binfo_or_else (t1, t2))
-       return build_type_attribute_variant (t1, attributes);
-      else if (binfo_or_else (t2, t1))
-       return build_type_attribute_variant (t2, attributes);
-      else
-       {
-         compiler_error ("common_type called with uncommon aggregate types");
-         return error_mark_node;
-       }
+    default:;
+    }
+  return build_type_attribute_variant (t1, attributes);
+}
 
-    case METHOD_TYPE:
-      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 raises, t3;
+/* Return the common type of two types.
+   We assume that comptypes has already been done and returned 1;
+   if that isn't so, this may crash.
 
-         tree b1 = TYPE_OFFSET_BASETYPE (t1);
-         tree b2 = TYPE_OFFSET_BASETYPE (t2);
+   This is the type for the result of most arithmetic operations
+   if the operands have the given two types.  */
 
-         if (same_type_p (b1, b2)
-             || (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)));
-           }
+tree
+common_type (t1, t2)
+     tree t1, t2;
+{
+  enum tree_code code1;
+  enum tree_code code2;
 
-         raises = TYPE_RAISES_EXCEPTIONS (t1);
-
-         /* If this was a member function type, get back to the
-            original type of type member function (i.e., without
-            the class instance variable up front.  */
-         t1 = build_function_type (TREE_TYPE (t1),
-                                   TREE_CHAIN (TYPE_ARG_TYPES (t1)));
-         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 (t3, raises);
-       }
-      else
-        compiler_error ("common_type called with uncommon method types");
+  /* If one type is nonsense, bail.  */
+  if (t1 == error_mark_node || t2 == error_mark_node)
+    return error_mark_node;
 
-      return build_type_attribute_variant (t1, attributes);
+  code1 = TREE_CODE (t1);
+  code2 = TREE_CODE (t2);
 
-    case OFFSET_TYPE:
-      /* Pointers to members should now be handled by the POINTER_TYPE
-        case above.  */
-      my_friendly_abort (990325);
+  if ((ARITHMETIC_TYPE_P (t1) || code1 == ENUMERAL_TYPE
+       || code1 == COMPLEX_TYPE)
+      && (ARITHMETIC_TYPE_P (t2) || code2 == ENUMERAL_TYPE
+         || code2 == COMPLEX_TYPE))
+    return type_after_usual_arithmetic_conversions (t1, t2);
 
-    default:
-      return build_type_attribute_variant (t1, attributes);
-    }
+  else if ((TYPE_PTR_P (t1) && TYPE_PTR_P (t2))
+          || (TYPE_PTRMEM_P (t1) && TYPE_PTRMEM_P (t2))
+          || (TYPE_PTRMEMFUNC_P (t1) && TYPE_PTRMEMFUNC_P (t2)))
+    return composite_pointer_type (t1, t2, error_mark_node, error_mark_node,
+                                  "conversion");
+
+  else
+    abort ();
 }
 \f
 /* Compare two exception specifier types for exactness or subsetness, if
@@ -795,7 +763,7 @@ comp_except_types (a, b, exact)
     return 1;
   else if (!exact)
     {
-      if (CP_TYPE_QUALS (a) || CP_TYPE_QUALS (b))
+      if (cp_type_quals (a) || cp_type_quals (b))
         return 0;
       
       if (TREE_CODE (a) == POINTER_TYPE
@@ -803,7 +771,7 @@ comp_except_types (a, b, exact)
         {
           a = TREE_TYPE (a);
           b = TREE_TYPE (b);
-          if (CP_TYPE_QUALS (a) || CP_TYPE_QUALS (b))
+          if (cp_type_quals (a) || cp_type_quals (b))
             return 0;
         }
       
@@ -818,7 +786,7 @@ comp_except_types (a, b, exact)
 }
 
 /* Return 1 if TYPE1 and TYPE2 are equivalent exception specifiers.
-   If EXACT is 0, T2 can be a subset of T1 (according to 15.4/7),
+   If EXACT is 0, T2 can be stricter than T1 (according to 15.4/7),
    otherwise it must be exact. Exception lists are unordered, but
    we've already filtered out duplicates. Most lists will be in order,
    we should try to make use of that.  */
@@ -835,13 +803,13 @@ comp_except_specs (t1, t2, exact)
   if (t1 == t2)
     return 1;
   
-  if (t1 == NULL_TREE)              /* T1 is ... */
+  if (t1 == NULL_TREE)              /* T1 is ...  */
     return t2 == NULL_TREE || !exact;
   if (!TREE_VALUE (t1)) /* t1 is EMPTY */
     return t2 != NULL_TREE && !TREE_VALUE (t2);
-  if (t2 == NULL_TREE)              /* T2 is ... */
+  if (t2 == NULL_TREE)              /* T2 is ...  */
     return 0;
-  if (TREE_VALUE(t1) && !TREE_VALUE (t2)) /* T2 is EMPTY, T1 is not */
+  if (TREE_VALUE (t1) && !TREE_VALUE (t2)) /* T2 is EMPTY, T1 is not */
     return !exact;
   
   /* Neither set is ... or EMPTY, make sure each part of T2 is in T1.
@@ -897,7 +865,7 @@ comp_array_types (cmp, t1, t2, strict)
     return 1;
 
   /* If one of the arrays is dimensionless, and the other has a
-     dimension, they are of different types.  However, it is legal to
+     dimension, they are of different types.  However, it is valid to
      write:
 
        extern int a[];
@@ -937,7 +905,7 @@ comptypes (t1, t2, strict)
        extern int (*i)[];
        int (*i)[8];
 
-     is not legal, for example.  */
+     is invalid, for example.  */
   strict &= ~COMPARE_REDECLARATION;
 
   /* Suppress errors caused by previously reported errors */
@@ -965,9 +933,9 @@ comptypes (t1, t2, strict)
       /* Treat an enum type as the unsigned integer type of the same width.  */
 
       if (TREE_CODE (t1) == ENUMERAL_TYPE)
-       t1 = type_for_size (TYPE_PRECISION (t1), 1);
+       t1 = c_common_type_for_size (TYPE_PRECISION (t1), 1);
       if (TREE_CODE (t2) == ENUMERAL_TYPE)
-       t2 = type_for_size (TYPE_PRECISION (t2), 1);
+       t2 = c_common_type_for_size (TYPE_PRECISION (t2), 1);
 
       if (t1 == t2)
        return 1;
@@ -978,12 +946,19 @@ comptypes (t1, t2, strict)
   if (TYPE_PTRMEMFUNC_P (t2))
     t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2);
 
+  /* TYPENAME_TYPEs should be resolved if the qualifying scope is the
+     current instantiation.  */
+  if (TREE_CODE (t1) == TYPENAME_TYPE)
+    t1 = resolve_typename_type_in_current_instantiation (t1);
+  if (TREE_CODE (t2) == TYPENAME_TYPE)
+    t2 = resolve_typename_type_in_current_instantiation (t2);
+
   /* Different classes of types can't be compatible.  */
   if (TREE_CODE (t1) != TREE_CODE (t2))
     return 0;
 
   /* Qualifiers must match.  */
-  if (CP_TYPE_QUALS (t1) != CP_TYPE_QUALS (t2))
+  if (cp_type_quals (t1) != cp_type_quals (t2))
     return 0;
   if (strict == COMPARE_STRICT 
       && TYPE_FOR_JAVA (t1) != TYPE_FOR_JAVA (t2))
@@ -1042,20 +1017,6 @@ comptypes (t1, t2, strict)
             && comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict));
       break;
 
-    case METHOD_TYPE:
-      if (! comp_except_specs (TYPE_RAISES_EXCEPTIONS (t1),
-                              TYPE_RAISES_EXCEPTIONS (t2), 1))
-       return 0;
-
-      /* This case is anti-symmetrical!
-        One can pass a base member (or member function)
-        to something expecting a derived member (or member function),
-        but not vice-versa!  */
-
-      val = (comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict)
-            && compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2)));
-      break;
-
     case POINTER_TYPE:
     case REFERENCE_TYPE:
       t1 = TREE_TYPE (t1);
@@ -1070,11 +1031,8 @@ comptypes (t1, t2, strict)
        goto look_hard;
       break;
 
+    case METHOD_TYPE:
     case FUNCTION_TYPE:
-      if (! comp_except_specs (TYPE_RAISES_EXCEPTIONS (t1),
-                              TYPE_RAISES_EXCEPTIONS (t2), 1))
-       return 0;
-
       val = ((TREE_TYPE (t1) == TREE_TYPE (t2)
              || comptypes (TREE_TYPE (t1), TREE_TYPE (t2), strict))
             && compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2)));
@@ -1097,6 +1055,12 @@ comptypes (t1, t2, strict)
         return 0;
       return same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2));
 
+    case UNBOUND_CLASS_TEMPLATE:
+      if (cp_tree_equal (TYPE_IDENTIFIER (t1),
+                         TYPE_IDENTIFIER (t2)) < 1)
+        return 0;
+      return same_type_p (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2));
+
     case COMPLEX_TYPE:
       return same_type_p (TREE_TYPE (t1), TREE_TYPE (t2));
 
@@ -1321,8 +1285,8 @@ at_least_as_qualified_p (type1, type2)
      tree type2;
 {
   /* All qualifiers for TYPE2 must also appear in TYPE1.  */
-  return ((CP_TYPE_QUALS (type1) & CP_TYPE_QUALS (type2))
-         == CP_TYPE_QUALS (type2));
+  return ((cp_type_quals (type1) & cp_type_quals (type2))
+         == cp_type_quals (type2));
 }
 
 /* Returns 1 if TYPE1 is more qualified than TYPE2.  */
@@ -1332,7 +1296,7 @@ more_qualified_p (type1, type2)
      tree type1;
      tree type2;
 {
-  return (CP_TYPE_QUALS (type1) != CP_TYPE_QUALS (type2)
+  return (cp_type_quals (type1) != cp_type_quals (type2)
          && at_least_as_qualified_p (type1, type2));
 }
 
@@ -1344,7 +1308,7 @@ comp_cv_qualification (type1, type2)
      tree type1;
      tree type2;
 {
-  if (CP_TYPE_QUALS (type1) == CP_TYPE_QUALS (type2))
+  if (cp_type_quals (type1) == cp_type_quals (type2))
     return 0;
 
   if (at_least_as_qualified_p (type1, type2))
@@ -1481,7 +1445,7 @@ comp_target_parms (parms1, parms2)
 
   if (t1 == 0 && t2 != 0)
     {
-      cp_pedwarn ("ISO C++ prohibits conversion from `%#T' to `(...)'",
+      pedwarn ("ISO C++ prohibits conversion from `%#T' to `(...)'",
                  parms2);
       return self_promoting_args_p (t2);
     }
@@ -1536,79 +1500,50 @@ comp_target_parms (parms1, parms2)
   return warn_contravariance ? -1 : 1;
 }
 \f
-/* Compute the value of the `sizeof' operator.  */
-
 tree
-c_sizeof (type)
+cxx_sizeof_or_alignof_type (type, op, complain)
      tree type;
+     enum tree_code op;
+     int complain;
 {
-  enum tree_code code = TREE_CODE (type);
-  tree size;
+  enum tree_code type_code;
+  tree value;
+  const char *op_name;
 
+  my_friendly_assert (op == SIZEOF_EXPR || op == ALIGNOF_EXPR, 20020720);
   if (processing_template_decl)
-    return build_min (SIZEOF_EXPR, sizetype, type);
+    return build_min_nt (op, type);
+  
+  op_name = operator_name_info[(int) op].name;
+  
+  if (TREE_CODE (type) == REFERENCE_TYPE)
+    type = TREE_TYPE (type);
+  type_code = TREE_CODE (type);
 
-  if (code == FUNCTION_TYPE)
+  if (type_code == METHOD_TYPE)
     {
-      if (pedantic || warn_pointer_arith)
-       pedwarn ("ISO C++ forbids applying `sizeof' to a function type");
-      size = size_one_node;
+      if (complain && (pedantic || warn_pointer_arith))
+       pedwarn ("invalid application of `%s' to a member function", op_name);
+      value = size_one_node;
     }
-  else if (code == METHOD_TYPE)
+  else if (type_code == OFFSET_TYPE)
     {
-      if (pedantic || warn_pointer_arith)
-       pedwarn ("ISO C++ forbids applying `sizeof' to a member function");
-      size = size_one_node;
+      if (complain)
+       error ("invalid application of `%s' to non-static member", op_name);
+      value = size_zero_node;
     }
-  else if (code == VOID_TYPE)
-    {
-      if (pedantic || warn_pointer_arith)
-       pedwarn ("ISO C++ forbids applying `sizeof' to type `void' which is an incomplete type");
-      size = size_one_node;
-    }
-  else if (code == ERROR_MARK)
-    size = size_one_node;
   else
-    {
-      /* ARM $5.3.2: ``When applied to a reference, the result is the
-        size of the referenced object.'' */
-      if (code == REFERENCE_TYPE)
-       type = TREE_TYPE (type);
+    value = c_sizeof_or_alignof_type (complete_type (type), op, complain);
 
-      if (code == OFFSET_TYPE)
-       {
-         cp_error ("`sizeof' applied to non-static member");
-         size = size_zero_node;
-       }
-      else if (!COMPLETE_TYPE_P (complete_type (type)))
-       {
-         cp_error ("`sizeof' applied to incomplete type `%T'", type);
-         size = size_zero_node;
-       }
-      else
-       /* Convert in case a char is more than one unit.  */
-       size = size_binop (CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type),
-                          size_int (TYPE_PRECISION (char_type_node)
-                                    / BITS_PER_UNIT));
-    }
-
-  /* SIZE will have an integer type with TYPE_IS_SIZETYPE set.
-     TYPE_IS_SIZETYPE means that certain things (like overflow) will
-     never happen.  However, this node should really have type
-     `size_t', which is just a typedef for an ordinary integer type.  */
-  size = fold (build1 (NOP_EXPR, c_size_type_node, size));
-  my_friendly_assert (!TYPE_IS_SIZETYPE (TREE_TYPE (size)), 
-                     20001021);
-  return size;
+  return value;
 }
 
-
 tree
 expr_sizeof (e)
      tree e;
 {
   if (processing_template_decl)
-    return build_min (SIZEOF_EXPR, sizetype, e);
+    return build_min_nt (SIZEOF_EXPR, e);
 
   if (TREE_CODE (e) == COMPONENT_REF
       && DECL_C_BIT_FIELD (TREE_OPERAND (e, 1)))
@@ -1620,10 +1555,10 @@ expr_sizeof (e)
     }
   else if (type_unknown_p (e))
     {
-      incomplete_type_error (e, TREE_TYPE (e));
+      cxx_incomplete_type_error (e, TREE_TYPE (e));
       return c_sizeof (char_type_node);
     }
-  /* It's illegal to say `sizeof (X::i)' for `i' a non-static data
+  /* It's invalid to say `sizeof (X::i)' for `i' a non-static data
      member unless you're in a non-static member of X.  So hand off to
      resolve_offset_ref.  [expr.prim]  */
   else if (TREE_CODE (e) == OFFSET_REF)
@@ -1632,73 +1567,9 @@ expr_sizeof (e)
   if (e == error_mark_node)
     return e;
 
-  return c_sizeof (TREE_TYPE (e));
+  return cxx_sizeof (TREE_TYPE (e));
 }
   
-tree
-c_sizeof_nowarn (type)
-     tree type;
-{
-  enum tree_code code = TREE_CODE (type);
-  tree size;
-
-  if (code == FUNCTION_TYPE
-      || code == METHOD_TYPE
-      || code == VOID_TYPE
-      || code == ERROR_MARK)
-    size = size_one_node;
-  else
-    {
-      if (code == REFERENCE_TYPE)
-       type = TREE_TYPE (type);
-
-      if (!COMPLETE_TYPE_P (type))
-       size = size_zero_node;
-      else
-       /* Convert in case a char is more than one unit.  */
-       size = size_binop (CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type),
-                          size_int (TYPE_PRECISION (char_type_node)
-                                    / BITS_PER_UNIT));
-    }
-
-  /* SIZE will have an integer type with TYPE_IS_SIZETYPE set.
-     TYPE_IS_SIZETYPE means that certain things (like overflow) will
-     never happen.  However, this node should really have type
-     `size_t', which is just a typedef for an ordinary integer type.  */
-  size = fold (build1 (NOP_EXPR, c_size_type_node, size));
-  my_friendly_assert (!TYPE_IS_SIZETYPE (TREE_TYPE (size)), 
-                     20001021);
-  return size;
-}
-
-/* Implement the __alignof keyword: Return the minimum required
-   alignment of TYPE, measured in bytes.  */
-
-tree
-c_alignof (type)
-     tree type;
-{
-  enum tree_code code = TREE_CODE (type);
-  tree t;
-
-  if (processing_template_decl)
-    return build_min (ALIGNOF_EXPR, sizetype, type);
-
-  if (code == FUNCTION_TYPE || code == METHOD_TYPE)
-    t = size_int (FUNCTION_BOUNDARY / BITS_PER_UNIT);
-  else if (code == VOID_TYPE || code == ERROR_MARK)
-    t = size_one_node;
-  else
-    { 
-      /* Similar to sizeof, __alignof applies to the referant.  */
-      if (code == REFERENCE_TYPE)
-       type = TREE_TYPE (type);
-
-      t = size_int (TYPE_ALIGN (type) / BITS_PER_UNIT);
-    }
-
-  return fold (build1 (NOP_EXPR, c_size_type_node, t));
-}
 \f
 /* Perform the array-to-pointer and function-to-pointer conversions
    for EXP.  
@@ -1729,6 +1600,12 @@ decay_conversion (exp)
   if (type == error_mark_node)
     return error_mark_node;
 
+  if (type_unknown_p (exp))
+    {
+      cxx_incomplete_type_error (exp, TREE_TYPE (exp));
+      return error_mark_node;
+    }
+  
   /* Constants can be used directly unless they're not loadable.  */
   if (TREE_CODE (exp) == CONST_DECL)
     exp = DECL_INITIAL (exp);
@@ -1751,7 +1628,7 @@ decay_conversion (exp)
       return error_mark_node;
     }
   if (code == METHOD_TYPE)
-    my_friendly_abort (990506);
+    abort ();
   if (code == FUNCTION_TYPE || is_overloaded_fn (exp))
     return build_unary_op (ADDR_EXPR, exp, 0);
   if (code == ARRAY_TYPE)
@@ -1798,7 +1675,7 @@ decay_conversion (exp)
             is not the target type of the type of the ADDR_EXPR itself.
             Question is, can this lossage be avoided?  */
          adr = build1 (ADDR_EXPR, ptrtype, exp);
-         if (mark_addressable (exp) == 0)
+         if (!cxx_mark_addressable (exp))
            return error_mark_node;
          TREE_CONSTANT (adr) = staticp (exp);
          TREE_SIDE_EFFECTS (adr) = 0;   /* Default would be, same as EXP.  */
@@ -1891,50 +1768,10 @@ string_conv_p (totype, exp, warn)
 
   /* This warning is not very useful, as it complains about printf.  */
   if (warn && warn_write_strings)
-    cp_warning ("deprecated conversion from string constant to `%T'", totype);
+    warning ("deprecated conversion from string constant to `%T'", totype);
 
   return 1;
 }
-\f
-tree
-build_object_ref (datum, basetype, field)
-     tree datum, basetype, field;
-{
-  tree dtype;
-  if (datum == error_mark_node)
-    return error_mark_node;
-
-  dtype = TREE_TYPE (datum);
-  if (TREE_CODE (dtype) == REFERENCE_TYPE)
-    dtype = TREE_TYPE (dtype);
-  if (! IS_AGGR_TYPE_CODE (TREE_CODE (dtype)))
-    {
-      cp_error ("request for member `%T::%D' in expression of non-aggregate type `%T'",
-               basetype, field, dtype);
-      return error_mark_node;
-    }
-  else if (is_aggr_type (basetype, 1))
-    {
-      tree binfo = binfo_or_else (basetype, dtype);
-      if (binfo)
-       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, and converts
-   from a reference.  Must compute access for current_class_ref.
-   Otherwise, ok.  */
-
-tree
-build_component_ref_1 (datum, field, protect)
-     tree datum, field;
-     int protect;
-{
-  return convert_from_reference
-    (build_component_ref (datum, field, NULL_TREE, protect));
-}
 
 /* Given a COND_EXPR, MIN_EXPR, or MAX_EXPR in T, return it in a form that we
    can, for example, use as an lvalue.  This code used to be in
@@ -1984,7 +1821,7 @@ lookup_anon_field (t, type)
     {
       if (TREE_STATIC (field))
        continue;
-      if (TREE_CODE (field) != FIELD_DECL)
+      if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field))
        continue;
 
       /* If we find it directly, return the field.  */
@@ -2006,307 +1843,454 @@ lookup_anon_field (t, type)
   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.  */
+/* Build an expression representing OBJECT.MEMBER.  OBJECT is an
+   expression; MEMBER is a DECL or baselink.  If ACCESS_PATH is
+   non-NULL, it indicates the path to the base used to name MEMBER.
+   If PRESERVE_REFERENCE is true, the expression returned will have
+   REFERENCE_TYPE if the MEMBER does.  Otherwise, the expression
+   returned will have the type referred to by the reference. 
+
+   This function does not perform access control; that is either done
+   earlier by the parser when the name of MEMBER is resolved to MEMBER
+   itself, or later when overload resolution selects one of the
+   functions indicated by MEMBER.  */
 
 tree
-build_component_ref (datum, component, basetype_path, protect)
-     tree datum, component, basetype_path;
-     int protect;
+build_class_member_access_expr (tree object, tree member, 
+                               tree access_path, bool preserve_reference)
 {
-  register tree basetype;
-  register enum tree_code code;
-  register tree field = NULL;
-  register tree ref;
-  tree field_type;
-  int type_quals;
+  tree object_type;
+  tree member_scope;
+  tree result = NULL_TREE;
 
-  if (processing_template_decl)
-    return build_min_nt (COMPONENT_REF, datum, component);
-  
-  if (datum == error_mark_node 
-      || TREE_TYPE (datum) == error_mark_node)
+  if (object == error_mark_node || member == error_mark_node)
     return error_mark_node;
 
-  /* BASETYPE holds the type of the class containing the COMPONENT.  */
-  basetype = TYPE_MAIN_VARIANT (TREE_TYPE (datum));
-    
-  /* If DATUM is a COMPOUND_EXPR or COND_EXPR, move our reference
-     inside it.  */
-  switch (TREE_CODE (datum))
-    {
-    case COMPOUND_EXPR:
-      {
-       tree value = build_component_ref (TREE_OPERAND (datum, 1), component,
-                                         basetype_path, protect);
-       return build (COMPOUND_EXPR, TREE_TYPE (value),
-                     TREE_OPERAND (datum, 0), value);
-      }
-    case COND_EXPR:
-      return build_conditional_expr
-       (TREE_OPERAND (datum, 0),
-        build_component_ref (TREE_OPERAND (datum, 1), component,
-                             basetype_path, protect),
-        build_component_ref (TREE_OPERAND (datum, 2), component,
-                             basetype_path, protect));
-
-    case TEMPLATE_DECL:
-      cp_error ("invalid use of %D", datum);
-      datum = error_mark_node;
-      break;
+  if (TREE_CODE (member) == PSEUDO_DTOR_EXPR)
+    return member;
 
-    default:
-      break;
-    }
+  my_friendly_assert (DECL_P (member) || BASELINK_P (member),
+                     20020801);
 
-  code = TREE_CODE (basetype);
+  /* [expr.ref]
 
-  if (code == REFERENCE_TYPE)
-    {
-      datum = convert_from_reference (datum);
-      basetype = TYPE_MAIN_VARIANT (TREE_TYPE (datum));
-      code = TREE_CODE (basetype);
-    }
-  if (TREE_CODE (datum) == OFFSET_REF)
+     The type of the first expression shall be "class object" (of a
+     complete type).  */
+  object_type = TREE_TYPE (object);
+  if (!complete_type_or_else (object_type, object))
+    return error_mark_node;
+  if (!CLASS_TYPE_P (object_type))
     {
-      datum = resolve_offset_ref (datum);
-      basetype = TYPE_MAIN_VARIANT (TREE_TYPE (datum));
-      code = TREE_CODE (basetype);
+      error ("request for member `%D' in `%E', which is of non-class type `%T'", 
+            member, object, object_type);
+      return error_mark_node;
     }
 
-  /* First, see if there is a field or component with name COMPONENT.  */
-  if (TREE_CODE (component) == TREE_LIST)
+  /* The standard does not seem to actually say that MEMBER must be a
+     member of OBJECT_TYPE.  However, that is clearly what is
+     intended.  */
+  if (DECL_P (member))
     {
-      /* I could not trigger this code. MvL */
-      my_friendly_abort (980326);
-#ifdef DEAD
-      my_friendly_assert (!(TREE_CHAIN (component) == NULL_TREE
-               && DECL_CHAIN (TREE_VALUE (component)) == NULL_TREE), 309);
-#endif
-      return build (COMPONENT_REF, TREE_TYPE (component), datum, component);
+      member_scope = DECL_CLASS_CONTEXT (member);
+      mark_used (member);
+      if (TREE_DEPRECATED (member))
+       warn_deprecated_use (member);
     }
-
-  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'",
-                 component, datum, basetype);
+  else
+    member_scope = BINFO_TYPE (BASELINK_BINFO (member));
+  /* If MEMBER is from an anonymous aggregate, MEMBER_SCOPE will
+     presently be the anonymous union.  Go outwards until we find a
+     type related to OBJECT_TYPE.  */
+  while (ANON_AGGR_TYPE_P (member_scope)
+        && !same_type_ignoring_top_level_qualifiers_p (member_scope,
+                                                       object_type))
+    member_scope = TYPE_CONTEXT (member_scope);
+  if (!member_scope || !DERIVED_FROM_P (member_scope, object_type))
+    {
+      error ("`%D' is not a member of `%T'", member, object_type);
       return error_mark_node;
     }
 
-  if (!complete_type_or_else (basetype, datum))
-    return error_mark_node;
+  /* Transform `(a, b).x' into `(*(a, &b)).x', `(a ? b : c).x' into
+     `(*(a ?  &b : &c)).x', and so on.  A COND_EXPR is only an lvalue
+     in the frontend; only _DECLs and _REFs are lvalues in the backend.  */
+  {
+    tree temp = unary_complex_lvalue (ADDR_EXPR, object);
+    if (temp)
+      object = build_indirect_ref (temp, NULL);
+  }
 
-  if (TREE_CODE (component) == BIT_NOT_EXPR)
+  /* In [expr.ref], there is an explicit list of the valid choices for
+     MEMBER.  We check for each of those cases here.  */
+  if (TREE_CODE (member) == VAR_DECL)
+    {
+      /* A static data member.  */
+      result = member;
+      /* If OBJECT has side-effects, they are supposed to occur.  */
+      if (TREE_SIDE_EFFECTS (object))
+       result = build (COMPOUND_EXPR, TREE_TYPE (result), object, result);
+    }
+  else if (TREE_CODE (member) == FIELD_DECL)
     {
-      if (TYPE_IDENTIFIER (basetype) != TREE_OPERAND (component, 0))
+      /* A non-static data member.  */
+      bool null_object_p;
+      int type_quals;
+      tree member_type;
+
+      null_object_p = (TREE_CODE (object) == INDIRECT_REF
+                      && integer_zerop (TREE_OPERAND (object, 0)));
+
+      /* Convert OBJECT to the type of MEMBER.  */
+      if (!same_type_p (object_type, member_scope))
        {
-         cp_error ("destructor specifier `%T::~%T' must have matching names",
-                   basetype, TREE_OPERAND (component, 0));
-         return error_mark_node;
+         tree binfo;
+         base_kind kind;
+
+         binfo = lookup_base (access_path ? access_path : object_type,
+                              member_scope, ba_ignore,  &kind);
+         if (binfo == error_mark_node)
+           return error_mark_node;
+
+         /* It is invalid to use to try to get to a virtual base of a
+            NULL object.  The most common cause is invalid use of
+            offsetof macro.  */
+         if (null_object_p && kind == bk_via_virtual)
+           {
+             error ("invalid access to non-static data member `%D' of NULL object",
+                    member);
+             error ("(perhaps the `offsetof' macro was used incorrectly)");
+             return error_mark_node;
+           }
+
+         /* Convert to the base.  */
+         object = build_base_path (PLUS_EXPR, object, binfo, 
+                                   /*nonnull=*/1);
+         /* If we found the base successfully then we should be able
+            to convert to it successfully.  */
+         my_friendly_assert (object != error_mark_node,
+                             20020801);
        }
-      if (! TYPE_HAS_DESTRUCTOR (basetype))
+
+      /* Complain about other invalid uses of offsetof, even though they will
+        give the right answer.  Note that we complain whether or not they
+        actually used the offsetof macro, since there's no way to know at this
+        point.  So we just give a warning, instead of a pedwarn.  */
+      if (null_object_p && CLASSTYPE_NON_POD_P (object_type))
        {
-         cp_error ("type `%T' has no destructor", basetype);
-         return error_mark_node;
+         warning ("invalid access to non-static data member `%D' of NULL object", 
+                  member);
+         warning  ("(perhaps the `offsetof' macro was used incorrectly)");
+       }
+
+      /* If MEMBER is from an anonymous aggregate, we have converted
+        OBJECT so that it refers to the class containing the
+        anonymous union.  Generate a reference to the anonymous union
+        itself, and recur to find MEMBER.  */
+      if (ANON_AGGR_TYPE_P (DECL_CONTEXT (member))
+         /* When this code is called from build_field_call, the
+            object already has the type of the anonymous union.
+            That is because the COMPONENT_REF was already
+            constructed, and was then disassembled before calling
+            build_field_call.  After the function-call code is
+            cleaned up, this waste can be eliminated.  */
+         && (!same_type_ignoring_top_level_qualifiers_p 
+             (TREE_TYPE (object), DECL_CONTEXT (member))))
+       {
+         tree anonymous_union;
+
+         anonymous_union = lookup_anon_field (TREE_TYPE (object),
+                                              DECL_CONTEXT (member));
+         object = build_class_member_access_expr (object,
+                                                  anonymous_union,
+                                                  /*access_path=*/NULL_TREE,
+                                                  preserve_reference);
        }
-      return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 1);
-    }
 
-  /* Look up component name in the structure type definition.  */
-  if (TYPE_VFIELD (basetype)
-      && DECL_NAME (TYPE_VFIELD (basetype)) == component)
-    /* Special-case this because if we use normal lookups in an ambiguous
-       hierarchy, the compiler will abort (because vptr lookups are
-       not supposed to be ambiguous.  */
-    field = TYPE_VFIELD (basetype);
-  else if (TREE_CODE (component) == FIELD_DECL)
-    field = component;
-  else if (TREE_CODE (component) == TYPE_DECL)
+      /* Compute the type of the field, as described in [expr.ref].  */
+      type_quals = TYPE_UNQUALIFIED;
+      member_type = TREE_TYPE (member);
+      if (TREE_CODE (member_type) != REFERENCE_TYPE)
+       {
+         type_quals = (cp_type_quals (member_type)  
+                       | cp_type_quals (object_type));
+         
+         /* A field is const (volatile) if the enclosing object, or the
+            field itself, is const (volatile).  But, a mutable field is
+            not const, even within a const object.  */
+         if (DECL_MUTABLE_P (member))
+           type_quals &= ~TYPE_QUAL_CONST;
+         member_type = cp_build_qualified_type (member_type, type_quals);
+       }
+
+      result = fold (build (COMPONENT_REF, member_type, object, member));
+
+      /* Mark the expression const or volatile, as appropriate.  Even
+        though we've dealt with the type above, we still have to mark the
+        expression itself.  */
+      if (type_quals & TYPE_QUAL_CONST)
+       TREE_READONLY (result) = 1;
+      else if (type_quals & TYPE_QUAL_VOLATILE)
+       TREE_THIS_VOLATILE (result) = 1;
+    }
+  else if (BASELINK_P (member))
+    {
+      /* The member is a (possibly overloaded) member function.  */
+      tree functions;
+      tree type;
+
+      /* If the MEMBER is exactly one static member function, then we
+        know the type of the expression.  Otherwise, we must wait
+        until overload resolution has been performed.  */
+      functions = BASELINK_FUNCTIONS (member);
+      if (TREE_CODE (functions) == FUNCTION_DECL
+         && DECL_STATIC_FUNCTION_P (functions))
+       type = TREE_TYPE (functions);
+      else
+       type = unknown_type_node;
+      /* Note that we do not convert OBJECT to the BASELINK_BINFO
+        base.  That will happen when the function is called.  */
+      result = build (COMPONENT_REF, type, object, member);
+    }
+  else if (TREE_CODE (member) == CONST_DECL)
+    {
+      /* The member is an enumerator.  */
+      result = member;
+      /* If OBJECT has side-effects, they are supposed to occur.  */
+      if (TREE_SIDE_EFFECTS (object))
+       result = build (COMPOUND_EXPR, TREE_TYPE (result),
+                       object, result);
+    }
+  else
     {
-      cp_error ("invalid use of type decl `%#D' as expression", component);
+      error ("invalid use of `%D'", member);
       return error_mark_node;
     }
-  else if (TREE_CODE (component) == TEMPLATE_DECL)
+
+  if (!preserve_reference)
+    /* [expr.ref]
+       
+       If E2 is declared to have type "reference to T", then ... the
+       type of E1.E2 is T.  */
+    result = convert_from_reference (result);
+
+  return result;
+}
+
+/* Return the destructor denoted by OBJECT.SCOPE::~DTOR_NAME, or, if
+   SCOPE is NULL, by OBJECT.~DTOR_NAME.  */
+
+static tree
+lookup_destructor (tree object, tree scope, tree dtor_name)
+{
+  tree object_type = TREE_TYPE (object);
+  tree dtor_type = TREE_OPERAND (dtor_name, 0);
+
+  if (scope && !check_dtor_name (scope, dtor_name))
     {
-      cp_error ("invalid use of template `%#D' as expression", component);
+      error ("qualified type `%T' does not match destructor name `~%T'",
+            scope, dtor_type);
       return error_mark_node;
     }
-  else
+  if (!same_type_p (dtor_type, TYPE_MAIN_VARIANT (object_type)))
     {
-      tree name = component;
-      if (TREE_CODE (component) == VAR_DECL)
-       name = DECL_NAME (component);
-      if (TREE_CODE (component) == NAMESPACE_DECL)
-        /* Source is in error, but produce a sensible diagnostic.  */
-        name = DECL_NAME (component);
-      if (basetype_path == NULL_TREE)
-       basetype_path = TYPE_BINFO (basetype);
-      field = lookup_field (basetype_path, name,
-                           protect && !VFIELD_NAME_P (name), 0);
-      if (field == error_mark_node)
-       return error_mark_node;
+      error ("destructor name `%T' does not match type `%T' of expression",
+            dtor_type, object_type);
+      return error_mark_node;
+    }
+  if (!TYPE_HAS_DESTRUCTOR (object_type))
+    return build (PSEUDO_DTOR_EXPR, void_type_node, object, scope,
+                 dtor_type);
+  return lookup_member (object_type, complete_dtor_identifier,
+                       /*protect=*/1, /*want_type=*/false);
+}
 
-      if (field == NULL_TREE)
-       {
-         /* 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, name, 1);
-         if (fndecls == error_mark_node)
-           return error_mark_node;
-         if (fndecls)
-           {
-             /* If the function is unique and static, we can resolve it
-                now.  Otherwise, we have to wait and see what context it is
-                used in; a component_ref involving a non-static member
-                function can only be used in a call (expr.ref).  */
+/* This function is called by the parser to process a class member
+   access expression of the form OBJECT.NAME.  NAME is a node used by
+   the parser to represent a name; it is not yet a DECL.  It may,
+   however, be a BASELINK where the BASELINK_FUNCTIONS is a
+   TEMPLATE_ID_EXPR.  Templates must be looked up by the parser, and
+   there is no reason to do the lookup twice, so the parser keeps the
+   BASELINK.  */
 
-             if (TREE_CHAIN (fndecls) == NULL_TREE
-                 && TREE_CODE (TREE_VALUE (fndecls)) == FUNCTION_DECL)
-               {
-                 if (DECL_STATIC_FUNCTION_P (TREE_VALUE (fndecls)))
-                   {
-                     tree fndecl = TREE_VALUE (fndecls);
-                     enforce_access (basetype_path, fndecl);
-                     mark_used (fndecl);
-                     return fndecl;
-                   }
-                 else
-                   {
-                     /* A unique non-static member function.  Other parts
-                        of the compiler expect something with
-                        unknown_type_node to be really overloaded, so
-                        let's oblige.  */
-                     TREE_VALUE (fndecls)
-                       = ovl_cons (TREE_VALUE (fndecls), NULL_TREE);
-                   }
-               }
+tree
+finish_class_member_access_expr (tree object, tree name)
+{
+  tree object_type;
+  tree member;
+  tree access_path = NULL_TREE;
 
-             ref = build (COMPONENT_REF, unknown_type_node,
-                          datum, TREE_VALUE (fndecls));
-             return ref;
-           }
+  if (object == error_mark_node || name == error_mark_node)
+    return error_mark_node;
 
-         cp_error ("`%#T' has no member named `%D'", basetype, name);
-         return error_mark_node;
-       }
-      else if (TREE_TYPE (field) == error_mark_node)
-       return error_mark_node;
+  if (processing_template_decl)
+    return build_min_nt (COMPONENT_REF, object, name);
+  
+  if (TREE_CODE (object) == OFFSET_REF)
+    object = resolve_offset_ref (object);
 
-      if (TREE_CODE (field) != FIELD_DECL)
-       {
-         if (TREE_CODE (field) == TYPE_DECL)
-           cp_pedwarn ("invalid use of type decl `%#D' as expression", field);
-         else if (DECL_RTL (field) != 0)
-           mark_used (field);
-         else
-           TREE_USED (field) = 1;
+  object_type = TREE_TYPE (object);
+  if (TREE_CODE (object_type) == REFERENCE_TYPE)
+    {
+      object = convert_from_reference (object);
+      object_type = TREE_TYPE (object);
+    }
 
-         /* Do evaluate the object when accessing a static member.  */
-         if (TREE_SIDE_EFFECTS (datum))
-           field = build (COMPOUND_EXPR, TREE_TYPE (field), datum, field);
+  /* [expr.ref]
 
-         return field;
-       }
+     The type of the first expression shall be "class object" (of a
+     complete type).  */
+  if (!complete_type_or_else (object_type, object))
+    return error_mark_node;
+  if (!CLASS_TYPE_P (object_type))
+    {
+      error ("request for member `%D' in `%E', which is of non-class type `%T'", 
+            name, object, object_type);
+      return error_mark_node;
     }
 
-  /* 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)
+  if (BASELINK_P (name))
     {
-      tree context = DECL_FIELD_CONTEXT (field);
-      tree base = context;
-      while (!same_type_p (base, basetype) && TYPE_NAME (base)
-            && ANON_AGGR_TYPE_P (base))
-       base = TYPE_CONTEXT (base);
+      /* A member function that has already been looked up.  */
+      my_friendly_assert ((TREE_CODE (BASELINK_FUNCTIONS (name)) 
+                          == TEMPLATE_ID_EXPR), 
+                         20020805);
+      member = name;
+    }
+  else
+    {
+      bool is_template_id = false;
+      tree template_args = NULL_TREE;
 
-      /* Handle base classes here...  */
-      if (base != basetype && TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (basetype))
+      if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
        {
-         tree addr = build_unary_op (ADDR_EXPR, datum, 0);
-         if (integer_zerop (addr))
+         is_template_id = true;
+         template_args = TREE_OPERAND (name, 1);
+         name = TREE_OPERAND (name, 0);
+       }
+
+      if (TREE_CODE (name) == SCOPE_REF)
+       {
+         tree scope;
+
+         /* A qualified name.  The qualifying class or namespace `S' has
+            already been looked up; it is either a TYPE or a
+            NAMESPACE_DECL.  The member name is either an IDENTIFIER_NODE
+            or a BIT_NOT_EXPR.  */
+         scope = TREE_OPERAND (name, 0);
+         name = TREE_OPERAND (name, 1);
+         my_friendly_assert ((CLASS_TYPE_P (scope) 
+                              || TREE_CODE (scope) == NAMESPACE_DECL),
+                             20020804);
+         my_friendly_assert ((TREE_CODE (name) == IDENTIFIER_NODE
+                              || TREE_CODE (name) == BIT_NOT_EXPR),
+                             20020804);
+
+         /* If SCOPE is a namespace, then the qualified name does not
+            name a member of OBJECT_TYPE.  */
+         if (TREE_CODE (scope) == NAMESPACE_DECL)
            {
-             error ("invalid reference to NULL ptr, use ptr-to-member instead");
+             error ("`%D::%D' is not a member of `%T'", 
+                    scope, name, object_type);
              return error_mark_node;
            }
-         if (VBASE_NAME_P (DECL_NAME (field)))
+
+         /* Find the base of OBJECT_TYPE corresponding to SCOPE.  */
+         access_path = lookup_base (object_type, scope, ba_check, NULL);
+         if (!access_path || access_path == error_mark_node)
+           return error_mark_node;
+
+         if (TREE_CODE (name) == BIT_NOT_EXPR)
+           member = lookup_destructor (object, scope, name);
+         else
            {
-             /* 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);
+             /* Look up the member.  */
+             member = lookup_member (access_path, name, /*protect=*/1, 
+                                     /*want_type=*/false);
+             if (member == NULL_TREE)
+               {
+                 error ("'%D' has no member named '%E'", object_type, name);
+                 return error_mark_node;
+               }
+             if (member == error_mark_node)
+               return error_mark_node;
            }
-         else
-           addr = convert_pointer_to (base, addr);
-         datum = build_indirect_ref (addr, NULL);
-         if (datum == error_mark_node)
+       }
+      else if (TREE_CODE (name) == BIT_NOT_EXPR)
+       member = lookup_destructor (object, /*scope=*/NULL_TREE, name);
+      else if (TREE_CODE (name) == IDENTIFIER_NODE)
+       {
+         /* An unqualified name.  */
+         member = lookup_member (object_type, name, /*protect=*/1, 
+                                 /*want_type=*/false);
+         if (member == NULL_TREE)
+           {
+             error ("'%D' has no member named '%E'", object_type, name);
+             return error_mark_node;
+           }
+         else if (member == error_mark_node)
            return error_mark_node;
        }
-      basetype = base;
-      /* Handle things from anon unions here...  */
-      if (TYPE_NAME (context) && ANON_AGGR_TYPE_P (context))
+      else
        {
-         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);
+         /* The YACC parser sometimes gives us things that are not names.
+            These always indicate errors.  The recursive-descent parser
+            does not do this, so this code can go away once that parser
+            replaces the YACC parser.  */
+         error ("invalid use of `%D'", name);
+         return error_mark_node;
+       }
+      
+      if (is_template_id)
+       {
+         tree template = member;
+         
+         if (BASELINK_P (template))
+           BASELINK_FUNCTIONS (template) 
+             = build_nt (TEMPLATE_ID_EXPR,
+                         BASELINK_FUNCTIONS (template),
+                         template_args);
+         else
+           {
+             error ("`%D' is not a member template function", name);
+             return error_mark_node;
+           }
        }
     }
 
-  /* Compute the type of the field, as described in [expr.ref].  */
-  type_quals = TYPE_UNQUALIFIED;
-  field_type = TREE_TYPE (field);
-  if (TREE_CODE (field_type) == REFERENCE_TYPE)
-    /* The standard says that the type of the result should be the
-       type referred to by the reference.  But for now, at least, we
-       do the conversion from reference type later.  */
-    ;
-  else
-    {
-      type_quals = (CP_TYPE_QUALS (field_type)  
-                   | CP_TYPE_QUALS (TREE_TYPE (datum)));
-
-      /* A field is const (volatile) if the enclosing object, or the
-        field itself, is const (volatile).  But, a mutable field is
-        not const, even within a const object.  */
-      if (DECL_MUTABLE_P (field))
-       type_quals &= ~TYPE_QUAL_CONST;
-      field_type = cp_build_qualified_type (field_type, type_quals);
-    }
-
-  ref = fold (build (COMPONENT_REF, field_type, datum, field));
-
-  /* Mark the expression const or volatile, as appropriate.  Even
-     though we've dealt with the type above, we still have to mark the
-     expression itself.  */
-  if (type_quals & TYPE_QUAL_CONST)
-    TREE_READONLY (ref) = 1;
-  else if (type_quals & TYPE_QUAL_VOLATILE)
-    TREE_THIS_VOLATILE (ref) = 1;
+  if (TREE_DEPRECATED (member))
+    warn_deprecated_use (member);
 
-  return ref;
+  return build_class_member_access_expr (object, member, access_path,
+                                        /*preserve_reference=*/false);
 }
 
-/* Variant of build_component_ref for use in expressions, which should
-   never have REFERENCE_TYPE.  */
+/* Return an expression for the MEMBER_NAME field in the internal
+   representation of PTRMEM, a pointer-to-member function.  (Each
+   pointer-to-member function type gets its own RECORD_TYPE so it is
+   more convenient to access the fields by name than by FIELD_DECL.)
+   This routine converts the NAME to a FIELD_DECL and then creates the
+   node for the complete expression.  */
 
 tree
-build_x_component_ref (datum, component, basetype_path, protect)
-     tree datum, component, basetype_path;
-     int protect;
+build_ptrmemfunc_access_expr (tree ptrmem, tree member_name)
 {
-  tree t = build_component_ref (datum, component, basetype_path, protect);
-
-  if (! processing_template_decl)
-    t = convert_from_reference (t);
-
-  return t;
+  tree ptrmem_type;
+  tree member;
+  tree member_type;
+
+  /* This code is a stripped down version of
+     build_class_member_access_expr.  It does not work to use that
+     routine directly because it expects the object to be of class
+     type.  */
+  ptrmem_type = TREE_TYPE (ptrmem);
+  my_friendly_assert (TYPE_PTRMEMFUNC_P (ptrmem_type), 20020804);
+  member = lookup_member (ptrmem_type, member_name, /*protect=*/0,
+                         /*want_type=*/false);
+  member_type = cp_build_qualified_type (TREE_TYPE (member),
+                                        cp_type_quals (ptrmem_type));
+  return fold (build (COMPONENT_REF, member_type, ptrmem, member));
 }
-\f
+
 /* Given an expression PTR for a pointer, return an expression
    for the value pointed to.
    ERRORSTRING is the name of the operator to appear in error messages.
@@ -2324,8 +2308,8 @@ build_x_indirect_ref (ptr, errorstring)
   if (processing_template_decl)
     return build_min_nt (INDIRECT_REF, ptr);
 
-  rval = build_opfncall (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE,
-                        NULL_TREE);
+  rval = build_new_op (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE,
+                      NULL_TREE);
   if (rval)
     return rval;
   return build_indirect_ref (ptr, errorstring);
@@ -2364,12 +2348,11 @@ build_indirect_ref (ptr, errorstring)
         {
           /* A pointer to incomplete type (other than cv void) can be
              dereferenced [expr.unary.op]/1  */
-          cp_error ("`%T' is not a pointer-to-object type", type);
+          error ("`%T' is not a pointer-to-object type", type);
           return error_mark_node;
         }
       else if (TREE_CODE (pointer) == ADDR_EXPR
-         && !flag_volatile
-         && same_type_p (t, TREE_TYPE (TREE_OPERAND (pointer, 0))))
+              && same_type_p (t, TREE_TYPE (TREE_OPERAND (pointer, 0))))
        /* The POINTER was something like `&x'.  We simplify `*&x' to
           `x'.  */
        return TREE_OPERAND (pointer, 0);
@@ -2383,8 +2366,7 @@ build_indirect_ref (ptr, errorstring)
          TREE_READONLY (ref) = CP_TYPE_CONST_P (t);
          TREE_THIS_VOLATILE (ref) = CP_TYPE_VOLATILE_P (t);
          TREE_SIDE_EFFECTS (ref)
-           = (TREE_THIS_VOLATILE (ref) || TREE_SIDE_EFFECTS (pointer)
-              || flag_volatile);
+           = (TREE_THIS_VOLATILE (ref) || TREE_SIDE_EFFECTS (pointer));
          return ref;
        }
     }
@@ -2483,7 +2465,7 @@ build_array_ref (array, idx)
              && (TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array))))
                  != INTEGER_CST)))
        {
-         if (mark_addressable (array) == 0)
+         if (!cxx_mark_addressable (array))
            return error_mark_node;
        }
 
@@ -2495,7 +2477,7 @@ build_array_ref (array, idx)
          && TYPE_VALUES (TREE_TYPE (array))
          && ! int_fits_type_p (idx, TYPE_VALUES (TREE_TYPE (array))))
        {
-         if (mark_addressable (array) == 0)
+         if (!cxx_mark_addressable (array))
            return error_mark_node;
        }
 
@@ -2558,293 +2540,15 @@ 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.  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
-   be.  If the list of methods comes from a class, then it will be
-   a list of lists (where each element is associated with the class
-   that produced it), otherwise it will be a simple list (for
-   functions overloaded in global scope).
-
-   In the first case, TREE_VALUE (function) is the head of one of those
-   lists, and TREE_PURPOSE is the name of the function.
-
-   In the second case, TREE_PURPOSE (function) is the function's
-   name directly.
-
-   DECL is the class instance variable, usually CURRENT_CLASS_REF.
-
-   When calling a TEMPLATE_DECL, we don't require a complete return
-   type.  */
-
-tree
-build_x_function_call (function, params, decl)
-     tree function, params, decl;
-{
-  tree type;
-  tree template_id = NULL_TREE;
-  int is_method;
-
-  if (function == error_mark_node)
-    return error_mark_node;
-
-  if (processing_template_decl)
-    return build_min_nt (CALL_EXPR, function, params, NULL_TREE);
-
-  /* Save explicit template arguments if found */
-  if (TREE_CODE (function) == TEMPLATE_ID_EXPR)
-    {
-      template_id = function;
-      function = TREE_OPERAND (function, 0);
-    }
-
-  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);
-      if (TREE_CODE (function) == OVERLOAD)
-       function = OVL_FUNCTION (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);
-    }
-    
-  if (TREE_CODE (function) == OFFSET_REF
-      && TREE_CODE (type) != METHOD_TYPE)
-    function = resolve_offset_ref (function);
-
-  if ((TREE_CODE (function) == FUNCTION_DECL
-       && DECL_STATIC_FUNCTION_P (function))
-      || (DECL_FUNCTION_TEMPLATE_P (function)
-         && DECL_STATIC_FUNCTION_P (DECL_TEMPLATE_RESULT (function))))
-      return build_member_call (DECL_CONTEXT (function), 
-                               template_id 
-                               ? template_id : DECL_NAME (function), 
-                               params);
-
-  is_method = ((TREE_CODE (function) == TREE_LIST
-               && current_class_type != NULL_TREE
-               && (IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (function))
-                   == function))
-              || (TREE_CODE (function) == OVERLOAD
-                  && DECL_FUNCTION_MEMBER_P (OVL_CURRENT (function)))
-              || TREE_CODE (function) == IDENTIFIER_NODE
-              || TREE_CODE (type) == METHOD_TYPE
-              || TYPE_PTRMEMFUNC_P (type));
-
-  /* A friend template.  Make it look like a toplevel declaration.  */
-  if (! is_method && TREE_CODE (function) == TEMPLATE_DECL)
-    function = ovl_cons (function, NULL_TREE);
-
-  /* Handle methods, friends, and overloaded functions, respectively.  */
-  if (is_method)
-    {
-      tree basetype = NULL_TREE;
-
-      if (TREE_CODE (function) == OVERLOAD)
-       function = OVL_CURRENT (function);
-
-      if (TREE_CODE (function) == FUNCTION_DECL
-         || DECL_FUNCTION_TEMPLATE_P (function))
-       {
-         basetype = DECL_CONTEXT (function);
-
-         if (DECL_NAME (function))
-           function = DECL_NAME (function);
-         else
-           function = TYPE_IDENTIFIER (DECL_CONTEXT (function));
-       }
-      else if (TREE_CODE (function) == TREE_LIST)
-       {
-         my_friendly_assert (TREE_CODE (TREE_VALUE (function))
-                             == FUNCTION_DECL, 312);
-         basetype = DECL_CONTEXT (TREE_VALUE (function));
-         function = TREE_PURPOSE (function);
-       }
-      else if (TREE_CODE (function) != IDENTIFIER_NODE)
-       {
-         if (TREE_CODE (function) == OFFSET_REF)
-           {
-             if (TREE_OPERAND (function, 0))
-               decl = TREE_OPERAND (function, 0);
-           }
-         /* Call via a pointer to member function.  */
-         if (decl == NULL_TREE)
-           {
-             error ("pointer to member function called, but not in class scope");
-             return error_mark_node;
-           }
-         /* What other type of POINTER_TYPE could this be? */
-         if (TREE_CODE (TREE_TYPE (function)) != POINTER_TYPE
-             && ! TYPE_PTRMEMFUNC_P (TREE_TYPE (function))
-             && TREE_CODE (function) != OFFSET_REF)
-           function = build (OFFSET_REF, TREE_TYPE (type), NULL_TREE,
-                             function);
-         goto do_x_function;
-       }
-
-      /* this is an abbreviated method call.
-         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)
-           {
-             cp_error ("object missing in call to method `%D'", function);
-             return error_mark_node;
-           }
-         /* Yow: call from a static member function.  */
-         decl = build_dummy_object (current_class_type);
-       }
-
-      /* Put back explicit template arguments, if any.  */
-      if (template_id)
-        function = template_id;
-      return build_method_call (decl, function, params,
-                               NULL_TREE, LOOKUP_NORMAL);
-    }
-  else if (TREE_CODE (function) == COMPONENT_REF
-          && type == unknown_type_node)
-    {
-      /* Undo what we did in build_component_ref.  */
-      decl = TREE_OPERAND (function, 0);
-      function = TREE_OPERAND (function, 1);
-      function = DECL_NAME (OVL_CURRENT (function));
-
-      if (template_id)
-       {
-         TREE_OPERAND (template_id, 0) = function;
-         function = template_id;
-       }
-
-      return build_method_call (decl, function, params,
-                               NULL_TREE, LOOKUP_NORMAL);
-    }
-  else if (really_overloaded_fn (function))
-    {
-      if (OVL_FUNCTION (function) == NULL_TREE)
-       {
-         cp_error ("function `%D' declared overloaded, but no definitions appear with which to resolve it?!?",
-                   TREE_PURPOSE (function));
-         return error_mark_node;
-       }
-      else
-       {
-         /* Put back explicit template arguments, if any.  */
-         if (template_id)
-           function = template_id;
-         return build_new_function_call (function, params);
-       }
-    }
-  else
-    /* Remove a potential OVERLOAD around it */
-    function = OVL_CURRENT (function);
-
- do_x_function:
-  if (TREE_CODE (function) == OFFSET_REF)
-    {
-      /* If the component is a data element (or a virtual function), we play
-        games here to make things work.  */
-      tree decl_addr;
-
-      if (TREE_OPERAND (function, 0))
-       decl = TREE_OPERAND (function, 0);
-      else
-       decl = current_class_ref;
-
-      decl_addr = build_unary_op (ADDR_EXPR, decl, 0);
-
-      /* Sigh.  OFFSET_REFs are being used for too many things.
-        They're being used both for -> and ->*, and we want to resolve
-        the -> cases here, but leave the ->*.  We could use
-        resolve_offset_ref for those, too, but it would call
-         get_member_function_from_ptrfunc and decl_addr wouldn't get
-         updated properly.  Nasty.  */
-      if (TREE_CODE (TREE_OPERAND (function, 1)) == FIELD_DECL)
-       function = resolve_offset_ref (function);
-      else
-       function = TREE_OPERAND (function, 1);
-
-      function = get_member_function_from_ptrfunc (&decl_addr, function);
-      params = tree_cons (NULL_TREE, decl_addr, params);
-      return build_function_call (function, params);
-    }
-
-  type = TREE_TYPE (function);
-  if (type != error_mark_node)
-    {
-      if (TREE_CODE (type) == REFERENCE_TYPE)
-       type = TREE_TYPE (type);
-
-      if (IS_AGGR_TYPE (type))
-       return build_opfncall (CALL_EXPR, LOOKUP_NORMAL, function, params, NULL_TREE);
-    }
-
-  if (is_method)
-    {
-      tree fntype = TREE_TYPE (function);
-      tree ctypeptr = NULL_TREE;
-
-      /* Explicitly named method?  */
-      if (TREE_CODE (function) == FUNCTION_DECL)
-       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 = build_pointer_type (rec);
-       }
-      /* Unexpected node type?  */
-      else
-       my_friendly_abort (116);
-      if (decl == NULL_TREE)
-       {
-         if (current_function_decl
-             && DECL_STATIC_FUNCTION_P (current_function_decl))
-           error ("invalid call to member function needing `this' in static member function scope");
-         else
-           error ("pointer to member function called, but not in class scope");
-         return error_mark_node;
-       }
-      if (TREE_CODE (TREE_TYPE (decl)) != POINTER_TYPE
-         && ! TYPE_PTRMEMFUNC_P (TREE_TYPE (decl)))
-       {
-         decl = build_unary_op (ADDR_EXPR, decl, 0);
-         decl = convert_pointer_to (TREE_TYPE (ctypeptr), decl);
-       }
-      else
-       decl = build_c_cast (ctypeptr, decl);
-      params = tree_cons (NULL_TREE, decl, params);
-    }
-
-  return build_function_call (function, params);
-}
-
 /* Resolve a pointer to member function.  INSTANCE is the object
-   instance to use, if the member points to a virtual member.  */
+   instance to use, if the member points to a virtual member.
+
+   This used to avoid checking for virtual functions if basetype
+   has no virtual functions, according to an earlier ANSI draft.
+   With the final ISO C++ rules, such an optimization is
+   incorrect: A pointer to a derived member can be static_cast
+   to pointer-to-base-member, as long as the dynamic object
+   later has the right member.  */
 
 tree
 get_member_function_from_ptrfunc (instance_ptrptr, function)
@@ -2852,130 +2556,98 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
      tree function;
 {
   if (TREE_CODE (function) == OFFSET_REF)
-    {
-      function = TREE_OPERAND (function, 1);
-    }
+    function = TREE_OPERAND (function, 1);
 
   if (TYPE_PTRMEMFUNC_P (TREE_TYPE (function)))
     {
-      tree fntype, idx, e1, delta, delta2, e2, e3, aref, vtbl;
-      tree instance, basetype;
+      tree idx, delta, e1, e2, e3, vtbl, basetype;
+      tree fntype = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function));
 
       tree instance_ptr = *instance_ptrptr;
-
-      if (instance_ptr == error_mark_node
-         && TREE_CODE (function) == PTRMEM_CST)
+      tree instance_save_expr = 0;
+      if (instance_ptr == error_mark_node)
        {
-         /* Extracting the function address from a pmf is only
-            allowed with -Wno-pmf-conversions. It only works for
-            pmf constants. */
-         e1 = build_addr_func (PTRMEM_CST_MEMBER (function));
-         e1 = convert (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function)), e1);
-         return e1;
+         if (TREE_CODE (function) == PTRMEM_CST)
+           {
+             /* Extracting the function address from a pmf is only
+                allowed with -Wno-pmf-conversions. It only works for
+                pmf constants.  */
+             e1 = build_addr_func (PTRMEM_CST_MEMBER (function));
+             e1 = convert (fntype, e1);
+             return e1;
+           }
+         else
+           {
+             error ("object missing in use of `%E'", function);
+             return error_mark_node;
+           }
        }
 
       if (TREE_SIDE_EFFECTS (instance_ptr))
-       instance_ptr = save_expr (instance_ptr);
+       instance_ptr = instance_save_expr = save_expr (instance_ptr);
 
       if (TREE_SIDE_EFFECTS (function))
        function = save_expr (function);
 
-      fntype = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function));
-      basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (fntype));
-
-      /* Convert down to the right base, before using the instance.  */
-      instance = convert_pointer_to_real (basetype, instance_ptr);
-      if (instance == error_mark_node && instance_ptr != error_mark_node)
-       return instance;
-
+      /* Start by extracting all the information from the PMF itself.  */
       e3 = PFN_FROM_PTRMEMFUNC (function);
-
-      vtbl = convert_pointer_to (ptr_type_node, instance);
-      delta = cp_convert (ptrdiff_type_node,
-                         build_component_ref (function, delta_identifier,
-                                              NULL_TREE, 0));
-
-      /* This used to avoid checking for virtual functions if basetype
-        has no virtual functions, according to an earlier ANSI draft.
-        With the final ISO C++ rules, such an optimization is
-        incorrect: A pointer to a derived member can be static_cast
-        to pointer-to-base-member, as long as the dynamic object
-        later has the right member. */
-
-      /* Promoting idx before saving it improves performance on RISC
-        targets.  Without promoting, the first compare used
-        load-with-sign-extend, while the second used normal load then
-        shift to sign-extend.  An optimizer flaw, perhaps, but it's
-        easier to make this change.  */
+      delta = build_ptrmemfunc_access_expr (function, delta_identifier);
+      idx = build1 (NOP_EXPR, vtable_index_type, e3);
       switch (TARGET_PTRMEMFUNC_VBIT_LOCATION)
        {
        case ptrmemfunc_vbit_in_pfn:
-         idx = cp_build_binary_op (TRUNC_DIV_EXPR, 
-                                   build1 (NOP_EXPR, vtable_index_type, e3),
-                                   TYPE_SIZE_UNIT (vtable_entry_type));
-         e1 = cp_build_binary_op (BIT_AND_EXPR,
-                                  build1 (NOP_EXPR, vtable_index_type, e3),
-                                  integer_one_node);
+         e1 = cp_build_binary_op (BIT_AND_EXPR, idx, integer_one_node);
+         idx = cp_build_binary_op (MINUS_EXPR, idx, integer_one_node);
          break;
 
        case ptrmemfunc_vbit_in_delta:
-         idx = build1 (NOP_EXPR, vtable_index_type, e3);
-         e1 = cp_build_binary_op (BIT_AND_EXPR,
-                                  delta, integer_one_node);
-         delta = cp_build_binary_op (RSHIFT_EXPR,
-                                     build1 (NOP_EXPR, vtable_index_type,
-                                             delta),
-                                     integer_one_node);
+         e1 = cp_build_binary_op (BIT_AND_EXPR, delta, integer_one_node);
+         delta = cp_build_binary_op (RSHIFT_EXPR, delta, integer_one_node);
          break;
 
        default:
          abort ();
        }
 
-      /* DELTA2 is the amount by which to adjust the `this' pointer
-        to find the vtbl.  */
-      delta2 = delta;
-      vtbl = build
-       (PLUS_EXPR,
-        build_pointer_type (build_pointer_type (vtable_entry_type)),
-        vtbl, cp_convert (ptrdiff_type_node, delta2));
+      /* Convert down to the right base before using the instance.  First
+         use the type...  */
+      basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (fntype));
+      basetype = lookup_base (TREE_TYPE (TREE_TYPE (instance_ptr)),
+                             basetype, ba_check, NULL);
+      instance_ptr = build_base_path (PLUS_EXPR, instance_ptr, basetype, 1);
+      if (instance_ptr == error_mark_node)
+       return error_mark_node;
+      /* ...and then the delta in the PMF.  */
+      instance_ptr = build (PLUS_EXPR, TREE_TYPE (instance_ptr),
+                           instance_ptr, delta);
+
+      /* Hand back the adjusted 'this' argument to our caller.  */
+      *instance_ptrptr = instance_ptr;
+
+      /* Next extract the vtable pointer from the object.  */
+      vtbl = build1 (NOP_EXPR, build_pointer_type (vtbl_ptr_type_node),
+                    instance_ptr);
       vtbl = build_indirect_ref (vtbl, NULL);
-      aref = build_array_ref (vtbl, idx);
 
-      if (! flag_vtable_thunks)
-       {
-         aref = save_expr (aref);
-         
-         delta = cp_build_binary_op
-           (PLUS_EXPR,
-            build_conditional_expr (e1,
-                                    build_component_ref (aref,
-                                                         delta_identifier,
-                                                         NULL_TREE, 0),
-                                    integer_zero_node),
-            delta);
-       }
+      /* Finally, extract the function pointer from the vtable.  */
+      e2 = fold (build (PLUS_EXPR, TREE_TYPE (vtbl), vtbl, idx));
+      e2 = build_indirect_ref (e2, NULL);
+      TREE_CONSTANT (e2) = 1;
+
+      /* When using function descriptors, the address of the
+        vtable entry is treated as a function pointer.  */
+      if (TARGET_VTABLE_USES_DESCRIPTORS)
+       e2 = build1 (NOP_EXPR, TREE_TYPE (e2),
+                    build_unary_op (ADDR_EXPR, e2, /*noconvert=*/1));
 
-      if (flag_vtable_thunks)
-       e2 = aref;
-      else
-       e2 = build_component_ref (aref, pfn_identifier, NULL_TREE, 0);
       TREE_TYPE (e2) = TREE_TYPE (e3);
       e1 = build_conditional_expr (e1, e2, e3);
       
       /* Make sure this doesn't get evaluated first inside one of the
         branches of the COND_EXPR.  */
-      if (TREE_CODE (instance_ptr) == SAVE_EXPR)
+      if (instance_save_expr)
        e1 = build (COMPOUND_EXPR, TREE_TYPE (e1),
-                   instance_ptr, e1);
-
-      *instance_ptrptr = build (PLUS_EXPR, TREE_TYPE (instance_ptr),
-                               instance_ptr, delta);
-
-      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);
+                   instance_save_expr, e1);
 
       function = e1;
     }
@@ -2983,9 +2655,8 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
 }
 
 tree
-build_function_call_real (function, params, require_complete, flags)
+build_function_call (function, params)
      tree function, params;
-     int require_complete, flags;
 {
   register tree fntype, fndecl;
   register tree value_type;
@@ -2993,6 +2664,7 @@ build_function_call_real (function, params, require_complete, flags)
   tree result;
   tree name = NULL_TREE, assembler_name = NULL_TREE;
   int is_method;
+  tree original = function;
 
   /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
      Strip such NOP_EXPRs, since FUNCTION is used in non-lvalue context.  */
@@ -3005,10 +2677,6 @@ build_function_call_real (function, params, require_complete, flags)
       name = DECL_NAME (function);
       assembler_name = DECL_ASSEMBLER_NAME (function);
 
-      GNU_xref_call (current_function_decl,
-                    IDENTIFIER_POINTER (name ? name
-                                        : TYPE_IDENTIFIER (DECL_CLASS_CONTEXT
-                                                           (function))));
       mark_used (function);
       fndecl = function;
 
@@ -3019,7 +2687,7 @@ build_function_call_real (function, params, require_complete, flags)
       /* 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))
        function = inline_conversion (function);
       else
@@ -3039,8 +2707,8 @@ build_function_call_real (function, params, require_complete, flags)
 
   if (TYPE_PTRMEMFUNC_P (fntype))
     {
-      cp_error ("must use .* or ->* to call pointer-to-member function in `%E (...)'",
-               function);
+      error ("must use .* or ->* to call pointer-to-member function in `%E (...)'",
+               original);
       return error_mark_node;
     }
 
@@ -3052,7 +2720,7 @@ build_function_call_real (function, params, require_complete, flags)
        || is_method
        || TREE_CODE (function) == TEMPLATE_ID_EXPR))
     {
-      cp_error ("`%E' cannot be used as a function", function);
+      error ("`%E' cannot be used as a function", original);
       return error_mark_node;
     }
 
@@ -3060,27 +2728,17 @@ build_function_call_real (function, params, require_complete, flags)
   fntype = TREE_TYPE (fntype);
 
   /* Convert the parameters to the types declared in the
-     function prototype, or apply default promotions.  */
-
-  if (flags & LOOKUP_COMPLAIN)
-    coerced_params = convert_arguments (TYPE_ARG_TYPES (fntype),
-                                       params, fndecl, LOOKUP_NORMAL);
-  else
-    coerced_params = convert_arguments (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;
-    }
+     function prototype, or apply default promotions.  */
+
+  coerced_params = convert_arguments (TYPE_ARG_TYPES (fntype),
+                                     params, fndecl, LOOKUP_NORMAL);
+  if (coerced_params == error_mark_node)
+    return error_mark_node;
 
   /* Check for errors in format strings.  */
 
-  if (warn_format && (name || assembler_name))
-    check_function_format (NULL, name, assembler_name, coerced_params);
+  if (warn_format)
+    check_function_format (NULL, TYPE_ATTRIBUTES (fntype), coerced_params);
 
   /* Recognize certain built-in functions so we can make tree-codes
      other than CALL_EXPR.  We do this when it enables fold-const.c
@@ -3101,23 +2759,13 @@ build_function_call_real (function, params, require_complete, flags)
   result = fold (build_call (function, coerced_params));
   value_type = TREE_TYPE (result);
 
-  if (require_complete)
-    {
-      if (TREE_CODE (value_type) == VOID_TYPE)
-       return result;
-      result = require_complete_type (result);
-    }
+  if (TREE_CODE (value_type) == VOID_TYPE)
+    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);
 }
-
-tree
-build_function_call (function, params)
-     tree function, params;
-{
-  return build_function_call_real (function, params, 1, LOOKUP_NORMAL);
-}
 \f
 /* Convert the actual parameter expressions in the list VALUES
    to the types in the list TYPELIST.
@@ -3226,11 +2874,7 @@ convert_arguments (typelist, values, fndecl, flags)
              parmval = convert_for_initialization
                (NULL_TREE, type, val, flags,
                 "argument passing", fndecl, i);
-             if (PROMOTE_PROTOTYPES
-                 && INTEGRAL_TYPE_P (type)
-                 && (TYPE_PRECISION (type)
-                     < TYPE_PRECISION (integer_type_node)))
-               parmval = default_conversion (parmval);
+             parmval = convert_for_arg_passing (type, parmval);
            }
 
          if (parmval == error_mark_node)
@@ -3262,7 +2906,8 @@ convert_arguments (typelist, values, fndecl, flags)
   if (typetail != 0 && typetail != void_list_node)
     {
       /* See if there are default arguments that can be used */
-      if (TREE_PURPOSE (typetail))
+      if (TREE_PURPOSE (typetail) 
+         && TREE_CODE (TREE_PURPOSE (typetail)) != DEFAULT_ARG)
        {
          for (; typetail != void_list_node; ++i)
            {
@@ -3312,6 +2957,183 @@ build_x_binary_op (code, arg1, arg2)
   return build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE);
 }
 
+#if 0
+
+tree
+build_template_expr (enum tree_code code, tree op0, tree op1, tree op2)
+{
+  tree type;
+
+  /* If any of the operands is erroneous the result is erroneous too.  */
+  if (error_operand_p (op0)
+      || (op1 && error_operand_p (op1))
+      || (op2 && error_operand_p (op2)))
+    return error_mark_node;
+      
+  if (dependent_type_p (TREE_TYPE (op0))
+      || (op1 && dependent_type_p (TREE_TYPE (op1)))
+      || (op2 && dependent_type_p (TREE_TYPE (op2))))
+    /* If at least one operand has a dependent type, we cannot
+       determine the type of the expression until instantiation time.  */
+    type = NULL_TREE;
+  else
+    {
+      struct z_candidate *cand;
+      tree op0_type;
+      tree op1_type;
+      tree op2_type;
+
+      /* None of the operands is dependent, so we can compute the type
+        of the expression at this point.  We must compute the type so
+        that in things like:
+
+          template <int I>
+          void f() { S<sizeof(I + 3)> s; ... }
+
+        we can tell that the type of "s" is non-dependent.
+
+        If we're processing a template argument, we do not want to
+        actually change the operands in any way.  Adding conversions,
+        performing constant folding, etc., would all change mangled
+        names.  For example, in:
+        
+          template <int I>
+          void f(S<sizeof(3 + 4 + I)>);
+        
+        we need to determine that "3 + 4 + I" has type "int", without
+        actually turning the expression into "7 + I".  */
+      cand = find_overloaded_op (code, op0, op1, op2);
+      if (cand) 
+       /* If an overloaded operator was found, the expression will
+          have the type returned by the function.  */
+       type = non_reference (TREE_TYPE (cand->fn));
+      else
+       {
+         /* There is no overloaded operator so we can just use the
+            default rules for determining the type of the operand.  */
+         op0_type = TREE_TYPE (op0);
+         op1_type = op1 ? TREE_TYPE (op1) : NULL_TREE;
+         op2_type = op2 ? TREE_TYPE (op2) : NULL_TREE;
+         type = NULL_TREE;
+
+         switch (code)
+           {
+           case MODIFY_EXPR:
+             /* [expr.ass]
+
+                The result of the assignment operation is the value
+                stored in the left operand.  */
+             type = op0_type;
+             break;
+           case COMPONENT_REF:
+             /* Implement this case.  */
+             break;
+           case POSTINCREMENT_EXPR:
+           case POSTDECREMENT_EXPR:
+             /* [expr.post.incr]
+
+                The type of the result is the cv-unqualified version
+                of the type of the operand.  */
+             type = TYPE_MAIN_VARIANT (op0_type);
+             break;
+           case PREINCREMENT_EXPR:
+           case PREDECREMENT_EXPR:
+             /* [expr.pre.incr]
+
+                The value is the new value of the operand.  */
+             type = op0_type;
+             break;
+           case INDIRECT_REF:
+             /* [expr.unary.op]
+
+                If the type of the expression is "pointer to T", the
+                type of the result is "T".  */
+             type = TREE_TYPE (op0_type);
+             break;
+           case ADDR_EXPR:
+             /* [expr.unary.op]
+
+                If the type of the expression is "T", the type of the
+                result is "pointer to T".  */
+             /* FIXME: Handle the pointer-to-member case.  */
+             break;
+           case MEMBER_REF:
+             /* FIXME: Implement this case.  */
+             break;
+           case LSHIFT_EXPR:
+           case RSHIFT_EXPR:
+             /* [expr.shift]
+
+                The type of the result is that of the promoted left
+                operand.  */
+             break;
+           case PLUS_EXPR:
+           case MINUS_EXPR:
+             /* FIXME: Be careful of special pointer-arithmetic
+                cases.  */
+             /* Fall through. */
+           case MAX_EXPR:
+           case MIN_EXPR:
+             /* These are GNU extensions; the result type is computed
+                as it would be for other arithmetic operators.  */
+             /* Fall through. */
+           case BIT_AND_EXPR:
+           case BIT_XOR_EXPR:
+           case BIT_IOR_EXPR:
+           case MULT_EXPR:
+           case TRUNC_DIV_EXPR:
+           case TRUNC_MOD_EXPR:
+             /* [expr.bit.and], [expr.xor], [expr.or], [expr.mul]
+
+                The usual arithmetic conversions are performed on the
+                operands and determine the type of the result.  */
+             /* FIXME: Check that this is possible.  */
+             type = type_after_usual_arithmetic_conversions (t1, t2);
+             break;
+           case GT_EXPR:
+           case LT_EXPR:
+           case GE_EXPR:
+           case LE_EXPR:
+           case EQ_EXPR:
+           case NE_EXPR:
+             /* [expr.rel]
+
+                The type of the result is bool.  */
+             type = boolean_type_node;
+             break;
+           case TRUTH_ANDIF_EXPR:
+           case TRUTH_ORIF_EXPR:
+             /* [expr.log.and], [expr.log.org]
+                
+                The result is a bool.  */
+             type = boolean_type_node;
+             break;
+           case COND_EXPR:
+             /* FIXME: Handle special rules for conditioanl
+                expressions.  */
+             break;
+           case COMPOUND_EXPR:
+             type = op1_type;
+             break;
+           default:
+             abort ();
+           }
+         /* If the type of the expression could not be determined,
+            something is wrong.  */
+         if (!type)
+           abort ();
+         /* If the type is erroneous, the expression is erroneous
+            too.  */
+         if (type == error_mark_node)
+           return error_mark_node;
+       }
+    }
+  
+  return build_min (code, type, op0, op1, op2, NULL_TREE);
+}
+
+#endif
+
 /* Build a binary-operation expression without default conversions.
    CODE is the kind of expression to build.
    This function differs from `build' in several ways:
@@ -3383,17 +3205,24 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
   int common = 0;
 
   /* Apply default conversions.  */
+  op0 = orig_op0;
+  op1 = 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);
+      if (!really_overloaded_fn (op0))
+       op0 = decay_conversion (op0);
+      if (!really_overloaded_fn (op1))
+       op1 = decay_conversion (op1);
     }
   else
     {
-      op0 = default_conversion (orig_op0);
-      op1 = default_conversion (orig_op1);
+      if (!really_overloaded_fn (op0))
+       op0 = default_conversion (op0);
+      if (!really_overloaded_fn (op1))
+       op1 = default_conversion (op1);
     }
 
   /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue.  */
@@ -3403,20 +3232,20 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
   /* DTRT if one side is an overloaded function, but complain about it.  */
   if (type_unknown_p (op0))
     {
-      tree t = instantiate_type (TREE_TYPE (op1), op0, itf_none);
+      tree t = instantiate_type (TREE_TYPE (op1), op0, tf_none);
       if (t != error_mark_node)
        {
-         cp_pedwarn ("assuming cast to type `%T' from overloaded function",
+         pedwarn ("assuming cast to type `%T' from overloaded function",
                      TREE_TYPE (t));
          op0 = t;
        }
     }
   if (type_unknown_p (op1))
     {
-      tree t = instantiate_type (TREE_TYPE (op0), op1, itf_none);
+      tree t = instantiate_type (TREE_TYPE (op0), op1, tf_none);
       if (t != error_mark_node)
        {
-         cp_pedwarn ("assuming cast to type `%T' from overloaded function",
+         pedwarn ("assuming cast to type `%T' from overloaded function",
                      TREE_TYPE (t));
          op1 = t;
        }
@@ -3441,9 +3270,9 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
     case PLUS_EXPR:
       /* Handle the pointer + int case.  */
       if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
-       return pointer_int_sum (PLUS_EXPR, op0, op1);
+       return cp_pointer_int_sum (PLUS_EXPR, op0, op1);
       else if (code1 == POINTER_TYPE && code0 == INTEGER_TYPE)
-       return pointer_int_sum (PLUS_EXPR, op1, op0);
+       return cp_pointer_int_sum (PLUS_EXPR, op1, op0);
       else
        common = 1;
       break;
@@ -3456,7 +3285,7 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
        return pointer_diff (op0, op1, common_type (type0, type1));
       /* Handle pointer minus int.  Just like pointer plus int.  */
       else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
-       return pointer_int_sum (MINUS_EXPR, op0, op1);
+       return cp_pointer_int_sum (MINUS_EXPR, op0, op1);
       else
        common = 1;
       break;
@@ -3476,9 +3305,9 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
              || code1 == COMPLEX_TYPE))
        {
          if (TREE_CODE (op1) == INTEGER_CST && integer_zerop (op1))
-           cp_warning ("division by zero in `%E / 0'", op0);
+           warning ("division by zero in `%E / 0'", op0);
          else if (TREE_CODE (op1) == REAL_CST && real_zerop (op1))
-           cp_warning ("division by zero in `%E / 0.'", op0);
+           warning ("division by zero in `%E / 0.'", op0);
              
          if (!(code0 == INTEGER_TYPE && code1 == INTEGER_TYPE))
            resultcode = RDIV_EXPR;
@@ -3503,39 +3332,14 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
     case BIT_XOR_EXPR:
       if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
        shorten = -1;
-      /* If one operand is a constant, and the other is a short type
-        that has been converted to an int,
-        really do the work in the short type and then convert the
-        result to int.  If we are lucky, the constant will be 0 or 1
-        in the short type, making the entire operation go away.  */
-      if (TREE_CODE (op0) == INTEGER_CST
-         && TREE_CODE (op1) == NOP_EXPR
-         && (TYPE_PRECISION (type1)
-             > TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op1, 0))))
-         && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op1, 0))))
-       {
-         final_type = result_type;
-         op1 = TREE_OPERAND (op1, 0);
-         result_type = TREE_TYPE (op1);
-       }
-      if (TREE_CODE (op1) == INTEGER_CST
-         && TREE_CODE (op0) == NOP_EXPR
-         && (TYPE_PRECISION (type0)
-             > TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op0, 0))))
-         && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op0, 0))))
-       {
-         final_type = result_type;
-         op0 = TREE_OPERAND (op0, 0);
-         result_type = TREE_TYPE (op0);
-       }
       break;
 
     case TRUNC_MOD_EXPR:
     case FLOOR_MOD_EXPR:
       if (code1 == INTEGER_TYPE && integer_zerop (op1))
-       cp_warning ("division by zero in `%E %% 0'", op0);
+       warning ("division by zero in `%E %% 0'", op0);
       else if (code1 == REAL_TYPE && real_zerop (op1))
-       cp_warning ("division by zero in `%E %% 0.'", op0);
+       warning ("division by zero in `%E %% 0.'", op0);
       
       if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
        {
@@ -3658,7 +3462,7 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
        }
       else if (TYPE_PTRMEMFUNC_P (type0) && null_ptr_cst_p (op1))
        {
-         op0 = build_component_ref (op0, pfn_identifier, NULL_TREE, 0);
+         op0 = build_ptrmemfunc_access_expr (op0, pfn_identifier);
          op1 = cp_convert (TREE_TYPE (op0), integer_zero_node);
          result_type = TREE_TYPE (op0);
        }
@@ -3692,10 +3496,10 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
             DELTA field is unspecified.  */
          pfn0 = pfn_from_ptrmemfunc (op0);
          pfn1 = pfn_from_ptrmemfunc (op1);
-         delta0 = build_component_ref (op0, delta_identifier,
-                                       NULL_TREE, 0);
-         delta1 = build_component_ref (op1, delta_identifier,
-                                       NULL_TREE, 0);
+         delta0 = build_ptrmemfunc_access_expr (op0,
+                                                delta_identifier);
+         delta1 = build_ptrmemfunc_access_expr (op1,
+                                                delta_identifier);
          e1 = cp_build_binary_op (EQ_EXPR, delta0, delta1);
          e2 = cp_build_binary_op (EQ_EXPR, 
                                   pfn0,
@@ -3712,7 +3516,7 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
                && same_type_p (TYPE_PTRMEMFUNC_FN_TYPE (type0), type1))
               || (TYPE_PTRMEMFUNC_P (type1)
                   && same_type_p (TYPE_PTRMEMFUNC_FN_TYPE (type1), type0)))
-       my_friendly_abort (20000221);
+       abort ();
       break;
 
     case MAX_EXPR:
@@ -3833,24 +3637,22 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
                  == TYPE_PRECISION (TREE_TYPE (arg0)))
              && unsigned0 == unsigned1
              && (unsigned0 || !uns))
-           result_type
-             = signed_or_unsigned_type (unsigned0,
-                                        common_type (TREE_TYPE (arg0),
-                                                     TREE_TYPE (arg1)));
+           result_type = c_common_signed_or_unsigned_type
+             (unsigned0, common_type (TREE_TYPE (arg0), TREE_TYPE (arg1)));
          else if (TREE_CODE (arg0) == INTEGER_CST
                   && (unsigned1 || !uns)
                   && (TYPE_PRECISION (TREE_TYPE (arg1))
                       < TYPE_PRECISION (result_type))
-                  && (type = signed_or_unsigned_type (unsigned1,
-                                                      TREE_TYPE (arg1)),
+                  && (type = c_common_signed_or_unsigned_type
+                      (unsigned1, TREE_TYPE (arg1)),
                       int_fits_type_p (arg0, type)))
            result_type = type;
          else if (TREE_CODE (arg1) == INTEGER_CST
                   && (unsigned0 || !uns)
                   && (TYPE_PRECISION (TREE_TYPE (arg0))
                       < TYPE_PRECISION (result_type))
-                  && (type = signed_or_unsigned_type (unsigned0,
-                                                      TREE_TYPE (arg0)),
+                  && (type = c_common_signed_or_unsigned_type
+                      (unsigned0, TREE_TYPE (arg0)),
                       int_fits_type_p (arg1, type)))
            result_type = type;
        }
@@ -3885,8 +3687,8 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
            {
              /* Do an unsigned shift if the operand was zero-extended.  */
              result_type
-               = signed_or_unsigned_type (unsigned_arg,
-                                          TREE_TYPE (arg0));
+               = c_common_signed_or_unsigned_type (unsigned_arg,
+                                                   TREE_TYPE (arg0));
              /* Convert value-to-be-shifted to that type.  */
              if (TREE_TYPE (op0) != result_type)
                op0 = cp_convert (result_type, op0);
@@ -3930,7 +3732,7 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
              && TYPE_MAIN_VARIANT (TREE_TYPE (orig_op0))
                 != TYPE_MAIN_VARIANT (TREE_TYPE (orig_op1)))
            {
-             cp_warning ("comparison between types `%#T' and `%#T'", 
+             warning ("comparison between types `%#T' and `%#T'", 
                          TREE_TYPE (orig_op0), TREE_TYPE (orig_op1));
            }
 
@@ -3959,11 +3761,11 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
             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)))
+                       && int_fits_type_p (orig_op1, c_common_signed_type
+                                           (result_type)))
                        || (op1_signed && TREE_CODE (orig_op0) == INTEGER_CST
-                           && int_fits_type_p (orig_op0,
-                                               signed_type (result_type)))))
+                           && int_fits_type_p (orig_op0, c_common_signed_type
+                                               (result_type)))))
            /* OK */;
          else
            warning ("comparison between signed and unsigned integer expressions");
@@ -4031,12 +3833,12 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
 
   if (!result_type)
     {
-      cp_error ("invalid operands of types `%T' and `%T' to binary `%O'",
+      error ("invalid operands of types `%T' and `%T' to binary `%O'",
                TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), code);
       return error_mark_node;
     }
 
-  /* Issue warnings about peculiar, but legal, uses of NULL.  */
+  /* Issue warnings about peculiar, but valid, uses of NULL.  */
   if (/* It's reasonable to use pointer values as operands of &&
         and ||, so NULL is no exception.  */
       !(code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)
@@ -4053,7 +3855,7 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
        performed.  Note that pointer-difference and pointer-addition
        have already been handled above, and so we don't end up here in
        that case.  */
-    cp_warning ("NULL used in arithmetic");
+    warning ("NULL used in arithmetic");
 
   if (! converted)
     {
@@ -4086,94 +3888,20 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
    of pointer PTROP and integer INTOP.  */
 
 static tree
-pointer_int_sum (resultcode, ptrop, intop)
+cp_pointer_int_sum (resultcode, ptrop, intop)
      enum tree_code resultcode;
      register tree ptrop, intop;
 {
-  tree size_exp;
-
-  register tree result;
-  register tree folded = fold (intop);
-
-  /* The result is a pointer of the same type that is being added.  */
-
-  register tree result_type = TREE_TYPE (ptrop);
-
-  if (!complete_type_or_else (result_type, ptrop))
-    return error_mark_node;
-
-  if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE)
-    {
-      if (pedantic || warn_pointer_arith)
-       pedwarn ("ISO C++ forbids using pointer of type `void *' in pointer arithmetic");
-      size_exp = integer_one_node;
-    }
-  else if (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE)
-    {
-      if (pedantic || warn_pointer_arith)
-       pedwarn ("ISO C++ forbids using a pointer-to-function in pointer arithmetic");
-      size_exp = integer_one_node;
-    }
-  else if (TREE_CODE (TREE_TYPE (result_type)) == METHOD_TYPE)
-    {
-      if (pedantic || warn_pointer_arith)
-       pedwarn ("ISO C++ forbids using a pointer to member function in pointer arithmetic");
-      size_exp = integer_one_node;
-    }
-  else if (TREE_CODE (TREE_TYPE (result_type)) == OFFSET_TYPE)
-    {
-      if (pedantic || warn_pointer_arith)
-       pedwarn ("ISO C++ forbids using pointer to a member in pointer arithmetic");
-      size_exp = integer_one_node;
-    }
-  else
-    size_exp = size_in_bytes (complete_type (TREE_TYPE (result_type)));
-
-  /* Needed to make OOPS V2R3 work.  */
-  intop = folded;
-  if (integer_zerop (intop))
-    return ptrop;
-
-  /* If what we are about to multiply by the size of the elements
-     contains a constant term, apply distributive law
-     and multiply that constant term separately.
-     This helps produce common subexpressions.  */
-
-  if ((TREE_CODE (intop) == PLUS_EXPR || TREE_CODE (intop) == MINUS_EXPR)
-      && ! TREE_CONSTANT (intop)
-      && TREE_CONSTANT (TREE_OPERAND (intop, 1))
-      && TREE_CONSTANT (size_exp))
-    {
-      enum tree_code subcode = resultcode;
-      if (TREE_CODE (intop) == MINUS_EXPR)
-       subcode = (subcode == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR);
-      ptrop = cp_build_binary_op (subcode, ptrop, TREE_OPERAND (intop, 1));
-      intop = TREE_OPERAND (intop, 0);
-    }
+  tree res_type = TREE_TYPE (ptrop);
 
-  /* Convert the integer argument to a type the same size as sizetype
-     so the multiply won't overflow spuriously.  */
+  /* pointer_int_sum() uses size_in_bytes() on the TREE_TYPE(res_type)
+     in certain circumstance (when it's valid to do so).  So we need
+     to make sure it's complete.  We don't need to check here, if we
+     can actually complete it at all, as those checks will be done in
+     pointer_int_sum() anyway.  */
+  complete_type (TREE_TYPE (res_type));
 
-  if (TYPE_PRECISION (TREE_TYPE (intop)) != TYPE_PRECISION (sizetype))
-    intop = cp_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
-     pointer type (actually unsigned integral).  */
-
-  intop = cp_convert (result_type,
-                     cp_build_binary_op (MULT_EXPR, intop,
-                                         cp_convert (TREE_TYPE (intop),
-                                                     size_exp)));
-
-  /* Create the sum or difference.  */
-
-  result = build (resultcode, result_type, ptrop, intop);
-
-  folded = fold (result);
-  if (folded == result)
-    TREE_CONSTANT (folded) = TREE_CONSTANT (ptrop) & TREE_CONSTANT (intop);
-  return folded;
+  return pointer_int_sum (resultcode, ptrop, fold (intop));
 }
 
 /* Return a tree for the difference of pointers OP0 and OP1.
@@ -4231,47 +3959,6 @@ pointer_diff (op0, op1, ptrtype)
   return folded;
 }
 \f
-/* Handle the case of taking the address of a COMPONENT_REF.
-   Called by `build_unary_op'.
-
-   ARG is the COMPONENT_REF whose address we want.
-   ARGTYPE is the pointer type that this address should have. */
-
-static tree
-build_component_addr (arg, argtype)
-     tree arg, argtype;
-{
-  tree field = TREE_OPERAND (arg, 1);
-  tree basetype = decl_type_context (field);
-  tree rval = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), 0);
-
-  my_friendly_assert (TREE_CODE (field) == FIELD_DECL, 981018);
-
-  if (DECL_C_BIT_FIELD (field))
-    {
-      cp_error ("attempt to take address of bit-field structure member `%D'",
-                field);
-      return error_mark_node;
-    }
-
-  if (TREE_CODE (field) == FIELD_DECL
-      && TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (basetype))
-    {
-      /* Can't convert directly to ARGTYPE, since that
-        may have the same pointer type as one of our
-        baseclasses.  */
-      rval = build1 (NOP_EXPR, argtype,
-                    convert_pointer_to (basetype, rval));
-      TREE_CONSTANT (rval) = TREE_CONSTANT (TREE_OPERAND (rval, 0));
-    }
-  else
-    /* This conversion is harmless.  */
-    rval = convert_force (argtype, rval, 0);
-
-  return fold (build (PLUS_EXPR, argtype, rval,
-                     cp_convert (argtype, byte_position (field))));
-}
-   
 /* Construct and perhaps optimize a tree representation
    for a unary operation.  CODE, a tree_code, specifies the operation
    and XARG is the operand.  */
@@ -4306,15 +3993,40 @@ build_x_unary_op (code, xarg)
     }
   if (code == ADDR_EXPR)
     {
+      /*  A pointer to member-function can be formed only by saying
+         &X::mf.  */
+      if (!flag_ms_extensions && TREE_CODE (TREE_TYPE (xarg)) == METHOD_TYPE
+         && (TREE_CODE (xarg) != OFFSET_REF || !PTRMEM_OK_P (xarg)))
+       {
+         if (TREE_CODE (xarg) != OFFSET_REF)
+           {
+             error ("invalid use of '%E' to form a pointer-to-member-function.  Use a qualified-id.",
+                    xarg);
+             return error_mark_node;
+           }
+         else
+           {
+             error ("parenthesis around '%E' cannot be used to form a pointer-to-member-function",
+                    xarg);
+             PTRMEM_OK_P (xarg) = 1;
+           }
+       }
+      
       if (TREE_CODE (xarg) == OFFSET_REF)
         {
           ptrmem = PTRMEM_OK_P (xarg);
           
           if (!ptrmem && !flag_ms_extensions
               && TREE_CODE (TREE_TYPE (TREE_OPERAND (xarg, 1))) == METHOD_TYPE)
-            /* A single non-static member, make sure we don't allow a
-               pointer-to-member.  */
-            xarg = ovl_cons (TREE_OPERAND (xarg, 1), NULL_TREE);
+           {
+             /* A single non-static member, make sure we don't allow a
+                 pointer-to-member.  */
+             xarg = build (OFFSET_REF, TREE_TYPE (xarg),
+                           TREE_OPERAND (xarg, 0),
+                           ovl_cons (TREE_OPERAND (xarg, 1), NULL_TREE));
+             PTRMEM_OK_P (xarg) = ptrmem;
+           }
+             
         }
       else if (TREE_CODE (xarg) == TARGET_EXPR)
        warning ("taking address of temporary");
@@ -4326,8 +4038,9 @@ build_x_unary_op (code, xarg)
   return exp;
 }
 
-/* Like truthvalue_conversion, but handle pointer-to-member constants, where
-   a null value is represented by an INTEGER_CST of -1.  */
+/* Like c_common_truthvalue_conversion, but handle pointer-to-member
+   constants, where a null value is represented by an INTEGER_CST of
+   -1.  */
 
 tree
 cp_truthvalue_conversion (expr)
@@ -4337,7 +4050,7 @@ cp_truthvalue_conversion (expr)
   if (TYPE_PTRMEM_P (type))
     return build_binary_op (NE_EXPR, expr, integer_zero_node, 1);
   else
-    return truthvalue_conversion (expr);
+    return c_common_truthvalue_conversion (expr);
 }
 
 /* Just like cp_truthvalue_conversion, but we want a CLEANUP_POINT_EXPR.  */
@@ -4349,11 +4062,51 @@ condition_conversion (expr)
   tree t;
   if (processing_template_decl)
     return expr;
+  if (TREE_CODE (expr) == OFFSET_REF)
+    expr = resolve_offset_ref (expr);
   t = perform_implicit_conversion (boolean_type_node, expr);
   t = fold (build1 (CLEANUP_POINT_EXPR, boolean_type_node, t));
   return t;
 }
-                              
+               
+/* Return an ADDR_EXPR giving the address of T.  This function
+   attempts no optimizations or simplifications; it is a low-level
+   primitive.  */
+
+tree
+build_address (tree t)
+{
+  tree addr;
+
+  if (error_operand_p (t) || !cxx_mark_addressable (t))
+    return error_mark_node;
+
+  addr = build1 (ADDR_EXPR, 
+                build_pointer_type (TREE_TYPE (t)),
+                t);
+  if (staticp (t))
+    TREE_CONSTANT (addr) = 1;
+
+  return addr;
+}
+
+/* Return a NOP_EXPR converting EXPR to TYPE.  */
+
+tree
+build_nop (tree type, tree expr)
+{
+  tree nop;
+
+  if (type == error_mark_node || error_operand_p (expr))
+    return expr;
+    
+  nop = build1 (NOP_EXPR, type, expr);
+  if (TREE_CONSTANT (expr))
+    TREE_CONSTANT (nop) = 1;
+  
+  return nop;
+}
+
 /* C++: Must handle pointers to members.
 
    Perhaps type instantiation should be extended to handle conversion
@@ -4385,7 +4138,7 @@ build_unary_op (code, xarg, noconvert)
         is enough to prevent anybody from looking inside for
         associativity, but won't generate any code.  */
       if (!(arg = build_expr_type_conversion
-           (WANT_ARITH | WANT_ENUM | WANT_POINTER, arg, 1)))
+           (WANT_ARITH | WANT_ENUM | WANT_POINTER, arg, true)))
        errstring = "wrong type argument to unary plus";
       else
        {
@@ -4397,7 +4150,7 @@ build_unary_op (code, xarg, noconvert)
       break;
 
     case NEGATE_EXPR:
-      if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, 1)))
+      if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, true)))
        errstring = "wrong type argument to unary minus";
       else if (!noconvert)
        arg = default_conversion (arg);
@@ -4411,14 +4164,14 @@ build_unary_op (code, xarg, noconvert)
            arg = default_conversion (arg);
        }
       else if (!(arg = build_expr_type_conversion (WANT_INT | WANT_ENUM,
-                                                  arg, 1)))
+                                                  arg, true)))
        errstring = "wrong type argument to bit-complement";
       else if (!noconvert)
        arg = default_conversion (arg);
       break;
 
     case ABS_EXPR:
-      if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, 1)))
+      if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, true)))
        errstring = "wrong type argument to abs";
       else if (!noconvert)
        arg = default_conversion (arg);
@@ -4426,7 +4179,7 @@ build_unary_op (code, xarg, noconvert)
 
     case CONJ_EXPR:
       /* Conjugating a real value is a no-op, but allow it anyway.  */
-      if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, 1)))
+      if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, true)))
        errstring = "wrong type argument to conjugation";
       else if (!noconvert)
        arg = default_conversion (arg);
@@ -4486,7 +4239,7 @@ build_unary_op (code, xarg, noconvert)
       /* Report invalid types.  */
 
       if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_POINTER,
-                                             arg, 1)))
+                                             arg, true)))
        {
          if (code == PREINCREMENT_EXPR)
            errstring ="no pre-increment operator for type";
@@ -4529,18 +4282,18 @@ build_unary_op (code, xarg, noconvert)
            tree type = complete_type (TREE_TYPE (argtype));
            
            if (!COMPLETE_OR_VOID_TYPE_P (type))
-             cp_error ("cannot %s a pointer to incomplete type `%T'",
+             error ("cannot %s a pointer to incomplete type `%T'",
                        ((code == PREINCREMENT_EXPR
                          || code == POSTINCREMENT_EXPR)
                         ? "increment" : "decrement"), TREE_TYPE (argtype));
            else if ((pedantic || warn_pointer_arith)
                     && (tmp == FUNCTION_TYPE || tmp == METHOD_TYPE
                         || tmp == VOID_TYPE || tmp == OFFSET_TYPE))
-             cp_pedwarn ("ISO C++ forbids %sing a pointer of type `%T'",
+             pedwarn ("ISO C++ forbids %sing a pointer of type `%T'",
                          ((code == PREINCREMENT_EXPR
                            || code == POSTINCREMENT_EXPR)
                           ? "increment" : "decrement"), argtype);
-           inc = c_sizeof_nowarn (TREE_TYPE (argtype));
+           inc = cxx_sizeof_nowarn (TREE_TYPE (argtype));
          }
        else
          inc = integer_one_node;
@@ -4595,7 +4348,7 @@ build_unary_op (code, xarg, noconvert)
          {
            if (code == POSTDECREMENT_EXPR || code == PREDECREMENT_EXPR)
              {
-               cp_error ("invalid use of `--' on bool variable `%D'", arg);
+               error ("invalid use of `--' on bool variable `%D'", arg);
                return error_mark_node;
              }
 #if 0
@@ -4655,7 +4408,7 @@ build_unary_op (code, xarg, noconvert)
       /* For &x[y], return x+y */
       if (TREE_CODE (arg) == ARRAY_REF)
        {
-         if (mark_addressable (TREE_OPERAND (arg, 0)) == 0)
+         if (!cxx_mark_addressable (TREE_OPERAND (arg, 0)))
            return error_mark_node;
          return cp_build_binary_op (PLUS_EXPR, TREE_OPERAND (arg, 0),
                                     TREE_OPERAND (arg, 1));
@@ -4668,14 +4421,14 @@ build_unary_op (code, xarg, noconvert)
       if (TREE_CODE (arg) == IDENTIFIER_NODE
          && IDENTIFIER_OPNAME_P (arg))
        {
-         my_friendly_abort (117);
+         abort ();
          /* We don't know the type yet, so just work around the problem.
             We know that this will resolve to an lvalue.  */
          return build1 (ADDR_EXPR, unknown_type_node, arg);
        }
 
       if (TREE_CODE (arg) == COMPONENT_REF && type_unknown_p (arg)
-          && OVL_NEXT (TREE_OPERAND (arg, 1)) == NULL_TREE)
+         && !really_overloaded_fn (TREE_OPERAND (arg, 1)))
         {
          /* They're trying to take the address of a unique non-static
             member function.  This is ill-formed (except in MS-land),
@@ -4688,16 +4441,16 @@ build_unary_op (code, xarg, noconvert)
             a useful error here.  */
 
          tree base = TREE_TYPE (TREE_OPERAND (arg, 0));
-         tree name = DECL_NAME (OVL_CURRENT (TREE_OPERAND (arg, 1)));
+         tree name = DECL_NAME (get_first_fn (TREE_OPERAND (arg, 1)));
 
          if (! flag_ms_extensions)
            {
              if (current_class_type
                  && TREE_OPERAND (arg, 0) == current_class_ref)
                /* An expression like &memfn.  */
-               cp_pedwarn ("ISO C++ forbids taking the address of an unqualified non-static member function to form a pointer to member function.  Say `&%T::%D'", base, name);
+               pedwarn ("ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function.  Say `&%T::%D'", base, name);
              else
-               cp_pedwarn ("ISO C++ forbids taking the address of a bound member function to form a pointer to member function.  Say `&%T::%D'", base, name);
+               pedwarn ("ISO C++ forbids taking the address of a bound member function to form a pointer to member function.  Say `&%T::%D'", base, name);
            }
          arg = build_offset_ref (base, name);
         }
@@ -4737,27 +4490,46 @@ build_unary_op (code, xarg, noconvert)
         is an error.  */
       else if (TREE_CODE (argtype) != FUNCTION_TYPE
               && TREE_CODE (argtype) != METHOD_TYPE
-              && !lvalue_or_else (arg, "unary `&'"))
+              && !non_cast_lvalue_or_else (arg, "unary `&'"))
        return error_mark_node;
 
       if (argtype != error_mark_node)
        argtype = build_pointer_type (argtype);
 
-      if (mark_addressable (arg) == 0)
-       return error_mark_node;
-
       {
        tree addr;
 
-       if (TREE_CODE (arg) == COMPONENT_REF)
-         addr = build_component_addr (arg, argtype);
-       else
-         addr = build1 (ADDR_EXPR, argtype, arg);
+       if (TREE_CODE (arg) == COMPONENT_REF
+           && TREE_CODE (TREE_OPERAND (arg, 1)) == BASELINK)
+         arg = BASELINK_FUNCTIONS (TREE_OPERAND (arg, 1));
 
-       /* Address of a static or external variable or
-          function counts as a constant */
-       if (staticp (arg))
-         TREE_CONSTANT (addr) = 1;
+       if (TREE_CODE (arg) == COMPONENT_REF
+           && DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1)))
+         {
+           error ("attempt to take address of bit-field structure member `%D'",
+                  TREE_OPERAND (arg, 1));
+           return error_mark_node;
+         }
+       else if (TREE_CODE (arg) == COMPONENT_REF
+                && TREE_CODE (TREE_OPERAND (arg, 0)) == INDIRECT_REF
+                && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (arg, 0), 0))
+                    == INTEGER_CST))
+         {
+           /* offsetof idiom, fold it.  */
+           tree field = TREE_OPERAND (arg, 1);
+           tree rval = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), 0);
+           tree binfo = lookup_base (TREE_TYPE (TREE_TYPE (rval)),
+                                     decl_type_context (field),
+                                     ba_check, NULL);
+           
+           rval = build_base_path (PLUS_EXPR, rval, binfo, 1);
+           rval = build1 (NOP_EXPR, argtype, rval);
+           TREE_CONSTANT (rval) = TREE_CONSTANT (TREE_OPERAND (rval, 0));
+           addr = fold (build (PLUS_EXPR, argtype, rval,
+                               cp_convert (argtype, byte_position (field))));
+         }
+       else
+         addr = build_address (arg);
 
        if (TREE_CODE (argtype) == POINTER_TYPE
            && TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE)
@@ -4857,7 +4629,7 @@ unary_complex_lvalue (code, arg)
       if (TREE_CODE (t) == FUNCTION_DECL)
        {
          if (DECL_DESTRUCTOR_P (t))
-           cp_error ("taking address of destructor");
+           error ("taking address of destructor");
          return build_unary_op (ADDR_EXPR, t, 0);
        }
       if (TREE_CODE (t) == VAR_DECL)
@@ -4870,13 +4642,27 @@ unary_complex_lvalue (code, arg)
              && ! is_dummy_object (TREE_OPERAND (arg, 0))
              && TREE_CODE (t) != FIELD_DECL)
            {
-             cp_error ("taking address of bound pointer-to-member expression");
+             error ("taking address of bound pointer-to-member expression");
              return error_mark_node;
            }
+         if (!PTRMEM_OK_P (arg))
+           {
+             /* This cannot form a pointer to method, so we must
+                resolve the offset ref, and take the address of the
+                result.  For instance,
+                       &(C::m)       */
+             arg = resolve_offset_ref (arg);
 
-         type = build_offset_type (DECL_FIELD_CONTEXT (t), TREE_TYPE (t));
-         type = build_pointer_type (type);
+             return build_unary_op (code, arg, 0);
+           }
+         
+         if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
+           {
+             error ("cannot create pointer to reference member `%D'", t);
+             return error_mark_node;
+           }
 
+         type = build_ptrmem_type (DECL_FIELD_CONTEXT (t), TREE_TYPE (t));
          t = make_ptrmem_cst (type, TREE_OPERAND (arg, 1));
          return t;
        }
@@ -4911,19 +4697,16 @@ unary_complex_lvalue (code, arg)
 \f
 /* Mark EXP saying that we need to be able to take the
    address of it; it should not be allocated in a register.
-   Value is 1 if successful.
+   Value is true if successful.
 
    C++: we do not allow `current_class_ptr' to be addressable.  */
 
-int
-mark_addressable (exp)
+bool
+cxx_mark_addressable (exp)
      tree exp;
 {
   register tree x = exp;
 
-  if (TREE_ADDRESSABLE (x) == 1)
-    return 1;
-
   while (1)
     switch (TREE_CODE (x))
       {
@@ -4940,8 +4723,10 @@ mark_addressable (exp)
          {
             error ("cannot take the address of `this', which is an rvalue expression");
            TREE_ADDRESSABLE (x) = 1; /* so compiler doesn't die later */
-           return 1;
+           return true;
          }
+       /* FALLTHRU */
+
       case VAR_DECL:
        /* Caller should not be trying to mark initialized
           constant fields addressable.  */
@@ -4949,32 +4734,34 @@ mark_addressable (exp)
                            || DECL_IN_AGGR_P (x) == 0
                            || TREE_STATIC (x)
                            || DECL_EXTERNAL (x), 314);
+       /* FALLTHRU */
 
       case CONST_DECL:
       case RESULT_DECL:
        if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x)
            && !DECL_ARTIFICIAL (x) && extra_warnings)
-         cp_warning ("address requested for `%D', which is declared `register'",
+         warning ("address requested for `%D', which is declared `register'",
                      x);
        TREE_ADDRESSABLE (x) = 1;
-       return 1;
+       put_var_into_stack (x);
+       return true;
 
       case FUNCTION_DECL:
        TREE_ADDRESSABLE (x) = 1;
        TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (x)) = 1;
-       return 1;
+       return true;
 
       case CONSTRUCTOR:
        TREE_ADDRESSABLE (x) = 1;
-       return 1;
+       return true;
 
       case TARGET_EXPR:
        TREE_ADDRESSABLE (x) = 1;
-       mark_addressable (TREE_OPERAND (x, 0));
-       return 1;
+       cxx_mark_addressable (TREE_OPERAND (x, 0));
+       return true;
 
       default:
-       return 1;
+       return true;
     }
 }
 \f
@@ -5006,15 +4793,15 @@ build_x_compound_expr (list)
   if (rest == NULL_TREE)
     return build_compound_expr (list);
 
-  result = build_opfncall (COMPOUND_EXPR, LOOKUP_NORMAL,
-                          TREE_VALUE (list), TREE_VALUE (rest), NULL_TREE);
+  result = build_new_op (COMPOUND_EXPR, LOOKUP_NORMAL,
+                        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)))
     {
-      /* FIXME: This test should be in the implicit cast to void of the LHS. */
+      /* FIXME: This test should be in the implicit cast to void of the LHS.  */
       /* 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).  */
@@ -5111,12 +4898,11 @@ build_static_cast (type, expr)
                                   LOOKUP_COMPLAIN, NULL_TREE)));
 
   if (IS_AGGR_TYPE (type))
-    return build_cplus_new (type, (build_method_call
+    return build_cplus_new (type, (build_special_member_call
                                   (NULL_TREE, complete_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.  */
@@ -5126,20 +4912,36 @@ build_static_cast (type, expr)
       ? can_convert_arg (type, intype, expr)
       : can_convert_arg (strip_all_pointer_quals (type),
                          strip_all_pointer_quals (intype), expr))
-    /* This is a standard conversion. */
+    /* This is a standard conversion.  */
     ok = 1;
   else if (TYPE_PTROB_P (type) && TYPE_PTROB_P (intype))
     {
       /* They're pointers to objects. They must be aggregates that
-         are related non-virtually. */
-      
-      tree binfo;
+         are related non-virtually.  */
+      base_kind kind;
       
       if (IS_AGGR_TYPE (TREE_TYPE (type)) && IS_AGGR_TYPE (TREE_TYPE (intype))
-         && (binfo = get_binfo (TREE_TYPE (intype), TREE_TYPE (type), 0))
-         && !binfo_from_vbase (binfo))
+         && lookup_base (TREE_TYPE (type), TREE_TYPE (intype),
+                         ba_ignore | ba_quiet, &kind)
+         && kind != bk_via_virtual)
        ok = 1;
     }
+  else if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
+    {
+      /* They're pointers to members. The pointed to objects must be
+        the same (ignoring CV qualifiers), and the containing classes
+        must be related non-virtually.  */
+      base_kind kind;
+      
+      if (same_type_p
+         (strip_all_pointer_quals (TREE_TYPE (TREE_TYPE (type))),
+          strip_all_pointer_quals (TREE_TYPE (TREE_TYPE (intype))))
+         && (lookup_base (TYPE_OFFSET_BASETYPE (TREE_TYPE (intype)),
+                          TYPE_OFFSET_BASETYPE (TREE_TYPE (type)),
+                          ba_ignore | ba_quiet, &kind))
+         && kind != bk_via_virtual)
+       ok = 1;
+    }
   else if (TREE_CODE (intype) != BOOLEAN_TYPE
           && TREE_CODE (type) != ARRAY_TYPE
           && TREE_CODE (type) != FUNCTION_TYPE
@@ -5159,7 +4961,7 @@ build_static_cast (type, expr)
      constness.  */
   if (ok && casts_away_constness (intype, type))
     {
-      cp_error ("static_cast from type `%T' to type `%T' casts away constness",
+      error ("static_cast from type `%T' to type `%T' casts away constness",
                intype, type);
       return error_mark_node;
     }
@@ -5167,7 +4969,7 @@ build_static_cast (type, expr)
   if (ok)
     return build_c_cast (type, expr);
 
-  cp_error ("invalid static_cast from type `%T' to type `%T'", intype, type);
+  error ("invalid static_cast from type `%T' to type `%T'", intype, type);
   return error_mark_node;
 }
 
@@ -5206,7 +5008,7 @@ build_reinterpret_cast (type, expr)
     {
       if (! real_lvalue_p (expr))
        {
-         cp_error ("invalid reinterpret_cast of an rvalue expression of type `%T' to type `%T'", intype, type);
+         error ("invalid reinterpret_cast of an rvalue expression of type `%T' to type `%T'", intype, type);
          return error_mark_node;
        }
       expr = build_unary_op (ADDR_EXPR, expr, 0);
@@ -5226,7 +5028,7 @@ build_reinterpret_cast (type, expr)
   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",
+       pedwarn ("reinterpret_cast from `%T' to `%T' loses precision",
                    intype, type);
     }
   else if ((TYPE_PTRFN_P (type) && TYPE_PTRFN_P (intype))
@@ -5239,7 +5041,7 @@ build_reinterpret_cast (type, expr)
           || (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)",
+       pedwarn ("reinterpret_cast from `%T' to `%T' casts away const (or volatile)",
                    intype, type);
 
       expr = decl_constant_value (expr);
@@ -5254,7 +5056,7 @@ build_reinterpret_cast (type, expr)
     }
   else
     {
-      cp_error ("invalid reinterpret_cast from type `%T' to type `%T'",
+      error ("invalid reinterpret_cast from type `%T' to type `%T'",
                 intype, type);
       return error_mark_node;
     }
@@ -5281,10 +5083,10 @@ build_const_cast (type, expr)
     }
 
   if (!POINTER_TYPE_P (type))
-    cp_error ("invalid use of const_cast with type `%T', which is not a pointer, reference, nor a pointer-to-data-member type", type);
+    error ("invalid use of const_cast with type `%T', which is not a pointer, reference, nor a pointer-to-data-member type", type);
   else if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
     {
-      cp_error ("invalid use of const_cast with type `%T', which is a pointer or reference to a function type", type);
+      error ("invalid use of const_cast with type `%T', which is a pointer or reference to a function type", type);
       return error_mark_node;
     }
 
@@ -5307,7 +5109,7 @@ build_const_cast (type, expr)
     {
       if (! real_lvalue_p (expr))
        {
-         cp_error ("invalid const_cast of an rvalue of type `%T' to type `%T'", intype, type);
+         error ("invalid const_cast of an rvalue of type `%T' to type `%T'", intype, type);
          return error_mark_node;
        }
 
@@ -5323,7 +5125,7 @@ build_const_cast (type, expr)
           && comp_ptr_ttypes_const (TREE_TYPE (type), TREE_TYPE (intype)))
     return cp_convert (type, expr);
 
-  cp_error ("invalid const_cast from type `%T' to type `%T'", intype, type);
+  error ("invalid const_cast from type `%T' to type `%T'", intype, type);
   return error_mark_node;
 }
 
@@ -5365,12 +5167,12 @@ build_c_cast (type, expr)
         NIHCL uses it. It is not valid ISO C++ however.  */
       if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE)
        {
-         cp_pedwarn ("ISO C++ forbids casting to an array type `%T'", type);
+         pedwarn ("ISO C++ forbids casting to an array type `%T'", type);
          type = build_pointer_type (TREE_TYPE (type));
        }
       else
        {
-         cp_error ("ISO C++ forbids casting to an array type `%T'", type);
+         error ("ISO C++ forbids casting to an array type `%T'", type);
          return error_mark_node;
        }
     }
@@ -5378,7 +5180,7 @@ build_c_cast (type, expr)
   if (TREE_CODE (type) == FUNCTION_TYPE
       || TREE_CODE (type) == METHOD_TYPE)
     {
-      cp_error ("invalid cast to function type `%T'", type);
+      error ("invalid cast to function type `%T'", type);
       return error_mark_node;
     }
 
@@ -5430,7 +5232,7 @@ build_c_cast (type, expr)
       && TREE_CODE (otype) == POINTER_TYPE
       && !at_least_as_qualified_p (TREE_TYPE (type),
                                   TREE_TYPE (otype)))
-    cp_warning ("cast from `%T' to `%T' discards qualifiers from pointer target type",
+    warning ("cast from `%T' to `%T' discards qualifiers from pointer target type",
                 otype, type);
 
   if (TREE_CODE (type) == INTEGER_TYPE
@@ -5476,7 +5278,7 @@ build_c_cast (type, expr)
       && COMPLETE_TYPE_P (TREE_TYPE (otype))
       && COMPLETE_TYPE_P (TREE_TYPE (type))
       && TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (otype)))
-    cp_warning ("cast from `%T' to `%T' increases required alignment of target type",
+    warning ("cast from `%T' to `%T' increases required alignment of target type",
                 otype, type);
 
     /* Always produce some operator for an explicit cast,
@@ -5511,13 +5313,7 @@ build_modify_expr (lhs, modifycode, rhs)
   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);
-
-  newrhs = rhs;
-
   /* Handle control structure constructs used as "lvalues".  */
-
   switch (TREE_CODE (lhs))
     {
       /* Handle --foo = 5; as these are valid constructs in C++ */
@@ -5549,13 +5345,15 @@ build_modify_expr (lhs, modifycode, rhs)
 
       /* Handle (a ? b : c) used as an "lvalue".  */
     case COND_EXPR:
-      rhs = save_expr (rhs);
       {
        /* Produce (a ? (b = rhs) : (c = rhs))
           except that the RHS goes through a save-expr
           so the code to compute it is only emitted once.  */
        tree cond;
+       tree preeval = NULL_TREE;
 
+       rhs = stabilize_expr (rhs, &preeval);
+       
        /* Check this here to avoid odd errors when trying to convert
           a throw to the type of the COND_EXPR.  */
        if (!lvalue_or_else (lhs, "assignment"))
@@ -5574,55 +5372,25 @@ build_modify_expr (lhs, modifycode, rhs)
          return cond;
        /* Make sure the code to compute the rhs comes out
           before the split.  */
-       return build (COMPOUND_EXPR, TREE_TYPE (lhs),
-                     /* Case to void to suppress warning
-                        from warn_if_unused_value.  */
-                     cp_convert (void_type_node, rhs), cond);
+       return build (COMPOUND_EXPR, TREE_TYPE (lhs), preeval, cond);
       }
-
+      
+    case OFFSET_REF:
+      lhs = resolve_offset_ref (lhs);
+      if (lhs == error_mark_node)
+       return error_mark_node;
+      olhstype = lhstype = TREE_TYPE (lhs);
+    
     default:
       break;
     }
 
-  if (TREE_CODE (lhs) == OFFSET_REF)
-    {
-      if (TREE_OPERAND (lhs, 0) == NULL_TREE)
-       {
-         /* Static class member?  */
-         tree member = TREE_OPERAND (lhs, 1);
-         if (TREE_CODE (member) == VAR_DECL)
-           lhs = member;
-         else
-           {
-             compiler_error ("invalid static class member");
-             return error_mark_node;
-           }
-       }
-      else
-       lhs = resolve_offset_ref (lhs);
-
-      olhstype = lhstype = TREE_TYPE (lhs);
-    }
-
-  if (lhs == error_mark_node)
-    return lhs;
-
-  if (TREE_CODE (lhstype) == REFERENCE_TYPE
-      && modifycode != INIT_EXPR)
-    {
-      lhs = convert_from_reference (lhs);
-      olhstype = lhstype = TREE_TYPE (lhs);
-    }
-
-  /* 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)
     {
       if (TREE_CODE (rhs) == CONSTRUCTOR)
        {
-         if (! same_type_p (TREE_TYPE (rhs), lhstype))
-           abort ();
+         my_friendly_assert (same_type_p (TREE_TYPE (rhs), lhstype),
+                             20011220);
          result = build (INIT_EXPR, lhstype, lhs, rhs);
          TREE_SIDE_EFFECTS (result) = 1;
          return result;
@@ -5631,43 +5399,64 @@ build_modify_expr (lhs, modifycode, rhs)
        /* Do the default thing */;
       else
        {
-         result = build_method_call (lhs, complete_ctor_identifier,
-                                     build_tree_list (NULL_TREE, rhs),
-                                     TYPE_BINFO (lhstype), LOOKUP_NORMAL);
+         result = build_special_member_call (lhs, complete_ctor_identifier,
+                                             build_tree_list (NULL_TREE, rhs),
+                                             TYPE_BINFO (lhstype), 
+                                             LOOKUP_NORMAL);
          if (result == NULL_TREE)
            return error_mark_node;
          return result;
        }
     }
-  else if (modifycode == NOP_EXPR)
+  else
     {
-      /* `operator=' is not an inheritable operator.  */
-      if (! IS_AGGR_TYPE (lhstype))
-       /* Do the default thing */;
-      else
+      if (TREE_CODE (lhstype) == REFERENCE_TYPE)
        {
-         result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
-                                  lhs, rhs, make_node (NOP_EXPR));
-         if (result == NULL_TREE)
-           return error_mark_node;
-         return result;
+         lhs = convert_from_reference (lhs);
+         olhstype = lhstype = TREE_TYPE (lhs);
        }
-      lhstype = olhstype;
-    }
-  else if (PROMOTES_TO_AGGR_TYPE (lhstype, REFERENCE_TYPE))
-    {
-      my_friendly_abort (978652);
-    }
-  else
-    {
-      lhs = stabilize_reference (lhs);
-      newrhs = cp_build_binary_op (modifycode, lhs, rhs);
-      if (newrhs == error_mark_node)
+      lhs = require_complete_type (lhs);
+      if (lhs == error_mark_node)
+       return error_mark_node;
+
+      if (modifycode == NOP_EXPR)
        {
-         cp_error ("  in evaluation of `%Q(%#T, %#T)'", modifycode,
-                   TREE_TYPE (lhs), TREE_TYPE (rhs));
-         return error_mark_node;
+         /* `operator=' is not an inheritable operator.  */
+         if (! IS_AGGR_TYPE (lhstype))
+           /* Do the default thing */;
+         else
+           {
+             result = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL,
+                                    lhs, rhs, make_node (NOP_EXPR));
+             if (result == NULL_TREE)
+               return error_mark_node;
+             return result;
+           }
+         lhstype = olhstype;
+       }
+      else
+       {
+         /* A binary op has been requested.  Combine the old LHS
+            value with the RHS producing the value we should actually
+            store into the LHS.  */
+
+         my_friendly_assert (!PROMOTES_TO_AGGR_TYPE (lhstype, REFERENCE_TYPE),
+                             978652);
+         lhs = stabilize_reference (lhs);
+         newrhs = cp_build_binary_op (modifycode, lhs, rhs);
+         if (newrhs == error_mark_node)
+           {
+             error ("  in evaluation of `%Q(%#T, %#T)'", modifycode,
+                    TREE_TYPE (lhs), TREE_TYPE (rhs));
+             return error_mark_node;
+           }
+         
+         /* Now it looks like a plain assignment.  */
+         modifycode = NOP_EXPR;
        }
+      my_friendly_assert (TREE_CODE (lhstype) != REFERENCE_TYPE, 20011220);
+      my_friendly_assert (TREE_CODE (TREE_TYPE (newrhs)) != REFERENCE_TYPE,
+                         20011220);
     }
 
   /* Handle a cast used as an "lvalue".
@@ -5686,15 +5475,16 @@ build_modify_expr (lhs, modifycode, rhs)
     case FIX_FLOOR_EXPR:
     case FIX_ROUND_EXPR:
     case FIX_CEIL_EXPR:
-      if (TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE
-         || TREE_CODE (TREE_TYPE (newrhs)) == FUNCTION_TYPE
-         || TREE_CODE (TREE_TYPE (newrhs)) == METHOD_TYPE
-         || TREE_CODE (TREE_TYPE (newrhs)) == OFFSET_TYPE)
-       newrhs = default_conversion (newrhs);
       {
        tree inner_lhs = TREE_OPERAND (lhs, 0);
        tree result;
 
+       if (TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE
+           || TREE_CODE (TREE_TYPE (newrhs)) == FUNCTION_TYPE
+           || TREE_CODE (TREE_TYPE (newrhs)) == METHOD_TYPE
+           || TREE_CODE (TREE_TYPE (newrhs)) == OFFSET_TYPE)
+         newrhs = default_conversion (newrhs);
+       
        /* ISO C++ 5.4/1: The result is an lvalue if T is a reference
           type, otherwise the result is an rvalue.  */
        if (! lvalue_p (lhs))
@@ -5718,25 +5508,23 @@ build_modify_expr (lhs, modifycode, rhs)
   if (!lvalue_or_else (lhs, "assignment"))
     return error_mark_node;
 
-  GNU_xref_assign (lhs);
-
-  /* Warn about storing in something that is `const'.  */
-  /* For C++, don't warn if this is initialization.  */
+  /* Warn about modifying something that is `const'.  Don't warn if
+     this is initialization.  */
   if (modifycode != INIT_EXPR
       && (TREE_READONLY (lhs) || CP_TYPE_CONST_P (lhstype)
          /* Functions are not modifiable, even though they are
             lvalues.  */
          || TREE_CODE (TREE_TYPE (lhs)) == FUNCTION_TYPE
-         || (IS_AGGR_TYPE_CODE (TREE_CODE (lhstype))
-             && C_TYPE_FIELDS_READONLY (lhstype))
-         || (TREE_CODE (lhstype) == REFERENCE_TYPE
-             && CP_TYPE_CONST_P (TREE_TYPE (lhstype)))))
+         || TREE_CODE (TREE_TYPE (lhs)) == METHOD_TYPE
+         /* If it's an aggregate and any field is const, then it is
+            effectively const.  */
+         || (CLASS_TYPE_P (lhstype)
+             && C_TYPE_FIELDS_READONLY (lhstype))))
     readonly_error (lhs, "assignment", 0);
 
-  /* 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 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
@@ -5755,74 +5543,40 @@ build_modify_expr (lhs, modifycode, rhs)
        }
     }
 
-  if (modifycode != INIT_EXPR)
+  if (TREE_CODE (lhstype) != REFERENCE_TYPE)
     {
-      /* Make modifycode now either a NOP_EXPR or an INIT_EXPR.  */
-      modifycode = NOP_EXPR;
-      /* Reference-bashing */
-      if (TREE_CODE (lhstype) == REFERENCE_TYPE)
-       {
-         tree tmp = convert_from_reference (lhs);
-         lhstype = TREE_TYPE (tmp);
-         if (!COMPLETE_TYPE_P (lhstype))
-           {
-             incomplete_type_error (lhs, lhstype);
-             return error_mark_node;
-           }
-         lhs = tmp;
-         olhstype = lhstype;
-       }
-      if (TREE_CODE (TREE_TYPE (newrhs)) == REFERENCE_TYPE)
-       {
-         tree tmp = convert_from_reference (newrhs);
-         if (!COMPLETE_TYPE_P (TREE_TYPE (tmp)))
-           {
-             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 (TREE_SIDE_EFFECTS (lhs))
-    lhs = stabilize_reference (lhs);
-  if (TREE_SIDE_EFFECTS (newrhs))
-    newrhs = stabilize_reference (newrhs);
-
   /* Convert new value to destination type.  */
 
   if (TREE_CODE (lhstype) == ARRAY_TYPE)
     {
       int from_array;
       
-      if (!same_or_base_type_p (lhstype, TREE_TYPE (rhs)))
+      if (!same_or_base_type_p (TYPE_MAIN_VARIANT (lhstype),
+                               TYPE_MAIN_VARIANT (TREE_TYPE (rhs))))
        {
-         cp_error ("incompatible types in assignment of `%T' to `%T'",
-                   TREE_TYPE (rhs), lhstype);
+         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))
+      if (! DECL_ARTIFICIAL (current_function_decl))
        pedwarn ("ISO C++ forbids assignment of arrays");
 
       from_array = TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE
                   ? 1 + (modifycode != INIT_EXPR): 0;
-      return build_vec_init (lhs, newrhs, from_array);
+      return build_vec_init (lhs, NULL_TREE, newrhs, from_array);
     }
 
   if (modifycode == INIT_EXPR)
-    {
-      newrhs = convert_for_initialization (lhs, lhstype, newrhs, LOOKUP_NORMAL,
-                                          "initialization", NULL_TREE, 0);
-      if (current_function_decl && 
-         lhs == DECL_RESULT (current_function_decl))
-       {
-         if (DECL_INITIAL (lhs))
-           warning ("return value from function receives multiple initializations");
-         DECL_INITIAL (lhs) = newrhs;
-       }
-    }
+    newrhs = convert_for_initialization (lhs, lhstype, newrhs, LOOKUP_NORMAL,
+                                        "initialization", NULL_TREE, 0);
   else
     {
       /* Avoid warnings on enum bit fields.  */
@@ -5925,8 +5679,8 @@ build_x_modify_expr (lhs, modifycode, rhs)
 
   if (modifycode != NOP_EXPR)
     {
-      tree rval = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs,
-                                 make_node (modifycode));
+      tree rval = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs,
+                               make_node (modifycode));
       if (rval)
        return rval;
     }
@@ -5951,21 +5705,15 @@ get_delta_difference (from, to, force)
   tree delta = integer_zero_node;
   tree binfo;
   tree virt_binfo;
+  base_kind kind;
   
-  if (to == from)
-    return delta;
-
-  /* Should get_base_distance here, so we can check if any thing along
-     the path is virtual, and we need to make sure we stay inside the
-     real binfos when going through virtual bases.  Maybe we should
-     replace virtual bases with BINFO_FOR_VBASE ... (mrs) */
-  binfo = get_binfo (from, to, 1);
-  if (binfo == error_mark_node)
+  binfo = lookup_base (to, from, ba_check, &kind);
+  if (kind == bk_inaccessible || kind == bk_ambig)
     {
       error ("   in pointer to member function conversion");
       return delta;
     }
-  if (binfo == 0)
+  if (!binfo)
     {
       if (!force)
        {
@@ -5973,17 +5721,16 @@ get_delta_difference (from, to, force)
          error ("   in pointer to member conversion");
          return delta;
        }
-      binfo = get_binfo (to, from, 1);
-      if (binfo == 0 || binfo == error_mark_node)
+      binfo = lookup_base (from, to, ba_check, &kind);
+      if (binfo == 0)
        return delta;
       virt_binfo = binfo_from_vbase (binfo);
       
       if (virt_binfo)
         {
-          /* This is a reinterpret cast, we choose to do nothing. */
-          cp_warning ("pointer to member cast via virtual base `%T' of `%T'",
-                     BINFO_TYPE (virt_binfo),
-                     BINFO_TYPE (BINFO_INHERITANCE_CHAIN (virt_binfo)));
+          /* This is a reinterpret cast, we choose to do nothing.  */
+          warning ("pointer to member cast via virtual base `%T'",
+                  BINFO_TYPE (virt_binfo));
           return delta;
         }
       delta = BINFO_OFFSET (binfo);
@@ -5998,15 +5745,13 @@ get_delta_difference (from, to, force)
   virt_binfo = binfo_from_vbase (binfo);
   if (virt_binfo)
     {
-      /* This is a reinterpret cast, we choose to do nothing. */
+      /* This is a reinterpret cast, we choose to do nothing.  */
       if (force)
-        cp_warning ("pointer to member cast via virtual base `%T' of `%T'",
-                    BINFO_TYPE (virt_binfo),
-                    BINFO_TYPE (BINFO_INHERITANCE_CHAIN (virt_binfo)));
+        warning ("pointer to member cast via virtual base `%T'",
+                BINFO_TYPE (virt_binfo));
       else
-       cp_error ("pointer to member conversion via virtual base `%T' of `%T'",
-                 BINFO_TYPE (virt_binfo),
-                  BINFO_TYPE (BINFO_INHERITANCE_CHAIN (virt_binfo)));
+       error ("pointer to member conversion via virtual base `%T'",
+              BINFO_TYPE (virt_binfo));
       return delta;
     }
   delta = BINFO_OFFSET (binfo);
@@ -6050,7 +5795,7 @@ build_ptrmemfunc1 (type, delta, pfn)
    as a value in expressions.  TYPE is the POINTER to METHOD_TYPE we
    want to be.
 
-   If FORCE is non-zero, then force this conversion, even if
+   If FORCE is nonzero, then force this conversion, even if
    we would rather not do it.  Usually set when using an explicit
    cast.
 
@@ -6062,11 +5807,17 @@ build_ptrmemfunc (type, pfn, force)
      int force;
 {
   tree fn;
-  tree pfn_type = TREE_TYPE (pfn);
-  tree to_type = build_ptrmemfunc_type (type);
+  tree pfn_type;
+  tree to_type;
+
+  if (error_operand_p (pfn))
+    return error_mark_node;
+
+  pfn_type = TREE_TYPE (pfn);
+  to_type = build_ptrmemfunc_type (type);
 
   /* Handle multiple conversions of pointer to member functions.  */
-  if (TYPE_PTRMEMFUNC_P (TREE_TYPE (pfn)))
+  if (TYPE_PTRMEMFUNC_P (pfn_type))
     {
       tree delta = NULL_TREE;
       tree npfn = NULL_TREE;
@@ -6074,7 +5825,7 @@ build_ptrmemfunc (type, pfn, force)
 
       if (!force 
          && !can_convert_arg (to_type, TREE_TYPE (pfn), pfn))
-       cp_error ("invalid conversion to type `%T' from type `%T'", 
+       error ("invalid conversion to type `%T' from type `%T'", 
                  to_type, pfn_type);
 
       n = get_delta_difference (TYPE_PTRMEMFUNC_OBJECT_TYPE (pfn_type),
@@ -6101,12 +5852,11 @@ build_ptrmemfunc (type, pfn, force)
        expand_ptrmemfunc_cst (pfn, &delta, &npfn);
       else
        {
-         npfn = build_component_ref (pfn, pfn_identifier, NULL_TREE, 0);
-         delta = build_component_ref (pfn, delta_identifier, NULL_TREE, 0);
+         npfn = build_ptrmemfunc_access_expr (pfn, pfn_identifier);
+         delta = build_ptrmemfunc_access_expr (pfn, delta_identifier);
        }
 
-      /* Under the new ABI, the conversion is easy.  Just adjust
-        the DELTA field.  */
+      /* Just adjust the DELTA field.  */
       delta = cp_convert (ptrdiff_type_node, delta);
       if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_delta)
        n = cp_build_binary_op (LSHIFT_EXPR, n, integer_one_node);
@@ -6124,7 +5874,7 @@ build_ptrmemfunc (type, pfn, force)
     }
 
   if (type_unknown_p (pfn))
-    return instantiate_type (type, pfn, itf_complain);
+    return instantiate_type (type, pfn, tf_error | tf_warning);
 
   fn = TREE_OPERAND (pfn, 0);
   my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 0);
@@ -6166,15 +5916,14 @@ expand_ptrmemfunc_cst (cst, delta, pfn)
       /* If we're dealing with a virtual function, we have to adjust 'this'
          again, to point to the base which provides the vtable entry for
          fn; the call will do the opposite adjustment.  */
-      tree orig_class = DECL_VIRTUAL_CONTEXT (fn);
+      tree orig_class = DECL_CONTEXT (fn);
       tree binfo = binfo_or_else (orig_class, fn_class);
       *delta = fold (build (PLUS_EXPR, TREE_TYPE (*delta),
                            *delta, BINFO_OFFSET (binfo)));
 
-      /* Under the new ABI, we set PFN to the vtable offset at
-        which the function can be found, plus one (unless
-        ptrmemfunc_vbit_in_delta, in which case delta is shifted
-        left, and then incremented).  */
+      /* We set PFN to the vtable offset at which the function can be
+        found, plus one (unless ptrmemfunc_vbit_in_delta, in which
+        case delta is shifted left, and then incremented).  */
       *pfn = DECL_VINDEX (fn);
       *pfn = fold (build (MULT_EXPR, integer_type_node, *pfn,
                          TYPE_SIZE_UNIT (vtable_entry_type)));
@@ -6219,7 +5968,7 @@ pfn_from_ptrmemfunc (t)
        return pfn;
     }
 
-  return build_component_ref (t, pfn_identifier, NULL_TREE, 0);
+  return build_ptrmemfunc_access_expr (t, pfn_identifier);
 }
 
 /* Expression EXPR is about to be implicitly converted to TYPE.  Warn
@@ -6237,14 +5986,14 @@ dubious_conversion_warnings (type, expr, errtype, fndecl, parmnum)
   if (TREE_CODE (type) == REFERENCE_TYPE)
     type = TREE_TYPE (type);
   
-  /* Issue warnings about peculiar, but legal, uses of NULL.  */
+  /* Issue warnings about peculiar, but valid, uses of NULL.  */
   if (ARITHMETIC_TYPE_P (type) && expr == null_node)
     {
       if (fndecl)
-        cp_warning ("passing NULL used for non-pointer %s %P of `%D'",
+        warning ("passing NULL used for non-pointer %s %P of `%D'",
                     errtype, parmnum, fndecl);
       else
-        cp_warning ("%s to non-pointer type `%T' from NULL", errtype, type);
+        warning ("%s to non-pointer type `%T' from NULL", errtype, type);
     }
   
   /* Warn about assigning a floating-point type to an integer type.  */
@@ -6252,10 +6001,10 @@ dubious_conversion_warnings (type, expr, errtype, fndecl, parmnum)
       && TREE_CODE (type) == INTEGER_TYPE)
     {
       if (fndecl)
-       cp_warning ("passing `%T' for %s %P of `%D'",
+       warning ("passing `%T' for %s %P of `%D'",
                    TREE_TYPE (expr), errtype, parmnum, fndecl);
       else
-       cp_warning ("%s to `%T' from `%T'", errtype, type, TREE_TYPE (expr));
+       warning ("%s to `%T' from `%T'", errtype, type, TREE_TYPE (expr));
     }
   /* And warn about assigning a negative value to an unsigned
      variable.  */
@@ -6265,10 +6014,10 @@ dubious_conversion_warnings (type, expr, errtype, fndecl, parmnum)
          && TREE_NEGATED_INT (expr))
        {
          if (fndecl)
-           cp_warning ("passing negative value `%E' for %s %P of `%D'",
+           warning ("passing negative value `%E' for %s %P of `%D'",
                        expr, errtype, parmnum, fndecl);
          else
-           cp_warning ("%s of negative value `%E' to `%T'",
+           warning ("%s of negative value `%E' to `%T'",
                        errtype, expr, type);
        }
 
@@ -6298,7 +6047,7 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
   register enum tree_code coder;
 
   if (codel == OFFSET_TYPE)
-    my_friendly_abort (990505);
+    abort ();
 
   if (TREE_CODE (rhs) == OFFSET_REF)
     rhs = resolve_offset_ref (rhs);
@@ -6327,14 +6076,26 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
   /* Simplify the RHS if possible.  */
   if (TREE_CODE (rhs) == CONST_DECL)
     rhs = DECL_INITIAL (rhs);
-  else if (coder != ARRAY_TYPE)
-    rhs = decl_constant_value (rhs);
+  
+  /* We do not use decl_constant_value here because of this case:
+
+       const char* const s = "s";
+     The conversion rules for a string literal are more lax than for a
+     variable; in particular, a string literal can be converted to a
+     "char *" but the variable "s" cannot be converted in the same
+     way.  If the conversion is allowed, the optimization should be
+     performed while creating the converted expression.  */
 
   /* [expr.ass]
 
      The expression is implicitly converted (clause _conv_) to the
-     cv-unqualified type of the left operand.  */
-  if (!can_convert_arg (type, rhstype, rhs))
+     cv-unqualified type of the left operand.
+
+     We allow bad conversions here because by the time we get to this point
+     we are committed to doing the conversion.  If we end up doing a bad
+     conversion, convert_like will complain.  */
+  if (!can_convert_arg_bad (type, rhstype, rhs))
     {
       /* When -Wno-pmf-conversions is use, we just silently allow
         conversions from pointers-to-members to plain pointers.  If
@@ -6343,18 +6104,18 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
          && TYPE_PTR_P (type) 
          && TYPE_PTRMEMFUNC_P (rhstype))
        rhs = cp_convert (strip_top_quals (type), rhs);
-      else 
+      else
        {
          /* If the right-hand side has unknown type, then it is an
             overloaded function.  Call instantiate_type to get error
             messages.  */
          if (rhstype == unknown_type_node)
-           instantiate_type (type, rhs, itf_complain);
+           instantiate_type (type, rhs, tf_error | tf_warning);
          else if (fndecl)
-           cp_error ("cannot convert `%T' to `%T' for argument `%P' to `%D'",
+           error ("cannot convert `%T' to `%T' for argument `%P' to `%D'",
                      rhstype, type, parmnum, fndecl);
          else
-           cp_error ("cannot convert `%T' to `%T' in %s", rhstype, type, 
+           error ("cannot convert `%T' to `%T' in %s", rhstype, type, 
                      errtype);
          return error_mark_node;
        }
@@ -6363,7 +6124,7 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
 }
 
 /* Convert RHS to be of type TYPE.
-   If EXP is non-zero, it is the target of the initialization.
+   If EXP is nonzero, it is the target of the initialization.
    ERRTYPE is a string to use in error messages.
 
    Two major differences between the behavior of
@@ -6437,7 +6198,7 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
 
       if (fndecl)
        savew = warningcount, savee = errorcount;
-      rhs = initialize_reference (type, rhs);
+      rhs = initialize_reference (type, rhs, /*decl=*/NULL_TREE);
       if (fndecl)
        {
          if (warningcount > savew)
@@ -6513,9 +6274,9 @@ c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
       else
        {
          tree type = TREE_TYPE (o[i]);
-         if (CP_TYPE_CONST_P (type)
-             || (IS_AGGR_TYPE_CODE (TREE_CODE (type))
-                 && C_TYPE_FIELDS_READONLY (type)))
+         if (type != error_mark_node
+             && (CP_TYPE_CONST_P (type)
+                 || (CLASS_TYPE_P (type) && C_TYPE_FIELDS_READONLY (type))))
            readonly_error (o[i], "modification by `asm'", 1);
        }
     }
@@ -6585,7 +6346,7 @@ maybe_warn_about_returning_address_of_local (retval)
     }
 }
 
-/* Check that returning RETVAL from the current function is legal.
+/* Check that returning RETVAL from the current function is valid.
    Return an expression explicitly showing all conversions required to
    change RETVAL into the function return type, and to assign it to
    the DECL_RESULT for the function.  */
@@ -6607,7 +6368,7 @@ check_return_expr (retval)
     warning ("function declared `noreturn' has a `return' statement");
 
   /* Check for various simple errors.  */
-  if (dtor_label)
+  if (DECL_DESTRUCTOR_P (current_function_decl))
     {
       if (retval)
        error ("returning a value from a destructor");
@@ -6617,7 +6378,7 @@ check_return_expr (retval)
     {
       if (in_function_try_handler)
        /* If a return statement appears in a handler of the
-          function-try-block of a constructor, the program is ill-formed. */
+          function-try-block of a constructor, the program is ill-formed.  */
        error ("cannot return from a handler of a function-try-block of a constructor");
       else if (retval)
        /* You can't return a value from a constructor.  */
@@ -6625,6 +6386,12 @@ check_return_expr (retval)
       return NULL_TREE;
     }
 
+  if (processing_template_decl)
+    {
+      current_function_returns_value = 1;
+      return retval;
+    }
+  
   /* When no explicit return-value is given in a function with a named
      return value, the named return value is used.  */
   result = DECL_RESULT (current_function_decl);
@@ -6675,23 +6442,33 @@ check_return_expr (retval)
       && !TYPE_NOTHROW_P (TREE_TYPE (current_function_decl))
       && ! flag_check_new
       && null_ptr_cst_p (retval))
-    cp_warning ("`operator new' must not return NULL unless it is declared `throw()' (or -fcheck-new is in effect)");
+    warning ("`operator new' must not return NULL unless it is declared `throw()' (or -fcheck-new is in effect)");
 
   /* Effective C++ rule 15.  See also start_function.  */
   if (warn_ecpp
       && DECL_NAME (current_function_decl) == ansi_assopname(NOP_EXPR)
       && retval != current_class_ref)
-    cp_warning ("`operator=' should return a reference to `*this'");
+    warning ("`operator=' should return a reference to `*this'");
+
+  /* The fabled Named Return Value optimization, as per [class.copy]/15:
+
+     [...]      For  a function with a class return type, if the expression
+     in the return statement is the name of a local  object,  and  the  cv-
+     unqualified  type  of  the  local  object  is the same as the function
+     return type, an implementation is permitted to omit creating the  tem-
+     porary  object  to  hold  the function return value [...]
 
-  /* The fabled Named Return Value optimization: If this is a
-     value-returning function that always returns the same local
-     variable, remember it.
+     So, if this is a value-returning function that always returns the same
+     local variable, remember it.
 
      It might be nice to be more flexible, and choose the first suitable
      variable even if the function sometimes returns something else, but
      then we run the risk of clobbering the variable we chose if the other
      returned expression uses the chosen variable somehow.  And people expect
-     this restriction, anyway.  (jason 2000-11-19) */
+     this restriction, anyway.  (jason 2000-11-19)
+
+     See finish_function, genrtl_start_function, and declare_return_variable
+     for other pieces of this optimization.  */
 
   if (fn_returns_value_p && flag_elide_constructors)
     {
@@ -6702,9 +6479,11 @@ check_return_expr (retval)
          && DECL_CONTEXT (retval) == current_function_decl
          && ! TREE_STATIC (retval)
          && (DECL_ALIGN (retval)
-             == DECL_ALIGN (DECL_RESULT (current_function_decl)))
-         && same_type_p (TREE_TYPE (retval),
-                         TREE_TYPE (TREE_TYPE (current_function_decl))))
+             >= DECL_ALIGN (DECL_RESULT (current_function_decl)))
+         && same_type_p ((TYPE_MAIN_VARIANT
+                          (TREE_TYPE (retval))),
+                         (TYPE_MAIN_VARIANT
+                          (TREE_TYPE (TREE_TYPE (current_function_decl))))))
        current_function_return_value = retval;
       else
        current_function_return_value = error_mark_node;
@@ -6726,7 +6505,7 @@ check_return_expr (retval)
 
       /* First convert the value to the function's return type, then
         to the type of return value's location to handle the
-         case that functype is smaller than the valtype. */
+         case that functype is smaller than the valtype.  */
       retval = convert_for_initialization
        (NULL_TREE, functype, retval, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
         "return", NULL_TREE, 0);
@@ -6753,9 +6532,9 @@ check_return_expr (retval)
 }
 
 \f
-/* Returns non-zero if the pointer-type FROM can be converted to the
+/* Returns nonzero if the pointer-type FROM can be converted to the
    pointer-type TO via a qualification conversion.  If CONSTP is -1,
-   then we return non-zero if the pointers are similar, and the
+   then we return nonzero if the pointers are similar, and the
    cv-qualification signature of FROM is a proper subset of that of TO.
 
    If CONSTP is positive, then all outer pointers have been
@@ -6824,6 +6603,11 @@ ptr_reasonably_similar (to, from)
 {
   for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
     {
+      /* Any target type is similar enough to void.  */
+      if (TREE_CODE (to) == VOID_TYPE
+         || TREE_CODE (from) == VOID_TYPE)
+       return 1;
+
       if (TREE_CODE (to) != TREE_CODE (from))
        return 0;
 
@@ -6833,6 +6617,13 @@ ptr_reasonably_similar (to, from)
                        COMPARE_BASE | COMPARE_RELAXED))
        continue;
 
+      if (TREE_CODE (to) == INTEGER_TYPE
+         && TYPE_PRECISION (to) == TYPE_PRECISION (from))
+       return 1;
+
+      if (TREE_CODE (to) == FUNCTION_TYPE)
+       return 1;
+
       if (TREE_CODE (to) != POINTER_TYPE)
        return comptypes
          (TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from), 
@@ -6896,17 +6687,20 @@ comp_ptr_ttypes_reinterpret (to, from)
     }
 }
 
-/* Returns the type-qualifier set corresponding to TYPE.  */
+/* Returns the type qualifiers for this type, including the qualifiers on the
+   elements for an array type.  */
 
 int
 cp_type_quals (type)
      tree type;
 {
   type = strip_array_types (type);
+  if (type == error_mark_node)
+    return TYPE_UNQUALIFIED;
   return TYPE_QUALS (type);
 }
 
-/* Returns non-zero if the TYPE contains a mutable member */
+/* Returns nonzero if the TYPE contains a mutable member */
 
 int
 cp_has_mutable_p (type)
@@ -6962,14 +6756,14 @@ casts_away_constness_r (t1, t2)
       || TREE_CODE (*t2) != POINTER_TYPE)
     {
       *t1 = cp_build_qualified_type (void_type_node,
-                                    CP_TYPE_QUALS (*t1));
+                                    cp_type_quals (*t1));
       *t2 = cp_build_qualified_type (void_type_node,
-                                    CP_TYPE_QUALS (*t2));
+                                    cp_type_quals (*t2));
       return;
     }
   
-  quals1 = CP_TYPE_QUALS (*t1);
-  quals2 = CP_TYPE_QUALS (*t2);
+  quals1 = cp_type_quals (*t1);
+  quals2 = cp_type_quals (*t2);
   *t1 = TREE_TYPE (*t1);
   *t2 = TREE_TYPE (*t2);
   casts_away_constness_r (t1, t2);
@@ -6979,7 +6773,7 @@ casts_away_constness_r (t1, t2)
   *t2 = cp_build_qualified_type (*t2, quals2);
 }
 
-/* Returns non-zero if casting from TYPE1 to TYPE2 casts away
+/* Returns nonzero if casting from TYPE1 to TYPE2 casts away
    constness.  */
 
 static int
@@ -7007,7 +6801,7 @@ casts_away_constness (t1, t2)
        Casting from an rvalue of type "pointer to data member of X
        of type T1" to the type "pointer to data member of Y of type
        T2" casts away constness if a cast from an rvalue of type
-       "poitner to T1" to the type "pointer to T2" casts away
+       "pointer to T1" to the type "pointer to T2" casts away
        constness.  */
     return casts_away_constness
       (build_pointer_type (TREE_TYPE (TREE_TYPE (t1))),