OSDN Git Service

(handle_braces): Rework last change.
[pf3gnuchains/gcc-fork.git] / gcc / cp / typeck.c
index c3fdb79..60c8f00 100644 (file)
@@ -1,5 +1,5 @@
 /* Build expressions with type checking for C++ compiler.
-   Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
@@ -40,15 +40,17 @@ extern void warning ();
 #include "flags.h"
 #include "output.h"
 
-int mark_addressable ();
-static tree convert_for_assignment ();
-/* static */ tree convert_for_initialization ();
+int mark_addressable PROTO((tree));
+static tree convert_for_assignment PROTO((tree, tree, char*, tree, int));
+/* static */ tree convert_for_initialization PROTO((tree, tree, tree, int, char*, tree, int));
 extern tree shorten_compare ();
 extern void binary_op_error ();
-static tree pointer_int_sum ();
-static tree pointer_diff ();
+static tree pointer_int_sum PROTO((enum tree_code, register tree, register tree));
+static tree pointer_diff PROTO((register tree, register tree));
+#if 0
 static tree convert_sequence ();
-/* static */ tree unary_complex_lvalue ();
+#endif
+/* static */ tree unary_complex_lvalue PROTO((enum tree_code, tree));
 static tree get_delta_difference PROTO((tree, tree, int));
 
 extern rtx original_result_rtx;
@@ -81,7 +83,7 @@ require_complete_type (value)
 {
   tree type;
 
-  if (current_template_parms)
+  if (processing_template_decl)
     return value;
 
   type = TREE_TYPE (value);
@@ -98,13 +100,13 @@ require_complete_type (value)
      not been laid out.  Try to avoid an error by interpreting
      it as this->X::Y, if reasonable.  */
   if (TREE_CODE (value) == OFFSET_REF
-      && C_C_D != 0
-      && TREE_OPERAND (value, 0) == C_C_D)
+      && current_class_ref != 0
+      && TREE_OPERAND (value, 0) == current_class_ref)
     {
       tree base, member = TREE_OPERAND (value, 1);
       tree basetype = TYPE_OFFSET_BASETYPE (type);
       my_friendly_assert (TREE_CODE (member) == FIELD_DECL, 305);
-      base = convert_pointer_to (basetype, current_class_decl);
+      base = convert_pointer_to (basetype, current_class_ptr);
       value = build (COMPONENT_REF, TREE_TYPE (member),
                     build_indirect_ref (base, NULL_PTR), member);
       return require_complete_type (value);
@@ -112,7 +114,7 @@ require_complete_type (value)
 
   if (IS_AGGR_TYPE (type) && CLASSTYPE_TEMPLATE_INSTANTIATION (type))
     {
-      instantiate_class_template (type);
+      instantiate_class_template (TYPE_MAIN_VARIANT (type));
       if (TYPE_SIZE (type) != 0)
        return value;
     }
@@ -125,13 +127,17 @@ tree
 complete_type (type)
      tree type;
 {
-  if (TYPE_SIZE (type) != NULL_TREE)
+  if (type == error_mark_node || TYPE_SIZE (type) != NULL_TREE)
     ;
-  else if (TREE_CODE (type) == ARRAY_TYPE)
+  else if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
     {
       tree t = complete_type (TREE_TYPE (type));
-      if (TYPE_SIZE (t) != NULL_TREE)
-       type = build_cplus_array_type (t, TYPE_DOMAIN (type));
+      if (TYPE_SIZE (t) != NULL_TREE && ! processing_template_decl)
+       layout_type (type);
+      TYPE_NEEDS_CONSTRUCTING (type)
+       = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (t));
+      TYPE_NEEDS_DESTRUCTOR (type)
+       = TYPE_NEEDS_DESTRUCTOR (TYPE_MAIN_VARIANT (t));
     }
   else if (IS_AGGR_TYPE (type) && CLASSTYPE_TEMPLATE_INSTANTIATION (type))
     instantiate_class_template (TYPE_MAIN_VARIANT (type));
@@ -140,6 +146,7 @@ complete_type (type)
 }
 
 /* Return truthvalue of whether type of EXP is instantiated.  */
+
 int
 type_unknown_p (exp)
      tree exp;
@@ -151,6 +158,7 @@ type_unknown_p (exp)
 }
 
 /* Return truthvalue of whether T is function (or pfn) type.  */
+
 int
 fntype_p (t)
      tree t;
@@ -164,6 +172,7 @@ fntype_p (t)
 /* Do `exp = require_instantiated_type (type, exp);' to make sure EXP
    does not have an uninstantiated type.
    TYPE is type to instantiate with, if uninstantiated.  */
+
 tree
 require_instantiated_type (type, exp, errval)
      tree type, exp, errval;
@@ -442,7 +451,8 @@ common_type (t1, t2)
        if (elt == TREE_TYPE (t2) && TYPE_DOMAIN (t2))
          return build_type_attribute_variant (t2, attributes);
        /* Merge the element types, and have a size if either arg has one.  */
-       t1 = build_cplus_array_type (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2));
+       t1 = build_cplus_array_type
+         (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2));
        return build_type_attribute_variant (t1, attributes);
       }
 
@@ -538,7 +548,8 @@ common_type (t1, t2)
          tree b1 = TYPE_OFFSET_BASETYPE (t1);
          tree b2 = TYPE_OFFSET_BASETYPE (t2);
 
-         if (DERIVED_FROM_P (b1, b2) && binfo_or_else (b1, b2))
+         if (comptypes (b1, b2, 1)
+             || (DERIVED_FROM_P (b1, b2) && binfo_or_else (b1, b2)))
            return build_type_attribute_variant (t2, attributes);
          else if (binfo_or_else (b2, b1))
            return build_type_attribute_variant (t1, attributes);
@@ -551,6 +562,7 @@ common_type (t1, t2)
 }
 \f
 /* Return 1 if TYPE1 and TYPE2 raise the same exceptions.  */
+
 int
 compexcepttypes (t1, t2)
      tree t1, t2;
@@ -613,6 +625,7 @@ comp_array_types (cmp, t1, t2, strict)
    pointer to a base classes. These allowances do not commute. In this
    case, TYPE1 is assumed to be the base class, and TYPE2 is assumed to
    be the derived class.  */
+
 int
 comptypes (type1, type2, strict)
      tree type1, type2;
@@ -761,7 +774,7 @@ comptypes (type1, type2, strict)
            {
              int rval;
            look_hard:
-             rval = t1 == t2 || UNIQUELY_DERIVED_FROM_P (t1, t2);
+             rval = t1 == t2 || DERIVED_FROM_P (t1, t2);
 
              if (rval)
                {
@@ -770,7 +783,7 @@ comptypes (type1, type2, strict)
                }
              if (strict < 0)
                {
-                 val = UNIQUELY_DERIVED_FROM_P (t2, t1);
+                 val = DERIVED_FROM_P (t2, t1);
                  break;
                }
            }
@@ -928,6 +941,7 @@ comp_target_types (ttl, ttr, nptrs)
 /* If two types share a common base type, return that basetype.
    If there is not a unique most-derived base type, this function
    returns ERROR_MARK_NODE.  */
+
 tree
 common_base_type (tt1, tt2)
      tree tt1, tt2;
@@ -987,6 +1001,7 @@ common_base_type (tt1, tt2)
    C++: See comment above about TYPE1, TYPE2, STRICT.
    If STRICT == 3, it means checking is strict, but do not compare
    default parameter values.  */
+
 int
 compparms (parms1, parms2, strict)
      tree parms1, parms2;
@@ -1033,6 +1048,7 @@ compparms (parms1, parms2, strict)
 
 /* This really wants return whether or not parameter type lists
    would make their owning functions assignment compatible or not.  */
+
 int
 comp_target_parms (parms1, parms2, strict)
      tree parms1, parms2;
@@ -1194,7 +1210,8 @@ unsigned_type (type)
     return unsigned_intHI_type_node;
   if (type1 == intQI_type_node)
     return unsigned_intQI_type_node;
-  return type;
+
+  return signed_or_unsigned_type (1, type);
 }
 
 /* Return a signed type the same as TYPE in other respects.  */
@@ -1222,7 +1239,8 @@ signed_type (type)
     return intHI_type_node;
   if (type1 == unsigned_intQI_type_node)
     return intQI_type_node;
-  return type;
+
+  return signed_or_unsigned_type (0, type);
 }
 
 /* Return a type the same as TYPE except unsigned or
@@ -1233,8 +1251,10 @@ signed_or_unsigned_type (unsignedp, type)
      int unsignedp;
      tree type;
 {
-  if (! INTEGRAL_TYPE_P (type))
+  if (! INTEGRAL_TYPE_P (type)
+      || TREE_UNSIGNED (type) == unsignedp)
     return type;
+
   if (TYPE_PRECISION (type) == TYPE_PRECISION (signed_char_type_node))
     return unsignedp ? unsigned_char_type_node : signed_char_type_node;
   if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)) 
@@ -1258,7 +1278,7 @@ c_sizeof (type)
   enum tree_code code = TREE_CODE (type);
   tree t;
 
-  if (current_template_parms)
+  if (processing_template_decl)
     return build_min (SIZEOF_EXPR, sizetype, type);
 
   if (code == FUNCTION_TYPE)
@@ -1324,7 +1344,7 @@ tree
 expr_sizeof (e)
      tree e;
 {
-  if (current_template_parms)
+  if (processing_template_decl)
     return build_min (SIZEOF_EXPR, sizetype, e);
 
   if (TREE_CODE (e) == COMPONENT_REF
@@ -1422,13 +1442,19 @@ decay_conversion (exp)
   register tree type = TREE_TYPE (exp);
   register enum tree_code code = TREE_CODE (type);
 
-  if (code == OFFSET_TYPE /* || TREE_CODE (exp) == OFFSET_REF */ )
+  if (code == OFFSET_TYPE)
     {
       if (TREE_CODE (exp) == OFFSET_REF)
        return decay_conversion (resolve_offset_ref (exp));
 
       type = TREE_TYPE (type);
       code = TREE_CODE (type);
+
+      if (type == unknown_type_node)
+       {
+         cp_pedwarn ("assuming & on overloaded member function");
+         return build_unary_op (ADDR_EXPR, exp, 0);
+       }
     }
 
   if (code == REFERENCE_TYPE)
@@ -1462,14 +1488,7 @@ decay_conversion (exp)
     }
   if (code == METHOD_TYPE)
     {
-      if (TREE_CODE (exp) == OFFSET_REF)
-       {
-         /* FIXME: We should emit an error here about using a ptrmemfunc
-            for something other than a function call.  */
-         my_friendly_assert (TREE_CODE (TREE_OPERAND (exp, 1)) == FUNCTION_DECL,
-                             308);
-         return build_unary_op (ADDR_EXPR, TREE_OPERAND (exp, 1), 0);
-       }
+      cp_pedwarn ("assuming & on `%E'", exp);
       return build_unary_op (ADDR_EXPR, exp, 0);
     }
   if (code == ARRAY_TYPE)
@@ -1564,12 +1583,25 @@ default_conversion (exp)
       if (t != type)
        return convert (t, exp);
     }
-  if (flag_traditional
-      && TYPE_MAIN_VARIANT (type) == float_type_node)
-    return convert (double_type_node, exp);
 
   return exp;
 }
+
+/* Take the address of an inline function without setting TREE_ADDRESSABLE
+   or TREE_USED.  */
+
+tree
+inline_conversion (exp)
+     tree exp;
+{
+  if (TREE_CODE (exp) == FUNCTION_DECL)
+    {
+      tree type = build_type_variant
+       (TREE_TYPE (exp), TREE_READONLY (exp), TREE_THIS_VOLATILE (exp));
+      exp = build1 (ADDR_EXPR, build_pointer_type (type), exp);
+    }
+  return exp;
+}
 \f
 tree
 build_object_ref (datum, basetype, field)
@@ -1597,78 +1629,21 @@ build_object_ref (datum, basetype, field)
     {
       tree binfo = binfo_or_else (basetype, dtype);
       if (binfo)
-       return build_component_ref (build_scoped_ref (datum, basetype),
-                                   field, binfo, 1);
+       return build_x_component_ref (build_scoped_ref (datum, basetype),
+                                     field, binfo, 1);
     }
   return error_mark_node;
 }
 
 /* Like `build_component_ref, but uses an already found field.
-   Must compute access for C_C_D.  Otherwise, ok.  */
+   Must compute access for current_class_ref.  Otherwise, ok.  */
+
 tree
 build_component_ref_1 (datum, field, protect)
      tree datum, field;
      int protect;
 {
-  register tree basetype = TREE_TYPE (datum);
-  register enum tree_code code = TREE_CODE (basetype);
-  register tree ref;
-
-  if (code == REFERENCE_TYPE)
-    {
-      datum = convert_from_reference (datum);
-      basetype = TREE_TYPE (datum);
-      code = TREE_CODE (basetype);
-    }
-
-  if (! IS_AGGR_TYPE_CODE (code))
-    {
-      if (code != ERROR_MARK)
-       cp_error ("request for member `%D' in `%E', which is of non-aggregate type `%T'",
-                 field, datum, basetype);
-      return error_mark_node;
-    }
-
-  if (TYPE_SIZE (basetype) == 0)
-    {
-      incomplete_type_error (0, basetype);
-      return error_mark_node;
-    }
-
-  /* Look up component name in the structure type definition.  */
-
-  if (field == error_mark_node)
-    my_friendly_abort (115);
-
-  if (TREE_STATIC (field))
-    return field;
-
-  if (datum == C_C_D)
-    {
-      tree access = compute_access (TYPE_BINFO (current_class_type), field);
-
-      if (access == access_private_node)
-       {
-         cp_error ("field `%D' is private", field);
-         return error_mark_node;
-       }
-      else if (access == access_protected_node)
-       {
-         cp_error ("field `%D' is protected", field);
-         return error_mark_node;
-       }
-    }
-
-  ref = build (COMPONENT_REF, TREE_TYPE (field), datum, field);
-
-  if (TREE_READONLY (datum) || TREE_READONLY (field))
-    TREE_READONLY (ref) = 1;
-  if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (field))
-    TREE_THIS_VOLATILE (ref) = 1;
-  if (DECL_MUTABLE_P (field))
-    TREE_READONLY (ref) = 0;
-
-  return ref;
+  return build_component_ref (datum, field, NULL_TREE, protect);
 }
 
 /* Given a COND_EXPR in T, return it in a form that we can, for
@@ -1677,6 +1652,7 @@ build_component_ref_1 (datum, field, protect)
    we're dealing with aggregates.  So, we now call this in unary_complex_lvalue,
    and in build_modify_expr.  The case (in particular) that led to this was
    with CODE == ADDR_EXPR, since it's not an lvalue when we'd get it there.  */
