OSDN Git Service

Make DECL_CONTEXT mean the class in which a member function was
[pf3gnuchains/gcc-fork.git] / gcc / cp / search.c
index 8c335b0..7886f48 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-97, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1987, 89, 92-97, 1998, 1999, 2000 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
@@ -36,7 +36,6 @@ Boston, MA 02111-1307, USA.  */
 #define obstack_chunk_free free
 
 extern struct obstack *current_obstack;
-extern tree abort_fndecl;
 
 #include "stack.h"
 
@@ -76,61 +75,79 @@ pop_stack_level (stack)
 #define search_level stack_level
 static struct search_level *search_stack;
 
-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 tree next_baselink PARAMS ((tree));
+static tree get_vbase_1 PARAMS ((tree, tree, unsigned int *));
+static tree lookup_field_1 PARAMS ((tree, tree));
+static tree convert_pointer_to_single_level PARAMS ((tree, tree));
+static int lookup_fnfields_here PARAMS ((tree, tree));
+static int is_subobject_of_p PARAMS ((tree, tree));
+static int hides PARAMS ((tree, tree));
+static tree virtual_context PARAMS ((tree, tree, tree));
+static tree dfs_check_overlap PARAMS ((tree, void *));
+static tree dfs_no_overlap_yet PARAMS ((tree, void *));
 static int get_base_distance_recursive
-       PROTO((tree, int, int, int, int *, tree *, tree,
+       PARAMS ((tree, int, int, int, int *, tree *, tree,
               int, int *, int, int));
+static int dynamic_cast_base_recurse PARAMS ((tree, tree, int, tree *));
 static void expand_upcast_fixups 
-       PROTO((tree, tree, tree, tree, tree, tree, tree *));
+       PARAMS ((tree, tree, tree, tree, tree, tree, tree *));
 static void fixup_virtual_upcast_offsets
-       PROTO((tree, tree, int, int, tree, tree, tree, tree,
+       PARAMS ((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 tree marked_vtable_pathp PARAMS ((tree, void *));
+static tree unmarked_vtable_pathp PARAMS ((tree, void *));
+static tree marked_new_vtablep PARAMS ((tree, void *));
+static tree unmarked_new_vtablep PARAMS ((tree, void *));
+static tree marked_pushdecls_p PARAMS ((tree, void *));
+static tree unmarked_pushdecls_p PARAMS ((tree, void *));
+#if 0
+static tree dfs_debug_unmarkedp PARAMS ((tree, void *));
+static tree dfs_debug_mark PARAMS ((tree, void *));
+#endif
+static tree dfs_find_vbases PARAMS ((tree, void *));
+static tree dfs_clear_vbase_slots PARAMS ((tree, void *));
+static tree dfs_init_vbase_pointers PARAMS ((tree, void *));
+static tree dfs_get_vbase_types PARAMS ((tree, void *));
+static tree dfs_push_type_decls PARAMS ((tree, void *));
+static tree dfs_push_decls PARAMS ((tree, void *));
+static tree dfs_unuse_fields PARAMS ((tree, void *));
+static tree add_conversions PARAMS ((tree, void *));
+static tree get_virtuals_named_this PARAMS ((tree, tree));
+static tree get_virtual_destructor PARAMS ((tree, void *));
+static tree tree_has_any_destructor_p PARAMS ((tree, void *));
+static int covariant_return_p PARAMS ((tree, tree));
+static int check_final_overrider PARAMS ((tree, tree));
 static struct search_level *push_search_level
-       PROTO((struct stack_level *, struct obstack *));
+       PARAMS ((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_ptr_intermediate, vbase_decl_ptr;
-static tree vbase_init_result;
+       PARAMS ((struct stack_level *));
+static tree bfs_walk
+       PARAMS ((tree, tree (*) (tree, void *), tree (*) (tree, void *),
+              void *));
+static tree lookup_field_queue_p PARAMS ((tree, void *));
+static tree lookup_field_r PARAMS ((tree, void *));
+static tree get_virtuals_named_this_r PARAMS ((tree, void *));
+static tree context_for_name_lookup PARAMS ((tree));
+static tree canonical_binfo PARAMS ((tree));
+static tree shared_marked_p PARAMS ((tree, void *));
+static tree shared_unmarked_p PARAMS ((tree, void *));
+static int  dependent_base_p PARAMS ((tree));
+static tree dfs_accessible_queue_p PARAMS ((tree, void *));
+static tree dfs_accessible_p PARAMS ((tree, void *));
+static tree dfs_access_in_type PARAMS ((tree, void *));
+static tree access_in_type PARAMS ((tree, tree));
+static tree dfs_canonical_queue PARAMS ((tree, void *));
+static tree dfs_assert_unmarked_p PARAMS ((tree, void *));
+static void assert_canonical_unmarked PARAMS ((tree));
+static int protected_accessible_p PARAMS ((tree, tree, tree, tree));
+static int friend_accessible_p PARAMS ((tree, tree, tree, tree));
+static void setup_class_bindings PARAMS ((tree, int));
+static int template_self_reference_p PARAMS ((tree, tree));
+static void fixup_all_virtual_upcast_offsets PARAMS ((tree, tree));
+static tree dfs_mark_primary_bases PARAMS ((tree, void *));
+static tree get_shared_vbase_if_not_primary PARAMS ((tree, void *));
+static tree dfs_find_vbase_instance PARAMS ((tree, void *));
+static tree dfs_get_pure_virtuals PARAMS ((tree, void *));
 
 /* Allocate a level of searching.  */
 
@@ -156,8 +173,6 @@ pop_search_level (obstack)
   return stack;
 }
 \f
-static tree _vptr_name;
-
 /* Variables for gathering statistics.  */
 #ifdef GATHER_STATISTICS
 static int n_fields_searched;
@@ -168,9 +183,6 @@ static int n_outer_fields_searched;
 static int n_contexts_saved;
 #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;
 \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
@@ -233,7 +245,7 @@ get_vbase (parent, binfo)
    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.  */
 
-static tree
+tree
 convert_pointer_to_vbase (type, expr)
      tree type;
      tree expr;
@@ -469,8 +481,7 @@ get_base_distance (parent, binfo, protect, path_ptr)
      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)))
+      && parent == BINFO_FOR_VBASE (BINFO_TYPE (parent), type))
     {
       my_friendly_assert (BINFO_INHERITANCE_CHAIN (parent) == binfo, 980827);
       new_binfo = parent;
@@ -482,6 +493,79 @@ get_base_distance (parent, binfo, protect, path_ptr)
   return rval;
 }
 
+/* Worker function for get_dynamic_cast_base_type.  */
+
+static int
+dynamic_cast_base_recurse (subtype, binfo, via_virtual, offset_ptr)
+     tree subtype;
+     tree binfo;
+     int via_virtual;
+     tree *offset_ptr;
+{
+  tree binfos;
+  int i, n_baselinks;
+  int worst = -2;
+  
+  if (BINFO_TYPE (binfo) == subtype)
+    {
+      if (via_virtual)
+        return -1;
+      else
+        {
+          *offset_ptr = BINFO_OFFSET (binfo);
+          return 0;
+        }
+    }
+  
+  binfos = BINFO_BASETYPES (binfo);
+  n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+  for (i = 0; i < n_baselinks; i++)
+    {
+      tree base_binfo = TREE_VEC_ELT (binfos, i);
+      int rval;
+      
+      if (!TREE_VIA_PUBLIC (base_binfo))
+        continue;
+      rval = dynamic_cast_base_recurse
+             (subtype, base_binfo,
+              via_virtual || TREE_VIA_VIRTUAL (base_binfo), offset_ptr);
+      if (worst == -2)
+        worst = rval;
+      else if (rval >= 0)
+        worst = worst >= 0 ? -3 : worst;
+      else if (rval == -1)
+        worst = -1;
+      else if (rval == -3 && worst != -1)
+        worst = -3;
+    }
+  return worst;
+}
+
+/* The dynamic cast runtime needs a hint about how the static SUBTYPE type
+   started from is related to the required TARGET type, in order to optimize
+   the inheritance graph search. This information is independant of the
+   current context, and ignores private paths, hence get_base_distance is
+   inappropriate. Return a TREE specifying the base offset, BOFF.
+   BOFF >= 0, there is only one public non-virtual SUBTYPE base at offset BOFF,
+      and there are no public virtual SUBTYPE bases.
+   BOFF == -1, SUBTYPE occurs as multiple public virtual or non-virtual bases.
+   BOFF == -2, SUBTYPE is not a public base.
+   BOFF == -3, SUBTYPE occurs as multiple public non-virtual bases.  */
+
+tree
+get_dynamic_cast_base_type (subtype, target)
+     tree subtype;
+     tree target;
+{
+  tree offset = NULL_TREE;
+  int boff = dynamic_cast_base_recurse (subtype, TYPE_BINFO (target),
+                                        0, &offset);
+  
+  if (!boff)
+    return offset;
+  return build_int_2 (boff, -1);
+}
+
 /* Search for a member with name NAME in a multiple inheritance lattice
    specified by TYPE.  If it does not exist, return NULL_TREE.
    If the member is ambiguously referenced, return `error_mark_node'.
@@ -505,6 +589,41 @@ lookup_field_1 (type, name)
        of fields!)  */
     return NULL_TREE;
 
+  if (TYPE_NAME (type)
+      && DECL_LANG_SPECIFIC (TYPE_NAME (type))
+      && DECL_SORTED_FIELDS (TYPE_NAME (type)))
+    {
+      tree *fields = &TREE_VEC_ELT (DECL_SORTED_FIELDS (TYPE_NAME (type)), 0);
+      int lo = 0, hi = TREE_VEC_LENGTH (DECL_SORTED_FIELDS (TYPE_NAME (type)));
+      int i;
+
+      while (lo < hi)
+       {
+         i = (lo + hi) / 2;
+
+#ifdef GATHER_STATISTICS
+         n_fields_searched++;
+#endif /* GATHER_STATISTICS */
+
+         if (DECL_NAME (fields[i]) > name)
+           hi = i;
+         else if (DECL_NAME (fields[i]) < name)
+           lo = i + 1;
+         else
+           {
+             /* We might have a nested class and a field with the
+                same name; we sorted them appropriately via
+                field_decl_cmp, so just look for the last field with
+                this name.  */
+             while (i + 1 < hi
+                    && DECL_NAME (fields[i+1]) == name)
+               ++i;
+             return fields[i];
+           }
+       }
+      return NULL_TREE;
+    }
+
   field = TYPE_FIELDS (type);
 
 #ifdef GATHER_STATISTICS
@@ -517,13 +636,20 @@ lookup_field_1 (type, name)
 #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)
+         && ANON_AGGR_TYPE_P (TREE_TYPE (field)))
        {
          tree temp = lookup_field_1 (TREE_TYPE (field), 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)
@@ -534,11 +660,11 @@ lookup_field_1 (type, name)
       field = TREE_CHAIN (field);
     }
   /* Not found.  */
-  if (name == _vptr_name)
+  if (name == vptr_identifier)
     {
       /* Give the user what s/he thinks s/he wants.  */
-      if (TYPE_VIRTUAL_P (type))
-       return CLASSTYPE_VFIELD (type);
+      if (TYPE_POLYMORPHIC_P (type))
+       return TYPE_VFIELD (type);
     }
   return NULL_TREE;
 }
@@ -566,215 +692,522 @@ current_scope ()
     return current_class_type;
   if (current_class_type == NULL_TREE)
     return current_function_decl;
-  if (DECL_CLASS_CONTEXT (current_function_decl) == current_class_type)
+  if ((DECL_FUNCTION_MEMBER_P (current_function_decl)
+       && same_type_p (DECL_CONTEXT (current_function_decl),
+                      current_class_type))
+      || (DECL_FRIEND_CONTEXT (current_function_decl)
+         && same_type_p (DECL_FRIEND_CONTEXT (current_function_decl),
+                         current_class_type)))
     return current_function_decl;
 
   return current_class_type;
 }
 
-/* Compute the access of FIELD.  This is done by computing
-   the access available to each type in BASETYPES (which comes
-   as a list of [via_public/basetype] in reverse order, namely base
-   class before derived class).  The first one which defines a
-   access defines the access for the field.  Otherwise, the
-   access of the field is that which occurs normally.
+/* Returns non-zero if we are currently in a function scope.  Note
+   that this function returns zero if we are within a local class, but
+   not within a member function body of the local class.  */
 
-   Uses global variables CURRENT_CLASS_TYPE and
-   CURRENT_FUNCTION_DECL to use friend relationships
-   if necessary.
+int
+at_function_scope_p ()
+{
+  tree cs = current_scope ();
+  return cs && TREE_CODE (cs) == FUNCTION_DECL;
+}
 
-   This will be static when lookup_fnfield comes into this file.
+/* Return the scope of DECL, as appropriate when doing name-lookup.  */
 
-   access_public_node means that the field can be accessed by the current lexical
-   scope.
+static tree
+context_for_name_lookup (decl)
+     tree decl;
+{
+  /* [class.union]
+     
+     For the purposes of name lookup, after the anonymous union
+     definition, the members of the anonymous union are considered to
+     have been defined in the scope in which teh anonymous union is
+     declared.  */ 
+  tree context = CP_DECL_CONTEXT (decl);
+
+  while (TYPE_P (context) && ANON_AGGR_TYPE_P (context))
+    context = TYPE_CONTEXT (context);
+  if (!context)
+    context = global_namespace;
 
-   access_protected_node means that the field cannot be accessed by the current
-   lexical scope because it is protected.
+  return context;
+}
 
-   access_private_node means that the field cannot be accessed by the current
-   lexical scope because it is private.  */
+/* Return a canonical BINFO if BINFO is a virtual base, or just BINFO
+   otherwise.  */
 
-#if 0
-#define PUBLIC_RETURN return (DECL_PUBLIC (field) = 1), access_public_node
-#define PROTECTED_RETURN return (DECL_PROTECTED (field) = 1), access_protected_node
-#define PRIVATE_RETURN return (DECL_PRIVATE (field) = 1), access_private_node
-#else
-#define PUBLIC_RETURN return access_public_node
-#define PROTECTED_RETURN return access_protected_node
-#define PRIVATE_RETURN return access_private_node
-#endif
+static tree
+canonical_binfo (binfo)
+     tree binfo;
+{
+  return (TREE_VIA_VIRTUAL (binfo)
+         ? TYPE_BINFO (BINFO_TYPE (binfo)) : binfo);
+}
 
-#if 0
-/* Disabled with DECL_PUBLIC &c.  */
-static tree previous_scope = NULL_TREE;
-#endif
+/* A queue function that simply ensures that we walk into the
+   canonical versions of virtual bases.  */
 
