class.c (instantiate_type): Don't just return a known type if it's wrong.
[gcc.git] / gcc / cp / typeck.c
index 23630983e3d2a9ab1a862c38d3459a2732b6c5a9..5009644eabbf4e72956c3689eee91952b6acc06b 100644 (file)
@@ -1,5 +1,5 @@
 /* Build expressions with type checking for C++ compiler.
-   Copyright (C) 1987, 88, 89, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 92-96, 1997 Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
@@ -29,9 +29,6 @@ Boston, MA 02111-1307, USA.  */
    and to process initializations in declarations (since they work
    like a strange sort of assignment).  */
 
-extern void error ();
-extern void warning ();
-
 #include "config.h"
 #include <stdio.h>
 #include "tree.h"
@@ -39,22 +36,32 @@ extern void warning ();
 #include "cp-tree.h"
 #include "flags.h"
 #include "output.h"
+#include "expr.h"
 
-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 PROTO((enum tree_code, register tree, register tree));
-static tree pointer_diff PROTO((register tree, register tree));
-#if 0
-static tree convert_sequence ();
+#ifdef HAVE_STRING_H
+#include <string.h>
 #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;
-extern int warn_synth;
+extern void compiler_error ();
+
+static tree convert_for_assignment PROTO((tree, tree, char*, tree,
+                                         int));
+static tree pointer_int_sum PROTO((enum tree_code, tree, tree));
+static tree rationalize_conditional_expr PROTO((enum tree_code, tree));
+static int comp_target_parms PROTO((tree, tree, int));
+static int comp_ptr_ttypes_real PROTO((tree, tree, int));
+static int comp_ptr_ttypes_const PROTO((tree, tree));
+static int comp_ptr_ttypes_reinterpret PROTO((tree, tree));
+static int comp_array_types PROTO((int (*) (tree, tree, int), tree,
+                                  tree, int));
+static tree build_ptrmemfunc1 PROTO((tree, tree, tree, tree, tree));
+static tree common_base_type PROTO((tree, tree));
+static tree convert_sequence PROTO((tree, tree));
+static tree lookup_anon_field PROTO((tree, tree));
+static tree pointer_diff PROTO((tree, tree, tree));
+static tree qualify_type PROTO((tree, tree));
+static tree expand_target_expr PROTO((tree));
+static tree get_delta_difference PROTO((tree, tree, int));
 
 /* Return the target type of TYPE, which meas return T for:
    T*, T&, T[], T (...), and otherwise, just T.  */
@@ -356,6 +363,24 @@ common_type (t1, t2)
   code1 = TREE_CODE (t1);
   code2 = TREE_CODE (t2);
 
+  /* If one type is complex, form the common type of the non-complex
+     components, then make that complex.  Use T1 or T2 if it is the
+     required type.  */
+  if (code1 == COMPLEX_TYPE || code2 == COMPLEX_TYPE)
+    {
+      tree subtype1 = code1 == COMPLEX_TYPE ? TREE_TYPE (t1) : t1;
+      tree subtype2 = code2 == COMPLEX_TYPE ? TREE_TYPE (t2) : t2;
+      tree subtype = common_type (subtype1, subtype2);
+
+      if (code1 == COMPLEX_TYPE && TREE_TYPE (t1) == subtype)
+       return build_type_attribute_variant (t1, attributes);
+      else if (code2 == COMPLEX_TYPE && TREE_TYPE (t2) == subtype)
+       return build_type_attribute_variant (t2, attributes);
+      else
+       return build_type_attribute_variant (build_complex_type (subtype),
+                                            attributes);
+    }
+
   switch (code1)
     {
     case INTEGER_TYPE:
@@ -426,6 +451,10 @@ common_type (t1, t2)
          target = tt1;
        else if (tt1 == void_type_node || tt2 == void_type_node)
          target = void_type_node;
+       else if (tt1 == unknown_type_node)
+         target = tt2;
+       else if (tt2 == unknown_type_node)
+         target = tt1;
        else
          target = common_type (tt1, tt2);
 
@@ -572,7 +601,7 @@ compexcepttypes (t1, t2)
 
 static int
 comp_array_types (cmp, t1, t2, strict)
-     register int (*cmp)();
+     register int (*cmp) PROTO((tree, tree, int));
      tree t1, t2;
      int strict;
 {
@@ -618,9 +647,9 @@ comp_array_types (cmp, t1, t2, strict)
        0 : <= (compared according to C++)
        -1: <= or >= (relaxed)
 
-   Otherwise, pointers involving base classes and derived classes
-   can be mixed as valid: i.e. a pointer to a base class may be assigned
-   to a pointer to one of its derived classes, as per C++. A pointer to
+   Otherwise, pointers involving base classes and derived classes can
+   be mixed as valid: i.e. a pointer to a derived class may be converted
+   to a pointer to one of its base classes, as per C++. A pointer to
    a derived class may be passed as a parameter to a function expecting a
    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
@@ -807,19 +836,56 @@ comptypes (type1, type2, strict)
       val = comp_array_types (comptypes, t1, t2, strict);
       break;
 
+    case TEMPLATE_TEMPLATE_PARM:
+      if (TEMPLATE_TYPE_IDX (t1) != TEMPLATE_TYPE_IDX (t2)
+         || TEMPLATE_TYPE_LEVEL (t1) != TEMPLATE_TYPE_LEVEL (t2))
+       return 0;
+
+      if (CLASSTYPE_TEMPLATE_INFO (t1) && CLASSTYPE_TEMPLATE_INFO (t2))
+       {
+         int i = TREE_VEC_LENGTH (CLASSTYPE_TI_ARGS (t1));
+         tree *p1 = &TREE_VEC_ELT (CLASSTYPE_TI_ARGS (t1), 0);
+         tree *p2 = &TREE_VEC_ELT (CLASSTYPE_TI_ARGS (t2), 0);
+       
+         while (i--)
+           {
+             if (TREE_CODE_CLASS (TREE_CODE (p1[i])) == 't')
+               {
+                 if (! comptypes (p1[i], p2[i], 1))
+                   return 0;
+               }
+             else
+               {
+                 if (simple_cst_equal (p1[i], p2[i]) <= 0)
+                   return 0;
+               }
+           }
+         return 1;
+       }
+      else if (CLASSTYPE_TEMPLATE_INFO (t1) || CLASSTYPE_TEMPLATE_INFO (t2))
+       return 0;
+      else
+       return 1;
+
     case TEMPLATE_TYPE_PARM:
-      return TEMPLATE_TYPE_IDX (t1) == TEMPLATE_TYPE_IDX (t2);
+      return TEMPLATE_TYPE_IDX (t1) == TEMPLATE_TYPE_IDX (t2)
+       && TEMPLATE_TYPE_LEVEL (t1) == TEMPLATE_TYPE_LEVEL (t2);
 
     case TYPENAME_TYPE:
       if (TYPE_IDENTIFIER (t1) != TYPE_IDENTIFIER (t2))
        return 0;
       return comptypes (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2), 1);
+
+    default:
+      break;
     }
   return attrval == 2 && val == 1 ? 2 : val;
 }
 
-/* Return 1 if TTL and TTR are pointers to types that are equivalent,
-   ignoring their qualifiers.
+/* Return 1 or -1 if TTL and TTR are pointers to types that are equivalent,
+   ignoring their qualifiers, 0 if not. Return 1 means that TTR can be
+   converted to TTL. Return -1 means that TTL can be converted to TTR but
+   not vice versa.
 
    NPTRS is the number of pointers we can strip off and keep cool.
    This is used to permit (for aggr A, aggr B) A, B* to convert to A*,
@@ -845,7 +911,10 @@ comp_target_types (ttl, ttr, nptrs)
 
       if (nptrs > 0)
        {
-         if (TREE_CODE (ttl) == VOID_TYPE
+         if (TREE_CODE (ttl) == UNKNOWN_TYPE
+             || TREE_CODE (ttr) == UNKNOWN_TYPE)
+           return 1;
+         else if (TREE_CODE (ttl) == VOID_TYPE
                   && TREE_CODE (ttr) != FUNCTION_TYPE
                   && TREE_CODE (ttr) != METHOD_TYPE
                   && TREE_CODE (ttr) != OFFSET_TYPE)
@@ -897,7 +966,7 @@ comp_target_types (ttl, ttr, nptrs)
   if (TREE_CODE (ttr) == ARRAY_TYPE)
     return comp_array_types (comp_target_types, ttl, ttr, 0);
   else if (TREE_CODE (ttr) == FUNCTION_TYPE || TREE_CODE (ttr) == METHOD_TYPE)
-    if (comp_target_types (TREE_TYPE (ttl), TREE_TYPE (ttr), nptrs))
+    if (comp_target_types (TREE_TYPE (ttl), TREE_TYPE (ttr), -1))
       switch (comp_target_parms (TYPE_ARG_TYPES (ttl), TYPE_ARG_TYPES (ttr), 1))
        {
        case 0:
@@ -942,7 +1011,7 @@ comp_target_types (ttl, ttr, nptrs)
    If there is not a unique most-derived base type, this function
    returns ERROR_MARK_NODE.  */
 
