class.c (instantiate_type): Don't just return a known type if it's wrong.
[gcc.git] / gcc / cp / tree.c
index 32567446fc0d3c396f0ba43318f0f4e95de2bb04..16bcb1357351fc98a265e44b59c2ac70fed97d3a 100644 (file)
@@ -1,5 +1,5 @@
 /* Language-dependent node constructors for parse phase of GNU compiler.
-   Copyright (C) 1987, 1988, 1992, 1993 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
@@ -16,7 +16,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 #include "config.h"
 #include <stdio.h>
@@ -24,6 +25,31 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "tree.h"
 #include "cp-tree.h"
 #include "flags.h"
+#include "rtl.h"
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef NEED_DECLARATION_FREE
+extern void free       PROTO((void *));
+#endif
+
+extern void compiler_error ();
+
+static tree get_identifier_list PROTO((tree));
+static tree bot_manip PROTO((tree));
+static tree perm_manip PROTO((tree));
+static tree build_cplus_array_type_1 PROTO((tree, tree));
+static void list_hash_add PROTO((int, tree));
+static int list_hash PROTO((tree, tree, tree));
+static tree list_hash_lookup PROTO((int, int, int, int, tree, tree,
+                                   tree));
 
 #define CEIL(x,y) (((x) + (y) - 1) / (y))
 
@@ -32,69 +58,166 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    Lvalues can have their address taken, unless they have DECL_REGISTER.  */
 
 int
+real_lvalue_p (ref)
+     tree ref;
+{
+  if (! language_lvalue_valid (ref))
+    return 0;
+  
+  if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE)
+    return 1;
+
+  if (ref == current_class_ptr && flag_this_is_variable <= 0)
+    return 0;
+
+  switch (TREE_CODE (ref))
+    {
+      /* preincrements and predecrements are valid lvals, provided
+        what they refer to are valid lvals.  */
+    case PREINCREMENT_EXPR:
+    case PREDECREMENT_EXPR:
+    case COMPONENT_REF:
+    case SAVE_EXPR:
+    case UNSAVE_EXPR:
+    case TRY_CATCH_EXPR:
+    case WITH_CLEANUP_EXPR:
+      return real_lvalue_p (TREE_OPERAND (ref, 0));
+
+    case STRING_CST:
+      return 1;
+
+    case VAR_DECL:
+      if (TREE_READONLY (ref) && ! TREE_STATIC (ref)
+         && DECL_LANG_SPECIFIC (ref)
+         && DECL_IN_AGGR_P (ref))
+       return 0;
+    case INDIRECT_REF:
+    case ARRAY_REF:
+    case PARM_DECL:
+    case RESULT_DECL:
+    case ERROR_MARK:
+      if (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE
+         && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE)
+       return 1;
+      break;
+
+      /* A currently unresolved scope ref.  */
+    case SCOPE_REF:
+      my_friendly_abort (103);
+    case OFFSET_REF:
+      if (TREE_CODE (TREE_OPERAND (ref, 1)) == FUNCTION_DECL)
+       return 1;
+      return real_lvalue_p (TREE_OPERAND (ref, 0))
+       && real_lvalue_p (TREE_OPERAND (ref, 1));
+      break;
+
+    case COND_EXPR:
+      return (real_lvalue_p (TREE_OPERAND (ref, 1))
+             && real_lvalue_p (TREE_OPERAND (ref, 2)));
+
+    case MODIFY_EXPR:
+      return 1;
+
+    case COMPOUND_EXPR:
+      return real_lvalue_p (TREE_OPERAND (ref, 1));
+
+    case MAX_EXPR:
+    case MIN_EXPR:
+      return (real_lvalue_p (TREE_OPERAND (ref, 0))
+             && real_lvalue_p (TREE_OPERAND (ref, 1)));
+
+    default:
+      break;
+    }
+
+  return 0;
+}
+
+/* This differs from real_lvalue_p in that class rvalues are considered
+   lvalues.  */
+int
 lvalue_p (ref)
      tree ref;
 {
-  register enum tree_code code = TREE_CODE (ref);
+  if (! language_lvalue_valid (ref))
+    return 0;
+  
+  if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE)
+    return 1;
+
+  if (ref == current_class_ptr && flag_this_is_variable <= 0)
+    return 0;
 
-  if (language_lvalue_valid (ref))
+  switch (TREE_CODE (ref))
     {
-      if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE)
+      /* preincrements and predecrements are valid lvals, provided
+        what they refer to are valid lvals.  */
+    case PREINCREMENT_EXPR:
+    case PREDECREMENT_EXPR:
+    case REALPART_EXPR:
+    case IMAGPART_EXPR:
+    case COMPONENT_REF:
+    case SAVE_EXPR:
+    case UNSAVE_EXPR:
+    case TRY_CATCH_EXPR:
+    case WITH_CLEANUP_EXPR:
+      return lvalue_p (TREE_OPERAND (ref, 0));
+
+    case STRING_CST:
+      return 1;
+
+    case VAR_DECL:
+      if (TREE_READONLY (ref) && ! TREE_STATIC (ref)
+         && DECL_LANG_SPECIFIC (ref)
+         && DECL_IN_AGGR_P (ref))
+       return 0;
+    case INDIRECT_REF:
+    case ARRAY_REF:
+    case PARM_DECL:
+    case RESULT_DECL:
+    case ERROR_MARK:
+      if (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE
+         && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE)
        return 1;
-      
-      switch (code)
-       {
-         /* preincrements and predecrements are valid lvals, provided
-            what they refer to are valid lvals. */
-       case PREINCREMENT_EXPR:
-       case PREDECREMENT_EXPR:
-       case COMPONENT_REF:
-       case SAVE_EXPR:
-         return lvalue_p (TREE_OPERAND (ref, 0));
-
-       case STRING_CST:
-         return 1;
-
-       case VAR_DECL:
-         if (TREE_READONLY (ref) && ! TREE_STATIC (ref)
-             && DECL_LANG_SPECIFIC (ref)
-             && DECL_IN_AGGR_P (ref))
-           return 0;
-       case INDIRECT_REF:
-       case ARRAY_REF:
-       case PARM_DECL:
-       case RESULT_DECL:
-       case ERROR_MARK:
-         if (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE
-             && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE)
-           return 1;
-         break;
+      break;
 
-       case TARGET_EXPR:
-       case WITH_CLEANUP_EXPR:
-         return 1;
-
-         /* A currently unresolved scope ref.  */
-       case SCOPE_REF:
-         my_friendly_abort (103);
-       case OFFSET_REF:
-         if (TREE_CODE (TREE_OPERAND (ref, 1)) == FUNCTION_DECL)
-           return 1;
-         return lvalue_p (TREE_OPERAND (ref, 0))
-           && lvalue_p (TREE_OPERAND (ref, 1));
-         break;
+    case TARGET_EXPR:
+      return 1;
 
-       case COND_EXPR:
-         return (lvalue_p (TREE_OPERAND (ref, 1))
-                 && lvalue_p (TREE_OPERAND (ref, 2)));
+    case CALL_EXPR:
+      if (IS_AGGR_TYPE (TREE_TYPE (ref)))
+       return 1;
+      break;
 
-       case MODIFY_EXPR:
-         return 1;
+      /* A currently unresolved scope ref.  */
+    case SCOPE_REF:
+      my_friendly_abort (103);
+    case OFFSET_REF:
+      if (TREE_CODE (TREE_OPERAND (ref, 1)) == FUNCTION_DECL)
+       return 1;
+      return lvalue_p (TREE_OPERAND (ref, 0))
+       && lvalue_p (TREE_OPERAND (ref, 1));
+      break;
 
-       case COMPOUND_EXPR:
-         return lvalue_p (TREE_OPERAND (ref, 1));
-       }
+    case COND_EXPR:
+      return (lvalue_p (TREE_OPERAND (ref, 1))
+             && lvalue_p (TREE_OPERAND (ref, 2)));
+
+    case MODIFY_EXPR:
+      return 1;
+
+    case COMPOUND_EXPR:
+      return lvalue_p (TREE_OPERAND (ref, 1));
+
+    case MAX_EXPR:
+    case MIN_EXPR:
+      return (lvalue_p (TREE_OPERAND (ref, 0))
+             && lvalue_p (TREE_OPERAND (ref, 1)));
+
+    default:
+      break;
     }
+
   return 0;
 }
 
@@ -117,40 +240,47 @@ lvalue_or_else (ref, string)
 
    Build an encapsulation of the initialization to perform
    and return it so that it can be processed by language-independent
-   and language-specific expression expanders.
+   and language-specific expression expanders.  */
 
-   If WITH_CLEANUP_P is nonzero, we build a cleanup for this expression.
-   Otherwise, cleanups are not built here.  For example, when building
-   an initialization for a stack slot, since the called function handles
-   the cleanup, we would not want to do it here.  */
 tree
-build_cplus_new (type, init, with_cleanup_p)
+build_cplus_new (type, init)
      tree type;
      tree init;