-tree
-compute_access (basetype_path, field)
-     tree basetype_path, field;
+static tree
+dfs_canonical_queue (binfo, data)
+     tree binfo;
+     void *data ATTRIBUTE_UNUSED;
 {
-  tree access;
-  tree types;
-  tree context;
-  int protected_ok, via_protected;
-  extern int flag_access_control;
-#if 1
-  /* 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)));
-
-  if (! flag_access_control)
-    return access_public_node;
+  return canonical_binfo (binfo);
+}
 
-  /* The field lives in the current class.  */
-  if (BINFO_TYPE (basetype_path) == current_class_type)
-    return access_public_node;
+/* Called via dfs_walk from assert_canonical_unmarked.  */
 
-#if 0
-  /* Disabled until pushing function scope clears these out.  If ever.  */
-  /* Make these special cases fast.  */
-  if (current_scope () == previous_scope)
-    {
-      if (DECL_PUBLIC (field))
-       return access_public_node;
-      if (DECL_PROTECTED (field))
-       return access_protected_node;
-      if (DECL_PRIVATE (field))
-       return access_private_node;
-    }
-#endif
+static tree
+dfs_assert_unmarked_p (binfo, data)
+     tree binfo;
+     void *data ATTRIBUTE_UNUSED;
+{
+  my_friendly_assert (!BINFO_MARKED (binfo), 0);
+  return NULL_TREE;
+}
 
-  /* We don't currently support access control on nested types.  */
-  if (TREE_CODE (field) == TYPE_DECL)
-    return access_public_node;
+/* Asserts that all the nodes below BINFO (using the canonical
+   versions of virtual bases) are unmarked.  */
 
-  previous_scope = current_scope ();
+static void
+assert_canonical_unmarked (binfo)
+     tree binfo;
+{
+  dfs_walk (binfo, dfs_assert_unmarked_p, dfs_canonical_queue, 0);
+}
 
-  context = DECL_REAL_CONTEXT (field);
+/* If BINFO is marked, return a canonical version of BINFO.
+   Otherwise, return NULL_TREE.  */
 
-  /* 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.  */
-  if (context && ANON_UNION_TYPE_P (context)
-      && TREE_CODE (field) == FIELD_DECL)
-    context = TYPE_CONTEXT (context);
+static tree
+shared_marked_p (binfo, data)
+     tree binfo;
+     void *data;
+{
+  binfo = canonical_binfo (binfo);
+  return markedp (binfo, data);
+}
 
-  /* Virtual function tables are never private.  But we should know that
-     we are looking for this, and not even try to hide it.  */
-  if (DECL_NAME (field) && VFIELD_NAME_P (DECL_NAME (field)) == 1)
-    PUBLIC_RETURN;
-
-  /* Member found immediately within object.  */
-  if (BINFO_INHERITANCE_CHAIN (basetype_path) == NULL_TREE)
-    {
-      /* Are we (or an enclosing scope) friends with the class that has
-         FIELD? */
-      if (is_friend (context, previous_scope))
-       PUBLIC_RETURN;
-
-      /* If it's private, it's private, you letch.  */
-      if (TREE_PRIVATE (field))
-       PRIVATE_RETURN;
-
-      /* ARM $11.5.  Member functions of a derived class can access the
-        non-static protected members of a base class only through a
-        pointer to the derived class, a reference to it, or an object
-        of it. Also any subsequently derived classes also have
-        access.  */
-      else if (TREE_PROTECTED (field))
-       {
-         if (current_class_type
-             && (static_mem || DECL_CONSTRUCTOR_P (field))
-             && ACCESSIBLY_DERIVED_FROM_P (context, current_class_type))
-           PUBLIC_RETURN;
-         else
-           PROTECTED_RETURN;
-       }
-      else
-       PUBLIC_RETURN;
-    }
+/* If BINFO is not marked, return a canonical version of BINFO.
+   Otherwise, return NULL_TREE.  */
 
-  /* must reverse more than one element */
-  basetype_path = reverse_path (basetype_path);
-  types = basetype_path;
-  via_protected = 0;
-  access = access_default_node;
-  protected_ok = static_mem && current_class_type
-    && ACCESSIBLY_DERIVED_FROM_P (BINFO_TYPE (types), current_class_type);
+static tree
+shared_unmarked_p (binfo, data)
+     tree binfo;
+     void *data;
+{
+  binfo = canonical_binfo (binfo);
+  return unmarkedp (binfo, data);
+}
 
-  while (1)
-    {
-      tree member;
-      tree binfo = types;
-      tree type = BINFO_TYPE (binfo);
-      int private_ok = 0;
+/* Called from access_in_type via dfs_walk.  Calculate the access to
+   DATA (which is really a DECL) in BINFO.  */
 
-      /* Friends of a class can see protected members of its bases.
-         Note that classes are their own friends.  */
-      if (is_friend (type, previous_scope))
-       {
-         protected_ok = 1;
-         private_ok = 1;
-       }
+static tree
+dfs_access_in_type (binfo, data)
+     tree binfo;
+     void *data;
+{
+  tree decl = (tree) data;
+  tree type = BINFO_TYPE (binfo);
+  tree access = NULL_TREE;
 
-      member = purpose_member (type, DECL_ACCESS (field));
-      if (member)
+  if (context_for_name_lookup (decl) == type)
+    {
+      /* If we have desceneded to the scope of DECL, just note the
+        appropriate access.  */
+      if (TREE_PRIVATE (decl))
+       access = access_private_node;
+      else if (TREE_PROTECTED (decl))
+       access = access_protected_node;
+      else
+       access = access_public_node;
+    }
+  else 
+    {
+      /* First, check for an access-declaration that gives us more
+        access to the DECL.  The CONST_DECL for an enumeration
+        constant will not have DECL_LANG_SPECIFIC, and thus no
+        DECL_ACCESS.  */
+      if (DECL_LANG_SPECIFIC (decl))
        {
-         access = TREE_VALUE (member);
-         break;
+         access = purpose_member (type, DECL_ACCESS (decl));
+         if (access)
+           access = TREE_VALUE (access);
        }
 
-      types = BINFO_INHERITANCE_CHAIN (types);
-
-      /* If the next type was VIA_PROTECTED, then fields of all remaining
-        classes past that one are *at least* protected.  */
-      if (types)
+      if (!access)
        {
-         if (TREE_VIA_PROTECTED (types))
-           via_protected = 1;
-         else if (! TREE_VIA_PUBLIC (types) && ! private_ok)
+         int i;
+         int n_baselinks;
+         tree binfos;
+         
+         /* Otherwise, scan our baseclasses, and pick the most favorable
+            access.  */
+         binfos = BINFO_BASETYPES (binfo);
+         n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+         for (i = 0; i < n_baselinks; ++i)
            {
-             access = access_private_node;
-             break;
+             tree base_binfo = TREE_VEC_ELT (binfos, i);
+             tree base_access = TREE_CHAIN (canonical_binfo (base_binfo));
+
+             if (!base_access || base_access == access_private_node)
+               /* If it was not accessible in the base, or only
+                  accessible as a private member, we can't access it
+                  all.  */
+               base_access = NULL_TREE;
+             else if (TREE_VIA_PROTECTED (base_binfo))
+               /* Public and protected members in the base are
+                  protected here.  */
+               base_access = access_protected_node;
+             else if (!TREE_VIA_PUBLIC (base_binfo))
+               /* Public and protected members in the base are
+                  private here.  */
+               base_access = access_private_node;
+
+             /* See if the new access, via this base, gives more
+                access than our previous best access.  */
+             if (base_access &&
+                 (base_access == access_public_node
+                  || (base_access == access_protected_node
+                      && access != access_public_node)
+                  || (base_access == access_private_node
+                      && !access)))
+               {
+                 access = base_access;
+
+                 /* If the new access is public, we can't do better.  */
+                 if (access == access_public_node)
+                   break;
+               }
            }
        }
-      else
-       break;
     }
 
-  /* No special visibilities apply.  Use normal rules.  */
+  /* Note the access to DECL in TYPE.  */
+  TREE_CHAIN (binfo) = access;
+
+  /* Mark TYPE as visited so that if we reach it again we do not
+     duplicate our efforts here.  */
+  SET_BINFO_MARKED (binfo);
+
+  return NULL_TREE;
+}
+
+/* Return the access to DECL in TYPE.  */
+
+static tree 
+access_in_type (type, decl)
+     tree type;
+     tree decl;
+{
+  tree binfo = TYPE_BINFO (type);
+
+  /* We must take into account
+
+       [class.paths]
+
+       If a name can be reached by several paths through a multiple
+       inheritance graph, the access is that of the path that gives
+       most access.  
+
+    The algorithm we use is to make a post-order depth-first traversal
+    of the base-class hierarchy.  As we come up the tree, we annotate
+    each node with the most lenient access.  */
+  dfs_walk_real (binfo, 0, dfs_access_in_type, shared_unmarked_p, decl);
+  dfs_walk (binfo, dfs_unmark, shared_marked_p,  0);
+  assert_canonical_unmarked (binfo);
+
+  return TREE_CHAIN (binfo);
+}
+
+/* Called from dfs_accessible_p via dfs_walk.  */
+
+static tree
+dfs_accessible_queue_p (binfo, data)
+     tree binfo;
+     void *data ATTRIBUTE_UNUSED;
+{
+  if (BINFO_MARKED (binfo))
+    return NULL_TREE;
+
+  /* If this class is inherited via private or protected inheritance,
+     then we can't see it, unless we are a friend of the subclass.  */
+  if (!TREE_VIA_PUBLIC (binfo)
+      && !is_friend (BINFO_TYPE (BINFO_INHERITANCE_CHAIN (binfo)),
+                    current_scope ()))
+    return NULL_TREE;
+
+  return canonical_binfo (binfo);
+}
+
+/* Called from dfs_accessible_p via dfs_walk.  */
+
+static tree
+dfs_accessible_p (binfo, data)
+     tree binfo;
+     void *data;
+{
+  int protected_ok = data != 0;
+  tree access;
+
+  /* We marked the binfos while computing the access in each type.
+     So, we unmark as we go now.  */
+  SET_BINFO_MARKED (binfo);
+
+  access = TREE_CHAIN (binfo);
+  if (access == access_public_node
+      || (access == access_protected_node && protected_ok))
+    return binfo;
+  else if (access && is_friend (BINFO_TYPE (binfo), current_scope ()))
+    return binfo;
+
+  return NULL_TREE;
+}
+
+/* Returns non-zero if it is OK to access DECL when named in TYPE
+   through an object indiated by BINFO in the context of DERIVED.  */
+
+static int
+protected_accessible_p (type, decl, derived, binfo)
+     tree type;
+     tree decl;
+     tree derived;
+     tree binfo;
+{
+  tree access;
+
+  /* We're checking this clause from [class.access.base]
+
+       m as a member of N is protected, and the reference occurs in a
+       member or friend of class N, or in a member or friend of a
+       class P derived from N, where m as a member of P is private or
+       protected.  
+
+    If DERIVED isn't derived from TYPE, then it certainly does not
+    apply.  */
+  if (!DERIVED_FROM_P (type, derived))
+    return 0;
+
+  access = access_in_type (derived, decl);
+  if (same_type_p (derived, type))
+    {
+      if (access != access_private_node)
+       return 0;
+    }
+  else if (access != access_private_node
+          && access != access_protected_node)
+    return 0;
+  
+  /* [class.protected]
+
+     When a friend or a member function of a derived class references
+     a protected nonstatic member of a base class, an access check
+     applies in addition to those described earlier in clause
+     _class.access_.4) Except when forming a pointer to member
+     (_expr.unary.op_), the access must be through a pointer to,
+     reference to, or object of the derived class itself (or any class
+     derived from that class) (_expr.ref_).  If the access is to form
+     a pointer to member, the nested-name-specifier shall name the
+     derived class (or any class derived from that class).  */
+  if (DECL_NONSTATIC_MEMBER_P (decl))
+    {
+      /* We can tell through what the reference is occurring by
+        chasing BINFO up to the root.  */
+      tree t = binfo;
+      while (BINFO_INHERITANCE_CHAIN (t))
+       t = BINFO_INHERITANCE_CHAIN (t);
+      
+      if (!DERIVED_FROM_P (derived, BINFO_TYPE (t)))
+       return 0;
+    }
+
+  return 1;
+}
+
+/* Returns non-zero if SCOPE is a friend of a type which would be able
+   to acces DECL, named in TYPE, through the object indicated by
+   BINFO.  */
+
+static int
+friend_accessible_p (scope, type, decl, binfo)
+     tree scope;
+     tree type;
+     tree decl;
+     tree binfo;
+{
+  tree befriending_classes;
+  tree t;
+
+  if (!scope)
+    return 0;
+
+  if (TREE_CODE (scope) == FUNCTION_DECL
+      || DECL_FUNCTION_TEMPLATE_P (scope))
+    befriending_classes = DECL_BEFRIENDING_CLASSES (scope);
+  else if (TYPE_P (scope))
+    befriending_classes = CLASSTYPE_BEFRIENDING_CLASSES (scope);
+  else
+    return 0;
+
+  for (t = befriending_classes; t; t = TREE_CHAIN (t))
+    if (protected_accessible_p (type, decl, TREE_VALUE (t), binfo))
+      return 1;
+
+  /* Nested classes are implicitly friends of their enclosing types, as
+     per core issue 45 (this is a change from the standard).  */
+  if (TYPE_P (scope))
+    for (t = TYPE_CONTEXT (scope); t && TYPE_P (t); t = TYPE_CONTEXT (t))
+      if (protected_accessible_p (type, decl, t, binfo))
+       return 1;
+
+  if (TREE_CODE (scope) == FUNCTION_DECL
+      || DECL_FUNCTION_TEMPLATE_P (scope))
+    {
+      /* Perhaps this SCOPE is a member of a class which is a 
+        friend.  */ 
+      if (DECL_CLASS_SCOPE_P (decl)
+         && friend_accessible_p (DECL_CONTEXT (scope), type,
+                                 decl, binfo))
+       return 1;
+
+      /* Or an instantiation of something which is a friend.  */
+      if (DECL_TEMPLATE_INFO (scope))
+       return friend_accessible_p (DECL_TI_TEMPLATE (scope),
+                                   type, decl, binfo);
+    }
+  else if (CLASSTYPE_TEMPLATE_INFO (scope))
+    return friend_accessible_p (CLASSTYPE_TI_TEMPLATE (scope),
+                               type, decl, binfo);
+
+  return 0;
+}
+
+/* Perform access control on TYPE_DECL VAL, which was looked up in TYPE.
+   This is fairly complex, so here's the design:
+
+   The lang_extdef nonterminal sets type_lookups to NULL_TREE before we
+     start to process a top-level declaration.
+   As we process the decl-specifier-seq for the declaration, any types we
+     see that might need access control are passed to type_access_control,
+     which defers checking by adding them to type_lookups.
+   When we are done with the decl-specifier-seq, we record the lookups we've
+     seen in the lookups field of the typed_declspecs nonterminal.
+   When we process the first declarator, either in parse_decl or
+     begin_function_definition, we call initial_deferred_type_access_control,
+     which processes any lookups from within that declarator, stores the
+     lookups from the decl-specifier-seq in current_type_lookups, and sets
+     type_lookups to error_mark_node.
+   Subsequent declarators process current_type_lookups again to make sure
+     that the types are accessible to all of the declarators.  Any lookups
+     within subsequent declarators are processed immediately.
+   Within a function, type_lookups is error_mark_node, so all lookups are
+     processed immediately.  */
+
+void
+type_access_control (type, val)
+     tree type, val;
+{
+  if (val == NULL_TREE || TREE_CODE (val) != TYPE_DECL
+      || ! DECL_CLASS_SCOPE_P (val))
+    return;
+
+  if (type_lookups == error_mark_node)
+    enforce_access (type, val);
+  else if (! accessible_p (type, val))
+    type_lookups = tree_cons (type, val, type_lookups);
+}
+
+/* DECL is a declaration from a base class of TYPE, which was the
+   class used to name DECL.  Return non-zero if, in the current
+   context, DECL is accessible.  If TYPE is actually a BINFO node,
+   then we can tell in what context the access is occurring by looking
+   at the most derived class along the path indicated by BINFO.  */
+
+int 
+accessible_p (type, decl)
+     tree type;
+     tree decl;
+     
+{
+  tree binfo;
+  tree t;
+
+  /* Non-zero if it's OK to access DECL if it has protected
+     accessibility in TYPE.  */
+  int protected_ok = 0;
 
-  if (access == access_default_node)
+  /* If we're not checking access, everything is accessible.  */
+  if (!flag_access_control)
+    return 1;
+
+  /* If this declaration is in a block or namespace scope, there's no
+     access control.  */
+  if (!TYPE_P (context_for_name_lookup (decl)))
+    return 1;
+
+  if (!TYPE_P (type))
     {
-      if (is_friend (context, previous_scope))
-       access = access_public_node;
-      else if (TREE_PRIVATE (field))
-       access = access_private_node;
-      else if (TREE_PROTECTED (field))
-       access = access_protected_node;
-      else
-       access = access_public_node;
+      binfo = type;
+      type = BINFO_TYPE (type);
     }
+  else
+    binfo = TYPE_BINFO (type);
 
-  if (access == access_public_node && via_protected)
-    access = access_protected_node;
+  /* [class.access.base]
 
-  if (access == access_protected_node && protected_ok)
-    access = access_public_node;
+     A member m is accessible when named in class N if
 
-#if 0
-  if (access == access_public_node)
-    DECL_PUBLIC (field) = 1;
-  else if (access == access_protected_node)
-    DECL_PROTECTED (field) = 1;
-  else if (access == access_private_node)
-    DECL_PRIVATE (field) = 1;
-  else my_friendly_abort (96);
-#endif
-  return access;
+     --m as a member of N is public, or
+
+     --m as a member of N is private, and the reference occurs in a
+       member or friend of class N, or
+
+     --m as a member of N is protected, and the reference occurs in a
+       member or friend of class N, or in a member or friend of a
+       class P derived from N, where m as a member of P is private or
+       protected, or
+
+     --there exists a base class B of N that is accessible at the point
+       of reference, and m is accessible when named in class B.  
+
+    We walk the base class hierarchy, checking these conditions.  */
+
+  /* Figure out where the reference is occurring.  Check to see if
+     DECL is private or protected in this scope, since that will
+     determine whether protected access in TYPE allowed.  */
+  if (current_class_type)
+    protected_ok 
+      = protected_accessible_p (type, decl, current_class_type,
+                               binfo);
+
+  /* Now, loop through the classes of which we are a friend.  */
+  if (!protected_ok)
+    protected_ok = friend_accessible_p (current_scope (),
+                                       type, decl, binfo);
+
+  /* Standardize the binfo that access_in_type will use.  We don't
+     need to know what path was chosen from this point onwards.  */
+  binfo = TYPE_BINFO (type);
+
+  /* Compute the accessibility of DECL in the class hierarchy
+     dominated by type.  */
+  access_in_type (type, decl);
+  /* Walk the hierarchy again, looking for a base class that allows
+     access.  */
+  t = dfs_walk (binfo, dfs_accessible_p, 
+               dfs_accessible_queue_p,
+               protected_ok ? &protected_ok : 0);
+  /* Clear any mark bits.  Note that we have to walk the whole tree
+     here, since we have aborted the previous walk from some point
+     deep in the tree.  */
+  dfs_walk (binfo, dfs_unmark, dfs_canonical_queue,  0);
+  assert_canonical_unmarked (binfo);
+
+  return t != NULL_TREE;
 }
 
 /* Routine to see if the sub-object denoted by the binfo PARENT can be
@@ -786,18 +1219,31 @@ static int
 is_subobject_of_p (parent, binfo)
      tree parent, binfo;
 {
-  tree binfos = BINFO_BASETYPES (binfo);
-  int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+  tree binfos;
+  int i, n_baselinks;
+
+  /* We want to canonicalize for comparison purposes.  But, when we
+     iterate through basetypes later, we want the binfos from the
+     original hierarchy.  That's why we have to calculate BINFOS
+     first, and then canonicalize.  */
+  binfos = BINFO_BASETYPES (binfo);
+  parent = canonical_binfo (parent);
+  binfo = canonical_binfo (binfo);
 
   if (parent == binfo)
     return 1;
 
+  n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+
   /* Process and/or queue base types.  */
   for (i = 0; i < n_baselinks; i++)
     {
       tree base_binfo = TREE_VEC_ELT (binfos, i);
-      if (TREE_VIA_VIRTUAL (base_binfo))
-       base_binfo = TYPE_BINFO (BINFO_TYPE (base_binfo));
+      if (!CLASS_TYPE_P (TREE_TYPE (base_binfo)))
+       /* If we see a TEMPLATE_TYPE_PARM, or some such, as a base
+          class there's no way to descend into it.  */
+       continue;
+
       if (is_subobject_of_p (parent, base_binfo))
        return 1;
     }
@@ -840,7 +1286,7 @@ lookup_fnfields_here (type, name)
   fndecls = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx);
   while (fndecls)
     {
-      if (TYPE_MAIN_VARIANT (DECL_CLASS_CONTEXT (OVL_CURRENT (fndecls)))
+      if (TYPE_MAIN_VARIANT (DECL_CONTEXT (OVL_CURRENT (fndecls)))
          == TYPE_MAIN_VARIANT (type))
        return idx;
       fndecls = OVL_CHAIN (fndecls);
@@ -848,52 +1294,236 @@ lookup_fnfields_here (type, name)
   return -1;
 }
 
-/* Look for a field 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.
+struct lookup_field_info {
+  /* The type in which we're looking.  */
+  tree type;
+  /* The name of the field for which we're looking.  */
+  tree name;
+  /* If non-NULL, the current result of the lookup.  */
+  tree rval;
+  /* The path to RVAL.  */
+  tree rval_binfo;
+  /* If non-NULL, the lookup was ambiguous, and this is a list of the
+     candidates.  */
+  tree ambiguous;
+  /* If non-zero, we are looking for types, not data members.  */
+  int want_type;
+  /* If non-zero, RVAL was found by looking through a dependent base.  */
+  int from_dep_base_p;
+  /* If something went wrong, a message indicating what.  */
+  const char *errstr;
+};
+
+/* Returns non-zero if BINFO is not hidden by the value found by the
+   lookup so far.  If BINFO is hidden, then there's no need to look in
+   it.  DATA is really a struct lookup_field_info.  Called from
+   lookup_field via breadth_first_search.  */
 
-   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;
+static tree
+lookup_field_queue_p (binfo, data)
+     tree binfo;
+     void *data;
 {
-  int head = 0, tail = 0;
-  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;
-  int vbase_name_p = VBASE_NAME_P (name);
+  struct lookup_field_info *lfi = (struct lookup_field_info *) data;
 
-  /* rval_binfo is the binfo associated with the found member, note,
+  /* Don't look for constructors or destructors in base classes.  */
+  if (lfi->name == ctor_identifier || lfi->name == dtor_identifier)
+    return NULL_TREE;
+
+  /* If this base class is hidden by the best-known value so far, we
+     don't need to look.  */
+  if (!lfi->from_dep_base_p && lfi->rval_binfo
+      && hides (lfi->rval_binfo, binfo))
+    return NULL_TREE;
+
+  if (TREE_VIA_VIRTUAL (binfo))
+    return BINFO_FOR_VBASE (BINFO_TYPE (binfo), lfi->type);
+  else
+    return binfo;
+}
+
+/* Within the scope of a template class, you can refer to the to the
+   current specialization with the name of the template itself.  For
+   example:
+   
+     template <typename T> struct S { S* sp; }
+
+   Returns non-zero if DECL is such a declaration in a class TYPE.  */
+
+static int
+template_self_reference_p (type, decl)
+     tree type;
+     tree decl;
+{
+  return  (CLASSTYPE_USE_TEMPLATE (type)
+          && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (type))
+          && TREE_CODE (decl) == TYPE_DECL
+          && DECL_ARTIFICIAL (decl)
+          && DECL_NAME (decl) == constructor_name (type));
+}
+
+/* DATA is really a struct lookup_field_info.  Look for a field with
+   the name indicated there in BINFO.  If this function returns a
+   non-NULL value it is the result of the lookup.  Called from
+   lookup_field via breadth_first_search.  */
+
+static tree
+lookup_field_r (binfo, data)
+     tree binfo;
+     void *data;
+{
+  struct lookup_field_info *lfi = (struct lookup_field_info *) data;
+  tree type = BINFO_TYPE (binfo);
+  tree nval = NULL_TREE;
+  int from_dep_base_p;
+
+  /* First, look for a function.  There can't be a function and a data
+     member with the same name, and if there's a function and a type
+     with the same name, the type is hidden by the function.  */
+  if (!lfi->want_type)
+    {
+      int idx = lookup_fnfields_here (type, lfi->name);
+      if (idx >= 0)
+       nval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx);
+    }
+
+  if (!nval)
+    /* Look for a data member or type.  */
+    nval = lookup_field_1 (type, lfi->name);
+
+  /* If there is no declaration with the indicated name in this type,
+     then there's nothing to do.  */
+  if (!nval)
+    return NULL_TREE;
+
+  /* If we're looking up a type (as with an elaborated type specifier)
+     we ignore all non-types we find.  */
+  if (lfi->want_type && TREE_CODE (nval) != TYPE_DECL)
+    {
+      nval = purpose_member (lfi->name, CLASSTYPE_TAGS (type));
+      if (nval)
+       nval = TYPE_MAIN_DECL (TREE_VALUE (nval));
+      else 
+       return NULL_TREE;
+    }
+
+  /* You must name a template base class with a template-id.  */
+  if (!same_type_p (type, lfi->type) 
+      && template_self_reference_p (type, nval))
+    return NULL_TREE;
+
+  from_dep_base_p = dependent_base_p (binfo);
+  if (lfi->from_dep_base_p && !from_dep_base_p)
+    {
+      /* If the new declaration is not found via a dependent base, and
+        the old one was, then we must prefer the new one.  We weren't
+        really supposed to be able to find the old one, so we don't
+        want to be affected by a specialization.  Consider:
+
+          struct B { typedef int I; };
+          template <typename T> struct D1 : virtual public B {}; 
+          template <typename T> struct D :
+          public D1, virtual pubic B { I i; };
+
+        The `I' in `D<T>' is unambigousuly `B::I', regardless of how
+        D1 is specialized.  */
+      lfi->from_dep_base_p = 0;
+      lfi->rval = NULL_TREE;
+      lfi->rval_binfo = NULL_TREE;
+      lfi->ambiguous = NULL_TREE;
+      lfi->errstr = 0;
+    }
+  else if (lfi->rval_binfo && !lfi->from_dep_base_p && from_dep_base_p)
+    /* Similarly, if the old declaration was not found via a dependent
+       base, and the new one is, ignore the new one.  */
+    return NULL_TREE;
+
+  /* If the lookup already found a match, and the new value doesn't
+     hide the old one, we might have an ambiguity.  */
+  if (lfi->rval_binfo && !hides (binfo, lfi->rval_binfo))
+    {
+      if (nval == lfi->rval && SHARED_MEMBER_P (nval))
+       /* The two things are really the same.  */
+       ;
+      else if (hides (lfi->rval_binfo, binfo))
+       /* The previous value hides the new one.  */
+       ;
+      else
+       {
+         /* We have a real ambiguity.  We keep a chain of all the
+            candidates.  */
+         if (!lfi->ambiguous && lfi->rval)
+           {
+             /* This is the first time we noticed an ambiguity.  Add
+                what we previously thought was a reasonable candidate
+                to the list.  */
+             lfi->ambiguous = tree_cons (NULL_TREE, lfi->rval, NULL_TREE);
+             TREE_TYPE (lfi->ambiguous) = error_mark_node;
+           }
+
+         /* Add the new value.  */
+         lfi->ambiguous = tree_cons (NULL_TREE, nval, lfi->ambiguous);
+         TREE_TYPE (lfi->ambiguous) = error_mark_node;
+         lfi->errstr = "request for member `%D' is ambiguous";
+       }
+    }
+  else
+    {
+      /* If the thing we're looking for is a virtual base class, then
+        we know we've got what we want at this point; there's no way
+        to get an ambiguity.  */
+      if (VBASE_NAME_P (lfi->name))
+       {
+         lfi->rval = nval;
+         return nval;
+       }
+
+      if (from_dep_base_p && TREE_CODE (nval) != TYPE_DECL
+         /* We need to return a member template class so we can
+            define partial specializations.  Is there a better
+            way?  */
+         && !DECL_CLASS_TEMPLATE_P (nval))
+       /* The thing we're looking for isn't a type, so the implicit
+          typename extension doesn't apply, so we just pretend we
+          didn't find anything.  */
+       return NULL_TREE;
+
+      lfi->rval = nval;
+      lfi->from_dep_base_p = from_dep_base_p;
+      lfi->rval_binfo = binfo;
+    }
+
+  return NULL_TREE;
+}
+
+/* Look for a memer named NAME in an inheritance lattice dominated by
+   XBASETYPE.  PROTECT is 0 or two, we do not check access.  If it is
+   1, we enforce accessibility.  If PROTECT is zero, then, for an
+   ambiguous lookup, we return NULL.  If PROTECT is 1, we issue an
+   error message.  If PROTECT is 2, we return a TREE_LIST whose
+   TREE_TYPE is error_mark_node and whose TREE_VALUEs are the list of
+   ambiguous candidates.
+
+   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)
+     register tree xbasetype, name;
+     int protect, want_type;
+{
+  tree rval, rval_binfo = NULL_TREE;
+  tree type = NULL_TREE, basetype_path = NULL_TREE;
+  struct lookup_field_info lfi;
+
+  /* rval_binfo is the binfo associated with the found member, note,
      this can be set with useful information, even when rval is not
      set, because it must deal with ALL members, not just non-function
      members.  It is used for ambiguity checking and the hidden
      checks.  Whereas rval is only set if a proper (not hidden)
      non-function member is found.  */
 