-tree
+static tree
 common_base_type (tt1, tt2)
      tree tt1, tt2;
 {
@@ -1049,7 +1118,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
+static int
 comp_target_parms (parms1, parms2, strict)
      tree parms1, parms2;
      int strict;
@@ -1405,6 +1474,9 @@ c_alignof (type)
   enum tree_code code = TREE_CODE (type);
   tree t;
 
+  if (processing_template_decl)
+    return build_min (ALIGNOF_EXPR, sizetype, type);
+
   if (code == FUNCTION_TYPE || code == METHOD_TYPE)
     return size_int (FUNCTION_BOUNDARY / BITS_PER_UNIT);
 
@@ -1508,9 +1580,9 @@ decay_conversion (exp)
              inner = build1 (CONVERT_EXPR,
                              build_pointer_type (TREE_TYPE (TREE_TYPE (inner))),
                              inner);
-             TREE_REFERENCE_EXPR (inner) = 1;
+             TREE_CONSTANT (inner) = TREE_CONSTANT (TREE_OPERAND (inner, 0));
            }
-         return convert (build_pointer_type (TREE_TYPE (type)), inner);
+         return cp_convert (build_pointer_type (TREE_TYPE (type)), inner);
        }
 
       if (TREE_CODE (exp) == COMPOUND_EXPR)
@@ -1559,7 +1631,7 @@ decay_conversion (exp)
       /* This way is better for a COMPONENT_REF since it can
         simplify the offset for a component.  */
       adr = build_unary_op (ADDR_EXPR, exp, 1);
-      return convert (ptrtype, adr);
+      return cp_convert (ptrtype, adr);
     }
 
   return exp;
@@ -1581,7 +1653,7 @@ default_conversion (exp)
     {
       tree t = type_promotes_to (type);
       if (t != type)
-       return convert (t, exp);
+       return cp_convert (t, exp);
     }
 
   return exp;
@@ -1635,29 +1707,46 @@ build_object_ref (datum, basetype, field)
   return error_mark_node;
 }
 
-/* Like `build_component_ref, but uses an already found field.
-   Must compute access for current_class_ref.  Otherwise, ok.  */
+/* Like `build_component_ref, but uses an already found field, and converts
+   from a reference.  Must compute access for current_class_ref.
+   Otherwise, ok.  */
 
 tree
 build_component_ref_1 (datum, field, protect)
      tree datum, field;
      int protect;
 {
-  return build_component_ref (datum, field, NULL_TREE, protect);
+  return convert_from_reference
+    (build_component_ref (datum, field, NULL_TREE, protect));
 }
 
-/* Given a COND_EXPR in T, return it in a form that we can, for
-   example, use as an lvalue.  This code used to be in unary_complex_lvalue,
-   but we needed it to deal with `a = (d == c) ? b : c' expressions, where
-   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.  */
+/* Given a COND_EXPR, MIN_EXPR, or MAX_EXPR in T, return it in a form that we
+   can, for example, use as an lvalue.  This code used to be in
+   unary_complex_lvalue, but we needed it to deal with `a = (d == c) ? b : c'
+   expressions, where we're dealing with aggregates.  But now it's again only
+   called from unary_complex_lvalue.  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;
      tree t;
 {
+  /* For MIN_EXPR or MAX_EXPR, fold-const.c has arranged things so that
+     the first operand is always the one to be used if both operands
+     are equal, so we know what conditional expression this used to be.  */
+  if (TREE_CODE (t) == MIN_EXPR || TREE_CODE (t) == MAX_EXPR)
+    {
+      return
+       build_conditional_expr (build_x_binary_op ((TREE_CODE (t) == MIN_EXPR
+                                                   ? LE_EXPR : GE_EXPR),
+                                                  TREE_OPERAND (t, 0),
+                                                  TREE_OPERAND (t, 1)),
+                           build_unary_op (code, TREE_OPERAND (t, 0), 0),
+                           build_unary_op (code, TREE_OPERAND (t, 1), 0));
+    }
+
   return
     build_conditional_expr (TREE_OPERAND (t, 0),
                            build_unary_op (code, TREE_OPERAND (t, 1), 0),
@@ -1736,6 +1825,14 @@ build_component_ref (datum, component, basetype_path, protect)
                              basetype_path, protect),
         build_component_ref (TREE_OPERAND (datum, 2), component,
                              basetype_path, protect));
+
+    case TEMPLATE_DECL:
+      cp_error ("invalid use of %D", datum);
+      datum = error_mark_node;
+      break;
+
+    default:
+      break;
     }
 
   code = TREE_CODE (basetype);
@@ -1848,7 +1945,8 @@ build_component_ref (datum, component, basetype_path, protect)
                          fndecl = build_vfn_ref (&addr, datum, DECL_VINDEX (fndecl));
                          TREE_TYPE (fndecl) = build_pointer_type (fntype);
                        }
-                     mark_used (fndecl);
+                     else
+                       mark_used (fndecl);
                      return build (OFFSET_REF, TREE_TYPE (fndecl), datum, fndecl);
                    }
                  if (access == access_protected_node)
@@ -2020,6 +2118,7 @@ build_indirect_ref (ptr, errorstring)
   if (TREE_CODE (type) == POINTER_TYPE || TREE_CODE (type) == REFERENCE_TYPE)
     {
       if (TREE_CODE (pointer) == ADDR_EXPR
+         && !flag_volatile
          && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (pointer, 0)))
              == TYPE_MAIN_VARIANT (TREE_TYPE (type)))
          && (TREE_READONLY (TREE_OPERAND (pointer, 0))
@@ -2033,10 +2132,13 @@ build_indirect_ref (ptr, errorstring)
          register tree ref = build1 (INDIRECT_REF,
                                      TYPE_MAIN_VARIANT (t), pointer);
 
+         /* We *must* set TREE_READONLY when dereferencing a pointer to const,
+            so that we get the proper error message if the result is used
+            to assign to.  Also, &* is supposed to be a no-op.  */
          TREE_READONLY (ref) = TYPE_READONLY (t);
-         TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t);
          TREE_SIDE_EFFECTS (ref)
-           = TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer);
+           = TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer) || flag_volatile;
+         TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t);
          return ref;
        }
     }
@@ -2070,16 +2172,6 @@ build_indirect_ref (ptr, errorstring)
    integer type.  Otherwise, to make a compatible PLUS_EXPR, it
    will inherit the type of the array, which will be some pointer type.  */
 
-tree
-build_x_array_ref (array, idx)
-     tree array, idx;
-{
-  tree rval = build_opfncall (ARRAY_REF, LOOKUP_NORMAL, array, idx, NULL_TREE);
-  if (rval)
-    return rval;
-  return build_array_ref (array, idx);
-}
-
 tree
 build_array_ref (array, idx)
      tree array, idx;
@@ -2236,6 +2328,7 @@ build_x_function_call (function, params, decl)
      tree function, params, decl;
 {
   tree type;
+  tree template_id = NULL_TREE;
   int is_method;
 
   if (function == error_mark_node)
@@ -2244,6 +2337,13 @@ build_x_function_call (function, params, decl)
   if (processing_template_decl)
     return build_min_nt (CALL_EXPR, function, params, NULL_TREE);
 
+  /* Save explicit template arguments if found */
+  if (TREE_CODE (function) == TEMPLATE_ID_EXPR)
+    {
+      template_id = function;
+      function = TREE_OPERAND (function, 0);
+    }
+
   type = TREE_TYPE (function);
 
   if (TREE_CODE (type) == OFFSET_TYPE
@@ -2279,7 +2379,8 @@ build_x_function_call (function, params, decl)
     {
       tree basetype = NULL_TREE;
 
-      if (TREE_CODE (function) == FUNCTION_DECL)
+      if (TREE_CODE (function) == FUNCTION_DECL
+         || DECL_FUNCTION_TEMPLATE_P (function))
        {
          basetype = DECL_CLASS_CONTEXT (function);
 
@@ -2337,6 +2438,9 @@ build_x_function_call (function, params, decl)
          decl = build_indirect_ref (decl, NULL_PTR);
        }
 
+      /* Put back explicit template arguments, if any.  */
+      if (template_id)
+        function = template_id;
       return build_method_call (decl, function, params,
                                NULL_TREE, LOOKUP_NORMAL);
     }
@@ -2352,7 +2456,7 @@ build_x_function_call (function, params, decl)
       return build_method_call (decl, function, params,
                                NULL_TREE, LOOKUP_NORMAL);
     }
-  else if (TREE_CODE (function) == TREE_LIST)
+  else if (really_overloaded_fn (function))
     {
       if (TREE_VALUE (function) == NULL_TREE)
        {
@@ -2365,7 +2469,12 @@ 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);
+           {
+             /* Put back explicit template arguments, if any.  */
+             if (template_id)
+               function = template_id;
+             return build_new_function_call (function, params);
+           }
 
          if (TREE_CODE (val) == TEMPLATE_DECL)
            return build_overload_call_real
@@ -2393,7 +2502,7 @@ build_x_function_call (function, params, decl)
       decl_addr = build_unary_op (ADDR_EXPR, decl, 0);
       function = get_member_function_from_ptrfunc (&decl_addr,
                                                   TREE_OPERAND (function, 1));
-      params = tree_cons (NULL_TREE, decl_addr, params);
+      params = expr_tree_cons (NULL_TREE, decl_addr, params);
       return build_function_call (function, params);
     }
 
@@ -2443,7 +2552,7 @@ build_x_function_call (function, params, decl)
        }
       else
        decl = build_c_cast (ctypeptr, decl);
