]> gcc.gnu.org Git - gcc.git/blobdiff - gcc/cp/search.c
class.c (build_vbase_path): Simplify.
[gcc.git] / gcc / cp / search.c
index f9ec9dced7f12f606179e1b67faf7e77d614e898..abd6867a0f4cc4b423f443e7c0daf6256f85bb6c 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-96, 1997 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,82 @@ 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 next_baselink PROTO((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 dfs_check_overlap PROTO((tree, void *));
+static tree dfs_no_overlap_yet PROTO((tree, void *));
 static int get_base_distance_recursive
        PROTO((tree, int, int, int, int *, tree *, tree,
               int, int *, int, int));
+static int dynamic_cast_base_recurse PROTO((tree, tree, int, tree *));
 static void expand_upcast_fixups 
        PROTO((tree, tree, tree, tree, tree, tree, tree *));
 static void fixup_virtual_upcast_offsets
        PROTO((tree, tree, int, int, tree, tree, tree, tree,
               tree *));
-static int markedp PROTO((tree));
-static int unmarkedp PROTO((tree));
-static int marked_vtable_pathp PROTO((tree));
-static int unmarked_vtable_pathp PROTO((tree));
-static int marked_new_vtablep PROTO((tree));
-static int unmarked_new_vtablep PROTO((tree));
-static int dfs_debug_unmarkedp PROTO((tree));
-static void dfs_debug_mark PROTO((tree));
-static void dfs_find_vbases PROTO((tree));
-static void dfs_clear_vbase_slots PROTO((tree));
-static void dfs_unmark PROTO((tree));
-static void dfs_init_vbase_pointers PROTO((tree));
-static void dfs_get_vbase_types PROTO((tree));
-static void dfs_pushdecls PROTO((tree));
-static void dfs_compress_decls PROTO((tree));
-static void dfs_unuse_fields PROTO((tree));
-static tree add_conversions PROTO((tree));
-static tree get_virtuals_named_this PROTO((tree));
-static tree get_virtual_destructor PROTO((tree));
-static int tree_has_any_destructor_p PROTO((tree));
+static tree marked_vtable_pathp PROTO((tree, void *));
+static tree unmarked_vtable_pathp PROTO((tree, void *));
+static tree marked_new_vtablep PROTO((tree, void *));
+static tree unmarked_new_vtablep PROTO((tree, void *));
+static tree marked_pushdecls_p PROTO((tree, void *));
+static tree unmarked_pushdecls_p PROTO((tree, void *));
+#if 0
+static tree dfs_debug_unmarkedp PROTO((tree, void *));
+static tree dfs_debug_mark PROTO((tree, void *));
+#endif
+static tree dfs_find_vbases PROTO((tree, void *));
+static tree dfs_clear_vbase_slots PROTO((tree, void *));
+static tree dfs_init_vbase_pointers PROTO((tree, void *));
+static tree dfs_get_vbase_types PROTO((tree, void *));
+static tree dfs_push_type_decls PROTO((tree, void *));
+static tree dfs_push_decls PROTO((tree, void *));
+static tree dfs_unuse_fields PROTO((tree, void *));
+static tree add_conversions PROTO((tree, void *));
+static tree get_virtuals_named_this PROTO((tree, tree));
+static tree get_virtual_destructor PROTO((tree, void *));
+static tree tree_has_any_destructor_p PROTO((tree, void *));
 static int covariant_return_p PROTO((tree, tree));
+static int check_final_overrider PROTO((tree, tree));
 static struct search_level *push_search_level
        PROTO((struct stack_level *, struct obstack *));
 static struct search_level *pop_search_level
        PROTO((struct stack_level *));
-static tree breadth_first_search
-       PROTO((tree, tree (*) (tree), int (*) (tree)));
-
-static tree vbase_types;
-static tree vbase_decl_ptr_intermediate, vbase_decl_ptr;
-static tree vbase_init_result;
+static tree bfs_walk
+       PROTO((tree, tree (*) (tree, void *), tree (*) (tree, void *),
+              void *));
+static tree lookup_field_queue_p PROTO((tree, void *));
+static tree lookup_field_r PROTO((tree, void *));
+static tree dfs_walk_real PROTO ((tree, 
+                                 tree (*) (tree, void *),
+                                 tree (*) (tree, void *),
+                                 tree (*) (tree, void *),
+                                 void *));
+static tree get_virtuals_named_this_r PROTO ((tree, void *));
+static tree context_for_name_lookup PROTO ((tree));
+static tree canonical_binfo PROTO ((tree));
+static tree shared_marked_p PROTO ((tree, void *));
+static tree shared_unmarked_p PROTO ((tree, void *));
+static int  dependent_base_p PROTO ((tree));
+static tree dfs_accessible_queue_p PROTO ((tree, void *));
+static tree dfs_accessible_p PROTO ((tree, void *));
+static tree dfs_access_in_type PROTO ((tree, void *));
+static tree access_in_type PROTO ((tree, tree));
+static tree dfs_canonical_queue PROTO ((tree, void *));
+static tree dfs_assert_unmarked_p PROTO ((tree, void *));
+static void assert_canonical_unmarked PROTO ((tree));
+static int protected_accessible_p PROTO ((tree, tree, tree, tree));
+static int friend_accessible_p PROTO ((tree, tree, tree, tree));
+static void setup_class_bindings PROTO ((tree, int));
+static int template_self_reference_p PROTO ((tree, tree));
+static void fixup_all_virtual_upcast_offsets PROTO ((tree, tree));
+static tree dfs_mark_primary_bases PROTO((tree, void *));
+static tree get_shared_vbase_if_not_primary PROTO((tree, tree));
 
 /* Allocate a level of searching.  */
 
@@ -156,8 +176,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 +186,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 +248,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 +484,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 +496,77 @@ 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 = -3;
+  
+  if (BINFO_TYPE (binfo) == subtype)
+    {
+      if (via_virtual)
+        return -2;
+      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 == -3)
+        worst = rval;
+      else if (rval >= 0)
+        worst = worst >= 0 ? -1 : worst;
+      else if (rval > -3)
+        worst = worst < rval ? worst : rval;
+    }
+  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 non-virtual bases.
+   BOFF == -2, SUBTYPE occurs as multiple public virtual or non-virtual bases.
+   BOFF == -3, SUBTYPE is not a public base.  */
+
+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 +590,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 +637,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 +661,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;
 }