+
 static tree
 rationalize_conditional_expr (code, t)
      enum tree_code code;
@@ -1692,6 +1668,7 @@ rationalize_conditional_expr (code, t)
    FIELD_DECL for the field.  If not found return NULL_TREE.  Because
    anonymous unions can nest, we must also search all anonymous unions
    that are directly reachable.  */
+
 static tree
 lookup_anon_field (t, type)
      tree t, type;
@@ -1727,6 +1704,7 @@ lookup_anon_field (t, type)
 /* Build a COMPONENT_REF for a given DATUM, and it's member COMPONENT.
    COMPONENT can be an IDENTIFIER_NODE that is the name of the member
    that we are interested in, or it can be a FIELD_DECL.  */
+
 tree
 build_component_ref (datum, component, basetype_path, protect)
      tree datum, component, basetype_path;
@@ -1737,10 +1715,11 @@ build_component_ref (datum, component, basetype_path, protect)
   register tree field = NULL;
   register tree ref;
 
-  if (current_template_parms)
+  if (processing_template_decl)
     return build_min_nt (COMPONENT_REF, datum, component);
 
-  /* If DATUM is a COMPOUND_EXPR or COND_EXPR, move our reference inside it. */
+  /* If DATUM is a COMPOUND_EXPR or COND_EXPR, move our reference
+     inside it.  */
   switch (TREE_CODE (datum))
     {
     case COMPOUND_EXPR:
@@ -1767,8 +1746,14 @@ build_component_ref (datum, component, basetype_path, protect)
       basetype = TREE_TYPE (datum);
       code = TREE_CODE (basetype);
     }
+  if (TREE_CODE (datum) == OFFSET_REF)
+    {
+      datum = resolve_offset_ref (datum);
+      basetype = TREE_TYPE (datum);
+      code = TREE_CODE (basetype);
+    }
 
-  /* First, see if there is a field or component with name COMPONENT. */
+  /* First, see if there is a field or component with name COMPONENT.  */
   if (TREE_CODE (component) == TREE_LIST)
     {
       my_friendly_assert (!(TREE_CHAIN (component) == NULL_TREE
@@ -1803,7 +1788,7 @@ build_component_ref (datum, component, basetype_path, protect)
          cp_error ("type `%T' has no destructor", basetype);
          return error_mark_node;
        }
-      return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0);
+      return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 1);
     }
 
   /* Look up component name in the structure type definition.  */
@@ -1813,7 +1798,8 @@ build_component_ref (datum, component, basetype_path, protect)
        hierarchy, the compiler will abort (because vptr lookups are
        not supposed to be ambiguous.  */
     field = CLASSTYPE_VFIELD (basetype);
-  else if (TREE_CODE (component) == FIELD_DECL)
+  else if (TREE_CODE (component) == FIELD_DECL
+          || TREE_CODE (component) == TYPE_DECL)
     {
       field = component;
     }
@@ -1857,7 +1843,7 @@ build_component_ref (datum, component, basetype_path, protect)
                          fndecl = build_vfn_ref (&addr, datum, DECL_VINDEX (fndecl));
                        }
                      mark_used (fndecl);
-                     return fndecl;
+                     return build (OFFSET_REF, TREE_TYPE (fndecl), datum, fndecl);
                    }
                  if (access == access_protected_node)
                    cp_error ("member function `%D' is protected", fndecl);
@@ -1905,7 +1891,8 @@ build_component_ref (datum, component, basetype_path, protect)
     {
       tree context = DECL_FIELD_CONTEXT (field);
       tree base = context;
-      while (base != basetype && ANON_AGGRNAME_P (TYPE_IDENTIFIER (base)))
+      while (base != basetype && TYPE_NAME (base)
+            && ANON_AGGRNAME_P (TYPE_IDENTIFIER (base)))
        {
          base = TYPE_CONTEXT (base);
        }
@@ -1935,7 +1922,7 @@ build_component_ref (datum, component, basetype_path, protect)
       basetype = base;
  
       /* Handle things from anon unions here...  */
-      if (ANON_AGGRNAME_P (TYPE_IDENTIFIER (context)))
+      if (TYPE_NAME (context) && ANON_AGGRNAME_P (TYPE_IDENTIFIER (context)))
        {
          tree subfield = lookup_anon_field (basetype, context);
          tree subdatum = build_component_ref (datum, subfield,
@@ -1956,6 +1943,22 @@ build_component_ref (datum, component, basetype_path, protect)
 
   return ref;
 }
+
+/* Variant of build_component_ref for use in expressions, which should
+   never have REFERENCE_TYPE.  */
+
+tree
+build_x_component_ref (datum, component, basetype_path, protect)
+     tree datum, component, basetype_path;
+     int protect;
+{
+  tree t = build_component_ref (datum, component, basetype_path, protect);
+
+  if (! processing_template_decl)
+    t = convert_from_reference (t);
+
+  return t;
+}
 \f
 /* Given an expression PTR for a pointer, return an expression
    for the value pointed to.
@@ -1971,7 +1974,7 @@ build_x_indirect_ref (ptr, errorstring)
 {
   tree rval;
 
-  if (current_template_parms)
+  if (processing_template_decl)
     return build_min_nt (INDIRECT_REF, ptr);
 
   rval = build_opfncall (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE, NULL_TREE);
@@ -1985,12 +1988,17 @@ build_indirect_ref (ptr, errorstring)
      tree ptr;
      char *errorstring;
 {
-  register tree pointer = (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE ?
-                          ptr : default_conversion (ptr));
-  register tree type = TREE_TYPE (pointer);
+  register tree pointer, type;
+
+  if (ptr == error_mark_node)
+    return error_mark_node;
 
-  if (ptr == current_class_decl)
-    return C_C_D;
+  pointer = (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE
+            ? ptr : default_conversion (ptr));
+  type = TREE_TYPE (pointer);
+
+  if (ptr == current_class_ptr)
+    return current_class_ref;
 
   if (IS_AGGR_TYPE (type))
     {
@@ -2057,13 +2065,13 @@ build_indirect_ref (ptr, errorstring)
    will inherit the type of the array, which will be some pointer type.  */
 
 tree
-build_x_array_ref (array, index)
-     tree array, index;
+build_x_array_ref (array, idx)
+     tree array, idx;
 {
-  tree rval = build_opfncall (ARRAY_REF, LOOKUP_NORMAL, array, index, NULL_TREE);
+  tree rval = build_opfncall (ARRAY_REF, LOOKUP_NORMAL, array, idx, NULL_TREE);
   if (rval)
     return rval;
-  return build_array_ref (array, index);
+  return build_array_ref (array, idx);
 }
 
 tree
@@ -2195,8 +2203,9 @@ build_array_ref (array, idx)
 \f
 /* Build a function call to function FUNCTION with parameters PARAMS.
    PARAMS is a list--a chain of TREE_LIST nodes--in which the
-   TREE_VALUE of each node is a parameter-expression.
-   FUNCTION's data type may be a function type or a pointer-to-function.
+   TREE_VALUE of each node is a parameter-expression.  The PARAMS do
+   not include any object pointer that may be required.  FUNCTION's
+   data type may be a function type or a pointer-to-function.
 
    For C++: If FUNCTION's data type is a TREE_LIST, then the tree list
    is the list of possible methods that FUNCTION could conceivably
@@ -2211,12 +2220,11 @@ build_array_ref (array, idx)
    In the second case, TREE_PURPOSE (function) is the function's
    name directly.
 
-   DECL is the class instance variable, usually CURRENT_CLASS_DECL.  */
+   DECL is the class instance variable, usually CURRENT_CLASS_REF.
+
+   When calling a TEMPLATE_DECL, we don't require a complete return
+   type.  */
 
-/*
- * [eichin:19911015.1726EST] actually return a possibly incomplete
- * type
- */
 tree
 build_x_function_call (function, params, decl)
      tree function, params, decl;
@@ -2227,10 +2235,27 @@ build_x_function_call (function, params, decl)
   if (function == error_mark_node)
     return error_mark_node;
 
-  if (current_template_parms)
-    return build_min_nt (CALL_EXPR, function, params, 0);
+  if (processing_template_decl)
+    return build_min_nt (CALL_EXPR, function, params, NULL_TREE);
 
   type = TREE_TYPE (function);
+
+  if (TREE_CODE (type) == OFFSET_TYPE
+      && TREE_TYPE (type) == unknown_type_node
+      && TREE_CODE (function) == TREE_LIST
+      && TREE_CHAIN (function) == NULL_TREE)
+    {
+      /* Undo (Foo:bar)()...  */
+      type = TYPE_OFFSET_BASETYPE (type);
+      function = TREE_VALUE (function);
+      my_friendly_assert (TREE_CODE (function) == TREE_LIST, 999);
+      my_friendly_assert (TREE_CHAIN (function) == NULL_TREE, 999);
+      function = TREE_VALUE (function);
+      my_friendly_assert (TREE_CODE (function) == FUNCTION_DECL, 999);
+      function = DECL_NAME (function);
+      return build_method_call (decl, function, params, TYPE_BINFO (type), LOOKUP_NORMAL);
+    }
+    
   is_method = ((TREE_CODE (function) == TREE_LIST
                && current_class_type != NULL_TREE
                && IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (function)) == function)
@@ -2238,11 +2263,20 @@ build_x_function_call (function, params, decl)
               || TREE_CODE (type) == METHOD_TYPE
               || TYPE_PTRMEMFUNC_P (type));
 
+  if (TREE_CODE (function) == FUNCTION_DECL
+      && DECL_STATIC_FUNCTION_P (function))
+    return build_member_call
+      (DECL_CONTEXT (function), DECL_NAME (function), params);
+
   /* Handle methods, friends, and overloaded functions, respectively.  */
   if (is_method)
     {
+      tree basetype = NULL_TREE;
+
       if (TREE_CODE (function) == FUNCTION_DECL)
        {
+         basetype = DECL_CLASS_CONTEXT (function);
+
          if (DECL_NAME (function))
            function = DECL_NAME (function);
          else
@@ -2251,6 +2285,7 @@ build_x_function_call (function, params, decl)
       else if (TREE_CODE (function) == TREE_LIST)
        {
          my_friendly_assert (TREE_CODE (TREE_VALUE (function)) == FUNCTION_DECL, 312);
+         basetype = DECL_CLASS_CONTEXT (TREE_VALUE (function));
          function = TREE_PURPOSE (function);
        }
       else if (TREE_CODE (function) != IDENTIFIER_NODE)
@@ -2278,6 +2313,10 @@ build_x_function_call (function, params, decl)
          must go through here in case it is a virtual function.
         @@ Perhaps this could be optimized.  */
 
+      if (basetype && (! current_class_type
+                      || ! DERIVED_FROM_P (basetype, current_class_type)))
+       return build_member_call (basetype, function, params);
+
       if (decl == NULL_TREE)
        {
          if (current_class_type == NULL_TREE)
@@ -2300,7 +2339,7 @@ build_x_function_call (function, params, decl)
     {
       /* Should we undo what was done in build_component_ref? */
       if (TREE_CODE (TREE_PURPOSE (TREE_OPERAND (function, 1))) == TREE_VEC)
-       /* Get the name that build_component_ref hid. */
+       /* Get the name that build_component_ref hid.  */
        function = DECL_NAME (TREE_VALUE (TREE_OPERAND (function, 1)));
       else
        function = TREE_PURPOSE (TREE_OPERAND (function, 1));
@@ -2319,12 +2358,15 @@ build_x_function_call (function, params, decl)
        {
          tree val = TREE_VALUE (function);
 
+         if (flag_ansi_overloading)
+           return build_new_function_call (function, params, NULL_TREE);
+
          if (TREE_CODE (val) == TEMPLATE_DECL)
-           return build_overload_call_maybe
-             (function, params, LOOKUP_COMPLAIN, (struct candidate *)0);
+           return build_overload_call_real
+             (function, params, LOOKUP_COMPLAIN, (struct candidate *)0, 0);
          else if (DECL_CHAIN (val) != NULL_TREE)
            return build_overload_call
-             (function, params, LOOKUP_COMPLAIN, (struct candidate *)0);
+             (function, params, LOOKUP_COMPLAIN);
          else
            my_friendly_abort (360);
        }
@@ -2340,7 +2382,7 @@ build_x_function_call (function, params, decl)
       if (TREE_OPERAND (function, 0))
        decl = TREE_OPERAND (function, 0);
       else
-       decl = C_C_D;
+       decl = current_class_ref;
 
       decl_addr = build_unary_op (ADDR_EXPR, decl, 0);
       function = get_member_function_from_ptrfunc (&decl_addr,
@@ -2355,8 +2397,7 @@ build_x_function_call (function, params, decl)
       if (TREE_CODE (type) == REFERENCE_TYPE)
        type = TREE_TYPE (type);
 
-      if (TYPE_LANG_SPECIFIC (type)
-         && TYPE_OVERLOADS_CALL_EXPR (complete_type (type)))
+      if (IS_AGGR_TYPE (type))
        return build_opfncall (CALL_EXPR, LOOKUP_NORMAL, function, params, NULL_TREE);
     }
 
@@ -2417,7 +2458,7 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
 
   if (TYPE_PTRMEMFUNC_P (TREE_TYPE (function)))
     {
-      tree fntype, index, e1, delta, delta2, e2, e3, aref, vtbl;
+      tree fntype, idx, e1, delta, delta2, e2, e3, aref, vtbl;
       tree instance;
 
       tree instance_ptr = *instance_ptrptr;
@@ -2429,20 +2470,20 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
        function = save_expr (function);
 
       fntype = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function));
-      index = save_expr (build_component_ref (function,
-                                             index_identifier,
-                                             0, 0));
-      e1 = build (GT_EXPR, boolean_type_node, index,
-                 convert (delta_type_node, integer_zero_node));
+      idx = save_expr (build_component_ref (function,
+                                           index_identifier,
+                                           NULL_TREE, 0));
+      e1 = fold (build (GT_EXPR, boolean_type_node, idx,
+                       convert (delta_type_node, integer_zero_node)));
       delta = convert (ptrdiff_type_node,
-                      build_component_ref (function, delta_identifier, 0, 0));
+                      build_component_ref (function, delta_identifier, NULL_TREE, 0));
       delta2 = DELTA2_FROM_PTRMEMFUNC (function);
 
-      /* convert down to the right base, before using the instance. */
+      /* convert down to the right base, before using the instance.  */
       instance
        = convert_pointer_to_real (TYPE_METHOD_BASETYPE (TREE_TYPE (fntype)),
                                   instance_ptr);
-      if (instance == error_mark_node)
+      if (instance == error_mark_node && instance_ptr != error_mark_node)
        return instance;
 
       vtbl = convert_pointer_to (ptr_type_node, instance);
@@ -2452,19 +2493,14 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
                 vtbl, convert (ptrdiff_type_node, delta2));
       vtbl = build_indirect_ref (vtbl, NULL_PTR);
       aref = build_array_ref (vtbl, build_binary_op (MINUS_EXPR,
-                                                    index,
+                                                    idx,
                                                     integer_one_node, 1));
       if (! flag_vtable_thunks)
        {
          aref = save_expr (aref);
 
-         /* Save the intermediate result in a SAVE_EXPR so we don't have to
-            compute each component of the virtual function pointer twice.  */ 
-         if (TREE_CODE (aref) == INDIRECT_REF)
-           TREE_OPERAND (aref, 0) = save_expr (TREE_OPERAND (aref, 0));
-      
          delta = build_binary_op (PLUS_EXPR,
-                                  build_conditional_expr (e1, build_component_ref (aref, delta_identifier, 0, 0), integer_zero_node),
+                                  build_conditional_expr (e1, build_component_ref (aref, delta_identifier, NULL_TREE, 0), integer_zero_node),
                                   delta, 1);
        }
 
@@ -2473,11 +2509,18 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
       if (flag_vtable_thunks)
        e2 = aref;
       else
-       e2 = build_component_ref (aref, pfn_identifier, 0, 0);
+       e2 = build_component_ref (aref, pfn_identifier, NULL_TREE, 0);
 
       e3 = PFN_FROM_PTRMEMFUNC (function);
       TREE_TYPE (e2) = TREE_TYPE (e3);
-      function = build_conditional_expr (e1, e2, e3);
+      e1 = build_conditional_expr (e1, e2, e3);
+
+      if (instance_ptr == error_mark_node
+         && TREE_CODE (e1) != ADDR_EXPR
+         && TREE_CODE (TREE_OPERAND (e1, 0)) != FUNCTION_DECL)
+       cp_error ("object missing in `%E'", function);
+
+      function = e1;
 
       /* Make sure this doesn't get evaluated first inside one of the
          branches of the COND_EXPR.  */
@@ -2537,38 +2580,27 @@ build_function_call_real (function, params, require_complete, flags)
         needs to be separately compiled).  */
 
       if (DECL_INLINE (function))
-       {
-         /* Is it a synthesized method that needs to be synthesized?  */
-         if (DECL_ARTIFICIAL (function) && ! DECL_INITIAL (function)
-             /* Kludge: don't synthesize for default args.  */
-             && current_function_decl)
-           synthesize_method (function);
-
-         fntype = build_type_variant (TREE_TYPE (function),
-                                      TREE_READONLY (function),
-                                      TREE_THIS_VOLATILE (function));
-         function = build1 (ADDR_EXPR, build_pointer_type (fntype), function);
-       }
+       function = inline_conversion (function);
       else
-       function = default_conversion (function);
+       function = build_addr_func (function);
     }
   else
     {
       fndecl = NULL_TREE;
 
-      /* Convert anything with function type to a pointer-to-function.  */
-      if (function == error_mark_node)
-       return error_mark_node;
-      function = default_conversion (function);
+      function = build_addr_func (function);
     }
 
