OSDN Git Service

* cp-tre.h (finish_function): Change prototype.
[pf3gnuchains/gcc-fork.git] / gcc / cp / tree.c
index d159ac1..db3c418 100644 (file)
@@ -1,5 +1,6 @@
 /* Language-dependent node constructors for parse phase of GNU compiler.
-   Copyright (C) 1987, 88, 92-98, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000 Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
@@ -27,20 +28,25 @@ Boston, MA 02111-1307, USA.  */
 #include "flags.h"
 #include "rtl.h"
 #include "toplev.h"
-
-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, tree, tree, tree));
-static void propagate_binfo_offsets PROTO((tree, tree));
-static int avoid_overlap PROTO((tree, tree));
-static cp_lvalue_kind lvalue_p_1 PROTO((tree, int));
-static tree no_linkage_helper PROTO((tree));
-static tree build_srcloc PROTO((char *, int));
-
-#define CEIL(x,y) (((x) + (y) - 1) / (y))
+#include "ggc.h"
+#include "insn-config.h"
+#include "integrate.h"
+
+static tree bot_manip PARAMS ((tree *, int *, void *));
+static tree bot_replace PARAMS ((tree *, int *, void *));
+static tree build_cplus_array_type_1 PARAMS ((tree, tree));
+static void list_hash_add PARAMS ((int, tree));
+static int list_hash PARAMS ((tree, tree, tree));
+static tree list_hash_lookup PARAMS ((int, tree, tree, tree));
+static cp_lvalue_kind lvalue_p_1 PARAMS ((tree, int));
+static tree no_linkage_helper PARAMS ((tree *, int *, void *));
+static tree build_srcloc PARAMS ((char *, int));
+static void mark_list_hash PARAMS ((void *));
+static int statement_code_p PARAMS ((enum tree_code));
+static tree mark_local_for_remap_r PARAMS ((tree *, int *, void *));
+static tree cp_unsave_r PARAMS ((tree *, int *, void *));
+static void cp_unsave PARAMS ((tree *));
+static tree build_target_expr PARAMS ((tree, tree));
 
 /* If REF is an lvalue, returns the kind of lvalue that REF is.
    Otherwise, returns clk_none.  If TREAT_CLASS_RVALUES_AS_LVALUES is
@@ -83,7 +89,7 @@ lvalue_p_1 (ref, treat_class_rvalues_as_lvalues)
          /* The "field" can be a FUNCTION_DECL or an OVERLOAD in some
             situations.  */
          && TREE_CODE (TREE_OPERAND (ref, 1)) == FIELD_DECL
-         && DECL_BIT_FIELD (TREE_OPERAND (ref, 1)))
+         && DECL_C_BIT_FIELD (TREE_OPERAND (ref, 1)))
        {
          /* Clear the ordinary bit.  If this object was a class
             rvalue we want to preserve that information.  */
@@ -142,6 +148,7 @@ lvalue_p_1 (ref, treat_class_rvalues_as_lvalues)
       return treat_class_rvalues_as_lvalues ? clk_class : clk_none;
 
     case CALL_EXPR:
+    case VA_ARG_EXPR:
       return ((treat_class_rvalues_as_lvalues
               && IS_AGGR_TYPE (TREE_TYPE (ref)))
              ? clk_class : clk_none);
@@ -208,6 +215,26 @@ lvalue_or_else (ref, string)
   return win;
 }
 
+/* Build a TARGET_EXPR, initializing the DECL with the VALUE.  */
+
+static tree
+build_target_expr (decl, value)
+     tree decl;
+     tree value;
+{
+  tree t;
+
+  t = build (TARGET_EXPR, TREE_TYPE (decl), decl, value, 
+            maybe_build_cleanup (decl), NULL_TREE);
+  /* We always set TREE_SIDE_EFFECTS so that expand_expr does not
+     ignore the TARGET_EXPR.  If there really turn out to be no
+     side-effects, then the optimizer should be able to get rid of
+     whatever code is generated anyhow.  */
+  TREE_SIDE_EFFECTS (t) = 1;
+
+  return t;
+}
+
 /* INIT is a CALL_EXPR which needs info about its target.
    TYPE is the type that this initialization should appear to have.
 
@@ -220,6 +247,7 @@ build_cplus_new (type, init)
      tree type;
      tree init;
 {
+  tree fn;
   tree slot;
   tree rval;
 
@@ -232,35 +260,58 @@ build_cplus_new (type, init)
 
   slot = build (VAR_DECL, type);
   DECL_ARTIFICIAL (slot) = 1;
+  DECL_CONTEXT (slot) = current_function_decl;
   layout_decl (slot, 0);
-  rval = build (AGGR_INIT_EXPR, type,
-               TREE_OPERAND (init, 0), TREE_OPERAND (init, 1), slot);
-  TREE_SIDE_EFFECTS (rval) = 1;
-  rval = build (TARGET_EXPR, type, slot, rval, NULL_TREE, NULL_TREE);
+
+  /* We split the CALL_EXPR into its function and its arguments here.
+     Then, in expand_expr, we put them back together.  The reason for
+     this is that this expression might be a default argument
+     expression.  In that case, we need a new temporary every time the
+     expression is used.  That's what break_out_target_exprs does; it
+     replaces every AGGR_INIT_EXPR with a copy that uses a fresh
+     temporary slot.  Then, expand_expr builds up a call-expression
+     using the new slot.  */
+  fn = TREE_OPERAND (init, 0);
+  rval = build (AGGR_INIT_EXPR, type, fn, TREE_OPERAND (init, 1), slot);
   TREE_SIDE_EFFECTS (rval) = 1;
+  AGGR_INIT_VIA_CTOR_P (rval) 
+    = (TREE_CODE (fn) == ADDR_EXPR
+       && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL
+       && DECL_CONSTRUCTOR_P (TREE_OPERAND (fn, 0)));
+  rval = build_target_expr (slot, rval);
 
   return rval;
 }
 
-/* Encapsulate the expression INIT in a TARGET_EXPR.  */
+/* Buidl a TARGET_EXPR using INIT to initialize a new temporary of the
+   indicated TYPE.  */
 
 tree
-get_target_expr (init)
+build_target_expr_with_type (init, type)
      tree init;
+     tree type;
 {
   tree slot;
   tree rval;
 
-  slot = build (VAR_DECL, TREE_TYPE (init));
+  slot = build (VAR_DECL, type);
   DECL_ARTIFICIAL (slot) = 1;
+  DECL_CONTEXT (slot) = current_function_decl;
   layout_decl (slot, 0);
-  rval = build (TARGET_EXPR, TREE_TYPE (init), slot, init,
-               NULL_TREE, NULL_TREE);
-  TREE_SIDE_EFFECTS (rval) = 1;
+  rval = build_target_expr (slot, init);
 
   return rval;
 }
 
+/* Like build_target_expr_with_type, but use the type of INIT.  */
+
+tree
+get_target_expr (init)
+     tree init;
+{
+  return build_target_expr_with_type (init, TREE_TYPE (init));
+}
+
 /* Recursively search EXP for CALL_EXPRs that need cleanups and replace
    these CALL_EXPRs with tree nodes that will perform the cleanups.  */
 
@@ -271,7 +322,7 @@ break_out_cleanups (exp)
   tree tmp = exp;
 
   if (TREE_CODE (tmp) == CALL_EXPR
-      && TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (tmp)))
+      && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (tmp)))
     return build_cplus_new (TREE_TYPE (tmp), tmp);
 
   while (TREE_CODE (tmp) == NOP_EXPR
@@ -279,7 +330,7 @@ break_out_cleanups (exp)
         || TREE_CODE (tmp) == NON_LVALUE_EXPR)
     {
       if (TREE_CODE (TREE_OPERAND (tmp, 0)) == CALL_EXPR
-         && TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (TREE_OPERAND (tmp, 0))))
+         && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (TREE_OPERAND (tmp, 0))))
        {
          TREE_OPERAND (tmp, 0)
            = build_cplus_new (TREE_TYPE (TREE_OPERAND (tmp, 0)),
@@ -383,10 +434,7 @@ break_out_calls (exp)
 
 }
 \f
-extern struct obstack *current_obstack;
-extern struct obstack permanent_obstack, class_obstack;
-extern struct obstack *saveable_obstack;
-extern struct obstack *expression_obstack;
+extern struct obstack permanent_obstack;
 
 /* Here is how primitive or already-canonicalized types' hash
    codes are made.  MUST BE CONSISTENT WITH tree.c !!! */
@@ -415,11 +463,9 @@ build_cplus_method_type (basetype, rettype, argtypes)
      which is "this".  Put it into the list of argument types.  Make
      sure that the new argument list is allocated on the same obstack
      as the type.  */
-  push_obstacks (TYPE_OBSTACK (t), TYPE_OBSTACK (t));
   argtypes = tree_cons (NULL_TREE, ptype, argtypes);
   TYPE_ARG_TYPES (t) = argtypes;
   TREE_SIDE_EFFECTS (argtypes) = 1;  /* Mark first argtype as "artificial".  */
-  pop_obstacks ();
 
   /* 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.  */
@@ -428,7 +474,7 @@ build_cplus_method_type (basetype, rettype, argtypes)
 
   t = type_hash_canon (hashcode, t);
 
-  if (TYPE_SIZE (t) == 0)
+  if (!COMPLETE_TYPE_P (t))
     layout_type (t);
 
   return t;
@@ -444,14 +490,6 @@ build_cplus_array_type_1 (elt_type, index_type)
   if (elt_type == error_mark_node || index_type == error_mark_node)
     return error_mark_node;
 
-  push_obstacks_nochange ();
-
-  /* If both ELT_TYPE and INDEX_TYPE are permanent,
-     make this permanent too.  */
-  if (TREE_PERMANENT (elt_type)
-      && (index_type == 0 || TREE_PERMANENT (index_type)))
-    end_temporary_allocation ();
-
   if (processing_template_decl 
       || uses_template_parms (elt_type) 
       || uses_template_parms (index_type))
@@ -467,9 +505,8 @@ build_cplus_array_type_1 (elt_type, index_type)
      more easily.  */
   TYPE_NEEDS_CONSTRUCTING (t) 
     = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (elt_type));