-     int with_cleanup_p;
 {
-  tree slot = build (VAR_DECL, type);
-  tree rval = build (NEW_EXPR, type,
-                    TREE_OPERAND (init, 0), TREE_OPERAND (init, 1), slot);
+  tree slot;
+  tree rval;
+
+  if (TREE_CODE (init) != CALL_EXPR && TREE_CODE (init) != AGGR_INIT_EXPR)
+    return init;
+
+  slot = build (VAR_DECL, type);
+  DECL_ARTIFICIAL (slot) = 1;
+  layout_decl (slot, 0);
+  rval = build (AGGR_INIT_EXPR, type,
+               TREE_OPERAND (init, 0), TREE_OPERAND (init, 1), slot);
   TREE_SIDE_EFFECTS (rval) = 1;
-  TREE_ADDRESSABLE (rval) = 1;
-  rval = build (TARGET_EXPR, type, slot, rval, 0);
+  rval = build (TARGET_EXPR, type, slot, rval, NULL_TREE, NULL_TREE);
+  TREE_SIDE_EFFECTS (rval) = 1;
+
+  return rval;
+}
+
+/* Encapsulate the expression INIT in a TARGET_EXPR.  */
+
+tree
+get_target_expr (init)
+     tree init;
+{
+  tree slot;
+  tree rval;
+
+  slot = build (VAR_DECL, TREE_TYPE (init));
+  DECL_ARTIFICIAL (slot) = 1;
+  layout_decl (slot, 0);
+  rval = build (TARGET_EXPR, TREE_TYPE (init), slot, init,
+               NULL_TREE, NULL_TREE);
   TREE_SIDE_EFFECTS (rval) = 1;
-  TREE_ADDRESSABLE (rval) = 1;
 
-#if 0
-  if (with_cleanup_p && TYPE_NEEDS_DESTRUCTOR (type))
-    {
-      TREE_OPERAND (rval, 2) = error_mark_node;
-      rval = build (WITH_CLEANUP_EXPR, type, rval, 0,
-                   build_delete (TYPE_POINTER_TO (type),
-                                 build_unary_op (ADDR_EXPR, slot, 0),
-                                 integer_two_node,
-                                 LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0));
-      TREE_SIDE_EFFECTS (rval) = 1;
-      TREE_ADDRESSABLE (rval) = 1;
-    }
-#endif
   return rval;
 }
 
@@ -165,7 +295,7 @@ break_out_cleanups (exp)
 
   if (TREE_CODE (tmp) == CALL_EXPR
       && TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (tmp)))
-    return build_cplus_new (TREE_TYPE (tmp), tmp, 1);
+    return build_cplus_new (TREE_TYPE (tmp), tmp);
 
   while (TREE_CODE (tmp) == NOP_EXPR
         || TREE_CODE (tmp) == CONVERT_EXPR
@@ -176,7 +306,7 @@ break_out_cleanups (exp)
        {
          TREE_OPERAND (tmp, 0)
            = build_cplus_new (TREE_TYPE (TREE_OPERAND (tmp, 0)),
-                              TREE_OPERAND (tmp, 0), 1);
+                              TREE_OPERAND (tmp, 0));
          break;
        }
       else
@@ -206,7 +336,7 @@ break_out_calls (exp)
   if (code == CALL_EXPR)
     return copy_node (exp);
 
-  /* Don't try and defeat a save_expr, as it should only be done once. */
+  /* Don't try and defeat a save_expr, as it should only be done once.  */
     if (code == SAVE_EXPR)
        return exp;
 
@@ -221,12 +351,15 @@ break_out_calls (exp)
       return exp;
 
     case 'd':  /* A decl node */
+#if 0                               /* This is bogus.  jason 9/21/94 */
+
       t1 = break_out_calls (DECL_INITIAL (exp));
       if (t1 != DECL_INITIAL (exp))
        {
          exp = copy_node (exp);
          DECL_INITIAL (exp) = t1;
        }
+#endif
       return exp;
 
     case 'b':  /* A block node */
@@ -276,6 +409,7 @@ break_out_calls (exp)
 extern struct obstack *current_obstack;
 extern struct obstack permanent_obstack, class_obstack;
 extern struct obstack *saveable_obstack;
+extern struct obstack *expression_obstack;
 
 /* Here is how primitive or already-canonicalized types' hash
    codes are made.  MUST BE CONSISTENT WITH tree.c !!! */
@@ -284,6 +418,7 @@ extern struct obstack *saveable_obstack;
 /* Construct, lay out and return the type of methods belonging to class
    BASETYPE and whose arguments are described by ARGTYPES and whose values
    are described by RETTYPE.  If each type exists already, reuse it.  */
+
 tree
 build_cplus_method_type (basetype, rettype, argtypes)
      tree basetype, rettype, argtypes;
@@ -302,10 +437,8 @@ build_cplus_method_type (basetype, rettype, argtypes)
                                          TYPE_READONLY (basetype),
                                          TYPE_VOLATILE (basetype));
   else
-    {
-      ptype = build_pointer_type (basetype);
-      ptype = build_type_variant (ptype, 1, 0);
-    }
+    ptype = build_pointer_type (basetype);
+
   /* The actual arglist for this function includes a "hidden" argument
      which is "this".  Put it into the list of argument types.  */
 
@@ -324,34 +457,8 @@ build_cplus_method_type (basetype, rettype, argtypes)
   return t;
 }
 
-tree
-build_cplus_staticfn_type (basetype, rettype, argtypes)
-     tree basetype, rettype, argtypes;
-{
-  register tree t;
-  int hashcode;
-
-  /* Make a node of the sort we want.  */
-  t = make_node (FUNCTION_TYPE);
-
-  TYPE_METHOD_BASETYPE (t) = TYPE_MAIN_VARIANT (basetype);
-  TREE_TYPE (t) = rettype;
-
-  TYPE_ARG_TYPES (t) = argtypes;
-
-  /* If we already have such a type, use the old one and free this one.
-     Note that it also frees up the above cons cell if found.  */
-  hashcode = TYPE_HASH (basetype) + TYPE_HASH (rettype) + type_hash_list (argtypes);
-  t = type_hash_canon (hashcode, t);
-
-  if (TYPE_SIZE (t) == 0)
-    layout_type (t);
-
-  return t;
-}
-
-tree
-build_cplus_array_type (elt_type, index_type)
+static tree
+build_cplus_array_type_1 (elt_type, index_type)
      tree elt_type;
      tree index_type;
 {
@@ -368,7 +475,14 @@ build_cplus_array_type (elt_type, index_type)
       saveable_obstack = &permanent_obstack;
     }
 
-  t = build_array_type (elt_type, index_type);
+  if (processing_template_decl)
+    {
+      t = make_node (ARRAY_TYPE);
+      TREE_TYPE (t) = elt_type;
+      TYPE_DOMAIN (t) = index_type;
+    }
+  else
+    t = build_array_type (elt_type, index_type);
 
   /* Push these needs up so that initialization takes place
      more easily.  */
@@ -378,6 +492,62 @@ build_cplus_array_type (elt_type, index_type)
   saveable_obstack = ambient_saveable_obstack;
   return t;
 }
+
+tree
+build_cplus_array_type (elt_type, index_type)
+     tree elt_type;
+     tree index_type;
+{
+  tree t;
+  int constp = TYPE_READONLY (elt_type);
+  int volatilep = TYPE_VOLATILE (elt_type);
+  elt_type = TYPE_MAIN_VARIANT (elt_type);
+
+  t = build_cplus_array_type_1 (elt_type, index_type);
+
+  if (constp || volatilep)
+    t = cp_build_type_variant (t, constp, volatilep);
+
+  return t;
+}
+\f
+/* Make a variant type in the proper way for C/C++, propagating qualifiers
+   down to the element type of an array.  */
+
+tree
+cp_build_type_variant (type, constp, volatilep)
+     tree type;
+     int constp, volatilep;
+{
+  if (type == error_mark_node)
+    return type;
+  
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      tree real_main_variant = TYPE_MAIN_VARIANT (type);
+
+      push_obstacks (TYPE_OBSTACK (real_main_variant),
+                    TYPE_OBSTACK (real_main_variant));
+      type = build_cplus_array_type_1 (cp_build_type_variant
+                                      (TREE_TYPE (type), constp, volatilep),
+                                      TYPE_DOMAIN (type));
+
+      /* TYPE must be on same obstack as REAL_MAIN_VARIANT.  If not,
+        make a copy.  (TYPE might have come from the hash table and
+        REAL_MAIN_VARIANT might be in some function's obstack.)  */
+
+      if (TYPE_OBSTACK (type) != TYPE_OBSTACK (real_main_variant))
+       {
+         type = copy_node (type);
+         TYPE_POINTER_TO (type) = TYPE_REFERENCE_TO (type) = 0;
+       }
+
+      TYPE_MAIN_VARIANT (type) = real_main_variant;
+      pop_obstacks ();
+      return type;
+    }
+  return build_type_variant (type, constp, volatilep);
+}
 \f
 /* Add OFFSET to all base types of T.
 
@@ -385,6 +555,7 @@ build_cplus_array_type (elt_type, index_type)
 
    Note that we don't have to worry about having two paths to the
    same base type, since this type owns its association list.  */
+
 void
 propagate_binfo_offsets (binfo, offset)
      tree binfo;
@@ -445,6 +616,7 @@ propagate_binfo_offsets (binfo, offset)
                  chain = TREE_VEC_ELT (base_binfos, k);
                  TREE_VIA_PUBLIC (chain) = TREE_VIA_PUBLIC (base_base_binfo);
                  TREE_VIA_PROTECTED (chain) = TREE_VIA_PROTECTED (base_base_binfo);
+                 BINFO_INHERITANCE_CHAIN (chain) = base_binfo;
                }
              /* Now propagate the offset to the base types.  */
              propagate_binfo_offsets (base_binfo, offset);