+  if (function == error_mark_node)
+    return error_mark_node;
+
   fntype = TREE_TYPE (function);
 
   if (TYPE_PTRMEMFUNC_P (fntype))
     {
-      tree instance_ptr = build_unary_op (ADDR_EXPR, C_C_D, 0);
-      fntype = TYPE_PTRMEMFUNC_FN_TYPE (fntype);
-      function = get_member_function_from_ptrfunc (&instance_ptr, function);
+      cp_error ("must use .* or ->* to call pointer-to-member function in `%E (...)'",
+               function);
+      return error_mark_node;
     }
 
   is_method = (TREE_CODE (fntype) == POINTER_TYPE
@@ -2626,17 +2658,17 @@ build_function_call_real (function, params, require_complete, flags)
   /* C++ */
   value_type = TREE_TYPE (fntype) ? TREE_TYPE (fntype) : void_type_node;
   {
-    register tree result = 
-      build (CALL_EXPR, value_type,
-            function, coerced_params, NULL_TREE);
+    register tree result
+      = build_call (function, value_type, coerced_params);
 
-    TREE_SIDE_EFFECTS (result) = 1;
-
-    if (! require_complete)
-      return convert_from_reference (result);
-    if (value_type == void_type_node)
-      return result;
-    result = require_complete_type (result);
+    if (require_complete)
+      {
+       if (value_type == void_type_node)
+         return result;
+       result = require_complete_type (result);
+      }
+    if (IS_AGGR_TYPE (value_type))
+      result = build_cplus_new (value_type, result);
     return convert_from_reference (result);
   }
 }
@@ -2712,9 +2744,8 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
        {
          if (fndecl)
            {
-             char *buf = (char *)alloca (40 + strlen (called_thing));
-             sprintf (buf, "too many arguments to %s `%%s'", called_thing);
-             error_with_decl (fndecl, buf);
+             cp_error_at ("too many arguments to %s `%+D'", called_thing,
+                          fndecl);
              error ("at this point in file");
            }
          else
@@ -2753,7 +2784,7 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
       else if (TREE_CODE (val) == OFFSET_REF
            && TREE_CODE (TREE_TYPE (val)) == METHOD_TYPE)
        {
-         /* This is unclean.  Should be handled elsewhere. */
+         /* This is unclean.  Should be handled elsewhere.  */
          val = build_unary_op (ADDR_EXPR, val, 0);
        }
       else if (TREE_CODE (val) == OFFSET_REF)
@@ -2791,9 +2822,9 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
            }
          else
            {
-             parmval = convert_for_initialization (return_loc, type, val,
-                                                   flags|INDIRECT_BIND,
-                                                   "argument passing", fndecl, i);
+             parmval = convert_for_initialization
+               (return_loc, type, val, flags,
+                "argument passing", fndecl, i);
 #ifdef PROMOTE_PROTOTYPES
              if ((TREE_CODE (type) == INTEGER_TYPE
                   || TREE_CODE (type) == ENUMERAL_TYPE)
@@ -2906,9 +2937,12 @@ build_x_binary_op (code, arg1, arg2)
 {
   tree rval;
 
-  if (current_template_parms)
+  if (processing_template_decl)
     return build_min_nt (code, arg1, arg2);
 
+  if (flag_ansi_overloading)
+    return build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE);
+
   rval = build_opfncall (code, LOOKUP_SPECULATIVELY,
                         arg1, arg2, NULL_TREE);
   if (rval)
@@ -3321,14 +3355,14 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
       else if (TYPE_PTRMEMFUNC_P (type0) && TREE_CODE (op1) == INTEGER_CST
               && integer_zerop (op1))
        {
-         op0 = build_component_ref (op0, index_identifier, 0, 0);
+         op0 = build_component_ref (op0, index_identifier, NULL_TREE, 0);
          op1 = integer_zero_node;
          result_type = TREE_TYPE (op0);
        }
       else if (TYPE_PTRMEMFUNC_P (type1) && TREE_CODE (op0) == INTEGER_CST
               && integer_zerop (op0))
        {
-         op0 = build_component_ref (op1, index_identifier, 0, 0);
+         op0 = build_component_ref (op1, index_identifier, NULL_TREE, 0);
          op1 = integer_zero_node;
          result_type = TREE_TYPE (op0);
        }
@@ -3342,8 +3376,8 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
           && ((op1.index != -1 && op0.delta2 == op1.delta2)
               || op0.pfn == op1.pfn)) */
 
-         tree index0 = build_component_ref (op0, index_identifier, 0, 0);
-         tree index1 = save_expr (build_component_ref (op1, index_identifier, 0, 0));
+         tree index0 = build_component_ref (op0, index_identifier, NULL_TREE, 0);
+         tree index1 = save_expr (build_component_ref (op1, index_identifier, NULL_TREE, 0));
          tree pfn0 = PFN_FROM_PTRMEMFUNC (op0);
          tree pfn1 = PFN_FROM_PTRMEMFUNC (op1);
          tree delta20 = DELTA2_FROM_PTRMEMFUNC (op0);
@@ -3364,7 +3398,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
       else if (TYPE_PTRMEMFUNC_P (type0)
               && TYPE_PTRMEMFUNC_FN_TYPE (type0) == type1)
        {
-         tree index0 = build_component_ref (op0, index_identifier, 0, 0);
+         tree index0 = build_component_ref (op0, index_identifier, NULL_TREE, 0);
          tree index1;
          tree pfn0 = PFN_FROM_PTRMEMFUNC (op0);
          tree delta20 = DELTA2_FROM_PTRMEMFUNC (op0);
@@ -3454,18 +3488,12 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
       else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
        {
          result_type = type0;
-         if (pedantic)
-           pedwarn ("ANSI C++ forbids comparison between pointer and integer");
-         else if (! flag_traditional)
-           warning ("comparison between pointer and integer");
+         pedwarn ("ANSI C++ forbids comparison between pointer and integer");
        }
       else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
        {
          result_type = type1;
-         if (pedantic)
-           pedwarn ("ANSI C++ forbids comparison between pointer and integer");
-         else if (! flag_traditional)
-           warning ("comparison between pointer and integer");
+         pedwarn ("ANSI C++ forbids comparison between pointer and integer");
        }
       break;
     }
@@ -3616,7 +3644,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
          tree primop0 = get_narrower (op0, &unsignedp0);
          tree primop1 = get_narrower (op1, &unsignedp1);
 
-         /* Check for comparison of different enum types. */
+         /* Check for comparison of different enum types.  */
          if (flag_int_enum_equivalence == 0 
              && TREE_CODE (TREE_TYPE (orig_op0)) == ENUMERAL_TYPE 
              && TREE_CODE (TREE_TYPE (orig_op1)) == ENUMERAL_TYPE 
@@ -3953,11 +3981,11 @@ build_x_unary_op (code, xarg)
      enum tree_code code;
      tree xarg;
 {
-  if (current_template_parms)
+  if (processing_template_decl)
     return build_min_nt (code, xarg, NULL_TREE);
 
   /* & rec, on incomplete RECORD_TYPEs is the simple opr &, not an
-     error message. */
+     error message.  */
   if (code == ADDR_EXPR
       && ((IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (xarg)))
           && TYPE_SIZE (TREE_TYPE (xarg)) == NULL_TREE)
@@ -3965,12 +3993,31 @@ build_x_unary_op (code, xarg)
     /* don't look for a function */;
   else
     {
-      tree rval = build_opfncall (code, LOOKUP_SPECULATIVELY, xarg,
-                                 NULL_TREE, NULL_TREE);
-      if (rval)
-       return build_opfncall (code, LOOKUP_NORMAL, xarg,
+      tree rval;
+
+      if (flag_ansi_overloading)
+       {
+         rval = build_new_op (code, LOOKUP_NORMAL, xarg,
                               NULL_TREE, NULL_TREE);
+         if (rval || code != ADDR_EXPR)
+           return rval;
+       }
+      else
+       {
+         rval = build_opfncall (code, LOOKUP_SPECULATIVELY, xarg,
+                                NULL_TREE, NULL_TREE);
+         if (rval)
+           return build_opfncall (code, LOOKUP_NORMAL, xarg,
+                                  NULL_TREE, NULL_TREE);
+       }
+    }
+
+  if (code == ADDR_EXPR)
+    {
+      if (TREE_CODE (xarg) == TARGET_EXPR)
+       warning ("taking address of temporary");
     }
+
   return build_unary_op (code, xarg, 0);
 }
 
@@ -3981,7 +4028,7 @@ condition_conversion (expr)
      tree expr;
 {
   tree t;
-  if (current_template_parms)
+  if (processing_template_decl)
     return expr;
   t = convert (boolean_type_node, expr);
   t = fold (build1 (CLEANUP_POINT_EXPR, boolean_type_node, t));
@@ -3996,6 +4043,7 @@ condition_conversion (expr)
 
    NOCONVERT nonzero suppresses the default promotions
    (such as from short to int).  */
+
 tree
 build_unary_op (code, xarg, noconvert)
      enum tree_code code;
@@ -4161,7 +4209,7 @@ build_unary_op (code, xarg, noconvert)
              modify = build_modify_expr (arg, NOP_EXPR, incremented);
              compound = build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value);
 
-             /* Eliminate warning about unused result of + or -. */
+             /* Eliminate warning about unused result of + or -.  */
              TREE_NO_UNUSED_WARNING (compound) = 1;
              return compound;
            }
@@ -4232,10 +4280,10 @@ build_unary_op (code, xarg, noconvert)
       /* Let &* cancel out to simplify resulting code.  */
       if (TREE_CODE (arg) == INDIRECT_REF)
        {
-         /* We don't need to have `current_class_decl' wrapped in a
+         /* We don't need to have `current_class_ptr' wrapped in a
             NON_LVALUE_EXPR node.  */
-         if (arg == C_C_D)
-           return current_class_decl;
+         if (arg == current_class_ref)
+           return current_class_ptr;
 
          /* Keep `default_conversion' from converting if
             ARG is of REFERENCE_TYPE.  */
@@ -4352,6 +4400,14 @@ build_unary_op (code, xarg, noconvert)
           function counts as a constant */
        if (staticp (arg))
          TREE_CONSTANT (addr) = 1;
+
+       if (TREE_CODE (argtype) == POINTER_TYPE &&
+           TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE)
+         {
+           build_ptrmemfunc_type (argtype);
+           addr = build_ptrmemfunc (argtype, addr, 0);
+         }
+
        return addr;
       }
     }
@@ -4445,7 +4501,6 @@ unary_complex_lvalue (code, arg)
         is really the representation of a pointer to it.
         Here give the representation its true type.  */
       tree t;
-      tree offset;
 
       my_friendly_assert (TREE_CODE (arg) != SCOPE_REF, 313);
 
@@ -4454,12 +4509,15 @@ unary_complex_lvalue (code, arg)
 
       t = TREE_OPERAND (arg, 1);
 
-      if (TREE_CODE (t) == FUNCTION_DECL) /* Check all this code for right semantics. */
+      if (TREE_CODE (t) == FUNCTION_DECL) /* Check all this code for right semantics.  */
        return build_unary_op (ADDR_EXPR, t, 0);
       if (TREE_CODE (t) == VAR_DECL)
        return build_unary_op (ADDR_EXPR, t, 0);
       else
        {
+         tree type;
+         tree offset = integer_zero_node;
+
          if (TREE_OPERAND (arg, 0)
              && (TREE_CODE (TREE_OPERAND (arg, 0)) != NOP_EXPR
                  || TREE_OPERAND (TREE_OPERAND (arg, 0), 0) != error_mark_node))
@@ -4471,38 +4529,40 @@ unary_complex_lvalue (code, arg)
                return error_mark_node;
              }
 
-         offset = get_delta_difference (DECL_FIELD_CONTEXT (t), 
-                                        TREE_TYPE (TREE_OPERAND (arg, 0)),
-                                        0);
+         type = TREE_TYPE (TREE_OPERAND (arg, 0));
+
+         if (TREE_CODE (TREE_TYPE (arg)) == OFFSET_TYPE)
+           {
+             /* Add in the offset to the intermediate subobject, if any.  */
+             offset = get_delta_difference (TYPE_OFFSET_BASETYPE (TREE_TYPE (arg)),
+                                            type,
+                                            0);
+             type = TYPE_OFFSET_BASETYPE (TREE_TYPE (arg));
+           }
+
+         /* Now in the offset to the final subobject.  */
+         offset = size_binop (PLUS_EXPR,
+                              offset,
+                              get_delta_difference (DECL_FIELD_CONTEXT (t), 
+                                                    type,
+                                                    0));
+
+         /* Add in the offset to the field.  */
          offset = size_binop (PLUS_EXPR, offset,
                               size_binop (EASY_DIV_EXPR,
                                           DECL_FIELD_BITPOS (t),
                                           size_int (BITS_PER_UNIT)));
-         return convert (build_pointer_type (TREE_TYPE (arg)), offset);
-       }
-    }
-
-  if (TREE_CODE (arg) == OFFSET_REF)
-    {
-      tree left = TREE_OPERAND (arg, 0), left_addr;
-      tree right_addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 1), 0);
 