-      params = tree_cons (NULL_TREE, decl, params);
+      params = expr_tree_cons (NULL_TREE, decl, params);
     }
 
   return build_function_call (function, params);
@@ -2476,16 +2585,22 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
        function = save_expr (function);
 
       fntype = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function));
-      idx = save_expr (build_component_ref (function,
-                                           index_identifier,
-                                           NULL_TREE, 0));
-      e1 = fold (build (GT_EXPR, boolean_type_node, idx,
-                       convert (delta_type_node, integer_zero_node)));
-      delta = convert (ptrdiff_type_node,
-                      build_component_ref (function, delta_identifier, NULL_TREE, 0));
+
+      /* Promoting idx before saving it improves performance on RISC
+        targets.  Without promoting, the first compare used
+        load-with-sign-extend, while the second used normal load then
+        shift to sign-extend.  An optimizer flaw, perhaps, but it's easier
+        to make this change.  */
+      idx = save_expr (default_conversion
+                      (build_component_ref (function,
+                                            index_identifier,
+                                            NULL_TREE, 0)));
+      e1 = build_binary_op (GT_EXPR, idx, integer_zero_node, 1);
+      delta = cp_convert (ptrdiff_type_node,
+                         build_component_ref (function, delta_identifier, NULL_TREE, 0));
       delta2 = DELTA2_FROM_PTRMEMFUNC (function);
 
-      /* convert down to the right base, before using the instance.  */
+      /* Convert down to the right base, before using the instance.  */
       instance
        = convert_pointer_to_real (TYPE_METHOD_BASETYPE (TREE_TYPE (fntype)),
                                   instance_ptr);
@@ -2496,7 +2611,7 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
       vtbl
        = build (PLUS_EXPR,
                 build_pointer_type (build_pointer_type (vtable_entry_type)),
-                vtbl, convert (ptrdiff_type_node, delta2));
+                vtbl, cp_convert (ptrdiff_type_node, delta2));
       vtbl = build_indirect_ref (vtbl, NULL_PTR);
       aref = build_array_ref (vtbl, build_binary_op (MINUS_EXPR,
                                                     idx,
@@ -2575,12 +2690,6 @@ build_function_call_real (function, params, require_complete, flags)
          pedwarn ("ANSI C++ forbids calling `main' from within program");
        }
 
-      if (pedantic && DECL_THIS_INLINE (function) && ! DECL_INITIAL (function)
-         && ! DECL_ARTIFICIAL (function)
-         && ! DECL_PENDING_INLINE_INFO (function))
-       cp_pedwarn ("inline function `%#D' called before definition",
-                   function);
-
       /* Differs from default_conversion by not setting TREE_ADDRESSABLE
         (because calling an inline function does not mean the function
         needs to be separately compiled).  */
@@ -2614,7 +2723,8 @@ build_function_call_real (function, params, require_complete, flags)
 
   if (!((TREE_CODE (fntype) == POINTER_TYPE
         && TREE_CODE (TREE_TYPE (fntype)) == FUNCTION_TYPE)
-       || is_method))
+       || is_method
+       || TREE_CODE (function) == TEMPLATE_ID_EXPR))
     {
       cp_error ("`%E' cannot be used as a function", function);
       return error_mark_node;
@@ -2659,6 +2769,9 @@ build_function_call_real (function, params, require_complete, flags)
        if (coerced_params == 0)
          return integer_zero_node;
        return build_unary_op (ABS_EXPR, TREE_VALUE (coerced_params), 0);
+
+      default:
+       break;
       }
 
   /* C++ */
@@ -2777,18 +2890,12 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
          /* Strip the `&' from an overloaded FUNCTION_DECL.  */
          if (TREE_CODE (val) == ADDR_EXPR)
            val = TREE_OPERAND (val, 0);
-         if (TREE_CODE (val) == TREE_LIST
-             && TREE_CHAIN (val) == NULL_TREE
-             && TREE_TYPE (TREE_VALUE (val)) != NULL_TREE
-             && (TREE_TYPE (val) == unknown_type_node
-                 || DECL_CHAIN (TREE_VALUE (val)) == NULL_TREE))
-           /* Instantiates automatically.  */
-           val = TREE_VALUE (val);
+         if (really_overloaded_fn (val))
+           cp_error ("insufficient type information to resolve address of overloaded function `%D'",
+                     DECL_NAME (get_first_fn (val)));
          else
-           {
-             error ("insufficient type information in parameter list");
-             val = integer_zero_node;
-           }
+           error ("insufficient type information in parameter list");
+         val = integer_zero_node;
        }
       else if (TREE_CODE (val) == OFFSET_REF
            && TREE_CODE (TREE_TYPE (val)) == METHOD_TYPE)
@@ -2845,7 +2952,7 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
          if (parmval == error_mark_node)
            return error_mark_node;
 
-         result = tree_cons (NULL_TREE, parmval, result);
+         result = expr_tree_cons (NULL_TREE, parmval, result);
        }
       else
        {
@@ -2856,17 +2963,17 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
              && (TYPE_PRECISION (TREE_TYPE (val))
                  < TYPE_PRECISION (double_type_node)))
            /* Convert `float' to `double'.  */
-           result = tree_cons (NULL_TREE, convert (double_type_node, val), result);
+           result = expr_tree_cons (NULL_TREE, cp_convert (double_type_node, val), result);
          else if (TYPE_LANG_SPECIFIC (TREE_TYPE (val))
                   && ! TYPE_HAS_TRIVIAL_INIT_REF (TREE_TYPE (val)))
            {
              cp_warning ("cannot pass objects of type `%T' through `...'",
                          TREE_TYPE (val));
-             result = tree_cons (NULL_TREE, val, result);
+             result = expr_tree_cons (NULL_TREE, val, result);
            }
          else
            /* Convert `short' and `char' to full-size `int'.  */
-           result = tree_cons (NULL_TREE, default_conversion (val), result);
+           result = expr_tree_cons (NULL_TREE, default_conversion (val), result);
        }
 
       if (typetail)
@@ -2911,7 +3018,7 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
              if (parmval == error_mark_node)
                return error_mark_node;
 
-             result = tree_cons (0, parmval, result);
+             result = expr_tree_cons (0, parmval, result);
              typetail = TREE_CHAIN (typetail);
              /* ends with `...'.  */
              if (typetail == NULL_TREE)
@@ -3133,7 +3240,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
         We must subtract them as integers, then divide by object size.  */
       if (code0 == POINTER_TYPE && code1 == POINTER_TYPE
          && comp_target_types (type0, type1, 1))
-       return pointer_diff (op0, op1);
+       return pointer_diff (op0, op1, common_type (type0, type1));
       /* Handle pointer minus int.  Just like pointer plus int.  */
       else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
        return pointer_int_sum (MINUS_EXPR, op0, op1);
@@ -3150,8 +3257,10 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
     case FLOOR_DIV_EXPR:
     case ROUND_DIV_EXPR:
     case EXACT_DIV_EXPR:
-      if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
-         && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
+      if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
+          || code0 == COMPLEX_TYPE)
+         && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
+             || code1 == COMPLEX_TYPE))
        {
          if (TREE_CODE (op1) == INTEGER_CST && integer_zerop (op1))
            cp_warning ("division by zero in `%E / 0'", op0);
@@ -3260,7 +3369,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
          /* Convert the shift-count to an integer, regardless of
             size of value being shifted.  */
          if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
-           op1 = convert (integer_type_node, op1);
+           op1 = cp_convert (integer_type_node, op1);
          /* Avoid converting op1 to result_type later.  */
          converted = 1;
        }
@@ -3282,7 +3391,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
          /* Convert the shift-count to an integer, regardless of
             size of value being shifted.  */
          if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
-           op1 = convert (integer_type_node, op1);
+           op1 = cp_convert (integer_type_node, op1);
          /* Avoid converting op1 to result_type later.  */
          converted = 1;
        }
@@ -3307,15 +3416,17 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
          /* Convert the shift-count to an integer, regardless of
             size of value being shifted.  */
          if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
-           op1 = convert (integer_type_node, op1);
+           op1 = cp_convert (integer_type_node, op1);
        }
       break;
 
     case EQ_EXPR:
     case NE_EXPR:
       build_type = boolean_type_node; 
-      if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
-         && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
+      if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
+          || code0 == COMPLEX_TYPE)
+         && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
+             || code1 == COMPLEX_TYPE))
        short_compare = 1;
       else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
        {
@@ -3505,11 +3616,17 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
          pedwarn ("ANSI C++ forbids comparison between pointer and integer");
        }
       break;
+
+    default:
+      break;
     }
 
-  if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
-      && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
+  if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE)
+      &&
+      (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE))
     {
+      int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE);
+
       if (shorten || common || short_compare)
        result_type = common_type (type0, type1);
 
@@ -3524,7 +3641,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
         Eg, (short)-1 | (unsigned short)-1 is (int)-1
         but calculated in (unsigned short) it would be (unsigned short)-1.  */
 
