langhooks.h (struct lang_hooks_for_tree_inlining): Add start_inlining, end_inlining.
[gcc.git] / gcc / cp / tree.c
index ce26ec9831518856c4c9db615822a1b1a058957e..1d0c32475ad3e818a6eef1f58a19f5966d58ca31 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, 2001 Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
@@ -30,25 +31,29 @@ Boston, MA 02111-1307, USA.  */
 #include "ggc.h"
 #include "insn-config.h"
 #include "integrate.h"
-
-static tree bot_manip PROTO((tree *, int *, void *));
-static tree bot_replace PROTO((tree *, int *, void *));
-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 cp_lvalue_kind lvalue_p_1 PROTO((tree, int));
-static tree no_linkage_helper PROTO((tree *, int *, void *));
-static tree build_srcloc PROTO((char *, int));
-static void mark_list_hash PROTO ((void *));
-static int statement_code_p PROTO((enum tree_code));
-static tree mark_local_for_remap_r PROTO((tree *, int *, void *));
-static tree cp_unsave_r PROTO ((tree *, int *, void *));
-static void cp_unsave PROTO((tree *));
-static tree build_target_expr PROTO((tree, tree));
-
-#define CEIL(x,y) (((x) + (y) - 1) / (y))
+#include "tree-inline.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 int list_hash_eq PARAMS ((const void *, const void *));
+static hashval_t list_hash_pieces PARAMS ((tree, tree, tree));
+static hashval_t list_hash PARAMS ((const void *));
+static cp_lvalue_kind lvalue_p_1 PARAMS ((tree, int));
+static tree no_linkage_helper PARAMS ((tree *, int *, void *));
+static tree build_srcloc PARAMS ((const char *, int));
+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));
+static tree count_trees_r PARAMS ((tree *, int *, void *));
+static tree verify_stmt_tree_r PARAMS ((tree *, int *, void *));
+static tree find_tree_r PARAMS ((tree *, int *, void *));
+extern int cp_statement_code_p PARAMS ((enum tree_code));
+
+static tree handle_java_interface_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_com_interface_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree handle_init_priority_attribute PARAMS ((tree *, tree, tree, int, bool *));
 
 /* If REF is an lvalue, returns the kind of lvalue that REF is.
    Otherwise, returns clk_none.  If TREAT_CLASS_RVALUES_AS_LVALUES is
@@ -65,7 +70,7 @@ lvalue_p_1 (ref, treat_class_rvalues_as_lvalues)
   if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE)
     return clk_ordinary;
 
-  if (ref == current_class_ptr && flag_this_is_variable <= 0)
+  if (ref == current_class_ptr)
     return clk_none;
 
   switch (TREE_CODE (ref))
@@ -80,6 +85,9 @@ lvalue_p_1 (ref, treat_class_rvalues_as_lvalues)
     case WITH_CLEANUP_EXPR:
     case REALPART_EXPR:
     case IMAGPART_EXPR:
+      /* This shouldn't be here, but there are lots of places in the compiler
+         that are sloppy about tacking on NOP_EXPRs to the same type when
+        no actual conversion is happening.  */
     case NOP_EXPR:
       return lvalue_p_1 (TREE_OPERAND (ref, 0),
                         treat_class_rvalues_as_lvalues);
@@ -296,6 +304,9 @@ build_target_expr_with_type (init, type)
   tree slot;
   tree rval;
 
+  if (TREE_CODE (init) == TARGET_EXPR)
+    return init;
+
   slot = build (VAR_DECL, type);
   DECL_ARTIFICIAL (slot) = 1;
   DECL_CONTEXT (slot) = current_function_decl;
@@ -314,37 +325,6 @@ get_target_expr (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.  */
-
-tree
-break_out_cleanups (exp)
-     tree exp;
-{
-  tree tmp = exp;
-
-  if (TREE_CODE (tmp) == CALL_EXPR
-      && TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (tmp)))
-    return build_cplus_new (TREE_TYPE (tmp), tmp);
-
-  while (TREE_CODE (tmp) == NOP_EXPR
-        || TREE_CODE (tmp) == CONVERT_EXPR
-        || TREE_CODE (tmp) == NON_LVALUE_EXPR)
-    {
-      if (TREE_CODE (TREE_OPERAND (tmp, 0)) == CALL_EXPR
-         && TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (TREE_OPERAND (tmp, 0))))
-       {
-         TREE_OPERAND (tmp, 0)
-           = build_cplus_new (TREE_TYPE (TREE_OPERAND (tmp, 0)),
-                              TREE_OPERAND (tmp, 0));
-         break;
-       }
-      else
-       tmp = TREE_OPERAND (tmp, 0);
-    }
-  return exp;
-}
-
 /* Recursively perform a preorder search EXP for CALL_EXPRs, making
    copies where they are found.  Returns a deep copy all nodes transitively
    containing CALL_EXPRs.  */
@@ -404,7 +384,7 @@ break_out_calls (exp)
     case 'e':  /* an expression */
     case 'r':  /* a reference */
     case 's':  /* an expression with side effects */
-      for (i = tree_code_length[(int) code] - 1; i >= 0; i--)
+      for (i = TREE_CODE_LENGTH (code) - 1; i >= 0; i--)
        {
          t1 = break_out_calls (TREE_OPERAND (exp, i));
          if (t1 != TREE_OPERAND (exp, i))
@@ -426,7 +406,7 @@ break_out_calls (exp)
        changed = 1;
       if (changed)
        {
-         if (tree_code_length[(int) code] == 1)
+         if (TREE_CODE_LENGTH (code) == 1)
            return build1 (code, TREE_TYPE (exp), t1);
          else
            return build (code, TREE_TYPE (exp), t1, t2);
@@ -436,12 +416,6 @@ break_out_calls (exp)
 
 }
 \f
-extern struct obstack permanent_obstack;
-
-/* Here is how primitive or already-canonicalized types' hash
-   codes are made.  MUST BE CONSISTENT WITH tree.c !!! */
-#define TYPE_HASH(TYPE) ((HOST_WIDE_INT) (TYPE) & 0777777)
-
 /* 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.  */
@@ -462,9 +436,7 @@ build_cplus_method_type (basetype, rettype, argtypes)
   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.  Make
-     sure that the new argument list is allocated on the same obstack
-     as the type.  */
+     which is "this".  Put it into the list of argument types.  */
   argtypes = tree_cons (NULL_TREE, ptype, argtypes);
   TYPE_ARG_TYPES (t) = argtypes;
   TREE_SIDE_EFFECTS (argtypes) = 1;  /* Mark first argtype as "artificial".  */
@@ -476,7 +448,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;
@@ -507,8 +479,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));
+  TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) 
+    = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TYPE_MAIN_VARIANT (elt_type));
   return t;
 }
 
