OSDN Git Service

Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>
[pf3gnuchains/gcc-fork.git] / gcc / cp / search.c
index 208cc0a..8b15764 100644 (file)
@@ -1,6 +1,6 @@
 /* Breadth-first and depth-first routines for
    searching multiple-inheritance lattice for GNU C++.
-   Copyright (C) 1987, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+   Copyright (C) 1987, 89, 92-97, 1998 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
@@ -20,30 +20,32 @@ along with GNU CC; see the file COPYING.  If not, write to
 the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
-/* High-level class interface. */
+/* High-level class interface.  */
 
 #include "config.h"
+#include "system.h"
 #include "tree.h"
-#include <stdio.h>
 #include "cp-tree.h"
 #include "obstack.h"
 #include "flags.h"
 #include "rtl.h"
 #include "output.h"
+#include "toplev.h"
 
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
 
-void init_search ();
 extern struct obstack *current_obstack;
 extern tree abort_fndecl;
 
 #include "stack.h"
 
 /* Obstack used for remembering decision points of breadth-first.  */
+
 static struct obstack search_obstack;
 
 /* Methods for pushing and popping objects to and from obstacks.  */
+
 struct stack_level *
 push_stack_level (obstack, tp, size)
      struct obstack *obstack;
@@ -74,19 +76,64 @@ pop_stack_level (stack)
 #define search_level stack_level
 static struct search_level *search_stack;
 
-static tree lookup_field_1 ();
-static int lookup_fnfields_1 ();
-static void dfs_walk ();
-static int markedp ();
-static void dfs_unmark ();
-static void dfs_init_vbase_pointers ();
+static tree get_abstract_virtuals_1 PROTO((tree, int, tree));
+static tree get_vbase_1 PROTO((tree, tree, unsigned int *));
+static tree convert_pointer_to_vbase PROTO((tree, tree));
+static tree lookup_field_1 PROTO((tree, tree));
+static tree convert_pointer_to_single_level PROTO((tree, tree));
+static int lookup_fnfields_1 PROTO((tree, tree));
+static int lookup_fnfields_here PROTO((tree, tree));
+static int is_subobject_of_p PROTO((tree, tree));
+static int hides PROTO((tree, tree));
+static tree virtual_context PROTO((tree, tree, tree));
+static tree get_template_base_recursive
+       PROTO((tree, tree, tree, int));
+static void dfs_walk PROTO((tree, void (*) (tree), int (*) (tree)));
+static void dfs_check_overlap PROTO((tree));
+static int dfs_no_overlap_yet PROTO((tree));
+static void envelope_add_decl PROTO((tree, tree, tree *));
+static int get_base_distance_recursive
+       PROTO((tree, int, int, int, int *, tree *, tree,
+              int, int *, int, int));
+static void expand_upcast_fixups 
+       PROTO((tree, tree, tree, tree, tree, tree, tree *));
+static void fixup_virtual_upcast_offsets
+       PROTO((tree, tree, int, int, tree, tree, tree, tree,
+              tree *));
+static int markedp PROTO((tree));
+static int unmarkedp PROTO((tree));
+static int marked_vtable_pathp PROTO((tree));
+static int unmarked_vtable_pathp PROTO((tree));
+static int marked_new_vtablep PROTO((tree));
+static int unmarked_new_vtablep PROTO((tree));
+static int dfs_debug_unmarkedp PROTO((tree));
+static void dfs_debug_mark PROTO((tree));
+static void dfs_find_vbases PROTO((tree));
+static void dfs_clear_vbase_slots PROTO((tree));
+static void dfs_unmark PROTO((tree));
+static void dfs_init_vbase_pointers PROTO((tree));
+static void dfs_get_vbase_types PROTO((tree));
+static void dfs_pushdecls PROTO((tree));
+static void dfs_compress_decls PROTO((tree));
+static void dfs_unuse_fields PROTO((tree));
+static tree add_conversions PROTO((tree));
+static tree get_virtuals_named_this PROTO((tree));
+static tree get_virtual_destructor PROTO((tree));
+static int tree_has_any_destructor_p PROTO((tree));
+static int covariant_return_p PROTO((tree, tree));
+static struct search_level *push_search_level
+       PROTO((struct stack_level *, struct obstack *));
+static struct search_level *pop_search_level
+       PROTO((struct stack_level *));
+static tree breadth_first_search
+       PROTO((tree, tree (*) (tree), int (*) (tree)));
 
 static tree vbase_types;
-static tree vbase_decl, vbase_decl_ptr;
-static tree vbase_decl_ptr_intermediate;
+static tree vbase_decl_ptr_intermediate, vbase_decl_ptr;
 static tree vbase_init_result;
 
 /* Allocate a level of searching.  */
+
 static struct search_level *
 push_search_level (stack, obstack)
      struct stack_level *stack;
@@ -99,6 +146,7 @@ push_search_level (stack, obstack)
 }
 
 /* Discard a level of search allocation.  */
+
 static struct search_level *
 pop_search_level (obstack)
      struct stack_level *obstack;
@@ -108,285 +156,32 @@ pop_search_level (obstack)
   return stack;
 }
 \f
-/* Search memoization.  */
-struct type_level
-{
-  struct stack_level base;
-
-  /* First object allocated in obstack of entries.  */
-  char *entries;
-
-  /* Number of types memoized in this context.  */
-  int len;
-
-  /* Type being memoized; save this if we are saving
-     memoized contexts.  */
-  tree type;
-};
-
-/* Obstack used for memoizing member and member function lookup.  */
-
-static struct obstack type_obstack, type_obstack_entries;
-static struct type_level *type_stack;
 static tree _vptr_name;
 
-/* Make things that look like tree nodes, but allocate them
-   on type_obstack_entries.  */
-static int my_tree_node_counter;
-static tree my_tree_cons (), my_build_string ();
-
-extern int flag_memoize_lookups, flag_save_memoized_contexts;
-
 /* Variables for gathering statistics.  */
-static int my_memoized_entry_counter;
-static int memoized_fast_finds[2], memoized_adds[2], memoized_fast_rejects[2];
-static int memoized_fields_searched[2];
+#ifdef GATHER_STATISTICS
 static int n_fields_searched;
 static int n_calls_lookup_field, n_calls_lookup_field_1;
 static int n_calls_lookup_fnfields, n_calls_lookup_fnfields_1;
 static int n_calls_get_base_type;
 static int n_outer_fields_searched;
 static int n_contexts_saved;
-
-/* Local variables to help save memoization contexts.  */
-static tree prev_type_memoized;
-static struct type_level *prev_type_stack;
+#endif /* GATHER_STATISTICS */
 
 /* This list is used by push_class_decls to know what decls need to
    be pushed into class scope.  */
 static tree closed_envelopes = NULL_TREE;
-
-/* Allocate a level of type memoization context.  */
-static struct type_level *
-push_type_level (stack, obstack)
-     struct stack_level *stack;
-     struct obstack *obstack;
-{
-  struct type_level tem;
-
-  tem.base.prev = stack;
-
-  obstack_finish (&type_obstack_entries);
-  tem.entries = (char *) obstack_base (&type_obstack_entries);
-  tem.len = 0;
-  tem.type = NULL_TREE;
-
-  return (struct type_level *)push_stack_level (obstack, (char *)&tem, sizeof (tem));
-}
-
-/* Discard a level of type memoization context.  */
-
-static struct type_level *
-pop_type_level (stack)
-     struct type_level *stack;
-{
-  obstack_free (&type_obstack_entries, stack->entries);
-  return (struct type_level *)pop_stack_level ((struct stack_level *)stack);
-}
-
-/* Make something that looks like a TREE_LIST, but
-   do it on the type_obstack_entries obstack.  */
-static tree
-my_tree_cons (purpose, value, chain)
-     tree purpose, value, chain;
-{
-  tree p = (tree)obstack_alloc (&type_obstack_entries, sizeof (struct tree_list));
-  ++my_tree_node_counter;
-  TREE_TYPE (p) = NULL_TREE;
-  ((HOST_WIDE_INT *)p)[3] = 0;
-  TREE_SET_CODE (p, TREE_LIST);
-  TREE_PURPOSE (p) = purpose;
-  TREE_VALUE (p) = value;
-  TREE_CHAIN (p) = chain;
-  return p;
-}
-
-static tree
-my_build_string (str)
-     char *str;
-{
-  tree p = (tree)obstack_alloc (&type_obstack_entries, sizeof (struct tree_string));
-  ++my_tree_node_counter;
-  TREE_TYPE (p) = 0;
-  ((int *)p)[3] = 0;
-  TREE_SET_CODE (p, STRING_CST);
-  TREE_STRING_POINTER (p) = str;
-  TREE_STRING_LENGTH (p) = strlen (str);
-  return p;
-}
-\f
-/* Memoizing machinery to make searches for multiple inheritance
-   reasonably efficient.  */
-#define MEMOIZE_HASHSIZE 8
-typedef struct memoized_entry
-{
-  struct memoized_entry *chain;
-  int uid;
-  tree data_members[MEMOIZE_HASHSIZE];
-  tree function_members[MEMOIZE_HASHSIZE];
-} *ME;
-
-#define MEMOIZED_CHAIN(ENTRY) (((ME)ENTRY)->chain)
-#define MEMOIZED_UID(ENTRY) (((ME)ENTRY)->uid)
-#define MEMOIZED_FIELDS(ENTRY,INDEX) (((ME)ENTRY)->data_members[INDEX])
-#define MEMOIZED_FNFIELDS(ENTRY,INDEX) (((ME)ENTRY)->function_members[INDEX])
-/* The following is probably a lousy hash function.  */
-#define MEMOIZED_HASH_FN(NODE) (((long)(NODE)>>4)&(MEMOIZE_HASHSIZE - 1))
-
-static struct memoized_entry *
-my_new_memoized_entry (chain)
-     struct memoized_entry *chain;
-{
-  struct memoized_entry *p =
-    (struct memoized_entry *)obstack_alloc (&type_obstack_entries,
-                                           sizeof (struct memoized_entry));
-  bzero ((char *) p, sizeof (struct memoized_entry));
-  MEMOIZED_CHAIN (p) = chain;
-  MEMOIZED_UID (p) = ++my_memoized_entry_counter;
-  return p;
-}
-
-/* Make an entry in the memoized table for type TYPE
-   that the entry for NAME is FIELD.  */
-
-tree
-make_memoized_table_entry (type, name, function_p)
-     tree type, name;
-     int function_p;
-{
-  int index = MEMOIZED_HASH_FN (name);
-  tree entry, *prev_entry;
-
-  memoized_adds[function_p] += 1;
-  if (CLASSTYPE_MTABLE_ENTRY (type) == 0)
-    {
-      obstack_ptr_grow (&type_obstack, type);
-      obstack_blank (&type_obstack, sizeof (struct memoized_entry *));
-      CLASSTYPE_MTABLE_ENTRY (type) = (char *)my_new_memoized_entry ((struct memoized_entry *)0);
-      type_stack->len++;
-      if (type_stack->len * 2 >= type_stack->base.limit)
-       my_friendly_abort (88);
-    }
-  if (function_p)
-    prev_entry = &MEMOIZED_FNFIELDS (CLASSTYPE_MTABLE_ENTRY (type), index);
-  else
-    prev_entry = &MEMOIZED_FIELDS (CLASSTYPE_MTABLE_ENTRY (type), index);
-
-  entry = my_tree_cons (name, NULL_TREE, *prev_entry);
-  *prev_entry = entry;
-
-  /* Don't know the error message to give yet.  */
-  TREE_TYPE (entry) = error_mark_node;
-
-  return entry;
-}
-
-/* When a new function or class context is entered, we build
-   a table of types which have been searched for members.
-   The table is an array (obstack) of types.  When a type is
-   entered into the obstack, its CLASSTYPE_MTABLE_ENTRY
-   field is set to point to a new record, of type struct memoized_entry.
-
-   A non-NULL TREE_TYPE of the entry contains an access control error message.
-
-   The slots for the data members are arrays of tree nodes.
-   These tree nodes are lists, with the TREE_PURPOSE
-   of this list the known member name, and the TREE_VALUE
-   as the FIELD_DECL for the member.
-
-   For member functions, the TREE_PURPOSE is again the
-   name of the member functions for that class,
-   and the TREE_VALUE of the list is a pairs
-   whose TREE_PURPOSE is a member functions of this name,
-   and whose TREE_VALUE is a list of known argument lists this
-   member function has been called with.  The TREE_TYPE of the pair,
-   if non-NULL, is an error message to print.  */
-
-/* Tell search machinery that we are entering a new context, and
-   to update tables appropriately.
-
-   TYPE is the type of the context we are entering, which can
-   be NULL_TREE if we are not in a class's scope.
-
-   USE_OLD, if nonzero tries to use previous context.  */
-void
-push_memoized_context (type, use_old)
-     tree type;
-     int use_old;
-{
-  int len;
-  tree *tem;
-
-  if (prev_type_stack)
-    {
-      if (use_old && prev_type_memoized == type)
-       {
-#ifdef GATHER_STATISTICS
-         n_contexts_saved++;
-#endif
-         type_stack = prev_type_stack;
-         prev_type_stack = 0;
-
-         tem = &type_stack->base.first[0];
-         len = type_stack->len;
-         while (len--)
-           CLASSTYPE_MTABLE_ENTRY (tem[len*2]) = (char *)tem[len*2+1];
-         return;
-       }
-      /* Otherwise, need to pop old stack here.  */
-      type_stack = pop_type_level (prev_type_stack);
-      prev_type_memoized = 0;
-      prev_type_stack = 0;
-    }
-
-  type_stack = push_type_level ((struct stack_level *)type_stack,
-                               &type_obstack);
-  type_stack->type = type;
-}
-
-/* Tell search machinery that we have left a context.
-   We do not currently save these contexts for later use.
-   If we wanted to, we could not use pop_search_level, since
-   poping that level allows the data we have collected to
-   be clobbered; a stack of obstacks would be needed.  */
-void
-pop_memoized_context (use_old)
-     int use_old;
-{
-  int len;
-  tree *tem = &type_stack->base.first[0];
-
-  if (! flag_save_memoized_contexts)
-    use_old = 0;
-  else if (use_old)
-    {
-      len = type_stack->len;
-      while (len--)
-       tem[len*2+1] = (tree)CLASSTYPE_MTABLE_ENTRY (tem[len*2]);
-
-      prev_type_stack = type_stack;
-      prev_type_memoized = type_stack->type;
-    }
-
-  if (flag_memoize_lookups)
-    {
-      len = type_stack->len;
-      while (len--)
-       CLASSTYPE_MTABLE_ENTRY (tem[len*2])
-         = (char *)MEMOIZED_CHAIN (CLASSTYPE_MTABLE_ENTRY (tem[len*2]));
-    }
-  if (! use_old)
-    type_stack = pop_type_level (type_stack);
-  else
-    type_stack = (struct type_level *)type_stack->base.prev;
-}
 \f
 /* Get a virtual binfo that is found inside BINFO's hierarchy that is
    the same type as the type given in PARENT.  To be optimal, we want
    the first one that is found by going through the least number of
-   virtual bases.  DEPTH should be NULL_PTR.  */
+   virtual bases.
+
+   This uses a clever algorithm that updates *depth when we find the vbase,
+   and cuts off other paths of search when they reach that depth.  */
+
 static tree
-get_vbase (parent, binfo, depth)
+get_vbase_1 (parent, binfo, depth)
      tree parent, binfo;
      unsigned int *depth;
 {
@@ -394,12 +189,6 @@ get_vbase (parent, binfo, depth)
   int i, n_baselinks;
   tree rval = NULL_TREE;
 
-  if (depth == 0)
-    {
-      unsigned int d = (unsigned int)-1;
-      return get_vbase (parent, binfo, &d);
-    }
-
   if (BINFO_TYPE (binfo) == parent && TREE_VIA_VIRTUAL (binfo))
     {
       *depth = 0;
@@ -420,7 +209,7 @@ get_vbase (parent, binfo, depth)
       if (*depth == 0)
        break;
 
-      nrval = get_vbase (parent, base_binfo, depth);
+      nrval = get_vbase_1 (parent, base_binfo, depth);
       if (nrval)
        rval = nrval;
     }
@@ -428,46 +217,31 @@ get_vbase (parent, binfo, depth)
   return rval;
 }
 
+/* Return the shortest path to vbase PARENT within BINFO, ignoring
+   access and ambiguity.  */
+
+tree
+get_vbase (parent, binfo)
+     tree parent;
+     tree binfo;
+{
+  unsigned int d = (unsigned int)-1;
+  return get_vbase_1 (parent, binfo, &d);
+}
+
 /* Convert EXPR to a virtual base class of type TYPE.  We know that
    EXPR is a non-null POINTER_TYPE to RECORD_TYPE.  We also know that
    the type of what expr points to has a virtual base of type TYPE.  */
-tree
+
+static tree
 convert_pointer_to_vbase (type, expr)
      tree type;
      tree expr;
 {
-  tree vb = get_vbase (type, TYPE_BINFO (TREE_TYPE (TREE_TYPE (expr))), NULL_PTR);
+  tree vb = get_vbase (type, TYPE_BINFO (TREE_TYPE (TREE_TYPE (expr))));
   return convert_pointer_to_real (vb, expr);
 }
 