-      if (shorten)
+      if (shorten && none_complex)
        {
          int unsigned0, unsigned1;
          tree arg0 = get_narrower (op0, &unsigned0);
@@ -3619,7 +3736,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
                                           TREE_TYPE (arg0));
              /* Convert value-to-be-shifted to that type.  */
              if (TREE_TYPE (op0) != result_type)
-               op0 = convert (result_type, op0);
+               op0 = cp_convert (result_type, op0);
              converted = 1;
            }
        }
@@ -3638,7 +3755,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
          tree val 
            = shorten_compare (&xop0, &xop1, &xresult_type, &xresultcode);
          if (val != 0)
-           return convert (boolean_type_node, val);
+           return cp_convert (boolean_type_node, val);
          op0 = xop0, op1 = xop1;
          converted = 1;
          resultcode = xresultcode;
@@ -3769,9 +3886,9 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
   if (! converted)
     {
       if (TREE_TYPE (op0) != result_type)
-       op0 = convert (result_type, op0); 
+       op0 = cp_convert (result_type, op0); 
       if (TREE_TYPE (op1) != result_type)
-       op1 = convert (result_type, op1); 
+       op1 = cp_convert (result_type, op1); 
     }
 
   if (build_type == NULL_TREE)
@@ -3785,7 +3902,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
     if (folded == result)
       TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1);
     if (final_type != 0)
-      return convert (final_type, folded);
+      return cp_convert (final_type, folded);
     return folded;
   }
 }
@@ -3862,15 +3979,15 @@ pointer_int_sum (resultcode, ptrop, intop)
      so the multiply won't overflow spuriously.  */
 
   if (TYPE_PRECISION (TREE_TYPE (intop)) != TYPE_PRECISION (sizetype))
-    intop = convert (type_for_size (TYPE_PRECISION (sizetype), 0), intop);
+    intop = cp_convert (type_for_size (TYPE_PRECISION (sizetype), 0), intop);
 
   /* Replace the integer argument with a suitable product by the object size.
      Do this multiplication as signed, then convert to the appropriate
      pointer type (actually unsigned integral).  */
 
-  intop = convert (result_type,
-                  build_binary_op (MULT_EXPR, intop,
-                                   convert (TREE_TYPE (intop), size_exp), 1));
+  intop = cp_convert (result_type,
+                     build_binary_op (MULT_EXPR, intop,
+                                      cp_convert (TREE_TYPE (intop), size_exp), 1));
 
   /* Create the sum or difference.  */
 
@@ -3886,12 +4003,13 @@ pointer_int_sum (resultcode, ptrop, intop)
    The resulting tree has type int.  */
 
 static tree
-pointer_diff (op0, op1)
+pointer_diff (op0, op1, ptrtype)
      register tree op0, op1;
+     register tree ptrtype;
 {
   register tree result, folded;
   tree restype = ptrdiff_type_node;
-  tree target_type = TREE_TYPE (TREE_TYPE (op0));
+  tree target_type = TREE_TYPE (ptrtype);
 
   if (pedantic || warn_pointer_arith)
     {
@@ -3909,7 +4027,7 @@ pointer_diff (op0, op1)
      then drop through to build the divide operator.  */
 
   op0 = build_binary_op (MINUS_EXPR,
-                        convert (restype, op0), convert (restype, op1), 1);
+                        cp_convert (restype, op0), cp_convert (restype, op1), 1);
 
   /* This generates an error if op1 is a pointer to an incomplete type.  */
   if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (op1))) == 0)
@@ -3924,7 +4042,7 @@ pointer_diff (op0, op1)
 
   /* Do the division.  */
 
-  result = build (EXACT_DIV_EXPR, restype, op0, convert (restype, op1));
+  result = build (EXACT_DIV_EXPR, restype, op0, cp_convert (restype, op1));
 
   folded = fold (result);
   if (folded == result)
@@ -3975,7 +4093,7 @@ build_component_addr (arg, argtype, msg)
                                size_int (BITS_PER_UNIT));
       int flag = TREE_CONSTANT (rval);
       rval = fold (build (PLUS_EXPR, argtype,
-                         rval, convert (argtype, offset)));
+                         rval, cp_convert (argtype, offset)));
       TREE_CONSTANT (rval) = flag;
     }
   return rval;
@@ -3996,6 +4114,7 @@ build_x_unary_op (code, xarg)
   /* & rec, on incomplete RECORD_TYPEs is the simple opr &, not an
      error message.  */
   if (code == ADDR_EXPR
+      && TREE_CODE (xarg) != TEMPLATE_ID_EXPR
       && ((IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (xarg)))
           && TYPE_SIZE (TREE_TYPE (xarg)) == NULL_TREE)
          || (TREE_CODE (xarg) == OFFSET_REF)))
@@ -4039,7 +4158,7 @@ condition_conversion (expr)
   tree t;
   if (processing_template_decl)
     return expr;
-  t = convert (boolean_type_node, expr);
+  t = cp_convert (boolean_type_node, expr);
   t = fold (build1 (CLEANUP_POINT_EXPR, boolean_type_node, t));
   return t;
 }
@@ -4093,7 +4212,14 @@ build_unary_op (code, xarg, noconvert)
       break;
 
     case BIT_NOT_EXPR:
-      if (!(arg = build_expr_type_conversion (WANT_INT | WANT_ENUM, arg, 1)))
+      if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
+       {
+         code = CONJ_EXPR;
+         if (!noconvert)
+           arg = default_conversion (arg);
+       }
+      else if (!(arg = build_expr_type_conversion (WANT_INT | WANT_ENUM,
+                                                  arg, 1)))
        errstring = "wrong type argument to bit-complement";
       else if (!noconvert)
        arg = default_conversion (arg);
@@ -4106,8 +4232,16 @@ build_unary_op (code, xarg, noconvert)
        arg = default_conversion (arg);
       break;
 
+    case CONJ_EXPR:
+      /* Conjugating a real value is a no-op, but allow it anyway.  */
+      if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, 1)))
+       errstring = "wrong type argument to conjugation";
+      else if (!noconvert)
+       arg = default_conversion (arg);
+      break;
+
     case TRUTH_NOT_EXPR:
-      arg = convert (boolean_type_node, arg);
+      arg = cp_convert (boolean_type_node, arg);
       val = invert_truthvalue (arg);
       if (arg != error_mark_node)
        return val;
@@ -4117,6 +4251,22 @@ build_unary_op (code, xarg, noconvert)
     case NOP_EXPR:
       break;
       
+    case REALPART_EXPR:
+      if (TREE_CODE (arg) == COMPLEX_CST)
+       return TREE_REALPART (arg);
+      else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
+       return fold (build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
+      else
+       return arg;
+
+    case IMAGPART_EXPR:
+      if (TREE_CODE (arg) == COMPLEX_CST)
+       return TREE_IMAGPART (arg);
+      else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
+       return fold (build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
+      else
+       return cp_convert (TREE_TYPE (arg), integer_zero_node);
+      
     case PREINCREMENT_EXPR:
     case POSTINCREMENT_EXPR:
     case PREDECREMENT_EXPR:
@@ -4128,6 +4278,19 @@ build_unary_op (code, xarg, noconvert)
       if (val != 0)
        return val;
 
+      /* Increment or decrement the real part of the value,
+        and don't change the imaginary part.  */
+      if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
+       {
+         tree real, imag;
+
+         arg = stabilize_reference (arg);
+         real = build_unary_op (REALPART_EXPR, arg, 1);
+         imag = build_unary_op (IMAGPART_EXPR, arg, 1);
+         return build (COMPLEX_EXPR, TREE_TYPE (arg),
+                       build_unary_op (code, real, 1), imag);
+       }
+
       /* Report invalid types.  */
 
       if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_POINTER,
@@ -4187,7 +4350,7 @@ build_unary_op (code, xarg, noconvert)
        else
          inc = integer_one_node;
 
-       inc = convert (argtype, inc);
+       inc = cp_convert (argtype, inc);
 
        /* Handle incrementing a cast-expression.  */
 
@@ -4222,6 +4385,9 @@ build_unary_op (code, xarg, noconvert)
              TREE_NO_UNUSED_WARNING (compound) = 1;
              return compound;
            }
+
+         default:
+           break;
          }
 
        /* Complain about anything else that is not a true lvalue.  */
@@ -4262,7 +4428,7 @@ build_unary_op (code, xarg, noconvert)
          val = build (code, TREE_TYPE (arg), arg, inc);
 
        TREE_SIDE_EFFECTS (val) = 1;
-       return convert (result_type, val);
+       return cp_convert (result_type, val);
       }
 
     case ADDR_EXPR:
@@ -4272,8 +4438,10 @@ build_unary_op (code, xarg, noconvert)
       argtype = TREE_TYPE (arg);
       if (TREE_CODE (argtype) == REFERENCE_TYPE)
        {
-         arg = build1 (CONVERT_EXPR, build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg);
-         TREE_REFERENCE_EXPR (arg) = 1;
+         arg = build1
+           (CONVERT_EXPR,
+            build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg);
+         TREE_CONSTANT (arg) = TREE_CONSTANT (TREE_OPERAND (arg, 0));
          return arg;
        }
       else if (pedantic
@@ -4294,16 +4462,12 @@ build_unary_op (code, xarg, noconvert)
          if (arg == current_class_ref)
            return current_class_ptr;
 
-         /* Keep `default_conversion' from converting if
-            ARG is of REFERENCE_TYPE.  */
          arg = TREE_OPERAND (arg, 0);
          if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE)
            {
-             if (TREE_CODE (arg) == VAR_DECL && DECL_INITIAL (arg)
-                 && !TREE_SIDE_EFFECTS (DECL_INITIAL (arg)))
-               arg = DECL_INITIAL (arg);
-             arg = build1 (CONVERT_EXPR, build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg);
-             TREE_REFERENCE_EXPR (arg) = 1;
+             arg = build1
+               (CONVERT_EXPR,
+                build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg);
              TREE_CONSTANT (arg) = TREE_CONSTANT (TREE_OPERAND (arg, 0));
            }
          else if (lvalue_p (arg))
@@ -4348,6 +4512,29 @@ build_unary_op (code, xarg, noconvert)
                                   0);
          return build1 (ADDR_EXPR, unknown_type_node, arg);
        }
+      else if (TREE_CODE (arg) == TEMPLATE_ID_EXPR)
+       {
+         tree targs;
+         tree fn;
+         
+         /* We don't require a match here; it's possible that the
+            context (like a cast to a particular type) will resolve
+            the particular choice of template.  */
+         fn = determine_specialization (arg,
+                                        NULL_TREE,
+                                        &targs, 
+                                        0, 
+                                        0);
+
+         if (fn)
+           {
+             fn = instantiate_template (fn, targs);
+             mark_addressable (fn);
+             return build_unary_op (ADDR_EXPR, fn, 0);
+           }
+
+         return build1 (ADDR_EXPR, unknown_type_node, arg);
+       }
 
       /* Handle complex lvalues (when permitted)
         by reduction to simpler cases.  */
@@ -4366,6 +4553,10 @@ build_unary_op (code, xarg, noconvert)
        case FIX_CEIL_EXPR:
          if (! lvalue_p (arg) && pedantic)
            pedwarn ("taking the address of a cast to non-reference type");
+         break;
+         
+       default:
+         break;
        }
 
       /* Allow the address of a constructor if all the elements
@@ -4410,8 +4601,8 @@ build_unary_op (code, xarg, noconvert)
        if (staticp (arg))
          TREE_CONSTANT (addr) = 1;
 
-       if (TREE_CODE (argtype) == POINTER_TYPE &&
-           TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE)
+       if (TREE_CODE (argtype) == POINTER_TYPE
+           && TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE)
          {
            build_ptrmemfunc_type (argtype);
            addr = build_ptrmemfunc (argtype, addr, 0);
@@ -4419,6 +4610,9 @@ build_unary_op (code, xarg, noconvert)
 
        return addr;
       }
+
+    default:
+      break;
     }
 
   if (!errstring)
@@ -4451,9 +4645,9 @@ convert_sequence (conversions, arg)
     case FIX_FLOOR_EXPR:
     case FIX_ROUND_EXPR:
     case FIX_CEIL_EXPR:
-      return convert (TREE_TYPE (conversions),
-                     convert_sequence (TREE_OPERAND (conversions, 0),
-                                       arg));
+      return cp_convert (TREE_TYPE (conversions),
+                        convert_sequence (TREE_OPERAND (conversions, 0),
+                                          arg));
 
     default:
       return arg;
@@ -4481,7 +4675,8 @@ unary_complex_lvalue (code, arg)
     }
 
   /* Handle (a ? b : c) used as an "lvalue".  */
-  if (TREE_CODE (arg) == COND_EXPR)
+  if (TREE_CODE (arg) == COND_EXPR
+      || TREE_CODE (arg) == MIN_EXPR || TREE_CODE (arg) == MAX_EXPR)
     return rationalize_conditional_expr (code, arg);
 
   if (TREE_CODE (arg) == MODIFY_EXPR
@@ -4540,16 +4735,7 @@ unary_complex_lvalue (code, arg)
                return error_mark_node;
              }
 
-         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));
-           }
+         type = TYPE_OFFSET_BASETYPE (TREE_TYPE (arg));
 
          /* Now in the offset to the final subobject.  */
          offset = size_binop (PLUS_EXPR,
@@ -4564,12 +4750,12 @@ unary_complex_lvalue (code, arg)
                                           DECL_FIELD_BITPOS (t),
                                           size_int (BITS_PER_UNIT)));
 
-         /* We offset all pointer to data memebers by 1 so that we can
+         /* We offset all pointer to data members 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 convert (build_pointer_type (TREE_TYPE (arg)), offset);
+         return cp_convert (build_pointer_type (TREE_TYPE (arg)), offset);
        }
     }
 
@@ -4621,6 +4807,8 @@ mark_addressable (exp)
       case ADDR_EXPR:
       case COMPONENT_REF:
       case ARRAY_REF:
+      case REALPART_EXPR:
+      case IMAGPART_EXPR:
        x = TREE_OPERAND (x, 0);
        break;
 
@@ -4670,18 +4858,14 @@ mark_addressable (exp)
        return 1;
 
       case FUNCTION_DECL:
-       /* We have to test both conditions here.  The first may
-          be non-zero in the case of processing a default function.
-          The second may be non-zero in the case of a template function.  */
-       x = DECL_MAIN_VARIANT (x);
-       if ((DECL_THIS_INLINE (x) || DECL_PENDING_INLINE_INFO (x))
-           && (DECL_CONTEXT (x) == NULL_TREE
-               || TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (x))) != 't'
-               || ! CLASSTYPE_INTERFACE_ONLY (DECL_CONTEXT (x))))
+       if (DECL_LANG_SPECIFIC (x) != 0)
          {
-           mark_inline_for_output (x);
-           if (x == current_function_decl)
-             DECL_EXTERNAL (x) = 0;
+           x = DECL_MAIN_VARIANT (x);
+           /* We have to test both conditions here.  The first may be
+              non-zero in the case of processing a default function.  The
+              second may be non-zero in the case of a template function.  */
+           if (DECL_TEMPLATE_INFO (x) && !DECL_TEMPLATE_SPECIALIZATION (x))
+             mark_used (x);
          }
        TREE_ADDRESSABLE (x) = 1;
        TREE_USED (x) = 1;
@@ -4744,7 +4928,7 @@ build_conditional_expr (ifexp, op1, op2)
       ifexp = op1 = save_expr (ifexp);
     }
 
-  ifexp = convert (boolean_type_node, ifexp);
+  ifexp = cp_convert (boolean_type_node, ifexp);
 
   if (TREE_CODE (ifexp) == ERROR_MARK)
     return error_mark_node;
@@ -5023,9 +5207,11 @@ build_conditional_expr (ifexp, op1, op2)
     result_type = build_ptrmemfunc_type (result_type);
 
   if (result_type != TREE_TYPE (op1))
-    op1 = convert_and_check (result_type, op1);
+    op1 = convert_for_initialization
+      (NULL_TREE, result_type, op1, LOOKUP_NORMAL, "converting", NULL_TREE, 0);
   if (result_type != TREE_TYPE (op2))
-    op2 = convert_and_check (result_type, op2);
+    op2 = convert_for_initialization
+      (NULL_TREE, result_type, op2, LOOKUP_NORMAL, "converting", NULL_TREE, 0);
 
   if (TREE_CONSTANT (ifexp))
     return integer_zerop (ifexp) ? op2 : op1;
@@ -5053,7 +5239,7 @@ build_x_compound_expr (list)
   result = build_opfncall (COMPOUND_EXPR, LOOKUP_NORMAL,
                           TREE_VALUE (list), TREE_VALUE (rest), NULL_TREE);
   if (result)