-  /* 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 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;
-
-#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
+  const char *errstr = 0;
 
   if (xbasetype == current_class_type && TYPE_BEING_DEFINED (xbasetype)
       && IDENTIFIER_CLASS_VALUE (name))
@@ -901,6 +1531,8 @@ lookup_field (xbasetype, name, protect, want_type)
       tree field = IDENTIFIER_CLASS_VALUE (name);
       if (TREE_CODE (field) != FUNCTION_DECL
          && ! (want_type && TREE_CODE (field) != TYPE_DECL))
+       /* We're in the scope of this class, and the value has already
+          been looked up.  Just return the cached value.  */
        return field;
     }
 
@@ -925,791 +1557,387 @@ lookup_field (xbasetype, name, protect, want_type)
   n_calls_lookup_field++;
 #endif /* GATHER_STATISTICS */
 
-  rval = lookup_field_1 (type, name);
-
-  if (rval || lookup_fnfields_here (type, name) >= 0)
-    {
-      if (rval)
-       {
-         if (want_type)
-           {
-             if (TREE_CODE (rval) != TYPE_DECL)
-               {
-                 rval = purpose_member (name, CLASSTYPE_TAGS (type));
-                 if (rval)
-                   rval = TYPE_MAIN_DECL (TREE_VALUE (rval));
-               }
-           }
-         else
-           {
-             if (TREE_CODE (rval) == TYPE_DECL
-                 && lookup_fnfields_here (type, name) >= 0)
-               rval = NULL_TREE;
-           }
-       }
-
-      if (protect && rval)
-       {
-         if (TREE_PRIVATE (rval) | TREE_PROTECTED (rval))
-           this_v = compute_access (basetype_path, rval);
-         if (TREE_CODE (rval) == CONST_DECL)
-           {
-             if (this_v == access_private_node)
-               errstr = "enum `%D' is a private value of class `%T'";
-             else if (this_v == access_protected_node)
-               errstr = "enum `%D' is a protected value of class `%T'";
-           }
-         else
-           {
-             if (this_v == access_private_node)
-               errstr = "member `%D' is a private member of class `%T'";
-             else if (this_v == access_protected_node)
-               errstr = "member `%D' is a protected member of class `%T'";
-           }
-       }
-
-      rval_binfo = basetype_path;
-      goto out;
-    }
-
-  basetype_chain = build_expr_list (NULL_TREE, basetype_path);
-
-  /* The ambiguity check relies upon breadth first searching.  */
-
-  search_stack = push_search_level (search_stack, &search_obstack);
-  binfo = basetype_path;
-  binfo_h = binfo;
-
-  while (1)
+  bzero ((PTR) &lfi, sizeof (lfi));
+  lfi.type = type;
+  lfi.name = name;
+  lfi.want_type = want_type;
+  bfs_walk (basetype_path, &lookup_field_r, &lookup_field_queue_p, &lfi);
+  rval = lfi.rval;
+  rval_binfo = lfi.rval_binfo;
+  if (rval_binfo)
+    type = BINFO_TYPE (rval_binfo);
+  errstr = lfi.errstr;
+
+  /* If we are not interested in ambiguities, don't report them;
+     just return NULL_TREE.  */
+  if (!protect && lfi.ambiguous)
+    return NULL_TREE;
+  
+  if (protect == 2) 
     {
-      tree binfos = BINFO_BASETYPES (binfo);
-      int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-      tree nval;
-
-      /* Process and/or queue base types.  */
-      for (i = 0; i < n_baselinks; i++)
-       {
-         tree base_binfo = TREE_VEC_ELT (binfos, i);
-         if (BINFO_FIELDS_MARKED (base_binfo) == 0)
-           {
-             tree btypes;
-
-             SET_BINFO_FIELDS_MARKED (base_binfo);
-             btypes = scratch_tree_cons (NULL_TREE, base_binfo, basetype_chain);
-             if (TREE_VIA_VIRTUAL (base_binfo))
-               btypes = scratch_tree_cons (NULL_TREE,
-                                   TYPE_BINFO (BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i))),
-                                   btypes);
-             else
-               btypes = scratch_tree_cons (NULL_TREE,
-                                   TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i),
-                                   btypes);
-             obstack_ptr_grow (&search_obstack, btypes);
-             tail += 1;
-             if (tail >= search_stack->limit)
-               my_friendly_abort (98);
-           }
-       }
-
-      /* Process head of queue, if one exists.  */
-      if (head >= tail)
-       break;
-
-      basetype_chain = search_stack->first[head++];
-      binfo_h = TREE_VALUE (basetype_chain);
-      basetype_chain = TREE_CHAIN (basetype_chain);
-      basetype_path = TREE_VALUE (basetype_chain);
-      if (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);
+      if (lfi.ambiguous)
+       return lfi.ambiguous;
       else
-       my_friendly_assert (BINFO_INHERITANCE_CHAIN (basetype_path)
-                           == NULL_TREE, 980827);
-
-      binfo = basetype_path;
-      type = BINFO_TYPE (binfo);
+       protect = 0;
+    }
 
-      /* See if we can find NAME in TYPE.  If RVAL is nonzero,
-        and we do find NAME in TYPE, verify that such a second
-        sighting is in fact valid.  */
+  /* [class.access]
 
-      nval = lookup_field_1 (type, name);
-
-      if (nval || lookup_fnfields_here (type, name)>=0)
-       {
-         if (nval && nval == rval && SHARED_MEMBER_P (nval))
-           {
-             /* This is ok, the member found is the same [class.ambig] */
-           }
-         else if (rval_binfo && hides (rval_binfo_h, binfo_h))
-           {
-             /* This is ok, the member found is in rval_binfo, not
-                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.  */
-             if (nval)
-               {
-                 rval = nval;
-                 if (protect)
-                   this_v = compute_access (basetype_path, rval);
-                 /* These may look ambiguous, but they really are not.  */
-                 if (vbase_name_p)
-                   break;
-               }
-             else
-               {
-                 /* Undo finding it before, as something else hides it.  */
-                 rval = NULL_TREE;
-               }
-             rval_binfo = binfo;
-             rval_binfo_h = binfo_h;
-           }
-         else
-           {
-             /* This is ambiguous.  */
-             errstr = "request for member `%D' is ambiguous";
-             protect += 2;
-             break;
-           }
-       }
-    }
-  {
-    tree *tp = search_stack->first;
-    tree *search_tail = tp + tail;
-
-    if (rval_binfo)
-      {
-       type = BINFO_TYPE (rval_binfo);
-
-       if (rval)
-         {
-           if (want_type)
-             {
-               if (TREE_CODE (rval) != TYPE_DECL)
-                 {
-                   rval = purpose_member (name, CLASSTYPE_TAGS (type));
-                   if (rval)
-                     rval = TYPE_MAIN_DECL (TREE_VALUE (rval));
-                 }
-             }
-           else
-             {
-               if (TREE_CODE (rval) == TYPE_DECL
-                   && lookup_fnfields_here (type, name) >= 0)
-                 rval = NULL_TREE;
-             }
-         }
-      }
-
-    if (rval == NULL_TREE)
-      errstr = 0;
-
-    /* If this FIELD_DECL defines its own access level, deal with that.  */
-    if (rval && errstr == 0
-       && (protect & 1)
-       && DECL_LANG_SPECIFIC (rval)
-       && DECL_ACCESS (rval))
-      {
-       while (tp < search_tail)
-         {
-           /* 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 = NULL_TREE;
-
-           if (this_v != access_default_node)
-             new_v = compute_access (TREE_VALUE (TREE_CHAIN (*tp)), rval);
-           if (this_v != access_default_node && new_v != this_v)
-             {
-               errstr = "conflicting access to member `%D'";
-               this_v = access_default_node;
-             }
-           own_access = new_v;
-           CLEAR_BINFO_FIELDS_MARKED (TREE_VALUE (TREE_CHAIN (*tp)));
-           tp += 1;
-         }
-      }
-    else
-      {
-       while (tp < search_tail)
-         {
-           CLEAR_BINFO_FIELDS_MARKED (TREE_VALUE (TREE_CHAIN (*tp)));
-           tp += 1;
-         }
-      }
-  }
-  search_stack = pop_search_level (search_stack);
-
-  if (errstr == 0)
-    {
-      if (own_access == access_private_node)
-       errstr = "member `%D' declared private";
-      else if (own_access == access_protected_node)
-       errstr = "member `%D' declared protected";
-      else if (this_v == access_private_node)
-       errstr = TREE_PRIVATE (rval)
-         ? "member `%D' is private"
-           : "member `%D' is from private base class";
-      else if (this_v == access_protected_node)
-       errstr = TREE_PROTECTED (rval)
-         ? "member `%D' is protected"
-           : "member `%D' is from protected base class";
-    }
-
- out:
-  if (protect == 2)
-    {
-      /* If we are not interested in ambiguities, don't report them,
-        just return NULL_TREE.  */
-      rval = NULL_TREE;
-      protect = 0;
-    }
+     In the case of overloaded function names, access control is
+     applied to the function selected by overloaded resolution.  */
+  if (rval && protect && !is_overloaded_fn (rval)
+      && !enforce_access (xbasetype, rval))
+    return error_mark_node;
 
   if (errstr && protect)
     {
       cp_error (errstr, name, type);
+      if (lfi.ambiguous)
+        print_candidates (lfi.ambiguous);
       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() {}
+  /* If the thing we found was found via the implicit typename
+     extension, build the typename type.  */
+  if (rval && lfi.from_dep_base_p && !DECL_CLASS_TEMPLATE_P (rval))
+    rval = TYPE_STUB_DECL (build_typename_type (BINFO_TYPE (basetype_path),
+                                               name, name,
+                                               TREE_TYPE (rval)));
 
-     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))
+  if (rval && is_overloaded_fn (rval)) 
     {
-      /* 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);
+      rval = tree_cons (basetype_path, rval, NULL_TREE);
+      SET_BASELINK_P (rval);
     }
 
   return rval;
 }
 
-/* Try to find NAME inside a nested class.  */
+/* Like lookup_member, except that if we find a function member we
+   return NULL_TREE.  */
 
 tree
-lookup_nested_field (name, complain)
-     tree name;
-     int complain;
+lookup_field (xbasetype, name, protect, want_type)
+     register tree xbasetype, name;
+     int protect, want_type;
 {
-  register tree t;
+  tree rval = lookup_member (xbasetype, name, protect, want_type);
+  
+  /* Ignore functions.  */
+  if (rval && TREE_CODE (rval) == TREE_LIST)
+    return NULL_TREE;
 
-  tree id = NULL_TREE;
-  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 = TYPE_MAIN_DECL (current_class_type);
-          t && DECL_CONTEXT (t);
-          t = TYPE_MAIN_DECL (DECL_CONTEXT (t)))
-       {
-         if (TREE_CODE (DECL_CONTEXT (t)) != RECORD_TYPE)
-           break;
+  return rval;
+}
 
-         /* N.B.: lookup_field will do the access checking for us */
-         id = lookup_field (DECL_CONTEXT (t), name, complain, 0);
-         if (id == error_mark_node)
-           {
-             id = NULL_TREE;
-             continue;
-           }
+/* Like lookup_member, except that if we find a non-function member we
+   return NULL_TREE.  */
 
-         if (id != NULL_TREE)
-           {
-             if (TREE_CODE (id) == FIELD_DECL
-                 && ! TREE_STATIC (id)
-                 && TREE_TYPE (id) != error_mark_node)
-               {
-                 if (complain)
-                   {
-                     /* At parse time, we don't want to give this error, since
-                        we won't have enough state to make this kind of
-                        decision properly.  But there are times (e.g., with
-                        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.  */
-                     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;
-                   }
-                 else
-                   {
-                     id = NULL_TREE;
-                     continue;
-                   }
-               }
-             break;
-           }
-       }
-    }
+tree
+lookup_fnfields (xbasetype, name, protect)
+     register tree xbasetype, name;
+     int protect;
+{
+  tree rval = lookup_member (xbasetype, name, protect, /*want_type=*/0);
+
+  /* Ignore non-functions.  */
+  if (rval && TREE_CODE (rval) != TREE_LIST)
+    return NULL_TREE;
 
-  return id;
+  return rval;
 }
 
 /* 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
+int
 lookup_fnfields_1 (type, name)
      tree type, name;
 {
-  register tree method_vec 
+  tree method_vec 
     = CLASS_TYPE_P (type) ? CLASSTYPE_METHOD_VEC (type) : NULL_TREE;
 
   if (method_vec != 0)
     {
+      register int i;
       register tree *methods = &TREE_VEC_ELT (method_vec, 0);
-      register tree *end = TREE_VEC_END (method_vec);
+      int len = TREE_VEC_LENGTH (method_vec);
+      tree tmp;
 
 #ifdef GATHER_STATISTICS
       n_calls_lookup_fnfields_1++;
 #endif /* GATHER_STATISTICS */
 
       /* Constructors are first...  */