-/* This is the newer recursive depth first search routine. */
-#if 0                          /* unused */
-/* Return non-zero if PARENT is directly derived from TYPE.  By directly
-   we mean it's only one step up the inheritance lattice.  We check this
-   by walking horizontally across the types that TYPE directly inherits
-   from, to see if PARENT is among them.  This is used by get_binfo and
-   by compute_access.  */
-static int
-immediately_derived (parent, type)
-     tree parent, type;
-{
-  if (TYPE_BINFO (type))
-    {
-      tree binfos = BINFO_BASETYPES (TYPE_BINFO (type));
-      int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-
-      for (i = 0; i < n_baselinks; i++)
-       {
-         tree base_binfo = TREE_VEC_ELT (binfos, i);
-
-         if (parent == BINFO_TYPE (base_binfo))
-           return 1;
-       }
-    }
-  return 0;
-}
-#endif
-
 /* Check whether the type given in BINFO is derived from PARENT.  If
    it isn't, return 0.  If it is, but the derivation is MI-ambiguous
    AND protect != 0, emit an error message and return error_mark_node.
@@ -484,7 +258,7 @@ get_binfo (parent, binfo, protect)
      register tree parent, binfo;
      int protect;
 {
-  tree type;
+  tree type = NULL_TREE;
   int dist;
   tree rval = NULL_TREE;
   
@@ -519,51 +293,65 @@ get_binfo (parent, binfo, protect)
 }
 
 /* This is the newer depth first get_base_distance routine.  */
+
 static int
-get_base_distance_recursive (binfo, depth, is_private, basetype_path, rval,
-                            rval_private_ptr, new_binfo_ptr, parent, path_ptr,
-                            protect, via_virtual_ptr, via_virtual)
-     tree binfo, basetype_path, *new_binfo_ptr, parent, *path_ptr;
-     int *rval_private_ptr, depth, is_private, rval, protect, *via_virtual_ptr,
-       via_virtual;
+get_base_distance_recursive (binfo, depth, is_private, rval,
+                            rval_private_ptr, new_binfo_ptr, parent,
+                            protect, via_virtual_ptr, via_virtual,
+                            current_scope_in_chain)
+     tree binfo;
+     int depth, is_private, rval;
+     int *rval_private_ptr;
+     tree *new_binfo_ptr, parent;
+     int protect, *via_virtual_ptr, via_virtual;
+     int current_scope_in_chain;
 {
   tree binfos;
   int i, n_baselinks;
 
+  if (protect
+      && !current_scope_in_chain
+      && is_friend (BINFO_TYPE (binfo), current_scope ()))
+    current_scope_in_chain = 1;
+
   if (BINFO_TYPE (binfo) == parent || binfo == parent)
     {
+      int better = 0;
+
       if (rval == -1)
+       /* This is the first time we've found parent.  */
+       better = 1;
+      else if (tree_int_cst_equal (BINFO_OFFSET (*new_binfo_ptr),
+                                  BINFO_OFFSET (binfo))
+              && *via_virtual_ptr && via_virtual)
+       {
+         /* A new path to the same vbase.  If this one has better
+            access or is shorter, take it.  */
+
+         if (protect)
+           better = *rval_private_ptr - is_private;
+         if (better == 0)
+           better = rval - depth;
+       }
+      else
+       {
+         /* Ambiguous base class.  */
+         rval = depth = -2;
+
+         /* If we get an ambiguity between virtual and non-virtual base
+            class, return the non-virtual in case we are ignoring
+            ambiguity.  */
+         better = *via_virtual_ptr - via_virtual;
+       }
+
+      if (better > 0)
        {
          rval = depth;
          *rval_private_ptr = is_private;
          *new_binfo_ptr = binfo;
          *via_virtual_ptr = via_virtual;
        }
-      else
-       {
-         int same_object = (tree_int_cst_equal (BINFO_OFFSET (*new_binfo_ptr),
-                                                BINFO_OFFSET (binfo))
-                            && *via_virtual_ptr && via_virtual);
-                            
-         if (*via_virtual_ptr && via_virtual==0)
-           {
-             *rval_private_ptr = is_private;
-             *new_binfo_ptr = binfo;
-             *via_virtual_ptr = via_virtual;
-           }
-         else if (same_object)
-           {
-             if (*rval_private_ptr && ! is_private)
-               {
-                 *rval_private_ptr = is_private;
-                 *new_binfo_ptr = binfo;
-                 *via_virtual_ptr = via_virtual;
-               }
-             return rval;
-           }
 
-         rval = -2;
-       }
       return rval;
     }
 
@@ -576,40 +364,26 @@ get_base_distance_recursive (binfo, depth, is_private, basetype_path, rval,
     {
       tree base_binfo = TREE_VEC_ELT (binfos, i);
 
-      /* Find any specific instance of a virtual base, when searching with
-        a binfo... */
-      if (BINFO_MARKED (base_binfo) == 0 || TREE_CODE (parent) == TREE_VEC)
-       {
-         int via_private
-           = (protect
-              && (is_private
-                  || (!TREE_VIA_PUBLIC (base_binfo)
-                      && !is_friend (BINFO_TYPE (binfo), current_scope ()))));
-         int this_virtual = via_virtual || TREE_VIA_VIRTUAL (base_binfo);
-         int was;
-
-         /* When searching for a non-virtual, we cannot mark
-            virtually found binfos. */
-         if (! this_virtual)
-           SET_BINFO_MARKED (base_binfo);
-
-#define WATCH_VALUES(rval, via_private) (rval == -1 ? 3 : via_private)
-
-         was = WATCH_VALUES (rval, *via_virtual_ptr);
-         rval = get_base_distance_recursive (base_binfo, depth, via_private,
-                                             binfo, rval, rval_private_ptr,
-                                             new_binfo_ptr, parent, path_ptr,
-                                             protect, via_virtual_ptr,
-                                             this_virtual);
-         /* watch for updates; only update if path is good. */
-         if (path_ptr && WATCH_VALUES (rval, *via_virtual_ptr) != was)
-           BINFO_INHERITANCE_CHAIN (base_binfo) = binfo;
-         if (rval == -2 && *via_virtual_ptr == 0)
-           return rval;
+      int via_private
+       = (protect
+          && (is_private
+              || (!TREE_VIA_PUBLIC (base_binfo)
+                  && !(TREE_VIA_PROTECTED (base_binfo)
+                       && current_scope_in_chain)
+                  && !is_friend (BINFO_TYPE (binfo), current_scope ()))));
+      int this_virtual = via_virtual || TREE_VIA_VIRTUAL (base_binfo);
 
-#undef WATCH_VALUES
+      rval = get_base_distance_recursive (base_binfo, depth, via_private,
+                                         rval, rval_private_ptr,
+                                         new_binfo_ptr, parent,
+                                         protect, via_virtual_ptr,
+                                         this_virtual,
+                                         current_scope_in_chain);
 
-       }
+      /* If we've found a non-virtual, ambiguous base class, we don't need
+        to keep searching.  */
+      if (rval == -2 && *via_virtual_ptr == 0)
+       return rval;
     }
 
   return rval;
@@ -618,7 +392,7 @@ get_base_distance_recursive (binfo, depth, is_private, basetype_path, rval,
 /* Return the number of levels between type PARENT and the type given
    in BINFO, following the leftmost path to PARENT not found along a
    virtual path, if there are no real PARENTs (all come from virtual
-   base classes), then follow the leftmost path to PARENT.
+   base classes), then follow the shortest public path to PARENT.
 
    Return -1 if TYPE is not derived from PARENT.
    Return -2 if PARENT is an ambiguous base class of TYPE, and PROTECT is
@@ -642,23 +416,27 @@ get_base_distance (parent, binfo, protect, path_ptr)
 {
   int rval;
   int rval_private = 0;
-  tree type;
+  tree type = NULL_TREE;
   tree new_binfo = NULL_TREE;
   int via_virtual;
   int watch_access = protect;
 
+  /* Should we be completing types here?  */
   if (TREE_CODE (parent) != TREE_VEC)
-    parent = TYPE_MAIN_VARIANT (parent);
+    parent = complete_type (TYPE_MAIN_VARIANT (parent));
+  else
+    complete_type (TREE_TYPE (parent));
 
   if (TREE_CODE (binfo) == TREE_VEC)
     type = BINFO_TYPE (binfo);
   else if (IS_AGGR_TYPE_CODE (TREE_CODE (binfo)))
     {
-      type = binfo;
+      type = complete_type (binfo);
       binfo = TYPE_BINFO (type);
 
       if (path_ptr)
-       BINFO_INHERITANCE_CHAIN (binfo) = NULL_TREE;
+       my_friendly_assert (BINFO_INHERITANCE_CHAIN (binfo) == NULL_TREE,
+                           980827);
     }
   else
     my_friendly_abort (92);
@@ -675,11 +453,10 @@ get_base_distance (parent, binfo, protect, path_ptr)
   if (path_ptr)
     watch_access = 1;
 
-  rval = get_base_distance_recursive (binfo, 0, 0, NULL_TREE, -1,
+  rval = get_base_distance_recursive (binfo, 0, 0, -1,
                                      &rval_private, &new_binfo, parent,
-                                     path_ptr, watch_access, &via_virtual, 0);
-
-  dfs_walk (binfo, dfs_unmark, markedp);
+                                     watch_access, &via_virtual, 0,
+                                     0);
 
   /* Access restrictions don't count if we found an ambiguous basetype.  */
   if (rval == -2 && protect >= 0)
@@ -688,12 +465,14 @@ get_base_distance (parent, binfo, protect, path_ptr)
   if (rval && protect && rval_private)
     return -3;
 
-  /* find real virtual base classes. */
+  /* If they gave us the real vbase binfo, which isn't in the main binfo
+     tree, deal with it.  This happens when we are called from
+     expand_upcast_fixups.  */
   if (rval == -1 && TREE_CODE (parent) == TREE_VEC
       && parent == binfo_member (BINFO_TYPE (parent),
                                 CLASSTYPE_VBASECLASSES (type)))
     {
-      BINFO_INHERITANCE_CHAIN (parent) = binfo;
+      my_friendly_assert (BINFO_INHERITANCE_CHAIN (parent) == binfo, 980827);
       new_binfo = parent;
       rval = 1;
     }
@@ -711,20 +490,32 @@ get_base_distance (parent, binfo, protect, path_ptr)
 /* Do a 1-level search for NAME as a member of TYPE.  The caller must
    figure out whether it can access this field.  (Since it is only one
    level, this is reasonable.)  */
+
 static tree
 lookup_field_1 (type, name)
      tree type, name;
 {
-  register tree field = TYPE_FIELDS (type);
+  register tree field;
+
+  if (TREE_CODE (type) == TEMPLATE_TYPE_PARM
+      || TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM)
+    /* The TYPE_FIELDS of a TEMPLATE_TYPE_PARM are not fields at all;
+       instead TYPE_FIELDS is the TEMPLATE_PARM_INDEX.  (Miraculously,
+       the code often worked even when we treated the index as a list
+       of fields!)  */
+    return NULL_TREE;
+
+  field = TYPE_FIELDS (type);
 
 #ifdef GATHER_STATISTICS
   n_calls_lookup_field_1++;
-#endif
+#endif /* GATHER_STATISTICS */
   while (field)
     {
 #ifdef GATHER_STATISTICS
       n_fields_searched++;
-#endif
+#endif /* GATHER_STATISTICS */
+      my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (field)) == 'd', 0);
       if (DECL_NAME (field) == NULL_TREE
          && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
        {
@@ -732,7 +523,14 @@ lookup_field_1 (type, name)
          if (temp)
            return temp;
        }
-      if (DECL_NAME (field) == name)
+      if (TREE_CODE (field) == USING_DECL)
+       /* For now, we're just treating member using declarations as
+          old ARM-style access declarations.  Thus, there's no reason
+          to return a USING_DECL, and the rest of the compiler can't
+          handle it.  Once the class is defined, these are purged
+          from TYPE_FIELDS anyhow; see handle_using_decl.  */
+       ;
+      else if (DECL_NAME (field) == name)
        {
          if ((TREE_CODE(field) == VAR_DECL || TREE_CODE(field) == CONST_DECL)
              && DECL_ASSEMBLER_NAME (field) != NULL)
@@ -754,17 +552,17 @@ lookup_field_1 (type, name)
 
 /* There are a number of cases we need to be aware of here:
                         current_class_type     current_function_decl
-   * global                    NULL                    NULL
-   * fn-local                  NULL                    SET
-   * class-local               SET                     NULL
-   * class->fn                 SET                     SET
-   * fn->class                 SET                     SET
+     global                    NULL                    NULL
+     fn-local                  NULL                    SET
+     class-local               SET                     NULL
+     class->fn                 SET                     SET
+     fn->class                 SET                     SET
 
    Those last two make life interesting.  If we're in a function which is
    itself inside a class, we need decls to go into the fn's decls (our
    second case below).  But if we're in a class and the class itself is
    inside a function, we need decls to go into the decls for the class.  To
-   achieve this last goal, we must see if, when both current_class_decl and
+   achieve this last goal, we must see if, when both current_class_ptr and
    current_function_decl are set, the class was declared inside that
    function.  If so, we know to put the decls into the class's scope.  */
 
@@ -801,7 +599,7 @@ current_scope ()
    lexical scope because it is protected.
 
    access_private_node means that the field cannot be accessed by the current
-   lexical scope because it is private. */
+   lexical scope because it is private.  */
 
 #if 0
 #define PUBLIC_RETURN return (DECL_PUBLIC (field) = 1), access_public_node
@@ -831,9 +629,9 @@ compute_access (basetype_path, field)
   /* Replaces static decl above.  */
   tree previous_scope;
 #endif
-  int static_mem =
-    ((TREE_CODE (field) == FUNCTION_DECL && DECL_STATIC_FUNCTION_P (field))
-     || (TREE_CODE (field) != FUNCTION_DECL && TREE_STATIC (field)));
+  int static_mem
+    ((TREE_CODE (field) == FUNCTION_DECL && DECL_STATIC_FUNCTION_P (field))
+       || (TREE_CODE (field) != FUNCTION_DECL && TREE_STATIC (field)));
 
   if (! flag_access_control)
     return access_public_node;
@@ -861,17 +659,15 @@ compute_access (basetype_path, field)
     return access_public_node;
 
   previous_scope = current_scope ();
-  
-  context = DECL_CLASS_CONTEXT (field);
-  if (context == NULL_TREE)
-    context = DECL_CONTEXT (field);
+
+  context = DECL_REAL_CONTEXT (field);
 
   /* Fields coming from nested anonymous unions have their DECL_CLASS_CONTEXT
      slot set to the union type rather than the record type containing
-     the anonymous union.  In this case, DECL_FIELD_CONTEXT is correct.  */
-  if (context && TREE_CODE (context) == UNION_TYPE
-      && ANON_AGGRNAME_P (TYPE_IDENTIFIER (context)))
-    context = DECL_FIELD_CONTEXT (field);
+     the anonymous union.  */
+  if (context && ANON_UNION_TYPE_P (context)
+      && TREE_CODE (field) == FIELD_DECL)
+    context = TYPE_CONTEXT (context);
 
   /* Virtual function tables are never private.  But we should know that
      we are looking for this, and not even try to hide it.  */
@@ -898,8 +694,8 @@ compute_access (basetype_path, field)
       else if (TREE_PROTECTED (field))
        {
          if (current_class_type
-             && static_mem
-             && ACCESSIBLY_DERIVED_FROM_P (context, current_class_type))
+             && (static_mem || DECL_CONSTRUCTOR_P (field))
+             && ACCESSIBLY_DERIVED_FROM_P (context, current_class_type))
            PUBLIC_RETURN;
          else
            PROTECTED_RETURN;
@@ -955,7 +751,6 @@ compute_access (basetype_path, field)
       else
        break;
     }
-  reverse_path (basetype_path);
 
   /* No special visibilities apply.  Use normal rules.  */
 
@@ -993,6 +788,7 @@ compute_access (basetype_path, field)
    found as a base class and sub-object of the object denoted by
    BINFO.  This routine relies upon binfos not being shared, except
    for binfos for virtual bases.  */
+
 static int
 is_subobject_of_p (parent, binfo)
      tree parent, binfo;
@@ -1019,7 +815,8 @@ is_subobject_of_p (parent, binfo)
    correspond to ANSI working paper Sept 17, 1992 10p4.  The two
    binfos given are the binfos corresponding to the particular places
    the FIELD_DECLs are found.  This routine relies upon binfos not
-   being shared, except for virtual bases. */
+   being shared, except for virtual bases.  */
+
 static int
 hides (hider_binfo, hidee_binfo)
      tree hider_binfo, hidee_binfo;
@@ -1029,29 +826,31 @@ hides (hider_binfo, hidee_binfo)
      part is always true is the second part is true.
 
      When hider and hidee are the same (two ways to get to the exact
-     same member) we consider either one as hiding the other. */
+     same member) we consider either one as hiding the other.  */
   return is_subobject_of_p (hidee_binfo, hider_binfo);
 }
 
 /* Very similar to lookup_fnfields_1 but it ensures that at least one
    function was declared inside the class given by TYPE.  It really should
    only return functions that match the given TYPE.  */
+
 static int
 lookup_fnfields_here (type, name)
      tree type, name;
 {
-  int index = lookup_fnfields_1 (type, name);
+  int idx = lookup_fnfields_1 (type, name);
   tree fndecls;
 
-  if (index <= 0)
-    return index;
-  fndecls = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), index);
+  /* ctors and dtors are always only in the right class.  */
+  if (idx <= 1)
+    return idx;
+  fndecls = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx);
   while (fndecls)
     {
-      if (TYPE_MAIN_VARIANT (DECL_CLASS_CONTEXT (fndecls))
+      if (TYPE_MAIN_VARIANT (DECL_CLASS_CONTEXT (OVL_CURRENT (fndecls)))
          == TYPE_MAIN_VARIANT (type))
-       return index;
-      fndecls = TREE_CHAIN (fndecls);
+       return idx;
+      fndecls = OVL_CHAIN (fndecls);
     }
   return -1;
 }