-      if (left == 0)
-       if (current_class_decl)
-         left_addr = current_class_decl;
-       else
-         {
-           error ("no `this' for pointer to member");
-           return error_mark_node;
-         }
-      else
-       left_addr = build_unary_op (ADDR_EXPR, left, 0);
+         /* We offset all pointer to data memebers by 1 so that we can
+            distinguish between a null pointer to data member and the first
+            data member of a structure.  */
+         offset = size_binop (PLUS_EXPR, offset, size_int (1));
 
-      return build (PLUS_EXPR, build_pointer_type (TREE_TYPE (arg)),
-                   build1 (NOP_EXPR, integer_type_node, left_addr),
-                   build1 (NOP_EXPR, integer_type_node, right_addr));
+         return convert (build_pointer_type (TREE_TYPE (arg)), offset);
+       }
     }
 
+  
   /* We permit compiler to make function calls returning
      objects of aggregate type look like lvalues.  */
   {
@@ -4533,7 +4593,7 @@ unary_complex_lvalue (code, arg)
    address of it; it should not be allocated in a register.
    Value is 1 if successful.
 
-   C++: we do not allow `current_class_decl' to be addressable.  */
+   C++: we do not allow `current_class_ptr' to be addressable.  */
 
 int
 mark_addressable (exp)
@@ -4554,9 +4614,10 @@ mark_addressable (exp)
        break;
 
       case PARM_DECL:
-       if (x == current_class_decl)
+       if (x == current_class_ptr)
          {
-           error ("address of `this' not available");
+           if (! flag_this_is_variable)
+             error ("address of `this' not available");
            TREE_ADDRESSABLE (x) = 1; /* so compiler doesn't die later */
            put_var_into_stack (x);
            return 1;
@@ -4589,8 +4650,10 @@ mark_addressable (exp)
 
       case CONST_DECL:
       case RESULT_DECL:
-       /* For C++, we don't warn about taking the address of a register
-          variable for CONST_DECLs; ARM p97 explicitly says it's okay.  */
+       if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x)
+           && !DECL_ARTIFICIAL (x) && extra_warnings)
+         cp_warning ("address requested for `%D', which is declared `register'",
+                     x);
        put_var_into_stack (x);
        TREE_ADDRESSABLE (x) = 1;
        return 1;
@@ -4614,6 +4677,15 @@ mark_addressable (exp)
        TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (x)) = 1;
        return 1;
 
+      case CONSTRUCTOR:
+       TREE_ADDRESSABLE (x) = 1;
+       return 1;
+
+      case TARGET_EXPR:
+       TREE_ADDRESSABLE (x) = 1;
+       mark_addressable (TREE_OPERAND (x, 0));
+       return 1;
+
       default:
        return 1;
     }
@@ -4627,9 +4699,12 @@ build_x_conditional_expr (ifexp, op1, op2)
 {
   tree rval = NULL_TREE;
 
-  if (current_template_parms)
+  if (processing_template_decl)
     return build_min_nt (COND_EXPR, ifexp, op1, op2);
 
+  if (flag_ansi_overloading)
+    return build_new_op (COND_EXPR, LOOKUP_NORMAL, ifexp, op1, op2);
+
   /* See comments in `build_x_binary_op'.  */
   if (op1 != 0)
     rval = build_opfncall (COND_EXPR, LOOKUP_SPECULATIVELY, ifexp, op1, op2);
@@ -4724,6 +4799,15 @@ build_conditional_expr (ifexp, op1, op2)
       result = fold (build (COND_EXPR, type1, ifexp, op1, op2));
       if (TREE_TYPE (result) != type1)
        result = build1 (NOP_EXPR, type1, result);
+      /* Expand both sides into the same slot,
+        hopefully the target of the ?: expression.  */
+      if (TREE_CODE (op1) == TARGET_EXPR && TREE_CODE (op2) == TARGET_EXPR)
+       {
+         tree slot = build (VAR_DECL, TREE_TYPE (result));
+         layout_decl (slot, 0);
+         result = build (TARGET_EXPR, TREE_TYPE (result),
+                         slot, result, NULL_TREE, NULL_TREE);
+       }
       return result;
     }
 
@@ -4797,16 +4881,14 @@ build_conditional_expr (ifexp, op1, op2)
        pedwarn ("ANSI C++ forbids conditional expr with only one void side");
       result_type = void_type_node;
     }
+  else if (code1 == POINTER_TYPE && null_ptr_cst_p (op2))
+    result_type = qualify_type (type1, type2);
+  else if (code2 == POINTER_TYPE && null_ptr_cst_p (op1))
+    result_type = qualify_type (type2, type1);
   else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE)
     {
       if (comp_target_types (type1, type2, 1))
        result_type = common_type (type1, type2);
-      else if (integer_zerop (op1) && TREE_TYPE (type1) == void_type_node
-              && TREE_CODE (orig_op1) != NOP_EXPR)
-       result_type = qualify_type (type2, type1);
-      else if (integer_zerop (op2) && TREE_TYPE (type2) == void_type_node
-              && TREE_CODE (orig_op2) != NOP_EXPR)
-       result_type = qualify_type (type1, type2);
       else if (TYPE_MAIN_VARIANT (TREE_TYPE (type1)) == void_type_node)
        {
          if (pedantic && TREE_CODE (type2) == FUNCTION_TYPE)
@@ -4851,20 +4933,12 @@ build_conditional_expr (ifexp, op1, op2)
     }
   else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE)
     {
-      if (!integer_zerop (op2))
-       pedwarn ("pointer/integer type mismatch in conditional expression");
-      else
-       op2 = null_pointer_node;
-
+      pedwarn ("pointer/integer type mismatch in conditional expression");
       result_type = type1;
     }
   else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE)
     {
-      if (!integer_zerop (op1))
-       pedwarn ("pointer/integer type mismatch in conditional expression");
-      else
-       op1 = null_pointer_node;
-
+      pedwarn ("pointer/integer type mismatch in conditional expression");
       result_type = type2;
     }
 
@@ -4877,30 +4951,52 @@ build_conditional_expr (ifexp, op1, op2)
          cp_error ("aggregate mismatch in conditional expression: `%T' vs `%T'", type1, type2);
          return error_mark_node;
        }
+      /* Warning: this code assumes that conversion between cv-variants of
+         a type is done using NOP_EXPRs.  */
       if (code1 == RECORD_TYPE && TYPE_HAS_CONVERSION (type1))
        {
-         tree tmp = build_type_conversion (CONVERT_EXPR, type2, op1, 0);
+         /* There are other types besides pointers and records.  */
+         tree tmp;
+         if (code2 == POINTER_TYPE)
+             tmp = build_pointer_type
+               (build_type_variant (TREE_TYPE (type2), 1, 1));
+         else
+           tmp = type2;
+         tmp = build_type_conversion (CONVERT_EXPR, tmp, op1, 0);
          if (tmp == NULL_TREE)
            {
-             cp_error ("aggregate type `%T' could not convert on lhs of `:'", type1);
+             cp_error ("incompatible types `%T' and `%T' in `?:'",
+                       type1, type2);
              return error_mark_node;
            }
          if (tmp == error_mark_node)
            error ("ambiguous pointer conversion");
-         result_type = type2;
+         else
+           STRIP_NOPS (tmp);
+         result_type = common_type (type2, TREE_TYPE (tmp));
          op1 = tmp;
        }
       else if (code2 == RECORD_TYPE && TYPE_HAS_CONVERSION (type2))
        {
-         tree tmp = build_type_conversion (CONVERT_EXPR, type1, op2, 0);
+         tree tmp;
+         if (code1 == POINTER_TYPE)
+           tmp = build_pointer_type
+             (build_type_variant (TREE_TYPE (type1), 1, 1));
+         else
+           tmp = type1;
+
+         tmp = build_type_conversion (CONVERT_EXPR, tmp, op2, 0);
          if (tmp == NULL_TREE)
            {
-             cp_error ("aggregate type `%T' could not convert on rhs of `:'", type2);
+             cp_error ("incompatible types `%T' and `%T' in `?:'",
+                       type1, type2);
              return error_mark_node;
            }
          if (tmp == error_mark_node)
            error ("ambiguous pointer conversion");
-         result_type = type1;
+         else
+           STRIP_NOPS (tmp);
+         result_type = common_type (type1, TREE_TYPE (tmp));
          op2 = tmp;
        }
       else if (flag_cond_mismatch)
@@ -4930,6 +5026,7 @@ build_conditional_expr (ifexp, op1, op2)
 \f
 /* Handle overloading of the ',' operator when needed.  Otherwise,
    this function just builds an expression list.  */
+
 tree
 build_x_compound_expr (list)
      tree list;
@@ -4937,7 +5034,7 @@ build_x_compound_expr (list)
   tree rest = TREE_CHAIN (list);
   tree result;
 
-  if (current_template_parms)
+  if (processing_template_decl)
     return build_min_nt (COMPOUND_EXPR, list, NULL_TREE);
 
   if (rest == NULL_TREE)
