OSDN Git Service

* g++.old-deja/g++.benjamin/16077.C: Adjust warnings.
[pf3gnuchains/gcc-fork.git] / gcc / cp / typeck.c
index 7ccbee9..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, 2002 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"
@@ -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.  */
@@ -156,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)
@@ -171,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
@@ -202,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));
       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;
@@ -485,7 +494,7 @@ 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))
@@ -592,12 +601,14 @@ merge_types (t1, t2)
       /* For two pointers, do this recursively on the target type.  */
       {
        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);
@@ -792,11 +803,11 @@ 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 */
     return !exact;
@@ -854,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[];
@@ -894,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 */
@@ -935,6 +946,13 @@ 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;
@@ -1482,73 +1500,44 @@ 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_nt (SIZEOF_EXPR, 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 (pedantic || warn_pointer_arith)
-       pedwarn ("ISO C++ forbids applying `sizeof' to a function type");
-      size = size_one_node;
-    }
-  else if (code == METHOD_TYPE)
+  if (type_code == METHOD_TYPE)
     {
-      if (pedantic || warn_pointer_arith)
-       pedwarn ("ISO C++ forbids applying `sizeof' to a member function");
-      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 == VOID_TYPE)
+  else if (type_code == OFFSET_TYPE)
     {
-      if (pedantic || warn_pointer_arith)
-       pedwarn ("ISO C++ forbids applying `sizeof' to type `void' which is an incomplete type");
-      size = size_one_node;
+      if (complain)
+       error ("invalid application of `%s' to non-static member", op_name);
+      value = size_zero_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)
-       {
-         error ("`sizeof' applied to non-static member");
-         size = size_zero_node;
-       }
-      else if (!COMPLETE_TYPE_P (complete_type (type)))
-       {
-         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;
@@ -1566,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)
@@ -1578,44 +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;
-}
 \f
 /* Perform the array-to-pointer and function-to-pointer conversions
    for EXP.  
@@ -1648,7 +1602,7 @@ decay_conversion (exp)
 
   if (type_unknown_p (exp))
     {
-      incomplete_type_error (exp, TREE_TYPE (exp));
+      cxx_incomplete_type_error (exp, TREE_TYPE (exp));
       return error_mark_node;
     }
   
@@ -1818,45 +1772,6 @@ string_conv_p (totype, exp, warn)
 
   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)))
-    {
-      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 = NULL_TREE;
-      datum = build_scoped_ref (datum, basetype, &binfo);
-      return build_x_component_ref (datum, 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
@@ -1906,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.  */
@@ -1928,342 +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 old_datum;
-  tree old_basetype;
+  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:
-      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 */
-      abort ();
-#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)
-       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)
     {
-      if (TYPE_IDENTIFIER (basetype) != TREE_OPERAND (component, 0))
+      /* 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)
+    {
+      /* 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))
        {
-         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))
        {
-         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)
     {
-      error ("invalid use of type decl `%#D' as expression", component);
+      /* 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
+    {
+      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))
     {
-      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) == TEMPLATE_ID_EXPR)
-       name = TREE_OPERAND (component, 0);
-      else 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;
-
-      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).  */
-             
-             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);
-                   }
-               }
+      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);
+}
 
-             fndecls = TREE_VALUE (fndecls);
-             
-             if (IDENTIFIER_TYPENAME_P (name))
-               {
-                 /* We want for a conversion op. We need to remember
-                    the actual type we wanted, in case we got a set of
-                    templated conversion operators back.  */
-                 fndecls = ovl_cons (OVL_CURRENT (fndecls),
-                                     OVL_NEXT (fndecls));
-                 TREE_TYPE (fndecls) = TREE_TYPE (name);
-               }
-             else if (TREE_CODE (component) == TEMPLATE_ID_EXPR)
-               fndecls = build_nt (TEMPLATE_ID_EXPR,
-                                   fndecls, TREE_OPERAND (component, 1));
-             
-             ref = build (COMPONENT_REF, unknown_type_node,
-                          datum, fndecls);
-             return 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.  */
 