@@ -1064,14 +863,15 @@ lookup_fnfields_here (type, name)
    It was not clear what should happen if WANT_TYPE is set, and an
    ambiguity is found.  At least one use (lookup_name) to not see
    the error.  */
+
 tree
 lookup_field (xbasetype, name, protect, want_type)
      register tree xbasetype, name;
      int protect, want_type;
 {
   int head = 0, tail = 0;
-  tree rval, rval_binfo = NULL_TREE, rval_binfo_h;
-  tree type, basetype_chain, basetype_path;
+  tree rval, rval_binfo = NULL_TREE, rval_binfo_h = NULL_TREE;
+  tree type = NULL_TREE, basetype_chain, basetype_path = NULL_TREE;
   tree this_v = access_default_node;
   tree entry, binfo, binfo_h;
   tree own_access = access_default_node;
@@ -1086,21 +886,30 @@ lookup_field (xbasetype, name, protect, want_type)
 
   /* rval_binfo_h and binfo_h are binfo values used when we perform the
      hiding checks, as virtual base classes may not be shared.  The strategy
-     is we always go into the the binfo hierarchy owned by TYPE_BINFO of
+     is we always go into the binfo hierarchy owned by TYPE_BINFO of
      virtual base classes, as we cross virtual base class lines.  This way
      we know that binfo of a virtual base class will always == itself when
      found along any line.  (mrs)  */
 
   char *errstr = 0;
 
-  /* Set this to nonzero if we don't know how to compute
-     accurate error messages for access control.  */
-  int index = MEMOIZED_HASH_FN (name);
-
+#if 0
+  /* We cannot search for constructor/destructor names like this.  */
+  /* This can't go here, but where should it go?  */
   /* If we are looking for a constructor in a templated type, use the
      unspecialized name, as that is how we store it.  */
   if (IDENTIFIER_TEMPLATE (name))
     name = constructor_name (name);
+#endif
+
+  if (xbasetype == current_class_type && TYPE_BEING_DEFINED (xbasetype)
+      && IDENTIFIER_CLASS_VALUE (name))
+    {
+      tree field = IDENTIFIER_CLASS_VALUE (name);
+      if (TREE_CODE (field) != FUNCTION_DECL
+         && ! (want_type && TREE_CODE (field) != TYPE_DECL))
+       return field;
+    }
 
   if (TREE_CODE (xbasetype) == TREE_VEC)
     {
@@ -1110,45 +919,18 @@ lookup_field (xbasetype, name, protect, want_type)
   else if (IS_AGGR_TYPE_CODE (TREE_CODE (xbasetype)))
     {
       type = xbasetype;
-      basetype_path = TYPE_BINFO (xbasetype);
-      BINFO_VIA_PUBLIC (basetype_path) = 1;
-      BINFO_INHERITANCE_CHAIN (basetype_path) = NULL_TREE;
+      basetype_path = TYPE_BINFO (type);
+      my_friendly_assert (BINFO_INHERITANCE_CHAIN (basetype_path) == NULL_TREE,
+                         980827);
     }
-  else my_friendly_abort (97);
-
-  if (CLASSTYPE_MTABLE_ENTRY (type))
-    {
-      tree tem = MEMOIZED_FIELDS (CLASSTYPE_MTABLE_ENTRY (type), index);
+  else
+    my_friendly_abort (97);
 
-      while (tem && TREE_PURPOSE (tem) != name)
-       {
-         memoized_fields_searched[0]++;
-         tem = TREE_CHAIN (tem);
-       }
-      if (tem)
-       {
-         if (protect && TREE_TYPE (tem))
-           {
-             error (TREE_STRING_POINTER (TREE_TYPE (tem)),
-                    IDENTIFIER_POINTER (name),
-                    TYPE_NAME_STRING (DECL_FIELD_CONTEXT (TREE_VALUE (tem))));
-             return error_mark_node;
-           }
-         if (TREE_VALUE (tem) == NULL_TREE)
-           memoized_fast_rejects[0] += 1;
-         else
-           memoized_fast_finds[0] += 1;
-         return TREE_VALUE (tem);
-       }
-    }
+  complete_type (type);
 
 #ifdef GATHER_STATISTICS
   n_calls_lookup_field++;
-#endif
-  if (protect && flag_memoize_lookups && ! global_bindings_p ())
-    entry = make_memoized_table_entry (type, name, 0);
-  else
-    entry = 0;
+#endif /* GATHER_STATISTICS */
 
   rval = lookup_field_1 (type, name);
 
@@ -1193,36 +975,13 @@ lookup_field (xbasetype, name, protect, want_type)
            }
        }
 
-      if (entry)
-       {
-         if (errstr)
-           {
-             /* This depends on behavior of lookup_field_1!  */
-             tree error_string = my_build_string (errstr);
-             TREE_TYPE (entry) = error_string;
-           }
-         else
-           {
-             /* Let entry know there is no problem with this access.  */
-             TREE_TYPE (entry) = NULL_TREE;
-           }
-         TREE_VALUE (entry) = rval;
-       }
-
-      if (errstr && protect)
-       {
-         cp_error (errstr, name, type);
-         return error_mark_node;
-       }
-      return rval;
+      rval_binfo = basetype_path;
+      goto out;
     }
 
-  basetype_chain = build_tree_list (NULL_TREE, basetype_path);
-  TREE_VIA_PUBLIC (basetype_chain) = TREE_VIA_PUBLIC (basetype_path);
-  TREE_VIA_PROTECTED (basetype_chain) = TREE_VIA_PROTECTED (basetype_path);
-  TREE_VIA_VIRTUAL (basetype_chain) = TREE_VIA_VIRTUAL (basetype_path);
+  basetype_chain = build_expr_list (NULL_TREE, basetype_path);
 
-  /* The ambiguity check relies upon breadth first searching. */
+  /* The ambiguity check relies upon breadth first searching.  */
 
   search_stack = push_search_level (search_stack, &search_obstack);
   binfo = basetype_path;
@@ -1243,16 +1002,13 @@ lookup_field (xbasetype, name, protect, want_type)
              tree btypes;
 
              SET_BINFO_FIELDS_MARKED (base_binfo);
-             btypes = my_tree_cons (NULL_TREE, base_binfo, basetype_chain);
-             TREE_VIA_PUBLIC (btypes) = TREE_VIA_PUBLIC (base_binfo);
-             TREE_VIA_PROTECTED (btypes) = TREE_VIA_PROTECTED (base_binfo);
-             TREE_VIA_VIRTUAL (btypes) = TREE_VIA_VIRTUAL (base_binfo);
+             btypes = scratch_tree_cons (NULL_TREE, base_binfo, basetype_chain);
              if (TREE_VIA_VIRTUAL (base_binfo))
-               btypes = tree_cons (NULL_TREE,
+               btypes = scratch_tree_cons (NULL_TREE,
                                    TYPE_BINFO (BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i))),
                                    btypes);
              else
-               btypes = tree_cons (NULL_TREE,
+               btypes = scratch_tree_cons (NULL_TREE,
                                    TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i),
                                    btypes);
              obstack_ptr_grow (&search_obstack, btypes);
@@ -1271,9 +1027,15 @@ lookup_field (xbasetype, name, protect, want_type)
       basetype_chain = TREE_CHAIN (basetype_chain);
       basetype_path = TREE_VALUE (basetype_chain);
       if (TREE_CHAIN (basetype_chain))
-       BINFO_INHERITANCE_CHAIN (basetype_path) = TREE_VALUE (TREE_CHAIN (basetype_chain));
+       my_friendly_assert
+         ((BINFO_INHERITANCE_CHAIN (basetype_path)
+           == TREE_VALUE (TREE_CHAIN (basetype_chain)))
+          /* We only approximate base info for partial instantiations.  */ 
+          || current_template_parms,
+          980827);
       else
-       BINFO_INHERITANCE_CHAIN (basetype_path) = NULL_TREE;
+       my_friendly_assert (BINFO_INHERITANCE_CHAIN (basetype_path)
+                           == NULL_TREE, 980827);
 
       binfo = basetype_path;
       type = BINFO_TYPE (binfo);
@@ -1293,16 +1055,16 @@ lookup_field (xbasetype, name, protect, want_type)
          else if (rval_binfo && hides (rval_binfo_h, binfo_h))
            {
              /* This is ok, the member found is in rval_binfo, not
-                here (binfo). */
+                here (binfo).  */
            }
          else if (rval_binfo==NULL_TREE || hides (binfo_h, rval_binfo_h))
            {
              /* This is ok, the member found is here (binfo), not in
-                rval_binfo. */
+                rval_binfo.  */
              if (nval)
                {
                  rval = nval;
-                 if (entry || protect)
+                 if (protect)
                    this_v = compute_access (basetype_path, rval);
                  /* These may look ambiguous, but they really are not.  */
                  if (vbase_name_p)
@@ -1310,7 +1072,7 @@ lookup_field (xbasetype, name, protect, want_type)
                }
              else
                {
-                 /* Undo finding it before, as something else hides it. */
+                 /* Undo finding it before, as something else hides it.  */
                  rval = NULL_TREE;
                }
              rval_binfo = binfo;
@@ -1318,9 +1080,9 @@ lookup_field (xbasetype, name, protect, want_type)
            }
          else
            {
-             /* This is ambiguous. */
+             /* This is ambiguous.  */
              errstr = "request for member `%D' is ambiguous";
-             protect = 2;
+             protect += 2;
              break;
            }
        }
@@ -1329,9 +1091,6 @@ lookup_field (xbasetype, name, protect, want_type)
     tree *tp = search_stack->first;
     tree *search_tail = tp + tail;
 
-    if (entry)
-      TREE_VALUE (entry) = rval;
-
     if (rval_binfo)
       {
        type = BINFO_TYPE (rval_binfo);
@@ -1361,7 +1120,7 @@ lookup_field (xbasetype, name, protect, want_type)
 
     /* If this FIELD_DECL defines its own access level, deal with that.  */
     if (rval && errstr == 0
-       && ((protect&1) || entry)
+       && (protect & 1)
        && DECL_LANG_SPECIFIC (rval)
        && DECL_ACCESS (rval))
       {
@@ -1370,7 +1129,7 @@ lookup_field (xbasetype, name, protect, want_type)
            /* If is possible for one of the derived types on the path to
               have defined special access for this field.  Look for such
               declarations and report an error if a conflict is found.  */
-           tree new_v;
+           tree new_v = NULL_TREE;
 
            if (this_v != access_default_node)
              new_v = compute_access (TREE_VALUE (TREE_CHAIN (*tp)), rval);
@@ -1411,19 +1170,13 @@ lookup_field (xbasetype, name, protect, want_type)
            : "member `%D' is from protected base class";
     }
 
-  if (entry)
+ out:
+  if (protect == 2)
     {
-      if (errstr)
-       {
-         tree error_string = my_build_string (errstr);
-         /* Save error message with entry.  */
-         TREE_TYPE (entry) = error_string;
-       }
-      else
-       {
-         /* Mark entry as having no error string.  */
-         TREE_TYPE (entry) = NULL_TREE;
-       }
+      /* If we are not interested in ambiguities, don't report them,
+        just return NULL_TREE.  */
+      rval = NULL_TREE;
+      protect = 0;
     }
 
   if (errstr && protect)
@@ -1431,10 +1184,46 @@ lookup_field (xbasetype, name, protect, want_type)
       cp_error (errstr, name, type);
       rval = error_mark_node;
     }
+
+  /* Do implicit typename stuff.  This code also handles out-of-class
+     definitions of nested classes whose enclosing class is a
+     template.  For example:
+    
+       template <class T> struct S { struct I { void f(); }; };
+       template <class T> void S<T>::I::f() {}
+
+     will come through here to handle `S<T>::I'.  */
+  if (rval && processing_template_decl
+      && ! currently_open_class (BINFO_TYPE (rval_binfo))
+      && uses_template_parms (type))
+    {
+      /* We need to return a member template class so we can define partial
+        specializations.  Is there a better way?  */
+      if (DECL_CLASS_TEMPLATE_P (rval))
+       return rval;
+
+      /* Don't return a non-type.  Actually, we ought to return something
+        so lookup_name_real can give a warning.  */
+      if (TREE_CODE (rval) != TYPE_DECL)
+       return NULL_TREE;
+
+      binfo = rval_binfo;
+      for (; ; binfo = BINFO_INHERITANCE_CHAIN (binfo))
+       if (BINFO_INHERITANCE_CHAIN (binfo) == NULL_TREE
+           || (BINFO_TYPE (BINFO_INHERITANCE_CHAIN (binfo))
+               == current_class_type))
+         break;
+
+      entry = build_typename_type (BINFO_TYPE (binfo), name,  name, 
+                                  TREE_TYPE (rval));
+      return TYPE_STUB_DECL (entry);
+    }
+
   return rval;
 }
 
 /* Try to find NAME inside a nested class.  */
+
 tree
 lookup_nested_field (name, complain)
      tree name;
@@ -1443,14 +1232,14 @@ lookup_nested_field (name, complain)
   register tree t;
 
   tree id = NULL_TREE;