@@ -465,6 +637,7 @@ propagate_binfo_offsets (binfo, offset)
 
    Returns the maximum number of virtual functions any of the virtual
    baseclasses provide.  */
+
 int
 layout_vbasetypes (rec, max)
      tree rec;
@@ -489,7 +662,6 @@ layout_vbasetypes (rec, max)
   register unsigned const_size = 0;
   register tree var_size = 0;
   int nonvirtual_const_size;
-  tree nonvirtual_var_size;
 
   CLASSTYPE_VBASECLASSES (rec) = vbase_types;
 
@@ -499,7 +671,6 @@ layout_vbasetypes (rec, max)
     var_size = TYPE_SIZE (rec);
 
   nonvirtual_const_size = const_size;
-  nonvirtual_var_size = var_size;
 
   while (vbase_types)
     {
@@ -524,9 +695,13 @@ layout_vbasetypes (rec, max)
       BINFO_OFFSET (vbase_types) = offset;
 
       if (TREE_CODE (TYPE_SIZE (basetype)) == INTEGER_CST)
-       const_size += MAX (BITS_PER_UNIT,
-                          TREE_INT_CST_LOW (TYPE_SIZE (basetype))
-                          - TREE_INT_CST_LOW (CLASSTYPE_VBASE_SIZE (basetype)));
+       {
+         /* Every virtual baseclass takes a least a UNIT, so that we can
+            take it's address and get something different for each base.  */
+         const_size += MAX (BITS_PER_UNIT,
+                            TREE_INT_CST_LOW (TYPE_SIZE (basetype))
+                            - TREE_INT_CST_LOW (CLASSTYPE_VBASE_SIZE (basetype)));
+       }
       else if (var_size == 0)
        var_size = TYPE_SIZE (basetype);
       else
@@ -535,6 +710,15 @@ layout_vbasetypes (rec, max)
       vbase_types = TREE_CHAIN (vbase_types);
     }
 
+  if (const_size)
+    {
+      /* Because a virtual base might take a single byte above,
+        we have to re-adjust the total size to make sure it it
+        a multiple of the alignment.  */
+      /* Give the whole object the alignment it wants.  */
+      const_size = CEIL (const_size, record_align) * record_align;
+    }
+
   /* Set the alignment in the complete type.  We don't set CLASSTYPE_ALIGN
    here, as that is for this class, without any virtual base classes.  */
   TYPE_ALIGN (rec) = record_align;
@@ -552,6 +736,8 @@ layout_vbasetypes (rec, max)
     {
       tree base_binfos = BINFO_BASETYPES (vbase_types);
 
+      BINFO_INHERITANCE_CHAIN (vbase_types) = TYPE_BINFO (rec);
+
       if (base_binfos)
        {
          tree chain = NULL_TREE;
@@ -572,6 +758,7 @@ layout_vbasetypes (rec, max)
              chain = TREE_VEC_ELT (base_binfos, j);
              TREE_VIA_PUBLIC (chain) = TREE_VIA_PUBLIC (base_base_binfo);
              TREE_VIA_PROTECTED (chain) = TREE_VIA_PROTECTED (base_base_binfo);
+             BINFO_INHERITANCE_CHAIN (chain) = vbase_types;
            }
 
          propagate_binfo_offsets (vbase_types, BINFO_OFFSET (vbase_types));
@@ -591,6 +778,7 @@ layout_vbasetypes (rec, max)
    creates a list of base_binfos in TYPE_BINFO (REC) from BINFOS.
 
    Returns list of virtual base classes in a FIELD_DECL chain.  */
+
 tree
 layout_basetypes (rec, binfos)
      tree rec, binfos;
@@ -608,7 +796,7 @@ layout_basetypes (rec, binfos)
   /* Record size so far is CONST_SIZE + VAR_SIZE bits, where CONST_SIZE is
      an integer and VAR_SIZE is a tree expression.  If VAR_SIZE is null,
      the size is just CONST_SIZE.  Naturally we try to avoid using
-     VAR_SIZE.  And so far, we've been sucessful. */
+     VAR_SIZE.  And so far, we've been successful.  */
 #if 0
   register tree var_size = 0;
 #endif
@@ -643,7 +831,7 @@ layout_basetypes (rec, binfos)
             class A;
             class B: private A { virtual void F(); };
 
-            does not dump core when compiled. */
+            does not dump core when compiled.  */
          my_friendly_abort (121);
 #endif
          continue;
@@ -675,36 +863,36 @@ layout_basetypes (rec, binfos)
                goto got_it;
            }
          sprintf (name, VBASE_NAME_FORMAT, TYPE_NAME_STRING (basetype));
-         decl = build_lang_decl (FIELD_DECL, get_identifier (name),
-                                 build_pointer_type (basetype));
+         decl = build_lang_field_decl (FIELD_DECL, get_identifier (name),
+                                       build_pointer_type (basetype));
          /* If you change any of the below, take a look at all the
             other VFIELD_BASEs and VTABLE_BASEs in the code, and change
-            them too. */
+            them too.  */
          DECL_ASSEMBLER_NAME (decl) = get_identifier (VTABLE_BASE);
          DECL_VIRTUAL_P (decl) = 1;
+         DECL_ARTIFICIAL (decl) = 1;
          DECL_FIELD_CONTEXT (decl) = rec;
          DECL_CLASS_CONTEXT (decl) = rec;
          DECL_FCONTEXT (decl) = basetype;
+         DECL_SAVED_INSNS (decl) = NULL_RTX;
          DECL_FIELD_SIZE (decl) = 0;
          DECL_ALIGN (decl) = TYPE_ALIGN (ptr_type_node);
          TREE_CHAIN (decl) = vbase_decls;
          BINFO_VPTR_FIELD (base_binfo) = decl;
          vbase_decls = decl;
 
-         if (warn_nonvdtor && TYPE_HAS_DESTRUCTOR (basetype)
-             && DECL_VINDEX (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0)) == NULL_TREE)
-           {
-             warning_with_decl (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0),
-                                "destructor `%s' non-virtual");
-             warning ("in inheritance relationship `%s: virtual %s'",
-                      TYPE_NAME_STRING (rec),
-                      TYPE_NAME_STRING (basetype));
-           }
        got_it:
          /* The space this decl occupies has already been accounted for.  */
          continue;
        }
 
+      /* Effective C++ rule 14.  We only need to check TYPE_VIRTUAL_P
+        here because the case of virtual functions but non-virtual
+        dtor is handled in finish_struct_1.  */
+      if (warn_ecpp && ! TYPE_VIRTUAL_P (basetype)
+         && TYPE_HAS_DESTRUCTOR (basetype))
+       cp_warning ("base class `%#T' has a non-virtual destructor", basetype);
+
       if (const_size == 0)
        offset = integer_zero_node;
       else
@@ -713,22 +901,6 @@ layout_basetypes (rec, binfos)
          const_size = CEIL (const_size, TYPE_ALIGN (basetype))
            * TYPE_ALIGN (basetype);
          offset = size_int ((const_size + BITS_PER_UNIT - 1) / BITS_PER_UNIT);
-
-#if 0
-         /* bpk: Disabled this check until someone is willing to
-            claim it as theirs and explain exactly what circumstances
-            warrant the warning.  */ 
-         if (warn_nonvdtor && TYPE_HAS_DESTRUCTOR (basetype)
-             && DECL_VINDEX (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0)) == NULL_TREE)
-           {
-             warning_with_decl (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0),
-                                "destructor `%s' non-virtual");
-             warning ("in inheritance relationship `%s:%s %s'",
-                      TYPE_NAME_STRING (rec),
-                      TREE_VIA_VIRTUAL (base_binfo) ? " virtual" : "",
-                      TYPE_NAME_STRING (basetype));
-           }
-#endif
        }
       BINFO_OFFSET (base_binfo) = offset;
       if (CLASSTYPE_VSIZE (basetype))
@@ -786,27 +958,27 @@ struct list_hash
    and the hash code is computed differently for each of these.  */
 
 #define TYPE_HASH_SIZE 59
-struct list_hash *list_hash_table[TYPE_HASH_SIZE];
+static struct list_hash *list_hash_table[TYPE_HASH_SIZE];
 
 /* Compute a hash code for a list (chain of TREE_LIST nodes
    with goodies in the TREE_PURPOSE, TREE_VALUE, and bits of the
    TREE_COMMON slots), by adding the hash codes of the individual entries.  */
 