-         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;
+tree
+finish_class_member_access_expr (tree object, tree name)
+{
+  tree object_type;
+  tree member;
+  tree access_path = NULL_TREE;
 
-      if (TREE_CODE (field) != FIELD_DECL)
-       {
-         if (TREE_CODE (field) == TYPE_DECL)
-           pedwarn ("invalid use of type decl `%#D' as expression", field);
-         else if (DECL_RTL (field) != 0)
-           mark_used (field);
-         else
-           TREE_USED (field) = 1;
+  if (object == error_mark_node || name == error_mark_node)
+    return error_mark_node;
 
-         /* Do evaluate the object when accessing a static member.  */
-         if (TREE_SIDE_EFFECTS (datum))
-           field = build (COMPOUND_EXPR, TREE_TYPE (field), datum, field);
+  if (processing_template_decl)
+    return build_min_nt (COMPONENT_REF, object, name);
+  
+  if (TREE_CODE (object) == OFFSET_REF)
+    object = resolve_offset_ref (object);
 
-         return field;
-       }
+  object_type = TREE_TYPE (object);
+  if (TREE_CODE (object_type) == REFERENCE_TYPE)
+    {
+      object = convert_from_reference (object);
+      object_type = TREE_TYPE (object);
     }
 
-  if (TREE_DEPRECATED (field))
-    warn_deprecated_use (field);
+  /* [expr.ref]
 
-  old_datum = datum;
-  old_basetype = basetype;
+     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)
        {
-         base_kind kind;
-         tree binfo = lookup_base (TREE_TYPE (datum), base, ba_check, &kind);
+         is_template_id = true;
+         template_args = TREE_OPERAND (name, 1);
+         name = TREE_OPERAND (name, 0);
+       }
 
-         /* Complain about use of offsetof which will break.  */
-         if (TREE_CODE (datum) == INDIRECT_REF
-             && integer_zerop (TREE_OPERAND (datum, 0))
-             && kind == bk_via_virtual)
+      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 offsetof from non-POD type `%#T'; use pointer to member instead",
-                    basetype);
+             error ("`%D::%D' is not a member of `%T'", 
+                    scope, name, object_type);
              return error_mark_node;
            }