-  if (TREE_CHAIN (current_class_type))
+  if (TYPE_MAIN_DECL (current_class_type))
     {
       /* Climb our way up the nested ladder, seeing if we're trying to
         modify a field in an enclosing class.  If so, we should only
         be able to modify if it's static.  */
-      for (t = TREE_CHAIN (current_class_type);
+      for (t = TYPE_MAIN_DECL (current_class_type);
           t && DECL_CONTEXT (t);
-          t = TREE_CHAIN (DECL_CONTEXT (t)))
+          t = TYPE_MAIN_DECL (DECL_CONTEXT (t)))
        {
          if (TREE_CODE (DECL_CONTEXT (t)) != RECORD_TYPE)
            break;
@@ -1477,10 +1266,8 @@ lookup_nested_field (name, complain)
                         enums in nested classes) when we do need to call
                         this fn at parse time.  So, in those cases, we pass
                         complain as a 0 and just return a NULL_TREE.  */
-                     error ("assignment to non-static member `%s' of enclosing class `%s'",
-                            lang_printable_name (id),
-                            IDENTIFIER_POINTER (TYPE_IDENTIFIER
-                                                (DECL_CONTEXT (t))));
+                     cp_error ("assignment to non-static member `%D' of enclosing class `%T'",
+                               id, DECL_CONTEXT (t));
                      /* Mark this for do_identifier().  It would otherwise
                         claim that the variable was undeclared.  */
                      TREE_TYPE (id) = error_mark_node;
@@ -1501,11 +1288,13 @@ lookup_nested_field (name, complain)
 
 /* TYPE is a class type. Return the index of the fields within
    the method vector with name NAME, or -1 is no such field exists.  */
+
 static int
 lookup_fnfields_1 (type, name)
      tree type, name;
 {
-  register tree method_vec = CLASSTYPE_METHOD_VEC (type);
+  register tree method_vec 
+    = CLASS_TYPE_P (type) ? CLASSTYPE_METHOD_VEC (type) : NULL_TREE;
 
   if (method_vec != 0)
     {
@@ -1514,19 +1303,50 @@ lookup_fnfields_1 (type, name)
 
 #ifdef GATHER_STATISTICS
       n_calls_lookup_fnfields_1++;
-#endif
-      if (*methods && name == constructor_name (type))
+#endif /* GATHER_STATISTICS */
+
+      /* Constructors are first...  */
+      if (*methods && name == ctor_identifier)
        return 0;
 
-      while (++methods != end)
+      /* and destructors are second.  */
+      if (*++methods && name == dtor_identifier)
+       return 1;
+
+      while (++methods != end && *methods)
        {
 #ifdef GATHER_STATISTICS
          n_outer_fields_searched++;
-#endif
-         if (DECL_NAME (*methods) == name)
+#endif /* GATHER_STATISTICS */
+         if (DECL_NAME (OVL_CURRENT (*methods)) == name)
            break;
        }
-      if (methods != end)
+
+      /* If we didn't find it, it might have been a template
+        conversion operator.  (Note that we don't look for this case
+        above so that we will always find specializations first.)  */
+      if ((methods == end || !*methods)
+         && IDENTIFIER_TYPENAME_P (name)) 
+       {
+         methods = &TREE_VEC_ELT (method_vec, 0) + 1;
+         
+         while (++methods != end && *methods)
+           {
+             tree method_name = DECL_NAME (OVL_CURRENT (*methods));
+
+             if (!IDENTIFIER_TYPENAME_P (method_name))
+               {
+                 /* Since all conversion operators come first, we know
+                    there is no such operator.  */
+                 methods = end;
+                 break;
+               }
+             else if (TREE_CODE (OVL_CURRENT (*methods)) == TEMPLATE_DECL)
+               break;
+           }
+       }
+
+      if (methods != end && *methods)
        return methods - &TREE_VEC_ELT (method_vec, 0);
     }
 
@@ -1537,7 +1357,7 @@ lookup_fnfields_1 (type, name)
    which gives the following information (in a list):
 
    TREE_TYPE: list of basetypes needed to get to...
-   TREE_VALUE: list of all functions in of given type
+   TREE_VALUE: list of all functions in a given type
    which have name NAME.
 
    No access information is computed by this function,
@@ -1551,15 +1371,16 @@ lookup_fnfields_1 (type, name)
    As a special case, is COMPLAIN is -1, we don't complain, and we
    don't return error_mark_node, but rather the complete list of
    virtuals.  This is used by get_virtuals_named_this.  */
+
 tree
 lookup_fnfields (basetype_path, name, complain)
      tree basetype_path, name;
      int complain;
 {
   int head = 0, tail = 0;
-  tree type, rval, rval_binfo = NULL_TREE, rvals = NULL_TREE, rval_binfo_h;
-  tree entry, binfo, basetype_chain, binfo_h;
-  int find_all = 0;
+  tree type, rval, rval_binfo = NULL_TREE, rvals = NULL_TREE;
+  tree rval_binfo_h = NULL_TREE, binfo, basetype_chain, binfo_h;
+  int idx, find_all = 0;
 
   /* rval_binfo is the binfo associated with the found member, note,
      this can be set with useful information, even when rval is not
@@ -1570,7 +1391,7 @@ lookup_fnfields (basetype_path, name, complain)
 
   /* rval_binfo_h and binfo_h are binfo values used when we perform the
      hiding checks, as virtual base classes may not be shared.  The strategy
-     is we always go into the the binfo hierarchy owned by TYPE_BINFO of
+     is we always go into the binfo hierarchy owned by TYPE_BINFO of
      virtual base classes, as we cross virtual base class lines.  This way
      we know that binfo of a virtual base class will always == itself when
      found along any line.  (mrs)  */
@@ -1580,125 +1401,64 @@ lookup_fnfields (basetype_path, name, complain)
 
   char *errstr = 0;
 
-  /* Set this to nonzero if we don't know how to compute
-     accurate error messages for access control.  */
-  int index = MEMOIZED_HASH_FN (name);
-
   if (complain == -1)
     {
       find_all = 1;
       protect = complain = 0;
     }
 
+#if 0
+  /* We cannot search for constructor/destructor names like this.  */
+  /* This can't go here, but where should it go?  */
   /* If we are looking for a constructor in a templated type, use the
      unspecialized name, as that is how we store it.  */
   if (IDENTIFIER_TEMPLATE (name))
     name = constructor_name (name);
+#endif
 
   binfo = basetype_path;
   binfo_h = binfo;
-  type = BINFO_TYPE (basetype_path);
-
-  /* The memoization code is in need of maintenance. */
-  if (!find_all && CLASSTYPE_MTABLE_ENTRY (type))
-    {
-      tree tem = MEMOIZED_FNFIELDS (CLASSTYPE_MTABLE_ENTRY (type), index);
-
-      while (tem && TREE_PURPOSE (tem) != name)
-       {
-         memoized_fields_searched[1]++;
-         tem = TREE_CHAIN (tem);
-       }
-      if (tem)
-       {
-         if (protect && TREE_TYPE (tem))
-           {
-             error (TREE_STRING_POINTER (TREE_TYPE (tem)),
-                    IDENTIFIER_POINTER (name),
-                    TYPE_NAME_STRING (DECL_CLASS_CONTEXT (TREE_VALUE (TREE_VALUE (tem)))));
-             return error_mark_node;
-           }
-         if (TREE_VALUE (tem) == NULL_TREE)
-           {
-             memoized_fast_rejects[1] += 1;
-             return NULL_TREE;
-           }
-         else
-           {
-             /* Want to return this, but we must make sure
-                that access information is consistent.  */
-             tree baselink = TREE_VALUE (tem);
-             tree memoized_basetypes = TREE_PURPOSE (baselink);
-             tree these_basetypes = basetype_path;
-             while (memoized_basetypes && these_basetypes)
-               {
-                 memoized_fields_searched[1]++;
-                 if (TREE_VALUE (memoized_basetypes) != these_basetypes)
-                   break;
-                 memoized_basetypes = TREE_CHAIN (memoized_basetypes);
-                 these_basetypes = BINFO_INHERITANCE_CHAIN (these_basetypes);
-               }
-             /* The following statement is true only when both are NULL.  */
-             if (memoized_basetypes == these_basetypes)
-               {
-                 memoized_fast_finds[1] += 1;
-                 return TREE_VALUE (tem);
-               }
-             /* else, we must re-find this field by hand.  */
-             baselink = tree_cons (basetype_path, TREE_VALUE (baselink), TREE_CHAIN (baselink));
-             return baselink;
-           }
-       }
-    }
+  type = complete_type (BINFO_TYPE (basetype_path));
 
 #ifdef GATHER_STATISTICS
   n_calls_lookup_fnfields++;
-#endif
-  if (protect && flag_memoize_lookups && ! global_bindings_p ())
-    entry = make_memoized_table_entry (type, name, 1);
-  else
-    entry = 0;
+#endif /* GATHER_STATISTICS */
 
-  index = lookup_fnfields_here (type, name);
-  if (index >= 0 || lookup_field_1 (type, name))
+  idx = lookup_fnfields_here (type, name);
+  if (idx >= 0 || lookup_field_1 (type, name))
     {
       rval_binfo = basetype_path;
       rval_binfo_h = rval_binfo;
     }
 
-  if (index >= 0)
+  if (idx >= 0)
     {
-      rval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), index);
-      rvals = my_tree_cons (basetype_path, rval, rvals);
+      rval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx);
+      rvals = scratch_tree_cons (basetype_path, rval, rvals);
       if (BINFO_BASETYPES (binfo) && CLASSTYPE_BASELINK_VEC (type))
-       TREE_TYPE (rvals) = TREE_VEC_ELT (CLASSTYPE_BASELINK_VEC (type), index);
-
-      if (entry)
-       {
-         TREE_VALUE (entry) = rvals;
-         TREE_TYPE (entry) = NULL_TREE;
-       }
+       TREE_TYPE (rvals) = TREE_VEC_ELT (CLASSTYPE_BASELINK_VEC (type), idx);
 
       return rvals;
     }
   rval = NULL_TREE;
 
+  if (name == ctor_identifier || name == dtor_identifier)
+    {
+      /* Don't allow lookups of constructors and destructors to go
+        deeper than the first place we look.  */
+      return NULL_TREE;
+    }
+
   if (basetype_path == TYPE_BINFO (type))
     {
       basetype_chain = CLASSTYPE_BINFO_AS_LIST (type);
-      TREE_VIA_PUBLIC (basetype_chain) = 1;
-      BINFO_VIA_PUBLIC (basetype_path) = 1;
-      BINFO_INHERITANCE_CHAIN (basetype_path) = NULL_TREE;
+      my_friendly_assert (BINFO_INHERITANCE_CHAIN (basetype_path) == NULL_TREE,
+                         980827);
     }
   else
-    {
-      basetype_chain = build_tree_list (NULL_TREE, basetype_path);
-      TREE_VIA_PUBLIC (basetype_chain) = TREE_VIA_PUBLIC (basetype_path);
-      TREE_VIA_PROTECTED (basetype_chain) = TREE_VIA_PROTECTED (basetype_path);
-      TREE_VIA_VIRTUAL (basetype_chain) = TREE_VIA_VIRTUAL (basetype_path);
-    }
+    basetype_chain = build_expr_list (NULL_TREE, basetype_path);
 
-  /* The ambiguity check relies upon breadth first searching. */
+  /* The ambiguity check relies upon breadth first searching.  */
 
   search_stack = push_search_level (search_stack, &search_obstack);
   binfo = basetype_path;
@@ -1708,7 +1468,7 @@ lookup_fnfields (basetype_path, name, complain)
     {
       tree binfos = BINFO_BASETYPES (binfo);
       int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-      int index;
+      int idx;
 
       /* Process and/or queue base types.  */
       for (i = 0; i < n_baselinks; i++)
@@ -1719,16 +1479,13 @@ lookup_fnfields (basetype_path, name, complain)
              tree btypes;
 
              SET_BINFO_FIELDS_MARKED (base_binfo);
-             btypes = my_tree_cons (NULL_TREE, base_binfo, basetype_chain);
-             TREE_VIA_PUBLIC (btypes) = TREE_VIA_PUBLIC (base_binfo);
-             TREE_VIA_PROTECTED (btypes) = TREE_VIA_PROTECTED (base_binfo);
-             TREE_VIA_VIRTUAL (btypes) = TREE_VIA_VIRTUAL (base_binfo);
+             btypes = scratch_tree_cons (NULL_TREE, base_binfo, basetype_chain);
              if (TREE_VIA_VIRTUAL (base_binfo))
-               btypes = tree_cons (NULL_TREE,
+               btypes = scratch_tree_cons (NULL_TREE,
                                    TYPE_BINFO (BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i))),
                                    btypes);
              else
-               btypes = tree_cons (NULL_TREE,
+               btypes = scratch_tree_cons (NULL_TREE,
                                    TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i),
                                    btypes);
              obstack_ptr_grow (&search_obstack, btypes);
@@ -1747,9 +1504,15 @@ lookup_fnfields (basetype_path, name, complain)
       basetype_chain = TREE_CHAIN (basetype_chain);
       basetype_path = TREE_VALUE (basetype_chain);
       if (TREE_CHAIN (basetype_chain))
-       BINFO_INHERITANCE_CHAIN (basetype_path) = TREE_VALUE (TREE_CHAIN (basetype_chain));
+       my_friendly_assert
+         ((BINFO_INHERITANCE_CHAIN (basetype_path)
+           == TREE_VALUE (TREE_CHAIN (basetype_chain)))
+          /* We only approximate base info for partial instantiations.  */ 
+          || current_template_parms,
+          980827);
       else
-       BINFO_INHERITANCE_CHAIN (basetype_path) = NULL_TREE;
+       my_friendly_assert (BINFO_INHERITANCE_CHAIN (basetype_path)
+                           == NULL_TREE, 980827);
 
       binfo = basetype_path;
       type = BINFO_TYPE (binfo);
@@ -1758,32 +1521,32 @@ lookup_fnfields (basetype_path, name, complain)
         and we do find NAME in TYPE, verify that such a second
         sighting is in fact valid.  */
 
-      index = lookup_fnfields_here (type, name);
+      idx = lookup_fnfields_here (type, name);
 
-      if (index >= 0 || (lookup_field_1 (type, name)!=NULL_TREE && !find_all))
+      if (idx >= 0 || (lookup_field_1 (type, name)!=NULL_TREE && !find_all))
        {
          if (rval_binfo && !find_all && hides (rval_binfo_h, binfo_h))
            {
              /* This is ok, the member found is in rval_binfo, not
-                here (binfo). */
+                here (binfo).  */
            }
          else if (rval_binfo==NULL_TREE || find_all || hides (binfo_h, rval_binfo_h))
            {
              /* This is ok, the member found is here (binfo), not in
-                rval_binfo. */
-             if (index >= 0)
+                rval_binfo.  */
+             if (idx >= 0)
                {
-                 rval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), index);
+                 rval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx);
                  /* Note, rvals can only be previously set if find_all is
                     true.  */
-                 rvals = my_tree_cons (basetype_path, rval, rvals);
+                 rvals = scratch_tree_cons (basetype_path, rval, rvals);
                  if (TYPE_BINFO_BASETYPES (type)
                      && CLASSTYPE_BASELINK_VEC (type))
-                   TREE_TYPE (rvals) = TREE_VEC_ELT (CLASSTYPE_BASELINK_VEC (type), index);
+                   TREE_TYPE (rvals) = TREE_VEC_ELT (CLASSTYPE_BASELINK_VEC (type), idx);
                }
              else
                {
-                 /* Undo finding it before, as something else hides it. */
+                 /* Undo finding it before, as something else hides it.  */
                  rval = NULL_TREE;
                  rvals = NULL_TREE;
                }
@@ -1792,7 +1555,7 @@ lookup_fnfields (basetype_path, name, complain)
            }
          else
            {
-             /* This is ambiguous. */
+             /* This is ambiguous.  */
              errstr = "request for method `%D' is ambiguous";
              rvals = error_mark_node;
              break;
@@ -1811,23 +1574,7 @@ lookup_fnfields (basetype_path, name, complain)
   }
   search_stack = pop_search_level (search_stack);
 
-  if (entry)
-    {
-      if (errstr)
-       {
-         tree error_string = my_build_string (errstr);
-         /* Save error message with entry.  */
-         TREE_TYPE (entry) = error_string;
-       }
-      else
-       {
-         /* Mark entry as having no error string.  */
-         TREE_TYPE (entry) = NULL_TREE;
-         TREE_VALUE (entry) = rvals;
-       }
-    }
-
-  if (errstr && protect)
+  if (errstr && protect)
     {
       cp_error (errstr, name);
       rvals = error_mark_node;
@@ -1835,28 +1582,61 @@ lookup_fnfields (basetype_path, name, complain)
 
   return rvals;
 }
+
+/* Look for a field or function named NAME in an inheritance lattice
+   dominated by XBASETYPE.  PROTECT is zero if we can avoid computing
+   access information, otherwise it is 1.  WANT_TYPE is 1 when we should
+   only return TYPE_DECLs, if no TYPE_DECL can be found return NULL_TREE.  */
+
+tree
+lookup_member (xbasetype, name, protect, want_type)
+     tree xbasetype, name;
+     int protect, want_type;
+{
+  tree ret, basetype_path;
+
+  if (TREE_CODE (xbasetype) == TREE_VEC)
+    basetype_path = xbasetype;
+  else if (IS_AGGR_TYPE_CODE (TREE_CODE (xbasetype)))
+    {
+      basetype_path = TYPE_BINFO (xbasetype);
+      my_friendly_assert (BINFO_INHERITANCE_CHAIN (basetype_path)
+                         == NULL_TREE, 980827);
+    }
+  else
+    my_friendly_abort (97);
+  
+  ret = lookup_field (basetype_path, name, protect, want_type);
+  if (! ret && ! want_type)
+    ret = lookup_fnfields (basetype_path, name, protect);
+  return ret;
+}
 \f
 /* BREADTH-FIRST SEARCH ROUTINES.  */
 
 /* Search a multiple inheritance hierarchy by breadth-first search.
 
-   TYPE is an aggregate type, possibly in a multiple-inheritance hierarchy.
+   BINFO is an aggregate type, possibly in a multiple-inheritance hierarchy.
    TESTFN is a function, which, if true, means that our condition has been met,
    and its return value should be returned.
    QFN, if non-NULL, is a predicate dictating whether the type should
    even be queued.  */
 
-HOST_WIDE_INT
+static tree
 breadth_first_search (binfo, testfn, qfn)
      tree binfo;
-     int (*testfn)();
-     int (*qfn)();
+     tree (*testfn) PROTO((tree));
+     int (*qfn) PROTO((tree));
 {
   int head = 0, tail = 0;
-  int rval = 0;
+  tree rval = NULL_TREE;
 
   search_stack = push_search_level (search_stack, &search_obstack);
 
+  SET_BINFO_MARKED (binfo);
+  obstack_ptr_grow (&search_obstack, binfo);
+  ++tail;
+
   while (1)
     {
       tree binfos = BINFO_BASETYPES (binfo);
@@ -1869,12 +1649,11 @@ breadth_first_search (binfo, testfn, qfn)
          tree base_binfo = TREE_VEC_ELT (binfos, i);
 
          if (BINFO_MARKED (base_binfo) == 0
-             && (qfn == 0 || (*qfn) (binfo, i)))
+             && (qfn == 0 || (*qfn) (base_binfo)))
            {
              SET_BINFO_MARKED (base_binfo);
-             obstack_ptr_grow (&search_obstack, binfo);
-             obstack_ptr_grow (&search_obstack, (HOST_WIDE_INT) i);
-             tail += 2;
+             obstack_ptr_grow (&search_obstack, base_binfo);
+             ++tail;
              if (tail >= search_stack->limit)
                my_friendly_abort (100);
            }
@@ -1887,10 +1666,8 @@ breadth_first_search (binfo, testfn, qfn)
        }
 
       binfo = search_stack->first[head++];
-      i = (HOST_WIDE_INT) search_stack->first[head++];
-      if (rval = (*testfn) (binfo, i))
+      if ((rval = (*testfn) (binfo)))
        break;
-      binfo = BINFO_BASETYPE (binfo, i);
     }
   {
     tree *tp = search_stack->first;
@@ -1898,8 +1675,7 @@ breadth_first_search (binfo, testfn, qfn)
     while (tp < search_tail)
       {
        tree binfo = *tp++;
-       int i = (HOST_WIDE_INT)(*tp++);
-       CLEAR_BINFO_MARKED (BINFO_BASETYPE (binfo, i));
+       CLEAR_BINFO_MARKED (binfo);
       }
   }
 