@@ -5004,124 +5101,251 @@ build_compound_expr (list)
                break_out_cleanups (TREE_VALUE (list)), rest);
 }
 
-tree build_static_cast (type, expr)
+tree
+build_static_cast (type, expr)
    tree type, expr;
 {
-  return build_c_cast (type, expr, 0);
+  tree intype, binfo;
+  int ok;
+
+  if (type == error_mark_node || expr == error_mark_node)
+    return error_mark_node;
+
+  if (TREE_CODE (expr) == OFFSET_REF)
+    expr = resolve_offset_ref (expr);
+
+  if (processing_template_decl)
+    {
+      tree t = build_min (STATIC_CAST_EXPR, type, expr);
+      return t;
+    }
+
+  /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
+     Strip such NOP_EXPRs if VALUE is being used in non-lvalue context.  */
+  if (TREE_CODE (type) != REFERENCE_TYPE
+      && TREE_CODE (expr) == NOP_EXPR
+      && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
+    expr = TREE_OPERAND (expr, 0);
+
+  if (TREE_CODE (type) == VOID_TYPE)
+    return build1 (CONVERT_EXPR, type, expr);
+
+  if (type_unknown_p (expr))
+    {
+      expr = instantiate_type (type, expr, 1);
+      if (expr == error_mark_node)
+       return error_mark_node;
+    }
+
+  if (TREE_CODE (type) == REFERENCE_TYPE)
+    return (convert_from_reference
+           (convert_to_reference (type, expr, CONV_STATIC|CONV_IMPLICIT,
+                                  LOOKUP_COMPLAIN, NULL_TREE)));
+
+  if (IS_AGGR_TYPE (type))
+    return build_cplus_new
+      (type, (build_method_call
+             (NULL_TREE, ctor_identifier, build_tree_list (NULL_TREE, expr),
+              TYPE_BINFO (type), LOOKUP_NORMAL)));
+
+  expr = decay_conversion (expr);
+  intype = TREE_TYPE (expr);
+
+  /* FIXME handle casting to array type.  */
+
+  ok = 0;
+  if (can_convert_arg (type, intype, expr))
+    ok = 1;
+  else if (TYPE_PTROB_P (type) && TYPE_PTROB_P (intype))
+    {
+      tree binfo;
+      if (IS_AGGR_TYPE (TREE_TYPE (type)) && IS_AGGR_TYPE (TREE_TYPE (intype))
+         && (TYPE_READONLY (TREE_TYPE (type))
+             >= TYPE_READONLY (TREE_TYPE (intype)))
+         && (TYPE_VOLATILE (TREE_TYPE (type))
+             >= TYPE_VOLATILE (TREE_TYPE (intype)))
+         && (binfo = get_binfo (TREE_TYPE (intype), TREE_TYPE (type), 0))
+         && ! TREE_VIA_VIRTUAL (binfo))
+       ok = 1;
+    }
+  else if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
+    {
+      if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type))),
+                    TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (intype))), 1)
+         && (TYPE_READONLY (TREE_TYPE (TREE_TYPE (type)))
+             >= TYPE_READONLY (TREE_TYPE (TREE_TYPE (intype))))
+         && (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (type)))
+             >= TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (intype))))
+         && (binfo = get_binfo (TYPE_OFFSET_BASETYPE (intype),
+                                TYPE_OFFSET_BASETYPE (type), 0))
+         && ! TREE_VIA_VIRTUAL (binfo))
+       ok = 1;
+    }
+  else if (TREE_CODE (intype) != BOOLEAN_TYPE
+          && TREE_CODE (type) != ARRAY_TYPE
+          && TREE_CODE (type) != FUNCTION_TYPE
+          && can_convert (intype, type))
+    ok = 1;
+
+  if (ok)
+    return build_c_cast (type, expr, 0);
+
+  cp_error ("static_cast from `%T' to `%T'", intype, type);
+  return error_mark_node;
 }
 