@@ -572,209 +699,472 @@ current_scope ()
   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 = DECL_REAL_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;
+
+  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 (friend_accessible_p (DECL_CLASS_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;
+}
+   
+/* DECL is a declaration from a base class of TYPE, which was the
+   classs 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 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;
+
+  /* We don't do access control for types yet.  */
+  if (TREE_CODE (decl) == TYPE_DECL)
+    return 1;
 
-  if (access == access_default_node)
+  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 on the same that will 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 +1176,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;
     }
@@ -848,52 +1251,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);
-
-  /* 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.  */
+  struct lookup_field_info *lfi = (struct lookup_field_info *) data;
 
-  /* 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)  */
+  /* Don't look for constructors or destructors in base classes.  */
+  if (lfi->name == ctor_identifier || lfi->name == dtor_identifier)
+    return NULL_TREE;
 
-  char *errstr = 0;
+  /* 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 0
-  /* We cannot search for constructor/destructor names like this.  */
-  /* This can't go here, but where should it go?  */
-  /* If we are looking for a constructor in a templated type, use the
-     unspecialized name, as that is how we store it.  */
-  if (IDENTIFIER_TEMPLATE (name))
-    name = constructor_name (name);
-#endif
+  if (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
+   TREEE_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.  */
+
+  const char *errstr = 0;
 
   if (xbasetype == current_class_type && TYPE_BEING_DEFINED (xbasetype)
       && IDENTIFIER_CLASS_VALUE (name))
@@ -901,6 +1488,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,786 +1514,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)) 
     {
-      /* 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) PROTO((tree, void *));
+     tree (*qfn) PROTO((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)
+
+         if (qfn)
+           base_binfo = (*qfn) (base_binfo, data);
+
+         if (base_binfo)
            {
-             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);
+             if (tail == VARRAY_SIZE (bfs_bases))
+               VARRAY_GROW (bfs_bases, 2 * VARRAY_SIZE (bfs_bases));
+             VARRAY_TREE (bfs_bases, tail) = base_binfo;
+             ++tail;
            }
        }
+    }
 
-      /* 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);
+  /* Clean up.  */
+  VARRAY_FREE (bfs_bases);
 
-      binfo = basetype_path;
-      type = BINFO_TYPE (binfo);
+  return rval;
+}
 