@@ -518,9 +490,10 @@ build_cplus_array_type (elt_type, index_type)
      tree index_type;
 {
   tree t;
-  int type_quals = CP_TYPE_QUALS (elt_type);
+  int type_quals = cp_type_quals (elt_type);
 
-  elt_type = TYPE_MAIN_VARIANT (elt_type);
+  if (type_quals != TYPE_UNQUALIFIED)
+    elt_type = cp_build_qualified_type (elt_type, TYPE_UNQUALIFIED);
 
   t = build_cplus_array_type_1 (elt_type, index_type);
 
@@ -548,7 +521,7 @@ cp_build_qualified_type_real (type, type_quals, complain)
   if (type == error_mark_node)
     return type;
 
-  if (type_quals == TYPE_QUALS (type))
+  if (type_quals == cp_type_quals (type))
     return type;
 
   /* A restrict-qualified pointer type must be a pointer (or reference)
@@ -590,9 +563,7 @@ cp_build_qualified_type_real (type, type_quals, complain)
        return error_mark_node;
 
       /* See if we already have an identically qualified type.  */
-      for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
-       if (CP_TYPE_QUALS (t) == type_quals)
-         break;
+      t = get_qualified_type (type, type_quals);
 
       /* If we didn't already have it, create it now.  */
       if (!t)
@@ -604,7 +575,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
@@ -612,8 +583,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))
@@ -653,103 +624,9 @@ tree
 canonical_type_variant (t)
      tree t;
 {
-  return cp_build_qualified_type (TYPE_MAIN_VARIANT (t), CP_TYPE_QUALS (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;
-
-  if (flag_new_abi)
-    {
-      for (i = 0; i < n_baselinks; ++i)
-       {
-         tree base_binfo;
-
-         /* Figure out which base we're looking at.  */
-         base_binfo = TREE_VEC_ELT (binfos, i);
-
-         /* Skip virtual bases.  Their BINFO_OFFSET doesn't matter
-            since they are always reached by using offsets looked up
-            at run-time.  */
-         if (TREE_VIA_VIRTUAL (base_binfo))
-           continue;
-
-         /* Whatever offset this class used to have in its immediate
-            derived class, it is now at OFFSET more bytes in its
-            final derived class, since the immediate derived class is
-            already at the indicated OFFSET.  */
-         BINFO_OFFSET (base_binfo)
-           = size_binop (PLUS_EXPR, BINFO_OFFSET (base_binfo), offset);
-
-         propagate_binfo_offsets (base_binfo, offset);
-       }
-    }
-  else
-    {
-      /* This algorithm, used for the old ABI, is neither simple, nor
-        general.  For example, it mishandles the case of:
-       
-           struct A;
-          struct B : public A;
-          struct C : public B;
-          
-        if B is at offset zero in C, but A is not in offset zero in
-        B.  In that case, it sets the BINFO_OFFSET for A to zero.
-        (This sitution arises in the new ABI if B has virtual
-        functions, but A does not.)  Rather than change this
-        algorithm, and risking breaking the old ABI, it is preserved
-        here.  */
-      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;
-                 }
-
-             BINFO_OFFSET (base_binfo) = offset;
-
-             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.  */
 
@@ -778,194 +655,61 @@ unshare_base_binfos (binfo)
       TREE_VIA_PROTECTED (new_binfo) = TREE_VIA_PROTECTED (base_binfo);
       TREE_VIA_VIRTUAL (new_binfo) = TREE_VIA_VIRTUAL (base_binfo);
       BINFO_INHERITANCE_CHAIN (new_binfo) = binfo;
+      BINFO_PRIMARY_BASE_OF (new_binfo) = NULL_TREE;
       unshare_base_binfos (new_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 = CLASSTYPE_N_BASECLASSES (rec);
-  tree vbase_types;
-  tree *field;
-
-  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.
-     Simultaneously, remove the temporary FIELD_DECLS we created in
-     build_base_fields to refer to base types.  */
-  field = &TYPE_FIELDS (rec);
-  if (TYPE_VFIELD (rec) == *field)
-    {
-      /* If this class did not have a primary base, we create a
-        virtual function table pointer.  It will be the first thing
-        in the class, under the new ABI.  Skip it; the base fields
-        will follow it.  */
-      my_friendly_assert (flag_new_abi 
-                         && !CLASSTYPE_HAS_PRIMARY_BASE_P (rec),
-                         19991218);
-      field = &TREE_CHAIN (*field);
-    }
-    
-  for (i = 0; i < n_baseclasses; i++)
-    {
-      register tree base_binfo = TREE_VEC_ELT (binfos, i);
-      register tree basetype = BINFO_TYPE (base_binfo);
-
-      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));
-
-      /* Remove this field.  */
-      *field = 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;
-}
-
 \f
 /* Hashing of lists so that we don't make duplicates.
    The entry point is `list_hash_canon'.  */
 
-/* Each hash table slot is a bucket containing a chain
-   of these structures.  */
-
-struct list_hash
-{
-  struct list_hash *next;      /* Next structure in the bucket.  */
-  int hashcode;                        /* Hash code of this list.  */
-  tree list;                   /* The list recorded here.  */
-};
-
 /* Now here is the hash table.  When recording a list, it is added
    to the slot whose index is the hash code mod the table size.
    Note that the hash table is used for several kinds of lists.
    While all these live in the same table, they are completely independent,
    and the hash code is computed differently for each of these.  */
 
-#define TYPE_HASH_SIZE 59
-static struct list_hash *list_hash_table[TYPE_HASH_SIZE];
+static htab_t list_hash_table;
+
+struct list_proxy 
+{
+  tree purpose;
+  tree value;
+  tree chain;
+};
+
+/* Compare ENTRY (an entry in the hash table) with DATA (a list_proxy
+   for a node we are thinking about adding).  */
+
+static int
+list_hash_eq (entry, data)
+     const void *entry;
+     const void *data;
+{
+  tree t = (tree) entry;
+  struct list_proxy *proxy = (struct list_proxy *) data;
+
+  return (TREE_VALUE (t) == proxy->value
+         && TREE_PURPOSE (t) == proxy->purpose
+         && TREE_CHAIN (t) == proxy->chain);
+}
 
 /* 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.  */
 
-static int
-list_hash (purpose, value, chain)
-     tree purpose, value, chain;
+static hashval_t
+list_hash_pieces (purpose, value, chain)
+     tree purpose;
+     tree value;
+     tree chain;
 {
-  register int hashcode = 0;
-
+  hashval_t hashcode = 0;
+  
   if (chain)
     hashcode += TYPE_HASH (chain);
-
+  
   if (value)
     hashcode += TYPE_HASH (value);
   else
@@ -977,72 +721,44 @@ list_hash (purpose, value, chain)
   return hashcode;
 }
 
-/* Look in the type hash table for a type isomorphic to TYPE.
-   If one is found, return it.  Otherwise return 0.  */
-
-static tree
-list_hash_lookup (hashcode, purpose, value, chain)
-     int hashcode;
-     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_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.  */
+/* Hash an already existing TREE_LIST.  */
 
-static void
-list_hash_add (hashcode, list)
-     int hashcode;
-     tree list;
+static hashval_t
+list_hash (p)
+     const void *p;
 {
-  register struct list_hash *h;
-
-  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];
-  list_hash_table[hashcode % TYPE_HASH_SIZE] = h;
+  tree t = (tree) p;
+  return list_hash_pieces (TREE_PURPOSE (t), 
+                          TREE_VALUE (t), 
+                          TREE_CHAIN (t));
 }
 
 /* Given list components PURPOSE, VALUE, AND CHAIN, return the canonical
    object for an identical list if one already exists.  Otherwise, build a
    new one, and record it as the canonical object.  */
 
-/* Set to 1 to debug without canonicalization.  Never set by program.  */
-
-static int debug_no_list_hash = 0;
-
 tree
 hash_tree_cons (purpose, value, chain)
      tree purpose, value, chain;
 {
-  tree t;
   int hashcode = 0;
-
-  if (! debug_no_list_hash)
-    {
-      hashcode = list_hash (purpose, value, chain);
-      t = list_hash_lookup (hashcode, purpose, value, chain);
-      if (t)
-       return t;
-    }
-
-  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);
-
-  return t;
+  PTR* slot;
+  struct list_proxy proxy;
+
+  /* Hash the list node.  */
+  hashcode = list_hash_pieces (purpose, value, chain);
+  /* Create a proxy for the TREE_LIST we would like to create.  We
+     don't actually create it so as to avoid creating garbage.  */
+  proxy.purpose = purpose;
+  proxy.value = value;
+  proxy.chain = chain;
+  /* See if it is already in the table.  */
+  slot = htab_find_slot_with_hash (list_hash_table, &proxy, hashcode,
+                                  INSERT);
+  /* If not, create a new node.  */
+  if (!*slot)
+    *slot = (PTR) tree_cons (purpose, value, chain);
+  return *slot;
 }
 
 /* Constructor for hashed lists.  */