-tree build_reinterpret_cast (type, expr)
+tree
+build_reinterpret_cast (type, expr)
    tree type, expr;
 {
-  tree intype = TREE_TYPE (expr);
+  tree intype;
+
+  if (type == error_mark_node || expr == error_mark_node)
+    return error_mark_node;
 
-  if (TYPE_PTRMEMFUNC_P (type))
-    type = TYPE_PTRMEMFUNC_FN_TYPE (type);
+  if (TREE_CODE (expr) == OFFSET_REF)
+    expr = resolve_offset_ref (expr);
 
-  if (current_template_parms)
+  if (processing_template_decl)
     {
       tree t = build_min (REINTERPRET_CAST_EXPR, type, expr);
       return t;
     }
 
-  if (TYPE_PTRMEMFUNC_P (intype))
-    intype = TYPE_PTRMEMFUNC_FN_TYPE (intype);
+  if (TREE_CODE (type) != REFERENCE_TYPE)
+    {
+      expr = decay_conversion (expr);
 
-  if (! POINTER_TYPE_P (type) && ! TREE_CODE (type) == INTEGER_TYPE)
+      /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
+        Strip such NOP_EXPRs if VALUE is being used in non-lvalue context.  */
+      if (TREE_CODE (expr) == NOP_EXPR
+         && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
+       expr = TREE_OPERAND (expr, 0);
+    }
+
+  if (type_unknown_p (expr))
     {
-      cp_error ("reinterpret_cast cannot convert to type `%T'", type);
-      return error_mark_node;
+      expr = instantiate_type (type, expr, 1);
+      if (expr == error_mark_node)
+       return error_mark_node;
     }
-  if (! POINTER_TYPE_P (intype) && ! TREE_CODE (intype) == INTEGER_TYPE)
+
+  intype = TREE_TYPE (expr);
+
+  if (TREE_CODE (type) == REFERENCE_TYPE)
     {
-      cp_error ("reinterpret_cast cannot convert from type `%T'", type);
-      return error_mark_node;
+      if (! real_lvalue_p (expr))
+       {
+         cp_error ("reinterpret_cast from `%T' rvalue to `%T'", intype, type);
+         return error_mark_node;
+       }
+      expr = build_unary_op (ADDR_EXPR, expr, 0);
+      if (expr != error_mark_node)
+       expr = build_reinterpret_cast
+         (build_pointer_type (TREE_TYPE (type)), expr);
+      if (expr != error_mark_node)
+       expr = build_indirect_ref (expr, 0);
+      return expr;
     }
-  if (TREE_CODE (type) == INTEGER_TYPE && TREE_CODE (intype) != POINTER_TYPE)
+  else if (comptypes (TYPE_MAIN_VARIANT (intype), TYPE_MAIN_VARIANT (type), 1))
+    return build_static_cast (type, expr);
+
+  if (TYPE_PTR_P (type) && (TREE_CODE (intype) == INTEGER_TYPE
+                           || TREE_CODE (intype) == ENUMERAL_TYPE))
+    /* OK */;
+  else if (TREE_CODE (type) == INTEGER_TYPE && TYPE_PTR_P (intype))
     {
-      cp_error ("reinterpret_cast cannot convert non-pointer type `%T' to `%T'",
-               intype, type);
-      return error_mark_node;
+      if (TYPE_PRECISION (type) < TYPE_PRECISION (intype))
+       cp_pedwarn ("reinterpret_cast from `%T' to `%T' loses precision",
+                   intype, type);
     }
-  if (TREE_CODE (intype) == INTEGER_TYPE && TREE_CODE (type) != POINTER_TYPE)
+  else if ((TYPE_PTRFN_P (type) && TYPE_PTRFN_P (intype))
+          || (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
     {
-      cp_error ("reinterpret_cast cannot convert `%T' to non-pointer type `%T'",
-               intype, type);
-      return error_mark_node;
+      if (TREE_READONLY_DECL_P (expr))
+       expr = decl_constant_value (expr);
+      return fold (build1 (NOP_EXPR, type, expr));
     }
+  else if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
+          || (TYPE_PTROBV_P (type) && TYPE_PTROBV_P (intype)))
+    {
+      if (! comp_ptr_ttypes_reinterpret (TREE_TYPE (type), TREE_TYPE (intype)))
+       cp_pedwarn ("reinterpret_cast from `%T' to `%T' casts away const (or volatile)",
+                   intype, type);
 
-  if (TREE_CODE (type) == POINTER_TYPE && TREE_CODE (intype) == POINTER_TYPE)
-    expr = convert (ptr_type_node, expr);
-
-  return build_c_cast (type, expr, 0);
+      if (TREE_READONLY_DECL_P (expr))
+       expr = decl_constant_value (expr);
+      return fold (build1 (NOP_EXPR, type, expr));
+    }
+  else
+    {
+      cp_error ("reinterpret_cast from `%T' to `%T'", intype, type);
+      return error_mark_node;
+    }
+      
+  return convert (type, expr);
 }
 
-tree build_const_cast (type, expr)
+tree
+build_const_cast (type, expr)
    tree type, expr;
 {
-  tree intype = TREE_TYPE (expr);
-  tree t1, t2;
+  tree intype;
 
   if (type == error_mark_node || expr == error_mark_node)
     return error_mark_node;
 
-  if (TYPE_PTRMEMFUNC_P (type))
-    type = TYPE_PTRMEMFUNC_FN_TYPE (type);
-  if (TYPE_PTRMEMFUNC_P (intype))
-    intype = TYPE_PTRMEMFUNC_FN_TYPE (intype);
+  if (TREE_CODE (expr) == OFFSET_REF)
+    expr = resolve_offset_ref (expr);
 
-  if (! POINTER_TYPE_P (type))
-    {
-      cp_error ("const_cast cannot convert to non-pointer type `%T'", type);
-      return error_mark_node;
-    }
-  if (TREE_CODE (type) == REFERENCE_TYPE && ! real_lvalue_p (expr))
+  if (processing_template_decl)
     {
-      cp_error ("const_cast cannot convert rvalue to type `%T'", type);
-      return error_mark_node;
+      tree t = build_min (CONST_CAST_EXPR, type, expr);
+      return t;
     }
-  if (TREE_CODE (type) == POINTER_TYPE && TREE_CODE (intype) != POINTER_TYPE)
+
+  if (TREE_CODE (type) != REFERENCE_TYPE)
     {
-      cp_error ("const_cast cannot convert non-pointer type `%T' to type `%T'",
-               intype, type);
-      return error_mark_node;
+      expr = decay_conversion (expr);
+
+      /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
+        Strip such NOP_EXPRs if VALUE is being used in non-lvalue context.  */
+      if (TREE_CODE (expr) == NOP_EXPR
+         && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
+       expr = TREE_OPERAND (expr, 0);
     }
 
-  if (TREE_CODE (type) == REFERENCE_TYPE)
+  if (type_unknown_p (expr))
     {
-      t1 = TREE_TYPE (type);
-      t2 = intype;
+      expr = instantiate_type (type, expr, 1);
+      if (expr == error_mark_node)
+       return error_mark_node;
     }
-  else
-    {
-      t1 = TREE_TYPE (type);
-      t2 = TREE_TYPE (intype);
 
-      for (; TREE_CODE (t1) == POINTER_TYPE && TREE_CODE (t2) == POINTER_TYPE;
-          t1 = TREE_TYPE (t1), t2 = TREE_TYPE (t2))
-       ;
-    }
+  intype = TREE_TYPE (expr);
 
-  if (TREE_CODE (t1) == OFFSET_TYPE && TREE_CODE (t2) == OFFSET_TYPE)
+  if (comptypes (TYPE_MAIN_VARIANT (intype), TYPE_MAIN_VARIANT (type), 1))
+    return build_static_cast (type, expr);
+  else if (TREE_CODE (type) == REFERENCE_TYPE)
     {
-      if (TYPE_OFFSET_BASETYPE (t1) != TYPE_OFFSET_BASETYPE (t2))
+      if (! real_lvalue_p (expr))
        {
-         cp_error ("const_cast cannot convert between pointers to members of different types `%T' and `%T'",
-                   TYPE_OFFSET_BASETYPE (t2), TYPE_OFFSET_BASETYPE (t1));
+         cp_error ("const_cast from `%T' rvalue to `%T'", intype, type);
          return error_mark_node;
        }
-      t1 = TREE_TYPE (t1);
-      t2 = TREE_TYPE (t2);
-    }
 
-  if (TYPE_MAIN_VARIANT (t1) != TYPE_MAIN_VARIANT (t2))
-    {
-      cp_error ("const_cast cannot convert unrelated type `%T' to `%T'",
-               t2, t1);
-      return error_mark_node;
+      if (comp_ptr_ttypes_const (TREE_TYPE (type), intype))
+       return (convert_from_reference
+               (convert_to_reference (type, expr, CONV_CONST|CONV_IMPLICIT,
+                                      LOOKUP_COMPLAIN, NULL_TREE)));
     }
+  else if (TREE_CODE (type) == POINTER_TYPE
+          && TREE_CODE (intype) == POINTER_TYPE
+          && comp_ptr_ttypes_const (TREE_TYPE (type), TREE_TYPE (intype)))
+    return convert (type, expr);
 
-  return build_c_cast (type, expr, 0);
+  cp_error ("const_cast from `%T' to `%T'", intype, type);
+  return error_mark_node;
 }
 
 /* Build an expression representing a cast to type TYPE of expression EXPR.
@@ -5183,13 +5407,7 @@ build_c_cast (type, expr, allow_nonconverting)
       return error_mark_node;
     }
 
-  /* If there's only one function in the overloaded space,
-     just take it.  */
-  if (TREE_CODE (value) == TREE_LIST
-      && TREE_CHAIN (value) == NULL_TREE)
-    value = TREE_VALUE (value);
-
-  if (current_template_parms)
+  if (processing_template_decl)
     {
       tree t = build_min (CAST_EXPR, type,
                          min_tree_cons (NULL_TREE, value, NULL_TREE));
@@ -5215,7 +5433,11 @@ build_c_cast (type, expr, allow_nonconverting)
         convert references to their expanded types,
         but don't convert any other types.  */
       if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE
-         || TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE
+         || (TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE
+             /* Don't do the default conversion if we want a
+                pointer to a function.  */
+             && TREE_CODE (type) != POINTER_TYPE
+             && TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE)
          || TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
          || TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE)
        value = default_conversion (value);
@@ -5289,15 +5511,9 @@ build_c_cast (type, expr, allow_nonconverting)
     }
 
     /* Always produce some operator for an explicit cast,
-       so we can tell (for -pedantic) that the cast is no lvalue.
-       Also, pedantically, don't let (void *) (FOO *) 0 be a null
-       pointer constant.  */
-  if (TREE_CODE (type) != REFERENCE_TYPE
-      && (value == expr
-         || (pedantic
-             && TREE_CODE (value) == INTEGER_CST
-             && TREE_CODE (expr) == INTEGER_CST
-             && TREE_CODE (TREE_TYPE (expr)) != INTEGER_TYPE)))
+       so we can tell (for -pedantic) that the cast is no lvalue.  */
+  if (TREE_CODE (type) != REFERENCE_TYPE && value == expr
+      && real_lvalue_p (value))
     value = non_lvalue (value);
 
   return value;
@@ -5323,7 +5539,7 @@ expand_target_expr (t)
   do_pending_stack_adjust ();
   start_sequence_for_rtl_expr (xval);
   emit_note (0, -1);
-  rtxval = expand_expr (t, NULL, VOIDmode, 0);
+  rtxval = expand_expr (t, NULL_RTX, VOIDmode, 0);
   do_pending_stack_adjust ();
   TREE_SIDE_EFFECTS (xval) = 1;
   RTL_EXPR_SEQUENCE (xval) = get_insns ();
@@ -5342,8 +5558,8 @@ expand_target_expr (t)
    to combine the old value of LHS with RHS to get the new value.
    Or else MODIFYCODE is NOP_EXPR meaning do a simple assignment.
 
-   C++: If MODIFYCODE is INIT_EXPR, then leave references unbashed.
-*/
+   C++: If MODIFYCODE is INIT_EXPR, then leave references unbashed.  */
+
 tree
 build_modify_expr (lhs, modifycode, rhs)
      tree lhs;
@@ -5382,7 +5598,8 @@ build_modify_expr (lhs, modifycode, rhs)
     case PREINCREMENT_EXPR:
       if (TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0)))
        lhs = build (TREE_CODE (lhs), TREE_TYPE (lhs),
-                    stabilize_reference (TREE_OPERAND (lhs, 0)));
+                    stabilize_reference (TREE_OPERAND (lhs, 0)),
+                    TREE_OPERAND (lhs, 1));
       return build (COMPOUND_EXPR, lhstype,
                    lhs,
                    build_modify_expr (TREE_OPERAND (lhs, 0),
@@ -5471,9 +5688,9 @@ build_modify_expr (lhs, modifycode, rhs)
        /* Do the default thing */;
       else
        {
-         result = build_method_call (lhs, constructor_name_full (lhstype),
+         result = build_method_call (lhs, ctor_identifier,
                                      build_tree_list (NULL_TREE, rhs),
-                                     NULL_TREE, LOOKUP_NORMAL);
+                                     TYPE_BINFO (lhstype), LOOKUP_NORMAL);
          if (result == NULL_TREE)
            return error_mark_node;
          return result;
@@ -5492,10 +5709,8 @@ build_modify_expr (lhs, modifycode, rhs)
       else if (TYPE_HAS_TRIVIAL_ASSIGN_REF (lhstype)
               && TYPE_MAIN_VARIANT (lhstype) == TYPE_MAIN_VARIANT (TREE_TYPE (newrhs)))
        {
-         if (warn_synth)
-           /* If we care about this, do overload resolution.  */
-           build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
-                           lhs, rhs, make_node (NOP_EXPR));
+         build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
+                         lhs, rhs, make_node (NOP_EXPR));
 
          /* Do the default thing */;
        }
@@ -5524,7 +5739,7 @@ build_modify_expr (lhs, modifycode, rhs)
        }
       else
        {
-         cp_error ("no match for `%O(%#T, %#T)'", modifycode,
+         cp_error ("no match for `%Q(%#T, %#T)'", modifycode,
                    TREE_TYPE (lhs), TREE_TYPE (rhs));
          return error_mark_node;
        }
@@ -5533,6 +5748,12 @@ build_modify_expr (lhs, modifycode, rhs)
     {
       lhs = stabilize_reference (lhs);
       newrhs = build_binary_op (modifycode, lhs, rhs, 1);
+      if (newrhs == error_mark_node)
+       {
+         cp_error ("  in evaluation of `%Q(%#T, %#T)'", modifycode,
+                   TREE_TYPE (lhs), TREE_TYPE (rhs));
+         return error_mark_node;
+       }
     }
 
   /* Handle a cast used as an "lvalue".
@@ -5618,7 +5839,7 @@ build_modify_expr (lhs, modifycode, rhs)
     }
 
   /* check to see if there is an assignment to `this' */
-  if (lhs == current_class_decl)
+  if (lhs == current_class_ptr)
     {
       if (flag_this_is_variable > 0
          && DECL_NAME (current_function_decl) != NULL_TREE
@@ -5728,7 +5949,7 @@ build_modify_expr (lhs, modifycode, rhs)
     }
   else
     {
-      /* Avoid warnings on enum bit fields. */
+      /* Avoid warnings on enum bit fields.  */
       if (TREE_CODE (olhstype) == ENUMERAL_TYPE
          && TREE_CODE (lhstype) == INTEGER_TYPE)
        {
@@ -5749,7 +5970,7 @@ build_modify_expr (lhs, modifycode, rhs)
         expanded without a target.  */
       if (TREE_CODE (newrhs) == TARGET_EXPR)
        newrhs = build (COMPOUND_EXPR, TREE_TYPE (newrhs), newrhs,
-                       TREE_VALUE (newrhs));
+                       TREE_OPERAND (newrhs, 0));
     }
 
   if (TREE_CODE (newrhs) == ERROR_MARK)
@@ -5804,7 +6025,7 @@ build_modify_expr (lhs, modifycode, rhs)
   if (olhstype == TREE_TYPE (result))
     return result;
   /* Avoid warnings converting integral types back into enums
-     for enum bit fields. */
+     for enum bit fields.  */
   if (TREE_CODE (TREE_TYPE (result)) == INTEGER_TYPE
       && TREE_CODE (olhstype) == ENUMERAL_TYPE)
     {
@@ -5822,9 +6043,9 @@ build_x_modify_expr (lhs, modifycode, rhs)
      enum tree_code modifycode;
      tree rhs;
 {
-  if (current_template_parms)
+  if (processing_template_decl)
     return build_min_nt (MODOP_EXPR, lhs,
-                        build_min_nt (modifycode, 0, 0), rhs);
+                        build_min_nt (modifycode, NULL_TREE, NULL_TREE), rhs);
 
   if (modifycode != NOP_EXPR)
     {
@@ -5849,6 +6070,7 @@ language_lvalue_valid (exp)
 /* Get difference in deltas for different pointer to member function
    types.  Return integer_zero_node, if FROM cannot be converted to a
    TO type.  If FORCE is true, then allow reverse conversions as well.  */
+
 static tree
 get_delta_difference (from, to, force)
      tree from, to;
@@ -5868,7 +6090,7 @@ get_delta_difference (from, to, force)
   binfo = get_binfo (from, to, 1);
   if (binfo == error_mark_node)
     {
-      error ("   in pointer to member function conversion");
+      error ("   in pointer to member function conversiona");
       return delta;
     }
   if (binfo == 0)
@@ -5876,27 +6098,34 @@ get_delta_difference (from, to, force)
       if (!force)
        {
          error_not_base_type (from, to);
-         error ("   in pointer to member function conversion");
+         error ("   in pointer to member conversion");
          return delta;
        }
       binfo = get_binfo (to, from, 1);
       if (binfo == error_mark_node)
        {
-         error ("   in pointer to member function conversion");
+         if (!force)
+           error ("   in pointer to member conversion");
          return delta;
        }
       if (binfo == 0)
        {
-         error ("cannot convert pointer to member of type %T to unrelated pointer to member of type %T", from, to);
+         if (!force)
+           cp_error ("cannot convert pointer to member of type %T to unrelated pointer to member of type %T", from, to);
          return delta;
        }
       if (TREE_VIA_VIRTUAL (binfo))
        {
+         binfo = binfo_member (BINFO_TYPE (binfo),
+                               CLASSTYPE_VBASECLASSES (from));
          warning ("pointer to member conversion to virtual base class will only work if you are very careful");
        }
+      delta = BINFO_OFFSET (binfo);
+      delta = convert (ptrdiff_type_node, delta);
+      
       return build_binary_op (MINUS_EXPR,
                              integer_zero_node,
-                             BINFO_OFFSET (binfo), 1);
+                             delta, 1);
     }
   if (TREE_VIA_VIRTUAL (binfo))
     {
@@ -5905,6 +6134,79 @@ get_delta_difference (from, to, force)
   return BINFO_OFFSET (binfo);
 }
 
+static tree
+build_ptrmemfunc1 (type, delta, idx, pfn, delta2)
+     tree type, delta, idx, pfn, delta2;
+{
+  tree u;
+
+#if 0
+  /* This is the old way we did it.  We want to avoid calling
+     digest_init, so that it can give an error if we use { } when
+     initializing a pointer to member function.  */
+
+  if (pfn)
+    {
+      u = build_nt (CONSTRUCTOR, NULL_TREE,
+                   tree_cons (pfn_identifier, pfn, NULL_TREE));
+    }
+  else
+    {
+      u = build_nt (CONSTRUCTOR, NULL_TREE,
+                   tree_cons (delta2_identifier, delta2, NULL_TREE));
+    }
+
+  u = build_nt (CONSTRUCTOR, NULL_TREE,
+               tree_cons (NULL_TREE, delta,
+                          tree_cons (NULL_TREE, idx,
+                                     tree_cons (NULL_TREE, u, NULL_TREE))));
+
+  return digest_init (type, u, (tree*)0);
+#else
+  tree delta_field, idx_field, pfn_or_delta2_field, pfn_field, delta2_field;
+  tree subtype;
+  int allconstant, allsimple;
+
+  delta_field = TYPE_FIELDS (type);
+  idx_field = TREE_CHAIN (delta_field);
+  pfn_or_delta2_field = TREE_CHAIN (idx_field);
+  subtype = TREE_TYPE (pfn_or_delta2_field);
+  pfn_field = TYPE_FIELDS (subtype);
+  delta2_field = TREE_CHAIN (pfn_field);
+
+  if (pfn)
+    {
+      allconstant = TREE_CONSTANT (pfn);
+      allsimple = initializer_constant_valid_p (pfn, TREE_TYPE (pfn));
+      u = tree_cons (pfn_field, pfn, NULL_TREE);
+    }
+  else
+    {
+      delta2 = convert_and_check (delta_type_node, delta2);
+      allconstant = TREE_CONSTANT (delta2);
+      allsimple = initializer_constant_valid_p (delta2, TREE_TYPE (delta2));
+      u = tree_cons (delta2_field, delta2, NULL_TREE);
+    }
+
+  delta = convert_and_check (delta_type_node, delta);
+  idx = convert_and_check (delta_type_node, idx);
+
+  allconstant = allconstant && TREE_CONSTANT (delta) && TREE_CONSTANT (idx);
+  allsimple = allsimple
+    && initializer_constant_valid_p (delta, TREE_TYPE (delta))
+      && initializer_constant_valid_p (idx, TREE_TYPE (idx));
+
+  u = build (CONSTRUCTOR, subtype, NULL_TREE, u);
+  u = tree_cons (delta_field, delta,
+                tree_cons (idx_field, idx,
+                           tree_cons (pfn_or_delta2_field, u, NULL_TREE)));
+  u = build (CONSTRUCTOR, type, NULL_TREE, u);
+  TREE_CONSTANT (u) = allconstant;
+  TREE_STATIC (u) = allconstant && allsimple;
+  return u;
+#endif
+}
+
 /* Build a constructor for a pointer to member function.  It can be
    used to initialize global variables, local variable, or used
    as a value in expressions.  TYPE is the POINTER to METHOD_TYPE we
@@ -5921,117 +6223,82 @@ build_ptrmemfunc (type, pfn, force)
      tree type, pfn;
      int force;
 {
-  tree index = integer_zero_node;
+  tree idx = integer_zero_node;
   tree delta = integer_zero_node;
   tree delta2 = integer_zero_node;
   tree vfield_offset;
-  tree npfn;
+  tree npfn = NULL_TREE;
   tree u;
 
-  /* Handle multiple conversions of pointer to member functions. */
+  /* Handle multiple conversions of pointer to member functions.  */
   if (TYPE_PTRMEMFUNC_P (TREE_TYPE (pfn)))
     {
       tree ndelta, ndelta2, nindex;
+      tree e1, e2, e3, n;
+
       /* Is is already the right type? */
       if (type == TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))
        return pfn;
 
-      if (TREE_CODE (pfn) != CONSTRUCTOR)
-       {
-         tree e1, e2, e3;
-         ndelta = convert (ptrdiff_type_node, build_component_ref (pfn, delta_identifier, 0, 0));
-         ndelta2 = convert (ptrdiff_type_node, DELTA2_FROM_PTRMEMFUNC (pfn));
-         index = build_component_ref (pfn, index_identifier, 0, 0);
-         delta = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))),
-                                       TYPE_METHOD_BASETYPE (TREE_TYPE (type)),
-                                       force);
-         delta = build_binary_op (PLUS_EXPR, delta, ndelta, 1);
-         delta2 = build_binary_op (PLUS_EXPR, ndelta2, delta2, 1);
-         e1 = fold (build (GT_EXPR, boolean_type_node, index, integer_zero_node));
+      ndelta = convert (ptrdiff_type_node, build_component_ref (pfn, delta_identifier, NULL_TREE, 0));
+      ndelta2 = convert (ptrdiff_type_node, DELTA2_FROM_PTRMEMFUNC (pfn));
+      idx = build_component_ref (pfn, index_identifier, NULL_TREE, 0);
+
+      n = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))),
+                               TYPE_METHOD_BASETYPE (TREE_TYPE (type)),
+                               force);
+
+      delta = build_binary_op (PLUS_EXPR, ndelta, n, 1);
+      delta2 = build_binary_op (PLUS_EXPR, ndelta2, n, 1);
+      e1 = fold (build (GT_EXPR, boolean_type_node, idx, integer_zero_node));
          