-      if (*methods && name == ctor_identifier)
-       return 0;
+      if (name == ctor_identifier)
+       return methods[0] ? 0 : -1;
 
       /* and destructors are second.  */
-      if (*++methods && name == dtor_identifier)
-       return 1;
+      if (name == dtor_identifier)
+       return methods[1] ? 1 : -1;
 
-      while (++methods != end && *methods)
+      for (i = 2; i < len && methods[i]; ++i)
        {
 #ifdef GATHER_STATISTICS
          n_outer_fields_searched++;
 #endif /* GATHER_STATISTICS */
-         if (DECL_NAME (OVL_CURRENT (*methods)) == name)
-           break;
+
+         tmp = OVL_CURRENT (methods[i]);
+         if (DECL_NAME (tmp) == name)
+           return i;
+
+         /* If the type is complete and we're past the conversion ops,
+            switch to binary search.  */
+         if (! DECL_CONV_FN_P (tmp)
+             && TYPE_SIZE (type))
+           {
+             int lo = i + 1, hi = len;
+
+             while (lo < hi)
+               {
+                 i = (lo + hi) / 2;
+
+#ifdef GATHER_STATISTICS
+                 n_outer_fields_searched++;
+#endif /* GATHER_STATISTICS */
+
+                 tmp = DECL_NAME (OVL_CURRENT (methods[i]));
+
+                 if (tmp > name)
+                   hi = i;
+                 else if (tmp < name)
+                   lo = i + 1;
+                 else
+                   return i;
+               }
+             break;
+           }
        }
 
       /* 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)) 
+      if (IDENTIFIER_TYPENAME_P (name)) 
        {
-         methods = &TREE_VEC_ELT (method_vec, 0) + 1;
-         
-         while (++methods != end && *methods)
+         for (i = 2; i < len && methods[i]; ++i)
            {
-             tree method_name = DECL_NAME (OVL_CURRENT (*methods));
-
-             if (!IDENTIFIER_TYPENAME_P (method_name))
+             tmp = OVL_CURRENT (methods[i]);
+             if (! DECL_CONV_FN_P (tmp))
                {
                  /* 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;
+             else if (TREE_CODE (tmp) == TEMPLATE_DECL)
+               return i;
            }
        }
-
-      if (methods != end && *methods)
-       return methods - &TREE_VEC_ELT (method_vec, 0);
     }
 
   return -1;
 }
+\f
+/* Walk the class hierarchy dominated by TYPE.  FN is called for each
+   type in the hierarchy, in a breadth-first preorder traversal.  .
+   If it ever returns a non-NULL value, that value is immediately
+   returned and the walk is terminated.  At each node FN, is passed a
+   BINFO indicating the path from the curently visited base-class to
+   TYPE.  The TREE_CHAINs of the BINFOs may be used for scratch space;
+   they are otherwise unused.  Before each base-class is walked QFN is
+   called.  If the value returned is non-zero, the base-class is
+   walked; otherwise it is not.  If QFN is NULL, it is treated as a
+   function which always returns 1.  Both FN and QFN are passed the
+   DATA whenever they are called.  */
 
-/* Starting from BASETYPE, return a TREE_BASELINK-like object
-   which gives the following information (in a list):
-
-   TREE_TYPE: list of basetypes needed to get to...
-   TREE_VALUE: list of all functions in a given type
-   which have name NAME.
-
-   No access information is computed by this function,
-   other then to adorn the list of basetypes with
-   TREE_VIA_PUBLIC.
-
-   If there are two ways to find a name (two members), if COMPLAIN is
-   non-zero, then error_mark_node is returned, and an error message is
-   printed, otherwise, just an error_mark_node is returned.
-
-   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;
+static tree
+bfs_walk (binfo, fn, qfn, data)
+     tree binfo;
+     tree (*fn) PARAMS ((tree, void *));
+     tree (*qfn) PARAMS ((tree, void *));
+     void *data;
 {
-  int head = 0, tail = 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
-     set, because it must deal with ALL members, not just function
-     members.  It is used for ambiguity checking and the hidden
-     checks.  Whereas rval is only set if a proper (not hidden)
-     function member is found.  */
-
-  /* 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 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)  */
-
-  /* For now, don't try this.  */
-  int protect = complain;
-
-  char *errstr = 0;
-
-  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 = complete_type (BINFO_TYPE (basetype_path));
-
-#ifdef GATHER_STATISTICS
-  n_calls_lookup_fnfields++;
-#endif /* GATHER_STATISTICS */
-
-  idx = lookup_fnfields_here (type, name);
-  if (idx >= 0 || lookup_field_1 (type, name))
-    {
-      rval_binfo = basetype_path;
-      rval_binfo_h = rval_binfo;
-    }
-
-  if (idx >= 0)
-    {
-      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), idx);
+  size_t head;
+  size_t tail;
+  tree rval = NULL_TREE;
+  /* An array of the base classes of BINFO.  These will be built up in
+     breadth-first order, except where QFN prunes the search.  */
+  varray_type bfs_bases;
 
-      return rvals;
-    }
-  rval = NULL_TREE;
+  /* Start with enough room for ten base classes.  That will be enough
+     for most hierarchies.  */
+  VARRAY_TREE_INIT (bfs_bases, 10, "search_stack");
 
-  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;
-    }
+  /* Put the first type into the stack.  */
+  VARRAY_TREE (bfs_bases, 0) = binfo;
+  tail = 1;
 
-  if (basetype_path == TYPE_BINFO (type))
+  for (head = 0; head < tail; ++head)
     {
-      basetype_chain = CLASSTYPE_BINFO_AS_LIST (type);
-      my_friendly_assert (BINFO_INHERITANCE_CHAIN (basetype_path) == NULL_TREE,
-                         980827);
-    }
-  else
-    basetype_chain = build_expr_list (NULL_TREE, basetype_path);
+      int i;
+      int n_baselinks;
+      tree binfos;
 
-  /* The ambiguity check relies upon breadth first searching.  */
+      /* Pull the next type out of the queue.  */
+      binfo = VARRAY_TREE (bfs_bases, head);
 
-  search_stack = push_search_level (search_stack, &search_obstack);
-  binfo = basetype_path;
-  binfo_h = binfo;
-
-  while (1)
-    {
-      tree binfos = BINFO_BASETYPES (binfo);
-      int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-      int idx;
+      /* If this is the one we're looking for, we're done.  */
+      rval = (*fn) (binfo, data);
+      if (rval)
+       break;
 
-      /* Process and/or queue base types.  */
+      /* Queue up the base types.  */
+      binfos = BINFO_BASETYPES (binfo);
+      n_baselinks = binfos ? TREE_VEC_LENGTH (binfos): 0;
       for (i = 0; i < n_baselinks; i++)
        {
          tree base_binfo = TREE_VEC_ELT (binfos, i);
-         if (BINFO_FIELDS_MARKED (base_binfo) == 0)
-           {
-             tree btypes;
-
-             SET_BINFO_FIELDS_MARKED (base_binfo);
-             btypes = scratch_tree_cons (NULL_TREE, base_binfo, basetype_chain);
-             if (TREE_VIA_VIRTUAL (base_binfo))
-               btypes = scratch_tree_cons (NULL_TREE,
-                                   TYPE_BINFO (BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i))),
-                                   btypes);
-             else
-               btypes = scratch_tree_cons (NULL_TREE,
-                                   TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i),
-                                   btypes);
-             obstack_ptr_grow (&search_obstack, btypes);
-             tail += 1;
-             if (tail >= search_stack->limit)
-               my_friendly_abort (99);
-           }
-       }
 
-      /* Process head of queue, if one exists.  */
-      if (head >= tail)
-       break;
-
-      basetype_chain = search_stack->first[head++];
-      binfo_h = TREE_VALUE (basetype_chain);
-      basetype_chain = TREE_CHAIN (basetype_chain);
-      basetype_path = TREE_VALUE (basetype_chain);
-      if (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
-       my_friendly_assert (BINFO_INHERITANCE_CHAIN (basetype_path)
-                           == NULL_TREE, 980827);
+         if (qfn)
+           base_binfo = (*qfn) (base_binfo, data);
 
-      binfo = basetype_path;
-      type = BINFO_TYPE (binfo);
-
-      /* See if we can find NAME in TYPE.  If RVAL is nonzero,
-        and we do find NAME in TYPE, verify that such a second
-        sighting is in fact valid.  */
-
-      idx = lookup_fnfields_here (type, name);
-
-      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).  */
-           }
-         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 (idx >= 0)
-               {
-                 rval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx);
-                 /* Note, rvals can only be previously set if find_all is
-                    true.  */
-                 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), idx);
-               }
-             else
-               {
-                 /* Undo finding it before, as something else hides it.  */
-                 rval = NULL_TREE;
-                 rvals = NULL_TREE;
-               }
-             rval_binfo = binfo;
-             rval_binfo_h = binfo_h;
-           }
-         else
+         if (base_binfo)
            {
-             /* This is ambiguous.  */
-             errstr = "request for method `%D' is ambiguous";
-             rvals = error_mark_node;
-             break;
+             if (tail == VARRAY_SIZE (bfs_bases))
+               VARRAY_GROW (bfs_bases, 2 * VARRAY_SIZE (bfs_bases));
+             VARRAY_TREE (bfs_bases, tail) = base_binfo;
+             ++tail;
            }
        }
     }
-  {
-    tree *tp = search_stack->first;
-    tree *search_tail = tp + tail;
-
-    while (tp < search_tail)
-      {
-       CLEAR_BINFO_FIELDS_MARKED (TREE_VALUE (TREE_CHAIN (*tp)));
-       tp += 1;
-      }
-  }
-  search_stack = pop_search_level (search_stack);
 
-  if (errstr && protect)
-    {
-      cp_error (errstr, name);
-      rvals = error_mark_node;
-    }
+  /* Clean up.  */
+  VARRAY_FREE (bfs_bases);
 
-  return rvals;
+  return rval;
 }
 
-/* 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.  */
+/* Exactly like bfs_walk, except that a depth-first traversal is
+   performed, and PREFN is called in preorder, while POSTFN is called
+   in postorder.  */
 
 tree
-lookup_member (xbasetype, name, protect, want_type)
-     tree xbasetype, name;
-     int protect, want_type;
+dfs_walk_real (binfo, prefn, postfn, qfn, data)
+     tree binfo;
+     tree (*prefn) PARAMS ((tree, void *));
+     tree (*postfn) PARAMS ((tree, void *));
+     tree (*qfn) PARAMS ((tree, void *));
+     void *data;
 {
-  tree ret, basetype_path;
+  int i;
+  int n_baselinks;
+  tree binfos;
+  tree rval = NULL_TREE;
 
-  if (TREE_CODE (xbasetype) == TREE_VEC)
-    basetype_path = xbasetype;
-  else if (IS_AGGR_TYPE_CODE (TREE_CODE (xbasetype)))
+  /* Call the pre-order walking function.  */
+  if (prefn)
     {
-      basetype_path = TYPE_BINFO (xbasetype);
-      my_friendly_assert (BINFO_INHERITANCE_CHAIN (basetype_path)
-                         == NULL_TREE, 980827);
+      rval = (*prefn) (binfo, data);
+      if (rval)
+       return rval;
     }
-  else
-    my_friendly_abort (97);
+
+  /* Process the basetypes.  */
+  binfos = BINFO_BASETYPES (binfo);
+  n_baselinks = binfos ? TREE_VEC_LENGTH (binfos): 0;
+  for (i = 0; i < n_baselinks; i++)
+    {
+      tree base_binfo = TREE_VEC_ELT (binfos, i);
+      
+      if (qfn)
+       base_binfo = (*qfn) (base_binfo, data);
+
+      if (base_binfo)
+       {
+         rval = dfs_walk_real (base_binfo, prefn, postfn, qfn, data);
+         if (rval)
+           return rval;
+       }
+    }
+
+  /* Call the post-order walking function.  */
+  if (postfn)
+    rval = (*postfn) (binfo, data);
   
-  ret = lookup_field (basetype_path, name, protect, want_type);
-  if (! ret && ! want_type)
-    ret = lookup_fnfields (basetype_path, name, protect);
-  return ret;
+  return rval;
 }
-\f
-/* BREADTH-FIRST SEARCH ROUTINES.  */
 
-/* Search a multiple inheritance hierarchy by breadth-first search.
+/* Exactly like bfs_walk, except that a depth-first post-order traversal is
+   performed.  */
 
-   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.  */
-
-static tree
-breadth_first_search (binfo, testfn, qfn)
+tree
+dfs_walk (binfo, fn, qfn, data)
      tree binfo;
-     tree (*testfn) PROTO((tree));
-     int (*qfn) PROTO((tree));
+     tree (*fn) PARAMS ((tree, void *));
+     tree (*qfn) PARAMS ((tree, void *));
+     void *data;
 {
-  int head = 0, tail = 0;
-  tree rval = NULL_TREE;
+  return dfs_walk_real (binfo, 0, fn, qfn, data);
+}
 
-  search_stack = push_search_level (search_stack, &search_obstack);
+struct gvnt_info 
+{
+  /* The name of the function we are looking for.  */
+  tree name;
+  /* The overloaded functions we have found.  */
+  tree fields;
+};
 
-  SET_BINFO_MARKED (binfo);
-  obstack_ptr_grow (&search_obstack, binfo);
-  ++tail;
+/* Called from get_virtuals_named_this via bfs_walk.  */
 
-  while (1)
-    {
-      tree binfos = BINFO_BASETYPES (binfo);
-      int n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-      int i;
-
-      /* Process and/or queue base types.  */
-      for (i = 0; i < n_baselinks; i++)
-       {
-         tree base_binfo = TREE_VEC_ELT (binfos, i);
+static tree
+get_virtuals_named_this_r (binfo, data)
+     tree binfo;
+     void *data;
+{
+  struct gvnt_info *gvnti = (struct gvnt_info *) data;
+  tree type = BINFO_TYPE (binfo);
+  int idx;
 
-         if (BINFO_MARKED (base_binfo) == 0
-             && (qfn == 0 || (*qfn) (base_binfo)))
-           {
-             SET_BINFO_MARKED (base_binfo);
-             obstack_ptr_grow (&search_obstack, base_binfo);
-             ++tail;
-             if (tail >= search_stack->limit)
-               my_friendly_abort (100);
-           }
-       }
-      /* Process head of queue, if one exists.  */
-      if (head >= tail)
-       {
-         rval = 0;
-         break;
-       }
+  idx = lookup_fnfields_here (BINFO_TYPE (binfo), gvnti->name);
+  if (idx >= 0)
+    gvnti->fields
+      = tree_cons (binfo, 
+                  TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx),
+                  gvnti->fields);
 
-      binfo = search_stack->first[head++];
-      if ((rval = (*testfn) (binfo)))
-       break;
-    }
-  {
-    tree *tp = search_stack->first;
-    tree *search_tail = tp + tail;
-    while (tp < search_tail)
-      {
-       tree binfo = *tp++;
-       CLEAR_BINFO_MARKED (binfo);
-      }
-  }
-
-  search_stack = pop_search_level (search_stack);
-  return rval;
+  return NULL_TREE;
 }
 
-/* Functions to use in breadth first searches.  */
-typedef tree (*pfi) PROTO((tree));
-
-static tree declarator;
+/* Return the virtual functions with the indicated NAME in the type
+   indicated by BINFO.  The result is a TREE_LIST whose TREE_PURPOSE
+   indicates the base class from which the TREE_VALUE (an OVERLOAD or
+   just a FUNCTION_DECL) originated.  */
 
 static tree
-get_virtuals_named_this (binfo)
+get_virtuals_named_this (binfo, name)
      tree binfo;