-  TYPE_NEEDS_DESTRUCTOR (t) 
-    = TYPE_NEEDS_DESTRUCTOR (TYPE_MAIN_VARIANT (elt_type));
-  pop_obstacks ();
+  TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) 
+    = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TYPE_MAIN_VARIANT (elt_type));
   return t;
 }
 
@@ -508,7 +545,10 @@ cp_build_qualified_type_real (type, type_quals, complain)
 
   if (type == error_mark_node)
     return type;
-  
+
+  if (type_quals == TYPE_QUALS (type))
+    return type;
+
   /* A restrict-qualified pointer type must be a pointer (or reference)
      to object or incomplete type.  */
   if ((type_quals & TYPE_QUAL_RESTRICT)
@@ -562,7 +602,7 @@ cp_build_qualified_type_real (type, type_quals, complain)
        }
 
       /* Even if we already had this variant, we update
-        TYPE_NEEDS_CONSTRUCTING and TYPE_NEEDS_DESTRUCTOR in case
+        TYPE_NEEDS_CONSTRUCTING and TYPE_HAS_NONTRIVIAL_DESTRUCTOR in case
         they changed since the variant was originally created.  
         
         This seems hokey; if there is some way to use a previous
@@ -570,8 +610,8 @@ cp_build_qualified_type_real (type, type_quals, complain)
         TYPE_NEEDS_CONSTRUCTING will never be updated.  */
       TYPE_NEEDS_CONSTRUCTING (t) 
        = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (element_type));
-      TYPE_NEEDS_DESTRUCTOR (t) 
-       = TYPE_NEEDS_DESTRUCTOR (TYPE_MAIN_VARIANT (element_type));
+      TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) 
+       = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TYPE_MAIN_VARIANT (element_type));
       return t;
     }
   else if (TYPE_PTRMEMFUNC_P (type))
@@ -614,63 +654,6 @@ canonical_type_variant (t)
   return cp_build_qualified_type (TYPE_MAIN_VARIANT (t), CP_TYPE_QUALS (t));
 }
 \f
-/* Add OFFSET to all base types of T.
-
-   OFFSET, which is a type offset, is number of bytes.
-
-   Note that we don't have to worry about having two paths to the
-   same base type, since this type owns its association list.  */
-
-static void
-propagate_binfo_offsets (binfo, offset)
-     tree binfo;
-     tree offset;
-{
-  tree binfos = BINFO_BASETYPES (binfo);
-  int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-
-  for (i = 0; i < n_baselinks; /* note increment is done in the loop.  */)
-    {
-      tree base_binfo = TREE_VEC_ELT (binfos, i);
-
-      if (TREE_VIA_VIRTUAL (base_binfo))
-       i += 1;
-      else
-       {
-         int j;
-         tree delta = NULL_TREE;
-
-         for (j = i+1; j < n_baselinks; j++)
-           if (! TREE_VIA_VIRTUAL (TREE_VEC_ELT (binfos, j)))
-             {
-               /* The next basetype offset must take into account the space
-                  between the classes, not just the size of each class.  */
-               delta = size_binop (MINUS_EXPR,
-                                   BINFO_OFFSET (TREE_VEC_ELT (binfos, j)),
-                                   BINFO_OFFSET (base_binfo));
-               break;
-             }
-
-#if 0
-         if (BINFO_OFFSET_ZEROP (base_binfo))
-           BINFO_OFFSET (base_binfo) = offset;
-         else
-           BINFO_OFFSET (base_binfo)
-             = size_binop (PLUS_EXPR, BINFO_OFFSET (base_binfo), offset);
-#else
-         BINFO_OFFSET (base_binfo) = offset;
-#endif
-
-         propagate_binfo_offsets (base_binfo, offset);
-
-         /* Go to our next class that counts for offset propagation.  */
-         i = j;
-         if (i < n_baselinks)
-           offset = size_binop (PLUS_EXPR, offset, delta);
-       }
-    }
-}
-
 /* Makes new binfos for the indirect bases under BINFO, and updates
    BINFO_OFFSET for them and their bases.  */
 
@@ -703,329 +686,6 @@ unshare_base_binfos (binfo)
     }
 }
 