-      /* 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.  */
+/* Exactly like bfs_walk, except that a depth-first traversal is
+   performed, and PREFN is called in preorder, while POSTFN is called
+   in postorder.  */
 
-      idx = lookup_fnfields_here (type, name);
+static tree
+dfs_walk_real (binfo, prefn, postfn, qfn, data)
+     tree binfo;
+     tree (*prefn) PROTO((tree, void *));
+     tree (*postfn) PROTO((tree, void *));
+     tree (*qfn) PROTO((tree, void *));
+     void *data;
+{
+  int i;
+  int n_baselinks;
+  tree binfos;
+  tree rval = NULL_TREE;
 
-      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
-           {
-             /* This is ambiguous.  */
-             errstr = "request for method `%D' is ambiguous";
-             rvals = error_mark_node;
-             break;
-           }
-       }
+  /* Call the pre-order walking function.  */
+  if (prefn)
+    {
+      rval = (*prefn) (binfo, data);
+      if (rval)
+       return rval;
     }
-  {
-    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)
+  /* Process the basetypes.  */
+  binfos = BINFO_BASETYPES (binfo);
+  n_baselinks = binfos ? TREE_VEC_LENGTH (binfos): 0;
+  for (i = 0; i < n_baselinks; i++)
     {
-      cp_error (errstr, name);
-      rvals = error_mark_node;
+      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;
+       }
     }
 
-  return rvals;
+  /* Call the post-order walking function.  */
+  if (postfn)
+    rval = (*postfn) (binfo, data);
+  
+  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 post-order traversal is
+   performed.  */
 
 tree
-lookup_member (xbasetype, name, protect, want_type)
-     tree xbasetype, name;
-     int protect, want_type;
+dfs_walk (binfo, fn, qfn, data)
+     tree binfo;
+     tree (*fn) PROTO((tree, void *));
+     tree (*qfn) PROTO((tree, void *));
+     void *data;
 {
-  tree ret, basetype_path;
-
-  if (TREE_CODE (xbasetype) == TREE_VEC)
-    basetype_path = xbasetype;
-  else if (IS_AGGR_TYPE_CODE (TREE_CODE (xbasetype)))
-    {
-      basetype_path = TYPE_BINFO (xbasetype);
-      my_friendly_assert (BINFO_INHERITANCE_CHAIN (basetype_path)
-                         == NULL_TREE, 980827);
-    }
-  else
-    my_friendly_abort (97);
-  
-  ret = lookup_field (basetype_path, name, protect, want_type);
-  if (! ret && ! want_type)
-    ret = lookup_fnfields (basetype_path, name, protect);
-  return ret;
+  return dfs_walk_real (binfo, 0, fn, qfn, data);
 }
-\f
-/* BREADTH-FIRST SEARCH ROUTINES.  */
 
-/* Search a multiple inheritance hierarchy by breadth-first search.
+struct gvnt_info 
+{
+  /* The name of the function we are looking for.  */
+  tree name;
+  /* The overloaded functions we have found.  */
+  tree fields;
+};
 
-   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.  */
+/* Called from get_virtuals_named_this via bfs_walk.  */
 
 static tree
-breadth_first_search (binfo, testfn, qfn)
+get_virtuals_named_this_r (binfo, data)
      tree binfo;
-     tree (*testfn) PROTO((tree));
-     int (*qfn) PROTO((tree));
+     void *data;
 {
-  int head = 0, tail = 0;
-  tree rval = NULL_TREE;
-
-  search_stack = push_search_level (search_stack, &search_obstack);
-
-  SET_BINFO_MARKED (binfo);
-  obstack_ptr_grow (&search_obstack, binfo);
-  ++tail;
-
-  while (1)
-    {
-      tree binfos = BINFO_BASETYPES (binfo);
-      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);
+  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)
@@ -1713,12 +1903,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
@@ -1776,6 +1967,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_CLASS_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.
@@ -1789,7 +2037,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:
@@ -1801,23 +2048,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;
 