@@ -1908,18 +1684,7 @@ breadth_first_search (binfo, testfn, qfn)
 }
 
 /* Functions to use in breadth first searches.  */
-typedef tree (*pft)();
-typedef int (*pfi)();
-
-int tree_needs_constructor_p (binfo, i)
-     tree binfo;
-     int i;
-{
-  tree basetype;
-  my_friendly_assert (i != 0, 296);
-  basetype = BINFO_TYPE (BINFO_BASETYPE (binfo, i));
-  return TYPE_NEEDS_CONSTRUCTING (basetype);
-}
+typedef tree (*pfi) PROTO((tree));
 
 static tree declarator;
 
@@ -1941,64 +1706,117 @@ get_virtuals_named_this (binfo)
     {
       tree fndecl;
 
-      for (fndecl = TREE_VALUE (fields); fndecl; fndecl = DECL_CHAIN (fndecl))
-       if (DECL_VINDEX (fndecl))
+      for (fndecl = TREE_VALUE (fields); fndecl; fndecl = OVL_NEXT (fndecl))
+       if (DECL_VINDEX (OVL_CURRENT (fndecl)))
          return fields;
       fields = next_baselink (fields);
     }
   return NULL_TREE;
 }
 
-static tree get_virtual_destructor (binfo, i)
+static tree
+get_virtual_destructor (binfo)
      tree binfo;
-     int i;
 {
   tree type = BINFO_TYPE (binfo);
-  if (i >= 0)
-    type = BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (binfo), i));
   if (TYPE_HAS_DESTRUCTOR (type)
-      && DECL_VINDEX (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 0)))
-    return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 0);
+      && DECL_VINDEX (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 1)))
+    return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 1);
   return 0;
 }
 
-int tree_has_any_destructor_p (binfo, i)
+static int
+tree_has_any_destructor_p (binfo)
      tree binfo;
-     int i;
 {
   tree type = BINFO_TYPE (binfo);
-  if (i >= 0)
-    type = BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (binfo), i));
   return TYPE_NEEDS_DESTRUCTOR (type);
 }
 
+/* Returns > 0 if a function with type DRETTYPE overriding a function
+   with type BRETTYPE is covariant, as defined in [class.virtual].
+
+   Returns 1 if trivial covariance, 2 if non-trivial (requiring runtime
+   adjustment), or -1 if pedantically invalid covariance.  */
+
+static int
+covariant_return_p (brettype, drettype)
+     tree brettype, drettype;
+{
+  tree binfo;
+
+  if (TREE_CODE (brettype) == FUNCTION_DECL
+      || TREE_CODE (brettype) == THUNK_DECL)
+    {
+      brettype = TREE_TYPE (TREE_TYPE (brettype));
+      drettype = TREE_TYPE (TREE_TYPE (drettype));
+    }
+  else if (TREE_CODE (brettype) == METHOD_TYPE)
+    {
+      brettype = TREE_TYPE (brettype);
+      drettype = TREE_TYPE (drettype);
+    }
+
+  if (same_type_p (brettype, drettype))
+    return 0;
+
+  if (! (TREE_CODE (brettype) == TREE_CODE (drettype)
+        && (TREE_CODE (brettype) == POINTER_TYPE
+            || TREE_CODE (brettype) == REFERENCE_TYPE)
+        && TYPE_QUALS (brettype) == TYPE_QUALS (drettype)))
+    return 0;
+
+  if (! can_convert (brettype, drettype))
+    return 0;
+
+  brettype = TREE_TYPE (brettype);
+  drettype = TREE_TYPE (drettype);
+
+  /* If not pedantic, allow any standard pointer conversion.  */
+  if (! IS_AGGR_TYPE (drettype) || ! IS_AGGR_TYPE (brettype))
+    return -1;
+
+  binfo = get_binfo (brettype, drettype, 1);
+
+  /* If we get an error_mark_node from get_binfo, it already complained,
+     so let's just succeed.  */
+  if (binfo == error_mark_node)
+    return 1;
+
+  if (! BINFO_OFFSET_ZEROP (binfo) || TREE_VIA_VIRTUAL (binfo))
+    return 2;
+  return 1;
+}
+
 /* Given a class type TYPE, and a function decl FNDECL, look for a
    virtual function in TYPE's hierarchy which FNDECL could match as a
    virtual function.  It doesn't matter which one we find.
 
    DTORP is nonzero if we are looking for a destructor.  Destructors
    need special treatment because they do not match by name.  */
+
 tree
 get_matching_virtual (binfo, fndecl, dtorp)
      tree binfo, fndecl;
      int dtorp;
 {
   tree tmp = NULL_TREE;
+  int i;
+
+  if (TREE_CODE (fndecl) == TEMPLATE_DECL)
+    /* In [temp.mem] we have:
+
+         A specialization of a member function template does not
+         override a virtual function from a base class.  */
+    return NULL_TREE;
 
   /* Breadth first search routines start searching basetypes
      of TYPE, so we must perform first ply of search here.  */
   if (dtorp)
     {
-      if (tree_has_any_destructor_p (binfo, -1))
-       tmp = get_virtual_destructor (binfo, -1);
-
-      if (tmp)
-       return tmp;
-
-      tmp = (tree) breadth_first_search (binfo,
-                                        (pfi) get_virtual_destructor,
-                                        tree_has_any_destructor_p);
-      return tmp;
+      return breadth_first_search (binfo,
+                                  get_virtual_destructor,
+                                  tree_has_any_destructor_p);
     }
   else
     {
@@ -2024,82 +1842,67 @@ get_matching_virtual (binfo, fndecl, dtorp)
 
       for (; baselink; baselink = next_baselink (baselink))
        {
-         for (tmp = TREE_VALUE (baselink); tmp; tmp = DECL_CHAIN (tmp))
+         tree tmps;
+         for (tmps = TREE_VALUE (baselink); tmps; tmps = OVL_NEXT (tmps))
            {
+             tmp = OVL_CURRENT (tmps);
              if (! DECL_VINDEX (tmp))
                continue;
 
              btypes = TYPE_ARG_TYPES (TREE_TYPE (tmp));
              if (instptr_type == NULL_TREE)
                {
-                 if (compparms (TREE_CHAIN (btypes), dtypes, 3))
+                 if (compparms (TREE_CHAIN (btypes), dtypes))
                    /* Caller knows to give error in this case.  */
                    return tmp;
                  return NULL_TREE;
                }
 
-             if ((TYPE_READONLY (TREE_TYPE (TREE_VALUE (btypes)))
-                  == TYPE_READONLY (instptr_type))
-                 && compparms (TREE_CHAIN (btypes), TREE_CHAIN (dtypes), 3))
+             if (/* The first parameter is the `this' parameter,
+                    which has POINTER_TYPE, and we can therefore
+                    safely use TYPE_QUALS, rather than
+                    CP_TYPE_QUALS.  */
+                 (TYPE_QUALS (TREE_TYPE (TREE_VALUE (btypes)))
+                  == TYPE_QUALS (instptr_type))
+                 && compparms (TREE_CHAIN (btypes), TREE_CHAIN (dtypes)))
                {
                  tree brettype = TREE_TYPE (TREE_TYPE (tmp));
-                 if (comptypes (brettype, drettype, 1))
+                 if (same_type_p (brettype, drettype))
                    /* OK */;
-                 else if
-                   (TREE_CODE (brettype) == TREE_CODE (drettype)
-                    && (TREE_CODE (brettype) == POINTER_TYPE
-                        || TREE_CODE (brettype) == REFERENCE_TYPE)
-                    && comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (brettype)),
-                                  TYPE_MAIN_VARIANT (TREE_TYPE (drettype)),
-                                  0))
-                     /* covariant return type */
+                 else if ((i = covariant_return_p (brettype, drettype)))
                    {
-                     tree b = TREE_TYPE (brettype), d = TREE_TYPE (drettype);
-                     if (TYPE_MAIN_VARIANT (b) != TYPE_MAIN_VARIANT (d))
-                       {
-                         tree binfo = get_binfo (b, d, 1);
-                         if (binfo != error_mark_node
-                             && ! BINFO_OFFSET_ZEROP (binfo))
-                           sorry ("adjusting pointers for covariant returns");
-                       }
-                     if (TYPE_READONLY (d) > TYPE_READONLY (b))
-                       {
-                         cp_error ("return type of `%#D' adds const", fndecl);
-                         cp_error_at ("  overriding definition as `%#D'",
-                                      tmp);
-                       }
-                     else if (TYPE_VOLATILE (d) > TYPE_VOLATILE (b))
+                     if (i == 2)
+                       sorry ("adjusting pointers for covariant returns");
+
+                     if (pedantic && i == -1)
                        {
-                         cp_error ("return type of `%#D' adds volatile",
-                                   fndecl);
-                         cp_error_at ("  overriding definition as `%#D'",
-                                      tmp);
+                         cp_pedwarn_at ("invalid covariant return type for `%#D' (must be pointer or reference to class)", fndecl);
+                         cp_pedwarn_at ("  overriding `%#D'", tmp);
                        }
                    }
                  else if (IS_AGGR_TYPE_2 (brettype, drettype)
-                          && comptypes (brettype, drettype, 0))
+                          && same_or_base_type_p (brettype, drettype))
                    {
                      error ("invalid covariant return type (must use pointer or reference)");
                      cp_error_at ("  overriding `%#D'", tmp);
-                     cp_error ("  with `%#D'", fndecl);
+                     cp_error_at ("  with `%#D'", fndecl);
                    }
                  else if (IDENTIFIER_ERROR_LOCUS (name) == NULL_TREE)
                    {
-                     cp_error ("conflicting return type specified for virtual function `%#D'", fndecl);
+                     cp_error_at ("conflicting return type specified for virtual function `%#D'", fndecl);
                      cp_error_at ("  overriding definition as `%#D'", tmp);
                      SET_IDENTIFIER_ERROR_LOCUS (name, basetype);
                    }
                  break;
                }
            }
-         if (tmp)
+         /* If not at the end */
+         if (tmps)
            {
              best = tmp;
              break;
            }
        }
-      if (best == NULL_TREE && warn_overloaded_virtual)
-       cp_warning_at ("conflicting specification deriving virtual function `%D'", fndecl);
 
       return best;
     }
@@ -2108,10 +1911,12 @@ get_matching_virtual (binfo, fndecl, dtorp)
 /* Return the list of virtual functions which are abstract in type
    TYPE that come from non virtual base classes.  See
    expand_direct_vtbls_init for the style of search we do.  */
+
 static tree
 get_abstract_virtuals_1 (binfo, do_self, abstract_virtuals)
-     tree binfo, abstract_virtuals;
+     tree binfo;
      int do_self;
+     tree abstract_virtuals;
 {
   tree binfos = BINFO_BASETYPES (binfo);
   int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
@@ -2119,8 +1924,8 @@ get_abstract_virtuals_1 (binfo, do_self, abstract_virtuals)
   for (i = 0; i < n_baselinks; i++)
     {
       tree base_binfo = TREE_VEC_ELT (binfos, i);
-      int is_not_base_vtable =
-       i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
+      int is_not_base_vtable
+       i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
       if (! TREE_VIA_VIRTUAL (base_binfo))
        abstract_virtuals
          = get_abstract_virtuals_1 (base_binfo, is_not_base_vtable,
@@ -2148,14 +1953,15 @@ get_abstract_virtuals_1 (binfo, do_self, abstract_virtuals)
 /* Return the list of virtual functions which are abstract in type TYPE.
    This information is cached, and so must be built on a
    non-temporary obstack.  */
+
 tree
 get_abstract_virtuals (type)
      tree type;
 {
   tree vbases;
-  tree abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (type);
+  tree abstract_virtuals = NULL;
 
-  /* First get all from non-virtual bases. */
+  /* First get all from non-virtual bases.  */
   abstract_virtuals
     = get_abstract_virtuals_1 (TYPE_BINFO (type), 1, abstract_virtuals);
                                               
@@ -2169,7 +1975,9 @@ get_abstract_virtuals (type)
        {
          tree base_pfn = FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals));
          tree base_fndecl = TREE_OPERAND (base_pfn, 0);
-         if (DECL_ABSTRACT_VIRTUAL_P (base_fndecl))
+         if (DECL_NEEDS_FINAL_OVERRIDER_P (base_fndecl))
+           cp_error ("`%#D' needs a final overrider", base_fndecl);
+         else if (DECL_ABSTRACT_VIRTUAL_P (base_fndecl))
            abstract_virtuals = tree_cons (NULL_TREE, base_fndecl, abstract_virtuals);
          virtuals = TREE_CHAIN (virtuals);
        }
@@ -2190,7 +1998,7 @@ get_baselinks (type_as_binfo_list, type, name)
      tree type_as_binfo_list;
      tree type, name;
 {
-  int head = 0, tail = 0, index;
+  int head = 0, tail = 0, idx;
   tree rval = 0, nval = 0;
   tree basetypes = type_as_binfo_list;
   tree binfo = TYPE_BINFO (type);
@@ -2226,17 +2034,17 @@ get_baselinks (type_as_binfo_list, type, name)
       basetypes = search_stack->first[head++];
       binfo = TREE_VALUE (basetypes);
       type = BINFO_TYPE (binfo);
-      index = lookup_fnfields_1 (type, name);
-      if (index >= 0)
+      idx = lookup_fnfields_1 (type, name);
+      if (idx >= 0)
        {
-         nval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), index);
+         nval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx);
          rval = hash_tree_cons (0, 0, 0, basetypes, nval, rval);
          if (TYPE_BINFO_BASETYPES (type) == 0)
            goto dont_queue;
          else if (TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (type)) == 1)
            {
              if (CLASSTYPE_BASELINK_VEC (type))
-               TREE_TYPE (rval) = TREE_VEC_ELT (CLASSTYPE_BASELINK_VEC (type), index);
+               TREE_TYPE (rval) = TREE_VEC_ELT (CLASSTYPE_BASELINK_VEC (type), idx);
              goto dont_queue;
            }
        }
@@ -2266,35 +2074,11 @@ next_baselink (baselink)
 \f
 /* DEPTH-FIRST SEARCH ROUTINES.  */
 
-/* Assign unique numbers to _CLASSTYPE members of the lattice
-   specified by TYPE.  The root nodes are marked first; the nodes
-   are marked depth-fisrt, left-right.  */
-
-static int cid;
-
-/* Matrix implementing a relation from CLASSTYPE X CLASSTYPE => INT.
-   Relation yields 1 if C1 <= C2, 0 otherwise.  */
-typedef char mi_boolean;
-static mi_boolean *mi_matrix;
-
-/* Type for which this matrix is defined.  */
-static tree mi_type;
-
-/* Size of the matrix for indexing purposes.  */
-static int mi_size;
-
-/* Return nonzero if class C2 derives from class C1.  */
-#define BINFO_DERIVES_FROM(C1, C2)     \
-  ((mi_matrix+mi_size*(BINFO_CID (C1)-1))[BINFO_CID (C2)-1])
-#define TYPE_DERIVES_FROM(C1, C2)      \
-  ((mi_matrix+mi_size*(CLASSTYPE_CID (C1)-1))[CLASSTYPE_CID (C2)-1])
-#define BINFO_DERIVES_FROM_STAR(C)     \
-  (mi_matrix+(BINFO_CID (C)-1))
-
 /* This routine converts a pointer to be a pointer of an immediate
    base class.  The normal convert_pointer_to routine would diagnose
    the conversion as ambiguous, under MI code that has the base class
-   as an ambiguous base class. */
+   as an ambiguous base class.  */
+
 static tree
 convert_pointer_to_single_level (to_type, expr)
      tree to_type, expr;
@@ -2304,21 +2088,25 @@ convert_pointer_to_single_level (to_type, expr)
 
   binfo_of_derived = TYPE_BINFO (TREE_TYPE (TREE_TYPE (expr)));
   last = get_binfo (to_type, TREE_TYPE (TREE_TYPE (expr)), 0);
-  BINFO_INHERITANCE_CHAIN (last) = binfo_of_derived;
-  BINFO_INHERITANCE_CHAIN (binfo_of_derived) = NULL_TREE;
-  return build_vbase_path (PLUS_EXPR, build_pointer_type (to_type), expr, last, 1);
+  my_friendly_assert (BINFO_INHERITANCE_CHAIN (last) == binfo_of_derived,
+                     980827);
+  my_friendly_assert (BINFO_INHERITANCE_CHAIN (binfo_of_derived) == NULL_TREE,
+                     980827);
+  return build_vbase_path (PLUS_EXPR, build_pointer_type (to_type), expr,
+                          last, 1);
 }
 
 /* The main function which implements depth first search.
 
    This routine has to remember the path it walked up, when
    dfs_init_vbase_pointers is the work function, as otherwise there
-   would be no record. */
+   would be no record.  */
+
 static void
 dfs_walk (binfo, fn, qfn)
      tree binfo;