-/* Finish the work of layout_record, now taking virtual bases into account.
-   Also compute the actual offsets that our base classes will have.
-   This must be performed after the fields are laid out, since virtual
-   baseclasses must lay down at the end of the record.
-
-   Returns the maximum number of virtual functions any of the
-   baseclasses provide.  */
-
-int
-layout_basetypes (rec, max)
-     tree rec;
-     int max;
-{
-  tree binfos = TYPE_BINFO_BASETYPES (rec);
-  int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-
-  tree vbase_types;
-
-  unsigned int record_align = MAX (BITS_PER_UNIT, TYPE_ALIGN (rec));
-  unsigned int desired_align;
-
-  /* Record size so far is CONST_SIZE bits, where CONST_SIZE is an integer.  */
-  register unsigned int const_size = 0;
-  unsigned int nonvirtual_const_size;
-
-#ifdef STRUCTURE_SIZE_BOUNDARY
-  /* Packed structures don't need to have minimum size.  */
-  if (! TYPE_PACKED (rec))
-    record_align = MAX (record_align, STRUCTURE_SIZE_BOUNDARY);
-#endif
-
-  /* Get all the virtual base types that this type uses.  The
-     TREE_VALUE slot holds the virtual baseclass type.  Note that
-     get_vbase_types makes copies of the virtual base BINFOs, so that
-     the vbase_types are unshared.  */
-  vbase_types = CLASSTYPE_VBASECLASSES (rec);
-
-  my_friendly_assert (TREE_CODE (TYPE_SIZE (rec)) == INTEGER_CST, 19970302);
-  const_size = TREE_INT_CST_LOW (TYPE_SIZE (rec));
-
-  nonvirtual_const_size = const_size;
-
-  while (vbase_types)
-    {
-      tree basetype = BINFO_TYPE (vbase_types);
-      tree offset;
-
-      desired_align = TYPE_ALIGN (basetype);
-      record_align = MAX (record_align, desired_align);
-
-      if (const_size == 0)
-       offset = integer_zero_node;
-      else
-       {
-         /* Give each virtual base type the alignment it wants.  */
-         const_size = CEIL (const_size, desired_align) * desired_align;
-         offset = size_int (CEIL (const_size, BITS_PER_UNIT));
-       }
-
-      if (CLASSTYPE_VSIZE (basetype) > max)
-       max = CLASSTYPE_VSIZE (basetype);
-      BINFO_OFFSET (vbase_types) = offset;
-
-      /* 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 (CLASSTYPE_SIZE (basetype)));
-
-      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 is
-        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;
-  if (const_size != nonvirtual_const_size)
-    {
-      TYPE_SIZE (rec) = size_int (const_size);
-      TYPE_SIZE_UNIT (rec) = size_binop (FLOOR_DIV_EXPR, TYPE_SIZE (rec),
-                                         size_int (BITS_PER_UNIT));
-    }
-
-  /* Now propagate offset information throughout the lattice.  */
-  for (i = 0; i < n_baseclasses; i++)
-    {
-      register tree base_binfo = TREE_VEC_ELT (binfos, i);
-      register tree basetype = BINFO_TYPE (base_binfo);
-      tree field = TYPE_FIELDS (rec);
-
-      if (TREE_VIA_VIRTUAL (base_binfo))
-       continue;
-
-      my_friendly_assert (TREE_TYPE (field) == basetype, 23897);
-
-      if (get_base_distance (basetype, rec, 0, (tree*)0) == -2)
-       cp_warning ("direct base `%T' inaccessible in `%T' due to ambiguity",
-                   basetype, rec);
-
-      BINFO_OFFSET (base_binfo)
-       = size_int (CEIL (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field)),
-                         BITS_PER_UNIT));
-      propagate_binfo_offsets (base_binfo, BINFO_OFFSET (base_binfo));
-      TYPE_FIELDS (rec) = TREE_CHAIN (field);
-    }
-
-  for (vbase_types = CLASSTYPE_VBASECLASSES (rec); vbase_types;
-       vbase_types = TREE_CHAIN (vbase_types))
-    {
-      BINFO_INHERITANCE_CHAIN (vbase_types) = TYPE_BINFO (rec);
-      unshare_base_binfos (vbase_types);
-      propagate_binfo_offsets (vbase_types, BINFO_OFFSET (vbase_types));
-
-      if (extra_warnings)
-       {
-         tree basetype = BINFO_TYPE (vbase_types);
-         if (get_base_distance (basetype, rec, 0, (tree*)0) == -2)
-           cp_warning ("virtual base `%T' inaccessible in `%T' due to ambiguity",
-                       basetype, rec);
-       }
-    }
-
-  return max;
-}
-
-/* If the empty base field in DECL overlaps with a base of the same type in
-   NEWDECL, which is either another base field or the first data field of
-   the class, pad the base just before NEWDECL and return 1.  Otherwise,
-   return 0.  */
-
-static int
-avoid_overlap (decl, newdecl)
-     tree decl, newdecl;
-{
-  tree field;
-
-  if (newdecl == NULL_TREE
-      || ! types_overlap_p (TREE_TYPE (decl), TREE_TYPE (newdecl)))
-    return 0;
-
-  for (field = decl; TREE_CHAIN (field) && TREE_CHAIN (field) != newdecl;
-       field = TREE_CHAIN (field))
-    ;
-
-  DECL_SIZE (field) = integer_one_node;
-
-  return 1;
-}
-
-/* Returns a list of fields to stand in for the base class subobjects
-   of REC.  These fields are later removed by layout_basetypes.  */
-
-tree
-build_base_fields (rec)
-     tree rec;
-{
-  /* Chain to hold all the new FIELD_DECLs which stand in for base class
-     subobjects.  */
-  tree base_decls = NULL_TREE;
-  tree binfos = TYPE_BINFO_BASETYPES (rec);
-  int n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-  tree decl, nextdecl;
-  int i, saw_empty = 0;
-  unsigned int base_align = 0;
-
-  for (i = 0; i < n_baseclasses; ++i)
-    {
-      register tree base_binfo = TREE_VEC_ELT (binfos, i);
-      register tree basetype = BINFO_TYPE (base_binfo);
-
-      if (TYPE_SIZE (basetype) == 0)
-       /* This error is now reported in xref_tag, thus giving better
-          location information.  */
-       continue;
-
-      if (TREE_VIA_VIRTUAL (base_binfo))
-       continue;
-
-      decl = build_lang_decl (FIELD_DECL, NULL_TREE, basetype);
-      DECL_ARTIFICIAL (decl) = 1;
-      DECL_FIELD_CONTEXT (decl) = DECL_CLASS_CONTEXT (decl) = rec;
-      DECL_SIZE (decl) = CLASSTYPE_SIZE (basetype);
-      DECL_ALIGN (decl) = CLASSTYPE_ALIGN (basetype);
-      TREE_CHAIN (decl) = base_decls;
-      base_decls = decl;
-
-      if (! flag_new_abi)
-       {
-         /* Brain damage for backwards compatibility.  For no good reason,
-            the old layout_basetypes made every base at least as large as
-            the alignment for the bases up to that point, gratuitously
-            wasting space.  So we do the same thing here.  */
-         base_align = MAX (base_align, DECL_ALIGN (decl));
-         DECL_SIZE (decl)
-           = size_int (MAX (TREE_INT_CST_LOW (DECL_SIZE (decl)),
-                            (int) base_align));
-       }
-      else if (DECL_SIZE (decl) == integer_zero_node)
-       saw_empty = 1;
-    }
-
-  /* Reverse the list of fields so we allocate the bases in the proper
-     order.  */
-  base_decls = nreverse (base_decls);
-
-  /* In the presence of empty base classes, we run the risk of allocating
-     two objects of the same class on top of one another.  Avoid that.  */
-  if (flag_new_abi && saw_empty)
-    for (decl = base_decls; decl; decl = TREE_CHAIN (decl))
-      {
-       if (DECL_SIZE (decl) == integer_zero_node)
-         {
-           /* First step through the following bases until we find
-              an overlap or a non-empty base.  */
-           for (nextdecl = TREE_CHAIN (decl); nextdecl;
-                nextdecl = TREE_CHAIN (nextdecl))
-             {
-               if (avoid_overlap (decl, nextdecl)
-                   || DECL_SIZE (nextdecl) != integer_zero_node)
-                 goto nextbase;
-             }
-
-           /* If we're still looking, also check against the first
-              field.  */
-           for (nextdecl = TYPE_FIELDS (rec);
-                nextdecl && TREE_CODE (nextdecl) != FIELD_DECL;
-                nextdecl = TREE_CHAIN (nextdecl))
-             /* keep looking */;
-           avoid_overlap (decl, nextdecl);
-         }
-      nextbase:;
-      }
-
-  return base_decls;
-}
-
-/* Returns list of virtual base class pointers in a FIELD_DECL chain.  */
-
-tree
-build_vbase_pointer_fields (rec)
-     tree rec;
-{
-  /* Chain to hold all the new FIELD_DECLs which point at virtual
-     base classes.  */
-  tree vbase_decls = NULL_TREE;
-  tree binfos = TYPE_BINFO_BASETYPES (rec);
-  int n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-  tree decl;
-  int i;
-
-  /* Handle basetypes almost like fields, but record their
-     offsets differently.  */
-
-  for (i = 0; i < n_baseclasses; i++)
-    {
-      register tree base_binfo = TREE_VEC_ELT (binfos, i);
-      register tree basetype = BINFO_TYPE (base_binfo);
-
-      if (TYPE_SIZE (basetype) == 0)
-       /* This error is now reported in xref_tag, thus giving better
-          location information.  */
-       continue;
-
-      /* All basetypes are recorded in the association list of the
-        derived type.  */
-
-      if (TREE_VIA_VIRTUAL (base_binfo))
-       {
-         int j;
-         const char *name;
-
-         /* The offset for a virtual base class is only used in computing
-            virtual function tables and for initializing virtual base
-            pointers.  It is built once `get_vbase_types' is called.  */
-
-         /* If this basetype can come from another vbase pointer
-            without an additional indirection, we will share
-            that pointer.  If an indirection is involved, we
-            make our own pointer.  */
-         for (j = 0; j < n_baseclasses; j++)
-           {
-             tree other_base_binfo = TREE_VEC_ELT (binfos, j);
-             if (! TREE_VIA_VIRTUAL (other_base_binfo)
-                 && binfo_member (basetype,
-                                  CLASSTYPE_VBASECLASSES (BINFO_TYPE
-                                                          (other_base_binfo))
-                                  ))
-               goto got_it;
-           }
-         FORMAT_VBASE_NAME (name, basetype);
-         decl = build_lang_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.  */
-         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) = 0;
-         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;
-
-       got_it:
-         /* The space this decl occupies has already been accounted for.  */
-         ;
-       }
-    }
-
-  return vbase_decls;
-}
 \f
 /* Hashing of lists so that we don't make duplicates.
    The entry point is `list_hash_canon'.  */