@@ -1854,196 +2095,275 @@ 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 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.  */
+/* 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);
+}
+
+/* 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;
 
-  /* 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))
+  /* Mark the TYPE_BINFO hierarchy.  */
+  dfs_walk (TYPE_BINFO (type), dfs_mark_primary_bases, 
+           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))
     {
-      tree virtuals = BINFO_VIRTUALS (vbases);
+      if (BINFO_VBASE_PRIMARY_P (vbase))
+       /* This virtual base was already included in the hierarchy, so
+          there's nothing to do here.  */
+       continue;
 
-      skip_rtti_stuff (&virtuals);
+      /* 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;
 
-      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);
-       }
+      /* 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, type)
+     tree binfo;
+     tree type;
+{
+  if (TREE_VIA_VIRTUAL (binfo) && !BINFO_PRIMARY_MARKED_P (binfo))
+    {
+      /* 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);
+  tree type = (tree) data;
 
-  search_stack = push_search_level (search_stack, &search_obstack);
+  if (TREE_CODE (type) == TREE_LIST)
+    type = TREE_PURPOSE (type);
+  binfo = get_shared_vbase_if_not_primary (binfo, type); 
+  return binfo ? unmarkedp (binfo, NULL) : NULL_TREE;
+}
 
-  while (1)
-    {
-      tree binfos = BINFO_BASETYPES (binfo);
-      int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+/* Like dfs_unmarked_real_bases_queue_p but walks only into things
+   that are marked, rather than unmarked.  */
 
-      /* 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;
-       }
+tree
+dfs_marked_real_bases_queue_p (binfo, data)
+     tree binfo;
+     void *data;
+{
+  tree type = (tree) data;
 
-    dont_queue:
-      /* Process head of queue, if one exists.  */
-      if (head >= tail)
-       break;
+  if (TREE_CODE (type) == TREE_LIST)
+    type = TREE_PURPOSE (type);
+  binfo = get_shared_vbase_if_not_primary (binfo, type);
+  return binfo ? markedp (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)
+/* 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;
 {
@@ -2071,164 +2391,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
@@ -2240,9 +2506,25 @@ 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);
+}
 
 #if 0
 static void
@@ -2264,70 +2546,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;
 
@@ -2339,70 +2605,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
@@ -2412,17 +2698,29 @@ 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;
 }
@@ -2453,7 +2751,7 @@ virtual_context (fndecl, t, vbase)
              /* 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);
            }
        }
@@ -2496,7 +2794,7 @@ 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;
@@ -2511,13 +2809,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)
@@ -2543,7 +2840,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
@@ -2554,13 +2851,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);
@@ -2574,7 +2870,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
@@ -2595,7 +2891,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;
@@ -2603,7 +2899,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;
@@ -2649,26 +2945,67 @@ 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_offsets;
+         tree addr;
+
+         vbase_offsets = NULL_TREE;
+         addr = convert_pointer_to_vbase (TREE_TYPE (vbases), decl_ptr);
+         fixup_virtual_upcast_offsets (vbases,
+                                       TYPE_BINFO (BINFO_TYPE (vbases)),
+                                       1, 0, addr, decl_ptr,
+                                       type, vbases, &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);
 
@@ -2685,66 +3022,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);
     }
 }
 
@@ -2752,47 +3037,88 @@ 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);
+}
+\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.  */
 
-  /* unmark marked vbases */
-  for (vbases = vbase_types; vbases; vbases = TREE_CHAIN (vbases))
-    CLEAR_BINFO_VBASE_MARKED (vbases);
+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 virtual functions, write out the debug info
+     along with the vtable.  */
+  else if (TYPE_POLYMORPHIC_P (t))
+    TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1;
 
-  return vbase_types;
+  /* Otherwise, just emit the debug info normally.  */
 }
-\f
+
+#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
@@ -2811,128 +3137,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.  */
 
@@ -2942,7 +3164,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;
@@ -2950,178 +3172,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
@@ -3135,93 +3316,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;
@@ -3233,16 +3342,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
@@ -3272,7 +3383,7 @@ void
 init_search_processing ()
 {
   gcc_obstack_init (&search_obstack);
-  _vptr_name = get_identifier ("_vptr");
+  vptr_identifier = get_identifier ("_vptr");
 }
 
 void
@@ -3288,171 +3399,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;
 
-      /* 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
@@ -3462,34 +3504,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;
 }
This page took 0.13348 seconds and 5 git commands to generate.