-     void (*fn)();
-     int (*qfn)();
+     void (*fn) PROTO((tree));
+     int (*qfn) PROTO((tree));
 {
   tree binfos = BINFO_BASETYPES (binfo);
   int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
@@ -2329,7 +2117,10 @@ dfs_walk (binfo, fn, qfn)
 
       if (qfn == 0 || (*qfn)(base_binfo))
        {
-         if (fn == dfs_init_vbase_pointers)
+         if (TREE_CODE (BINFO_TYPE (base_binfo)) == TEMPLATE_TYPE_PARM
+             || TREE_CODE (BINFO_TYPE (base_binfo)) == TEMPLATE_TEMPLATE_PARM)
+           /* Pass */;
+         else if (fn == dfs_init_vbase_pointers)
            {
              /* When traversing an arbitrary MI hierarchy, we need to keep
                 a record of the path we took to get down to the final base
@@ -2354,7 +2145,7 @@ dfs_walk (binfo, fn, qfn)
                  /* No need for the conversion here, as we know it is the
                     right type.  */
                  vbase_decl_ptr_intermediate
-                   = (tree)CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (base_binfo));
+                   = CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (base_binfo));
                }
              else
                {
@@ -2366,47 +2157,87 @@ dfs_walk (binfo, fn, qfn)
              dfs_walk (base_binfo, fn, qfn);
 
              vbase_decl_ptr_intermediate = saved_vbase_decl_ptr_intermediate;
-           } else
-             dfs_walk (base_binfo, fn, qfn);
+           }
+         else
+           dfs_walk (base_binfo, fn, qfn);
        }
     }
 
   fn (binfo);
 }
 
-/* Predicate functions which serve for dfs_walk.  */
-static int numberedp (binfo) tree binfo;
-{ return BINFO_CID (binfo); }
-static int unnumberedp (binfo) tree binfo;
-{ return BINFO_CID (binfo) == 0; }
+/* Like dfs_walk, but only walk until fn returns something, and return
+   that.  We also use the real vbase binfos instead of the placeholders
+   in the normal binfo hierarchy.  START is the most-derived type for this
+   hierarchy, so that we can find the vbase binfos.  */
+
+static tree
+dfs_search (binfo, fn, start)
+     tree binfo, start;
+     tree (*fn) PROTO((tree));
+{
+  tree binfos = BINFO_BASETYPES (binfo);
+  int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+  tree retval;
+
+  for (i = 0; i < n_baselinks; i++)
+    {
+      tree base_binfo = TREE_VEC_ELT (binfos, i);
+
+      if (TREE_CODE (BINFO_TYPE (base_binfo)) == TEMPLATE_TYPE_PARM
+         || TREE_CODE (BINFO_TYPE (base_binfo)) == TEMPLATE_TEMPLATE_PARM)
+       /* Pass */;
+      else
+       {
+         if (TREE_VIA_VIRTUAL (base_binfo) && start)
+           base_binfo = binfo_member (BINFO_TYPE (base_binfo),
+                                      CLASSTYPE_VBASECLASSES (start));
+         retval = dfs_search (base_binfo, fn, start);
+         if (retval)
+           return retval;
+       }
+    }
+
+  return fn (binfo);
+}
 
 static int markedp (binfo) tree binfo;
 { return BINFO_MARKED (binfo); }
-static int bfs_markedp (binfo, i) tree binfo; int i;
-{ return BINFO_MARKED (BINFO_BASETYPE (binfo, i)); }
 static int unmarkedp (binfo) tree binfo;
 { return BINFO_MARKED (binfo) == 0; }
+
+#if 0
+static int bfs_markedp (binfo, i) tree binfo; int i;
+{ return BINFO_MARKED (BINFO_BASETYPE (binfo, i)); }
 static int bfs_unmarkedp (binfo, i) tree binfo; int i;
 { return BINFO_MARKED (BINFO_BASETYPE (binfo, i)) == 0; }
-static int marked_vtable_pathp (binfo) tree binfo;
-{ return BINFO_VTABLE_PATH_MARKED (binfo); }
 static int bfs_marked_vtable_pathp (binfo, i) tree binfo; int i;
 { return BINFO_VTABLE_PATH_MARKED (BINFO_BASETYPE (binfo, i)); }
-static int unmarked_vtable_pathp (binfo) tree binfo;
-{ return BINFO_VTABLE_PATH_MARKED (binfo) == 0; }
 static int bfs_unmarked_vtable_pathp (binfo, i) tree binfo; int i;
 { return BINFO_VTABLE_PATH_MARKED (BINFO_BASETYPE (binfo, i)) == 0; }
-static int marked_new_vtablep (binfo) tree binfo;
-{ return BINFO_NEW_VTABLE_MARKED (binfo); }
 static int bfs_marked_new_vtablep (binfo, i) tree binfo; int i;
 { return BINFO_NEW_VTABLE_MARKED (BINFO_BASETYPE (binfo, i)); }
-static int unmarked_new_vtablep (binfo) tree binfo;
-{ return BINFO_NEW_VTABLE_MARKED (binfo) == 0; }
 static int bfs_unmarked_new_vtablep (binfo, i) tree binfo; int i;
 { return BINFO_NEW_VTABLE_MARKED (BINFO_BASETYPE (binfo, i)) == 0; }
+#endif
+
+static int marked_vtable_pathp (binfo) tree binfo;
+{ return BINFO_VTABLE_PATH_MARKED (binfo); }
+static int unmarked_vtable_pathp (binfo) tree binfo;
+{ return BINFO_VTABLE_PATH_MARKED (binfo) == 0; }
+static int marked_new_vtablep (binfo) tree binfo;
+{ return BINFO_NEW_VTABLE_MARKED (binfo); }
+static int unmarked_new_vtablep (binfo) tree binfo;
+{ return BINFO_NEW_VTABLE_MARKED (binfo) == 0; }
+static int marked_pushdecls_p (binfo) tree binfo;
+{ return BINFO_PUSHDECLS_MARKED (binfo); }
+static int unmarked_pushdecls_p (binfo) tree binfo;
+{ return BINFO_PUSHDECLS_MARKED (binfo) == 0; }
 
+#if 0
 static int dfs_search_slot_nonempty_p (binfo) tree binfo;
 { return CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (binfo)) != 0; }
+#endif
 
 static int dfs_debug_unmarkedp (binfo) tree binfo;
 { return CLASSTYPE_DEBUG_REQUESTED (BINFO_TYPE (binfo)) == 0; }
@@ -2415,31 +2246,17 @@ static int dfs_debug_unmarkedp (binfo) tree binfo;
    test anything (vis a vis marking) if they are paired with
    a predicate function (above).  */
 
-/* Assign each type within the lattice a number which is unique
-   in the lattice.  The first number assigned is 1.  */
-
-static void
-dfs_number (binfo)
-     tree binfo;
-{
-  BINFO_CID (binfo) = ++cid;
-}
-
-static void
-dfs_unnumber (binfo)
-     tree binfo;
-{
-  BINFO_CID (binfo) = 0;
-}
-
+#if 0
 static void
 dfs_mark (binfo) tree binfo;
 { SET_BINFO_MARKED (binfo); }
+#endif
 
 static void
 dfs_unmark (binfo) tree binfo;
 { CLEAR_BINFO_MARKED (binfo); }
 
+#if 0
 static void
 dfs_mark_vtable_path (binfo) tree binfo;
 { SET_BINFO_VTABLE_PATH_MARKED (binfo); }
@@ -2459,6 +2276,7 @@ dfs_unmark_new_vtable (binfo) tree binfo;
 static void
 dfs_clear_search_slot (binfo) tree binfo;
 { CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (binfo)) = 0; }
+#endif
 
 static void
 dfs_debug_mark (binfo)
@@ -2472,10 +2290,12 @@ dfs_debug_mark (binfo)
 
   CLASSTYPE_DEBUG_REQUESTED (t) = 1;
 
-  /* If interface info is known, the value of (?@@?) is correct.  */
-  if (methods == 0
-      || CLASSTYPE_INTERFACE_KNOWN (t)
-      || (write_virtuals == 2 && TYPE_VIRTUAL_P (t)))
+  if (methods == 0)
+    return;
+
+  /* If interface info is known, either we've already emitted the debug
+     info or we don't need to.  */
+  if (CLASSTYPE_INTERFACE_KNOWN (t))
     return;
 
   /* If debug info is requested from this context for this type, supply it.
@@ -2484,10 +2304,13 @@ dfs_debug_mark (binfo)
   if (current_function_decl == NULL_TREE
       || DECL_CLASS_CONTEXT (current_function_decl) != t)
     {
-      if (TREE_VEC_ELT (methods, 0))
+      if (TREE_VEC_ELT (methods, 1))
+       methods = TREE_VEC_ELT (methods, 1);
+      else if (TREE_VEC_ELT (methods, 0))
        methods = TREE_VEC_ELT (methods, 0);
       else
-       methods = TREE_VEC_ELT (methods, 1);
+       methods = TREE_VEC_ELT (methods, 2);
+      methods = OVL_CURRENT (methods);
       while (methods)
        {
          if (DECL_VINDEX (methods)
@@ -2505,13 +2328,14 @@ dfs_debug_mark (binfo)
   /* We cannot rely on some alien method to solve our problems,
      so we must write out the debug info ourselves.  */
   TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (t)) = 0;
-  rest_of_type_compilation (t, global_bindings_p ());
+  rest_of_type_compilation (t, toplevel_bindings_p ());
 }
 \f
 /*  Attach to the type of the virtual base class, the pointer to the
     virtual base class, given the global pointer vbase_decl_ptr.
 
     We use the global vbase_types.  ICK!  */
+
 static void
 dfs_find_vbases (binfo)
      tree binfo;
@@ -2530,8 +2354,8 @@ dfs_find_vbases (binfo)
          tree binfo = binfo_member (vbase, vbase_types);
 
          CLASSTYPE_SEARCH_SLOT (vbase)
-           = (char *) build (PLUS_EXPR, build_pointer_type (vbase),
-                             vbase_decl_ptr, BINFO_OFFSET (binfo));
+           = build (PLUS_EXPR, build_pointer_type (vbase),
+                    vbase_decl_ptr, BINFO_OFFSET (binfo));
        }
     }
   SET_BINFO_VTABLE_PATH_MARKED (binfo);
@@ -2548,12 +2372,12 @@ dfs_init_vbase_pointers (binfo)
 
   CLEAR_BINFO_VTABLE_PATH_MARKED (binfo);
 
-  /* If there is a rtti, it is the first field, though perhaps from
-     the base class.  Otherwise, the first fields are virtual base class
-     pointer fields.  */
-  if (CLASSTYPE_RTTI (type) && VFIELD_NAME_P (DECL_NAME (fields)))
-    /* Get past vtable for the object.  */
+#if 0
+  /* See finish_struct_1 for when we can enable this.  */
+  /* If we have a vtable pointer first, skip it.  */
+  if (VFIELD_NAME_P (DECL_NAME (fields)))
     fields = TREE_CHAIN (fields);
+#endif
 
   if (fields == NULL_TREE
       || DECL_NAME (fields) == NULL_TREE
@@ -2570,7 +2394,7 @@ dfs_init_vbase_pointers (binfo)
     {
       tree ref = build (COMPONENT_REF, TREE_TYPE (fields),
                        build_indirect_ref (this_vbase_ptr, NULL_PTR), fields);
-      tree init = (tree)CLASSTYPE_SEARCH_SLOT (TREE_TYPE (TREE_TYPE (fields)));
+      tree init = CLASSTYPE_SEARCH_SLOT (TREE_TYPE (TREE_TYPE (fields)));
       vbase_init_result = tree_cons (binfo_member (TREE_TYPE (TREE_TYPE (fields)),
                                                   vbase_types),
                                     build_modify_expr (ref, NOP_EXPR, init),
@@ -2582,6 +2406,7 @@ dfs_init_vbase_pointers (binfo)
 /* Sometimes this needs to clear both VTABLE_PATH and NEW_VTABLE.  Other
    times, just NEW_VTABLE, but optimizer should make both with equal
    efficiency (though it does not currently).  */
+
 static void
 dfs_clear_vbase_slots (binfo)
      tree binfo;
@@ -2603,9 +2428,7 @@ init_vbase_pointers (type, decl_ptr)
       tree binfo = TYPE_BINFO (type);
       flag_this_is_variable = -2;
       vbase_types = CLASSTYPE_VBASECLASSES (type);
-      vbase_decl_ptr = decl_ptr;
-      vbase_decl = build_indirect_ref (decl_ptr, NULL_PTR);
-      vbase_decl_ptr_intermediate = vbase_decl_ptr;
+      vbase_decl_ptr = vbase_decl_ptr_intermediate = decl_ptr;
       vbase_init_result = NULL_TREE;
       dfs_walk (binfo, dfs_find_vbases, unmarked_vtable_pathp);
       dfs_walk (binfo, dfs_init_vbase_pointers, marked_vtable_pathp);
@@ -2626,6 +2449,7 @@ init_vbase_pointers (type, decl_ptr)
    We know that if there is more than one place (binfo) the fndecl that the
    declared, they all refer to the same binfo.  See get_class_offset_1 for
    the check that ensures this.  */
+
 static tree
 virtual_context (fndecl, t, vbase)
      tree fndecl, t, vbase;
@@ -2677,7 +2501,8 @@ virtual_context (fndecl, t, vbase)
    offset information for the virtual bases, so the offsets are only
    calculated once.  The offsets are computed by where we think the
    vbase should be (as noted by the CLASSTYPE_SEARCH_SLOT) minus where
-   the vbase really is. */
+   the vbase really is.  */
+
 static void
 expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
                      vbase_offsets)
@@ -2691,7 +2516,7 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
   delta = purpose_member (vbase, *vbase_offsets);
   if (! delta)
     {
-      delta = (tree)CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vbase));
+      delta = CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vbase));
       delta = build (MINUS_EXPR, ptrdiff_type_node, delta, vbase_addr);
       delta = save_expr (delta);
       delta = tree_cons (vbase, delta, *vbase_offsets);
@@ -2709,8 +2534,8 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
          && current_fndecl != abort_fndecl
          && (vc=virtual_context (current_fndecl, t, vbase)) != vbase)
        {
-         /* This may in fact need a runtime fixup. */
-         tree idx = DECL_VINDEX (current_fndecl);
+         /* This may in fact need a runtime fixup.  */
+         tree idx = build_int_2 (n, 0);
          tree vtbl = BINFO_VTABLE (binfo);
          tree nvtbl = lookup_name (DECL_NAME (vtbl), 0);
          tree aref, ref, naref;
@@ -2721,31 +2546,42 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
              || nvtbl == IDENTIFIER_GLOBAL_VALUE (DECL_NAME (vtbl)))
            {
              /* Dup it if it isn't in local scope yet.  */
-             nvtbl = build_decl (VAR_DECL,
-                                 DECL_NAME (vtbl),
-                                 TYPE_MAIN_VARIANT (TREE_TYPE (BINFO_VTABLE (binfo))));
+             nvtbl = build_decl
+               (VAR_DECL, DECL_NAME (vtbl),
+                TYPE_MAIN_VARIANT (TREE_TYPE (vtbl)));
              DECL_ALIGN (nvtbl) = MAX (TYPE_ALIGN (double_type_node),
                                        DECL_ALIGN (nvtbl));
              TREE_READONLY (nvtbl) = 0;
+             DECL_ARTIFICIAL (nvtbl) = 1;
              nvtbl = pushdecl (nvtbl);
              init = NULL_TREE;
-             cp_finish_decl (nvtbl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
-             DECL_VIRTUAL_P (nvtbl) = 1;
-             DECL_CONTEXT (nvtbl) = t;
+             cp_finish_decl (nvtbl, init, NULL_TREE, 0,
+                             LOOKUP_ONLYCONVERTING);
+
+             /* We don't set DECL_VIRTUAL_P and DECL_CONTEXT on nvtbl
+                because they wouldn't be useful; everything that wants to
+                look at the vtable will look at the decl for the normal
+                vtable.  Setting DECL_CONTEXT also screws up
+                decl_function_context.  */
+
              init = build (MODIFY_EXPR, TREE_TYPE (nvtbl),
                            nvtbl, vtbl);
              TREE_SIDE_EFFECTS (init) = 1;
              expand_expr_stmt (init);
-             /* Update the vtable pointers as necessary. */
-             ref = build_vfield_ref (build_indirect_ref (addr, NULL_PTR), DECL_CONTEXT (CLASSTYPE_VFIELD (BINFO_TYPE (binfo))));
-             expand_expr_stmt (build_modify_expr (ref, NOP_EXPR,
-                                                  build_unary_op (ADDR_EXPR, nvtbl, 0)));
+             /* Update the vtable pointers as necessary.  */
+             ref = build_vfield_ref
+               (build_indirect_ref (addr, NULL_PTR),
+                DECL_CONTEXT (CLASSTYPE_VFIELD (BINFO_TYPE (binfo))));
+             expand_expr_stmt
+               (build_modify_expr (ref, NOP_EXPR, nvtbl));
            }
          assemble_external (vtbl);
          aref = build_array_ref (vtbl, idx);
          naref = build_array_ref (nvtbl, idx);
-         old_delta = build_component_ref (aref, delta_identifier, 0, 0);
-         new_delta = build_component_ref (naref, delta_identifier, 0, 0);
+         old_delta = build_component_ref (aref, delta_identifier,
+                                          NULL_TREE, 0);
+         new_delta = build_component_ref (naref, delta_identifier,
+                                          NULL_TREE, 0);
 
          /* This is a upcast, so we have to add the offset for the
             virtual base.  */
@@ -2760,7 +2596,7 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
              if (! vc_delta)
                {
                  tree vc_addr = convert_pointer_to_real (vc, orig_addr);
-                 vc_delta = (tree)CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vc));
+                 vc_delta = CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vc));
                  vc_delta = build (MINUS_EXPR, ptrdiff_type_node,
                                    vc_delta, vc_addr);
                  vc_delta = save_expr (vc_delta);