@@ -1102,7 +762,7 @@ list_hash_add (hashcode, list)
 {
   register struct list_hash *h;
 
-  h = (struct list_hash *) obstack_alloc (&class_obstack, sizeof (struct list_hash));
+  h = (struct list_hash *) obstack_alloc (&permanent_obstack, sizeof (struct list_hash));
   h->hashcode = hashcode;
   h->list = list;
   h->next = list_hash_table[hashcode % TYPE_HASH_SIZE];
@@ -1121,7 +781,6 @@ tree
 hash_tree_cons (purpose, value, chain)
      tree purpose, value, chain;
 {
-  struct obstack *ambient_obstack = current_obstack;
   tree t;
   int hashcode = 0;
 
@@ -1133,15 +792,12 @@ hash_tree_cons (purpose, value, chain)
        return t;
     }
 
-  current_obstack = &class_obstack;
-
   t = tree_cons (purpose, value, chain);
 
   /* 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;
 }
 
@@ -1190,7 +846,7 @@ make_binfo (offset, binfo, vtable, virtuals)
      tree offset, binfo;
      tree vtable, virtuals;
 {
-  tree new_binfo = make_tree_vec (7);
+  tree new_binfo = make_tree_vec (8);
   tree type;
 
   if (TREE_CODE (binfo) == TREE_VEC)
@@ -1205,7 +861,6 @@ make_binfo (offset, binfo, vtable, virtuals)
   BINFO_OFFSET (new_binfo) = offset;
   BINFO_VTABLE (new_binfo) = vtable;
   BINFO_VIRTUALS (new_binfo) = virtuals;
-  BINFO_VPTR_FIELD (new_binfo) = NULL_TREE;
 
   if (binfo && BINFO_BASETYPES (binfo) != NULL_TREE)
     BINFO_BASETYPES (new_binfo) = copy_node (BINFO_BASETYPES (binfo));      
@@ -1229,47 +884,49 @@ binfo_value (elem, type)
   return get_binfo (elem, type, 0);
 }
 
-/* Return a reversed copy of the BINFO-chain given by PATH.  (If the 
-   BINFO_INHERITANCE_CHAIN points from base classes to derived
-   classes, it will instead point from derived classes to base
-   classes.)  Returns the first node in the reversed chain.  */
+/* Return a TREE_LIST whose TREE_VALUE nodes along the
+   BINFO_INHERITANCE_CHAIN for BINFO, but in the opposite order.  In
+   other words, while the BINFO_INHERITANCE_CHAIN goes from base
+   classes to derived classes, the reversed path goes from derived
+   classes to base classes.  */
 
 tree
-reverse_path (path)
-     tree path;
+reverse_path (binfo)
+     tree binfo;
 {
-  register tree prev = NULL_TREE, cur;
-  push_expression_obstack ();
-  for (cur = path; cur; cur = BINFO_INHERITANCE_CHAIN (cur))
+  tree reversed_path;
+
+  reversed_path = NULL_TREE;
+  while (binfo) 
     {
-      tree r = copy_node (cur);
-      BINFO_INHERITANCE_CHAIN (r) = prev;
-      prev = r;
+      reversed_path = tree_cons (NULL_TREE, binfo, reversed_path);
+      binfo = BINFO_INHERITANCE_CHAIN (binfo);
     }
-  pop_obstacks ();
-  return prev;
+
+  return reversed_path;
 }
 
 void
 debug_binfo (elem)
      tree elem;
 {
-  unsigned HOST_WIDE_INT n;
+  HOST_WIDE_INT n;
   tree virtuals;
 
-  fprintf (stderr, "type \"%s\"; offset = %ld\n",
-          TYPE_NAME_STRING (BINFO_TYPE (elem)),
-          (long) TREE_INT_CST_LOW (BINFO_OFFSET (elem)));
-  fprintf (stderr, "vtable type:\n");
+  fprintf (stderr, "type \"%s\", offset = ",
+          TYPE_NAME_STRING (BINFO_TYPE (elem)));
+  fprintf (stderr, HOST_WIDE_INT_PRINT_DEC,
+          TREE_INT_CST_LOW (BINFO_OFFSET (elem)));
+  fprintf (stderr, "\nvtable type:\n");
   debug_tree (BINFO_TYPE (elem));
   if (BINFO_VTABLE (elem))
-    fprintf (stderr, "vtable decl \"%s\"\n", IDENTIFIER_POINTER (DECL_NAME (BINFO_VTABLE (elem))));
+    fprintf (stderr, "vtable decl \"%s\"\n",
+            IDENTIFIER_POINTER (DECL_NAME (get_vtbl_decl_for_binfo (elem))));
   else
     fprintf (stderr, "no vtable decl yet\n");
   fprintf (stderr, "virtuals:\n");
   virtuals = BINFO_VIRTUALS (elem);
-
-  n = skip_rtti_stuff (&virtuals, BINFO_TYPE (elem));
+  n = first_vfun_index (BINFO_TYPE (elem));
 
   while (virtuals)
     {
@@ -1282,25 +939,6 @@ debug_binfo (elem)
     }
 }
 
-/* Initialize an CPLUS_BINDING node that does not live on an obstack. */
-
-tree
-binding_init (node)
-     struct tree_binding* node;
-{
-  static struct tree_binding* source;
-  if (!source)
-    {
-      extern struct obstack permanent_obstack;
-      push_obstacks (&permanent_obstack, &permanent_obstack);
-      source = (struct tree_binding*)make_node (CPLUS_BINDING);
-      pop_obstacks ();
-    }
-  *node = *source;
-  TREE_PERMANENT ((tree)node) = 0;
-  return (tree)node;
-}
-
 int
 count_functions (t)
      tree t;
@@ -1385,21 +1023,6 @@ ovl_cons (decl, chain)
   return result;
 }
 
-/* Same as ovl_cons, but on the scratch_obstack. */
-
-tree
-scratch_ovl_cons (value, chain)
-     tree value, chain;
-{
-  register tree node;
-  register struct obstack *ambient_obstack = current_obstack;
-  extern struct obstack *expression_obstack;
-  current_obstack = expression_obstack;
-  node = ovl_cons (value, chain);
-  current_obstack = ambient_obstack;
-  return node;
-}
-
 /* Build a new overloaded function. If this is the first one,
    just return it; otherwise, ovl_cons the _DECLs */
 
@@ -1440,10 +1063,49 @@ is_aggr_type_2 (t1, t2)
     return 0;
   return IS_AGGR_TYPE (t1) && IS_AGGR_TYPE (t2);
 }
+
+/* Returns non-zero if CODE is the code for a statement.  */
+
+static int
+statement_code_p (code)
+     enum tree_code code;
+{
+  switch (code)
+    {
+    case EXPR_STMT:
+    case COMPOUND_STMT:
+    case DECL_STMT:
+    case IF_STMT:
+    case FOR_STMT:
+    case WHILE_STMT:
+    case DO_STMT:
+    case RETURN_STMT:
+    case BREAK_STMT:
+    case CONTINUE_STMT:
+    case SWITCH_STMT:
+    case GOTO_STMT:
+    case LABEL_STMT:
+    case ASM_STMT:
+    case SUBOBJECT:
+    case CLEANUP_STMT:
+    case START_CATCH_STMT:
+    case CTOR_STMT:
+    case SCOPE_STMT:
+    case CTOR_INITIALIZER:
+    case CASE_LABEL:
+    case RETURN_INIT:
+    case TRY_BLOCK:
+    case HANDLER:
+      return 1;
+
+    default:
+      return 0;
+    }
+}
 \f
 #define PRINT_RING_SIZE 4
 
-char *
+const char *
 lang_printable_name (decl, v)
      tree decl;
      int v;
@@ -1504,10 +1166,6 @@ build_exception_variant (type, raises)
 
   /* Need to build a new variant.  */
   v = build_type_copy (type);
-
-  if (raises && ! TREE_PERMANENT (raises))
-    raises = copy_to_permanent (raises);
-
   TYPE_RAISES_EXCEPTIONS (v) = raises;
   return v;
 }
@@ -1522,14 +1180,8 @@ copy_template_template_parm (t)
   tree template = TYPE_NAME (t);
   tree t2;
 
-  /* Make sure these end up on the permanent_obstack.  */
-  push_permanent_obstack ();
-  
-  t2 = make_lang_type (TEMPLATE_TEMPLATE_PARM);
-  template = copy_node (template);
-  copy_lang_decl (template);
-
-  pop_obstacks ();
+  t2 = make_aggr_type (TEMPLATE_TEMPLATE_PARM);
+  template = copy_decl (template);
 
   TREE_TYPE (template) = t2;
   TYPE_NAME (t2) = template;
@@ -1542,214 +1194,212 @@ copy_template_template_parm (t)
   return t2;
 }
 
-/* Walk through the tree structure T, applying func.  If func ever returns
-   non-null, return that value.  */
+/* Apply FUNC to all the sub-trees of TP in a pre-order traversal.
+   FUNC is called with the DATA and the address of each sub-tree.  If
+   FUNC returns a non-NULL value, the traversal is aborted, and the
+   value returned by FUNC is returned.  */
 
-tree
-search_tree (t, func)
-     tree t;
-     tree (*func) PROTO((tree));
+tree 
+walk_tree (tp, func, data)
+     tree *tp;
+     walk_tree_fn func;
+     void *data;
 {
-#define TRY(ARG) if (tmp=search_tree (ARG, func), tmp != NULL_TREE) return tmp
+  enum tree_code code;
+  int walk_subtrees;
+  tree result;
+  
+#define WALK_SUBTREE(NODE)                     \
+  do                                           \
+    {                                          \
+      result = walk_tree (&(NODE), func, data);        \
+      if (result)                              \
+       return result;                          \
+    }                                          \
+  while (0)
+
+  /* Skip empty subtrees.  */
+  if (!*tp)
+    return NULL_TREE;
 
-  tree tmp;
-  enum tree_code code; 
+  /* Call the function.  */
+  walk_subtrees = 1;
+  result = (*func) (tp, &walk_subtrees, data);
 
-  if (t == NULL_TREE)
-    return t;
-  
-  tmp = func (t);
-  if (tmp)
-    return tmp;
+  /* If we found something, return it.  */
+  if (result)
+    return result;
 
-  /* Handle some common cases up front.  */
-  code = TREE_CODE (t);
-  if (TREE_CODE_CLASS (code) == '1')
+  /* Even if we didn't, FUNC may have decided that there was nothing
+     interesting below this point in the tree.  */
+  if (!walk_subtrees)
+    return NULL_TREE;
+
+  code = TREE_CODE (*tp);
+
+  /* Handle common cases up front.  */
+  if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
+      || TREE_CODE_CLASS (code) == 'r'
+      || TREE_CODE_CLASS (code) == 's')
     {
-      TRY (TREE_OPERAND (t, 0));
+      int i, len;
+
+      /* Walk over all the sub-trees of this operand.  */
+      len = first_rtl_op (code);
+      /* TARGET_EXPRs are peculiar: operands 1 and 3 can be the same.
+        But, we only want to walk once.  */
+      if (code == TARGET_EXPR
+         && TREE_OPERAND (*tp, 3) == TREE_OPERAND (*tp, 1))
+       --len;
+      /* Go through the subtrees.  We need to do this in forward order so
+         that the scope of a FOR_EXPR is handled properly.  */
+      for (i = 0; i < len; ++i)
+       WALK_SUBTREE (TREE_OPERAND (*tp, i));
+
+      /* For statements, we also walk the chain so that we cover the
+        entire statement tree.  */
+      if (statement_code_p (code))
+       {
+         if (code == DECL_STMT 
+             && DECL_STMT_DECL (*tp) 
+             && DECL_P (DECL_STMT_DECL (*tp)))
+           {
+             /* Walk the DECL_INITIAL and DECL_SIZE.  We don't want to walk
+                into declarations that are just mentioned, rather than
+                declared; they don't really belong to this part of the tree.
+                And, we can see cycles: the initializer for a declaration can
+                refer to the declaration itself.  */
+             WALK_SUBTREE (DECL_INITIAL (DECL_STMT_DECL (*tp)));
+             WALK_SUBTREE (DECL_SIZE (DECL_STMT_DECL (*tp)));
+             WALK_SUBTREE (DECL_SIZE_UNIT (DECL_STMT_DECL (*tp)));
+           }
+
+         WALK_SUBTREE (TREE_CHAIN (*tp));
+       }
+
+      /* We didn't find what we were looking for.  */
       return NULL_TREE;
     }