+     tree name;
 {
+  struct gvnt_info gvnti;
   tree fields;
 
-  fields = lookup_fnfields (binfo, declarator, -1);
-  /* fields cannot be error_mark_node */
+  gvnti.name = name;
+  gvnti.fields = NULL_TREE;
 
-  if (fields == 0)
-    return 0;
+  bfs_walk (binfo, get_virtuals_named_this_r, 0, &gvnti);
 
   /* Get to the function decls, and return the first virtual function
      with this name, if there is one.  */
-  while (fields)
+  for (fields = gvnti.fields; fields; fields = next_baselink (fields))
     {
       tree 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)
+get_virtual_destructor (binfo, data)
      tree binfo;
+     void *data ATTRIBUTE_UNUSED;
 {
   tree type = BINFO_TYPE (binfo);
   if (TYPE_HAS_DESTRUCTOR (type)
@@ -1718,12 +1946,13 @@ get_virtual_destructor (binfo)
   return 0;
 }
 
-static int
-tree_has_any_destructor_p (binfo)
+static tree
+tree_has_any_destructor_p (binfo, data)
      tree binfo;
+     void *data ATTRIBUTE_UNUSED;
 {
   tree type = BINFO_TYPE (binfo);
-  return TYPE_NEEDS_DESTRUCTOR (type);
+  return TYPE_NEEDS_DESTRUCTOR (type) ? binfo : NULL_TREE;
 }
 
 /* Returns > 0 if a function with type DRETTYPE overriding a function
@@ -1781,6 +2010,63 @@ covariant_return_p (brettype, drettype)
   return 1;
 }
 
+/* Check that virtual overrider OVERRIDER is acceptable for base function
+   BASEFN. Issue diagnostic, and return zero, if unacceptable.  */
+
+static int
+check_final_overrider (overrider, basefn)
+     tree overrider, basefn;
+{
+  tree over_type = TREE_TYPE (overrider);
+  tree base_type = TREE_TYPE (basefn);
+  tree over_return = TREE_TYPE (over_type);
+  tree base_return = TREE_TYPE (base_type);
+  tree over_throw = TYPE_RAISES_EXCEPTIONS (over_type);
+  tree base_throw = TYPE_RAISES_EXCEPTIONS (base_type);
+  int i;
+  
+  if (same_type_p (base_return, over_return))
+    /* OK */;
+  else if ((i = covariant_return_p (base_return, over_return)))
+    {
+      if (i == 2)
+       sorry ("adjusting pointers for covariant returns");
+
+      if (pedantic && i == -1)
+       {
+         cp_pedwarn_at ("invalid covariant return type for `virtual %#D'", overrider);
+         cp_pedwarn_at ("  overriding `virtual %#D' (must be pointer or reference to class)", basefn);
+       }
+    }
+  else if (IS_AGGR_TYPE_2 (base_return, over_return)
+          && same_or_base_type_p (base_return, over_return))
+    {
+      cp_error_at ("invalid covariant return type for `virtual %#D'", overrider);
+      cp_error_at ("  overriding `virtual %#D' (must use pointer or reference)", basefn);
+      return 0;
+    }
+  else if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider)) == NULL_TREE)
+    {
+      cp_error_at ("conflicting return type specified for `virtual %#D'", overrider);
+      cp_error_at ("  overriding `virtual %#D'", basefn);
+      SET_IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider),
+                                  DECL_CONTEXT (overrider));
+      return 0;
+    }
+  
+  /* Check throw specifier is subset.  */
+  /* XXX At the moment, punt on an overriding artificial function. We
+     don't generate its exception specifier, so can't check it properly.  */
+  if (! DECL_ARTIFICIAL (overrider)
+      && !comp_except_specs (base_throw, over_throw, 0))
+    {
+      cp_error_at ("looser throw specifier for `virtual %#F'", overrider);
+      cp_error_at ("  overriding `virtual %#F'", basefn);
+      return 0;
+    }
+  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.
@@ -1794,7 +2080,6 @@ get_matching_virtual (binfo, fndecl, dtorp)
      int dtorp;
 {
   tree tmp = NULL_TREE;
-  int i;
 
   if (TREE_CODE (fndecl) == TEMPLATE_DECL)
     /* In [temp.mem] we have:
@@ -1806,23 +2091,17 @@ get_matching_virtual (binfo, fndecl, dtorp)
   /* Breadth first search routines start searching basetypes
      of TYPE, so we must perform first ply of search here.  */
   if (dtorp)
-    {
-      return breadth_first_search (binfo,
-                                  get_virtual_destructor,
-                                  tree_has_any_destructor_p);
-    }
+    return bfs_walk (binfo, get_virtual_destructor,
+                    tree_has_any_destructor_p, 0);
   else
     {
       tree drettype, dtypes, btypes, instptr_type;
-      tree basetype = DECL_CLASS_CONTEXT (fndecl);
       tree baselink, best = NULL_TREE;
-      tree name = DECL_ASSEMBLER_NAME (fndecl);
-
-      declarator = DECL_NAME (fndecl);
+      tree declarator = DECL_NAME (fndecl);
       if (IDENTIFIER_VIRTUAL_P (declarator) == 0)
        return NULL_TREE;
 
-      baselink = get_virtuals_named_this (binfo);
+      baselink = get_virtuals_named_this (binfo, declarator);
       if (baselink == NULL_TREE)
        return NULL_TREE;
 
@@ -1859,196 +2138,315 @@ get_matching_virtual (binfo, fndecl, dtorp)
                   == TYPE_QUALS (instptr_type))
                  && compparms (TREE_CHAIN (btypes), TREE_CHAIN (dtypes)))
                {
-                 tree brettype = TREE_TYPE (TREE_TYPE (tmp));
-                 if (same_type_p (brettype, drettype))
-                   /* OK */;
-                 else if ((i = covariant_return_p (brettype, drettype)))
-                   {
-                     if (i == 2)
-                       sorry ("adjusting pointers for covariant returns");
-
-                     if (pedantic && i == -1)
-                       {
-                         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)
-                          && 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_at ("  with `%#D'", fndecl);
-                   }
-                 else if (IDENTIFIER_ERROR_LOCUS (name) == NULL_TREE)
-                   {
-                     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;
+                 check_final_overrider (fndecl, tmp);
+
+                 /* FNDECL overrides this function.  We continue to
+                    check all the other functions in order to catch
+                    errors; it might be that in some other baseclass
+                    a virtual function was declared with the same
+                    parameter types, but a different return type.  */
+                 best = tmp;
                }
            }
-         /* If not at the end */
-         if (tmps)
-           {
-             best = tmp;
-             break;
-           }
        }
 
-      return best;
-    }
+      return best;
+    }
+}
+
+/* A queue function for dfs_walk that skips any nonprimary virtual
+   bases and any already marked bases.  */
+
+tree
+dfs_skip_nonprimary_vbases_unmarkedp (binfo, data)
+     tree binfo;
+     void *data ATTRIBUTE_UNUSED;
+{
+  if (TREE_VIA_VIRTUAL (binfo) && !BINFO_PRIMARY_MARKED_P (binfo))
+    /* This is a non-primary virtual base.  SKip it.  */
+    return NULL_TREE;
+
+  return unmarkedp (binfo, NULL);
+}
+
+/* A queue function for dfs_walk that skips any nonprimary virtual
+   bases and any unmarked bases.  */
+
+tree
+dfs_skip_nonprimary_vbases_markedp (binfo, data)
+     tree binfo;
+     void *data ATTRIBUTE_UNUSED;
+{
+  if (TREE_VIA_VIRTUAL (binfo) && !BINFO_PRIMARY_MARKED_P (binfo))
+    /* This is a non-primary virtual base.  SKip it.  */
+    return NULL_TREE;
+
+  return markedp (binfo, NULL);
 }
 
-/* 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.  */
+/* Called via dfs_walk from mark_primary_bases.  */
 
 static tree
-get_abstract_virtuals_1 (binfo, do_self, abstract_virtuals)
+dfs_mark_primary_bases (binfo, data)
      tree binfo;
-     int do_self;
-     tree abstract_virtuals;
+     void *data;
 {
-  tree binfos = BINFO_BASETYPES (binfo);
-  int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+  int i;
+  tree base_binfo;
 
-  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));
-      if (! TREE_VIA_VIRTUAL (base_binfo))
-       abstract_virtuals
-         = get_abstract_virtuals_1 (base_binfo, is_not_base_vtable,
-                                    abstract_virtuals);
-    }
-  /* Should we use something besides CLASSTYPE_VFIELDS? */
-  if (do_self && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
+  if (!CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (binfo)))
+    return NULL_TREE;
+
+  i = CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
+  base_binfo = BINFO_BASETYPE (binfo, i);
+
+  if (!TREE_VIA_VIRTUAL (base_binfo))
+    /* Non-virtual base classes are easy.  */
+    BINFO_PRIMARY_MARKED_P (base_binfo) = 1;
+  else
     {
-      tree virtuals = BINFO_VIRTUALS (binfo);
+      tree shared_binfo;
 
-      skip_rtti_stuff (&virtuals);
+      shared_binfo 
+       = BINFO_FOR_VBASE (BINFO_TYPE (base_binfo), (tree) data);
 
-      while (virtuals)
+      /* If this virtual base is not already primary somewhere else in
+        the hiearchy, then we'll be using this copy.  */
+      if (!BINFO_VBASE_PRIMARY_P (shared_binfo)
+         && !BINFO_VBASE_MARKED (shared_binfo))
        {
-         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))
-           abstract_virtuals = tree_cons (NULL_TREE, base_fndecl, abstract_virtuals);
-         virtuals = TREE_CHAIN (virtuals);
+         BINFO_VBASE_PRIMARY_P (shared_binfo) = 1;
+         BINFO_PRIMARY_MARKED_P (base_binfo) = 1;
        }
     }
-  return abstract_virtuals;
+
+  return NULL_TREE;
 }
 
-/* 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.  */
+/* Set BINFO_PRIMARY_MARKED_P for all binfos in the hierarchy
+   dominated by BINFO that are primary bases.  */
 
-tree
-get_abstract_virtuals (type)
+void
+mark_primary_bases (type)
      tree type;
 {
-  tree vbases;
-  tree abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (type);
+  tree vbase;
+
+  /* Mark the TYPE_BINFO hierarchy.  We need to mark primary bases in
+     pre-order to deal with primary virtual bases.  (The virtual base
+     would be skipped if it were not marked as primary, and that
+     requires getting to dfs_mark_primary_bases before
+     dfs_skip_nonprimary_vbases_unmarkedp has a chance to skip the
+     virtual base.)  */
+  dfs_walk_real (TYPE_BINFO (type), dfs_mark_primary_bases, NULL,
+                dfs_skip_nonprimary_vbases_unmarkedp, type);
+
+  /* Now go through the virtual base classes.  Any that are not
+     already primary will need to be allocated in TYPE, and so we need
+     to mark their primary bases.  */
+  for (vbase = CLASSTYPE_VBASECLASSES (type); 
+       vbase; 
+       vbase = TREE_CHAIN (vbase))
+    {
+      if (BINFO_VBASE_PRIMARY_P (vbase))
+       /* This virtual base was already included in the hierarchy, so
+          there's nothing to do here.  */
+       continue;
 
-  /* First get all from non-virtual bases.  */
-  abstract_virtuals
-    = get_abstract_virtuals_1 (TYPE_BINFO (type), 1, abstract_virtuals);
-                                              
-  for (vbases = CLASSTYPE_VBASECLASSES (type); vbases; vbases = TREE_CHAIN (vbases))
+      /* Temporarily pretend that VBASE is primary so that its bases
+        will be walked; this is the real copy of VBASE.  */
+      BINFO_PRIMARY_MARKED_P (vbase) = 1;
+
+      /* Now, walk its bases.  */
+      dfs_walk (vbase, dfs_mark_primary_bases,
+               dfs_skip_nonprimary_vbases_unmarkedp, type);
+
+      /* VBASE wasn't really primary.  */
+      BINFO_PRIMARY_MARKED_P (vbase) = 0;
+      /* And we don't want to allow it to *become* primary if it is a
+        base of some subsequent base class.  */
+      SET_BINFO_VBASE_MARKED (vbase);
+    }
+
+  /* Clear the VBASE_MARKED bits we set above.  */
+  for (vbase = CLASSTYPE_VBASECLASSES (type); 
+       vbase; 
+       vbase = TREE_CHAIN (vbase))
+    CLEAR_BINFO_VBASE_MARKED (vbase);
+}
+
+/* If BINFO is a non-primary virtual baseclass (in the hierarchy
+   dominated by TYPE), and no primary copy appears anywhere in the
+   hierarchy, return the shared copy.  If a primary copy appears
+   elsewhere, return NULL_TREE.  Otherwise, return BINFO itself; it is
+   either a non-virtual base or a primary virtual base.  */
+
+static tree
+get_shared_vbase_if_not_primary (binfo, data)
+     tree binfo;
+     void *data;
+{
+  if (TREE_VIA_VIRTUAL (binfo) && !BINFO_PRIMARY_MARKED_P (binfo))
     {
-      tree virtuals = BINFO_VIRTUALS (vbases);
+      tree type = (tree) data;
 
-      skip_rtti_stuff (&virtuals);
+      if (TREE_CODE (type) == TREE_LIST)
+       type = TREE_PURPOSE (type);
 
-      while (virtuals)
-       {
-         tree base_pfn = FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals));
-         tree base_fndecl = TREE_OPERAND (base_pfn, 0);
-         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);
-       }
+      /* This is a non-primary virtual base.  If there is no primary
+        version, get the shared version.  */
+      binfo = BINFO_FOR_VBASE (BINFO_TYPE (binfo), type);
+      if (BINFO_VBASE_PRIMARY_P (binfo))
+       return NULL_TREE;
     }
-  return nreverse (abstract_virtuals);
+
+  return binfo;
 }
 
-/* For the type TYPE, return a list of member functions available from
-   base classes with name NAME.  The TREE_VALUE of the list is a chain of
-   member functions with name NAME.  The TREE_PURPOSE of the list is a
-   basetype, or a list of base types (in reverse order) which were
-   traversed to reach the chain of member functions.  If we reach a base
-   type which provides a member function of name NAME, and which has at
-   most one base type itself, then we can terminate the search.  */
+/* A queue function to use with dfs_walk that prevents travel into any
+   nonprimary virtual base, or its baseclasses.  DATA should be the
+   type of the complete object, or a TREE_LIST whose TREE_PURPOSE is
+   the type of the complete object.  By using this function as a queue
+   function, you will walk over exactly those BINFOs that actually
+   exist in the complete object, including those for virtual base
+   classes.  If you SET_BINFO_MARKED for each binfo you process, you
+   are further guaranteed that you will walk into each virtual base
+   class exactly once.  */
 
 tree
-get_baselinks (type_as_binfo_list, type, name)
-     tree type_as_binfo_list;
-     tree type, name;
+dfs_unmarked_real_bases_queue_p (binfo, data)
+     tree binfo;
+     void *data;
 {
-  int head = 0, tail = 0, idx;
-  tree rval = 0, nval = 0;
-  tree basetypes = type_as_binfo_list;
-  tree binfo = TYPE_BINFO (type);
+  binfo = get_shared_vbase_if_not_primary (binfo, data); 
+  return binfo ? unmarkedp (binfo, NULL) : NULL_TREE;
+}
 
-  search_stack = push_search_level (search_stack, &search_obstack);
+/* Like dfs_unmarked_real_bases_queue_p but walks only into things
+   that are marked, rather than unmarked.  */
 
-  while (1)
-    {
-      tree binfos = BINFO_BASETYPES (binfo);
-      int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+tree
+dfs_marked_real_bases_queue_p (binfo, data)
+     tree binfo;
+     void *data;
+{
+  binfo = get_shared_vbase_if_not_primary (binfo, data); 
+  return binfo ? markedp (binfo, NULL) : NULL_TREE;
+}
 
-      /* Process and/or queue base types.  */
-      for (i = 0; i < n_baselinks; i++)
-       {
-         tree base_binfo = TREE_VEC_ELT (binfos, i);
-         tree btypes;
-
-         btypes = hash_tree_cons (TREE_VIA_PUBLIC (base_binfo),
-                                  TREE_VIA_VIRTUAL (base_binfo),
-                                  TREE_VIA_PROTECTED (base_binfo),
-                                  NULL_TREE, base_binfo,
-                                  basetypes);
-         obstack_ptr_grow (&search_obstack, btypes);
-         search_stack->first = (tree *)obstack_base (&search_obstack);
-         tail += 1;
-       }
+/* Like dfs_unmarked_real_bases_queue_p but walks only into things
+   that are not BINFO_VTABLE_PATH_MARKED.  */
 
-    dont_queue:
-      /* Process head of queue, if one exists.  */
-      if (head >= tail)
-       break;
+tree
+dfs_vtable_path_unmarked_real_bases_queue_p (binfo, data)
+     tree binfo;
+     void *data;
+{
+  binfo = get_shared_vbase_if_not_primary (binfo, data); 
+  return binfo ? unmarked_vtable_pathp (binfo, NULL): NULL_TREE;
+}
 
-      basetypes = search_stack->first[head++];
-      binfo = TREE_VALUE (basetypes);
-      type = BINFO_TYPE (binfo);
-      idx = lookup_fnfields_1 (type, name);
-      if (idx >= 0)
+/* Like dfs_unmarked_real_bases_queue_p but walks only into things
+   that are BINFO_VTABLE_PATH_MARKED.  */
+
+tree
+dfs_vtable_path_marked_real_bases_queue_p (binfo, data)
+     tree binfo;
+     void *data;
+{
+  binfo = get_shared_vbase_if_not_primary (binfo, data); 
+  return binfo ? marked_vtable_pathp (binfo, NULL): NULL_TREE;
+}
+
+/* A queue function that skips all virtual bases (and their 
+   bases).  */
+
+tree
+dfs_skip_vbases (binfo, data)
+     tree binfo;
+     void *data ATTRIBUTE_UNUSED;
+{
+  if (TREE_VIA_VIRTUAL (binfo))
+    return NULL_TREE;
+
+  return binfo;
+}
+
+/* Called via dfs_walk from dfs_get_pure_virtuals.  */
+
+static tree
+dfs_get_pure_virtuals (binfo, data)
+     tree binfo;
+     void *data;
+{
+  tree type = (tree) data;
+
+  /* We're not interested in primary base classes; the derived class
+     of which they are a primary base will contain the information we
+     need.  */
+  if (!BINFO_PRIMARY_MARKED_P (binfo))
+    {
+      tree virtuals;
+      
+      for (virtuals = skip_rtti_stuff (binfo, 
+                                      BINFO_TYPE (binfo), 
+                                      NULL);
+          virtuals;
+          virtuals = TREE_CHAIN (virtuals))
+       if (DECL_PURE_VIRTUAL_P (TREE_VALUE (virtuals)))
+         CLASSTYPE_PURE_VIRTUALS (type) 
+           = tree_cons (NULL_TREE, TREE_VALUE (virtuals),
+                        CLASSTYPE_PURE_VIRTUALS (type));
+    }
+  
+  SET_BINFO_MARKED (binfo);
+
+  return NULL_TREE;
+}
+
+/* Set CLASSTYPE_PURE_VIRTUALS for TYPE.  */
+
+void
+get_pure_virtuals (type)
+     tree type;
+{
+  tree vbases;
+
+  /* Clear the CLASSTYPE_PURE_VIRTUALS list; whatever is already there
+     is going to be overridden.  */
+  CLASSTYPE_PURE_VIRTUALS (type) = NULL_TREE;
+  /* Now, run through all the bases which are not primary bases, and
+     collect the pure virtual functions.  We look at the vtable in
+     each class to determine what pure virtual functions are present.
+     (A primary base is not interesting because the derived class of
+     which it is a primary base will contain vtable entries for the
+     pure virtuals in the base class.  */
+  dfs_walk (TYPE_BINFO (type), dfs_get_pure_virtuals, 
+           dfs_unmarked_real_bases_queue_p, type);
+  dfs_walk (TYPE_BINFO (type), dfs_unmark, 
+           dfs_marked_real_bases_queue_p, type);
+
+  /* Put the pure virtuals in dfs order.  */
+  CLASSTYPE_PURE_VIRTUALS (type) = nreverse (CLASSTYPE_PURE_VIRTUALS (type));
+
+  for (vbases = CLASSTYPE_VBASECLASSES (type); 
+       vbases; 
+       vbases = TREE_CHAIN (vbases))
+    {
+      tree virtuals;
+
+      for (virtuals = skip_rtti_stuff (vbases, BINFO_TYPE (vbases), NULL);
+          virtuals;
+          virtuals = TREE_CHAIN (virtuals))
        {
-         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), idx);
-             goto dont_queue;
-           }
+         tree base_fndecl = TREE_VALUE (virtuals);
+         if (DECL_NEEDS_FINAL_OVERRIDER_P (base_fndecl))
+           cp_error ("`%#D' needs a final overrider", base_fndecl);
        }