-    return build_x_compound_expr (tree_cons (NULL_TREE, result, TREE_CHAIN (rest)));
+    return build_x_compound_expr (expr_tree_cons (NULL_TREE, result, TREE_CHAIN (rest)));
 
   if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)))
     {
@@ -5070,8 +5256,8 @@ build_x_compound_expr (list)
     warn_if_unused_value (TREE_VALUE(list));
 #endif
 
-  return build_compound_expr (tree_cons (NULL_TREE, TREE_VALUE (list),
-                                        build_tree_list (NULL_TREE, build_x_compound_expr (rest))));
+  return build_compound_expr (expr_tree_cons (NULL_TREE, TREE_VALUE (list),
+                                        build_expr_list (NULL_TREE, build_x_compound_expr (rest))));
 }
 
 /* Given a list of expressions, return a compound expression
@@ -5126,7 +5312,8 @@ build_static_cast (type, expr)
 
   if (processing_template_decl)
     {
-      tree t = build_min (STATIC_CAST_EXPR, type, expr);
+      tree t = build_min (STATIC_CAST_EXPR, copy_to_permanent (type),
+                         expr); 
       return t;
     }
 
@@ -5155,7 +5342,7 @@ build_static_cast (type, expr)
   if (IS_AGGR_TYPE (type))
     return build_cplus_new
       (type, (build_method_call
-             (NULL_TREE, ctor_identifier, build_tree_list (NULL_TREE, expr),
+             (NULL_TREE, ctor_identifier, build_expr_list (NULL_TREE, expr),
               TYPE_BINFO (type), LOOKUP_NORMAL)));
 
   expr = decay_conversion (expr);
@@ -5218,7 +5405,8 @@ build_reinterpret_cast (type, expr)
 
   if (processing_template_decl)
     {
-      tree t = build_min (REINTERPRET_CAST_EXPR, type, expr);
+      tree t = build_min (REINTERPRET_CAST_EXPR, 
+                         copy_to_permanent (type), expr);
       return t;
     }
 
@@ -5287,13 +5475,21 @@ build_reinterpret_cast (type, expr)
        expr = decl_constant_value (expr);
       return fold (build1 (NOP_EXPR, type, expr));
     }
+  else if ((TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype))
+          || (TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype)))
+    {
+      pedwarn ("ANSI C++ forbids casting between pointers to functions and objects");
+      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);
+  return cp_convert (type, expr);
 }
 
 tree
@@ -5310,7 +5506,8 @@ build_const_cast (type, expr)
 
   if (processing_template_decl)
     {
-      tree t = build_min (CONST_CAST_EXPR, type, expr);
+      tree t = build_min (CONST_CAST_EXPR, copy_to_permanent (type),
+                         expr);
       return t;
     }
 
@@ -5345,14 +5542,16 @@ build_const_cast (type, expr)
        }
 
       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)));
+       {
+         expr = build_unary_op (ADDR_EXPR, expr, 0);
+         expr = build1 (NOP_EXPR, type, expr);
+         return convert_from_reference (expr);
+       }
     }
   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 cp_convert (type, expr);
 
   cp_error ("const_cast from `%T' to `%T'", intype, type);
   return error_mark_node;
@@ -5365,8 +5564,7 @@ build_const_cast (type, expr)
 
 tree
 build_c_cast (type, expr)
-     register tree type;
-     tree expr;
+     tree type, expr;
 {
   register tree value = expr;
 
@@ -5436,7 +5634,6 @@ build_c_cast (type, expr)
   else
     {
       tree otype;
-      int flag;
 
       /* Convert functions and arrays to pointers and
         convert references to their expanded types,
@@ -5445,8 +5642,8 @@ build_c_cast (type, expr)
          || (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 (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);
@@ -5506,7 +5703,7 @@ build_c_cast (type, expr)
            value = decl_constant_value (value);
 
          ovalue = value;
-         value = convert_force (type, value, flag);
+         value = convert_force (type, value, CONV_C_CAST);
 
          /* Ignore any integer overflow caused by the cast.  */
          if (TREE_CODE (value) == INTEGER_CST)
@@ -5526,7 +5723,7 @@ build_c_cast (type, expr)
   return value;
 }
 \f
-tree
+static tree
 expand_target_expr (t)
      tree t;
 {
@@ -5546,7 +5743,7 @@ expand_target_expr (t)
   do_pending_stack_adjust ();
   start_sequence_for_rtl_expr (xval);
   emit_note (0, -1);
-  rtxval = expand_expr (t, NULL_RTX, VOIDmode, 0);
+  rtxval = expand_expr (t, NULL_RTX, VOIDmode, EXPAND_NORMAL);
   do_pending_stack_adjust ();
   TREE_SIDE_EFFECTS (xval) = 1;
   RTL_EXPR_SEQUENCE (xval) = get_insns ();
@@ -5580,7 +5777,7 @@ build_modify_expr (lhs, modifycode, rhs)
   tree olhs = lhs;
 
   /* Avoid duplicate error messages from operands that had errors.  */
-  if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
+  if (lhs == error_mark_node || rhs == error_mark_node)
     return error_mark_node;
 
   /* Types that aren't fully specified cannot be used in assignments.  */
@@ -5590,8 +5787,8 @@ build_modify_expr (lhs, modifycode, rhs)
 
   /* Handle assignment to signature pointers/refs.  */
 
-  if (TYPE_LANG_SPECIFIC (lhstype) &&
-      (IS_SIGNATURE_POINTER (lhstype) || IS_SIGNATURE_REFERENCE (lhstype)))
+  if (TYPE_LANG_SPECIFIC (lhstype)
+      && (IS_SIGNATURE_POINTER (lhstype) || IS_SIGNATURE_REFERENCE (lhstype)))
     {
       return build_signature_pointer_constructor (lhs, rhs);
     }
@@ -5616,14 +5813,14 @@ build_modify_expr (lhs, modifycode, rhs)
     case COMPOUND_EXPR:
       newrhs = build_modify_expr (TREE_OPERAND (lhs, 1),
                                  modifycode, rhs);
-      if (TREE_CODE (newrhs) == ERROR_MARK)
+      if (newrhs == error_mark_node)
        return error_mark_node;
       return build (COMPOUND_EXPR, lhstype,
                    TREE_OPERAND (lhs, 0), newrhs);
 
     case MODIFY_EXPR:
       newrhs = build_modify_expr (TREE_OPERAND (lhs, 0), modifycode, rhs);
-      if (TREE_CODE (newrhs) == ERROR_MARK)
+      if (newrhs == error_mark_node)
        return error_mark_node;
       return build (COMPOUND_EXPR, lhstype, lhs, newrhs);
 
@@ -5636,19 +5833,22 @@ build_modify_expr (lhs, modifycode, rhs)
           so the code to compute it is only emitted once.  */
        tree cond
          = build_conditional_expr (TREE_OPERAND (lhs, 0),
-                                   build_modify_expr (convert (TREE_TYPE (lhs), TREE_OPERAND (lhs, 1)),
+                                   build_modify_expr (cp_convert (TREE_TYPE (lhs), TREE_OPERAND (lhs, 1)),
                                                       modifycode, rhs),
-                                   build_modify_expr (convert (TREE_TYPE (lhs), TREE_OPERAND (lhs, 2)),
+                                   build_modify_expr (cp_convert (TREE_TYPE (lhs), TREE_OPERAND (lhs, 2)),
                                                       modifycode, rhs));
-       if (TREE_CODE (cond) == ERROR_MARK)
+       if (cond == error_mark_node)
          return cond;
        /* Make sure the code to compute the rhs comes out
           before the split.  */
        return build (COMPOUND_EXPR, TREE_TYPE (lhs),
                      /* Case to void to suppress warning
                         from warn_if_unused_value.  */
-                     convert (void_type_node, rhs), cond);
+                     cp_convert (void_type_node, rhs), cond);
       }
+
+    default:
+      break;
     }
 
   if (TREE_CODE (lhs) == OFFSET_REF)