-  else if (TREE_CODE_CLASS (code) == '2' || TREE_CODE_CLASS (code) == '<')
+  else if (TREE_CODE_CLASS (code) == 'd')
     {
-      TRY (TREE_OPERAND (t, 0));
-      TRY (TREE_OPERAND (t, 1));
+      WALK_SUBTREE (TREE_TYPE (*tp));
+
+      /* We didn't find what we were looking for.  */
       return NULL_TREE;
     }
 
+  /* Not one of the easy cases.  We must explicitly go through the
+     children.  */
   switch (code)
     {
     case ERROR_MARK:
-      break;
-
     case IDENTIFIER_NODE:
+    case INTEGER_CST:
+    case REAL_CST:
+    case STRING_CST:
+    case DEFAULT_ARG:
+    case TEMPLATE_TEMPLATE_PARM:
+    case TEMPLATE_PARM_INDEX:
+    case TEMPLATE_TYPE_PARM:
+    case REAL_TYPE:
+    case COMPLEX_TYPE:
+    case VOID_TYPE:
+    case BOOLEAN_TYPE:
+    case TYPENAME_TYPE:
+    case UNION_TYPE:
+    case ENUMERAL_TYPE:
+    case TYPEOF_TYPE:
+    case BLOCK:
+      /* None of thse have subtrees other than those already walked
+         above.  */
       break;
 
-    case VAR_DECL:
-    case FUNCTION_DECL:
-    case CONST_DECL:
-    case TEMPLATE_DECL:
-    case NAMESPACE_DECL:
-      break;
-
-    case TYPE_DECL:
-      TRY (TREE_TYPE (t));
+    case PTRMEM_CST:
+      WALK_SUBTREE (TREE_TYPE (*tp));
       break;
 
-    case PARM_DECL:
-      TRY (TREE_TYPE (t));
-      TRY (TREE_CHAIN (t));
+    case POINTER_TYPE:
+    case REFERENCE_TYPE:
+      WALK_SUBTREE (TREE_TYPE (*tp));
       break;
 
     case TREE_LIST:
-      TRY (TREE_PURPOSE (t));
-      TRY (TREE_VALUE (t));
-      TRY (TREE_CHAIN (t));
+      WALK_SUBTREE (TREE_PURPOSE (*tp));
+      WALK_SUBTREE (TREE_VALUE (*tp));
+      WALK_SUBTREE (TREE_CHAIN (*tp));
       break;
 
     case OVERLOAD:
-      TRY (OVL_FUNCTION (t));
-      TRY (OVL_CHAIN (t));
+      WALK_SUBTREE (OVL_FUNCTION (*tp));
+      WALK_SUBTREE (OVL_CHAIN (*tp));
       break;
 
     case TREE_VEC:
       {
-       int len = TREE_VEC_LENGTH (t);
-
-       t = copy_node (t);
+       int len = TREE_VEC_LENGTH (*tp);
        while (len--)
-         TRY (TREE_VEC_ELT (t, len));
+         WALK_SUBTREE (TREE_VEC_ELT (*tp, len));
       }
       break;
 
-    case INTEGER_CST:
-    case REAL_CST:
-    case STRING_CST:
-    case DEFAULT_ARG:
+    case COMPLEX_CST:
+      WALK_SUBTREE (TREE_REALPART (*tp));
+      WALK_SUBTREE (TREE_IMAGPART (*tp));
       break;
 
-    case PTRMEM_CST:
-      TRY (TREE_TYPE (t));
+    case CONSTRUCTOR:
+      WALK_SUBTREE (CONSTRUCTOR_ELTS (*tp));
       break;
 
-    case COND_EXPR:
-    case TARGET_EXPR:
-    case AGGR_INIT_EXPR:
-    case NEW_EXPR:
-      TRY (TREE_OPERAND (t, 0));
-      TRY (TREE_OPERAND (t, 1));
-      TRY (TREE_OPERAND (t, 2));
-      break;
+    case METHOD_TYPE:
+      WALK_SUBTREE (TYPE_METHOD_BASETYPE (*tp));
+      /* Fall through.  */
 
-    case TRUTH_AND_EXPR:
-    case TRUTH_OR_EXPR:
-    case TRUTH_XOR_EXPR:
-    case TRUTH_ANDIF_EXPR:
-    case TRUTH_ORIF_EXPR:
-    case PREDECREMENT_EXPR:
-    case PREINCREMENT_EXPR:
-    case POSTDECREMENT_EXPR:
-    case POSTINCREMENT_EXPR:
-    case ARRAY_REF:
-    case SCOPE_REF:
-    case TRY_CATCH_EXPR:
-    case WITH_CLEANUP_EXPR:
-    case CALL_EXPR:
-    case COMPOUND_EXPR:
-    case MODIFY_EXPR:
-      TRY (TREE_OPERAND (t, 0));
-      TRY (TREE_OPERAND (t, 1));
+    case FUNCTION_TYPE:
+      WALK_SUBTREE (TREE_TYPE (*tp));
+      WALK_SUBTREE (TYPE_ARG_TYPES (*tp));
       break;
 
-    case SAVE_EXPR:
-    case ADDR_EXPR:
-    case INDIRECT_REF:
-    case TRUTH_NOT_EXPR:
-    case COMPONENT_REF:
-    case CLEANUP_POINT_EXPR:
-    case LOOKUP_EXPR:
-    case THROW_EXPR:
-      TRY (TREE_OPERAND (t, 0));
+    case ARRAY_TYPE:
+      WALK_SUBTREE (TREE_TYPE (*tp));
+      WALK_SUBTREE (TYPE_DOMAIN (*tp));
       break;
 
-    case MODOP_EXPR:
-    case ARROW_EXPR:
-    case DOTSTAR_EXPR:
-    case TYPEID_EXPR:
+    case INTEGER_TYPE:
+      WALK_SUBTREE (TYPE_MIN_VALUE (*tp));
+      WALK_SUBTREE (TYPE_MAX_VALUE (*tp));
       break;
 
-    case COMPLEX_CST:
-      TRY (TREE_REALPART (t));
-      TRY (TREE_IMAGPART (t));
+    case OFFSET_TYPE:
+      WALK_SUBTREE (TREE_TYPE (*tp));
+      WALK_SUBTREE (TYPE_OFFSET_BASETYPE (*tp));
       break;
 
-    case CONSTRUCTOR:
-      TRY (CONSTRUCTOR_ELTS (t));
+    case RECORD_TYPE:
+      if (TYPE_PTRMEMFUNC_P (*tp))
+       WALK_SUBTREE (TYPE_PTRMEMFUNC_FN_TYPE (*tp));
       break;
 
-    case TEMPLATE_TEMPLATE_PARM:
-    case TEMPLATE_PARM_INDEX:
-    case TEMPLATE_TYPE_PARM:
-      break;
-
-    case BIND_EXPR:
-    case STMT_EXPR:
-      break;
-
-    case REAL_TYPE:
-    case COMPLEX_TYPE:
-    case VOID_TYPE:
-    case BOOLEAN_TYPE:
-    case TYPENAME_TYPE:
-    case UNION_TYPE:
-    case ENUMERAL_TYPE:
-    case TYPEOF_TYPE:
-      break;
-
-    case POINTER_TYPE:
-    case REFERENCE_TYPE:
-      TRY (TREE_TYPE (t));
-      break;
-
-    case FUNCTION_TYPE:
-    case METHOD_TYPE:
-      TRY (TREE_TYPE (t));
-      TRY (TYPE_ARG_TYPES (t));
-      break;
-
-    case ARRAY_TYPE:
-      TRY (TREE_TYPE (t));
-      TRY (TYPE_DOMAIN (t));
-      break;
-
-    case INTEGER_TYPE:
-      TRY (TYPE_MAX_VALUE (t));
-      break;
-
-    case OFFSET_TYPE:
-      TRY (TREE_TYPE (t));
-      TRY (TYPE_OFFSET_BASETYPE (t));
-      break;
-
-    case RECORD_TYPE:
-      if (TYPE_PTRMEMFUNC_P (t))
-       TRY (TYPE_PTRMEMFUNC_FN_TYPE (t));
-      break;
-      
-    default:
-      my_friendly_abort (19990803);
-    }
+    default:
+      my_friendly_abort (19990803);
+    }
 
+  /* We didn't find what we were looking for.  */
   return NULL_TREE;
 
-#undef TRY
+#undef WALK_SUBTREE
 }
 