-int
-list_hash (list)
-     tree list;
+static int
+list_hash (purpose, value, chain)
+     tree purpose, value, chain;
 {
   register int hashcode = 0;
 
-  if (TREE_CHAIN (list))
-    hashcode += TYPE_HASH (TREE_CHAIN (list));
+  if (chain)
+    hashcode += TYPE_HASH (chain);
 
-  if (TREE_VALUE (list))
-    hashcode += TYPE_HASH (TREE_VALUE (list));
+  if (value)
+    hashcode += TYPE_HASH (value);
   else
     hashcode += 1007;
-  if (TREE_PURPOSE (list))
-    hashcode += TYPE_HASH (TREE_PURPOSE (list));
+  if (purpose)
+    hashcode += TYPE_HASH (purpose);
   else
     hashcode += 1009;
   return hashcode;
@@ -815,31 +987,30 @@ list_hash (list)
 /* Look in the type hash table for a type isomorphic to TYPE.
    If one is found, return it.  Otherwise return 0.  */
 
-tree
-list_hash_lookup (hashcode, list)
-     int hashcode;
-     tree list;
+static tree
+list_hash_lookup (hashcode, via_public, via_protected, via_virtual,
+                 purpose, value, chain)
+     int hashcode, via_public, via_virtual, via_protected;
+     tree purpose, value, chain;
 {
   register struct list_hash *h;
+
   for (h = list_hash_table[hashcode % TYPE_HASH_SIZE]; h; h = h->next)
     if (h->hashcode == hashcode
-       && TREE_VIA_VIRTUAL (h->list) == TREE_VIA_VIRTUAL (list)
-       && TREE_VIA_PUBLIC (h->list) == TREE_VIA_PUBLIC (list)
-       && TREE_VIA_PROTECTED (h->list) == TREE_VIA_PROTECTED (list)
-       && TREE_PURPOSE (h->list) == TREE_PURPOSE (list)
-       && TREE_VALUE (h->list) == TREE_VALUE (list)
-       && TREE_CHAIN (h->list) == TREE_CHAIN (list))
-      {
-       my_friendly_assert (TREE_TYPE (h->list) == TREE_TYPE (list), 299);
-       return h->list;
-      }
+       && TREE_VIA_VIRTUAL (h->list) == via_virtual
+       && TREE_VIA_PUBLIC (h->list) == via_public
+       && TREE_VIA_PROTECTED (h->list) == via_protected
+       && TREE_PURPOSE (h->list) == purpose
+       && TREE_VALUE (h->list) == value
+       && TREE_CHAIN (h->list) == chain)
+      return h->list;
   return 0;
 }
 
 /* Add an entry to the list-hash-table
    for a list TYPE whose hash code is HASHCODE.  */
 
-void
+static void
 list_hash_add (hashcode, list)
      int hashcode;
      tree list;
@@ -865,30 +1036,8 @@ list_hash_add (hashcode, list)
    This function frees the list you pass in if it is a duplicate.  */
 
 /* Set to 1 to debug without canonicalization.  Never set by program.  */
-static int debug_no_list_hash = 0;
-
-tree
-list_hash_canon (hashcode, list)
-     int hashcode;
-     tree list;
-{
-  tree t1;
-
-  if (debug_no_list_hash)
-    return list;
-
-  t1 = list_hash_lookup (hashcode, list);
-  if (t1 != 0)
-    {
-      obstack_free (&class_obstack, list);
-      return t1;
-    }
-
-  /* If this is a new list, record it for later reuse.  */
-  list_hash_add (hashcode, list);
 
-  return list;
-}
+static int debug_no_list_hash = 0;
 
 tree
 hash_tree_cons (via_public, via_virtual, via_protected, purpose, value, chain)
@@ -899,35 +1048,41 @@ hash_tree_cons (via_public, via_virtual, via_protected, purpose, value, chain)
   tree t;
   int hashcode;
 
+  if (! debug_no_list_hash)
+    {
+      hashcode = list_hash (purpose, value, chain);
+      t = list_hash_lookup (hashcode, via_public, via_protected, via_virtual,
+                           purpose, value, chain);
+      if (t)
+       return t;
+    }
+
   current_obstack = &class_obstack;
+
   t = tree_cons (purpose, value, chain);
   TREE_VIA_PUBLIC (t) = via_public;
   TREE_VIA_PROTECTED (t) = via_protected;
   TREE_VIA_VIRTUAL (t) = via_virtual;
-  hashcode = list_hash (t);
-  t = list_hash_canon (hashcode, t);
+
+  /* If this is a new list, record it for later reuse.  */
+  if (! debug_no_list_hash)
+    list_hash_add (hashcode, t);
+
   current_obstack = ambient_obstack;
   return t;
 }
 
 /* Constructor for hashed lists.  */
+
 tree
 hash_tree_chain (value, chain)
      tree value, chain;
 {
-  struct obstack *ambient_obstack = current_obstack;
-  tree t;
-  int hashcode;
-
-  current_obstack = &class_obstack;
-  t = tree_cons (NULL_TREE, value, chain);
-  hashcode = list_hash (t);
-  t = list_hash_canon (hashcode, t);
-  current_obstack = ambient_obstack;
-  return t;
+  return hash_tree_cons (0, 0, 0, NULL_TREE, value, chain);
 }
 
 /* Similar, but used for concatenating two lists.  */
+
 tree
 hash_chainon (list1, list2)
      tree list1, list2;
@@ -965,17 +1120,9 @@ get_identifier_list (value)
        list = tree_cons (NULL_TREE, value, NULL_TREE);
       else
        {
-         register tree id;
-         /* This will return the correct thing for regular types,
-            nested types, and templates.  Yay! */
-         if (TYPE_NESTED_NAME (type))
-           id = TYPE_NESTED_NAME (type);
-         else
-           id = TYPE_IDENTIFIER (type);
-
-         if (CLASSTYPE_ID_AS_LIST (type) == NULL_TREE)
+         if (! CLASSTYPE_ID_AS_LIST (type))
            CLASSTYPE_ID_AS_LIST (type)
-             = perm_tree_cons (NULL_TREE, id, NULL_TREE);
+             = perm_tree_cons (NULL_TREE, TYPE_IDENTIFIER (type), NULL_TREE);
          list = CLASSTYPE_ID_AS_LIST (type);
        }
     }
@@ -991,7 +1138,8 @@ get_decl_list (value)
   if (TREE_CODE (value) == IDENTIFIER_NODE)
     list = get_identifier_list (value);
   else if (TREE_CODE (value) == RECORD_TYPE
-          && TYPE_LANG_SPECIFIC (value))
+          && TYPE_LANG_SPECIFIC (value)
+          && value == TYPE_MAIN_VARIANT (value))
     list = CLASSTYPE_AS_LIST (value);
 
   if (list != NULL_TREE)
@@ -1002,69 +1150,16 @@ get_decl_list (value)
 
   return build_decl_list (NULL_TREE, value);
 }
+\f
+/* Build an association between TYPE and some parameters:
 
-/* Look in the type hash table for a type isomorphic to
-   `build_tree_list (NULL_TREE, VALUE)'.
-   If one is found, return it.  Otherwise return 0.  */
+   OFFSET is the offset added to `this' to convert it to a pointer
+   of type `TYPE *'
 
-tree
-list_hash_lookup_or_cons (value)
-     tree value;
-{
-  register int hashcode = TYPE_HASH (value);
-  register struct list_hash *h;
-  struct obstack *ambient_obstack;
-  tree list = NULL_TREE;
-
-  if (TREE_CODE (value) == IDENTIFIER_NODE)
-    list = get_identifier_list (value);
-  else if (TREE_CODE (value) == TYPE_DECL
-          && TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE
-          && TYPE_LANG_SPECIFIC (TREE_TYPE (value)))
-    list = CLASSTYPE_ID_AS_LIST (TREE_TYPE (value));
-  else if (TREE_CODE (value) == RECORD_TYPE
-          && TYPE_LANG_SPECIFIC (value))
-    list = CLASSTYPE_AS_LIST (value);
-
-  if (list != NULL_TREE)
-    {
-      my_friendly_assert (TREE_CHAIN (list) == NULL_TREE, 302);
-      return list;
-    }
-
-  if (debug_no_list_hash)
-    return hash_tree_chain (value, NULL_TREE);
-
-  for (h = list_hash_table[hashcode % TYPE_HASH_SIZE]; h; h = h->next)
-    if (h->hashcode == hashcode
-       && TREE_VIA_VIRTUAL (h->list) == 0
-       && TREE_VIA_PUBLIC (h->list) == 0
-       && TREE_VIA_PROTECTED (h->list) == 0
-       && TREE_PURPOSE (h->list) == 0
-       && TREE_VALUE (h->list) == value)
-      {
-       my_friendly_assert (TREE_TYPE (h->list) == 0, 303);
-       my_friendly_assert (TREE_CHAIN (h->list) == 0, 304);
-       return h->list;
-      }
-
-  ambient_obstack = current_obstack;
-  current_obstack = &class_obstack;
-  list = build_tree_list (NULL_TREE, value);
-  list_hash_add (hashcode, list);
-  current_obstack = ambient_obstack;
-  return list;
-}
-\f
-/* Build an association between TYPE and some parameters:
-
-   OFFSET is the offset added to `this' to convert it to a pointer
-   of type `TYPE *'
-
-   BINFO is the base binfo to use, if we are deriving from one.  This
-   is necessary, as we want specialized parent binfos from base
-   classes, so that the VTABLE_NAMEs of bases are for the most derived
-   type, instead of of the simple type.
+   BINFO is the base binfo to use, if we are deriving from one.  This
+   is necessary, as we want specialized parent binfos from base
+   classes, so that the VTABLE_NAMEs of bases are for the most derived
+   type, instead of of the simple type.
 
    VTABLE is the virtual function table with which to initialize
    sub-objects of type TYPE.
@@ -1105,22 +1200,6 @@ make_binfo (offset, binfo, vtable, virtuals, chain)
   return new_binfo;
 }
 
-tree
-copy_binfo (list)
-     tree list;
-{
-  tree binfo = copy_list (list);
-  tree rval = binfo;
-  while (binfo)
-    {
-      TREE_USED (binfo) = 0;
-      if (BINFO_BASETYPES (binfo))
-       BINFO_BASETYPES (binfo) = copy_node (BINFO_BASETYPES (binfo));
-      binfo = TREE_CHAIN (binfo);
-    }
-  return rval;
-}
-
 /* Return the binfo value for ELEM in TYPE.  */
 
 tree