@@ -5685,18 +5885,10 @@ build_modify_expr (lhs, modifycode, rhs)
     {
       if (! IS_AGGR_TYPE (lhstype))
        /* Do the default thing */;
-      else if (! TYPE_HAS_CONSTRUCTOR (lhstype))
-       {
-         cp_error ("`%T' has no constructors", lhstype);
-         return error_mark_node;
-       }
-      else if (TYPE_HAS_TRIVIAL_INIT_REF (lhstype)
-              && TYPE_MAIN_VARIANT (lhstype) == TYPE_MAIN_VARIANT (TREE_TYPE (newrhs)))
-       /* Do the default thing */;
       else
        {
          result = build_method_call (lhs, ctor_identifier,
-                                     build_tree_list (NULL_TREE, rhs),
+                                     build_expr_list (NULL_TREE, rhs),
                                      TYPE_BINFO (lhstype), LOOKUP_NORMAL);
          if (result == NULL_TREE)
            return error_mark_node;
@@ -5708,19 +5900,6 @@ build_modify_expr (lhs, modifycode, rhs)
       /* `operator=' is not an inheritable operator.  */
       if (! IS_AGGR_TYPE (lhstype))
        /* Do the default thing */;
-      else if (! TYPE_HAS_ASSIGNMENT (lhstype))
-       {
-         cp_error ("`%T' does not define operator=", lhstype);
-         return error_mark_node;
-       }
-      else if (TYPE_HAS_TRIVIAL_ASSIGN_REF (lhstype)
-              && TYPE_MAIN_VARIANT (lhstype) == TYPE_MAIN_VARIANT (TREE_TYPE (newrhs)))
-       {
-         build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
-                         lhs, rhs, make_node (NOP_EXPR));
-
-         /* Do the default thing */;
-       }
       else
        {
          result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
@@ -5787,16 +5966,22 @@ build_modify_expr (lhs, modifycode, rhs)
       {
        tree inner_lhs = TREE_OPERAND (lhs, 0);
        tree result;
-       if (! lvalue_p (lhs) && pedantic)
-         pedwarn ("cast to non-reference type used as lvalue");
+
+       /* WP 5.4.1:  The result is an lvalue if T is a reference type,
+          otherwise the result is an rvalue.   */
+       if (! lvalue_p (lhs))
+         pedwarn ("ANSI C++ forbids cast to non-reference type used as lvalue");
 
        result = build_modify_expr (inner_lhs, NOP_EXPR,
-                                   convert (TREE_TYPE (inner_lhs),
-                                            convert (lhstype, newrhs)));
-       if (TREE_CODE (result) == ERROR_MARK)
+                                   cp_convert (TREE_TYPE (inner_lhs),
+                                               cp_convert (lhstype, newrhs)));
+       if (result == error_mark_node)
          return result;
-       return convert (TREE_TYPE (lhs), result);
+       return cp_convert (TREE_TYPE (lhs), result);
       }
+
+    default:
+      break;
     }
 
   /* Now we have handled acceptable kinds of LHS that are not truly lvalues.
@@ -5980,7 +6165,7 @@ build_modify_expr (lhs, modifycode, rhs)
                        TREE_OPERAND (newrhs, 0));
     }
 
-  if (TREE_CODE (newrhs) == ERROR_MARK)
+  if (newrhs == error_mark_node)
     return error_mark_node;
 
   if (TREE_CODE (newrhs) == COND_EXPR)
@@ -5991,7 +6176,7 @@ build_modify_expr (lhs, modifycode, rhs)
       if (TREE_SIDE_EFFECTS (lhs))
        cond = build_compound_expr (tree_cons
                                    (NULL_TREE, lhs,
-                                    build_tree_list (NULL_TREE, cond)));
+                                    build_expr_list (NULL_TREE, cond)));
 
       /* Cannot have two identical lhs on this one tree (result) as preexpand
         calls will rip them out and fill in RTL for them, but when the
@@ -6011,11 +6196,11 @@ build_modify_expr (lhs, modifycode, rhs)
          result
            = build (COND_EXPR, result_type, cond,
                     build_modify_expr (lhs, modifycode,
-                                       convert (result_type,
-                                                TREE_OPERAND (newrhs, 1))),
+                                       cp_convert (result_type,
+                                                   TREE_OPERAND (newrhs, 1))),
                     build_modify_expr (lhs1, modifycode,
-                                       convert (result_type,
-                                                TREE_OPERAND (newrhs, 2))));
+                                       cp_convert (result_type,
+                                                   TREE_OPERAND (newrhs, 2))));
        }
     }
   else
@@ -6097,7 +6282,7 @@ get_delta_difference (from, to, force)
   binfo = get_binfo (from, to, 1);
   if (binfo == error_mark_node)
     {
-      error ("   in pointer to member function conversiona");
+      error ("   in pointer to member function conversion");
       return delta;
     }
   if (binfo == 0)
@@ -6128,7 +6313,7 @@ get_delta_difference (from, to, force)
          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);
+      delta = cp_convert (ptrdiff_type_node, delta);
       
       return build_binary_op (MINUS_EXPR,
                              integer_zero_node,
@@ -6155,18 +6340,18 @@ build_ptrmemfunc1 (type, delta, idx, pfn, delta2)
   if (pfn)
     {
       u = build_nt (CONSTRUCTOR, NULL_TREE,
-                   tree_cons (pfn_identifier, pfn, NULL_TREE));
+                   expr_tree_cons (pfn_identifier, pfn, NULL_TREE));
     }
   else
     {
       u = build_nt (CONSTRUCTOR, NULL_TREE,
-                   tree_cons (delta2_identifier, delta2, NULL_TREE));
+                   expr_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))));
+               expr_tree_cons (NULL_TREE, delta,
+                          expr_tree_cons (NULL_TREE, idx,
+                                     expr_tree_cons (NULL_TREE, u, NULL_TREE))));
 
   return digest_init (type, u, (tree*)0);
 #else
@@ -6184,15 +6369,15 @@ build_ptrmemfunc1 (type, delta, idx, pfn, delta2)
   if (pfn)
     {
       allconstant = TREE_CONSTANT (pfn);
-      allsimple = initializer_constant_valid_p (pfn, TREE_TYPE (pfn));
-      u = tree_cons (pfn_field, pfn, NULL_TREE);
+      allsimple = !! initializer_constant_valid_p (pfn, TREE_TYPE (pfn));
+      u = expr_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);
+      allsimple = !! initializer_constant_valid_p (delta2, TREE_TYPE (delta2));
+      u = expr_tree_cons (delta2_field, delta2, NULL_TREE);
     }
 
   delta = convert_and_check (delta_type_node, delta);
@@ -6204,9 +6389,9 @@ build_ptrmemfunc1 (type, delta, idx, pfn, delta2)
       && 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 = expr_tree_cons (delta_field, delta,
+                expr_tree_cons (idx_field, idx,
+                           expr_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;
@@ -6246,8 +6431,8 @@ build_ptrmemfunc (type, pfn, force)
       if (type == TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))
        return pfn;
 
-      ndelta = convert (ptrdiff_type_node, build_component_ref (pfn, delta_identifier, NULL_TREE, 0));
-      ndelta2 = convert (ptrdiff_type_node, DELTA2_FROM_PTRMEMFUNC (pfn));
+      ndelta = cp_convert (ptrdiff_type_node, build_component_ref (pfn, delta_identifier, NULL_TREE, 0));
+      ndelta2 = cp_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)))),
@@ -6417,8 +6602,10 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
       return error_mark_node;
     }
   /* Arithmetic types all interconvert.  */
-  if ((codel == INTEGER_TYPE || codel == REAL_TYPE || codel == BOOLEAN_TYPE)
-       && (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == BOOLEAN_TYPE))
+  if ((codel == INTEGER_TYPE || codel == REAL_TYPE || codel == BOOLEAN_TYPE
+       || codel == COMPLEX_TYPE)
+       && (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == BOOLEAN_TYPE
+          || coder == COMPLEX_TYPE))
     {
       /* But we should warn if assigning REAL_TYPE to INTEGER_TYPE.  */
       if (coder == REAL_TYPE && codel == INTEGER_TYPE)
@@ -6456,7 +6643,7 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
           || (coder == ENUMERAL_TYPE
               && (INTEGRAL_CODE_P (codel) || codel == REAL_TYPE)))
     {
-      return cp_convert (type, rhs, CONV_IMPLICIT, LOOKUP_NORMAL);
+      return ocp_convert (type, rhs, CONV_IMPLICIT, LOOKUP_NORMAL);
     }
   /* Conversions among pointers */
   else if (codel == POINTER_TYPE
@@ -6690,7 +6877,7 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
              return error_mark_node;
            }
        }
-      return convert (type, rhs);
+      return cp_convert (type, rhs);
     }
   else if (codel == POINTER_TYPE && coder == INTEGER_TYPE)
     {
@@ -6705,7 +6892,7 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
            cp_pedwarn ("%s to `%T' from `%T' lacks a cast",
                        errtype, type, rhstype);
        }
-      return convert (type, rhs);
+      return cp_convert (type, rhs);
     }
   else if (codel == INTEGER_TYPE
           && (coder == POINTER_TYPE
@@ -6720,7 +6907,7 @@ 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 cp_convert (type, rhs);
     }
   else if (codel == BOOLEAN_TYPE
           && (coder == POINTER_TYPE
@@ -6728,7 +6915,7 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
                   && (IS_SIGNATURE_POINTER (rhstype)
                       || TYPE_PTRMEMFUNC_FLAG (rhstype)
                       || IS_SIGNATURE_REFERENCE (rhstype)))))