-/* Passed to search_tree.  Checks for the use of types with no linkage.  */
+/* Passed to walk_tree.  Checks for the use of types with no linkage.  */
 
 static tree
-no_linkage_helper (t)
-     tree t;
+no_linkage_helper (tp, walk_subtrees, data)
+     tree *tp;
+     int *walk_subtrees ATTRIBUTE_UNUSED;
+     void *data ATTRIBUTE_UNUSED;
 {
+  tree t = *tp;
+
   if (TYPE_P (t)
       && (IS_AGGR_TYPE (t) || TREE_CODE (t) == ENUMERAL_TYPE)
       && (decl_function_context (TYPE_MAIN_DECL (t))
@@ -1770,308 +1420,60 @@ no_linkage_check (t)
   if (processing_template_decl)
     return NULL_TREE;
 
-  t = search_tree (t, no_linkage_helper);
+  t = walk_tree (&t, no_linkage_helper, NULL);
   if (t != error_mark_node)
     return t;
   return NULL_TREE;
 }
 
-
-/* Make copies of all the nodes below T.  If FUNC is non-NULL, call it
-   for each node.  */
+/* Passed to walk_tree.  Copies the node pointed to, if appropriate.  */
 
 tree
-mapcar (t, func)
-     tree t;
-     tree (*func) PROTO((tree));
-{
-  tree tmp;
-  enum tree_code code; 
-
-  if (t == NULL_TREE)
-    return t;
-
-  if (func) 
+copy_tree_r (tp, walk_subtrees, data)
+     tree *tp;
+     int *walk_subtrees;
+     void *data ATTRIBUTE_UNUSED;
+{
+  enum tree_code code = TREE_CODE (*tp);
+
+  /* We make copies of most nodes.  */
+  if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
+      || TREE_CODE_CLASS (code) == 'r'
+      || TREE_CODE_CLASS (code) == 'c'
+      || TREE_CODE_CLASS (code) == 's'
+      || code == PARM_DECL
+      || code == TREE_LIST
+      || code == TREE_VEC
+      || code == OVERLOAD)
     {
-      tmp = func (t);
-      if (tmp)
-       return tmp;
-    }
-
-  /* Handle some common cases up front.  */
-  code = TREE_CODE (t);
-  if (TREE_CODE_CLASS (code) == '1')
-    {
-      t = copy_node (t);
-      TREE_TYPE (t) = mapcar (TREE_TYPE (t), func);
-      TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
-      return t;
+      /* Because the chain gets clobbered when we make a copy, we save it
+        here.  */
+      tree chain = TREE_CHAIN (*tp);
+
+      /* Copy the node.  */
+      *tp = copy_node (*tp);
+
+      /* Now, restore the chain, if appropriate.  That will cause
+        walk_tree to walk into the chain as well.  */
+      if (code == PARM_DECL || code == TREE_LIST || code == OVERLOAD
+         || statement_code_p (code))
+       TREE_CHAIN (*tp) = chain;
+
+      /* For now, we don't update BLOCKs when we make copies.  So, we
+        have to nullify all scope-statements.  */
+      if (TREE_CODE (*tp) == SCOPE_STMT)
+       SCOPE_STMT_BLOCK (*tp) = NULL_TREE;
     }
-  else if (TREE_CODE_CLASS (code) == '2' || TREE_CODE_CLASS (code) == '<')
-    {
-      t = copy_node (t);
-      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);
-      return t;
-    }
-
-  switch (TREE_CODE (t))
-    {
-    case ERROR_MARK:
-      return error_mark_node;
-
-    case VAR_DECL:
-    case FUNCTION_DECL:
-    case CONST_DECL:
-      /* 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); } 
-
-         In a case like:
-
-           void g() { const int i = 7; f<i>(7); }
-
-        however, we must actually return the constant initializer.  */
-      if (TREE_READONLY_DECL_P (t))
-       {
-         tmp = decl_constant_value (t);
-         if (tmp != t)
-           return mapcar (tmp, func);
-       }
-      return error_mark_node;
-
-    case PARM_DECL:
-      {
-       tree chain = TREE_CHAIN (t);
-       t = copy_node (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;
-      }
-
-    case TREE_LIST:
-      {
-       tree chain = TREE_CHAIN (t);
-       t = copy_node (t);
-       TREE_PURPOSE (t) = mapcar (TREE_PURPOSE (t), func);
-       TREE_VALUE (t) = mapcar (TREE_VALUE (t), func);
-       TREE_CHAIN (t) = mapcar (chain, func);
-       return t;
-      }
-
-    case OVERLOAD:
-      {
-       tree chain = OVL_CHAIN (t);
-       t = copy_node (t);
-       OVL_FUNCTION (t) = mapcar (OVL_FUNCTION (t), func);
-       OVL_CHAIN (t) = mapcar (chain, func);
-       return t;
-      }
-
-    case TREE_VEC:
-      {
-       int len = TREE_VEC_LENGTH (t);
-
-       t = copy_node (t);
-       while (len--)
-         TREE_VEC_ELT (t, len) = mapcar (TREE_VEC_ELT (t, len), func);
-       return t;
-      }
-
-    case INTEGER_CST:
-    case REAL_CST:
-    case STRING_CST:
-      return copy_node (t);
-
-    case PTRMEM_CST:
-      t = copy_node (t);
-      TREE_TYPE (t) = mapcar (TREE_TYPE (t), func);
-      PTRMEM_CST_MEMBER (t) = mapcar (PTRMEM_CST_MEMBER (t), func);
-      return t;
-
-    case COND_EXPR:
-    case TARGET_EXPR:
-    case AGGR_INIT_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);
-      TREE_OPERAND (t, 2) = mapcar (TREE_OPERAND (t, 2), func);
-      return t;
-
-    case TRUTH_AND_EXPR:
-    case TRUTH_OR_EXPR:
-    case TRUTH_XOR_EXPR:
-    case TRUTH_ANDIF_EXPR:
-    case TRUTH_ORIF_EXPR:
-    case PREDECREMENT_EXPR:
-    case PREINCREMENT_EXPR:
-    case POSTDECREMENT_EXPR:
-    case POSTINCREMENT_EXPR:
-    case ARRAY_REF:
-    case SCOPE_REF:
-    case TRY_CATCH_EXPR:
-    case WITH_CLEANUP_EXPR:
-    case COMPOUND_EXPR:
-    case MODIFY_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_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_OPERAND (t, 2) = NULL_TREE;
-      return t;
-
-    case SAVE_EXPR:
-    case ADDR_EXPR:
-    case INDIRECT_REF:
-    case TRUTH_NOT_EXPR:
-    case COMPONENT_REF:
-    case CLEANUP_POINT_EXPR:
-    case THROW_EXPR:
-    case STMT_EXPR:
-      t = copy_node (t);
-      TREE_TYPE (t) = mapcar (TREE_TYPE (t), func);
-      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_qualified_type (tmp, TYPE_QUALS (t));
-    case REFERENCE_TYPE:
-      tmp = build_reference_type (mapcar (TREE_TYPE (t), func));
-      return cp_build_qualified_type (tmp, TYPE_QUALS (t));
-    case FUNCTION_TYPE:
-      tmp = build_function_type (mapcar (TREE_TYPE (t), func),
-                                mapcar (TYPE_ARG_TYPES (t), func));
-      return cp_build_qualified_type (tmp, TYPE_QUALS (t));
-    case ARRAY_TYPE:
-      tmp = build_cplus_array_type (mapcar (TREE_TYPE (t), func),
-                                   mapcar (TYPE_DOMAIN (t), func));
-      return cp_build_qualified_type (tmp, CP_TYPE_QUALS (t));
-    case INTEGER_TYPE:
-      tmp = build_index_type (mapcar (TYPE_MAX_VALUE (t), func));
-      return cp_build_qualified_type (tmp, TYPE_QUALS (t));
-    case OFFSET_TYPE:
-      tmp = build_offset_type (mapcar (TYPE_OFFSET_BASETYPE (t), func),
-                              mapcar (TREE_TYPE (t), func));
-      return cp_build_qualified_type (tmp, TYPE_QUALS (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_qualified_type (tmp, TYPE_QUALS (t));
-
-    case COMPLEX_CST:
-      t = copy_node (t);
-      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 BIND_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);
-      TREE_OPERAND (t, 2) = NULL_TREE;
-      return t;
-
-    case NEW_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);
-      TREE_OPERAND (t, 2) = mapcar (TREE_OPERAND (t, 2), func);
-      return t;
-
-    case LOOKUP_EXPR:
-      t = copy_node (t);
-      TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
-      return t;
-
-    case RTL_EXPR:
-      t = copy_node (t);
-      TREE_TYPE (t) = mapcar (TREE_TYPE (t), func);
-      return t;
-
-    case RECORD_TYPE:
-      if (TYPE_PTRMEMFUNC_P (t))
-       return build_ptrmemfunc_type
-         (mapcar (TYPE_PTRMEMFUNC_FN_TYPE (t), func));
-      /* else fall through */
-
-    default:
-      my_friendly_abort (19990815);
-    }
-  my_friendly_abort (107);
-  /* NOTREACHED */
-  return NULL_TREE;
-}
-
-/* Returns T if T is allocated on the permanent obstack, NULL_TREE
-   otherwise.  */
-
-tree
-permanent_p (t)
-     tree t;
-{
-  return TREE_PERMANENT (t) ? t : NULL_TREE;
-}
-
-static tree
-perm_manip (t)
-     tree t;
-{
-  if (TREE_PERMANENT (t))
-    return t;
+  else if (code == TEMPLATE_TEMPLATE_PARM)
+    /* These must be copied specially.  */
+    *tp = copy_template_template_parm (*tp);
+  else if (TREE_CODE_CLASS (code) == 't')
+    /* There's no need to copy types, or anything beneath them.  */
+    *walk_subtrees = 0;
 
-  /* Support `void f () { extern int i; A<&i> a; }' */
-  if ((TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == FUNCTION_DECL)
-      && TREE_PUBLIC (t))
-    {
-      t = copy_node (t);
-
-      /* copy_rtx won't make a new SYMBOL_REF, so call make_decl_rtl again.  */
-      DECL_RTL (t) = 0;
-      make_decl_rtl (t, NULL_PTR, 1);
-
-      return 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;
-{
-  if (t == NULL_TREE || TREE_PERMANENT (t))
-    return t;
-
-  push_permanent_obstack ();
-  t = mapcar (t, perm_manip);
-  pop_obstacks ();
-
-  return t;
-}
-
 #ifdef GATHER_STATISTICS
 extern int depth_reached;
 #endif
@@ -2079,9 +1481,6 @@ extern int depth_reached;
 void
 print_lang_statistics ()
 {
-  extern struct obstack decl_obstack;
-  print_obstack_statistics ("class_obstack", &class_obstack);
-  print_obstack_statistics ("decl_obstack", &decl_obstack);
   print_search_statistics ();
   print_class_statistics ();
 #ifdef GATHER_STATISTICS
@@ -2090,23 +1489,6 @@ print_lang_statistics ()
 #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)
-     const char *string;
-     const char *expression;
-     unsigned line;
-     const char *filename;
-{
-  fprintf (stderr, string, expression, line, filename);
-  fflush (stderr);
-  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.  */
@@ -2139,54 +1521,127 @@ array_type_nelts_total (type)
   return sz;
 }
 
-static
-tree
-bot_manip (t)
-     tree t;
+/* Called from break_out_target_exprs via mapcar.  */
+
+static tree
+bot_manip (tp, walk_subtrees, data)
+     tree *tp;
+     int *walk_subtrees;
+     void *data;
 {
+  splay_tree target_remap = ((splay_tree) data);
+  tree t = *tp;
+
   if (TREE_CODE (t) != TREE_LIST && ! TREE_SIDE_EFFECTS (t))
-    return t;
+    {
+      /* There can't be any TARGET_EXPRs below this point.  */
+      *walk_subtrees = 0;
+      return NULL_TREE;
+    }
   else if (TREE_CODE (t) == TARGET_EXPR)
     {
+      tree u;
+
       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
+         u = 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 
+       {
+         tree var;
+
+         u = copy_node (t);
+         var = build (VAR_DECL, TREE_TYPE (t));
+         DECL_CONTEXT (var) = current_function_decl;
+         layout_decl (var, 0);
+         TREE_OPERAND (u, 0) = var;
+       }
+
+      /* Map the old variable to the new one.  */
+      splay_tree_insert (target_remap, 
+                        (splay_tree_key) TREE_OPERAND (t, 0), 
+                        (splay_tree_value) TREE_OPERAND (u, 0));
+
+      /* Replace the old expression with the new version.  */
+      *tp = u;
+      /* We don't have to go below this point; the recursive call to
+        break_out_target_exprs will have handled anything below this
+        point.  */
+      *walk_subtrees = 0;
+      return NULL_TREE;
     }
   else if (TREE_CODE (t) == CALL_EXPR)
     mark_used (TREE_OPERAND (TREE_OPERAND (t, 0), 0));
 
-  return NULL_TREE;
+  /* Make a copy of this node.  */
+  return copy_tree_r (tp, walk_subtrees, NULL);
 }
   
-/* Actually, we'll just clean out the target exprs for the moment.  */
+/* Replace all remapped VAR_DECLs in T with their new equivalents.
+   DATA is really a splay-tree mapping old variables to new
+   variables.  */
+
+static tree
+bot_replace (t, walk_subtrees, data)
+     tree *t;
+     int *walk_subtrees ATTRIBUTE_UNUSED;
+     void *data;
+{
+  splay_tree target_remap = ((splay_tree) data);
+
+  if (TREE_CODE (*t) == VAR_DECL)
+    {
+      splay_tree_node n = splay_tree_lookup (target_remap,
+                                            (splay_tree_key) *t);
+      if (n)
+       *t = (tree) n->value;
+    }
+
+  return NULL_TREE;
+}
+       
+/* When we parse a default argument expression, we may create
+   temporary variables via TARGET_EXPRs.  When we actually use the
+   default-argument expression, we make a copy of the expression, but
+   we must replace the temporaries with appropriate local versions.  */
 
 tree
 break_out_target_exprs (t)
      tree t;
 {
-  return mapcar (t, bot_manip);
+  static int target_remap_count;
+  static splay_tree target_remap;
+
+  if (!target_remap_count++)
+    target_remap = splay_tree_new (splay_tree_compare_pointers, 
+                                  /*splay_tree_delete_key_fn=*/NULL, 
+                                  /*splay_tree_delete_value_fn=*/NULL);
+  walk_tree (&t, bot_manip, target_remap);
+  walk_tree (&t, bot_replace, target_remap);
+
+  if (!--target_remap_count)
+    {
+      splay_tree_delete (target_remap);
+      target_remap = NULL;
+    }
+
+  return t;
 }
 
 /* Obstack used for allocating nodes in template function and variable
    definitions.  */
 
-/* Similar to `build_nt', except we build
-   on the permanent_obstack, regardless.  */
+/* Similar to `build_nt', except that we set TREE_COMPLEXITY to be the
+   current line number.  */
 
 tree
-build_min_nt VPROTO((enum tree_code code, ...))
+build_min_nt VPARAMS ((enum tree_code code, ...))
 {
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
   enum tree_code code;
 #endif
-  register struct obstack *ambient_obstack = expression_obstack;
   va_list p;
   register tree t;
   register int length;
@@ -2194,12 +1649,10 @@ build_min_nt VPROTO((enum tree_code code, ...))
 
   VA_START (p, code);
 
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
   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;
@@ -2207,25 +1660,23 @@ build_min_nt VPROTO((enum tree_code code, ...))
   for (i = 0; i < length; i++)
     {
       tree x = va_arg (p, tree);
-      TREE_OPERAND (t, i) = copy_to_permanent (x);
+      TREE_OPERAND (t, i) = x;
     }
 
   va_end (p);
-  expression_obstack = ambient_obstack;
   return t;
 }
 
-/* Similar to `build', except we build
-   on the permanent_obstack, regardless.  */
+/* Similar to `build', except we set TREE_COMPLEXITY to the current
+   line-number.  */
 
 tree
-build_min VPROTO((enum tree_code code, tree tt, ...))
+build_min VPARAMS ((enum tree_code code, tree tt, ...))
 {
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
   enum tree_code code;
   tree tt;
 #endif
-  register struct obstack *ambient_obstack = expression_obstack;
   va_list p;
   register tree t;
   register int length;
@@ -2233,43 +1684,44 @@ build_min VPROTO((enum tree_code code, tree tt, ...))
 
   VA_START (p, tt);
 
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
   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) = copy_to_permanent (tt);
+  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);
+      TREE_OPERAND (t, i) = x;
     }
 
   va_end (p);
-  expression_obstack = ambient_obstack;
   return t;
 }
 
-/* Same as `tree_cons' but make a permanent object.  */
+/* Returns an INTEGER_CST (of type `int') corresponding to I.
+   Multiple calls with the same value of I may or may not yield the
+   same node; therefore, callers should never modify the node
+   returned.  */
 
 tree
-min_tree_cons (purpose, value, chain)
-     tree purpose, value, chain;
+build_shared_int_cst (i)
+     int i;
 {
-  register tree node;
-  register struct obstack *ambient_obstack = current_obstack;
-  current_obstack = &permanent_obstack;
+  static tree cache[256];
 
-  node = tree_cons (copy_to_permanent (purpose),
-                   copy_to_permanent (value), chain);
-  current_obstack = ambient_obstack;
-  return node;
+  if (i >= 256)
+    return build_int_2 (i, 0);
+  
+  if (!cache[i])
+    cache[i] = build_int_2 (i, 0);
+  
+  return cache[i];
 }
 
 tree
@@ -2278,7 +1730,7 @@ get_type_decl (t)
 {
   if (TREE_CODE (t) == TYPE_DECL)
     return t;
-  if (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
+  if (TYPE_P (t))
     return TYPE_STUB_DECL (t);
   
   my_friendly_abort (42);
@@ -2325,20 +1777,6 @@ vec_binfo_member (elem, vec)
   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);
-}
-
 /* Returns the namespace that contains DECL, whether directly or
    indirectly.  */
 
@@ -2477,7 +1915,7 @@ cp_tree_equal (t1, t2)
     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')
+      if (TYPE_P (TREE_OPERAND (t1, 0)))
        return same_type_p (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
       break;
 
@@ -2513,20 +1951,6 @@ cp_tree_equal (t1, t2)
   return -1;
 }
 
-/* Similar to make_tree_vec, but build on the momentary_obstack.
-   Thus, these vectors are really and truly temporary.  */
-
-tree
-make_temp_vec (len)
-     int len;
-{
-  register tree node;
-  push_expression_obstack ();
-  node = make_tree_vec (len);
-  pop_obstacks ();
-  return node;
-}
-
 /* Build a wrapper around some pointer PTR so we can use it as a tree.  */
 
 tree
@@ -2544,11 +1968,7 @@ tree
 build_expr_ptr_wrapper (ptr)
      void *ptr;
 {
-  tree t;
-  push_expression_obstack ();
-  t = build_ptr_wrapper (ptr);
-  pop_obstacks ();
-  return t;
+  return build_ptr_wrapper (ptr);
 }
 
 /* Build a wrapper around some integer I so we can use it as a tree.  */
@@ -2569,19 +1989,10 @@ build_srcloc (file, line)
 {
   tree t;
 
-  /* Make sure that we put these on the permanent obstack; up in
-     add_pending_template, we pass this return value into perm_tree_cons,
-     which also puts it on the permanent_obstack.  However, this wasn't
-     explicitly doing the same.  */
-  register struct obstack *ambient_obstack = current_obstack;
-  current_obstack = &permanent_obstack;
-
   t = make_node (SRCLOC);
   SRCLOC_FILE (t) = file;
   SRCLOC_LINE (t) = line;
 
-  current_obstack = ambient_obstack;
-
   return t;
 }
 
@@ -2591,24 +2002,6 @@ build_srcloc_here ()
   return build_srcloc (input_filename, lineno);
 }
 
