class.c (instantiate_type): Don't just return a known type if it's wrong.
[gcc.git] / gcc / cp / typeck.c
index 6d2204ce81c16a1b3dd3b8a8e7a98fb61fde0538..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.
@@ -36,6 +36,7 @@ Boston, MA 02111-1307, USA.  */
 #include "cp-tree.h"
 #include "flags.h"
 #include "output.h"
+#include "expr.h"
 
 #ifdef HAVE_STRING_H
 #include <string.h>
@@ -57,7 +58,7 @@ 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));
+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));
@@ -450,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);
 
@@ -642,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
@@ -831,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*,
@@ -869,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)
@@ -921,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:
@@ -1429,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);
 
@@ -1672,18 +1720,33 @@ build_component_ref_1 (datum, field, protect)
     (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),
@@ -1762,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);
@@ -2047,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))
@@ -2060,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;
        }
     }
@@ -2253,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)
@@ -2261,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
@@ -2296,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);
 
@@ -2354,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);
     }
@@ -2369,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)
        {
@@ -2382,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
@@ -2410,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);
     }
 
@@ -2460,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);
@@ -2598,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).  */
@@ -2637,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;
@@ -2682,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++ */
@@ -2800,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)
@@ -2868,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
        {
@@ -2879,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, cp_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)
@@ -2934,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)
@@ -3156,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);
@@ -3532,6 +3616,9 @@ 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 || code0 == COMPLEX_TYPE)
@@ -3916,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)
     {
@@ -4026,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)))
@@ -4296,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.  */
@@ -4420,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.  */
@@ -4438,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
@@ -4491,6 +4610,9 @@ build_unary_op (code, xarg, noconvert)
 
        return addr;
       }
+
+    default:
+      break;
     }
 
   if (!errstring)
@@ -4553,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
@@ -4612,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,
@@ -4636,7 +4750,7 @@ 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));
@@ -4744,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;
@@ -5129,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)))
     {
@@ -5146,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
@@ -5202,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;
     }
 
@@ -5231,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);
@@ -5294,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;
     }
 
@@ -5363,6 +5475,14 @@ 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);
@@ -5386,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;
     }
 
@@ -5421,9 +5542,11 @@ 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
@@ -5620,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 ();
@@ -5723,6 +5846,9 @@ build_modify_expr (lhs, modifycode, rhs)
                         from warn_if_unused_value.  */
                      cp_convert (void_type_node, rhs), cond);
       }
+
+    default:
+      break;
     }
 
   if (TREE_CODE (lhs) == OFFSET_REF)
@@ -5759,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;
@@ -5782,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,
@@ -5874,6 +5979,9 @@ build_modify_expr (lhs, modifycode, rhs)
          return result;
        return cp_convert (TREE_TYPE (lhs), result);
       }
+
+    default:
+      break;
     }
 
   /* Now we have handled acceptable kinds of LHS that are not truly lvalues.
@@ -6068,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
@@ -6174,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)
@@ -6232,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
@@ -6262,14 +6370,14 @@ build_ptrmemfunc1 (type, delta, idx, pfn, delta2)
     {
       allconstant = TREE_CONSTANT (pfn);
       allsimple = !! initializer_constant_valid_p (pfn, TREE_TYPE (pfn));
-      u = tree_cons (pfn_field, pfn, NULL_TREE);
+      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);
+      u = expr_tree_cons (delta2_field, delta2, NULL_TREE);
     }
 
   delta = convert_and_check (delta_type_node, delta);
@@ -6281,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;
@@ -7011,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)
@@ -7094,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.
@@ -7210,79 +7318,6 @@ c_expand_return (retval)
       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);
-       }
-      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) == 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.
@@ -7303,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)
        {
@@ -7322,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