@@ -1090,7 +806,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 (11);
   tree type;
 
   if (TREE_CODE (binfo) == TREE_VEC)
@@ -1105,69 +821,55 @@ 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));      
   return new_binfo;
 }
 
-/* Return the binfo value for ELEM in TYPE.  */
+/* 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
-binfo_value (elem, type)
-     tree elem;
-     tree type;
+reverse_path (binfo)
+     tree binfo;
 {
-  if (get_base_distance (elem, type, 0, (tree *)0) == -2)
-    compiler_error ("base class `%s' ambiguous in binfo_value",
-                   TYPE_NAME_STRING (elem));
-  if (elem == type)
-    return TYPE_BINFO (type);
-  if (TREE_CODE (elem) == RECORD_TYPE && TYPE_BINFO (elem) == type)
-    return 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.  */
+  tree reversed_path;
 
-tree
-reverse_path (path)
-     tree path;
-{
-  register tree prev = NULL_TREE, cur;
-  for (cur = path; cur; cur = BINFO_INHERITANCE_CHAIN (cur))
+  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);
     }
-  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 = 0;
 
   while (virtuals)
     {
@@ -1279,23 +981,6 @@ build_overload (decl, chain)
   return ovl_cons (decl, chain);
 }
 
-/* True if fn is in ovl. */
-
-int
-ovl_member (fn, ovl)
-     tree fn;
-     tree ovl;
-{
-  if (ovl == NULL_TREE)
-    return 0;
-  if (TREE_CODE (ovl) != OVERLOAD)
-    return ovl == fn;
-  for (; ovl; ovl = OVL_CHAIN (ovl))
-    if (OVL_FUNCTION (ovl) == fn)
-      return 1;
-  return 0;
-}
-
 int
 is_aggr_type_2 (t1, t2)
      tree t1, t2;
@@ -1307,36 +992,22 @@ is_aggr_type_2 (t1, t2)
 
 /* Returns non-zero if CODE is the code for a statement.  */
 
-static int
-statement_code_p (code)
+int
+cp_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:
+    case EH_SPEC_BLOCK:
+    case USING_STMT:
+    case TAG_DEFN:
       return 1;
 
     default:
@@ -1411,246 +1082,145 @@ build_exception_variant (type, 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 */
+/* Given a TEMPLATE_TEMPLATE_PARM node T, create a new
+   BOUND_TEMPLATE_TEMPLATE_PARM bound with NEWARGS as its template
+   arguments.  */
 
 tree
-copy_template_template_parm (t)
+bind_template_template_parm (t, newargs)
      tree t;
+     tree newargs;
 {
-  tree template = TYPE_NAME (t);
+  tree decl = TYPE_NAME (t);
   tree t2;
 
-  t2 = make_aggr_type (TEMPLATE_TEMPLATE_PARM);
-  template = copy_node (template);
-  copy_lang_decl (template);
+  t2 = make_aggr_type (BOUND_TEMPLATE_TEMPLATE_PARM);
+  decl = build_decl (TYPE_DECL, DECL_NAME (decl), NULL_TREE);
+
+  /* These nodes have to be created to reflect new TYPE_DECL and template
+     arguments.  */
+  TEMPLATE_TYPE_PARM_INDEX (t2) = copy_node (TEMPLATE_TYPE_PARM_INDEX (t));
+  TEMPLATE_PARM_DECL (TEMPLATE_TYPE_PARM_INDEX (t2)) = decl;
+  TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t2)
+    = tree_cons (TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (t), 
+                newargs, NULL_TREE);
 
-  TREE_TYPE (template) = t2;
-  TYPE_NAME (t2) = template;
-  TYPE_STUB_DECL (t2) = template;
+  TREE_TYPE (decl) = t2;
+  TYPE_NAME (t2) = decl;
+  TYPE_STUB_DECL (t2) = decl;
+  TYPE_SIZE (t2) = 0;
 
-  /* No need to copy these */
-  TYPE_FIELDS (t2) = TYPE_FIELDS (t);
-  TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t2) 
-    = TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO (t);
   return t2;
 }
 
-/* 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.  */
+/* Called from count_trees via walk_tree.  */
 
-tree 
-walk_tree (tp, func, data)
-     tree *tp;
-     walk_tree_fn func;
+static tree
+count_trees_r (tp, walk_subtrees, data)
+     tree *tp ATTRIBUTE_UNUSED;
+     int *walk_subtrees ATTRIBUTE_UNUSED;
      void *data;
 {
-  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;
+  ++ *((int*) data);
+  return NULL_TREE;
+}
 
-  /* Call the function.  */
-  walk_subtrees = 1;
-  result = (*func) (tp, &walk_subtrees, data);
+/* Debugging function for measuring the rough complexity of a tree
+   representation.  */
 
-  /* If we found something, return it.  */
-  if (result)
-    return result;
+int
+count_trees (t)
+     tree t;
+{
+  int n_trees = 0;
+  walk_tree_without_duplicates (&t, count_trees_r, &n_trees);
+  return n_trees;
+}  
 
-  /* 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;
+/* Called from verify_stmt_tree via walk_tree.  */
 