@@ -1152,87 +1231,11 @@ reverse_path (path)
   return prev;
 }
 
-tree
-virtual_member (elem, list)
-     tree elem;
-     tree list;
-{
-  tree t;
-  tree rval, nval;
-
-  for (t = list; t; t = TREE_CHAIN (t))
-    if (elem == BINFO_TYPE (t))
-      return t;
-  rval = 0;
-  for (t = list; t; t = TREE_CHAIN (t))
-    {
-      tree binfos = BINFO_BASETYPES (t);
-      int i;
-
-      if (binfos != NULL_TREE)
-       for (i = TREE_VEC_LENGTH (binfos)-1; i >= 0; i--)
-         {
-           nval = binfo_value (elem, BINFO_TYPE (TREE_VEC_ELT (binfos, i)));
-           if (nval)
-             {
-               if (rval && BINFO_OFFSET (nval) != BINFO_OFFSET (rval))
-                 my_friendly_abort (104);
-               rval = nval;
-             }
-         }
-    }
-  return rval;
-}
-
-/* Return the offset (as an INTEGER_CST) for ELEM in LIST.
-   INITIAL_OFFSET is the value to add to the offset that ELEM's
-   binfo entry in LIST provides.
-
-   Returns NULL if ELEM does not have an binfo value in LIST.  */
-
-tree
-virtual_offset (elem, list, initial_offset)
-     tree elem;
-     tree list;
-     tree initial_offset;
-{
-  tree vb, offset;
-  tree rval, nval;
-
-  for (vb = list; vb; vb = TREE_CHAIN (vb))
-    if (elem == BINFO_TYPE (vb))
-      return size_binop (PLUS_EXPR, initial_offset, BINFO_OFFSET (vb));
-  rval = 0;
-  for (vb = list; vb; vb = TREE_CHAIN (vb))
-    {
-      tree binfos = BINFO_BASETYPES (vb);
-      int i;
-
-      if (binfos == NULL_TREE)
-       continue;
-
-      for (i = TREE_VEC_LENGTH (binfos)-1; i >= 0; i--)
-       {
-         nval = binfo_value (elem, BINFO_TYPE (TREE_VEC_ELT (binfos, i)));
-         if (nval)
-           {
-             if (rval && BINFO_OFFSET (nval) != BINFO_OFFSET (rval))
-               my_friendly_abort (105);
-             offset = BINFO_OFFSET (vb);
-             rval = nval;
-           }
-       }
-    }
-  if (rval == NULL_TREE)
-    return rval;
-  return size_binop (PLUS_EXPR, offset, BINFO_OFFSET (rval));
-}
-
 void
 debug_binfo (elem)
      tree elem;
 {
-  int i;
+  unsigned HOST_WIDE_INT n;
   tree virtuals;
 
   fprintf (stderr, "type \"%s\"; offset = %d\n",
@@ -1246,21 +1249,17 @@ debug_binfo (elem)
     fprintf (stderr, "no vtable decl yet\n");
   fprintf (stderr, "virtuals:\n");
   virtuals = BINFO_VIRTUALS (elem);
-  if (virtuals != 0)
-    {
-      virtuals = TREE_CHAIN (virtuals);
-      if (flag_dossier)
-       virtuals = TREE_CHAIN (virtuals);
-    }
-  i = 1;
+
+  n = skip_rtti_stuff (&virtuals);
+
   while (virtuals)
     {
       tree fndecl = TREE_OPERAND (FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals)), 0);
       fprintf (stderr, "%s [%d =? %d]\n",
               IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl)),
-              i, TREE_INT_CST_LOW (DECL_VINDEX (fndecl)));
+              n, TREE_INT_CST_LOW (DECL_VINDEX (fndecl)));
+      ++n;
       virtuals = TREE_CHAIN (virtuals);
-      i += 1;
     }
 }
 
@@ -1293,32 +1292,21 @@ count_functions (t)
     return decl_list_length (TREE_VALUE (t));
 
   my_friendly_abort (359);
-}
-
-/* Like value_member, but for DECL_CHAINs.  */
-tree
-decl_value_member (elem, list)
-     tree elem, list;
-{
-  while (list)
-    {
-      if (elem == list)
-       return list;
-      list = DECL_CHAIN (list);
-    }
-  return NULL_TREE;
+  return 0;
 }
 
 int
 is_overloaded_fn (x)
      tree x;
 {
-  if (TREE_CODE (x) == FUNCTION_DECL)
+  if (TREE_CODE (x) == FUNCTION_DECL
+      || TREE_CODE (x) == TEMPLATE_ID_EXPR
+      || DECL_FUNCTION_TEMPLATE_P (x))
     return 1;
 
   if (TREE_CODE (x) == TREE_LIST
       && (TREE_CODE (TREE_VALUE (x)) == FUNCTION_DECL
-         || TREE_CODE (TREE_VALUE (x)) == TEMPLATE_DECL))
+         || DECL_FUNCTION_TEMPLATE_P (TREE_VALUE (x))))
     return 1;
 
   return 0;
@@ -1328,19 +1316,17 @@ int
 really_overloaded_fn (x)
      tree x;
 {     
-  if (TREE_CODE (x) == TREE_LIST
-      && (TREE_CODE (TREE_VALUE (x)) == FUNCTION_DECL
-         || TREE_CODE (TREE_VALUE (x)) == TEMPLATE_DECL))
-    return 1;
-
-  return 0;
+  return TREE_CODE (x) != FUNCTION_DECL 
+    && is_overloaded_fn (x);
 }
 
 tree
 get_first_fn (from)
      tree from;
 {
-  if (TREE_CODE (from) == FUNCTION_DECL)
+  if (TREE_CODE (from) == FUNCTION_DECL
+      || TREE_CODE (from) == TEMPLATE_ID_EXPR
+      || DECL_FUNCTION_TEMPLATE_P (from))
     return from;
 
   my_friendly_assert (TREE_CODE (from) == TREE_LIST, 9);
@@ -1348,51 +1334,6 @@ get_first_fn (from)
   return TREE_VALUE (from);
 }
 
-tree
-fnaddr_from_vtable_entry (entry)
-     tree entry;
-{
-  if (flag_vtable_thunks)
-    {
-      tree func = entry;
-      if (TREE_CODE (func) == ADDR_EXPR)
-       func = TREE_OPERAND (func, 0);
-      if (TREE_CODE (func) == THUNK_DECL)
-       return DECL_INITIAL (func);
-      else
-       return entry;
-    }
-  else
-    return TREE_VALUE (TREE_CHAIN (TREE_CHAIN (CONSTRUCTOR_ELTS (entry))));
-}
-
-void
-set_fnaddr_from_vtable_entry (entry, value)
-     tree entry, value;
-{
-  if (flag_vtable_thunks)
-    abort ();
-  else
-  TREE_VALUE (TREE_CHAIN (TREE_CHAIN (CONSTRUCTOR_ELTS (entry)))) = value;
-}
-
-tree
-function_arg_chain (t)
-     tree t;
-{
-  return TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (t)));
-}
-
-int
-promotes_to_aggr_type (t, code)
-     tree t;
-     enum tree_code code;
-{
-  if (TREE_CODE (t) == code)
-    t = TREE_TYPE (t);
-  return IS_AGGR_TYPE (t);
-}
-
 int
 is_aggr_type_2 (t1, t2)
      tree t1, t2;
@@ -1401,30 +1342,13 @@ is_aggr_type_2 (t1, t2)
     return 0;
   return IS_AGGR_TYPE (t1) && IS_AGGR_TYPE (t2);
 }
-
-/* Give message using types TYPE1 and TYPE2 as arguments.
-   PFN is the function which will print the message;
-   S is the format string for PFN to use.  */
-void
-message_2_types (pfn, s, type1, type2)
-     void (*pfn) ();
-     char *s;
-     tree type1, type2;
-{
-  tree name1 = TYPE_NAME (type1);
-  tree name2 = TYPE_NAME (type2);
-  if (TREE_CODE (name1) == TYPE_DECL)
-    name1 = DECL_NAME (name1);
-  if (TREE_CODE (name2) == TYPE_DECL)
-    name2 = DECL_NAME (name2);
-  (*pfn) (s, IDENTIFIER_POINTER (name1), IDENTIFIER_POINTER (name2));
-}
 \f
 #define PRINT_RING_SIZE 4
 
 char *
-lang_printable_name (decl)
+lang_printable_name (decl, v)
      tree decl;
+     int v;
 {
   static tree decl_ring[PRINT_RING_SIZE];
   static char *print_ring[PRINT_RING_SIZE];
@@ -1432,9 +1356,10 @@ lang_printable_name (decl)
   int i;
 
   /* Only cache functions.  */
-  if (TREE_CODE (decl) != FUNCTION_DECL
+  if (v < 2
+      || TREE_CODE (decl) != FUNCTION_DECL
       || DECL_LANG_SPECIFIC (decl) == 0)
-    return decl_as_string (decl, 1);
+    return lang_decl_name (decl, v);
 
   /* See if this print name is lying around.  */
   for (i = 0; i < PRINT_RING_SIZE; i++)
@@ -1458,73 +1383,41 @@ lang_printable_name (decl)
   if (print_ring[ring_counter])
     free (print_ring[ring_counter]);
 
-  {
-    int print_ret_type_p
-      = (!DECL_CONSTRUCTOR_P (decl)
-        && !DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl)));
-
-    char *name = (char *)decl_as_string (decl, print_ret_type_p);
-    print_ring[ring_counter] = (char *)malloc (strlen (name) + 1);
-    strcpy (print_ring[ring_counter], name);
-    decl_ring[ring_counter] = decl;
-  }
+  print_ring[ring_counter] = xstrdup (lang_decl_name (decl, v));
+  decl_ring[ring_counter] = decl;
   return print_ring[ring_counter];
 }
 \f