-         u = build_nt (CONSTRUCTOR, 0, tree_cons (delta2_identifier, delta2, NULL_TREE));
-         u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, delta,
-                                                  tree_cons (NULL_TREE, index,
-                                                             tree_cons (NULL_TREE, u, NULL_TREE))));
-         e2 = digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0);
+      e2 = build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx,
+                             NULL_TREE, delta2);
 
-         pfn = PFN_FROM_PTRMEMFUNC (pfn);
-         npfn = build1 (NOP_EXPR, type, pfn);
-         TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
+      pfn = PFN_FROM_PTRMEMFUNC (pfn);
+      npfn = build1 (NOP_EXPR, type, pfn);
+      TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
 
-         u = build_nt (CONSTRUCTOR, 0, tree_cons (pfn_identifier, npfn, NULL_TREE));
-         u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, delta,
-                                                  tree_cons (NULL_TREE, index,
-                                                             tree_cons (NULL_TREE, u, NULL_TREE))));
-         e3 = digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0);
-         return build_conditional_expr (e1, e2, e3);
-       }
-
-      ndelta = TREE_VALUE (CONSTRUCTOR_ELTS (pfn));
-      nindex = TREE_VALUE (TREE_CHAIN (CONSTRUCTOR_ELTS (pfn)));
-      npfn = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (CONSTRUCTOR_ELTS (pfn))));
-      npfn = TREE_VALUE (CONSTRUCTOR_ELTS (npfn));
-      if (integer_zerop (nindex))
-       pfn = integer_zero_node;
-      else if (integer_zerop (fold (size_binop (PLUS_EXPR, nindex, integer_one_node))))
-       {
-         tree e3;
-         delta = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))),
-                                       TYPE_METHOD_BASETYPE (TREE_TYPE (type)),
-                                       force);
-         delta = build_binary_op (PLUS_EXPR, delta, ndelta, 1);
-         pfn = build1 (NOP_EXPR, type, npfn);
-         TREE_CONSTANT (pfn) = TREE_CONSTANT (npfn);
-
-         u = build_nt (CONSTRUCTOR, 0, tree_cons (pfn_identifier, pfn, NULL_TREE));
-         u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, delta,
-                                                  tree_cons (NULL_TREE, nindex,
-                                                             tree_cons (NULL_TREE, u, NULL_TREE))));
-         e3 = digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0);
-         return e3;
-       }
-      else
-       {
-         sorry ("value casting of variable nonnull pointer to member functions not supported");
-         return error_mark_node;
-       }
+      e3 = build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx, npfn,
+                             NULL_TREE);
+      return build_conditional_expr (e1, e2, e3);
     }
 
-  /* Handle null pointer to member function conversions. */
+  /* Handle null pointer to member function conversions.  */
   if (integer_zerop (pfn))
     {
       pfn = build_c_cast (type, integer_zero_node, 0);
-      u = build_nt (CONSTRUCTOR, 0, tree_cons (pfn_identifier, pfn, NULL_TREE));
-      u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, integer_zero_node,
-                                              tree_cons (NULL_TREE, integer_zero_node,
-                                                         tree_cons (NULL_TREE, u, NULL_TREE))));
-      return digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0);
+      return build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type),
+                               integer_zero_node, integer_zero_node,
+                               pfn, NULL_TREE);
     }
 
   if (TREE_CODE (pfn) == TREE_LIST
       || (TREE_CODE (pfn) == ADDR_EXPR
          && TREE_CODE (TREE_OPERAND (pfn, 0)) == TREE_LIST))
-    {
-      pfn = instantiate_type (type, pfn, 1);
-      if (pfn == error_mark_node)
-       return error_mark_node;
-      if (TREE_CODE (pfn) != ADDR_EXPR)
-       pfn = build_unary_op (ADDR_EXPR, pfn, 0);
-    }
+    return instantiate_type (type, pfn, 1);
 
-  /* Allow pointer to member conversions here. */
+  /* Allow pointer to member conversions here.  */
   delta = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (TREE_TYPE (pfn))),
                                TYPE_METHOD_BASETYPE (TREE_TYPE (type)),
                                force);
   delta2 = build_binary_op (PLUS_EXPR, delta2, delta, 1);
 
+#if 0
+  /* We need to check the argument types to see if they are compatible
+     (any const or volatile violations.  */
+  something like this:
+  comptype (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (type))),
+           TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (TREE_TYPE (pfn)))), ?);
+#endif
+
   if (TREE_CODE (TREE_OPERAND (pfn, 0)) != FUNCTION_DECL)
     warning ("assuming pointer to member function is non-virtual");
 
   if (TREE_CODE (TREE_OPERAND (pfn, 0)) == FUNCTION_DECL
       && DECL_VINDEX (TREE_OPERAND (pfn, 0)))
     {
-      /* Find the offset to the vfield pointer in the object. */
+      /* Find the offset to the vfield pointer in the object.  */
       vfield_offset = get_binfo (DECL_CONTEXT (TREE_OPERAND (pfn, 0)),
                                 DECL_CLASS_CONTEXT (TREE_OPERAND (pfn, 0)),
                                 0);
@@ -6039,25 +6306,26 @@ build_ptrmemfunc (type, pfn, force)
       delta2 = size_binop (PLUS_EXPR, vfield_offset, delta2);
 
       /* Map everything down one to make room for the null pointer to member.  */
-      index = size_binop (PLUS_EXPR,
-                         DECL_VINDEX (TREE_OPERAND (pfn, 0)),
-                         integer_one_node);
-      u = build_nt (CONSTRUCTOR, 0, tree_cons (delta2_identifier, delta2, NULL_TREE));
+      idx = size_binop (PLUS_EXPR,
+                       DECL_VINDEX (TREE_OPERAND (pfn, 0)),
+                       integer_one_node);
     }
   else
     {
-      index = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node);
+      idx = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node);
 
-      npfn = build1 (NOP_EXPR, type, pfn);
-      TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
-
-      u = build_nt (CONSTRUCTOR, 0, tree_cons (pfn_identifier, npfn, NULL_TREE));
+      if (type == TREE_TYPE (pfn))
+       {
+         npfn = pfn;
+       }
+      else
+       {
+         npfn = build1 (NOP_EXPR, type, pfn);
+         TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
+       }
     }
 
-  u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, delta,
-                                          tree_cons (NULL_TREE, index,
-                                                     tree_cons (NULL_TREE, u, NULL_TREE))));
-  return digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0);
+  return build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx, npfn, delta2);
 }
 
 /* Convert value RHS to type TYPE as preparation for an assignment
@@ -6258,13 +6526,13 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
              return error_mark_node;
            }
 
-         if (ctt < 0)
+         if (ctt < 0 && TYPE_MAIN_VARIANT (ttl) != TYPE_MAIN_VARIANT (ttr))
            cp_pedwarn ("converting `%T' to `%T' is a contravariance violation",
                        rhstype, type);
 
          if (TYPE_MAIN_VARIANT (ttl) != void_type_node
              && TYPE_MAIN_VARIANT (ttr) == void_type_node
-             && rhs != null_pointer_node)
+             && ! null_ptr_cst_p (rhs))
            {
              if (coder == RECORD_TYPE)
                cp_pedwarn ("implicit conversion of signature pointer to type `%T'",
@@ -6315,31 +6583,6 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
                }
            }
        }
-      else if (TREE_CODE (ttr) == OFFSET_TYPE
-              && TREE_CODE (ttl) != OFFSET_TYPE)
-       {
-         /* Normally, pointers to different type codes (other
-            than void) are not compatible, but we perform
-            some type instantiation if that resolves the
-            ambiguity of (X Y::*) and (X *).  */
-
-         if (current_class_decl)
-           {
-             if (TREE_CODE (rhs) == INTEGER_CST)
-               {
-                 rhs = build (PLUS_EXPR, build_pointer_type (TREE_TYPE (ttr)),
-                              current_class_decl, rhs);
-                 return convert_for_assignment (type, rhs,
-                                                errtype, fndecl, parmnum);
-               }
-           }
-         if (TREE_CODE (ttl) == METHOD_TYPE)
-           error ("%s between pointer-to-method and pointer-to-member types",
-                  errtype);
-         else
-           error ("%s between pointer and pointer-to-member types", errtype);
-         return error_mark_node;
-       }
       else
        {
          int add_quals = 0, const_parity = 0, volatile_parity = 0;
@@ -6431,24 +6674,6 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
                    cp_warning ("\t`%T' != `%T'", type, rhstype);
                  }
            }
-         else if (TREE_CODE (TREE_TYPE (rhs)) == METHOD_TYPE)
-           {
-             /* When does this happen?  */
-             my_friendly_abort (119);
-             /* Conversion of a pointer-to-member type to void *.  */
-             rhs = build_unary_op (ADDR_EXPR, rhs, 0);
-             TREE_TYPE (rhs) = type;
-             return rhs;
-           }
-         else if (TREE_CODE (TREE_TYPE (rhs)) == OFFSET_TYPE)
-           {
-             /* When does this happen?  */
-             my_friendly_abort (120);
-             /* Conversion of a pointer-to-member type to void *.  */
-             rhs = build_unary_op (ADDR_EXPR, rhs, 0);
-             TREE_TYPE (rhs) = type;
-             return rhs;
-           }
          else
            {
              if (fndecl)
@@ -6473,9 +6698,8 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
          else
            cp_pedwarn ("%s to `%T' from `%T' lacks a cast",
                        errtype, type, rhstype);
-         return convert (type, rhs);
        }
-      return null_pointer_node;
+      return convert (type, rhs);
     }
   else if (codel == INTEGER_TYPE
           && (coder == POINTER_TYPE
@@ -6518,7 +6742,7 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
       else if (ctt == 0)
        cp_error ("%s to `%T' from `%T'", errtype, ttl, ttr);
 
-      /* compatible pointer to member functions. */
+      /* compatible pointer to member functions.  */
       return build_ptrmemfunc (ttl, rhs, 0);
     }
   else if (codel == ERROR_MARK || coder == ERROR_MARK)
@@ -6537,6 +6761,13 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
     }
   else if (TYPE_HAS_CONSTRUCTOR (type) || IS_AGGR_TYPE (TREE_TYPE (rhs)))
     return convert (type, rhs);
+  /* Handle anachronistic conversions from (::*)() to void* or (*)().  */
+  else if (TREE_CODE (type) == POINTER_TYPE
+          && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
+              || TREE_TYPE (type) == void_type_node)
+          && TREE_TYPE (rhs)
+          && TYPE_PTRMEMFUNC_P (TREE_TYPE (rhs)))
+    return convert (type, rhs);
 
   cp_error ("%s to `%T' from `%T'", errtype, type, rhstype);
   return error_mark_node;
@@ -6557,6 +6788,7 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
    exist, an ambiguity exists.
 
    If flags doesn't include LOOKUP_COMPLAIN, don't complain about anything.  */
+
 tree
 convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
      tree exp, type, rhs;
@@ -6645,6 +6877,8 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
   if (TREE_CODE (rhstype) == REFERENCE_TYPE)
     rhstype = TREE_TYPE (rhstype);
 
+  type = complete_type (type);
+
   if (TYPE_LANG_SPECIFIC (type)
       && (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type)))
     return build_signature_pointer_constructor (type, rhs);
@@ -6688,7 +6922,7 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
        {
          if (TYPE_HAS_INIT_REF (type))
            {
-             tree init = build_method_call (exp, constructor_name_full (type),
+             tree init = build_method_call (exp, ctor_identifier,
                                             build_tree_list (NULL_TREE, rhs),
                                             TYPE_BINFO (type), LOOKUP_NORMAL);
 
@@ -6721,7 +6955,8 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
          return rhs;
        }
 
-      return cp_convert (type, rhs, CONV_OLD_CONVERT, flags);
+      return cp_convert (type, rhs, CONV_OLD_CONVERT,
+                        flags | LOOKUP_NO_CONVERSION);
     }
 
   if (type == TREE_TYPE (rhs))
@@ -6810,7 +7045,6 @@ c_expand_return (retval)
   extern tree dtor_label, ctor_label;
   tree result = DECL_RESULT (current_function_decl);
   tree valtype = TREE_TYPE (result);
-  int returns_value = 1;
 
   if (TREE_THIS_VOLATILE (current_function_decl))
     warning ("function declared `noreturn' has a `return' statement");
@@ -6821,7 +7055,7 @@ c_expand_return (retval)
       return;
     }
 