-  code = TREE_CODE (*tp);
+static tree
+verify_stmt_tree_r (tp, walk_subtrees, data)
+     tree *tp;
+     int *walk_subtrees ATTRIBUTE_UNUSED;
+     void *data;
+{
+  tree t = *tp;
+  htab_t *statements = (htab_t *) data;
+  void **slot;
 
-  /* Handle common cases up front.  */
-  if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
-      || TREE_CODE_CLASS (code) == 'r'
-      || TREE_CODE_CLASS (code) == 's')
-    {
-      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) 
-             && TREE_CODE_CLASS (TREE_CODE (DECL_STMT_DECL (*tp))) == 'd')
-           {
-             /* 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)));
-           }
+  if (!statement_code_p (TREE_CODE (t)))
+    return NULL_TREE;
 
-         WALK_SUBTREE (TREE_CHAIN (*tp));
-       }
+  /* If this statement is already present in the hash table, then
+     there is a circularity in the statement tree.  */
+  if (htab_find (*statements, t))
+    my_friendly_abort (20000727);
+  
+  slot = htab_find_slot (*statements, t, INSERT);
+  *slot = t;
 
-      /* We didn't find what we were looking for.  */
-      return NULL_TREE;
-    }
-  else if (TREE_CODE_CLASS (code) == 'd')
-    {
-      WALK_SUBTREE (TREE_TYPE (*tp));
+  return NULL_TREE;
+}
 
-      /* We didn't find what we were looking for.  */
-      return NULL_TREE;
-    }
+/* Debugging function to check that the statement T has not been
+   corrupted.  For now, this function simply checks that T contains no
+   circularities.  */
 
-  /* Not one of the easy cases.  We must explicitly go through the
-     children.  */
-  switch (code)
-    {
-    case ERROR_MARK:
-    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;
+void
+verify_stmt_tree (t)
+     tree t;
+{
+  htab_t statements;
+  statements = htab_create (37, htab_hash_pointer, htab_eq_pointer, NULL);
+  walk_tree (&t, verify_stmt_tree_r, &statements, NULL);
+  htab_delete (statements);
+}
 
-    case PTRMEM_CST:
-      WALK_SUBTREE (TREE_TYPE (*tp));
-      break;
+/* Called from find_tree via walk_tree.  */
 
-    case POINTER_TYPE:
-    case REFERENCE_TYPE:
-      WALK_SUBTREE (TREE_TYPE (*tp));
-      break;
+static tree
+find_tree_r (tp, walk_subtrees, data)
+     tree *tp;
+     int *walk_subtrees ATTRIBUTE_UNUSED;
+     void *data;
+{
+  if (*tp == (tree) data)
+    return (tree) data;
 
-    case TREE_LIST:
-      WALK_SUBTREE (TREE_PURPOSE (*tp));
-      WALK_SUBTREE (TREE_VALUE (*tp));
-      WALK_SUBTREE (TREE_CHAIN (*tp));
-      break;
+  return NULL_TREE;
+}
 
-    case OVERLOAD:
-      WALK_SUBTREE (OVL_FUNCTION (*tp));
-      WALK_SUBTREE (OVL_CHAIN (*tp));
-      break;
+/* Returns X if X appears in the tree structure rooted at T.  */
 
-    case TREE_VEC:
-      {
-       int len = TREE_VEC_LENGTH (*tp);
-       while (len--)
-         WALK_SUBTREE (TREE_VEC_ELT (*tp, len));
-      }
-      break;
+tree
+find_tree (t, x)
+     tree t;
+     tree x;
+{
+  return walk_tree_without_duplicates (&t, find_tree_r, x);
+}
 
-    case COMPLEX_CST:
-      WALK_SUBTREE (TREE_REALPART (*tp));
-      WALK_SUBTREE (TREE_IMAGPART (*tp));
-      break;
+/* Passed to walk_tree.  Checks for the use of types with no linkage.  */
 
-    case CONSTRUCTOR:
-      WALK_SUBTREE (CONSTRUCTOR_ELTS (*tp));
-      break;
+static tree
+no_linkage_helper (tp, walk_subtrees, data)
+     tree *tp;
+     int *walk_subtrees ATTRIBUTE_UNUSED;
+     void *data ATTRIBUTE_UNUSED;
+{
+  tree t = *tp;
 
-    case METHOD_TYPE:
-      WALK_SUBTREE (TYPE_METHOD_BASETYPE (*tp));
-      /* Fall through.  */
+  if (TYPE_P (t)
+      && (CLASS_TYPE_P (t) || TREE_CODE (t) == ENUMERAL_TYPE)
+      && (decl_function_context (TYPE_MAIN_DECL (t))
+         || TYPE_ANONYMOUS_P (t)))
+    return t;
+  return NULL_TREE;
+}
 
-    case FUNCTION_TYPE:
-      WALK_SUBTREE (TREE_TYPE (*tp));
-      WALK_SUBTREE (TYPE_ARG_TYPES (*tp));
-      break;
-
-    case ARRAY_TYPE:
-      WALK_SUBTREE (TREE_TYPE (*tp));
-      WALK_SUBTREE (TYPE_DOMAIN (*tp));
-      break;
-
-    case INTEGER_TYPE:
-      WALK_SUBTREE (TYPE_MIN_VALUE (*tp));
-      WALK_SUBTREE (TYPE_MAX_VALUE (*tp));
-      break;
-
-    case OFFSET_TYPE:
-      WALK_SUBTREE (TREE_TYPE (*tp));
-      WALK_SUBTREE (TYPE_OFFSET_BASETYPE (*tp));
-      break;
-
-    case RECORD_TYPE:
-      if (TYPE_PTRMEMFUNC_P (*tp))
-       WALK_SUBTREE (TYPE_PTRMEMFUNC_FN_TYPE (*tp));
-      break;
-
-    default:
-      my_friendly_abort (19990803);
-    }
-
-  /* We didn't find what we were looking for.  */
-  return NULL_TREE;
-
-#undef WALK_SUBTREE
-}
-
-/* Passed to walk_tree.  Checks for the use of types with no linkage.  */
-
-static tree
-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))
-         || ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))))
-    return t;
-  return NULL_TREE;
-}
-
-/* Check if the type T depends on a type with no linkage and if so, return
-   it.  */
+/* Check if the type T depends on a type with no linkage and if so, return
+   it.  */
 
 tree
 no_linkage_check (t)
@@ -1661,66 +1231,18 @@ no_linkage_check (t)
   if (processing_template_decl)
     return NULL_TREE;
 
-  t = walk_tree (&t, no_linkage_helper, NULL);
+  t = walk_tree_without_duplicates (&t, no_linkage_helper, NULL);
   if (t != error_mark_node)
     return t;
   return NULL_TREE;
 }
 
-/* Passed to walk_tree.  Copies the node pointed to, if appropriate.  */
-
-tree
-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)
-    {
-      /* 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 (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;
-
-  return NULL_TREE;
-}
-
 #ifdef GATHER_STATISTICS
 extern int depth_reached;
 #endif
 
 void
-print_lang_statistics ()
+cxx_print_statistics ()
 {
   print_search_statistics ();
   print_class_statistics ();
@@ -1730,23 +1252,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.  */
@@ -1790,13 +1295,15 @@ bot_manip (tp, walk_subtrees, data)
   splay_tree target_remap = ((splay_tree) data);
   tree t = *tp;
 
-  if (TREE_CODE (t) != TREE_LIST && ! TREE_SIDE_EFFECTS (t))
+  if (TREE_CONSTANT (t))
     {
-      /* There can't be any TARGET_EXPRs below this point.  */
+      /* There can't be any TARGET_EXPRs or their slot variables below
+         this point.  We used to check !TREE_SIDE_EFFECTS, but then we
+         failed to copy an ADDR_EXPR of the slot VAR_DECL.  */
       *walk_subtrees = 0;
       return NULL_TREE;
     }
-  else if (TREE_CODE (t) == TARGET_EXPR)
+  if (TREE_CODE (t) == TARGET_EXPR)
     {
       tree u;
 
@@ -1808,9 +1315,8 @@ bot_manip (tp, walk_subtrees, data)
        }
       else 
        {
-         u = copy_node (t);
-         TREE_OPERAND (u, 0) = build (VAR_DECL, TREE_TYPE (t));
-         layout_decl (TREE_OPERAND (u, 0), 0);
+         u = build_target_expr_with_type
+           (break_out_target_exprs (TREE_OPERAND (t, 1)), TREE_TYPE (t));
        }
 
       /* Map the old variable to the new one.  */
@@ -1872,8 +1378,8 @@ break_out_target_exprs (t)
     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);