-/* Comparison function for sorting identifiers in RAISES lists.
-   Note that because IDENTIFIER_NODEs are unique, we can sort
-   them by address, saving an indirection.  */
-static int
-id_cmp (p1, p2)
-     tree *p1, *p2;
-{
-  return (HOST_WIDE_INT)TREE_VALUE (*p1) - (HOST_WIDE_INT)TREE_VALUE (*p2);
-}
-
-/* Build the FUNCTION_TYPE or METHOD_TYPE which may raise exceptions
+/* Build the FUNCTION_TYPE or METHOD_TYPE which may throw exceptions
    listed in RAISES.  */
+
 tree
-build_exception_variant (ctype, type, raises)
-     tree ctype, type;
+build_exception_variant (type, raises)
+     tree type;
      tree raises;
 {
-  int i;
   tree v = TYPE_MAIN_VARIANT (type);
-  tree t, t2, cname;
-  tree *a = (tree *)alloca ((list_length (raises)+1) * sizeof (tree));
   int constp = TYPE_READONLY (type);
   int volatilep = TYPE_VOLATILE (type);
 
-  for (v = TYPE_NEXT_VARIANT (v); v; v = TYPE_NEXT_VARIANT (v))
+  for (; v; v = TYPE_NEXT_VARIANT (v))
     {
       if (TYPE_READONLY (v) != constp
          || TYPE_VOLATILE (v) != volatilep)
        continue;
 
-      t = raises;
-      t2 = TYPE_RAISES_EXCEPTIONS (v);
-      while (t && t2)
-       {
-         if (TREE_TYPE (t) == TREE_TYPE (t2))
-           {
-             t = TREE_CHAIN (t);
-             t2 = TREE_CHAIN (t2);
-           }
-         else break;
-       }
-      if (t || t2)
-       continue;
-      /* List of exceptions raised matches previously found list.
+      /* @@ This should do set equality, not exact match.  */
+      if (simple_cst_list_equal (TYPE_RAISES_EXCEPTIONS (v), raises))
+       /* List of exceptions raised matches previously found list.
 
-         @@ Nice to free up storage used in consing up the
-        @@ list of exceptions raised.  */
-      return v;
+          @@ Nice to free up storage used in consing up the
+          @@ list of exceptions raised.  */
+       return v;
     }
 
   /* Need to build a new variant.  */
-  v = copy_node (type);
-  TYPE_NEXT_VARIANT (v) = TYPE_NEXT_VARIANT (type);
-  TYPE_NEXT_VARIANT (type) = v;
+  v = build_type_copy (type);
+
   if (raises && ! TREE_PERMANENT (raises))
     {
       push_obstacks_nochange ();
@@ -1532,24 +1425,51 @@ build_exception_variant (ctype, type, raises)
       raises = copy_list (raises);
       pop_obstacks ();
     }
+
   TYPE_RAISES_EXCEPTIONS (v) = raises;
   return v;
 }
 
+/* Given a TEMPLATE_TEMPLATE_PARM node T, create a new one together with its 
+   lang_specific field and its corresponding TEMPLATE_DECL node */
+
+tree
+copy_template_template_parm (t)
+     tree t;
+{
+  tree template = TYPE_NAME (t);
+  tree t2 = make_lang_type (TEMPLATE_TEMPLATE_PARM);
+  template = copy_node (template);
+  copy_lang_decl (template);
+  TREE_TYPE (template) = t2;
+  TYPE_NAME (t2) = template;
+  TYPE_STUB_DECL (t2) = template;
+
+  /* No need to copy these */
+  TYPE_FIELDS (t2) = TYPE_FIELDS (t);
+  CLASSTYPE_TEMPLATE_INFO (t2) = CLASSTYPE_TEMPLATE_INFO (t);
+  return t2;
+}
+
 /* Subroutine of copy_to_permanent
 
    Assuming T is a node build bottom-up, make it all exist on
    permanent obstack, if it is not permanent already.  */
-static tree
-make_deep_copy (t)
+
+tree
+mapcar (t, func)
      tree t;
+     tree (*func) PROTO((tree));
 {
-  enum tree_code code;
+  tree tmp;
 
-  if (t == NULL_TREE || TREE_PERMANENT (t))
+  if (t == NULL_TREE)
     return t;
 
-  switch (code = TREE_CODE (t))
+  if (tmp = func (t), tmp != NULL_TREE)
+    return tmp;
+
+  switch (TREE_CODE (t))
     {
     case ERROR_MARK:
       return error_mark_node;
@@ -1557,16 +1477,20 @@ make_deep_copy (t)
     case VAR_DECL:
     case FUNCTION_DECL:
     case CONST_DECL:
-      break;
+      /* Rather than aborting, return error_mark_node.  This allows us
+        to report a sensible error message on code like this:
+
+        void g() { int i; f<i>(7); } */
+      return error_mark_node;
 
     case PARM_DECL:
       {
        tree chain = TREE_CHAIN (t);
        t = copy_node (t);
-       TREE_CHAIN (t) = make_deep_copy (chain);
-       TREE_TYPE (t) = make_deep_copy (TREE_TYPE (t));
-       DECL_INITIAL (t) = make_deep_copy (DECL_INITIAL (t));
-       DECL_SIZE (t) = make_deep_copy (DECL_SIZE (t));
+       TREE_CHAIN (t) = mapcar (chain, func);
+       TREE_TYPE (t) = mapcar (TREE_TYPE (t), func);
+       DECL_INITIAL (t) = mapcar (DECL_INITIAL (t), func);
+       DECL_SIZE (t) = mapcar (DECL_SIZE (t), func);
        return t;
       }
 
@@ -1574,9 +1498,9 @@ make_deep_copy (t)
       {
        tree chain = TREE_CHAIN (t);
        t = copy_node (t);
-       TREE_PURPOSE (t) = make_deep_copy (TREE_PURPOSE (t));
-       TREE_VALUE (t) = make_deep_copy (TREE_VALUE (t));
-       TREE_CHAIN (t) = make_deep_copy (chain);
+       TREE_PURPOSE (t) = mapcar (TREE_PURPOSE (t), func);
+       TREE_VALUE (t) = mapcar (TREE_VALUE (t), func);
+       TREE_CHAIN (t) = mapcar (chain, func);
        return t;
       }
 
@@ -1586,7 +1510,7 @@ make_deep_copy (t)
 
        t = copy_node (t);
        while (len--)
-         TREE_VEC_ELT (t, len) = make_deep_copy (TREE_VEC_ELT (t, len));
+         TREE_VEC_ELT (t, len) = mapcar (TREE_VEC_ELT (t, len), func);
        return t;
       }
 
@@ -1597,16 +1521,16 @@ make_deep_copy (t)
 
     case COND_EXPR:
     case TARGET_EXPR:
-    case NEW_EXPR:
+    case AGGR_INIT_EXPR:
       t = copy_node (t);
-      TREE_OPERAND (t, 0) = make_deep_copy (TREE_OPERAND (t, 0));
-      TREE_OPERAND (t, 1) = make_deep_copy (TREE_OPERAND (t, 1));
-      TREE_OPERAND (t, 2) = make_deep_copy (TREE_OPERAND (t, 2));
+      TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
+      TREE_OPERAND (t, 1) = mapcar (TREE_OPERAND (t, 1), func);
+      TREE_OPERAND (t, 2) = mapcar (TREE_OPERAND (t, 2), func);
       return t;
 
     case SAVE_EXPR:
       t = copy_node (t);
-      TREE_OPERAND (t, 0) = make_deep_copy (TREE_OPERAND (t, 0));
+      TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
       return t;
 
     case MODIFY_EXPR:
@@ -1642,10 +1566,28 @@ make_deep_copy (t)
     case PREINCREMENT_EXPR:
     case POSTDECREMENT_EXPR:
     case POSTINCREMENT_EXPR:
+    case ARRAY_REF:
+    case SCOPE_REF:
+    case TRY_CATCH_EXPR:
+    case WITH_CLEANUP_EXPR:
+      t = copy_node (t);
+      TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
+      TREE_OPERAND (t, 1) = mapcar (TREE_OPERAND (t, 1), func);
+      return t;
+
     case CALL_EXPR:
       t = copy_node (t);
-      TREE_OPERAND (t, 0) = make_deep_copy (TREE_OPERAND (t, 0));
-      TREE_OPERAND (t, 1) = make_deep_copy (TREE_OPERAND (t, 1));
+      TREE_TYPE (t) = mapcar (TREE_TYPE (t), func);
+      TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
+      TREE_OPERAND (t, 1) = mapcar (TREE_OPERAND (t, 1), func);
+
+      /* tree.def says that operand two is RTL, but
+        build_call_declarator puts trees in there.  */
+      if (TREE_OPERAND (t, 2)
+         && TREE_CODE (TREE_OPERAND (t, 2)) == TREE_LIST)
+       TREE_OPERAND (t, 2) = mapcar (TREE_OPERAND (t, 2), func);
+      else
+       TREE_OPERAND (t, 2) = NULL_TREE;
       return t;
 
     case CONVERT_EXPR:
@@ -1656,12 +1598,61 @@ make_deep_copy (t)
     case TRUTH_NOT_EXPR:
     case NOP_EXPR:
     case COMPONENT_REF:
+    case CLEANUP_POINT_EXPR:
+      t = copy_node (t);
+      TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
+      return t;
+
+    case POINTER_TYPE:
+      tmp = build_pointer_type (mapcar (TREE_TYPE (t), func));
+      return cp_build_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
+    case REFERENCE_TYPE:
+      tmp = build_reference_type (mapcar (TREE_TYPE (t), func));
+      return cp_build_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
+    case FUNCTION_TYPE:
+      tmp = build_function_type (mapcar (TREE_TYPE (t), func),
+                                mapcar (TYPE_ARG_TYPES (t), func));
+      return cp_build_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
+    case ARRAY_TYPE:
+      tmp = build_cplus_array_type (mapcar (TREE_TYPE (t), func),
+                                   mapcar (TYPE_DOMAIN (t), func));
+      return cp_build_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
+    case INTEGER_TYPE:
+      tmp = build_index_type (mapcar (TYPE_MAX_VALUE (t), func));
+      return cp_build_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
+    case OFFSET_TYPE:
+      tmp = build_offset_type (mapcar (TYPE_OFFSET_BASETYPE (t), func),
+                              mapcar (TREE_TYPE (t), func));
+      return cp_build_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
+    case METHOD_TYPE:
+      tmp = build_cplus_method_type
+       (mapcar (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t))), func),
+        mapcar (TREE_TYPE (t), func),
+        mapcar (TREE_CHAIN (TYPE_ARG_TYPES (t)), func));
+      return cp_build_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
+
+    case COMPLEX_CST:
       t = copy_node (t);