@@ -2775,6 +2611,10 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
            }
 
          TREE_READONLY (new_delta) = 0;
+         TREE_TYPE (new_delta) = 
+           cp_build_qualified_type (TREE_TYPE (new_delta),
+                                    CP_TYPE_QUALS (TREE_TYPE (new_delta))
+                                    & ~TYPE_QUAL_CONST);
          expand_expr_stmt (build_modify_expr (new_delta, NOP_EXPR,
                                               old_delta));
        }
@@ -2785,10 +2625,12 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
 
 /* Fixup upcast offsets for all direct vtables.  Patterned after
    expand_direct_vtbls_init.  */
+
 static void
 fixup_virtual_upcast_offsets (real_binfo, binfo, init_self, can_elide, addr, orig_addr, type, vbase, vbase_offsets)
-     tree real_binfo, binfo, addr, orig_addr, type, vbase, *vbase_offsets;
+     tree real_binfo, binfo;
      int init_self, can_elide;
+     tree addr, orig_addr, type, vbase, *vbase_offsets;
 {
   tree real_binfos = BINFO_BASETYPES (real_binfo);
   tree binfos = BINFO_BASETYPES (binfo);
@@ -2798,8 +2640,8 @@ fixup_virtual_upcast_offsets (real_binfo, binfo, init_self, can_elide, addr, ori
     {
       tree real_base_binfo = TREE_VEC_ELT (real_binfos, i);
       tree base_binfo = TREE_VEC_ELT (binfos, i);
-      int is_not_base_vtable =
-       i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (real_binfo));
+      int is_not_base_vtable
+       i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (real_binfo));
       if (! TREE_VIA_VIRTUAL (real_base_binfo))
        fixup_virtual_upcast_offsets (real_base_binfo, base_binfo,
                                      is_not_base_vtable, can_elide, addr,
@@ -2832,30 +2674,33 @@ fixup_virtual_upcast_offsets (real_binfo, binfo, init_self, can_elide, addr, ori
    offsets are valid to store vtables.  When zero, we must store new
    vtables through virtual baseclass pointers.
 
-   We setup and use the globals: vbase_decl, vbase_decl_ptr, vbase_types
+   We setup and use the globals: vbase_decl_ptr, vbase_types
    ICK!  */
 
 void
-expand_indirect_vtbls_init (binfo, true_exp, decl_ptr, use_computed_offsets)
+expand_indirect_vtbls_init (binfo, true_exp, decl_ptr)
      tree binfo;
      tree true_exp, decl_ptr;
-     int use_computed_offsets;
 {
   tree type = BINFO_TYPE (binfo);
+
+  /* This function executes during the finish_function() segment,
+     AFTER the auto variables and temporary stack space has been marked
+     unused...If space is needed for the virtual function tables,
+     some of them might fit within what the compiler now thinks
+     are available stack slots... These values are actually initialized at
+     the beginnning of the function, so when the automatics use their space,
+     they will overwrite the values that are placed here. Marking all
+     temporary space as unavailable prevents this from happening. */
+
+  mark_all_temps_used();
+
   if (TYPE_USES_VIRTUAL_BASECLASSES (type))
     {
       rtx fixup_insns = NULL_RTX;
-      int old_flag = flag_this_is_variable;
       tree vbases = CLASSTYPE_VBASECLASSES (type);
       vbase_types = vbases;
       vbase_decl_ptr = true_exp ? build_unary_op (ADDR_EXPR, true_exp, 0) : decl_ptr;
-      vbase_decl = true_exp ? true_exp : build_indirect_ref (decl_ptr, NULL_PTR);
-
-      if (use_computed_offsets)
-       {
-         /* This is an object of type IN_TYPE,  */
-         flag_this_is_variable = -2;
-       }
 
       dfs_walk (binfo, dfs_find_vbases, unmarked_new_vtablep);
 
@@ -2863,57 +2708,25 @@ expand_indirect_vtbls_init (binfo, true_exp, decl_ptr, use_computed_offsets)
       for (; vbases; vbases = TREE_CHAIN (vbases))
        {
          tree addr;
-         if (use_computed_offsets)
-           addr = (tree)CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vbases));
-         else
-           {
-#if 1
-             addr = convert_pointer_to_vbase (TREE_TYPE (vbases), vbase_decl_ptr);
-#else
-             /* This should should never work better than the above.  (mrs) */
-             tree vbinfo = get_binfo (TREE_TYPE (vbases),
-                                      TREE_TYPE (vbase_decl),
-                                      0);
-
-             /* See is we can get lucky.  */
-             if (TREE_VIA_VIRTUAL (vbinfo))
-               addr = convert_pointer_to_real (vbinfo, vbase_decl_ptr);
-             else
-               {
-                 /* We go through all these contortions to avoid this
-                    call, as it will fail when the virtual base type
-                    is ambiguous from here.  We don't yet have a way
-                    to search for and find just an instance of the
-                    virtual base class.  Searching for the binfo in
-                    vbases won't work, as we don't have the vbase
-                    pointer field, for all vbases in the main class,
-                    only direct vbases.  */
-                 addr = convert_pointer_to_real (TREE_TYPE (vbases),
-                                                 vbase_decl_ptr);
-                 if (addr == error_mark_node)
-                   continue;
-               }
-#endif
-           }
 
-         /* Do all vtables from this virtual base. */
+         addr = convert_pointer_to_vbase (TREE_TYPE (vbases), vbase_decl_ptr);
+
+         /* Do all vtables from this virtual base.  */
          /* This assumes that virtual bases can never serve as parent
-            binfos.  (in the CLASSTPE_VFIELD_PARENT sense)  */
+            binfos.  (in the CLASSTYPE_VFIELD_PARENT sense)  */
          expand_direct_vtbls_init (vbases, TYPE_BINFO (BINFO_TYPE (vbases)),
                                    1, 0, addr);
 
-         /* If we are using computed offsets we can skip fixups.  */
-         if (use_computed_offsets)
-           continue;
-
-         /* Now we adjust the offsets for virtual functions that cross
-            virtual boundaries on an implicit upcast on vf call so that
-            the layout of the most complete type is used, instead of
-            assuming the layout of the virtual bases from our current type. */
+         /* Now we adjust the offsets for virtual functions that
+            cross virtual boundaries on an implicit upcast on vf call
+            so that the layout of the most complete type is used,
+            instead of assuming the layout of the virtual bases from
+            our current type.  */
 
          if (flag_vtable_thunks)
            {
-             /* We don't have dynamic thunks yet!  So for now, just fail silently. */
+             /* We don't have dynamic thunks yet!
+                So for now, just fail silently.  */
            }
          else
            {
@@ -2944,19 +2757,9 @@ expand_indirect_vtbls_init (binfo, true_exp, decl_ptr, use_computed_offsets)
        }
 
       dfs_walk (binfo, dfs_clear_vbase_slots, marked_new_vtablep);
-
-      flag_this_is_variable = old_flag;
     }
 }
 
-void
-clear_search_slots (type)
-     tree type;
-{
-  dfs_walk (TYPE_BINFO (type),
-           dfs_clear_search_slot, dfs_search_slot_nonempty_p);
-}
-
 /* get virtual base class types.
    This adds type to the vbase_types list in reverse dfs order.
    Ordering is very important, so don't change it.  */
@@ -2967,16 +2770,19 @@ dfs_get_vbase_types (binfo)
 {
   if (TREE_VIA_VIRTUAL (binfo) && ! BINFO_VBASE_MARKED (binfo))
     {
-      vbase_types = make_binfo (integer_zero_node, binfo,
-                               BINFO_VTABLE (binfo),
-                               BINFO_VIRTUALS (binfo), vbase_types);
-      TREE_VIA_VIRTUAL (vbase_types) = 1;
+      tree new_vbase = make_binfo (integer_zero_node, binfo,
+                                  BINFO_VTABLE (binfo),
+                                  BINFO_VIRTUALS (binfo));
+      TREE_CHAIN (new_vbase) = vbase_types;
+      TREE_VIA_VIRTUAL (new_vbase) = 1;
+      vbase_types = new_vbase;
       SET_BINFO_VBASE_MARKED (binfo);
     }
   SET_BINFO_MARKED (binfo);
 }
 
 /* get a list of virtual base classes in dfs order.  */
+
 tree
 get_vbase_types (type)
      tree type;
@@ -2984,11 +2790,7 @@ get_vbase_types (type)
   tree vbases;
   tree binfo;
 
-  if (TREE_CODE (type) == TREE_VEC)
-    binfo = type;
-  else
-    binfo = TYPE_BINFO (type);
-
+  binfo = TYPE_BINFO (type);
   vbase_types = NULL_TREE;
   dfs_walk (binfo, dfs_get_vbase_types, unmarkedp);
   dfs_walk (binfo, dfs_unmark, markedp);
@@ -3003,85 +2805,6 @@ get_vbase_types (type)
   return vbase_types;
 }
 \f
-static void
-dfs_record_inheritance (binfo)
-     tree binfo;
-{
-  tree binfos = BINFO_BASETYPES (binfo);
-  int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-  mi_boolean *derived_row = BINFO_DERIVES_FROM_STAR (binfo);
-
-  for (i = n_baselinks-1; i >= 0; i--)
-    {
-      int j;
-      tree base_binfo = TREE_VEC_ELT (binfos, i);
-      tree baseclass = BINFO_TYPE (base_binfo);
-      mi_boolean *base_row = BINFO_DERIVES_FROM_STAR (base_binfo);
-
-      /* Don't search if there's nothing there!  MI_SIZE can be
-        zero as a result of parse errors.  */
-      if (TYPE_BINFO_BASETYPES (baseclass) && mi_size > 0)
-       for (j = mi_size*(CLASSTYPE_CID (baseclass)-1); j >= 0; j -= mi_size)
-         derived_row[j] |= base_row[j];
-      TYPE_DERIVES_FROM (baseclass, BINFO_TYPE (binfo)) = 1;
-    }
-
-  SET_BINFO_MARKED (binfo);
-}
-
-/* Given a _CLASSTYPE node in a multiple inheritance lattice,
-   convert the lattice into a simple relation such that,
-   given to CIDs, C1 and C2, one can determine if C1 <= C2
-   or C2 <= C1 or C1 <> C2.
-
-   Once constructed, we walk the lattice depth fisrt,
-   applying various functions to elements as they are encountered.
-
-   We use xmalloc here, in case we want to randomly free these tables.  */
-
-#define SAVE_MI_MATRIX
-
-void
-build_mi_matrix (type)
-     tree type;
-{
-  tree binfo = TYPE_BINFO (type);
-  cid = 0;
-
-#ifdef SAVE_MI_MATRIX
-  if (CLASSTYPE_MI_MATRIX (type))
-    {
-      mi_size = CLASSTYPE_N_SUPERCLASSES (type) + CLASSTYPE_N_VBASECLASSES (type);
-      mi_matrix = CLASSTYPE_MI_MATRIX (type);
-      mi_type = type;
-      dfs_walk (binfo, dfs_number, unnumberedp);
-      return;
-    }
-#endif
-
-  mi_size = CLASSTYPE_N_SUPERCLASSES (type) + CLASSTYPE_N_VBASECLASSES (type);
-  mi_matrix = (char *)xmalloc ((mi_size + 1) * (mi_size + 1));
-  mi_type = type;
-  bzero (mi_matrix, (mi_size + 1) * (mi_size + 1));
-  dfs_walk (binfo, dfs_number, unnumberedp);
-  dfs_walk (binfo, dfs_record_inheritance, unmarkedp);
-  dfs_walk (binfo, dfs_unmark, markedp);
-}
-
-void
-free_mi_matrix ()
-{
-  dfs_walk (TYPE_BINFO (mi_type), dfs_unnumber, numberedp);
-
-#ifdef SAVE_MI_MATRIX
-  CLASSTYPE_MI_MATRIX (mi_type) = mi_matrix;
-#else
-  free (mi_matrix);
-  mi_size = 0;
-  cid = 0;
-#endif
-}
-\f
 /* If we want debug info for a type TYPE, make sure all its base types
    are also marked as being potentially interesting.  This avoids
    the problem of not writing any debug info for intermediate basetypes
@@ -3092,6 +2815,22 @@ note_debug_info_needed (type)
      tree type;
 {
   tree field;
+
+  if (current_template_parms)
+    return;
+    
+  if (TYPE_BEING_DEFINED (type))
+    /* We can't go looking for the base types and fields just yet.  */
+    return;
+
+  /* We can't do the TYPE_DECL_SUPPRESS_DEBUG thing with DWARF, which
+     does not support name references between translation units.  Well, we
+     could, but that would mean putting global labels in the debug output
+     before each exported type and each of its functions and static data
+     members.  */
+  if (write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG)
+    return;
+
   dfs_walk (TYPE_BINFO (type), dfs_debug_mark, dfs_debug_unmarkedp);
   for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
     {
@@ -3114,7 +2853,13 @@ envelope_add_decl (type, decl, values)
   tree name = DECL_NAME (decl);
   int dont_add = 0;
 
-  /* virtual base names are always unique. */
+  /* Yet Another Implicit Typename Kludge:  Since we don't tsubst
+     the members for partial instantiations, DECL_CONTEXT (decl) is wrong.
+     But pretend it's right for this function.  */
+  if (processing_template_decl)
+    type = DECL_REAL_CONTEXT (decl);
+
+  /* virtual base names are always unique.  */
   if (VBASE_NAME_P (name))
     *values = NULL_TREE;
 
@@ -3135,10 +2880,7 @@ envelope_add_decl (type, decl, values)
          warning ("in this context");
        }
 
-      context = (TREE_CODE (value) == FUNCTION_DECL
-                && DECL_VIRTUAL_P (value))
-       ? DECL_CLASS_CONTEXT (value)
-         : DECL_CONTEXT (value);
+      context = DECL_REAL_CONTEXT (value);
 
       if (context == type)
        {
@@ -3148,7 +2890,8 @@ envelope_add_decl (type, decl, values)
          else
            dont_add = 1;
        }
-      else if (context && TYPE_DERIVES_FROM (context, type))
+      else if (type == current_class_type
+              || DERIVED_FROM_P (context, type))
        {
          /* Don't add in *values to list */
          *values = NULL_TREE;
@@ -3166,7 +2909,8 @@ envelope_add_decl (type, decl, values)
          ? DECL_CLASS_CONTEXT (value)
            : DECL_CONTEXT (value);
 
-       if (context && TYPE_DERIVES_FROM (context, type))
+       if (type == current_class_type
+           || DERIVED_FROM_P (context, type))
          {
            /* remove *tmp from list */
            *tmp = TREE_CHAIN (*tmp);
@@ -3201,6 +2945,23 @@ envelope_add_decl (type, decl, values)
     }
 }
 
+/* Returns 1 iff BINFO is a base we shouldn't really be able to see into,
+   because it (or one of the intermediate bases) depends on template parms.  */
+
+static int
+dependent_base_p (binfo)
+     tree binfo;
+{
+  for (; binfo; binfo = BINFO_INHERITANCE_CHAIN (binfo))
+    {
+      if (TREE_TYPE (binfo) == current_class_type)
+       break;
+      if (uses_template_parms (TREE_TYPE (binfo)))
+       return 1;
+    }
+  return 0;
+}
+
 /* Add the instance variables which this class contributed to the
    current class binding contour.  When a redefinition occurs, if the
    redefinition is strictly within a single inheritance path, we just
@@ -3225,11 +2986,20 @@ dfs_pushdecls (binfo)
      tree binfo;
 {
   tree type = BINFO_TYPE (binfo);
-  tree fields, *methods, *end;
+  tree fields;
   tree method_vec;
+  int dummy = 0;
+
+  /* Only record types if we're a template base.  */
+  if (processing_template_decl && type != current_class_type
+      && dependent_base_p (binfo))
+    dummy = 1;
 
   for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields))
     {
+      if (dummy && TREE_CODE (fields) != TYPE_DECL)
+       continue;
+
       /* Unmark so that if we are in a constructor, and then find that
         this field was initialized by a base initializer,
         we can emit an error message.  */
@@ -3251,6 +3021,7 @@ dfs_pushdecls (binfo)
 
          /* If the class value is not an envelope of the kind described in
             the comment above, we create a new envelope.  */
+         maybe_push_cache_obstack ();
          if (class_value == NULL_TREE || TREE_CODE (class_value) != TREE_LIST
              || TREE_PURPOSE (class_value) == NULL_TREE
              || TREE_CODE (TREE_PURPOSE (class_value)) == IDENTIFIER_NODE)
@@ -3263,22 +3034,33 @@ dfs_pushdecls (binfo)
            }
 
          envelope_add_decl (type, fields, &TREE_PURPOSE (class_value));
+         pop_obstacks ();
        }
     }
 