+  walk_tree (&t, bot_manip, target_remap, NULL);
+  walk_tree (&t, bot_replace, target_remap, NULL);
 
   if (!--target_remap_count)
     {
@@ -1891,24 +1397,17 @@ break_out_target_exprs (t)
    current line number.  */
 
 tree
-build_min_nt VPROTO((enum tree_code code, ...))
+build_min_nt VPARAMS ((enum tree_code code, ...))
 {
-#ifndef ANSI_PROTOTYPES
-  enum tree_code code;
-#endif
-  va_list p;
   register tree t;
   register int length;
   register int i;
 
-  VA_START (p, code);
-
-#ifndef ANSI_PROTOTYPES
-  code = va_arg (p, enum tree_code);
-#endif
+  VA_OPEN (p, code);
+  VA_FIXEDARG (p, enum tree_code, code);
 
   t = make_node (code);
-  length = tree_code_length[(int) code];
+  length = TREE_CODE_LENGTH (code);
   TREE_COMPLEXITY (t) = lineno;
 
   for (i = 0; i < length; i++)
@@ -1917,7 +1416,7 @@ build_min_nt VPROTO((enum tree_code code, ...))
       TREE_OPERAND (t, i) = x;
     }
 
-  va_end (p);
+  VA_CLOSE (p);
   return t;
 }
 
@@ -1925,26 +1424,18 @@ build_min_nt VPROTO((enum tree_code code, ...))
    line-number.  */
 
 tree
-build_min VPROTO((enum tree_code code, tree tt, ...))
+build_min VPARAMS ((enum tree_code code, tree tt, ...))
 {
-#ifndef ANSI_PROTOTYPES
-  enum tree_code code;
-  tree tt;
-#endif
-  va_list p;
   register tree t;
   register int length;
   register int i;
 
-  VA_START (p, tt);
-
-#ifndef ANSI_PROTOTYPES
-  code = va_arg (p, enum tree_code);
-  tt = va_arg (p, tree);
-#endif
+  VA_OPEN (p, tt);
+  VA_FIXEDARG (p, enum tree_code, code);
+  VA_FIXEDARG (p, tree, tt);
 
   t = make_node (code);
-  length = tree_code_length[(int) code];
+  length = TREE_CODE_LENGTH (code);
   TREE_TYPE (t) = tt;
   TREE_COMPLEXITY (t) = lineno;
 
@@ -1954,18 +1445,40 @@ build_min VPROTO((enum tree_code code, tree tt, ...))
       TREE_OPERAND (t, i) = x;
     }
 
-  va_end (p);
+  VA_CLOSE (p);
   return t;
 }
 
+/* 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
+build_shared_int_cst (i)
+     int i;
+{
+  static tree cache[256];
+
+  if (i >= 256)
+    return build_int_2 (i, 0);
+  
+  if (!cache[i])
+    cache[i] = build_int_2 (i, 0);
+  
+  return cache[i];
+}
+
 tree
 get_type_decl (t)
      tree 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);
+  if (t == error_mark_node)
+    return t;
   
   my_friendly_abort (42);
 
@@ -1973,27 +1486,6 @@ get_type_decl (t)
   return 0;
 }
 
-int
-can_free (obstack, t)
-     struct obstack *obstack;
-     tree t;
-{
-  int size = 0;
-
-  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.  */
 
@@ -2011,20 +1503,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.  */
 
@@ -2089,7 +1567,7 @@ cp_tree_equal (t1, t2)
 
     case STRING_CST:
       return TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2)
-       && !bcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2),
+       && !memcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2),
                  TREE_STRING_LENGTH (t1));
 
     case CONSTRUCTOR:
@@ -2127,10 +1605,10 @@ cp_tree_equal (t1, t2)
         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)
+          && !DECL_RTL_SET_P (TREE_OPERAND (t1, 0)))
          || (TREE_CODE (TREE_OPERAND (t2, 0)) == VAR_DECL
              && DECL_NAME (TREE_OPERAND (t2, 0)) == NULL_TREE
-             && DECL_RTL (TREE_OPERAND (t2, 0)) == 0))
+             && !DECL_RTL_SET_P (TREE_OPERAND (t2, 0))))
        cmp = 1;
       else
        cmp = cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
@@ -2142,7 +1620,7 @@ cp_tree_equal (t1, t2)
       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));
+      return cp_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t1, 1));
 
     case COMPONENT_REF:
       if (TREE_OPERAND (t1, 1) == TREE_OPERAND (t2, 1))
@@ -2163,7 +1641,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;
 
@@ -2179,21 +1657,27 @@ cp_tree_equal (t1, t2)
 
   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;
+      {
+       int i;
+       
+       cmp = 1;
+       for (i = 0; i < TREE_CODE_LENGTH (code1); ++i)
+         {
+           cmp = cp_tree_equal (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i));
+           if (cmp <= 0)
+             return cmp;
+         }
+       return cmp;
+      }
+    
+      case 't':
+       return same_type_p (t1, t2) ? 1 : 0;
     }
 
   return -1;
@@ -2210,15 +1694,6 @@ build_ptr_wrapper (ptr)
   return t;
 }
 
-/* Same, but on the expression_obstack.  */
-
-tree
-build_expr_ptr_wrapper (ptr)
-     void *ptr;
-{
-  return build_ptr_wrapper (ptr);
-}
-
 /* Build a wrapper around some integer I so we can use it as a tree.  */
 
 tree
@@ -2232,7 +1707,7 @@ build_int_wrapper (i)
 
 static tree
 build_srcloc (file, line)
-     char *file;
+     const char *file;
      int line;
 {
   tree t;
@@ -2299,8 +1774,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
@@ -2311,7 +1786,7 @@ build_dummy_object (type)
      tree type;
 {
   tree decl = build1 (NOP_EXPR, build_pointer_type (type), void_zero_node);
-  return build_indirect_ref (decl, NULL_PTR);
+  return build_indirect_ref (decl, NULL);
 }
 
 /* We've gotten a reference to a member of TYPE.  Return *this if appropriate,
@@ -2324,18 +1799,22 @@ maybe_dummy_object (type, binfop)
      tree *binfop;
 {
   tree decl, context;
-
+  tree binfo;
+  
   if (current_class_type
-      && get_base_distance (type, current_class_type, 0, binfop) != -1)
+      && (binfo = lookup_base (current_class_type, type,
+                              ba_ignore | ba_quiet, NULL)))
     context = current_class_type;
   else
     {
       /* Reference from a nested class member function.  */
       context = type;
-      if (binfop)
-       *binfop = TYPE_BINFO (type);
+      binfo = TYPE_BINFO (type);
     }
 