-    return convert (type, rhs);
+    return cp_convert (type, rhs);
 
   /* C++ */
   else if (((coder == POINTER_TYPE
@@ -6766,14 +6953,14 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
       return nrhs;
     }
   else if (TYPE_HAS_CONSTRUCTOR (type) || IS_AGGR_TYPE (TREE_TYPE (rhs)))
-    return convert (type, rhs);
+    return cp_convert (type, rhs);
   /* Handle anachronistic conversions from (::*)() to cv void* or (*)().  */
   else if (TREE_CODE (type) == POINTER_TYPE
           && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
               || TYPE_MAIN_VARIANT (TREE_TYPE (type)) == void_type_node)
           && TREE_TYPE (rhs)
           && TYPE_PTRMEMFUNC_P (TREE_TYPE (rhs)))
-    return convert (type, rhs);
+    return cp_convert (type, rhs);
 
   cp_error ("%s to `%T' from `%T'", errtype, type, rhstype);
   return error_mark_node;
@@ -6893,7 +7080,7 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
       && (TYPE_NEEDS_CONSTRUCTING (type) || TREE_HAS_CONSTRUCTOR (rhs)))
     {
       if (flag_ansi_overloading)
-       return cp_convert (type, rhs, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
+       return ocp_convert (type, rhs, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
 
       if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
        {
@@ -6932,7 +7119,7 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
          if (TYPE_HAS_INIT_REF (type))
            {
              tree init = build_method_call (exp, ctor_identifier,
-                                            build_tree_list (NULL_TREE, rhs),
+                                            build_expr_list (NULL_TREE, rhs),
                                             TYPE_BINFO (type), LOOKUP_NORMAL);
 
              if (init == error_mark_node)
@@ -6964,8 +7151,8 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
          return rhs;
        }
 
-      return cp_convert (type, rhs, CONV_OLD_CONVERT,
-                        flags | LOOKUP_NO_CONVERSION);
+      return ocp_convert (type, rhs, CONV_OLD_CONVERT,
+                         flags | LOOKUP_NO_CONVERSION);
     }
 
   if (type == TREE_TYPE (rhs))
@@ -7015,7 +7202,7 @@ c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
       if (o[i] != TREE_VALUE (tail))
        {
          expand_expr (build_modify_expr (o[i], NOP_EXPR, TREE_VALUE (tail)),
-                      const0_rtx, VOIDmode, 0);
+                      const0_rtx, VOIDmode, EXPAND_NORMAL);
          free_temp_slots ();
        }
       /* Detect modification of read-only values.
@@ -7117,7 +7304,7 @@ c_expand_return (retval)
     }
 
   /* Effective C++ rule 15.  See also start_function.  */
-  if (extra_warnings
+  if (warn_ecpp
       && DECL_NAME (current_function_decl) == ansi_opname[(int) MODIFY_EXPR]
       && retval != current_class_ref)
     cp_warning ("`operator=' should return a reference to `*this'");
@@ -7125,81 +7312,12 @@ c_expand_return (retval)
   if (valtype == NULL_TREE || TREE_CODE (valtype) == VOID_TYPE)
     {
       current_function_returns_null = 1;
-      if (pedantic || TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
+      if ((pedantic && ! DECL_ARTIFICIAL (current_function_decl))
+         || TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
        pedwarn ("`return' with a value, in function returning void");
       expand_return (retval);
       return;
     }
-  /* Add some useful error checking for C++.  */
-  else if (TREE_CODE (valtype) == REFERENCE_TYPE)
-    {
-      tree whats_returned;
-      tree tmp_result = result;
-
-      /* Don't initialize directly into a non-BLKmode retval, since that
-        could lose when being inlined by another caller.  (GCC can't
-        read the function return register in an inline function when
-        the return value is being ignored).  */
-      if (result && TYPE_MODE (TREE_TYPE (tmp_result)) != BLKmode)
-       tmp_result = 0;
-
-      /* convert to reference now, so we can give error if we
-        return an reference to a non-lvalue.  */
-      retval = convert_for_initialization
-       (tmp_result, valtype, retval, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
-        "return", NULL_TREE, 0);
-
-      /* Sort through common things to see what it is
-        we are returning.  */
-      whats_returned = retval;
-      if (TREE_CODE (whats_returned) == COMPOUND_EXPR)
-       {
-         whats_returned = TREE_OPERAND (whats_returned, 1);
-         if (TREE_CODE (whats_returned) == ADDR_EXPR)
-           whats_returned = TREE_OPERAND (whats_returned, 0);
-       }
-      if (TREE_CODE (whats_returned) == ADDR_EXPR)
-       {
-         whats_returned = TREE_OPERAND (whats_returned, 0);
-         while (TREE_CODE (whats_returned) == NEW_EXPR
-                || TREE_CODE (whats_returned) == TARGET_EXPR)
-           {
-             /* Get the target.  */
-             whats_returned = TREE_OPERAND (whats_returned, 0);
-             warning ("returning reference to temporary");
-           }
-       }
-
-      if (TREE_CODE (whats_returned) == VAR_DECL && DECL_NAME (whats_returned))
-       {
-         if (TEMP_NAME_P (DECL_NAME (whats_returned)))
-           warning ("reference to non-lvalue returned");
-         else if (! TREE_STATIC (whats_returned)
-                  && IDENTIFIER_LOCAL_VALUE (DECL_NAME (whats_returned))
-                  && !TREE_PUBLIC (whats_returned))
-           cp_warning_at ("reference to local variable `%D' returned", whats_returned);
-       }
-    }
-  else if (TREE_CODE (retval) == ADDR_EXPR)
-    {
-      tree whats_returned = TREE_OPERAND (retval, 0);
-
-      if (TREE_CODE (whats_returned) == VAR_DECL
-         && DECL_NAME (whats_returned)
-         && IDENTIFIER_LOCAL_VALUE (DECL_NAME (whats_returned))
-         && !TREE_STATIC (whats_returned)
-         && !TREE_PUBLIC (whats_returned))
-       cp_warning_at ("address of local variable `%D' returned", whats_returned);
-    }
-  else if (TREE_CODE (retval) == VAR_DECL)
-    {
-      if (TREE_CODE (TREE_TYPE (retval)) == ARRAY_TYPE
-         && DECL_NAME (retval)
-         && IDENTIFIER_LOCAL_VALUE (DECL_NAME (retval))
-         && !TREE_STATIC (retval)
-         && !TREE_PUBLIC (retval))
-       cp_warning_at ("address of local array `%D' returned", retval);
-    }
   
   /* Now deal with possible C++ hair:
      (1) Compute the return value.
@@ -7220,18 +7338,9 @@ c_expand_return (retval)
     }
   else
     {
-      /* We already did this above for refs, don't do it again.  */
-      if (TREE_CODE (valtype) != REFERENCE_TYPE)
-       retval = convert_for_initialization
-         (NULL_TREE, valtype, retval, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
-          "return", NULL_TREE, 0);
-
-      /* We can't initialize a register from a NEW_EXPR.  */
-      if (! current_function_returns_struct
-         && TREE_CODE (retval) == TARGET_EXPR
-         && TREE_CODE (TREE_OPERAND (retval, 1)) == NEW_EXPR)
-       retval = build (COMPOUND_EXPR, TREE_TYPE (retval), retval,
-                       TREE_OPERAND (retval, 0));
+      retval = convert_for_initialization
+       (NULL_TREE, valtype, retval, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
+        "return", NULL_TREE, 0);
 
       if (retval == error_mark_node)
        {
@@ -7239,6 +7348,65 @@ c_expand_return (retval)
          expand_null_return ();
          return;
        }
+
+      /* We can't initialize a register from a AGGR_INIT_EXPR.  */
+      else if (! current_function_returns_struct
+              && TREE_CODE (retval) == TARGET_EXPR
+              && TREE_CODE (TREE_OPERAND (retval, 1)) == AGGR_INIT_EXPR)
+       retval = build (COMPOUND_EXPR, TREE_TYPE (retval), retval,
+                       TREE_OPERAND (retval, 0));
+
+      /* Add some useful error checking for C++.  */
+      else if (TREE_CODE (valtype) == REFERENCE_TYPE)
+       {
+         tree whats_returned;
+
+         /* Sort through common things to see what it is
+            we are returning.  */
+         whats_returned = retval;
+         if (TREE_CODE (whats_returned) == COMPOUND_EXPR)
+           {
+             whats_returned = TREE_OPERAND (whats_returned, 1);
+             if (TREE_CODE (whats_returned) == ADDR_EXPR)
+               whats_returned = TREE_OPERAND (whats_returned, 0);
+           }
+         while (TREE_CODE (whats_returned) == CONVERT_EXPR
+                || TREE_CODE (whats_returned) == NOP_EXPR)
+           whats_returned = TREE_OPERAND (whats_returned, 0);
+         if (TREE_CODE (whats_returned) == ADDR_EXPR)
+           {
+             whats_returned = TREE_OPERAND (whats_returned, 0);
+             while (TREE_CODE (whats_returned) == AGGR_INIT_EXPR
+                    || TREE_CODE (whats_returned) == TARGET_EXPR)
+               {
+                 /* Get the target.  */
+                 whats_returned = TREE_OPERAND (whats_returned, 0);
+                 warning ("returning reference to temporary");
+               }
+           }
+
+         if (TREE_CODE (whats_returned) == VAR_DECL && DECL_NAME (whats_returned))
+           {
+             if (TEMP_NAME_P (DECL_NAME (whats_returned)))
+               warning ("reference to non-lvalue returned");
+             else if (TREE_CODE (TREE_TYPE (whats_returned)) != REFERENCE_TYPE
+                      && ! TREE_STATIC (whats_returned)
+                      && IDENTIFIER_LOCAL_VALUE (DECL_NAME (whats_returned))
+                      && !TREE_PUBLIC (whats_returned))
+               cp_warning_at ("reference to local variable `%D' returned", whats_returned);
+           }
+       }
+      else if (TREE_CODE (retval) == ADDR_EXPR)
+       {
+         tree whats_returned = TREE_OPERAND (retval, 0);
+
+         if (TREE_CODE (whats_returned) == VAR_DECL
+             && DECL_NAME (whats_returned)
+             && IDENTIFIER_LOCAL_VALUE (DECL_NAME (whats_returned))
+             && !TREE_STATIC (whats_returned)
+             && !TREE_PUBLIC (whats_returned))
+           cp_warning_at ("address of local variable `%D' returned", whats_returned);
+       }
     }
 
   if (retval != NULL_TREE
@@ -7257,7 +7425,13 @@ c_expand_return (retval)
       result = build (INIT_EXPR, TREE_TYPE (result), result, retval);
       TREE_SIDE_EFFECTS (result) = 1;
     }
+
+  expand_start_target_temps ();
+
   expand_return (result);
+
+  expand_end_target_temps ();
+
   current_function_returns_value = 1;
 }
 \f
@@ -7318,7 +7492,7 @@ c_expand_start_case (exp)
 /* CONSTP remembers whether or not all the intervening pointers in the `to'
    type have been const.  */
 
-int
+static int
 comp_ptr_ttypes_real (to, from, constp)
      tree to, from;
      int constp;
@@ -7389,7 +7563,7 @@ ptr_reasonably_similar (to, from)
 
 /* Like comp_ptr_ttypes, for const_cast.  */
 
-int
+static int
 comp_ptr_ttypes_const (to, from)
      tree to, from;
 {
@@ -7410,7 +7584,7 @@ comp_ptr_ttypes_const (to, from)
 
 /* Like comp_ptr_ttypes, for reinterpret_cast.  */
 
-int
+static int
 comp_ptr_ttypes_reinterpret (to, from)
      tree to, from;
 {