-      nval = NULL_TREE;
     }
-
-  search_stack = pop_search_level (search_stack);
-  return rval;
 }
 
-tree
+static tree
 next_baselink (baselink)
      tree baselink;
 {
@@ -2076,164 +2474,110 @@ static tree
 convert_pointer_to_single_level (to_type, expr)
      tree to_type, expr;
 {
+  tree derived;
   tree binfo_of_derived;
-  tree last;
+  int i;
 
-  binfo_of_derived = TYPE_BINFO (TREE_TYPE (TREE_TYPE (expr)));
-  last = get_binfo (to_type, TREE_TYPE (TREE_TYPE (expr)), 0);
-  my_friendly_assert (BINFO_INHERITANCE_CHAIN (last) == binfo_of_derived,
-                     980827);
+  derived = TREE_TYPE (TREE_TYPE (expr));
+  binfo_of_derived = TYPE_BINFO (derived);
   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.  */
-
-static void
-dfs_walk (binfo, fn, qfn)
-     tree binfo;
-     void (*fn) PROTO((tree));
-     int (*qfn) PROTO((tree));
-{
-  tree binfos = BINFO_BASETYPES (binfo);
-  int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-
-  for (i = 0; i < n_baselinks; i++)
+  for (i = CLASSTYPE_N_BASECLASSES (derived) - 1; i >= 0; --i)
     {
-      tree base_binfo = TREE_VEC_ELT (binfos, i);
-
-      if (qfn == 0 || (*qfn)(base_binfo))
-       {
-         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
-                type, as otherwise there would be no record of it, and just
-                trying to blindly convert at the bottom would be ambiguous.
+      tree binfo = BINFO_BASETYPE (binfo_of_derived, i);
+      my_friendly_assert (BINFO_INHERITANCE_CHAIN (binfo) == binfo_of_derived,
+                         980827);
+      if (same_type_p (BINFO_TYPE (binfo), to_type))
+       return build_vbase_path (PLUS_EXPR, 
+                                build_pointer_type (to_type), 
+                                expr, binfo, 1);
+    }
 
-                The easiest way is to do the conversions one step at a time,
-                as we know we want the immediate base class at each step.
+  my_friendly_abort (19990607);
 
-                The only special trick to converting one step at a time,
-                is that when we hit the last virtual base class, we must
-                use the SLOT value for it, and not use the normal convert
-                routine.  We use the last virtual base class, as in our
-                implementation, we have pointers to all virtual base
-                classes in the base object.  */
+  /* NOTREACHED */
+  return NULL_TREE;
+}
 
-             tree saved_vbase_decl_ptr_intermediate
-               = vbase_decl_ptr_intermediate;
+tree 
+markedp (binfo, data) 
+     tree binfo;
+     void *data ATTRIBUTE_UNUSED;
+{ 
+  return BINFO_MARKED (binfo) ? binfo : NULL_TREE; 
+}
 
-             if (TREE_VIA_VIRTUAL (base_binfo))
-               {
-                 /* No need for the conversion here, as we know it is the
-                    right type.  */
-                 vbase_decl_ptr_intermediate
-                   = CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (base_binfo));
-               }
-             else
-               {
-                 vbase_decl_ptr_intermediate
-                   = convert_pointer_to_single_level (BINFO_TYPE (base_binfo),
-                                                      vbase_decl_ptr_intermediate);
-               }
+tree
+unmarkedp (binfo, data) 
+     tree binfo;
+     void *data ATTRIBUTE_UNUSED;
+{
+  return !BINFO_MARKED (binfo) ? binfo : NULL_TREE;
+}
 
-             dfs_walk (base_binfo, fn, qfn);
+static tree
+marked_vtable_pathp (binfo, data) 
+     tree binfo;
+     void *data ATTRIBUTE_UNUSED;
+{ 
+  return BINFO_VTABLE_PATH_MARKED (binfo) ? binfo : NULL_TREE; 
+}
 
-             vbase_decl_ptr_intermediate = saved_vbase_decl_ptr_intermediate;
-           }
-         else
-           dfs_walk (base_binfo, fn, qfn);
-       }
-    }
+static tree
+unmarked_vtable_pathp (binfo, data) 
+     tree binfo;
+     void *data ATTRIBUTE_UNUSED;
+{ 
+  return !BINFO_VTABLE_PATH_MARKED (binfo) ? binfo : NULL_TREE; 
+}
 
-  fn (binfo);
+static tree 
+marked_new_vtablep (binfo, data) 
+     tree binfo;
+     void *data ATTRIBUTE_UNUSED;
+{
+  return BINFO_NEW_VTABLE_MARKED (binfo) ? binfo : NULL_TREE; 
 }
 
-/* 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
+unmarked_new_vtablep (binfo, data) 
+     tree binfo;
+     void *data ATTRIBUTE_UNUSED;
+{ 
+  return !BINFO_NEW_VTABLE_MARKED (binfo) ? binfo : NULL_TREE; 
+}
 
 static tree
-dfs_search (binfo, fn, start)
-     tree binfo, start;
-     tree (*fn) PROTO((tree));
+marked_pushdecls_p (binfo, data) 
+     tree binfo;
+     void *data ATTRIBUTE_UNUSED;
 {
-  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);
+  return (CLASS_TYPE_P (BINFO_TYPE (binfo))
+         && BINFO_PUSHDECLS_MARKED (binfo)) ? binfo : NULL_TREE; 
 }
 
-static int markedp (binfo) tree binfo;
-{ return BINFO_MARKED (binfo); }
-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 bfs_marked_vtable_pathp (binfo, i) tree binfo; int i;
-{ return BINFO_VTABLE_PATH_MARKED (BINFO_BASETYPE (binfo, i)); }
-static int bfs_unmarked_vtable_pathp (binfo, i) tree binfo; int i;
-{ return BINFO_VTABLE_PATH_MARKED (BINFO_BASETYPE (binfo, i)) == 0; }
-static int bfs_marked_new_vtablep (binfo, i) tree binfo; int i;
-{ return BINFO_NEW_VTABLE_MARKED (BINFO_BASETYPE (binfo, i)); }
-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; }
+static tree
+unmarked_pushdecls_p (binfo, data) 
+     tree binfo;
+     void *data ATTRIBUTE_UNUSED;
+{ 
+  return (CLASS_TYPE_P (BINFO_TYPE (binfo))
+         && !BINFO_PUSHDECLS_MARKED (binfo)) ? binfo : NULL_TREE;
+}
 
 #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; }
+static tree 
+dfs_debug_unmarkedp (binfo, data) 
+     tree binfo;
+     void *data ATTRIBUTE_UNUSED;
+{ 
+  return (!CLASSTYPE_DEBUG_REQUESTED (BINFO_TYPE (binfo)) 
+         ? binfo : NULL_TREE);
+}
+#endif
 
 /* The worker functions for `dfs_walk'.  These do not need to
    test anything (vis a vis marking) if they are paired with
@@ -2245,9 +2589,36 @@ dfs_mark (binfo) tree binfo;
 { SET_BINFO_MARKED (binfo); }
 #endif
 
-static void
-dfs_unmark (binfo) tree binfo;
-{ CLEAR_BINFO_MARKED (binfo); }
+tree
+dfs_unmark (binfo, data) 
+     tree binfo;
+     void *data ATTRIBUTE_UNUSED;
+{ 
+  CLEAR_BINFO_MARKED (binfo); 
+  return NULL_TREE;
+}
+
+/* Clear both BINFO_MARKED and BINFO_VBASE_MARKED.  */
+
+tree
+dfs_vbase_unmark (binfo, data)
+     tree binfo;
+     void *data ATTRIBUTE_UNUSED;
+{
+  CLEAR_BINFO_VBASE_MARKED (binfo);
+  return dfs_unmark (binfo, data);
+}
+
+/* Clear BINFO_VTABLE_PATH_MARKED.  */
+
+tree
+dfs_vtable_path_unmark (binfo, data)
+     tree binfo;
+     void *data ATTRIBUTE_UNUSED;
+{ 
+  CLEAR_BINFO_VTABLE_PATH_MARKED (binfo); 
+  return NULL_TREE;
+}
 
 #if 0
 static void
@@ -2255,10 +2626,6 @@ dfs_mark_vtable_path (binfo) tree binfo;
 { SET_BINFO_VTABLE_PATH_MARKED (binfo); }
 
 static void
-dfs_unmark_vtable_path (binfo) tree binfo;
-{ CLEAR_BINFO_VTABLE_PATH_MARKED (binfo); }
-
-static void
 dfs_mark_new_vtable (binfo) tree binfo;
 { SET_BINFO_NEW_VTABLE_MARKED (binfo); }
 
@@ -2269,70 +2636,54 @@ 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)
+/* Keep this code around in case we later want to control debug info
+   based on whether a type is "used".  Currently, we only suppress debug
+   info if we can emit it with the vtable.  jason 1999-11-11) */
+static tree
+dfs_debug_mark (binfo, data)
      tree binfo;
+     void *data ATTRIBUTE_UNUSED;
 {
   tree t = BINFO_TYPE (binfo);
 
-  /* Use heuristic that if there are virtual functions,
-     ignore until we see a non-inline virtual function.  */
-  tree methods = CLASSTYPE_METHOD_VEC (t);
-
   CLASSTYPE_DEBUG_REQUESTED (t) = 1;
 
-  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;
+    return NULL_TREE;
+
+  /* If the class has virtual functions, we'll emit the debug info
+     with the vtable.  */
+  if (TYPE_POLYMORPHIC_P (t))
+    return NULL_TREE;
 
-  /* If debug info is requested from this context for this type, supply it.
-     If debug info is requested from another context for this type,
-     see if some third context can supply it.  */
-  if (current_function_decl == NULL_TREE
-      || DECL_CLASS_CONTEXT (current_function_decl) != t)
-    {
-      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, 2);
-      methods = OVL_CURRENT (methods);
-      while (methods)
-       {
-         if (DECL_VINDEX (methods)
-             && DECL_THIS_INLINE (methods) == 0
-             && DECL_ABSTRACT_VIRTUAL_P (methods) == 0)
-           {
-             /* Somebody, somewhere is going to have to define this
-                virtual function.  When they do, they will provide
-                the debugging info.  */
-             return;
-           }
-         methods = TREE_CHAIN (methods);
-       }
-    }
   /* 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, toplevel_bindings_p ());
+
+  return NULL_TREE;
 }
+#endif
 \f
-/*  Attach to the type of the virtual base class, the pointer to the
-    virtual base class, given the global pointer vbase_decl_ptr.
+struct vbase_info 
+{
+  tree decl_ptr;
+  tree inits;
+  tree vbase_types;
+};
 
-    We use the global vbase_types.  ICK!  */
+/*  Attach to the type of the virtual base class, the pointer to the
+    virtual base class.  */
 
-static void
-dfs_find_vbases (binfo)
+static tree
+dfs_find_vbases (binfo, data)
      tree binfo;
+     void *data;
 {
+  struct vbase_info *vi = (struct vbase_info *) data;
   tree binfos = BINFO_BASETYPES (binfo);
   int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
 
@@ -2344,70 +2695,90 @@ dfs_find_vbases (binfo)
          && CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (base_binfo)) == 0)
        {
          tree vbase = BINFO_TYPE (base_binfo);
-         tree binfo = binfo_member (vbase, vbase_types);
+         tree binfo = binfo_member (vbase, vi->vbase_types);
 
          CLASSTYPE_SEARCH_SLOT (vbase)
            = build (PLUS_EXPR, build_pointer_type (vbase),
-                    vbase_decl_ptr, BINFO_OFFSET (binfo));
+                    vi->decl_ptr, BINFO_OFFSET (binfo));
        }
     }
   SET_BINFO_VTABLE_PATH_MARKED (binfo);
   SET_BINFO_NEW_VTABLE_MARKED (binfo);
+
+  return NULL_TREE;
 }
 
-static void
-dfs_init_vbase_pointers (binfo)
+static tree
+dfs_init_vbase_pointers (binfo, data)
      tree binfo;
+     void *data;
 {
+  struct vbase_info *vi = (struct vbase_info *) data;
   tree type = BINFO_TYPE (binfo);
-  tree fields = TYPE_FIELDS (type);
+  tree fields;
   tree this_vbase_ptr;
 
   CLEAR_BINFO_VTABLE_PATH_MARKED (binfo);
 
-#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)))
+  if (BINFO_INHERITANCE_CHAIN (binfo))
+    {
+      this_vbase_ptr = TREE_CHAIN (BINFO_INHERITANCE_CHAIN (binfo));
+      if (TREE_VIA_VIRTUAL (binfo))
+       this_vbase_ptr = CLASSTYPE_SEARCH_SLOT (type);
+      else
+       this_vbase_ptr = convert_pointer_to_single_level (type,
+                                                         this_vbase_ptr); 
+      TREE_CHAIN (binfo) = this_vbase_ptr;
+    }
+  else
+    this_vbase_ptr = TREE_CHAIN (binfo);
+
+  /* We're going to iterate through all the pointers to virtual
+     base-classes.  They come at the beginning of the class.  */
+  fields = TYPE_FIELDS (type);
+  if (fields == TYPE_VFIELD (type))
+    /* If the first field is the vtbl pointer (as happens in the new
+       ABI), skip it.  */
     fields = TREE_CHAIN (fields);
-#endif
 
   if (fields == NULL_TREE
       || DECL_NAME (fields) == NULL_TREE
       || ! VBASE_NAME_P (DECL_NAME (fields)))
-    return;
-
-  this_vbase_ptr = vbase_decl_ptr_intermediate;
+    return NULL_TREE;
 
-  if (build_pointer_type (type) != TYPE_MAIN_VARIANT (TREE_TYPE (this_vbase_ptr)))
+  if (build_pointer_type (type) 
+      != TYPE_MAIN_VARIANT (TREE_TYPE (this_vbase_ptr)))
     my_friendly_abort (125);
 
-  while (fields && DECL_NAME (fields)
-        && VBASE_NAME_P (DECL_NAME (fields)))
+  while (fields && DECL_NAME (fields) && VBASE_NAME_P (DECL_NAME (fields)))
     {
       tree ref = build (COMPONENT_REF, TREE_TYPE (fields),
                        build_indirect_ref (this_vbase_ptr, NULL_PTR), 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),
-                                    vbase_init_result);
+      vi->inits = tree_cons (binfo_member (TREE_TYPE (TREE_TYPE (fields)),
+                                          vi->vbase_types),
+                            build_modify_expr (ref, NOP_EXPR, init),
+                            vi->inits);
       fields = TREE_CHAIN (fields);
     }
+  
+  return NULL_TREE;
 }
 
 /* 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)
+static tree
+dfs_clear_vbase_slots (binfo, data)
      tree binfo;
+     void *data ATTRIBUTE_UNUSED;
 {
   tree type = BINFO_TYPE (binfo);
   CLASSTYPE_SEARCH_SLOT (type) = 0;
   CLEAR_BINFO_VTABLE_PATH_MARKED (binfo);
   CLEAR_BINFO_NEW_VTABLE_MARKED (binfo);
+  return NULL_TREE;
 }
 
 tree
@@ -2417,27 +2788,39 @@ init_vbase_pointers (type, decl_ptr)
 {
   if (TYPE_USES_VIRTUAL_BASECLASSES (type))
     {
+      struct vbase_info vi;
       int old_flag = flag_this_is_variable;
       tree binfo = TYPE_BINFO (type);
       flag_this_is_variable = -2;
-      vbase_types = CLASSTYPE_VBASECLASSES (type);
-      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);
-      dfs_walk (binfo, dfs_clear_vbase_slots, marked_new_vtablep);
+
+      /* Find all the virtual base classes, marking them for later
+        initialization.  */
+      vi.decl_ptr = decl_ptr;
+      vi.vbase_types = CLASSTYPE_VBASECLASSES (type);
+      vi.inits = NULL_TREE;
+
+      dfs_walk (binfo, dfs_find_vbases, unmarked_vtable_pathp, &vi);
+
+      /* Build up a list of the initializers.  */
+      TREE_CHAIN (binfo) = decl_ptr;
+      dfs_walk_real (binfo, 
+                    dfs_init_vbase_pointers, 0,
+                    marked_vtable_pathp,
+                    &vi);
+
+      dfs_walk (binfo, dfs_clear_vbase_slots, marked_new_vtablep, 0);
       flag_this_is_variable = old_flag;
-      return vbase_init_result;
+      return vi.inits;
     }
   return 0;
 }
 
 /* get the virtual context (the vbase that directly contains the
-   DECL_CLASS_CONTEXT of the FNDECL) that the given FNDECL is declared in,
+   DECL_CONTEXT of the FNDECL) that the given FNDECL is declared in,
    or NULL_TREE if there is none.
 
-   FNDECL must come from a virtual table from a virtual base to ensure that
-   there is only one possible DECL_CLASS_CONTEXT.
+   FNDECL must come from a virtual table from a virtual base to ensure
+   that there is only one possible DECL_CONTEXT.
 
    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
@@ -2448,17 +2831,17 @@ virtual_context (fndecl, t, vbase)
      tree fndecl, t, vbase;
 {
   tree path;
-  if (get_base_distance (DECL_CLASS_CONTEXT (fndecl), t, 0, &path) < 0)
+  if (get_base_distance (DECL_CONTEXT (fndecl), t, 0, &path) < 0)
     {
-      /* DECL_CLASS_CONTEXT can be ambiguous in t.  */
-      if (get_base_distance (DECL_CLASS_CONTEXT (fndecl), vbase, 0, &path) >= 0)
+      /* DECL_CONTEXT can be ambiguous in t.  */
+      if (get_base_distance (DECL_CONTEXT (fndecl), vbase, 0, &path) >= 0)
        {
          while (path)
            {
              /* Not sure if checking path == vbase is necessary here, but just in
                 case it is.  */
              if (TREE_VIA_VIRTUAL (path) || path == vbase)
-               return binfo_member (BINFO_TYPE (path), CLASSTYPE_VBASECLASSES (t));
+               return BINFO_FOR_VBASE (BINFO_TYPE (path), t);
              path = BINFO_INHERITANCE_CHAIN (path);
            }
        }