-  method_vec = CLASSTYPE_METHOD_VEC (type);
-  if (method_vec != 0)
+  method_vec = CLASS_TYPE_P (type) ? CLASSTYPE_METHOD_VEC (type) : NULL_TREE;
+  if (method_vec && ! dummy)
     {
+      tree *methods;
+      tree *end;
+
       /* Farm out constructors and destructors.  */
-      methods = &TREE_VEC_ELT (method_vec, 1);
       end = TREE_VEC_END (method_vec);
 
-      while (methods != end)
+      for (methods = &TREE_VEC_ELT (method_vec, 2);
+          *methods && methods != end;
+          methods++)
        {
          /* This will cause lookup_name to return a pointer
             to the tree_list of possible methods of this name.  */
-         tree name = DECL_NAME (*methods);
-         tree class_value = IDENTIFIER_CLASS_VALUE (name);
+         tree name;
+         tree class_value;
+
+         
+         name = DECL_NAME (OVL_CURRENT (*methods));
+         class_value = IDENTIFIER_CLASS_VALUE (name);
+
+         maybe_push_cache_obstack ();
 
          /* If the class value is not an envelope of the kind described in
             the comment above, we create a new envelope.  */
@@ -3296,35 +3078,46 @@ dfs_pushdecls (binfo)
          /* Here we try to rule out possible ambiguities.
             If we can't do that, keep a TREE_LIST with possibly ambiguous
             decls in there.  */
-         maybe_push_cache_obstack ();
-         envelope_add_decl (type, *methods, &TREE_PURPOSE (class_value));
+         /* Arbitrarily choose the first function in the list.  This is OK
+            because this is only used for initial lookup; anything that
+            actually uses the function will look it up again.  */
+         envelope_add_decl (type, OVL_CURRENT (*methods),
+                            &TREE_PURPOSE (class_value));
          pop_obstacks ();
-
-         methods++;
        }
     }
-  SET_BINFO_MARKED (binfo);
+
+  /* We can't just use BINFO_MARKED because envelope_add_decl uses
+     DERIVED_FROM_P, which calls get_base_distance.  */
+  SET_BINFO_PUSHDECLS_MARKED (binfo);
 }
 
 /* Consolidate unique (by name) member functions.  */
+
 static void
 dfs_compress_decls (binfo)
      tree binfo;
 {
   tree type = BINFO_TYPE (binfo);
-  tree method_vec = CLASSTYPE_METHOD_VEC (type);
+  tree method_vec 
+    = CLASS_TYPE_P (type) ? CLASSTYPE_METHOD_VEC (type) : NULL_TREE;
 
-  if (method_vec != 0)
+  if (processing_template_decl && type != current_class_type
+      && dependent_base_p (binfo))
+    /* We only record types if we're a template base.  */;
+  else if (method_vec != 0)
     {
       /* Farm out constructors and destructors.  */
-      tree *methods = &TREE_VEC_ELT (method_vec, 1);
+      tree *methods;
       tree *end = TREE_VEC_END (method_vec);
 
-      for (; methods != end; methods++)
+      for (methods = &TREE_VEC_ELT (method_vec, 2); 
+          methods != end && *methods; methods++)
        {
          /* This is known to be an envelope of the kind described before
             dfs_pushdecls.  */
-         tree class_value = IDENTIFIER_CLASS_VALUE (DECL_NAME (*methods));
+         tree class_value = 
+           IDENTIFIER_CLASS_VALUE (DECL_NAME (OVL_CURRENT (*methods)));
          tree tmp = TREE_PURPOSE (class_value);
 
          /* This was replaced in scope by somebody else.  Just leave it
@@ -3334,13 +3127,13 @@ dfs_compress_decls (binfo)
 
          if (TREE_CHAIN (tmp) == NULL_TREE
              && TREE_VALUE (tmp)
-             && DECL_CHAIN (TREE_VALUE (tmp)) == NULL_TREE)
+             && OVL_NEXT (TREE_VALUE (tmp)) == NULL_TREE)
            {
              TREE_PURPOSE (class_value) = TREE_VALUE (tmp);
            }
        }
     }
-  CLEAR_BINFO_MARKED (binfo);
+  CLEAR_BINFO_PUSHDECLS_MARKED (binfo);
 }
 
 /* When entering the scope of a class, we cache all of the
@@ -3349,32 +3142,25 @@ dfs_compress_decls (binfo)
    with `error_mark_node' so that if they are encountered
    without explicit qualification, we can emit an error
    message.  */
+
 void
 push_class_decls (type)
      tree type;
 {
-  tree id;
   struct obstack *ambient_obstack = current_obstack;
-
   search_stack = push_search_level (search_stack, &search_obstack);
 
-  id = TYPE_IDENTIFIER (type);
-#if 0
-  if (IDENTIFIER_TEMPLATE (id) != 0)
-    {
-      tree tmpl = IDENTIFIER_TEMPLATE (id);
-      push_template_decls (DECL_ARGUMENTS (TREE_PURPOSE (tmpl)),
-                          TREE_VALUE (tmpl), 1);
-      overload_template_name (id, 1);
-    }
-#endif
+  /* Build up all the relevant bindings and such on the cache
+     obstack.  That way no memory is wasted when we throw away the
+     cache later.  */
+  maybe_push_cache_obstack ();
 
   /* Push class fields into CLASS_VALUE scope, and mark.  */
-  dfs_walk (TYPE_BINFO (type), dfs_pushdecls, unmarkedp);
+  dfs_walk (TYPE_BINFO (type), dfs_pushdecls, unmarked_pushdecls_p);
 
   /* Compress fields which have only a single entry
      by a given name, and unmark.  */
-  dfs_walk (TYPE_BINFO (type), dfs_compress_decls, markedp);
+  dfs_walk (TYPE_BINFO (type), dfs_compress_decls, marked_pushdecls_p);
 
   /* Open up all the closed envelopes and push the contained decls into
      class scope.  */
@@ -3395,7 +3181,31 @@ push_class_decls (type)
            {
              tree node = TREE_VALUE (new);
 
-             while (TREE_CODE (node) == TREE_LIST)
+             if (TREE_CODE (node) == TYPE_DECL
+                 && DECL_ARTIFICIAL (node)
+                 && IS_AGGR_TYPE (TREE_TYPE (node))
+                 && CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (node)))
+               {
+                 tree t = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (node));
+                 tree n = new;
+
+                 for (; n; n = TREE_CHAIN (n))
+                   {
+                     tree d = TREE_VALUE (n);
+                     if (TREE_CODE (d) == TYPE_DECL
+                         && DECL_ARTIFICIAL (node)
+                         && IS_AGGR_TYPE (TREE_TYPE (d))
+                         && CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (d))
+                         && CLASSTYPE_TI_TEMPLATE (TREE_TYPE (d)) == t)
+                       /* OK */;
+                     else
+                       break;
+                   }
+
+                 if (n == NULL_TREE)
+                   new = t;
+               }
+             else while (TREE_CODE (node) == TREE_LIST)
                node = TREE_VALUE (node);
              id = DECL_NAME (node);
            }
@@ -3412,10 +3222,15 @@ push_class_decls (type)
        pushdecl_class_level (new);
       closed_envelopes = TREE_CHAIN (closed_envelopes);
     }
+  
+  /* Undo the call to maybe_push_cache_obstack above.  */
+  pop_obstacks ();
+
   current_obstack = ambient_obstack;
 }
 
 /* Here's a subroutine we need because C lacks lambdas.  */
+
 static void
 dfs_unuse_fields (binfo)
      tree binfo;
@@ -3443,8 +3258,7 @@ unuse_fields (type)
 }
 
 void
-pop_class_decls (type)
-     tree type;
+pop_class_decls ()
 {
   /* We haven't pushed a search level when dealing with cached classes,
      so we'd better not try to pop it.  */
@@ -3456,89 +3270,228 @@ void
 print_search_statistics ()
 {
 #ifdef GATHER_STATISTICS
-  if (flag_memoize_lookups)
-    {
-      fprintf (stderr, "%d memoized contexts saved\n",
-              n_contexts_saved);
-      fprintf (stderr, "%d local tree nodes made\n", my_tree_node_counter);
-      fprintf (stderr, "%d local hash nodes made\n", my_memoized_entry_counter);
-      fprintf (stderr, "fields statistics:\n");
-      fprintf (stderr, "  memoized finds = %d; rejects = %d; (searches = %d)\n",
-              memoized_fast_finds[0], memoized_fast_rejects[0],
-              memoized_fields_searched[0]);
-      fprintf (stderr, "  memoized_adds = %d\n", memoized_adds[0]);
-      fprintf (stderr, "fnfields statistics:\n");
-      fprintf (stderr, "  memoized finds = %d; rejects = %d; (searches = %d)\n",
-              memoized_fast_finds[1], memoized_fast_rejects[1],
-              memoized_fields_searched[1]);
-      fprintf (stderr, "  memoized_adds = %d\n", memoized_adds[1]);
-    }
   fprintf (stderr, "%d fields searched in %d[%d] calls to lookup_field[_1]\n",
           n_fields_searched, n_calls_lookup_field, n_calls_lookup_field_1);
   fprintf (stderr, "%d fnfields searched in %d calls to lookup_fnfields\n",
           n_outer_fields_searched, n_calls_lookup_fnfields);
   fprintf (stderr, "%d calls to get_base_type\n", n_calls_get_base_type);
-#else
+#else /* GATHER_STATISTICS */
   fprintf (stderr, "no search statistics\n");
-#endif
+#endif /* GATHER_STATISTICS */
 }
 
 void
 init_search_processing ()
 {
   gcc_obstack_init (&search_obstack);
-  gcc_obstack_init (&type_obstack);
-  gcc_obstack_init (&type_obstack_entries);
-
-  /* This gives us room to build our chains of basetypes,
-     whether or not we decide to memoize them.  */
-  type_stack = push_type_level (0, &type_obstack);
   _vptr_name = get_identifier ("_vptr");
 }
 
 void
 reinit_search_statistics ()
 {
-  my_memoized_entry_counter = 0;
-  memoized_fast_finds[0] = 0;
-  memoized_fast_finds[1] = 0;
-  memoized_adds[0] = 0;
-  memoized_adds[1] = 0;
-  memoized_fast_rejects[0] = 0;
-  memoized_fast_rejects[1] = 0;
-  memoized_fields_searched[0] = 0;
-  memoized_fields_searched[1] = 0;
+#ifdef GATHER_STATISTICS
   n_fields_searched = 0;
   n_calls_lookup_field = 0, n_calls_lookup_field_1 = 0;
   n_calls_lookup_fnfields = 0, n_calls_lookup_fnfields_1 = 0;
   n_calls_get_base_type = 0;
   n_outer_fields_searched = 0;
   n_contexts_saved = 0;
+#endif /* GATHER_STATISTICS */
 }
 
+#define scratch_tree_cons expr_tree_cons
+
 static tree conversions;
-static void
+static tree
 add_conversions (binfo)
      tree binfo;
 {
   int i;
-  tree vec = CLASSTYPE_METHOD_VEC (BINFO_TYPE (binfo));
+  tree method_vec = CLASSTYPE_METHOD_VEC (BINFO_TYPE (binfo));
 
-  for (i = 1; i < TREE_VEC_LENGTH (vec); ++i)
+  for (i = 2; i < TREE_VEC_LENGTH (method_vec); ++i)
     {
-      tree tmp = TREE_VEC_ELT (vec, i);
-      if (! IDENTIFIER_TYPENAME_P (DECL_NAME (tmp)))
+      tree tmp = TREE_VEC_ELT (method_vec, i);
+      tree name;
+
+      if (!tmp || ! DECL_CONV_FN_P (OVL_CURRENT (tmp)))
        break;
-      conversions = tree_cons (DECL_NAME (tmp), TREE_TYPE (TREE_TYPE (tmp)),
-                              conversions);
+
+      name = DECL_NAME (OVL_CURRENT (tmp));
+
+      /* Make sure we don't already have this conversion.  */
+      if (! IDENTIFIER_MARKED (name))
+       {
+         conversions = scratch_tree_cons (binfo, tmp, conversions);
+         IDENTIFIER_MARKED (name) = 1;
+       }
     }
+  return NULL_TREE;
 }
 
 tree
 lookup_conversions (type)
      tree type;
 {
+  tree t;
+
   conversions = NULL_TREE;
-  dfs_walk (TYPE_BINFO (type), add_conversions, 0);
+
+  if (TYPE_SIZE (type))
+    breadth_first_search (TYPE_BINFO (type), add_conversions, 0);
+
+  for (t = conversions; t; t = TREE_CHAIN (t))
+    IDENTIFIER_MARKED (DECL_NAME (OVL_CURRENT (TREE_VALUE (t)))) = 0;
+
   return conversions;
 }
+
+/* Subroutine of get_template_base.  */
+
+static tree
+get_template_base_recursive (binfo, rval, template, via_virtual)
+     tree binfo, template, rval;
+     int via_virtual;
+{
+  tree binfos;
+  int i, n_baselinks;
+  tree type = BINFO_TYPE (binfo);
+
+  if (CLASSTYPE_TEMPLATE_INFO (type)
+      && CLASSTYPE_TI_TEMPLATE (type) == template)
+    {
+      if (rval == NULL_TREE || rval == type)
+       return type;
+      else
+       return error_mark_node;
+    }
+
+  binfos = BINFO_BASETYPES (binfo);
+  n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+
+  /* Process base types.  */
+  for (i = 0; i < n_baselinks; i++)
+    {
+      tree base_binfo = TREE_VEC_ELT (binfos, i);
+
+      /* Find any specific instance of a virtual base, when searching with
+        a binfo...  */
+      if (BINFO_MARKED (base_binfo) == 0)
+       {
+         int this_virtual = via_virtual || TREE_VIA_VIRTUAL (base_binfo);
+
+         /* When searching for a non-virtual, we cannot mark
+            virtually found binfos.  */
+         if (! this_virtual)
+           SET_BINFO_MARKED (base_binfo);
+
+         rval = get_template_base_recursive
+           (base_binfo, rval, template, this_virtual);
+         if (rval == error_mark_node)
+           return rval;
+       }
+    }
+
+  return rval;
+}
+
+/* Given a class template TEMPLATE and a class type or binfo node BINFO,
+   find the unique base type in BINFO that is an instance of TEMPLATE.
+   If there are more than one, return error_mark_node.  Used by unify.  */
+
+tree
+get_template_base (template, binfo)
+     register tree template, binfo;
+{
+  tree type = NULL_TREE, rval;
+
+  if (TREE_CODE (binfo) == TREE_VEC)
+    type = BINFO_TYPE (binfo);
+  else if (IS_AGGR_TYPE_CODE (TREE_CODE (binfo)))
+    {
+      type = complete_type (binfo);
+      binfo = TYPE_BINFO (type);
+    }
+  else
+    my_friendly_abort (92);
+
+  if (CLASSTYPE_TEMPLATE_INFO (type)
+      && CLASSTYPE_TI_TEMPLATE (type) == template)
+    return type;
+
+  rval = get_template_base_recursive (binfo, NULL_TREE, template, 0);
+  dfs_walk (binfo, dfs_unmark, markedp);
+
+  return rval;
+}
+
+/* Check whether the empty class indicated by EMPTY_BINFO is also present
+   at offset 0 in COMPARE_TYPE, and set found_overlap if so.  */
+
+static tree compare_type;
+static int found_overlap;
+static void
+dfs_check_overlap (empty_binfo)
+     tree empty_binfo;
+{
+  tree binfo;
+  for (binfo = TYPE_BINFO (compare_type); ; binfo = BINFO_BASETYPE (binfo, 0))
+    {
+      if (BINFO_TYPE (binfo) == BINFO_TYPE (empty_binfo))
+       {
+         found_overlap = 1;
+         break;
+       }
+      else if (BINFO_BASETYPES (binfo) == NULL_TREE)
+       break;
+    }
+}
+
+/* Trivial function to stop base traversal when we find something.  */
+
+static int
+dfs_no_overlap_yet (t)
+     tree t ATTRIBUTE_UNUSED;
+{
+  return found_overlap == 0;
+}
+
+/* Returns nonzero if EMPTY_TYPE or any of its bases can also be found at
+   offset 0 in NEXT_TYPE.  Used in laying out empty base class subobjects.  */
+
+int
+types_overlap_p (empty_type, next_type)
+     tree empty_type, next_type;
+{
+  if (! IS_AGGR_TYPE (next_type))
+    return 0;
+  compare_type = next_type;
+  found_overlap = 0;
+  dfs_walk (TYPE_BINFO (empty_type), dfs_check_overlap, dfs_no_overlap_yet);
+  return found_overlap;
+}
+
+/* Passed to dfs_search by binfo_for_vtable; determine if bvtable comes
+   from BINFO.  */
+
+static tree bvtable;
+static tree
+dfs_bfv_helper (binfo)
+     tree binfo;
+{
+  if (BINFO_VTABLE (binfo) == bvtable)
+    return binfo;
+  return NULL_TREE;
+}
+
+/* Given a vtable VARS, determine which binfo it comes from.  */
+
+tree
+binfo_for_vtable (vars)
+     tree vars;
+{
+  bvtable = vars;
+  return dfs_search (TYPE_BINFO (DECL_CONTEXT (vars)), dfs_bfv_helper,
+                    DECL_CONTEXT (vars));
+}