-  if (current_template_parms)
+  if (processing_template_decl)
     {
       add_tree (build_min_nt (RETURN_STMT, retval));
       return;
@@ -6839,7 +7073,7 @@ c_expand_return (retval)
        }
 
       if (DECL_CONSTRUCTOR_P (current_function_decl))
-       retval = current_class_decl;
+       retval = current_class_ptr;
       else if (DECL_NAME (result) != NULL_TREE
               && TREE_CODE (valtype) != VOID_TYPE)
        retval = result;
@@ -6864,22 +7098,22 @@ c_expand_return (retval)
        }
     }
   else if (DECL_CONSTRUCTOR_P (current_function_decl)
-          && retval != current_class_decl)
+          && retval != current_class_ptr)
     {
-      error ("return from a constructor: use `this = ...' instead");
-      retval = current_class_decl;
+      if (flag_this_is_variable)
+       error ("return from a constructor: use `this = ...' instead");
+      else
+       error ("return from a constructor");
+      retval = current_class_ptr;
     }
 
   if (valtype == NULL_TREE || TREE_CODE (valtype) == VOID_TYPE)
     {
       current_function_returns_null = 1;
-      /* We do this here so we'll avoid a warning about how the function
-        "may or may not return a value" in finish_function.  */
-      returns_value = 0;
-
-      if (retval)
+      if (pedantic || TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
        pedwarn ("`return' with a value, in function returning void");
       expand_return (retval);
+      return;
     }
   /* Add some useful error checking for C++.  */
   else if (TREE_CODE (valtype) == REFERENCE_TYPE)
@@ -6942,6 +7176,15 @@ c_expand_return (retval)
          && !TREE_PUBLIC (whats_returned))
        cp_warning_at ("address of local variable `%D' returned", whats_returned);
     }
+  else if (TREE_CODE (retval) == VAR_DECL)
+    {
+      if (TREE_CODE (TREE_TYPE (retval)) == ARRAY_TYPE
+         && DECL_NAME (retval)
+         && IDENTIFIER_LOCAL_VALUE (DECL_NAME (retval))
+         && !TREE_STATIC (retval)
+         && !TREE_PUBLIC (retval))
+       cp_warning_at ("address of local array `%D' returned", retval);
+    }
   
   /* Now deal with possible C++ hair:
      (1) Compute the return value.
@@ -6951,141 +7194,56 @@ c_expand_return (retval)
      (3) If an X(X&) constructor is defined, the return
      value must be returned via that.  */
 
-  /* If we're returning in a register, we can't initialize the
-     return value from a TARGET_EXPR.  */
-  if (TREE_CODE (retval) == TARGET_EXPR
-      && TYPE_MAIN_VARIANT (TREE_TYPE (retval)) == TYPE_MAIN_VARIANT (valtype)
-      && ! current_function_returns_struct)
-    retval = expand_target_expr (retval);
-
   if (retval == result
-      /* Watch out for constructors, which "return" aggregates
-        via initialization, but which otherwise "return" a pointer.  */
       || DECL_CONSTRUCTOR_P (current_function_decl))
+    /* It's already done for us.  */;
+  else if (TREE_TYPE (retval) == void_type_node)
     {
-      /* This is just an error--it's already been reported.  */
-      if (TYPE_SIZE (valtype) == NULL_TREE)
-       return;
-
-      if (TYPE_MODE (valtype) != BLKmode
-         && any_pending_cleanups (1))
-       retval = get_temp_regvar (valtype, retval);
-    }
-  else if (IS_AGGR_TYPE (valtype) && current_function_returns_struct)
-    {
-      expand_aggr_init (result, retval, 0, LOOKUP_ONLYCONVERTING);
-      expand_cleanups_to (NULL_TREE);
-      DECL_INITIAL (result) = NULL_TREE;
+      pedwarn ("return of void value in function returning non-void");
+      expand_expr_stmt (retval);
       retval = 0;
     }
   else
     {
-      if (TYPE_MODE (valtype) == VOIDmode)
-       {
-         if (TYPE_MODE (TREE_TYPE (result)) != VOIDmode
-             && warn_return_type)
-           warning ("return of void value in function returning non-void");
-         expand_expr_stmt (retval);
-         retval = 0;
-         result = 0;
-       }
-      else if (TYPE_MODE (valtype) != BLKmode
-              && any_pending_cleanups (1))
-       {
-         retval = get_temp_regvar (valtype, retval);
-         expand_cleanups_to (NULL_TREE);
-         result = 0;
-       }
-      else
+      /* We already did this above for refs, don't do it again.  */
+      if (TREE_CODE (valtype) != REFERENCE_TYPE)
+       retval = convert_for_initialization (NULL_TREE, valtype, retval,
+                                            LOOKUP_NORMAL,
+                                            "return", NULL_TREE, 0);
+
+      /* We can't initialize a register from a NEW_EXPR.  */
+      if (! current_function_returns_struct
+         && TREE_CODE (retval) == TARGET_EXPR
+         && TREE_CODE (TREE_OPERAND (retval, 0)) == NEW_EXPR)
+       retval = build (COMPOUND_EXPR, TREE_TYPE (retval), retval,
+                       TREE_OPERAND (retval, 0));
+
+      if (retval == error_mark_node)
        {
-         retval = convert_for_initialization (result, valtype, retval,
-                                              LOOKUP_NORMAL,
-                                              "return", NULL_TREE, 0);
-         DECL_INITIAL (result) = NULL_TREE;
+         /* Avoid warning about control reaching end of function.  */
+         expand_null_return ();
+         return;
        }
-      if (retval == error_mark_node)
-       return;
     }
 
-  emit_queue ();
-
   if (retval != NULL_TREE
       && TREE_CODE_CLASS (TREE_CODE (retval)) == 'd'
       && cond_stack == 0 && loop_stack == 0 && case_stack == 0)
     current_function_return_value = retval;
 
-  if (result)
+  if (ctor_label && TREE_CODE (ctor_label) != ERROR_MARK)
     {
-      /* Everything's great--RETVAL is in RESULT.  */
-      if (original_result_rtx)
-       {
-         store_expr (result, original_result_rtx, 0);
-         expand_cleanups_to (NULL_TREE);
-         use_variable (DECL_RTL (result));
-         if (ctor_label  && TREE_CODE (ctor_label) != ERROR_MARK)
-           expand_goto (ctor_label);
-         else
-           expand_null_return ();
-       }
-      else if (retval && retval != result)
-       {
-         /* Clear this out so the later call to decl_function_context
-            won't end up bombing on us.  */
-         if (DECL_CONTEXT (result) == error_mark_node)
-           DECL_CONTEXT (result) = NULL_TREE;
-         /* Here is where we finally get RETVAL into RESULT.
-            `expand_return' does the magic of protecting
-            RESULT from cleanups.  */
-         retval = fold (build1 (CLEANUP_POINT_EXPR, TREE_TYPE (result),
-                                retval));
-         /* This part _must_ come second, because expand_return looks for
-            the INIT_EXPR as the toplevel node only.  :-( */
-         retval = build (INIT_EXPR, TREE_TYPE (result), result, retval);
-         TREE_SIDE_EFFECTS (retval) = 1;
-         expand_return (retval);
-       }
-      else
-       expand_return (result);
+      /* Here RETVAL is CURRENT_CLASS_PTR, so there's nothing to do.  */
+      expand_goto (ctor_label);
     }
-  else
+
+  if (retval && retval != result)
     {
-      /* We may still need to put RETVAL into RESULT.  */
-      result = DECL_RESULT (current_function_decl);
-      if (original_result_rtx)
-       {
-         /* Here we have a named return value that went
-            into memory.  We can compute RETVAL into that.  */
-         if (retval)
-           expand_assignment (result, retval, 0, 0);
-         else
-           store_expr (result, original_result_rtx, 0);
-         result = make_tree (TREE_TYPE (result), original_result_rtx);
-       }
-      else if (ctor_label && TREE_CODE (ctor_label) != ERROR_MARK)
-       {
-         /* Here RETVAL is CURRENT_CLASS_DECL, so there's nothing to do.  */
-         expand_goto (ctor_label);
-       }
-      else if (retval)
-       {
-         /* Here is where we finally get RETVAL into RESULT.
-            `expand_return' does the magic of protecting
-            RESULT from cleanups.  */
-         result = build (INIT_EXPR, TREE_TYPE (result), result, retval);
-         TREE_SIDE_EFFECTS (result) = 1;
-         expand_return (result);
-       }
-      else if (TYPE_MODE (TREE_TYPE (result)) != VOIDmode)
-       expand_return (result);
+      result = build (INIT_EXPR, TREE_TYPE (result), result, retval);
+      TREE_SIDE_EFFECTS (result) = 1;
     }
-
-  current_function_returns_value = returns_value;
-
-  /* One way to clear out cleanups that EXPR might
-     generate.  Note that this code will really be
-     dead code, but that is ok--cleanups that were
-     needed were handled by the magic of `return'.  */
-  expand_cleanups_to (NULL_TREE);
+  expand_return (result);
+  current_function_returns_value = 1;
 }
 \f
 /* Start a C switch statement, testing expression EXP.
@@ -7121,18 +7279,18 @@ c_expand_start_case (exp)
     }
   else
     {
-      tree index;
+      tree idx;
 
       exp = default_conversion (exp);
       type = TREE_TYPE (exp);
-      index = get_unwidened (exp, 0);
+      idx = get_unwidened (exp, 0);
       /* We can't strip a conversion from a signed type to an unsigned,
         because if we did, int_fits_type_p would do the wrong thing
         when checking case values for being in range,
         and it's too hard to do the right thing.  */
       if (TREE_UNSIGNED (TREE_TYPE (exp))
-         == TREE_UNSIGNED (TREE_TYPE (index)))
-       exp = index;
+         == TREE_UNSIGNED (TREE_TYPE (idx)))
+       exp = idx;
     }
 
   expand_start_case
@@ -7144,6 +7302,7 @@ c_expand_start_case (exp)
 
 /* CONSTP remembers whether or not all the intervening pointers in the `to'
    type have been const.  */
+
 int
 comp_ptr_ttypes_real (to, from, constp)
      tree to, from;
@@ -7154,6 +7313,11 @@ comp_ptr_ttypes_real (to, from, constp)
       if (TREE_CODE (to) != TREE_CODE (from))
        return 0;
 
+      if (TREE_CODE (from) == OFFSET_TYPE
+         && comptypes (TYPE_OFFSET_BASETYPE (from),
+                       TYPE_OFFSET_BASETYPE (to), 1))
+         continue;
+
       /* Const and volatile mean something different for function types,
         so the usual checks are not appropriate.  */
       if (TREE_CODE (to) != FUNCTION_TYPE && TREE_CODE (to) != METHOD_TYPE)
@@ -7177,9 +7341,92 @@ comp_ptr_ttypes_real (to, from, constp)
 /* When comparing, say, char ** to char const **, this function takes the
    'char *' and 'char const *'.  Do not pass non-pointer types to this
    function.  */
+
 int
 comp_ptr_ttypes (to, from)
      tree to, from;
 {
   return comp_ptr_ttypes_real (to, from, 1);
 }
+
+/* Returns 1 if to and from are (possibly multi-level) pointers to the same
+   type or inheritance-related types, regardless of cv-quals.  */
+
+int
+ptr_reasonably_similar (to, from)
+     tree to, from;
+{
+  for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
+    {
+      if (TREE_CODE (to) != TREE_CODE (from))
+       return 0;
+
+      if (TREE_CODE (from) == OFFSET_TYPE
+         && comptypes (TYPE_OFFSET_BASETYPE (to),
+                       TYPE_OFFSET_BASETYPE (from), -1))
+       continue;
+
+      if (TREE_CODE (to) != POINTER_TYPE)
+       return comptypes
+         (TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from), -1);
+    }
+}
+
+/* Like comp_ptr_ttypes, for const_cast.  */
+
+int
+comp_ptr_ttypes_const (to, from)
+     tree to, from;
+{
+  for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
+    {
+      if (TREE_CODE (to) != TREE_CODE (from))
+       return 0;
+
+      if (TREE_CODE (from) == OFFSET_TYPE
+         && comptypes (TYPE_OFFSET_BASETYPE (from),
+                       TYPE_OFFSET_BASETYPE (to), 1))
+         continue;
+
+      if (TREE_CODE (to) != POINTER_TYPE)
+       return comptypes (TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from), 1);
+    }
+}
+
+/* Like comp_ptr_ttypes, for reinterpret_cast.  */
+
+int
+comp_ptr_ttypes_reinterpret (to, from)
+     tree to, from;
+{
+  int constp = 1;
+
+  for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
+    {
+      if (TREE_CODE (from) == OFFSET_TYPE)
+       from = TREE_TYPE (from);
+      if (TREE_CODE (to) == OFFSET_TYPE)
+       to = TREE_TYPE (to);
+
+      if (TREE_CODE (to) != TREE_CODE (from))
+       return 1;
+
+      /* Const and volatile mean something different for function types,
+        so the usual checks are not appropriate.  */
+      if (TREE_CODE (to) != FUNCTION_TYPE && TREE_CODE (to) != METHOD_TYPE)
+       {
+         if (TYPE_READONLY (from) > TYPE_READONLY (to)
+             || TYPE_VOLATILE (from) > TYPE_VOLATILE (to))
+           return 0;
+
+         if (! constp
+             && (TYPE_READONLY (to) > TYPE_READONLY (from)
+                 || TYPE_VOLATILE (to) > TYPE_READONLY (from)))
+           return 0;
+         constp &= TYPE_READONLY (to);
+       }
+
+      if (TREE_CODE (to) != POINTER_TYPE)
+       return 1;
+    }
+}