@@ -2501,11 +2884,18 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
                      vbase_offsets)
      tree binfo, addr, orig_addr, vbase, vbase_addr, t, *vbase_offsets;
 {
-  tree virtuals = BINFO_VIRTUALS (binfo);
+  tree virtuals;
   tree vc;
   tree delta;
   unsigned HOST_WIDE_INT n;
-  
+
+  while (BINFO_PRIMARY_MARKED_P (binfo))
+    {
+      binfo = BINFO_INHERITANCE_CHAIN (binfo);
+      if (TREE_VIA_VIRTUAL (binfo))
+       return;
+    }
+
   delta = purpose_member (vbase, *vbase_offsets);
   if (! delta)
     {
@@ -2516,13 +2906,12 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
       *vbase_offsets = delta;
     }
 
-  n = skip_rtti_stuff (&virtuals);
+  virtuals = skip_rtti_stuff (binfo, BINFO_TYPE (binfo), &n);
 
   while (virtuals)
     {
       tree current_fndecl = TREE_VALUE (virtuals);
-      current_fndecl = FNADDR_FROM_VTABLE_ENTRY (current_fndecl);
-      current_fndecl = TREE_OPERAND (current_fndecl, 0);
+
       if (current_fndecl
          && current_fndecl != abort_fndecl
          && (vc=virtual_context (current_fndecl, t, vbase)) != vbase)
@@ -2548,7 +2937,7 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
              DECL_ARTIFICIAL (nvtbl) = 1;
              nvtbl = pushdecl (nvtbl);
              init = NULL_TREE;
-             cp_finish_decl (nvtbl, init, NULL_TREE, 0,
+             cp_finish_decl (nvtbl, init, NULL_TREE,
                              LOOKUP_ONLYCONVERTING);
 
              /* We don't set DECL_VIRTUAL_P and DECL_CONTEXT on nvtbl
@@ -2559,13 +2948,12 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
 
              init = build (MODIFY_EXPR, TREE_TYPE (nvtbl),
                            nvtbl, vtbl);
-             TREE_SIDE_EFFECTS (init) = 1;
-             expand_expr_stmt (init);
+             finish_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
+                DECL_CONTEXT (TYPE_VFIELD (BINFO_TYPE (binfo))));
+             finish_expr_stmt
                (build_modify_expr (ref, NOP_EXPR, nvtbl));
            }
          assemble_external (vtbl);
@@ -2579,7 +2967,7 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
          /* This is a upcast, so we have to add the offset for the
             virtual base.  */
          old_delta = build_binary_op (PLUS_EXPR, old_delta,
-                                      TREE_VALUE (delta), 0);
+                                      TREE_VALUE (delta));
          if (vc)
            {
              /* If this is set, we need to subtract out the delta
@@ -2600,7 +2988,7 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
    
              /* This is a downcast, so we have to subtract the offset
                 for the virtual base.  */
-             old_delta = build_binary_op (MINUS_EXPR, old_delta, vc_delta, 0);
+             old_delta = build_binary_op (MINUS_EXPR, old_delta, vc_delta);
            }
 
          TREE_READONLY (new_delta) = 0;
@@ -2608,7 +2996,7 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
            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,
+         finish_expr_stmt (build_modify_expr (new_delta, NOP_EXPR,
                                               old_delta));
        }
       ++n;
@@ -2634,7 +3022,7 @@ 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));
+       = !BINFO_PRIMARY_MARKED_P (real_base_binfo);
       if (! TREE_VIA_VIRTUAL (real_base_binfo))
        fixup_virtual_upcast_offsets (real_base_binfo, base_binfo,
                                      is_not_base_vtable, can_elide, addr,
@@ -2654,26 +3042,69 @@ fixup_virtual_upcast_offsets (real_binfo, binfo, init_self, can_elide, addr, ori
     }
 }
 
-/* Build a COMPOUND_EXPR which when expanded will generate the code
-   needed to initialize all the virtual function table slots of all
-   the virtual baseclasses.  MAIN_BINFO is the binfo which determines
-   the virtual baseclasses to use; TYPE is the type of the object to
-   which the initialization applies.  TRUE_EXP is the true object we
-   are initializing, and DECL_PTR is the pointer to the sub-object we
-   are initializing.
+/* Fixup all the virtual upcast offsets for TYPE.  DECL_PTR is the
+   address of the sub-object being initialized.  */
+
+static void
+fixup_all_virtual_upcast_offsets (type, decl_ptr)
+     tree type;
+     tree decl_ptr;
+{
+  tree if_stmt;
+  tree in_charge_node;
+  tree vbases;
+
+  /* Only tweak the vtables if we're in charge.  */
+  in_charge_node = current_in_charge_parm;
+  if (!in_charge_node)
+    /* There's no need for any fixups in this case.  */
+    return;
+  in_charge_node = build_binary_op (EQ_EXPR, 
+                                   in_charge_node, integer_zero_node);
+  if_stmt = begin_if_stmt ();
+  finish_if_stmt_cond (in_charge_node, if_stmt);
+  
+  /* Iterate through the virtual bases, fixing up the upcast offset
+     for each one.  */
+  for (vbases = CLASSTYPE_VBASECLASSES (type);
+       vbases;
+       vbases = TREE_CHAIN (vbases))
+    {
+      if (flag_vtable_thunks)
+       /* We don't have dynamic thunks yet!  So for now, just fail
+          silently.  */
+       ;
+      else
+       {
+         tree vbase;
+         tree vbase_offsets;
+         tree addr;
+
+         vbase = find_vbase_instance (BINFO_TYPE (vbases), type);
+         vbase_offsets = NULL_TREE;
+         addr = convert_pointer_to_vbase (BINFO_TYPE (vbases), decl_ptr);
+         fixup_virtual_upcast_offsets (vbase,
+                                       TYPE_BINFO (BINFO_TYPE (vbases)),
+                                       1, 0, addr, decl_ptr,
+                                       type, vbase, &vbase_offsets);
+       }
+    }
 
-   When USE_COMPUTED_OFFSETS is non-zero, we can assume that the
-   object was laid out by a top-level constructor and the computed
-   offsets are valid to store vtables.  When zero, we must store new
-   vtables through virtual baseclass pointers.
+  /* Close out the if-statement.  */
+  finish_then_clause (if_stmt);
+  finish_if_stmt ();
+}
 
-   We setup and use the globals: vbase_decl_ptr, vbase_types
-   ICK!  */
+/* Generate the code needed to initialize all the virtual function
+   table slots of all the virtual baseclasses.  BINFO is the binfo
+   which determines the virtual baseclasses to use.  TRUE_EXP is the
+   true object we are initializing, and DECL_PTR is the pointer to the
+   sub-object we are initializing.  */
 
 void
-expand_indirect_vtbls_init (binfo, true_exp, decl_ptr)
+expand_indirect_vtbls_init (binfo, decl_ptr)
      tree binfo;
-     tree true_exp, decl_ptr;
+     tree decl_ptr;
 {
   tree type = BINFO_TYPE (binfo);
 
@@ -2690,66 +3121,14 @@ expand_indirect_vtbls_init (binfo, true_exp, decl_ptr)
 
   if (TYPE_USES_VIRTUAL_BASECLASSES (type))
     {
-      rtx fixup_insns = NULL_RTX;
       tree vbases = CLASSTYPE_VBASECLASSES (type);
-      vbase_types = vbases;
-      vbase_decl_ptr = true_exp ? build_unary_op (ADDR_EXPR, true_exp, 0) : decl_ptr;
-
-      dfs_walk (binfo, dfs_find_vbases, unmarked_new_vtablep);
-
-      /* Initialized with vtables of type TYPE.  */
-      for (; vbases; vbases = TREE_CHAIN (vbases))
-       {
-         tree addr;
-
-         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 CLASSTYPE_VFIELD_PARENT sense)  */
-         expand_direct_vtbls_init (vbases, TYPE_BINFO (BINFO_TYPE (vbases)),
-                                   1, 0, addr);
-
-         /* 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.  */
-           }
-         else
-           {
-             tree vbase_offsets = NULL_TREE;
-             push_to_sequence (fixup_insns);
-             fixup_virtual_upcast_offsets (vbases,
-                                           TYPE_BINFO (BINFO_TYPE (vbases)),
-                                           1, 0, addr, vbase_decl_ptr,
-                                           type, vbases, &vbase_offsets);
-             fixup_insns = get_insns ();
-             end_sequence ();
-           }
-       }
-
-      if (fixup_insns)
-       {
-         extern tree in_charge_identifier;
-         tree in_charge_node = lookup_name (in_charge_identifier, 0);
-         if (! in_charge_node)
-           {
-             warning ("recoverable internal compiler error, nobody's in charge!");
-             in_charge_node = integer_zero_node;
-           }
-         in_charge_node = build_binary_op (EQ_EXPR, in_charge_node, integer_zero_node, 1);
-         expand_start_cond (in_charge_node, 0);
-         emit_insns (fixup_insns);
-         expand_end_cond ();
-       }
+      struct vbase_info vi;
+      vi.decl_ptr = decl_ptr;
+      vi.vbase_types = vbases;
 
-      dfs_walk (binfo, dfs_clear_vbase_slots, marked_new_vtablep);
+      dfs_walk (binfo, dfs_find_vbases, unmarked_new_vtablep, &vi);
+      fixup_all_virtual_upcast_offsets (type, vi.decl_ptr);
+      dfs_walk (binfo, dfs_clear_vbase_slots, marked_new_vtablep, 0);
     }
 }
 
@@ -2757,47 +3136,125 @@ expand_indirect_vtbls_init (binfo, true_exp, decl_ptr)
    This adds type to the vbase_types list in reverse dfs order.
    Ordering is very important, so don't change it.  */
 
-static void
-dfs_get_vbase_types (binfo)
+static tree
+dfs_get_vbase_types (binfo, data)
      tree binfo;
+     void *data;
 {
+  tree type = (tree) data;
+
   if (TREE_VIA_VIRTUAL (binfo) && ! BINFO_VBASE_MARKED (binfo))
     {
-      tree new_vbase = make_binfo (integer_zero_node, binfo,
+      tree new_vbase = make_binfo (integer_zero_node, 
+                                  BINFO_TYPE (binfo),
                                   BINFO_VTABLE (binfo),
                                   BINFO_VIRTUALS (binfo));
-      TREE_CHAIN (new_vbase) = vbase_types;
+      unshare_base_binfos (new_vbase);
       TREE_VIA_VIRTUAL (new_vbase) = 1;
-      vbase_types = new_vbase;
+      BINFO_INHERITANCE_CHAIN (new_vbase) = TYPE_BINFO (type);
+      TREE_CHAIN (new_vbase) = CLASSTYPE_VBASECLASSES (type);
+      CLASSTYPE_VBASECLASSES (type) = new_vbase;
       SET_BINFO_VBASE_MARKED (binfo);
     }
   SET_BINFO_MARKED (binfo);
+  return NULL_TREE;
 }
 
-/* get a list of virtual base classes in dfs order.  */
+/* Set CLASSTYPE_VBASECLASSES for TYPE.  */
 
-tree
+void
 get_vbase_types (type)
      tree type;
 {
-  tree vbases;
-  tree binfo;
-
-  binfo = TYPE_BINFO (type);
-  vbase_types = NULL_TREE;
-  dfs_walk (binfo, dfs_get_vbase_types, unmarkedp);
-  dfs_walk (binfo, dfs_unmark, markedp);
+  CLASSTYPE_VBASECLASSES (type) = NULL_TREE;
+  dfs_walk (TYPE_BINFO (type), dfs_get_vbase_types, unmarkedp, type);
   /* Rely upon the reverse dfs ordering from dfs_get_vbase_types, and now
      reverse it so that we get normal dfs ordering.  */
-  vbase_types = nreverse (vbase_types);
+  CLASSTYPE_VBASECLASSES (type) = nreverse (CLASSTYPE_VBASECLASSES (type));
+  dfs_walk (TYPE_BINFO (type), dfs_vbase_unmark, markedp, 0);
+}
+
+/* Called from find_vbase_instance via dfs_walk.  */
+
+static tree
+dfs_find_vbase_instance (binfo, data)
+     tree binfo;
+     void *data;
+{
+  tree base = TREE_VALUE ((tree) data);
+
+  if (BINFO_PRIMARY_MARKED_P (binfo)
+      && same_type_p (BINFO_TYPE (binfo), base))
+    return binfo;
+
+  return NULL_TREE;
+}
+
+/* Find the real occurrence of the virtual BASE (a class type) in the
+   hierarchy dominated by TYPE.  */
+
+tree
+find_vbase_instance (base, type)
+     tree base;
+     tree type;
+{
+  tree instance;
 
-  /* unmark marked vbases */
-  for (vbases = vbase_types; vbases; vbases = TREE_CHAIN (vbases))
-    CLEAR_BINFO_VBASE_MARKED (vbases);
+  instance = BINFO_FOR_VBASE (base, type);
+  if (!BINFO_VBASE_PRIMARY_P (instance))
+    return instance;
 
-  return vbase_types;
+  return dfs_walk (TYPE_BINFO (type), 
+                  dfs_find_vbase_instance, 
+                  NULL,
+                  build_tree_list (type, base));
 }
+
 \f
+/* Debug info for C++ classes can get very large; try to avoid
+   emitting it everywhere.
+
+   Note that this optimization wins even when the target supports
+   BINCL (if only slightly), and reduces the amount of work for the
+   linker.  */
+
+void
+maybe_suppress_debug_info (t)
+     tree t;
+{
+  /* We can't do the usual TYPE_DECL_SUPPRESS_DEBUG thing with DWARF, which
+     does not support name references between translation units.  It supports
+     symbolic references between translation units, but only within a single
+     executable or shared library.
+
+     For DWARF 2, we handle TYPE_DECL_SUPPRESS_DEBUG by pretending
+     that the type was never defined, so we only get the members we
+     actually define.  */
+  if (write_symbols == DWARF_DEBUG || write_symbols == NO_DEBUG)
+    return;
+
+  /* We might have set this earlier in cp_finish_decl.  */
+  TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 0;
+
+  /* If we already know how we're handling this class, handle debug info
+     the same way.  */
+  if (CLASSTYPE_INTERFACE_ONLY (t))
+    TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1;
+  else if (CLASSTYPE_INTERFACE_KNOWN (t))
+    /* Don't set it.  */;
+  /* If the class has a vtable, write out the debug info along with
+     the vtable.  */
+  else if (TYPE_CONTAINS_VPTR_P (t))
+    TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1;
+
+  /* Otherwise, just emit the debug info normally.  */
+}
+
+#if 0
+/* Keep this code around in case we later want to control debug info
+   based on whether a type is "used".  Currently, we only suppress debug
+   info if we can emit it with the vtable.  jason 1999-11-11) */
+
 /* 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
@@ -2816,128 +3273,24 @@ note_debug_info_needed (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)
+  /* See the comment in maybe_suppress_debug_info.  */
+  if (write_symbols == DWARF_DEBUG || write_symbols == NO_DEBUG)
     return;
 
-  dfs_walk (TYPE_BINFO (type), dfs_debug_mark, dfs_debug_unmarkedp);
+  dfs_walk (TYPE_BINFO (type), dfs_debug_mark, dfs_debug_unmarkedp, 0);
   for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
     {
       tree ttype;
       if (TREE_CODE (field) == FIELD_DECL
          && IS_AGGR_TYPE (ttype = target_type (TREE_TYPE (field)))
-         && dfs_debug_unmarkedp (TYPE_BINFO (ttype)))
+         && dfs_debug_unmarkedp (TYPE_BINFO (ttype), 0))
        note_debug_info_needed (ttype);
     }
 }
+#endif
 \f
 /* Subroutines of push_class_decls ().  */
 
-/* Add in a decl to the envelope.  */
-static void
-envelope_add_decl (type, decl, values)
-     tree type, decl, *values;
-{
-  tree context, *tmp;
-  tree name = DECL_NAME (decl);
-  int dont_add = 0;
-
-  /* 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;
-
-  /* Possible ambiguity.  If its defining type(s)
-     is (are all) derived from us, no problem.  */
-  else if (*values && TREE_CODE (*values) != TREE_LIST)
-    {
-      tree value = *values;
-      /* Only complain if we shadow something we can access.  */
-      if (warn_shadow && TREE_CODE (decl) == FUNCTION_DECL
-         && ((DECL_LANG_SPECIFIC (*values)
-              && DECL_CLASS_CONTEXT (value) == current_class_type)
-             || ! TREE_PRIVATE (value)))
-       /* Should figure out access control more accurately.  */
-       {
-         cp_warning_at ("member `%#D' is shadowed", value);
-         cp_warning_at ("by member function `%#D'", decl);
-         warning ("in this context");
-       }
-
-      context = DECL_REAL_CONTEXT (value);
-
-      if (context == type)
-       {
-         if (TREE_CODE (value) == TYPE_DECL
-             && DECL_ARTIFICIAL (value))
-           *values = NULL_TREE;
-         else
-           dont_add = 1;
-       }
-      else if (type == current_class_type
-              || DERIVED_FROM_P (context, type))
-       {
-         /* Don't add in *values to list */
-         *values = NULL_TREE;
-       }
-      else
-       *values = build_tree_list (NULL_TREE, value);
-    }
-  else
-    for (tmp = values; *tmp;)
-      {
-       tree value = TREE_VALUE (*tmp);
-       my_friendly_assert (TREE_CODE (value) != TREE_LIST, 999);
-       context = (TREE_CODE (value) == FUNCTION_DECL
-                  && DECL_VIRTUAL_P (value))
-         ? DECL_CLASS_CONTEXT (value)
-           : DECL_CONTEXT (value);
-
-       if (type == current_class_type
-           || DERIVED_FROM_P (context, type))
-         {
-           /* remove *tmp from list */
-           *tmp = TREE_CHAIN (*tmp);
-         }
-       else
-         tmp = &TREE_CHAIN (*tmp);
-      }
-
-  if (! dont_add)
-    {
-      /* Put the new contents in our envelope.  */
-      if (TREE_CODE (decl) == FUNCTION_DECL)
-       {
-         *values = tree_cons (name, decl, *values);
-         TREE_NONLOCAL_FLAG (*values) = 1;
-         TREE_TYPE (*values) = unknown_type_node;
-       }
-      else
-       {
-         if (*values)
-           {
-             *values = tree_cons (NULL_TREE, decl, *values);
-             /* Mark this as a potentially ambiguous member.  */
-             /* Leaving TREE_TYPE blank is intentional.
-                We cannot use `error_mark_node' (lookup_name)
-                or `unknown_type_node' (all member functions use this).  */
-             TREE_NONLOCAL_FLAG (*values) = 1;
-           }
-         else
-           *values = decl;
-       }
-    }
-}
-
 /* 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.  */
 