-      TREE_OPERAND (t, 0) = make_deep_copy (TREE_OPERAND (t, 0));
+      TREE_REALPART (t) = mapcar (TREE_REALPART (t), func);
+      TREE_IMAGPART (t) = mapcar (TREE_REALPART (t), func);
       return t;
 
+    case CONSTRUCTOR:
+      t = copy_node (t);
+      CONSTRUCTOR_ELTS (t) = mapcar (CONSTRUCTOR_ELTS (t), func);
+      return t;
+
+    case TEMPLATE_TEMPLATE_PARM:
+      return copy_template_template_parm (t);
+
+    case RECORD_TYPE:
+      if (TYPE_PTRMEMFUNC_P (t))
+       return build_ptrmemfunc_type
+         (mapcar (TYPE_PTRMEMFUNC_FN_TYPE (t), func));
+      /* else fall through */
+      
       /*  This list is incomplete, but should suffice for now.
-         It is very important that `sorry' does not call
+         It is very important that `sorry' not call
          `report_error_function'.  That could cause an infinite loop.  */
     default:
       sorry ("initializer contains unrecognized tree code");
@@ -1673,44 +1664,69 @@ make_deep_copy (t)
   return NULL_TREE;
 }
 
+static tree
+perm_manip (t)
+     tree t;
+{
+  if (TREE_PERMANENT (t))
+    return t;
+  /* Support `void f () { extern int i; A<&i> a; }' */
+  if ((TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == FUNCTION_DECL)
+      && TREE_PUBLIC (t))
+    return copy_node (t);
+  return NULL_TREE;
+}
+
 /* Assuming T is a node built bottom-up, make it all exist on
    permanent obstack, if it is not permanent already.  */
+
 tree
 copy_to_permanent (t)
      tree t;
 {
   register struct obstack *ambient_obstack = current_obstack;
   register struct obstack *ambient_saveable_obstack = saveable_obstack;
+  register struct obstack *ambient_expression_obstack = expression_obstack;
 
   if (t == NULL_TREE || TREE_PERMANENT (t))
     return t;
 
   saveable_obstack = &permanent_obstack;
   current_obstack = saveable_obstack;
+  expression_obstack = saveable_obstack;
 
-  t = make_deep_copy (t);
+  t = mapcar (t, perm_manip);
 
   current_obstack = ambient_obstack;
   saveable_obstack = ambient_saveable_obstack;
+  expression_obstack = ambient_expression_obstack;
 
   return t;
 }
 
+#ifdef GATHER_STATISTICS
+extern int depth_reached;
+#endif
+
 void
 print_lang_statistics ()
 {
-  extern struct obstack maybepermanent_obstack;
+  extern struct obstack decl_obstack;
   print_obstack_statistics ("class_obstack", &class_obstack);
-  print_obstack_statistics ("permanent_obstack", &permanent_obstack);
-  print_obstack_statistics ("maybepermanent_obstack", &maybepermanent_obstack);
+  print_obstack_statistics ("decl_obstack", &decl_obstack);
   print_search_statistics ();
   print_class_statistics ();
+#ifdef GATHER_STATISTICS
+  fprintf (stderr, "maximum template instantiation depth reached: %d\n",
+          depth_reached);
+#endif
 }
 
 /* This is used by the `assert' macro.  It is provided in libgcc.a,
    which `cc' doesn't know how to link.  Note that the C++ front-end
    no longer actually uses the `assert' macro (instead, it calls
    my_friendly_assert).  But all of the back-end files still need this.  */
+
 void
 __eprintf (string, expression, line, filename)
 #ifdef __STDC__
@@ -1730,21 +1746,22 @@ __eprintf (string, expression, line, filename)
   abort ();
 }
 