-void
-push_expression_obstack ()
-{
-  push_obstacks_nochange ();
-  current_obstack = expression_obstack;
-}
-
-/* Begin allocating on the permanent obstack.  When you're done
-   allocating there, call pop_obstacks to return to the previous set
-   of obstacks.  */
-
-void
-push_permanent_obstack ()
-{
-  push_obstacks_nochange ();
-  end_temporary_allocation ();
-}
-
 /* The type of ARG when used as an lvalue.  */
 
 tree
@@ -2658,8 +2051,8 @@ int
 member_p (decl)
      tree decl;
 {
-  tree ctx = DECL_CONTEXT (decl);
-  return (ctx && TREE_CODE_CLASS (TREE_CODE (ctx)) == 't');
+  const tree ctx = DECL_CONTEXT (decl);
+  return (ctx && TYPE_P (ctx));
 }
 
 /* Create a placeholder for member access where we don't actually have an
@@ -2846,41 +2239,172 @@ make_ptrmem_cst (type, member)
   return ptrmem_cst;
 }
 
-/* Initialize unsave for C++. */
+/* Mark ARG (which is really a list_hash_table **) for GC.  */
+
+static void
+mark_list_hash (arg)
+     void *arg;
+{
+  struct list_hash *lh;
+
+  for (lh = * ((struct list_hash **) arg); lh; lh = lh->next)
+    ggc_mark_tree (lh->list);
+}
+
+/* Initialize tree.c.  */
+
 void