-         datum = build_base_path (PLUS_EXPR, datum, binfo, 1);
-         if (datum == error_mark_node)
+
+         /* 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
+           {
+             /* 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;
+           }
        }
-      basetype = base;
-      /* Handle things from anon unions here...  */
-      if (TYPE_NAME (context) && ANON_AGGR_TYPE_P (context))
+      else if (TREE_CODE (name) == BIT_NOT_EXPR)
+       member = lookup_destructor (object, /*scope=*/NULL_TREE, name);
+      else if (TREE_CODE (name) == IDENTIFIER_NODE)
        {
-         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);
+         /* 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;
+       }
+      else
+       {
+         /* 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;
+           }
        }
     }
 
-  /* 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 (protect
-      && CLASSTYPE_NON_POD_P (old_basetype)
-      && TREE_CODE (old_datum) == INDIRECT_REF
-      && integer_zerop (TREE_OPERAND (old_datum, 0)))
-    warning ("\
-invalid offsetof from non-POD type `%#T'; use pointer to member instead",
-            basetype);
-
-  /* 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.
@@ -2281,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);
@@ -2325,8 +2352,7 @@ build_indirect_ref (ptr, errorstring)
           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);
@@ -2340,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;
        }
     }
@@ -2515,311 +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)
-           {
-             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);
-
-      if (TREE_CODE (function) == OVERLOAD
-         && TREE_TYPE (function) != unknown_type_node)
-       /* It was a conversion operator. We can't use DECL_NAME, as
-          that might refer to a templated function.  */
-       function = mangle_conv_op_name_for_type (TREE_TYPE (function));
-      else if (TREE_CODE (function) == TEMPLATE_ID_EXPR)
-       {
-         my_friendly_assert (!template_id, 20011228);
-
-         template_id = function;
-       }
-      else
-       {
-         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)
-       {
-         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
-       abort ();
-      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)))
-       {
-         tree binfo = lookup_base (TREE_TYPE (decl), TREE_TYPE (ctypeptr),
-                                   ba_check, NULL);
-         
-         decl = build_unary_op (ADDR_EXPR, decl, 0);
-         decl = build_base_path (PLUS_EXPR, decl, binfo, 1);
-       }
-      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)
@@ -2831,92 +2560,79 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
 
   if (TYPE_PTRMEMFUNC_P (TREE_TYPE (function)))
     {
-      tree fntype, idx, e1, delta, delta2, e2, e3, 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 = lookup_base (TREE_TYPE (TREE_TYPE (instance_ptr)), basetype,
-                             ba_check, NULL);
-      instance = build_base_path (PLUS_EXPR, instance_ptr, instance, 1);
-      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 = build1 (NOP_EXPR, build_pointer_type (ptr_type_node), instance);
-      TREE_CONSTANT (vtbl) = TREE_CONSTANT (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.  */
-      idx = cp_build_binary_op (TRUNC_DIV_EXPR, 
-                               build1 (NOP_EXPR, vtable_index_type, e3),
-                               TYPE_SIZE_UNIT (vtable_entry_type));
+      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:
-         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:
-         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);
-      e2 = build_array_ref (vtbl, idx);
+
+      /* 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.  */
@@ -2929,17 +2645,9 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
       
       /* 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)
-       error ("object missing in `%E'", function);
+                   instance_save_expr, e1);
 
       function = e1;
     }
@@ -2947,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;
@@ -3023,20 +2730,10 @@ build_function_call_real (function, params, require_complete, flags)
   /* 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);
-
+  coerced_params = convert_arguments (TYPE_ARG_TYPES (fntype),
+                                     params, fndecl, LOOKUP_NORMAL);
   if (coerced_params == error_mark_node)
-    {
-      if (flags & LOOKUP_SPECULATIVELY)
-       return NULL_TREE;
-      else
-       return error_mark_node;
-    }
+    return error_mark_node;
 
   /* Check for errors in format strings.  */
 
@@ -3062,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.
@@ -3187,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)
@@ -3223,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)
            {
@@ -3273,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:
@@ -3601,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);
        }
@@ -3635,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,
@@ -3977,7 +3838,7 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
       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)
@@ -4098,50 +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))
-    {
-      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.  */
-      tree binfo = lookup_base (TREE_TYPE (TREE_TYPE (rval)), basetype,
-                               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));
-    }
-  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.  */
@@ -4176,6 +3993,25 @@ 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);
@@ -4232,7 +4068,45 @@ condition_conversion (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
@@ -4264,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
        {
@@ -4276,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);
@@ -4290,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);
@@ -4305,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);
@@ -4365,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";
@@ -4419,7 +4293,7 @@ build_unary_op (code, xarg, noconvert)
                          ((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;
@@ -4554,7 +4428,7 @@ build_unary_op (code, xarg, noconvert)
        }
 
       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),
@@ -4567,14 +4441,14 @@ 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.  */
-               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
                pedwarn ("ISO C++ forbids taking the address of a bound member function to form a pointer to member function.  Say `&%T::%D'", base, name);
            }
@@ -4616,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 (!cxx_mark_addressable (arg))
-       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)
@@ -4769,9 +4662,7 @@ unary_complex_lvalue (code, arg)
              return error_mark_node;
            }
 
-         type = build_offset_type (DECL_FIELD_CONTEXT (t), TREE_TYPE (t));
-         type = build_pointer_type (type);
-
+         type = build_ptrmem_type (DECL_FIELD_CONTEXT (t), TREE_TYPE (t));
          t = make_ptrmem_cst (type, TREE_OPERAND (arg, 1));
          return t;
        }