+  if (binfop)
+    *binfop = binfo;
+  
   if (current_class_ref && context == current_class_type)
     decl = current_class_ref;
   else
@@ -2362,8 +1841,7 @@ int
 pod_type_p (t)
      tree t;
 {
-  while (TREE_CODE (t) == ARRAY_TYPE)
-    t = TREE_TYPE (t);
+  t = strip_array_types (t);
 
   if (INTEGRAL_TYPE_P (t))
     return 1;  /* integral, character or enumeral type */
@@ -2383,91 +1861,145 @@ pod_type_p (t)
   return 1;
 }
 
-/* Return a 1 if ATTR_NAME and ATTR_ARGS denote a valid C++-specific
-   attribute for either declaration DECL or type TYPE and 0 otherwise.
-   Plugged into valid_lang_attribute.  */
-
-int
-cp_valid_lang_attribute (attr_name, attr_args, decl, type)
-  tree attr_name;
-  tree attr_args ATTRIBUTE_UNUSED;
-  tree decl ATTRIBUTE_UNUSED;
-  tree type ATTRIBUTE_UNUSED;
+/* Table of valid C++ attributes.  */
+const struct attribute_spec cp_attribute_table[] =
 {
-  if (is_attribute_p ("com_interface", attr_name))
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+  { "java_interface", 0, 0, false, false, false, handle_java_interface_attribute },
+  { "com_interface",  0, 0, false, false, false, handle_com_interface_attribute },
+  { "init_priority",  1, 1, true,  false, false, handle_init_priority_attribute },
+  { NULL,             0, 0, false, false, false, NULL }
+};
+
+/* Handle a "java_interface" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+handle_java_interface_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags;
+     bool *no_add_attrs;
+{
+  if (DECL_P (*node)
+      || !CLASS_TYPE_P (*node)
+      || !TYPE_FOR_JAVA (*node))
     {
-      if (! flag_vtable_thunks)
-       {
-         error ("`com_interface' only supported with -fvtable-thunks");
-         return 0;
-       }
+      error ("`%s' attribute can only be applied to Java class definitions",
+            IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+  if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+    *node = build_type_copy (*node);
+  TYPE_JAVA_INTERFACE (*node) = 1;
 
-      if (attr_args != NULL_TREE
-         || decl != NULL_TREE
-         || ! CLASS_TYPE_P (type)
-         || type != TYPE_MAIN_VARIANT (type))
-       {
-         warning ("`com_interface' attribute can only be applied to class definitions");
-         return 0;
-       }
+  return NULL_TREE;
+}
 
-      CLASSTYPE_COM_INTERFACE (type) = 1;
-      return 1;
-    }
-  else if (is_attribute_p ("init_priority", attr_name))
+/* Handle a "com_interface" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+handle_com_interface_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  static int warned;
+
+  *no_add_attrs = true;
+
+  if (DECL_P (*node)
+      || !CLASS_TYPE_P (*node)
+      || *node != TYPE_MAIN_VARIANT (*node))
     {
-      tree initp_expr = (attr_args ? TREE_VALUE (attr_args): NULL_TREE);
-      int pri;
+      warning ("`%s' attribute can only be applied to class definitions",
+              IDENTIFIER_POINTER (name));
+      return NULL_TREE;
+    }
+
+  if (!warned++)
+    warning ("`%s' is obsolete; g++ vtables are now COM-compatible by default",
+            IDENTIFIER_POINTER (name));
 
-      if (initp_expr)
-       STRIP_NOPS (initp_expr);
+  return NULL_TREE;
+}
+
+/* Handle an "init_priority" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+handle_init_priority_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  tree initp_expr = TREE_VALUE (args);
+  tree decl = *node;
+  tree type = TREE_TYPE (decl);
+  int pri;
+
+  STRIP_NOPS (initp_expr);
          
-      if (!initp_expr || TREE_CODE (initp_expr) != INTEGER_CST)
-       {
-         error ("requested init_priority is not an integer constant");
-         return 0;
-       }
+  if (!initp_expr || TREE_CODE (initp_expr) != INTEGER_CST)
+    {
+      error ("requested init_priority is not an integer constant");
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
 
-      pri = TREE_INT_CST_LOW (initp_expr);
+  pri = TREE_INT_CST_LOW (initp_expr);
        
-      while (TREE_CODE (type) == ARRAY_TYPE)
-       type = TREE_TYPE (type);
-
-      if (decl == NULL_TREE
-         || TREE_CODE (decl) != VAR_DECL
-         || ! TREE_STATIC (decl)
-         || DECL_EXTERNAL (decl)
-         || (TREE_CODE (type) != RECORD_TYPE
-             && TREE_CODE (type) != UNION_TYPE)
-         /* Static objects in functions are initialized the
-            first time control passes through that
-            function. This is not precise enough to pin down an
-            init_priority value, so don't allow it. */
-         || current_function_decl) 
-       {
-         error ("can only use init_priority attribute on file-scope definitions of objects of class type");
-         return 0;
-       }
+  type = strip_array_types (type);
+
+  if (decl == NULL_TREE
+      || TREE_CODE (decl) != VAR_DECL
+      || !TREE_STATIC (decl)
+      || DECL_EXTERNAL (decl)
+      || (TREE_CODE (type) != RECORD_TYPE
+         && TREE_CODE (type) != UNION_TYPE)
+      /* Static objects in functions are initialized the
+        first time control passes through that
+        function. This is not precise enough to pin down an
+        init_priority value, so don't allow it. */
+      || current_function_decl) 
+    {
+      error ("can only use `%s' attribute on file-scope definitions of objects of class type",
+            IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
 
-      if (pri > MAX_INIT_PRIORITY || pri <= 0)
-       {
-         error ("requested init_priority is out of range");
-         return 0;
-       }
+  if (pri > MAX_INIT_PRIORITY || pri <= 0)
+    {
+      error ("requested init_priority is out of range");
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
 
-      /* Check for init_priorities that are reserved for
-        language and runtime support implementations.*/
-      if (pri <= MAX_RESERVED_INIT_PRIORITY)
-       {
-         warning 
-           ("requested init_priority is reserved for internal use");
-       }
+  /* Check for init_priorities that are reserved for
+     language and runtime support implementations.*/
+  if (pri <= MAX_RESERVED_INIT_PRIORITY)
+    {
+      warning 
+       ("requested init_priority is reserved for internal use");
+    }
 
+  if (SUPPORTS_INIT_PRIORITY)
+    {
       DECL_INIT_PRIORITY (decl) = pri;
-      return 1;
+      return NULL_TREE;
+    }
+  else
+    {
+      error ("`%s' attribute is not supported on this platform",
+            IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+      return NULL_TREE;
     }
-
-  return 0;
 }
 
 /* Return a new PTRMEM_CST of the indicated TYPE.  The MEMBER is the
@@ -2487,70 +2019,254 @@ make_ptrmem_cst (type, member)
   return ptrmem_cst;
 }
 
-/* Mark ARG (which is really a list_hash_table **) for GC.  */
+/* Apply FUNC to all language-specific sub-trees of TP in a pre-order
+   traversal.  Called from walk_tree().  */
 
-static void
-mark_list_hash (arg)
-     void *arg;
+tree 
+cp_walk_subtrees (tp, walk_subtrees_p, func, data, htab)
+     tree *tp;
+     int *walk_subtrees_p;
+     walk_tree_fn func;
+     void *data;
+     void *htab;
 {
-  struct list_hash *lh;
+  enum tree_code code = TREE_CODE (*tp);
+  tree result;
+  
+#define WALK_SUBTREE(NODE)                             \
+  do                                                   \
+    {                                                  \
+      result = walk_tree (&(NODE), func, data, htab);  \
+      if (result)                                      \
+       return result;                                  \
+    }                                                  \
+  while (0)
+
+  /* Not one of the easy cases.  We must explicitly go through the
+     children.  */
+  switch (code)
+    {
+    case DEFAULT_ARG:
+    case TEMPLATE_TEMPLATE_PARM:
+    case BOUND_TEMPLATE_TEMPLATE_PARM:
+    case UNBOUND_CLASS_TEMPLATE:
+    case TEMPLATE_PARM_INDEX:
+    case TEMPLATE_TYPE_PARM:
+    case TYPENAME_TYPE:
+    case TYPEOF_TYPE:
+      /* None of thse have subtrees other than those already walked
+         above.  */
+      *walk_subtrees_p = 0;
+      break;
+
+    case PTRMEM_CST:
+      WALK_SUBTREE (TREE_TYPE (*tp));
+      *walk_subtrees_p = 0;
+      break;
+
+    case TREE_LIST:
+      /* A BASELINK_P's TREE_PURPOSE is a BINFO, and hence circular.  */
+      if (!BASELINK_P (*tp))
+        WALK_SUBTREE (TREE_PURPOSE (*tp));
+      break;
+
+    case OVERLOAD:
+      WALK_SUBTREE (OVL_FUNCTION (*tp));
+      WALK_SUBTREE (OVL_CHAIN (*tp));
+      *walk_subtrees_p = 0;
+      break;
+
+    case RECORD_TYPE:
+      if (TYPE_PTRMEMFUNC_P (*tp))
+       WALK_SUBTREE (TYPE_PTRMEMFUNC_FN_TYPE (*tp));
+      break;
+
+    default:
+      break;
+    }
 
-  for (lh = * ((struct list_hash **) arg); lh; lh = lh->next)
-    ggc_mark_tree (lh->list);
+  /* We didn't find what we were looking for.  */
+  return NULL_TREE;
+
+#undef WALK_SUBTREE
 }
 
-/* Initialize tree.c.  */
+/* Decide whether there are language-specific reasons to not inline a
+   function as a tree.  */
 
-void
-init_tree ()
+int
+cp_cannot_inline_tree_fn (fnp)
+     tree *fnp;
 {
-  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);
+  tree fn = *fnp;
+
+  /* We can inline a template instantiation only if it's fully
+     instantiated.  */
+  if (DECL_TEMPLATE_INFO (fn)
+      && TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (fn)))
+    {
+      fn = *fnp = instantiate_decl (fn, /*defer_ok=*/0);
+      return TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (fn));
+    }
+
+  if (varargs_function_p (fn))
+    {
+      DECL_UNINLINABLE (fn) = 1;
+      return 1;
+    }
+
+  if (! function_attribute_inlinable_p (fn))
+    {
+      DECL_UNINLINABLE (fn) = 1;
+      return 1;
+    }
+
+  return 0;
 }
 