-init_cplus_unsave ()
+init_tree ()
 {
-  lang_unsave_expr_now = cplus_unsave_expr_now;
+  make_lang_type_fn = cp_make_lang_type;
+  lang_unsave = cp_unsave;
+  ggc_add_root (list_hash_table, 
+               sizeof (list_hash_table) / sizeof (struct list_hash *),
+               sizeof (struct list_hash *),
+               mark_list_hash);
 }
 
-/* The C++ version of unsave_expr_now.
-   See gcc/tree.c:unsave_expr_now for comments. */
+/* The SAVE_EXPR pointed to by TP is being copied.  If ST contains
+   information indicating to what new SAVE_EXPR this one should be
+   mapped, use that one.  Otherwise, create a new node and enter it in
+   ST.  FN is the function into which the copy will be placed.  */
 
-tree
-cplus_unsave_expr_now (expr)
-     tree expr;
+void
+remap_save_expr (tp, st, fn, walk_subtrees)
+     tree *tp;
+     splay_tree st;
+     tree fn;
+     int *walk_subtrees;
 {
-  if (expr == NULL)
-    return expr;
+  splay_tree_node n;
 
-  else if (TREE_CODE (expr) == AGGR_INIT_EXPR)
+  /* See if we already encountered this SAVE_EXPR.  */
+  n = splay_tree_lookup (st, (splay_tree_key) *tp);
+      
+  /* If we didn't already remap this SAVE_EXPR, do so now.  */
+  if (!n)
     {
-      unsave_expr_now (TREE_OPERAND (expr,0));
-      if (TREE_OPERAND (expr, 1)
-         && TREE_CODE (TREE_OPERAND (expr, 1)) == TREE_LIST)
-       {
-         tree exp = TREE_OPERAND (expr, 1);
-         while (exp)
-           {
-             unsave_expr_now (TREE_VALUE (exp));
-             exp = TREE_CHAIN (exp);
-           }
-       }
-      unsave_expr_now (TREE_OPERAND (expr,2));
-      return expr;
+      tree t = copy_node (*tp);
+
+      /* The SAVE_EXPR is now part of the function into which we
+        are inlining this body.  */
+      SAVE_EXPR_CONTEXT (t) = fn;
+      /* And we haven't evaluated it yet.  */
+      SAVE_EXPR_RTL (t) = NULL_RTX;
+      /* Remember this SAVE_EXPR.  */
+      n = splay_tree_insert (st,
+                            (splay_tree_key) *tp,
+                            (splay_tree_value) t);
     }
+  else
+    /* We've already walked into this SAVE_EXPR, so we needn't do it
+       again.  */
+    *walk_subtrees = 0;
+
+  /* Replace this SAVE_EXPR with the copy.  */
+  *tp = (tree) n->value;
+}
 
+/* Called via walk_tree.  If *TP points to a DECL_STMT for a local
+   declaration, copies the declaration and enters it in the splay_tree
+   pointed to by DATA (which is really a `splay_tree *').  */
+
+static tree
+mark_local_for_remap_r (tp, walk_subtrees, data)
+     tree *tp;
+     int *walk_subtrees ATTRIBUTE_UNUSED;
+     void *data;
+{
+  tree t = *tp;
+  splay_tree st = (splay_tree) data;
+  tree decl;
+
+  
+  if (TREE_CODE (t) == DECL_STMT
+      && nonstatic_local_decl_p (DECL_STMT_DECL (t)))
+    decl = DECL_STMT_DECL (t);
+  else if (TREE_CODE (t) == LABEL_STMT)
+    decl = LABEL_STMT_LABEL (t);
+  else if (TREE_CODE (t) == TARGET_EXPR
+          && nonstatic_local_decl_p (TREE_OPERAND (t, 0)))
+    decl = TREE_OPERAND (t, 0);
+  else
+    decl = NULL_TREE;
+
+  if (decl)
+    {
+      tree copy;
+
+      /* Make a copy.  */
+      copy = copy_decl_for_inlining (decl, 
+                                    DECL_CONTEXT (decl), 
+                                    DECL_CONTEXT (decl));
+
+      /* Remember the copy.  */
+      splay_tree_insert (st,
+                        (splay_tree_key) decl, 
+                        (splay_tree_value) copy);
+    }
+
+  return NULL_TREE;
+}
+
+/* Called via walk_tree when an expression is unsaved.  Using the
+   splay_tree pointed to by ST (which is really a `splay_tree'),
+   remaps all local declarations to appropriate replacements.  */
+
+static tree
+cp_unsave_r (tp, walk_subtrees, data)
+     tree *tp;
+     int *walk_subtrees;
+     void *data;
+{
+  splay_tree st = (splay_tree) data;
+  splay_tree_node n;
+
+  /* Only a local declaration (variable or label).  */
+  if (nonstatic_local_decl_p (*tp))
+    {
+      /* Lookup the declaration.  */
+      n = splay_tree_lookup (st, (splay_tree_key) *tp);
+      
+      /* If it's there, remap it.  */
+      if (n)
+       *tp = (tree) n->value;
+    }
+  else if (TREE_CODE (*tp) == SAVE_EXPR)
+    remap_save_expr (tp, st, current_function_decl, walk_subtrees);
   else
-    return expr;
+    {
+      copy_tree_r (tp, walk_subtrees, NULL);
+
+      /* Do whatever unsaving is required.  */
+      unsave_expr_1 (*tp);
+    }
+
+  /* Keep iterating.  */
+  return NULL_TREE;
 }
 
+/* Called by unsave_expr_now whenever an expression (*TP) needs to be
+   unsaved.  */
+
+static void
+cp_unsave (tp)
+     tree *tp;
+{
+  splay_tree st;
+
+  /* Create a splay-tree to map old local variable declarations to new
+     ones.  */
+  st = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
+
+  /* Walk the tree once figuring out what needs to be remapped.  */
+  walk_tree (tp, mark_local_for_remap_r, st);
+
+  /* Walk the tree again, copying, remapping, and unsaving.  */
+  walk_tree (tp, cp_unsave_r, st);
+
+  /* Clean up.  */
+  splay_tree_delete (st);
+}