@@ -2947,7 +3300,7 @@ dependent_base_p (binfo)
 {
   for (; binfo; binfo = BINFO_INHERITANCE_CHAIN (binfo))
     {
-      if (TREE_TYPE (binfo) == current_class_type)
+      if (currently_open_class (TREE_TYPE (binfo)))
        break;
       if (uses_template_parms (TREE_TYPE (binfo)))
        return 1;
@@ -2955,178 +3308,137 @@ dependent_base_p (binfo)
   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
-   overwrite the old declaration with the new.  If the fields are not
-   within a single inheritance path, we must cons them.
-
-   In order to know what decls are new (stemming from the current
-   invocation of push_class_decls) we enclose them in an "envelope",
-   which is a TREE_LIST node where the TREE_PURPOSE slot contains the
-   new decl (or possibly a list of competing ones), the TREE_VALUE slot
-   points to the old value and the TREE_CHAIN slot chains together all
-   envelopes which needs to be "opened" in push_class_decls.  Opening an
-   envelope means: push the old value onto the class_shadowed list,
-   install the new one and if it's a TYPE_DECL do the same to the
-   IDENTIFIER_TYPE_VALUE.  Such an envelope is recognized by seeing that
-   the TREE_PURPOSE slot is non-null, and that it is not an identifier.
-   Because if it is, it could be a set of overloaded methods from an
-   outer scope.  */
-
 static void
-dfs_pushdecls (binfo)
-     tree binfo;
+setup_class_bindings (name, type_binding_p)
+     tree name;
+     int type_binding_p;
 {
-  tree type = BINFO_TYPE (binfo);
-  tree fields;
-  tree method_vec;
-  int dummy = 0;
+  tree type_binding = NULL_TREE;
+  tree value_binding;
 
-  /* Only record types if we're a template base.  */
-  if (processing_template_decl && type != current_class_type
-      && dependent_base_p (binfo))
-    dummy = 1;
+  /* If we've already done the lookup for this declaration, we're
+     done.  */
+  if (IDENTIFIER_CLASS_VALUE (name))
+    return;
 
-  for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields))
+  /* First, deal with the type binding.  */
+  if (type_binding_p)
     {
-      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.  */
-      if (TREE_CODE (fields) == FIELD_DECL)
-       TREE_USED (fields) = 0;
-
-      /* Recurse into anonymous unions.  */
-      if (DECL_NAME (fields) == NULL_TREE
-         && TREE_CODE (TREE_TYPE (fields)) == UNION_TYPE)
-       {
-         dfs_pushdecls (TYPE_BINFO (TREE_TYPE (fields)));
-         continue;
-       }
-
-      if (DECL_NAME (fields))
+      type_binding = lookup_member (current_class_type, name,
+                                   /*protect=*/2,
+                                   /*want_type=*/1);
+      if (TREE_CODE (type_binding) == TREE_LIST 
+         && TREE_TYPE (type_binding) == error_mark_node)
+       /* NAME is ambiguous.  */
+       push_class_level_binding (name, type_binding);
+      else
+       pushdecl_class_level (type_binding);
+    }
+
+  /* Now, do the value binding.  */
+  value_binding = lookup_member (current_class_type, name,
+                                /*protect=*/2,
+                                /*want_type=*/0);
+
+  if (type_binding_p
+      && (TREE_CODE (value_binding) == TYPE_DECL
+         || (TREE_CODE (value_binding) == TREE_LIST
+             && TREE_TYPE (value_binding) == error_mark_node
+             && (TREE_CODE (TREE_VALUE (value_binding))
+                 == TYPE_DECL))))
+    /* We found a type-binding, even when looking for a non-type
+       binding.  This means that we already processed this binding
+       above.  */
+    my_friendly_assert (type_binding_p, 19990401);
+  else if (value_binding)
+    {
+      if (TREE_CODE (value_binding) == TREE_LIST 
+         && TREE_TYPE (value_binding) == error_mark_node)
+       /* NAME is ambiguous.  */
+       push_class_level_binding (name, value_binding);
+      else
        {
-         tree name = DECL_NAME (fields);
-         tree class_value = IDENTIFIER_CLASS_VALUE (name);
-
-         /* 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)
-           {
-             /* See comment above for a description of envelopes.  */
-             closed_envelopes = tree_cons (NULL_TREE, class_value,
-                                           closed_envelopes);
-             IDENTIFIER_CLASS_VALUE (name) = closed_envelopes;
-             class_value = IDENTIFIER_CLASS_VALUE (name);
-           }
-
-         envelope_add_decl (type, fields, &TREE_PURPOSE (class_value));
-         pop_obstacks ();
+         if (BASELINK_P (value_binding))
+           /* NAME is some overloaded functions.  */
+           value_binding = TREE_VALUE (value_binding);
+         pushdecl_class_level (value_binding);
        }
     }
+}
 
-  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.  */
-      end = TREE_VEC_END (method_vec);
-
-      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;
-         tree class_value;
-
-         
-         name = DECL_NAME (OVL_CURRENT (*methods));
-         class_value = IDENTIFIER_CLASS_VALUE (name);
-
-         maybe_push_cache_obstack ();
+/* Push class-level declarations for any names appearing in BINFO that
+   are TYPE_DECLS.  */
 
-         /* If the class value is not an envelope of the kind described in
-            the comment above, we create a new envelope.  */
-         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)
-           {
-             /* See comment above for a description of envelopes.  */
-             closed_envelopes = tree_cons (NULL_TREE, class_value,
-                                           closed_envelopes);
-             IDENTIFIER_CLASS_VALUE (name) = closed_envelopes;
-             class_value = IDENTIFIER_CLASS_VALUE (name);
-           }
+static tree
+dfs_push_type_decls (binfo, data)
+     tree binfo;
+     void *data ATTRIBUTE_UNUSED;
+{
+  tree type;
+  tree fields;
 
-         /* Here we try to rule out possible ambiguities.
-            If we can't do that, keep a TREE_LIST with possibly ambiguous
-            decls in there.  */
-         /* 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 ();
-       }
-    }
+  type = BINFO_TYPE (binfo);
+  for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields))
+    if (DECL_NAME (fields) && TREE_CODE (fields) == TYPE_DECL
+       && !(!same_type_p (type, current_class_type)
+            && template_self_reference_p (type, fields)))
+      setup_class_bindings (DECL_NAME (fields), /*type_binding_p=*/1);
 
   /* 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);
+
+  return NULL_TREE;
 }
 
-/* Consolidate unique (by name) member functions.  */
+/* Push class-level declarations for any names appearing in BINFO that
+   are not TYPE_DECLS.  */
 
-static void
-dfs_compress_decls (binfo)
+static tree
+dfs_push_decls (binfo, data)
      tree binfo;
+     void *data;
 {
-  tree type = BINFO_TYPE (binfo);
-  tree method_vec 
-    = CLASS_TYPE_P (type) ? CLASSTYPE_METHOD_VEC (type) : NULL_TREE;
+  tree type;
+  tree method_vec;
+  int dep_base_p;
+
+  type = BINFO_TYPE (binfo);
+  dep_base_p = (processing_template_decl && type != current_class_type
+               && dependent_base_p (binfo));
+  if (!dep_base_p)
+    {
+      tree fields;
+      for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields))
+       if (DECL_NAME (fields) 
+           && TREE_CODE (fields) != TYPE_DECL
+           && TREE_CODE (fields) != USING_DECL)
+         setup_class_bindings (DECL_NAME (fields), /*type_binding_p=*/0);
+       else if (TREE_CODE (fields) == FIELD_DECL
+                && ANON_AGGR_TYPE_P (TREE_TYPE (fields)))
+         dfs_push_decls (TYPE_BINFO (TREE_TYPE (fields)), data);
+         
+      method_vec = (CLASS_TYPE_P (type) 
+                   ? CLASSTYPE_METHOD_VEC (type) : NULL_TREE);
+      if (method_vec)
+       {
+         tree *methods;
+         tree *end;
 
-  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 *end = TREE_VEC_END (method_vec);
+         /* Farm out constructors and destructors.  */
+         end = TREE_VEC_END (method_vec);
 
-      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 (OVL_CURRENT (*methods)));
-         tree tmp = TREE_PURPOSE (class_value);
-
-         /* This was replaced in scope by somebody else.  Just leave it
-            alone.  */
-         if (TREE_CODE (tmp) != TREE_LIST)
-           continue;
-
-         if (TREE_CHAIN (tmp) == NULL_TREE
-             && TREE_VALUE (tmp)
-             && OVL_NEXT (TREE_VALUE (tmp)) == NULL_TREE)
-           {
-             TREE_PURPOSE (class_value) = TREE_VALUE (tmp);
-           }
+         for (methods = &TREE_VEC_ELT (method_vec, 2);
+              *methods && methods != end;
+              methods++)
+           setup_class_bindings (DECL_NAME (OVL_CURRENT (*methods)), 
+                                 /*type_binding_p=*/0);
        }
     }
+
   CLEAR_BINFO_PUSHDECLS_MARKED (binfo);
+
+  return NULL_TREE;
 }
 
 /* When entering the scope of a class, we cache all of the
@@ -3140,93 +3452,21 @@ void
 push_class_decls (type)
      tree type;
 {
-  struct obstack *ambient_obstack = current_obstack;
   search_stack = push_search_level (search_stack, &search_obstack);
 
-  /* 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, 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, marked_pushdecls_p);
-
-  /* Open up all the closed envelopes and push the contained decls into
-     class scope.  */
-  while (closed_envelopes)
-    {
-      tree new = TREE_PURPOSE (closed_envelopes);
-      tree id;
-
-      /* This is messy because the class value may be a *_DECL, or a
-        TREE_LIST of overloaded *_DECLs or even a TREE_LIST of ambiguous
-        *_DECLs.  The name is stored at different places in these three
-        cases.  */
-      if (TREE_CODE (new) == TREE_LIST)
-       {
-         if (TREE_PURPOSE (new) != NULL_TREE)
-           id = TREE_PURPOSE (new);
-         else
-           {
-             tree node = TREE_VALUE (new);
-
-             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);
-           }
-       }
-      else
-       id = DECL_NAME (new);
-
-      /* Install the original class value in order to make
-        pushdecl_class_level work correctly.  */
-      IDENTIFIER_CLASS_VALUE (id) = TREE_VALUE (closed_envelopes);
-      if (TREE_CODE (new) == TREE_LIST)
-       push_class_level_binding (id, new);
-      else
-       pushdecl_class_level (new);
-      closed_envelopes = TREE_CHAIN (closed_envelopes);
-    }
-  
-  /* Undo the call to maybe_push_cache_obstack above.  */
-  pop_obstacks ();
+  /* Enter type declarations and mark.  */
+  dfs_walk (TYPE_BINFO (type), dfs_push_type_decls, unmarked_pushdecls_p, 0);
 
-  current_obstack = ambient_obstack;
+  /* Enter non-type declarations and unmark.  */
+  dfs_walk (TYPE_BINFO (type), dfs_push_decls, marked_pushdecls_p, 0);
 }
 
 /* Here's a subroutine we need because C lacks lambdas.  */
 
-static void
-dfs_unuse_fields (binfo)
+static tree
+dfs_unuse_fields (binfo, data)
      tree binfo;
+     void *data ATTRIBUTE_UNUSED;
 {
   tree type = TREE_TYPE (binfo);
   tree fields;
@@ -3238,16 +3478,18 @@ dfs_unuse_fields (binfo)
 
       TREE_USED (fields) = 0;
       if (DECL_NAME (fields) == NULL_TREE
-         && TREE_CODE (TREE_TYPE (fields)) == UNION_TYPE)
+         && ANON_AGGR_TYPE_P (TREE_TYPE (fields)))
        unuse_fields (TREE_TYPE (fields));
     }
+
+  return NULL_TREE;
 }
 
 void
 unuse_fields (type)
      tree type;
 {
-  dfs_walk (TYPE_BINFO (type), dfs_unuse_fields, unmarkedp);
+  dfs_walk (TYPE_BINFO (type), dfs_unuse_fields, unmarkedp, 0);
 }
 
 void
@@ -3277,7 +3519,7 @@ void
 init_search_processing ()
 {
   gcc_obstack_init (&search_obstack);
-  _vptr_name = get_identifier ("_vptr");
+  vptr_identifier = get_identifier ("_vptr");
 }
 
 void
@@ -3293,177 +3535,102 @@ reinit_search_statistics ()
 #endif /* GATHER_STATISTICS */
 }
 
-#define scratch_tree_cons expr_tree_cons
-
-static tree conversions;
 static tree
-add_conversions (binfo)
+add_conversions (binfo, data)
      tree binfo;
+     void *data;
 {
   int i;
   tree method_vec = CLASSTYPE_METHOD_VEC (BINFO_TYPE (binfo));
-  tree name = NULL_TREE;
+  tree *conversions = (tree *) data;
+
+  /* Some builtin types have no method vector, not even an empty one.  */
+  if (!method_vec)
+    return NULL_TREE;
 
   for (i = 2; i < TREE_VEC_LENGTH (method_vec); ++i)
     {
       tree tmp = TREE_VEC_ELT (method_vec, i);
+      tree name;
 
       if (!tmp || ! DECL_CONV_FN_P (OVL_CURRENT (tmp)))
        break;
 
-      if (TREE_CODE (tmp) == OVERLOAD)
-       {
-         my_friendly_assert (TREE_CHAIN (tmp) == NULL_TREE, 981121);
-         tmp = OVL_FUNCTION (tmp);
-       }
-
-      /* We don't want to mark 'name' until we've seen all the overloads
-        in this class; we could be overloading on the quals of 'this'.  */
-      if (name && name != DECL_NAME (tmp))
-       {
-         IDENTIFIER_MARKED (name) = 1;
-         name = NULL_TREE;
-       }
+      name = DECL_NAME (OVL_CURRENT (tmp));
 
       /* Make sure we don't already have this conversion.  */
-      if (! IDENTIFIER_MARKED (DECL_NAME (tmp)))
+      if (! IDENTIFIER_MARKED (name))
        {
-         conversions = scratch_tree_cons (binfo, tmp, conversions);
-         name = DECL_NAME (tmp);
+         *conversions = tree_cons (binfo, tmp, *conversions);
+         IDENTIFIER_MARKED (name) = 1;
        }
     }
-
-  if (name)
-     IDENTIFIER_MARKED (name) = 1;
-
   return NULL_TREE;
 }
 
+/* Return a TREE_LIST containing all the non-hidden user-defined
+   conversion functions for TYPE (and its base-classes).  The
+   TREE_VALUE of each node is a FUNCTION_DECL or an OVERLOAD
+   containing the conversion functions.  The TREE_PURPOSE is the BINFO
+   from which the conversion functions in this node were selected.  */
+
 tree
 lookup_conversions (type)
      tree type;
 {
   tree t;
-
-  conversions = NULL_TREE;
+  tree conversions = NULL_TREE;
 
   if (TYPE_SIZE (type))
-    breadth_first_search (TYPE_BINFO (type), add_conversions, 0);
+    bfs_walk (TYPE_BINFO (type), add_conversions, 0, &conversions);
 
   for (t = conversions; t; t = TREE_CHAIN (t))
-    IDENTIFIER_MARKED (DECL_NAME (TREE_VALUE (t))) = 0;
+    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;
+struct overlap_info 
 {
-  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;
-}
+  tree compare_type;
+  int found_overlap;
+};
 
 /* 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)
+static tree
+dfs_check_overlap (empty_binfo, data)
      tree empty_binfo;
+     void *data;
 {
+  struct overlap_info *oi = (struct overlap_info *) data;
   tree binfo;
-  for (binfo = TYPE_BINFO (compare_type); ; binfo = BINFO_BASETYPE (binfo, 0))
+  for (binfo = TYPE_BINFO (oi->compare_type); 
+       ; 
+       binfo = BINFO_BASETYPE (binfo, 0))
     {
       if (BINFO_TYPE (binfo) == BINFO_TYPE (empty_binfo))
        {
-         found_overlap = 1;
+         oi->found_overlap = 1;
          break;
        }
       else if (BINFO_BASETYPES (binfo) == NULL_TREE)
        break;
     }
+
+  return NULL_TREE;
 }
 
 /* Trivial function to stop base traversal when we find something.  */
 
-static int
-dfs_no_overlap_yet (t)
-     tree t ATTRIBUTE_UNUSED;
+static tree
+dfs_no_overlap_yet (binfo, data)
+     tree binfo;
+     void *data;
 {
-  return found_overlap == 0;
+  struct overlap_info *oi = (struct overlap_info *) data;
+  return !oi->found_overlap ? binfo : NULL_TREE;
 }
 
 /* Returns nonzero if EMPTY_TYPE or any of its bases can also be found at
@@ -3473,34 +3640,55 @@ int
 types_overlap_p (empty_type, next_type)
      tree empty_type, next_type;
 {
+  struct overlap_info oi;
+
   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;
+  oi.compare_type = next_type;
+  oi.found_overlap = 0;
+  dfs_walk (TYPE_BINFO (empty_type), dfs_check_overlap,
+           dfs_no_overlap_yet, &oi);
+  return oi.found_overlap;
 }
 
-/* Passed to dfs_search by binfo_for_vtable; determine if bvtable comes
-   from BINFO.  */
+/* Given a vtable VAR, determine which binfo it comes from.
 
-static tree bvtable;
-static tree
-dfs_bfv_helper (binfo)
-     tree binfo;
+   FIXME What about secondary vtables?  */
+
+tree
+binfo_for_vtable (var)
+     tree var;
 {
-  if (BINFO_VTABLE (binfo) == bvtable)
-    return binfo;
-  return NULL_TREE;
+  tree binfo = TYPE_BINFO (DECL_CONTEXT (var));
+  tree binfos;
+  int i;
+
+  while (1)
+    {
+      binfos = BINFO_BASETYPES (binfo);
+      if (binfos == NULL_TREE)
+       break;
+
+      i = CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
+      if (i == -1)
+       break;
+
+      binfo = TREE_VEC_ELT (binfos, i);
+    }
+
+  return binfo;
 }
 
-/* Given a vtable VARS, determine which binfo it comes from.  */
+/* Returns 1 iff BINFO is from a direct or indirect virtual base.  */
 
-tree
-binfo_for_vtable (vars)
-     tree vars;
+int
+binfo_from_vbase (binfo)
+     tree binfo;
 {
-  bvtable = vars;
-  return dfs_search (TYPE_BINFO (DECL_CONTEXT (vars)), dfs_bfv_helper,
-                    DECL_CONTEXT (vars));
+  for (; binfo; binfo = BINFO_INHERITANCE_CHAIN (binfo))
+    {
+      if (TREE_VIA_VIRTUAL (binfo))
+       return 1;
+    }
+  return 0;
 }