-/* 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.  */
+/* Add any pending functions other than the current function (already
+   handled by the caller), that thus cannot be inlined, to FNS_P, then
+   return the latest function added to the array, PREV_FN.  */
 
-void
-remap_save_expr (tp, st, fn, walk_subtrees)
-     tree *tp;
-     splay_tree st;
-     tree fn;
-     int *walk_subtrees;
+tree
+cp_add_pending_fn_decls (fns_p, prev_fn)
+     void *fns_p;
+     tree prev_fn;
 {
-  splay_tree_node n;
+  varray_type *fnsp = (varray_type *)fns_p;
+  struct saved_scope *s;
 
-  /* 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)
+  for (s = scope_chain; s; s = s->prev)
+    if (s->function_decl && s->function_decl != prev_fn)
+      {
+       VARRAY_PUSH_TREE (*fnsp, s->function_decl);
+       prev_fn = s->function_decl;
+      }
+
+  return prev_fn;
+}
+
+/* Determine whether a tree node is an OVERLOAD node.  Used to decide
+   whether to copy a node or to preserve its chain when inlining a
+   function.  */
+
+int
+cp_is_overload_p (t)
+     tree t;
+{
+  return TREE_CODE (t) == OVERLOAD;
+}
+
+/* Determine whether VAR is a declaration of an automatic variable in
+   function FN.  */
+
+int
+cp_auto_var_in_fn_p (var, fn)
+     tree var, fn;
+{
+  return (DECL_P (var) && DECL_CONTEXT (var) == fn
+         && nonstatic_local_decl_p (var));
+}
+
+/* Tell whether a declaration is needed for the RESULT of a function
+   FN being inlined into CALLER or if the top node of target_exprs is
+   to be used.  */
+
+tree
+cp_copy_res_decl_for_inlining (result, fn, caller, decl_map_,
+                              need_decl, target_exprs)
+     tree result, fn, caller;
+     void *decl_map_;
+     int *need_decl;
+     void *target_exprs;
+{
+  splay_tree decl_map = (splay_tree)decl_map_;
+  varray_type *texps = (varray_type *)target_exprs;
+  tree var;
+  int aggregate_return_p;
+
+  /* Figure out whether or not FN returns an aggregate.  */
+  aggregate_return_p = IS_AGGR_TYPE (TREE_TYPE (result));
+  *need_decl = ! aggregate_return_p;
+
+  /* If FN returns an aggregate then the caller will always create the
+     temporary (using a TARGET_EXPR) and the call will be the
+     initializing expression for the TARGET_EXPR.  If we were just to
+     create a new VAR_DECL here, then the result of this function
+     would be copied (bitwise) into the variable initialized by the
+     TARGET_EXPR.  That's incorrect, so we must transform any
+     references to the RESULT into references to the target.  */
+  if (aggregate_return_p)
     {
-      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);
+      if (VARRAY_ACTIVE_SIZE (*texps) == 0)
+       abort ();
+      var = TREE_OPERAND (VARRAY_TOP_TREE (*texps), 0);
+      if (! same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (var),
+                                                      TREE_TYPE (result)))
+       abort ();
     }