-/* Return, as an INTEGER_CST node, the number of elements for
-   TYPE (which is an ARRAY_TYPE).  This counts only elements of the top array. */
+/* Return, as an INTEGER_CST node, the number of elements for TYPE
+   (which is an ARRAY_TYPE).  This counts only elements of the top
+   array.  */
 
 tree
 array_type_nelts_top (type)
      tree type;
 {
-  return fold (build (PLUS_EXPR, integer_type_node,
+  return fold (build (PLUS_EXPR, sizetype,
                      array_type_nelts (type),
                      integer_one_node));
 }
 
-/* Return, as an INTEGER_CST node, the number of elements for
-   TYPE (which is an ARRAY_TYPE).  This one is a recursive count of all
-   ARRAY_TYPEs that are clumped together. */
+/* Return, as an INTEGER_CST node, the number of elements for TYPE
+   (which is an ARRAY_TYPE).  This one is a recursive count of all
+   ARRAY_TYPEs that are clumped together.  */
 
 tree
 array_type_nelts_total (type)
@@ -1755,8 +1772,399 @@ array_type_nelts_total (type)
   while (TREE_CODE (type) == ARRAY_TYPE)
     {
       tree n = array_type_nelts_top (type);
-      sz = fold (build (MULT_EXPR, integer_type_node, sz, n));
+      sz = fold (build (MULT_EXPR, sizetype, sz, n));
       type = TREE_TYPE (type);
     }
   return sz;
 }
+
+static
+tree
+bot_manip (t)
+     tree t;
+{
+  if (TREE_CODE (t) != TREE_LIST && ! TREE_SIDE_EFFECTS (t))
+    return t;
+  else if (TREE_CODE (t) == TARGET_EXPR)
+    {
+      if (TREE_CODE (TREE_OPERAND (t, 1)) == AGGR_INIT_EXPR)
+       {
+         mark_used (TREE_OPERAND (TREE_OPERAND (TREE_OPERAND (t, 1), 0), 0));
+         return build_cplus_new
+           (TREE_TYPE (t), break_out_target_exprs (TREE_OPERAND (t, 1)));
+       }
+      t = copy_node (t);
+      TREE_OPERAND (t, 0) = build (VAR_DECL, TREE_TYPE (t));
+      layout_decl (TREE_OPERAND (t, 0), 0);
+      return t;
+    }
+  else if (TREE_CODE (t) == CALL_EXPR)
+    mark_used (TREE_OPERAND (TREE_OPERAND (t, 0), 0));
+
+  return NULL_TREE;
+}
+  
+/* Actually, we'll just clean out the target exprs for the moment.  */
+
+tree
+break_out_target_exprs (t)
+     tree t;
+{
+  return mapcar (t, bot_manip);
+}
+
+/* Obstack used for allocating nodes in template function and variable
+   definitions.  */
+
+/* Similar to `build_nt', except we build
+   on the permanent_obstack, regardless.  */
+
+tree
+build_min_nt VPROTO((enum tree_code code, ...))
+{
+#ifndef __STDC__
+  enum tree_code code;
+#endif
+  register struct obstack *ambient_obstack = expression_obstack;
+  va_list p;
+  register tree t;
+  register int length;
+  register int i;
+
+  VA_START (p, code);
+
+#ifndef __STDC__
+  code = va_arg (p, enum tree_code);
+#endif
+
+  expression_obstack = &permanent_obstack;
+
+  t = make_node (code);
+  length = tree_code_length[(int) code];
+  TREE_COMPLEXITY (t) = lineno;
+
+  for (i = 0; i < length; i++)
+    {
+      tree x = va_arg (p, tree);
+      TREE_OPERAND (t, i) = copy_to_permanent (x);
+    }
+
+  va_end (p);
+  expression_obstack = ambient_obstack;
+  return t;
+}
+
+/* Similar to `build', except we build
+   on the permanent_obstack, regardless.  */
+
+tree
+build_min VPROTO((enum tree_code code, tree tt, ...))
+{
+#ifndef __STDC__
+  enum tree_code code;
+  tree tt;
+#endif
+  register struct obstack *ambient_obstack = expression_obstack;
+  va_list p;
+  register tree t;
+  register int length;
+  register int i;
+
+  VA_START (p, tt);
+
+#ifndef __STDC__
+  code = va_arg (p, enum tree_code);
+  tt = va_arg (p, tree);
+#endif
+
+  expression_obstack = &permanent_obstack;
+
+  t = make_node (code);
+  length = tree_code_length[(int) code];
+  TREE_TYPE (t) = tt;
+  TREE_COMPLEXITY (t) = lineno;
+
+  for (i = 0; i < length; i++)
+    {
+      tree x = va_arg (p, tree);
+      TREE_OPERAND (t, i) = copy_to_permanent (x);
+    }
+
+  va_end (p);
+  expression_obstack = ambient_obstack;
+  return t;
+}
+
+/* Same as `tree_cons' but make a permanent object.  */
+
+tree
+min_tree_cons (purpose, value, chain)
+     tree purpose, value, chain;
+{
+  register tree node;
+  register struct obstack *ambient_obstack = current_obstack;
+  current_obstack = &permanent_obstack;
+
+  node = tree_cons (copy_to_permanent (purpose),
+                   copy_to_permanent (value), chain);
+  current_obstack = ambient_obstack;
+  return node;
+}
+
+tree
+get_type_decl (t)
+     tree t;
+{
+  if (TREE_CODE (t) == TYPE_DECL)
+    return t;
+  if (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
+    return TYPE_STUB_DECL (t);
+  
+  my_friendly_abort (42);
+}
+
+int
+can_free (obstack, t)
+     struct obstack *obstack;
+     tree t;
+{
+  int size;
+
+  if (TREE_CODE (t) == TREE_VEC)
+    size = (TREE_VEC_LENGTH (t)-1) * sizeof (tree) + sizeof (struct tree_vec);
+  else
+    my_friendly_abort (42);
+
+#define ROUND(x) ((x + obstack_alignment_mask (obstack)) \
+                 & ~ obstack_alignment_mask (obstack))
+  if ((char *)t + ROUND (size) == obstack_next_free (obstack))
+    return 1;
+#undef ROUND
+
+  return 0;
+}
+
+/* Return first vector element whose BINFO_TYPE is ELEM.
+   Return 0 if ELEM is not in VEC.  VEC may be NULL_TREE.  */
+
+tree
+vec_binfo_member (elem, vec)
+     tree elem, vec;
+{
+  int i;
+
+  if (vec)
+    for (i = 0; i < TREE_VEC_LENGTH (vec); ++i)
+      if (comptypes (elem, BINFO_TYPE (TREE_VEC_ELT (vec, i)), 1))
+       return TREE_VEC_ELT (vec, i);
+
+  return NULL_TREE;
+}
+
+/* Kludge around the fact that DECL_CONTEXT for virtual functions returns
+   the wrong thing for decl_function_context.  Hopefully the uses in the
+   backend won't matter, since we don't need a static chain for local class
+   methods.  FIXME!  */
+
+tree
+hack_decl_function_context (decl)
+     tree decl;
+{
+  if (TREE_CODE (decl) == FUNCTION_DECL && DECL_FUNCTION_MEMBER_P (decl))
+    return decl_function_context (TYPE_MAIN_DECL (DECL_CLASS_CONTEXT (decl)));
+  return decl_function_context (decl);
+}
+
+/* Return truthvalue of whether T1 is the same tree structure as T2.
+   Return 1 if they are the same.
+   Return 0 if they are understandably different.
+   Return -1 if either contains tree structure not understood by
+   this function.  */
+
+int
+cp_tree_equal (t1, t2)
+     tree t1, t2;
+{
+  register enum tree_code code1, code2;
+  int cmp;
+
+  if (t1 == t2)
+    return 1;
+  if (t1 == 0 || t2 == 0)
+    return 0;
+
+  code1 = TREE_CODE (t1);
+  code2 = TREE_CODE (t2);
+
+  if (code1 == NOP_EXPR || code1 == CONVERT_EXPR || code1 == NON_LVALUE_EXPR)
+    if (code2 == NOP_EXPR || code2 == CONVERT_EXPR || code2 == NON_LVALUE_EXPR)
+      return cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+    else
+      return cp_tree_equal (TREE_OPERAND (t1, 0), t2);
+  else if (code2 == NOP_EXPR || code2 == CONVERT_EXPR
+          || code2 == NON_LVALUE_EXPR)
+    return cp_tree_equal (t1, TREE_OPERAND (t2, 0));
+
+  if (code1 != code2)
+    return 0;
+
+  switch (code1)
+    {
+    case INTEGER_CST:
+      return TREE_INT_CST_LOW (t1) == TREE_INT_CST_LOW (t2)
+       && TREE_INT_CST_HIGH (t1) == TREE_INT_CST_HIGH (t2);
+
+    case REAL_CST:
+      return REAL_VALUES_EQUAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2));
+
+    case STRING_CST:
+      return TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2)
+       && !bcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2),
+                 TREE_STRING_LENGTH (t1));
+
+    case CONSTRUCTOR:
+      abort ();
+
+    case SAVE_EXPR:
+      return cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+
+    case CALL_EXPR:
+      cmp = cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+      if (cmp <= 0)
+       return cmp;
+      return simple_cst_list_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
+
+    case TARGET_EXPR:
+      /* Special case: if either target is an unallocated VAR_DECL,
+        it means that it's going to be unified with whatever the
+        TARGET_EXPR is really supposed to initialize, so treat it
+        as being equivalent to anything.  */
+      if ((TREE_CODE (TREE_OPERAND (t1, 0)) == VAR_DECL
+          && DECL_NAME (TREE_OPERAND (t1, 0)) == NULL_TREE
+          && DECL_RTL (TREE_OPERAND (t1, 0)) == 0)
+         || (TREE_CODE (TREE_OPERAND (t2, 0)) == VAR_DECL
+             && DECL_NAME (TREE_OPERAND (t2, 0)) == NULL_TREE
+             && DECL_RTL (TREE_OPERAND (t2, 0)) == 0))
+       cmp = 1;
+      else
+       cmp = cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+      if (cmp <= 0)
+       return cmp;
+      return cp_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
+
+    case WITH_CLEANUP_EXPR:
+      cmp = cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+      if (cmp <= 0)
+       return cmp;
+      return cp_tree_equal (TREE_OPERAND (t1, 2), TREE_OPERAND (t1, 2));
+
+    case COMPONENT_REF:
+      if (TREE_OPERAND (t1, 1) == TREE_OPERAND (t2, 1))
+       return cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+      return 0;
+
+    case VAR_DECL:
+    case PARM_DECL:
+    case CONST_DECL:
+    case FUNCTION_DECL:
+      return 0;
+
+    case TEMPLATE_CONST_PARM:
+      return TEMPLATE_CONST_IDX (t1) == TEMPLATE_CONST_IDX (t2)
+       && TEMPLATE_CONST_LEVEL (t1) == TEMPLATE_CONST_LEVEL (t2);
+
+    case SIZEOF_EXPR:
+    case ALIGNOF_EXPR:
+      if (TREE_CODE (TREE_OPERAND (t1, 0)) != TREE_CODE (TREE_OPERAND (t2, 0)))
+       return 0;
+      if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (t1, 0))) == 't')
+       return comptypes (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0), 1);
+      break;
+
+    default:
+      break;
+    }
+
+  switch (TREE_CODE_CLASS (code1))
+    {
+      int i;
+    case '1':
+    case '2':
+    case '<':
+    case 'e':
+    case 'r':
+    case 's':
+      cmp = 1;
+      for (i=0; i<tree_code_length[(int) code1]; ++i)
+       {
+         cmp = cp_tree_equal (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i));
+         if (cmp <= 0)
+           return cmp;
+       }
+      return cmp;
+    }
+
+  return -1;
+}
+
+/* Similar to make_tree_vec, but build on a temporary obstack.  */
+
+tree
+make_temp_vec (len)
+     int len;
+{
+  register tree node;
+  register struct obstack *ambient_obstack = current_obstack;
+  current_obstack = expression_obstack;
+  node = make_tree_vec (len);
+  current_obstack = ambient_obstack;
+  return node;
+}
+
+void
+push_expression_obstack ()
+{
+  push_obstacks_nochange ();
+  current_obstack = expression_obstack;
+}
+
+/* The type of ARG when used as an lvalue.  */
+
+tree
+lvalue_type (arg)
+     tree arg;
+{
+  return cp_build_type_variant
+    (TREE_TYPE (arg), TREE_READONLY (arg), TREE_THIS_VOLATILE (arg));
+}
+
+/* The type of ARG for printing error messages; denote lvalues with
+   reference types.  */
+
+tree
+error_type (arg)
+     tree arg;
+{
+  tree type = TREE_TYPE (arg);
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    ;
+  else if (real_lvalue_p (arg))
+    type = build_reference_type (lvalue_type (arg));
+  else if (IS_AGGR_TYPE (type))
+    type = lvalue_type (arg);
+
+  return type;
+}
+
+/* Does FUNCTION use a variable-length argument list?  */
+
+int
+varargs_function_p (function)
+     tree function;
+{
+  tree parm = TYPE_ARG_TYPES (TREE_TYPE (function));
+  for (; parm; parm = TREE_CHAIN (parm))
+    if (TREE_VALUE (parm) == void_type_node)
+      return 0;
+  return 1;
+}