@@ -4816,9 +4707,6 @@ cxx_mark_addressable (exp)
 {
   register tree x = exp;
 
-  if (TREE_ADDRESSABLE (x) == 1)
-    return true;
-
   while (1)
     switch (TREE_CODE (x))
       {
@@ -4837,6 +4725,8 @@ cxx_mark_addressable (exp)
            TREE_ADDRESSABLE (x) = 1; /* so compiler doesn't die later */
            return true;
          }
+       /* FALLTHRU */
+
       case VAR_DECL:
        /* Caller should not be trying to mark initialized
           constant fields addressable.  */
@@ -4844,6 +4734,7 @@ cxx_mark_addressable (exp)
                            || DECL_IN_AGGR_P (x) == 0
                            || TREE_STATIC (x)
                            || DECL_EXTERNAL (x), 314);
+       /* FALLTHRU */
 
       case CONST_DECL:
       case RESULT_DECL:
@@ -4852,6 +4743,7 @@ cxx_mark_addressable (exp)
          warning ("address requested for `%D', which is declared `register'",
                      x);
        TREE_ADDRESSABLE (x) = 1;
+       put_var_into_stack (x);
        return true;
 
       case FUNCTION_DECL:
@@ -4901,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).  */
@@ -5006,7 +4898,7 @@ 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)));
@@ -5020,12 +4912,12 @@ 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. */
+         are related non-virtually.  */
       base_kind kind;
       
       if (IS_AGGR_TYPE (TREE_TYPE (type)) && IS_AGGR_TYPE (TREE_TYPE (intype))
@@ -5038,7 +4930,7 @@ build_static_cast (type, expr)
     {
       /* 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. */
+        must be related non-virtually.  */
       base_kind kind;
       
       if (same_type_p
@@ -5458,8 +5350,9 @@ build_modify_expr (lhs, modifycode, 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 = save_expr (rhs);
+       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.  */
@@ -5479,10 +5372,7 @@ 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),
-                     /* Cast 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:
@@ -5509,9 +5399,10 @@ 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;
@@ -5535,8 +5426,8 @@ build_modify_expr (lhs, modifycode, rhs)
            /* Do the default thing */;
          else
            {
-             result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
-                                      lhs, rhs, make_node (NOP_EXPR));
+             result = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL,
+                                    lhs, rhs, make_node (NOP_EXPR));
              if (result == NULL_TREE)
                return error_mark_node;
              return result;
@@ -5627,7 +5518,7 @@ build_modify_expr (lhs, modifycode, rhs)
          || TREE_CODE (TREE_TYPE (lhs)) == METHOD_TYPE
          /* If it's an aggregate and any field is const, then it is
             effectively const.  */
-         || (IS_AGGR_TYPE_CODE (TREE_CODE (lhstype))
+         || (CLASS_TYPE_P (lhstype)
              && C_TYPE_FIELDS_READONLY (lhstype))))
     readonly_error (lhs, "assignment", 0);
 
@@ -5666,20 +5557,21 @@ build_modify_expr (lhs, modifycode, rhs)
     {
       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))))
        {
          error ("incompatible types in assignment of `%T' to `%T'",
-                   TREE_TYPE (rhs), lhstype);
+                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)
@@ -5787,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;
     }
@@ -5836,10 +5728,9 @@ get_delta_difference (from, to, force)
       
       if (virt_binfo)
         {
-          /* This is a reinterpret cast, we choose to do nothing. */
-          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);
@@ -5854,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)
-        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
-       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);
@@ -5906,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.
 
@@ -5918,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;
@@ -5957,8 +5852,8 @@ 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);
        }
 
       /* Just adjust the DELTA field.  */
@@ -6021,7 +5916,7 @@ 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)));
@@ -6073,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
@@ -6091,7 +5986,7 @@ 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)
@@ -6181,8 +6076,16 @@ 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]
 
@@ -6221,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
@@ -6295,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)
@@ -6371,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);
        }
     }
@@ -6443,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.  */
@@ -6475,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.  */
@@ -6483,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);
@@ -6596,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);
@@ -6623,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
@@ -6786,10 +6695,12 @@ 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)
@@ -6862,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