+  /* Otherwise, make an appropriate copy.  */
+  else
+    var = copy_decl_for_inlining (result, fn, caller);
+
+  if (DECL_SAVED_FUNCTION_DATA (fn))
+    {
+      tree nrv = DECL_SAVED_FUNCTION_DATA (fn)->x_return_value;
+      if (nrv)
+       {
+         /* We have a named return value; copy the name and source
+            position so we can get reasonable debugging information, and
+            register the return variable as its equivalent.  */
+         DECL_NAME (var) = DECL_NAME (nrv);
+         DECL_SOURCE_FILE (var) = DECL_SOURCE_FILE (nrv);
+         DECL_SOURCE_LINE (var) = DECL_SOURCE_LINE (nrv);
+         DECL_ABSTRACT_ORIGIN (var) = DECL_ORIGIN (nrv);
+         splay_tree_insert (decl_map,
+                            (splay_tree_key) nrv,
+                            (splay_tree_value) var);
+       }
+    }
+
+  return var;
+}
+
+/* Record that we're about to start inlining FN, and return non-zero if
+   that's OK.  Used for lang_hooks.tree_inlining.start_inlining.  */
+
+int
+cp_start_inlining (fn)
+     tree fn;
+{
+  if (DECL_TEMPLATE_INSTANTIATION (fn))
+    return push_tinst_level (fn);
   else
-    /* We've already walked into this SAVE_EXPR, so we needn't do it
-       again.  */
-    *walk_subtrees = 0;
+    return 1;
+}
 
-  /* Replace this SAVE_EXPR with the copy.  */
-  *tp = (tree) n->value;
+/* Record that we're done inlining FN.  Used for
+   lang_hooks.tree_inlining.end_inlining.  */
+
+void
+cp_end_inlining (fn)
+     tree fn ATTRIBUTE_UNUSED;
+{
+  if (DECL_TEMPLATE_INSTANTIATION (fn))
+    pop_tinst_level ();
+}
+
+/* Initialize tree.c.  */
+
+void
+init_tree ()
+{
+  make_lang_type_fn = cp_make_lang_type;
+  lang_unsave = cp_unsave;
+  lang_statement_code_p = cp_statement_code_p;
+  lang_set_decl_assembler_name = mangle_decl;
+  list_hash_table = htab_create (31, list_hash, list_hash_eq, NULL);
+  ggc_add_root (&list_hash_table, 1, 
+               sizeof (list_hash_table),
+               mark_tree_hashtable);
 }
 
 /* Called via walk_tree.  If *TP points to a DECL_STMT for a local
@@ -2565,18 +2281,26 @@ mark_local_for_remap_r (tp, walk_subtrees, 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)))
-      || TREE_CODE (t) == LABEL_STMT)
+  
+  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 if (TREE_CODE (t) == CASE_LABEL)
+    decl = CASE_LABEL_DECL (t);
+  else
+    decl = NULL_TREE;
+
+  if (decl)
     {
-      tree decl;
       tree copy;
 
-      /* Figure out what's being declared.  */
-      decl = (TREE_CODE (t) == DECL_STMT
-             ? DECL_STMT_DECL (t) : LABEL_STMT_LABEL (t));
-      
       /* Make a copy.  */
       copy = copy_decl_for_inlining (decl, 
                                     DECL_CONTEXT (decl), 
@@ -2592,7 +2316,7 @@ mark_local_for_remap_r (tp, walk_subtrees, data)
 }
 
 /* Called via walk_tree when an expression is unsaved.  Using the
-   splay_tree pointed to by ST (which is really a `splay_tree *'),
+   splay_tree pointed to by ST (which is really a `splay_tree'),
    remaps all local declarations to appropriate replacements.  */
 
 static tree
@@ -2642,11 +2366,97 @@ cp_unsave (tp)
   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_tree (tp, mark_local_for_remap_r, st, NULL);
 
   /* Walk the tree again, copying, remapping, and unsaving.  */
-  walk_tree (tp, cp_unsave_r, st);
+  walk_tree (tp, cp_unsave_r, st, NULL);
 
   /* Clean up.  */
   splay_tree_delete (st);
 }
+
+/* Returns the kind of special function that DECL (a FUNCTION_DECL)
+   is.  Note that this sfk_none is zero, so this function can be used
+   as a predicate to test whether or not DECL is a special function.  */
+
+special_function_kind
+special_function_p (decl)
+     tree decl;
+{
+  /* Rather than doing all this stuff with magic names, we should
+     probably have a field of type `special_function_kind' in
+     DECL_LANG_SPECIFIC.  */
+  if (DECL_COPY_CONSTRUCTOR_P (decl))
+    return sfk_copy_constructor;
+  if (DECL_CONSTRUCTOR_P (decl))
+    return sfk_constructor;
+  if (DECL_OVERLOADED_OPERATOR_P (decl) == NOP_EXPR)
+    return sfk_assignment_operator;
+  if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl))
+    return sfk_destructor;
+  if (DECL_COMPLETE_DESTRUCTOR_P (decl))
+    return sfk_complete_destructor;
+  if (DECL_BASE_DESTRUCTOR_P (decl))
+    return sfk_base_destructor;
+  if (DECL_DELETING_DESTRUCTOR_P (decl))
+    return sfk_deleting_destructor;
+  if (DECL_CONV_FN_P (decl))
+    return sfk_conversion;
+
+  return sfk_none;
+}
+
+/* Returns non-zero if TYPE is a character type, including wchar_t.  */
+
+int
+char_type_p (type)
+     tree type;
+{
+  return (same_type_p (type, char_type_node)
+         || same_type_p (type, unsigned_char_type_node)
+         || same_type_p (type, signed_char_type_node)
+         || same_type_p (type, wchar_type_node));
+}
+
+/* Returns the kind of linkage associated with the indicated DECL.  Th
+   value returned is as specified by the language standard; it is
+   independent of implementation details regarding template
+   instantiation, etc.  For example, it is possible that a declaration
+   to which this function assigns external linkage would not show up
+   as a global symbol when you run `nm' on the resulting object file.  */
+
+linkage_kind
+decl_linkage (decl)
+     tree decl;
+{
+  /* This function doesn't attempt to calculate the linkage from first
+     principles as given in [basic.link].  Instead, it makes use of
+     the fact that we have already set TREE_PUBLIC appropriately, and
+     then handles a few special cases.  Ideally, we would calculate
+     linkage first, and then transform that into a concrete
+     implementation.  */
+
+  /* Things that don't have names have no linkage.  */
+  if (!DECL_NAME (decl))
+    return lk_none;
+
+  /* Things that are TREE_PUBLIC have external linkage.  */
+  if (TREE_PUBLIC (decl))
+    return lk_external;
+
+  /* Some things that are not TREE_PUBLIC have external linkage, too.
+     For example, on targets that don't have weak symbols, we make all
+     template instantiations have internal linkage (in the object
+     file), but the symbols should still be treated as having external
+     linkage from the point of view of the language.  */
+  if (DECL_LANG_SPECIFIC (decl) && DECL_COMDAT (decl))
+    return lk_external;
+
+  /* Things in local scope do not have linkage, if they don't have
+     TREE_PUBLIC set.  */
+  if (decl_function_context (decl))
+    return lk_none;
+
+  /* Everything else has internal linkage.  */
+  return lk_internal;
+}