OSDN Git Service

* parser.c (cp_parser_simple_type_specifier): Fix typo.
[pf3gnuchains/gcc-fork.git] / gcc / cp / search.c
index 4c3249b..63cb639 100644 (file)
@@ -1,23 +1,23 @@
 /* Breadth-first and depth-first routines for
    searching multiple-inheritance lattice for GNU C++.
    Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000 Free Software Foundation, Inc.
+   1999, 2000, 2002, 2003, 2004 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
+GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2, or (at your option)
 any later version.
 
-GNU CC is distributed in the hope that it will be useful,
+GCC is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
+along with GCC; see the file COPYING.  If not, write to
 the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
@@ -25,6 +25,8 @@ Boston, MA 02111-1307, USA.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "tree.h"
 #include "cp-tree.h"
 #include "obstack.h"
@@ -32,48 +34,8 @@ Boston, MA 02111-1307, USA.  */
 #include "rtl.h"
 #include "output.h"
 #include "toplev.h"
-
-#define obstack_chunk_alloc xmalloc
-#define obstack_chunk_free free
-
 #include "stack.h"
 
-/* Obstack used for remembering decision points of breadth-first.  */
-
-static struct obstack search_obstack;
-
-/* Methods for pushing and popping objects to and from obstacks.  */
-
-struct stack_level *
-push_stack_level (obstack, tp, size)
-     struct obstack *obstack;
-     char *tp;  /* Sony NewsOS 5.0 compiler doesn't like void * here.  */
-     int size;
-{
-  struct stack_level *stack;
-  obstack_grow (obstack, tp, size);
-  stack = (struct stack_level *) ((char*)obstack_next_free (obstack) - size);
-  obstack_finish (obstack);
-  stack->obstack = obstack;
-  stack->first = (tree *) obstack_base (obstack);
-  stack->limit = obstack_room (obstack) / sizeof (tree *);
-  return stack;
-}
-
-struct stack_level *
-pop_stack_level (stack)
-     struct stack_level *stack;
-{
-  struct stack_level *tem = stack;
-  struct obstack *obstack = tem->obstack;
-  stack = tem->prev;
-  obstack_free (obstack, tem);
-  return stack;
-}
-
-#define search_level stack_level
-static struct search_level *search_stack;
-
 struct vbase_info 
 {
   /* The class dominating the hierarchy.  */
@@ -83,80 +45,28 @@ struct vbase_info
   tree inits;
 };
 
-static tree get_vbase_1 PARAMS ((tree, tree, unsigned int *));
-static tree lookup_field_1 PARAMS ((tree, tree));
-static int is_subobject_of_p PARAMS ((tree, tree, tree));
-static tree dfs_check_overlap PARAMS ((tree, void *));
-static tree dfs_no_overlap_yet PARAMS ((tree, void *));
-static int get_base_distance_recursive
-       PARAMS ((tree, int, int, int, int *, tree *, tree,
-              int, int *, int, int));
-static int dynamic_cast_base_recurse PARAMS ((tree, tree, int, tree *));
-static tree marked_pushdecls_p PARAMS ((tree, void *));
-static tree unmarked_pushdecls_p PARAMS ((tree, void *));
-static tree dfs_debug_unmarkedp PARAMS ((tree, void *));
-static tree dfs_debug_mark PARAMS ((tree, void *));
-static tree dfs_get_vbase_types PARAMS ((tree, void *));
-static tree dfs_push_type_decls PARAMS ((tree, void *));
-static tree dfs_push_decls PARAMS ((tree, void *));
-static tree dfs_unuse_fields PARAMS ((tree, void *));
-static tree add_conversions PARAMS ((tree, void *));
-static int covariant_return_p PARAMS ((tree, tree));
-static int check_final_overrider PARAMS ((tree, tree));
-static int look_for_overrides_r PARAMS ((tree, tree));
-static struct search_level *push_search_level
-       PARAMS ((struct stack_level *, struct obstack *));
-static struct search_level *pop_search_level
-       PARAMS ((struct stack_level *));
-static tree bfs_walk
-       PARAMS ((tree, tree (*) (tree, void *), tree (*) (tree, void *),
-              void *));
-static tree lookup_field_queue_p PARAMS ((tree, void *));
-static int shared_member_p PARAMS ((tree));
-static tree lookup_field_r PARAMS ((tree, void *));
-static tree canonical_binfo PARAMS ((tree));
-static tree shared_marked_p PARAMS ((tree, void *));
-static tree shared_unmarked_p PARAMS ((tree, void *));
-static int  dependent_base_p PARAMS ((tree));
-static tree dfs_accessible_queue_p PARAMS ((tree, void *));
-static tree dfs_accessible_p PARAMS ((tree, void *));
-static tree dfs_access_in_type PARAMS ((tree, void *));
-static access_kind access_in_type PARAMS ((tree, tree));
-static tree dfs_canonical_queue PARAMS ((tree, void *));
-static tree dfs_assert_unmarked_p PARAMS ((tree, void *));
-static void assert_canonical_unmarked PARAMS ((tree));
-static int protected_accessible_p PARAMS ((tree, tree, tree));
-static int friend_accessible_p PARAMS ((tree, tree, tree));
-static void setup_class_bindings PARAMS ((tree, int));
-static int template_self_reference_p PARAMS ((tree, tree));
-static tree get_shared_vbase_if_not_primary PARAMS ((tree, void *));
-static tree dfs_find_vbase_instance PARAMS ((tree, void *));
-static tree dfs_get_pure_virtuals PARAMS ((tree, void *));
-static tree dfs_build_inheritance_graph_order PARAMS ((tree, void *));
-
-/* Allocate a level of searching.  */
-
-static struct search_level *
-push_search_level (stack, obstack)
-     struct stack_level *stack;
-     struct obstack *obstack;
-{
-  struct search_level tem;
-
-  tem.prev = stack;
-  return push_stack_level (obstack, (char *)&tem, sizeof (tem));
-}
-
-/* Discard a level of search allocation.  */
+static tree dfs_check_overlap (tree, void *);
+static tree dfs_no_overlap_yet (tree, int, void *);
+static base_kind lookup_base_r (tree, tree, base_access, bool, tree *);
+static int dynamic_cast_base_recurse (tree, tree, bool, tree *);
+static tree dfs_debug_unmarkedp (tree, int, void *);
+static tree dfs_debug_mark (tree, void *);
+static tree add_conversions (tree, void *);
+static int look_for_overrides_r (tree, tree);
+static tree bfs_walk (tree, tree (*) (tree, void *),
+                     tree (*) (tree, int, void *), void *);
+static tree lookup_field_queue_p (tree, int, void *);
+static int shared_member_p (tree);
+static tree lookup_field_r (tree, void *);
+static tree dfs_accessible_queue_p (tree, int, void *);
+static tree dfs_accessible_p (tree, void *);
+static tree dfs_access_in_type (tree, void *);
+static access_kind access_in_type (tree, tree);
+static int protected_accessible_p (tree, tree, tree);
+static int friend_accessible_p (tree, tree, tree);
+static int template_self_reference_p (tree, tree);
+static tree dfs_get_pure_virtuals (tree, void *);
 
-static struct search_level *
-pop_search_level (obstack)
-     struct stack_level *obstack;
-{
-  register struct search_level *stack = pop_stack_level (obstack);
-
-  return stack;
-}
 \f
 /* Variables for gathering statistics.  */
 #ifdef GATHER_STATISTICS
@@ -169,326 +79,219 @@ static int n_contexts_saved;
 #endif /* GATHER_STATISTICS */
 
 \f
-/* Get a virtual binfo that is found inside BINFO's hierarchy that is
-   the same type as the type given in PARENT.  To be optimal, we want
-   the first one that is found by going through the least number of
-   virtual bases.
+/* Worker for lookup_base.  BINFO is the binfo we are searching at,
+   BASE is the RECORD_TYPE we are searching for.  ACCESS is the
+   required access checks.  IS_VIRTUAL indicates if BINFO is morally
+   virtual.
 
-   This uses a clever algorithm that updates *depth when we find the vbase,
-   and cuts off other paths of search when they reach that depth.  */
+   If BINFO is of the required type, then *BINFO_PTR is examined to
+   compare with any other instance of BASE we might have already
+   discovered. *BINFO_PTR is initialized and a base_kind return value
+   indicates what kind of base was located.
 
-static tree
-get_vbase_1 (parent, binfo, depth)
-     tree parent, binfo;
-     unsigned int *depth;
-{
-  tree binfos;
-  int i, n_baselinks;
-  tree rval = NULL_TREE;
-  int virtualp = TREE_VIA_VIRTUAL (binfo) != 0;
+   Otherwise BINFO's bases are searched.  */
 
-  *depth -= virtualp;
-  if (virtualp && BINFO_TYPE (binfo) == parent)
+static base_kind
+lookup_base_r (tree binfo, tree base, base_access access,
+              bool is_virtual,                 /* inside a virtual part */
+              tree *binfo_ptr)
+{
+  int i;
+  tree base_binfo;
+  base_kind found = bk_not_base;
+  
+  if (same_type_p (BINFO_TYPE (binfo), base))
     {
-      *depth = 0;
-      return binfo;
+      /* We have found a base. Check against what we have found
+         already.  */
+      found = bk_same_type;
+      if (is_virtual)
+       found = bk_via_virtual;
+      
+      if (!*binfo_ptr)
+       *binfo_ptr = binfo;
+      else if (binfo != *binfo_ptr)
+       {
+         if (access != ba_any)
+           *binfo_ptr = NULL;
+         else if (!is_virtual)
+           /* Prefer a non-virtual base.  */
+           *binfo_ptr = binfo;
+         found = bk_ambig;
+       }
+      
+      return found;
     }
-
-  binfos = BINFO_BASETYPES (binfo);
-  n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-
-  /* Process base types.  */
-  for (i = 0; i < n_baselinks; i++)
+  
+  for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
     {
-      tree base_binfo = TREE_VEC_ELT (binfos, i);
-      tree nrval;
-
-      if (*depth == 0)
-       break;
+      base_kind bk;
 
-      nrval = get_vbase_1 (parent, base_binfo, depth);
-      if (nrval)
-       rval = nrval;
-    }
-  *depth += virtualp;
-  return rval;
-}
+      bk = lookup_base_r (base_binfo, base,
+                         access,
+                         is_virtual || BINFO_VIRTUAL_P (base_binfo),
+                         binfo_ptr);
 
-/* Return the shortest path to vbase PARENT within BINFO, ignoring
-   access and ambiguity.  */
+      switch (bk)
+       {
+       case bk_ambig:
+         if (access != ba_any)
+           return bk;
+         found = bk;
+         break;
+         
+       case bk_same_type:
+         bk = bk_proper_base;
+         /* Fall through.  */
+       case bk_proper_base:
+         my_friendly_assert (found == bk_not_base, 20010723);
+         found = bk;
+         break;
+         
+       case bk_via_virtual:
+         if (found != bk_ambig)
+           found = bk;
+         break;
+         
+       case bk_not_base:
+         break;
 
-tree
-get_vbase (parent, binfo)
-     tree parent;
-     tree binfo;
-{
-  unsigned int d = (unsigned int)-1;
-  return get_vbase_1 (parent, binfo, &d);
+       default:
+         abort ();
+       }
+    }
+  return found;
 }
 
-/* Convert EXPR to a virtual base class of type TYPE.  We know that
-   EXPR is a non-null POINTER_TYPE to RECORD_TYPE.  We also know that
-   the type of what expr points to has a virtual base of type TYPE.  */
+/* Returns true if type BASE is accessible in T.  (BASE is known to be
+   a (possibly non-proper) base class of T.)  */
 
-tree
-convert_pointer_to_vbase (type, expr)
-     tree type;
-     tree expr;
+bool
+accessible_base_p (tree t, tree base)
 {
-  tree vb = get_vbase (type, TYPE_BINFO (TREE_TYPE (TREE_TYPE (expr))));
-  return convert_pointer_to_real (vb, expr);
-}
-
-/* Check whether the type given in BINFO is derived from PARENT.  If
-   it isn't, return 0.  If it is, but the derivation is MI-ambiguous
-   AND protect != 0, emit an error message and return error_mark_node.
+  tree decl;
 
-   Otherwise, if TYPE is derived from PARENT, return the actual base
-   information, unless a one of the protection violations below
-   occurs, in which case emit an error message and return error_mark_node.
+  /* [class.access.base]
 
-   If PROTECT is 1, then check if access to a public field of PARENT
-   would be private.  Also check for ambiguity.  */
+     A base class is said to be accessible if an invented public
+     member of the base class is accessible.  
+
+     If BASE is a non-proper base, this condition is trivially
+     true.  */
+  if (same_type_p (t, base))
+    return true;
+  /* Rather than inventing a public member, we use the implicit
+     public typedef created in the scope of every class.  */
+  decl = TYPE_FIELDS (base);
+  while (!DECL_SELF_REFERENCE_P (decl))
+    decl = TREE_CHAIN (decl);
+  while (ANON_AGGR_TYPE_P (t))
+    t = TYPE_CONTEXT (t);
+  return accessible_p (t, decl);
+}
+
+/* Lookup BASE in the hierarchy dominated by T.  Do access checking as
+   ACCESS specifies.  Return the binfo we discover.  If KIND_PTR is
+   non-NULL, fill with information about what kind of base we
+   discovered.
+
+   If the base is inaccessible, or ambiguous, and the ba_quiet bit is
+   not set in ACCESS, then an error is issued and error_mark_node is
+   returned.  If the ba_quiet bit is set, then no error is issued and
+   NULL_TREE is returned.  */
 
 tree
-get_binfo (parent, binfo, protect)
-     register tree parent, binfo;
-     int protect;
+lookup_base (tree t, tree base, base_access access, base_kind *kind_ptr)
 {
-  tree type = NULL_TREE;
-  int dist;
-  tree rval = NULL_TREE;
+  tree binfo = NULL_TREE;      /* The binfo we've found so far.  */
+  tree t_binfo = NULL_TREE;
+  base_kind bk;
   
-  if (TREE_CODE (parent) == TREE_VEC)
-    parent = BINFO_TYPE (parent);
-  else if (! IS_AGGR_TYPE_CODE (TREE_CODE (parent)))
-    my_friendly_abort (89);
-
-  if (TREE_CODE (binfo) == TREE_VEC)
-    type = BINFO_TYPE (binfo);
-  else if (IS_AGGR_TYPE_CODE (TREE_CODE (binfo)))
-    type = binfo;
-  else
-    my_friendly_abort (90);
-  
-  dist = get_base_distance (parent, binfo, protect, &rval);
-
-  if (dist == -3)
-    {
-      cp_error ("fields of `%T' are inaccessible in `%T' due to private inheritance",
-               parent, type);
-      return error_mark_node;
-    }
-  else if (dist == -2 && protect)
+  if (t == error_mark_node || base == error_mark_node)
     {
-      cp_error ("type `%T' is ambiguous base class for type `%T'", parent,
-               type);
+      if (kind_ptr)
+       *kind_ptr = bk_not_base;
       return error_mark_node;
     }
-
-  return rval;
-}
-
-/* This is the newer depth first get_base_distance routine.  */
-
-static int
-get_base_distance_recursive (binfo, depth, is_private, rval,
-                            rval_private_ptr, new_binfo_ptr, parent,
-                            protect, via_virtual_ptr, via_virtual,
-                            current_scope_in_chain)
-     tree binfo;
-     int depth, is_private, rval;
-     int *rval_private_ptr;
-     tree *new_binfo_ptr, parent;
-     int protect, *via_virtual_ptr, via_virtual;
-     int current_scope_in_chain;
-{
-  tree binfos;
-  int i, n_baselinks;
-
-  if (protect == 1
-      && !current_scope_in_chain
-      && is_friend (BINFO_TYPE (binfo), current_scope ()))
-    current_scope_in_chain = 1;
-
-  if (BINFO_TYPE (binfo) == parent || binfo == parent)
+  my_friendly_assert (TYPE_P (base), 20011127);
+  
+  if (!TYPE_P (t))
     {
-      int better = 0;
-
-      if (rval == -1)
-       /* This is the first time we've found parent.  */
-       better = 1;
-      else if (tree_int_cst_equal (BINFO_OFFSET (*new_binfo_ptr),
-                                  BINFO_OFFSET (binfo))
-              && *via_virtual_ptr && via_virtual)
-       {
-         /* A new path to the same vbase.  If this one has better
-            access or is shorter, take it.  */
-
-         if (protect)
-           better = *rval_private_ptr - is_private;
-         if (better == 0)
-           better = rval - depth;
-       }
-      else
-       {
-         /* Ambiguous base class.  */
-         rval = depth = -2;
-
-         /* If we get an ambiguity between virtual and non-virtual base
-            class, return the non-virtual in case we are ignoring
-            ambiguity.  */
-         better = *via_virtual_ptr - via_virtual;
-       }
-
-      if (better > 0)
-       {
-         rval = depth;
-         *rval_private_ptr = is_private;
-         *new_binfo_ptr = binfo;
-         *via_virtual_ptr = via_virtual;
-       }
-
-      return rval;
+      t_binfo = t;
+      t = BINFO_TYPE (t);
     }
-
-  binfos = BINFO_BASETYPES (binfo);
-  n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-  depth += 1;
-
-  /* Process base types.  */
-  for (i = 0; i < n_baselinks; i++)
+  else  
     {
-      tree base_binfo = TREE_VEC_ELT (binfos, i);
-
-      int via_private
-       = ((protect == 1
-           && (is_private
-               || (!TREE_VIA_PUBLIC (base_binfo)
-                   && !(TREE_VIA_PROTECTED (base_binfo)
-                        && current_scope_in_chain)
-                   && !is_friend (BINFO_TYPE (binfo), current_scope ()))))
-          || (protect > 1
-              && (is_private || !TREE_VIA_PUBLIC (base_binfo))));
-
-      int this_virtual = via_virtual || TREE_VIA_VIRTUAL (base_binfo);
-
-      rval = get_base_distance_recursive (base_binfo, depth, via_private,
-                                         rval, rval_private_ptr,
-                                         new_binfo_ptr, parent,
-                                         protect, via_virtual_ptr,
-                                         this_virtual,
-                                         current_scope_in_chain);
-
-      /* If we've found a non-virtual, ambiguous base class, we don't need
-        to keep searching.  */
-      if (rval == -2 && *via_virtual_ptr == 0)
-       return rval;
+      t = complete_type (TYPE_MAIN_VARIANT (t));
+      t_binfo = TYPE_BINFO (t);
     }
+  
+  base = complete_type (TYPE_MAIN_VARIANT (base));
 
-  return rval;
-}
-
-/* Return the number of levels between type PARENT and the type given
-   in BINFO, following the leftmost path to PARENT not found along a
-   virtual path, if there are no real PARENTs (all come from virtual
-   base classes), then follow the shortest public path to PARENT.
-
-   Return -1 if TYPE is not derived from PARENT.
-   Return -2 if PARENT is an ambiguous base class of TYPE, and PROTECT is
-    non-negative.
-   Return -3 if PARENT is not accessible in TYPE, and PROTECT is non-zero.
-
-   If PATH_PTR is non-NULL, then also build the list of types
-   from PARENT to TYPE, with TREE_VIA_VIRTUAL and TREE_VIA_PUBLIC
-   set.
-
-   If PROTECT is greater than 1, ignore any special access the current
-   scope might have when determining whether PARENT is inaccessible.
-
-   PARENT can also be a binfo, in which case that exact parent is found
-   and no other.  convert_pointer_to_real uses this functionality.
-
-   If BINFO is a binfo, its BINFO_INHERITANCE_CHAIN will be left alone.  */
-
-int
-get_base_distance (parent, binfo, protect, path_ptr)
-     register tree parent, binfo;
-     int protect;
-     tree *path_ptr;
-{
-  int rval;
-  int rval_private = 0;
-  tree type = NULL_TREE;
-  tree new_binfo = NULL_TREE;
-  int via_virtual;
-  int watch_access = protect;
-
-  /* Should we be completing types here?  */
-  if (TREE_CODE (parent) != TREE_VEC)
-    parent = complete_type (TYPE_MAIN_VARIANT (parent));
-  else
-    complete_type (TREE_TYPE (parent));
-
-  if (TREE_CODE (binfo) == TREE_VEC)
-    type = BINFO_TYPE (binfo);
-  else if (IS_AGGR_TYPE_CODE (TREE_CODE (binfo)))
-    {
-      type = complete_type (binfo);
-      binfo = TYPE_BINFO (type);
-
-      if (path_ptr)
-       my_friendly_assert (BINFO_INHERITANCE_CHAIN (binfo) == NULL_TREE,
-                           980827);
-    }
+  if (t_binfo)
+    bk = lookup_base_r (t_binfo, base, access, 0, &binfo);
   else
-    my_friendly_abort (92);
+    bk = bk_not_base;
 
-  if (parent == type || parent == binfo)
-    {
-      /* If the distance is 0, then we don't really need
-        a path pointer, but we shouldn't let garbage go back.  */
-      if (path_ptr)
-       *path_ptr = binfo;
-      return 0;
-    }
-
-  if (path_ptr && watch_access == 0)
-    watch_access = 1;
-
-  rval = get_base_distance_recursive (binfo, 0, 0, -1,
-                                     &rval_private, &new_binfo, parent,
-                                     watch_access, &via_virtual, 0,
-                                     0);
+  /* Check that the base is unambiguous and accessible.  */
+  if (access != ba_any)
+    switch (bk)
+      {
+      case bk_not_base:
+       break;
 
-  /* Access restrictions don't count if we found an ambiguous basetype.  */
-  if (rval == -2 && protect >= 0)
-    rval_private = 0;
+      case bk_ambig:
+       binfo = NULL_TREE;
+       if (!(access & ba_quiet))
+         {
+           error ("`%T' is an ambiguous base of `%T'", base, t);
+           binfo = error_mark_node;
+         }
+       break;
 
-  if (rval && protect && rval_private)
-    return -3;
+      default:
+       if ((access & ~ba_quiet) != ba_ignore
+           /* If BASE is incomplete, then BASE and TYPE are probably
+              the same, in which case BASE is accessible.  If they
+              are not the same, then TYPE is invalid.  In that case,
+              there's no need to issue another error here, and
+              there's no implicit typedef to use in the code that
+              follows, so we skip the check.  */
+           && COMPLETE_TYPE_P (base)
+           && !accessible_base_p (t, base))
+         {
+           if (!(access & ba_quiet))
+             {
+               error ("`%T' is an inaccessible base of `%T'", base, t);
+               binfo = error_mark_node;
+             }
+           else
+             binfo = NULL_TREE;
+           bk = bk_inaccessible;
+         }
+       break;
+      }
 
-  if (path_ptr)
-    *path_ptr = new_binfo;
-  return rval;
+  if (kind_ptr)
+    *kind_ptr = bk;
+  
+  return binfo;
 }
 
 /* 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;
+dynamic_cast_base_recurse (tree subtype, tree binfo, bool is_via_virtual,
+                          tree *offset_ptr)
 {
-  tree binfos;
-  int i, n_baselinks;
+  tree accesses;
+  tree base_binfo;
+  int i;
   int worst = -2;
   
   if (BINFO_TYPE (binfo) == subtype)
     {
-      if (via_virtual)
+      if (is_via_virtual)
         return -1;
       else
         {
@@ -497,18 +300,17 @@ dynamic_cast_base_recurse (subtype, binfo, via_virtual, offset_ptr)
         }
     }
   
-  binfos = BINFO_BASETYPES (binfo);
-  n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-  for (i = 0; i < n_baselinks; i++)
+  accesses = BINFO_BASE_ACCESSES (binfo);
+  for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
     {
-      tree base_binfo = TREE_VEC_ELT (binfos, i);
+      tree base_access = TREE_VEC_ELT (accesses, i);
       int rval;
       
-      if (!TREE_VIA_PUBLIC (base_binfo))
+      if (base_access != access_public_node)
         continue;
       rval = dynamic_cast_base_recurse
              (subtype, base_binfo,
-              via_virtual || TREE_VIA_VIRTUAL (base_binfo), offset_ptr);
+              is_via_virtual || BINFO_VIRTUAL_P (base_binfo), offset_ptr);
       if (worst == -2)
         worst = rval;
       else if (rval >= 0)
@@ -523,7 +325,7 @@ dynamic_cast_base_recurse (subtype, binfo, via_virtual, offset_ptr)
 
 /* 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
+   the inheritance graph search. This information is independent 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,
@@ -533,13 +335,11 @@ dynamic_cast_base_recurse (subtype, binfo, via_virtual, offset_ptr)
    BOFF == -3, SUBTYPE occurs as multiple public non-virtual bases.  */
 
 tree
-get_dynamic_cast_base_type (subtype, target)
-     tree subtype;
-     tree target;
+get_dynamic_cast_base_type (tree subtype, tree target)
 {
   tree offset = NULL_TREE;
   int boff = dynamic_cast_base_recurse (subtype, TYPE_BINFO (target),
-                                        0, &offset);
+                                        false, &offset);
   
   if (!boff)
     return offset;
@@ -548,20 +348,20 @@ get_dynamic_cast_base_type (subtype, target)
   return offset;
 }
 
-/* Search for a member with name NAME in a multiple inheritance lattice
-   specified by TYPE.  If it does not exist, return NULL_TREE.
+/* 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'.
-   Otherwise, return the FIELD_DECL.  */
+   Otherwise, return a DECL with the indicated name.  If WANT_TYPE is
+   true, type declarations are preferred.  */
 
 /* Do a 1-level search for NAME as a member of TYPE.  The caller must
    figure out whether it can access this field.  (Since it is only one
    level, this is reasonable.)  */
 
-static tree
-lookup_field_1 (type, name)
-     tree type, name;
+tree
+lookup_field_1 (tree type, tree name, bool want_type)
 {
-  register tree field;
+  tree field;
 
   if (TREE_CODE (type) == TEMPLATE_TYPE_PARM
       || TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM
@@ -578,8 +378,8 @@ lookup_field_1 (type, name)
       && 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)));
+      tree *fields = &DECL_SORTED_FIELDS (TYPE_NAME (type))->elts[0];
+      int lo = 0, hi = DECL_SORTED_FIELDS (TYPE_NAME (type))->len;
       int i;
 
       while (lo < hi)
@@ -596,14 +396,28 @@ lookup_field_1 (type, name)
            lo = i + 1;
          else
            {
+             field = NULL_TREE;
+
              /* 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];
+                field_decl_cmp, so just look for the first or last
+                field with this name.  */
+             if (want_type)
+               {
+                 do
+                   field = fields[i--];
+                 while (i >= lo && DECL_NAME (fields[i]) == name);
+                 if (TREE_CODE (field) != TYPE_DECL
+                     && !DECL_CLASS_TEMPLATE_P (field))
+                   field = NULL_TREE;
+               }
+             else
+               {
+                 do
+                   field = fields[i++];
+                 while (i < hi && DECL_NAME (fields[i]) == name);
+               }
+             return field;
            }
        }
       return NULL_TREE;
@@ -614,7 +428,7 @@ lookup_field_1 (type, name)
 #ifdef GATHER_STATISTICS
   n_calls_lookup_field_1++;
 #endif /* GATHER_STATISTICS */
-  while (field)
+  for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
     {
 #ifdef GATHER_STATISTICS
       n_fields_searched++;
@@ -623,26 +437,34 @@ lookup_field_1 (type, name)
       if (DECL_NAME (field) == NULL_TREE
          && ANON_AGGR_TYPE_P (TREE_TYPE (field)))
        {
-         tree temp = lookup_field_1 (TREE_TYPE (field), name);
+         tree temp = lookup_field_1 (TREE_TYPE (field), name, want_type);
          if (temp)
            return temp;
        }
       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_STATIC (field) || DECL_EXTERNAL (field)))
-           GNU_xref_ref(current_function_decl,
-                        IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (field)));
-         return field;
+         /* We generally treat class-scope using-declarations as
+            ARM-style access specifications, because support for the
+            ISO semantics has not been implemented.  So, in general,
+            there's no reason to return a USING_DECL, and the rest of
+            the compiler cannot handle that.  Once the class is
+            defined, USING_DECLs are purged from TYPE_FIELDS; see
+            handle_using_decl.  However, we make special efforts to
+            make using-declarations in template classes work
+            correctly.  */
+         if (CLASSTYPE_TEMPLATE_INFO (type)
+             && !CLASSTYPE_USE_TEMPLATE (type)
+             && !TREE_TYPE (field))
+           ;
+         else
+           continue;
        }
-      field = TREE_CHAIN (field);
+
+      if (DECL_NAME (field) == name
+         && (!want_type 
+             || TREE_CODE (field) == TYPE_DECL
+             || DECL_CLASS_TEMPLATE_P (field)))
+       return field;
     }
   /* Not found.  */
   if (name == vptr_identifier)
@@ -671,7 +493,7 @@ lookup_field_1 (type, name)
    function.  If so, we know to put the decls into the class's scope.  */
 
 tree
-current_scope ()
+current_scope (void)
 {
   if (current_function_decl == NULL_TREE)
     return current_class_type;
@@ -688,22 +510,40 @@ current_scope ()
   return current_class_type;
 }
 
-/* Returns non-zero if we are currently in a function scope.  Note
+/* Returns nonzero 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.  */
 
 int
-at_function_scope_p ()
+at_function_scope_p (void)
 {
   tree cs = current_scope ();
   return cs && TREE_CODE (cs) == FUNCTION_DECL;
 }
 
+/* Returns true if the innermost active scope is a class scope.  */
+
+bool
+at_class_scope_p (void)
+{
+  tree cs = current_scope ();
+  return cs && TYPE_P (cs);
+}
+
+/* Returns true if the innermost active scope is a namespace scope.  */
+
+bool
+at_namespace_scope_p (void)
+{
+  /* We are in a namespace scope if we are not it a class scope or a
+     function scope.  */
+  return !current_scope();
+}
+
 /* Return the scope of DECL, as appropriate when doing name-lookup.  */
 
 tree
-context_for_name_lookup (decl)
-     tree decl;
+context_for_name_lookup (tree decl)
 {
   /* [class.union]
      
@@ -721,92 +561,23 @@ context_for_name_lookup (decl)
   return context;
 }
 
-/* Return a canonical BINFO if BINFO is a virtual base, or just BINFO
-   otherwise.  */
-
-static tree
-canonical_binfo (binfo)
-     tree binfo;
-{
-  return (TREE_VIA_VIRTUAL (binfo)
-         ? TYPE_BINFO (BINFO_TYPE (binfo)) : binfo);
-}
-
-/* A queue function that simply ensures that we walk into the
-   canonical versions of virtual bases.  */
-
-static tree
-dfs_canonical_queue (binfo, data)
-     tree binfo;
-     void *data ATTRIBUTE_UNUSED;
-{
-  return canonical_binfo (binfo);
-}
-
-/* Called via dfs_walk from assert_canonical_unmarked.  */
-
-static tree
-dfs_assert_unmarked_p (binfo, data)
-     tree binfo;
-     void *data ATTRIBUTE_UNUSED;
-{
-  my_friendly_assert (!BINFO_MARKED (binfo), 0);
-  return NULL_TREE;
-}
-
-/* Asserts that all the nodes below BINFO (using the canonical
-   versions of virtual bases) are unmarked.  */
-
-static void
-assert_canonical_unmarked (binfo)
-     tree binfo;
-{
-  dfs_walk (binfo, dfs_assert_unmarked_p, dfs_canonical_queue, 0);
-}
-
-/* If BINFO is marked, return a canonical version of BINFO.
-   Otherwise, return NULL_TREE.  */
-
-static tree
-shared_marked_p (binfo, data)
-     tree binfo;
-     void *data;
-{
-  binfo = canonical_binfo (binfo);
-  return markedp (binfo, data);
-}
-
-/* If BINFO is not marked, return a canonical version of BINFO.
-   Otherwise, return NULL_TREE.  */
-
-static tree
-shared_unmarked_p (binfo, data)
-     tree binfo;
-     void *data;
-{
-  binfo = canonical_binfo (binfo);
-  return unmarkedp (binfo, data);
-}
-
 /* The accessibility routines use BINFO_ACCESS for scratch space
-   during the computation of the accssibility of some declaration.  */
+   during the computation of the accessibility of some declaration.  */
 
 #define BINFO_ACCESS(NODE) \
-  ((access_kind) ((TREE_LANG_FLAG_1 (NODE) << 1) | TREE_LANG_FLAG_6 (NODE)))
+  ((access_kind) ((TREE_PUBLIC (NODE) << 1) | TREE_PRIVATE (NODE)))
 
 /* Set the access associated with NODE to ACCESS.  */
 
 #define SET_BINFO_ACCESS(NODE, ACCESS)                 \
-  ((TREE_LANG_FLAG_1 (NODE) = (ACCESS & 2) != 0),      \
-   (TREE_LANG_FLAG_6 (NODE) = (ACCESS & 1) != 0))
+  ((TREE_PUBLIC (NODE) = ((ACCESS) & 2) != 0), \
+   (TREE_PRIVATE (NODE) = ((ACCESS) & 1) != 0))
 
 /* Called from access_in_type via dfs_walk.  Calculate the access to
    DATA (which is really a DECL) in BINFO.  */
 
 static tree
-dfs_access_in_type (binfo, data)
-     tree binfo;
-     void *data;
+dfs_access_in_type (tree binfo, void *data)
 {
   tree decl = (tree) data;
   tree type = BINFO_TYPE (binfo);
@@ -814,7 +585,7 @@ dfs_access_in_type (binfo, data)
 
   if (context_for_name_lookup (decl) == type)
     {
-      /* If we have desceneded to the scope of DECL, just note the
+      /* If we have descended to the scope of DECL, just note the
         appropriate access.  */
       if (TREE_PRIVATE (decl))
        access = ak_private;
@@ -832,51 +603,55 @@ dfs_access_in_type (binfo, data)
       if (DECL_LANG_SPECIFIC (decl) && !DECL_DISCRIMINATOR_P (decl))
        {
          tree decl_access = purpose_member (type, DECL_ACCESS (decl));
+         
          if (decl_access)
-           access = ((access_kind) 
-                     TREE_INT_CST_LOW (TREE_VALUE (decl_access)));
+           {
+             decl_access = TREE_VALUE (decl_access);
+             
+             if (decl_access == access_public_node)
+               access = ak_public;
+             else if (decl_access == access_protected_node)
+               access = ak_protected;
+             else if (decl_access == access_private_node)
+               access = ak_private;
+             else
+               my_friendly_assert (false, 20030217);
+           }
        }
 
       if (!access)
        {
          int i;
-         int n_baselinks;
-         tree binfos;
+         tree base_binfo, accesses;
          
          /* 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)
+         accesses = BINFO_BASE_ACCESSES (binfo);
+         for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
            {
-             tree base_binfo = TREE_VEC_ELT (binfos, i);
-             access_kind base_access 
-               = BINFO_ACCESS (canonical_binfo (base_binfo));
+             tree base_access = TREE_VEC_ELT (accesses, i);
+             access_kind base_access_now = BINFO_ACCESS (base_binfo);
 
-             if (base_access == ak_none || base_access == ak_private)
+             if (base_access_now == ak_none || base_access_now == ak_private)
                /* If it was not accessible in the base, or only
                   accessible as a private member, we can't access it
                   all.  */
-               base_access = ak_none;
-             else if (TREE_VIA_PROTECTED (base_binfo))
-               /* Public and protected members in the base are
+               base_access_now = ak_none;
+             else if (base_access == access_protected_node)
+               /* Public and protected members in the base become
                   protected here.  */
-               base_access = ak_protected;
-             else if (!TREE_VIA_PUBLIC (base_binfo))
-               /* Public and protected members in the base are
+               base_access_now = ak_protected;
+             else if (base_access == access_private_node)
+               /* Public and protected members in the base become
                   private here.  */
-               base_access = ak_private;
+               base_access_now = ak_private;
 
              /* See if the new access, via this base, gives more
                 access than our previous best access.  */
-             if (base_access != ak_none
-                 && (base_access == ak_public
-                     || (base_access == ak_protected
-                         && access != ak_public)
-                     || (base_access == ak_private 
-                         && access == ak_none)))
+             if (base_access_now != ak_none
+                 && (access == ak_none || base_access_now < access))
                {
-                 access = base_access;
+                 access = base_access_now;
 
                  /* If the new access is public, we can't do better.  */
                  if (access == ak_public)
@@ -891,7 +666,7 @@ dfs_access_in_type (binfo, data)
 
   /* Mark TYPE as visited so that if we reach it again we do not
      duplicate our efforts here.  */
-  SET_BINFO_MARKED (binfo);
+  BINFO_MARKED (binfo) = 1;
 
   return NULL_TREE;
 }
@@ -899,9 +674,7 @@ dfs_access_in_type (binfo, data)
 /* Return the access to DECL in TYPE.  */
 
 static access_kind
-access_in_type (type, decl)
-     tree type;
-     tree decl;
+access_in_type (tree type, tree decl)
 {
   tree binfo = TYPE_BINFO (type);
 
@@ -916,62 +689,52 @@ access_in_type (type, decl)
     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);
+  dfs_walk_real (binfo, 0, dfs_access_in_type, unmarkedp, decl);
+  dfs_walk (binfo, dfs_unmark, markedp,  0);
 
   return BINFO_ACCESS (binfo);
 }
 
-/* Called from dfs_accessible_p via dfs_walk.  */
+/* Called from accessible_p via dfs_walk.  */
 
 static tree
-dfs_accessible_queue_p (binfo, data)
-     tree binfo;
-     void *data ATTRIBUTE_UNUSED;
+dfs_accessible_queue_p (tree derived, int ix, void *data ATTRIBUTE_UNUSED)
 {
+  tree binfo = BINFO_BASE_BINFO (derived, ix);
+  
   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 ()))
+     then we can't see it, unless we are a friend of the derived class.  */
+  if (BINFO_BASE_ACCESS (derived, ix) != access_public_node
+      && !is_friend (BINFO_TYPE (derived), current_scope ()))
     return NULL_TREE;
 
-  return canonical_binfo (binfo);
+  return binfo;
 }
 
-/* Called from dfs_accessible_p via dfs_walk.  */
+/* Called from accessible_p via dfs_walk.  */
 
 static tree
-dfs_accessible_p (binfo, data)
-     tree binfo;
-     void *data;
+dfs_accessible_p (tree binfo, void *data ATTRIBUTE_UNUSED)
 {
-  int protected_ok = data != 0;
   access_kind access;
 
-  SET_BINFO_MARKED (binfo);
+  BINFO_MARKED (binfo) = 1;
   access = BINFO_ACCESS (binfo);
-  if (access == ak_public || (access == ak_protected && protected_ok))
-    return binfo;
-  else if (access != ak_none
-          && is_friend (BINFO_TYPE (binfo), current_scope ()))
+  if (access != ak_none
+      && is_friend (BINFO_TYPE (binfo), current_scope ()))
     return binfo;
 
   return NULL_TREE;
 }
 
-/* Returns non-zero if it is OK to access DECL through an object
-   indiated by BINFO in the context of DERIVED.  */
+/* Returns nonzero if it is OK to access DECL through an object
+   indicated by BINFO in the context of DERIVED.  */
 
 static int
-protected_accessible_p (decl, derived, binfo)
-     tree decl;
-     tree derived;
-     tree binfo;
+protected_accessible_p (tree decl, tree derived, tree binfo)
 {
   access_kind access;
 
@@ -1027,14 +790,11 @@ protected_accessible_p (decl, derived, binfo)
   return 1;
 }
 
-/* Returns non-zero if SCOPE is a friend of a type which would be able
+/* Returns nonzero if SCOPE is a friend of a type which would be able
    to access DECL through the object indicated by BINFO.  */
 
 static int
-friend_accessible_p (scope, decl, binfo)
-     tree scope;
-     tree decl;
-     tree binfo;
+friend_accessible_p (tree scope, tree decl, tree binfo)
 {
   tree befriending_classes;
   tree t;
@@ -1080,68 +840,41 @@ friend_accessible_p (scope, decl, binfo)
   return 0;
 }
 
-/* Perform access control on TYPE_DECL VAL, which was looked up in TYPE.
-   This is fairly complex, so here's the design:
-
-   The lang_extdef nonterminal sets type_lookups to NULL_TREE before we
-     start to process a top-level declaration.
-   As we process the decl-specifier-seq for the declaration, any types we
-     see that might need access control are passed to type_access_control,
-     which defers checking by adding them to type_lookups.
-   When we are done with the decl-specifier-seq, we record the lookups we've
-     seen in the lookups field of the typed_declspecs nonterminal.
-   When we process the first declarator, either in parse_decl or
-     begin_function_definition, we call save_type_access_control,
-     which stores the lookups from the decl-specifier-seq in
-     current_type_lookups.
-   As we finish with each declarator, we process everything in type_lookups
-     via decl_type_access_control, which resets type_lookups to the value of
-     current_type_lookups for subsequent declarators.
-   When we enter a function, we set type_lookups to error_mark_node, so all
-     lookups are processed immediately.  */
-
-void
-type_access_control (type, val)
-     tree type, val;
-{
-  if (val == NULL_TREE || TREE_CODE (val) != TYPE_DECL
-      || ! DECL_CLASS_SCOPE_P (val))
-    return;
-
-  if (type_lookups == error_mark_node)
-    enforce_access (type, val);
-  else if (! accessible_p (type, val))
-    type_lookups = tree_cons (type, val, type_lookups);
-}
-
 /* DECL is a declaration from a base class of TYPE, which was the
-   class used to name DECL.  Return non-zero if, in the current
+   class used to name DECL.  Return nonzero 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;
-     
+accessible_p (tree type, tree decl)
 {
   tree binfo;
   tree t;
+  tree scope;
+  access_kind access;
 
-  /* Non-zero if it's OK to access DECL if it has protected
+  /* Nonzero 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;
 
+  /* There is no need to perform access checks inside a thunk.  */
+  scope = current_scope ();
+  if (scope && DECL_THUNK_P (scope))
+    return 1;
+
+  /* In a template declaration, we cannot be sure whether the
+     particular specialization that is instantiated will be a friend
+     or not.  Therefore, all access checks are deferred until
+     instantiation.  */
+  if (processing_template_decl)
+    return 1;
+
   if (!TYPE_P (type))
     {
       binfo = type;
@@ -1177,7 +910,7 @@ accessible_p (type, decl)
 
   /* Now, loop through the classes of which we are a friend.  */
   if (!protected_ok)
-    protected_ok = friend_accessible_p (current_scope (), decl, binfo);
+    protected_ok = friend_accessible_p (scope, decl, binfo);
 
   /* Standardize the binfo that access_in_type will use.  We don't
      need to know what path was chosen from this point onwards.  */
@@ -1185,54 +918,22 @@ accessible_p (type, decl)
 
   /* 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
-   found as a base class and sub-object of the object denoted by
-   BINFO.  MOST_DERIVED is the most derived type of the hierarchy being
-   searched.  */
-
-static int
-is_subobject_of_p (parent, binfo, most_derived)
-     tree parent, binfo, most_derived;
-{
-  tree binfos;
-  int i, n_baselinks;
-
-  if (parent == binfo)
+  access = access_in_type (type, decl);
+  if (access == ak_public
+      || (access == ak_protected && protected_ok))
     return 1;
-
-  binfos = BINFO_BASETYPES (binfo);
-  n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-
-  /* Iterate the base types.  */
-  for (i = 0; i < n_baselinks; i++)
+  else
     {
-      tree base_binfo = TREE_VEC_ELT (binfos, i);
-      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, 
-                             CANONICAL_BINFO (base_binfo, most_derived),
-                             most_derived))
-       return 1;
+      /* Walk the hierarchy again, looking for a base class that allows
+        access.  */
+      t = dfs_walk (binfo, dfs_accessible_p, dfs_accessible_queue_p, 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, 0,  0);
+
+      return t != NULL_TREE;
     }
-  return 0;
 }
 
 struct lookup_field_info {
@@ -1247,24 +948,21 @@ struct lookup_field_info {
   /* 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.  */
+  /* If nonzero, 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
+/* Returns nonzero 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.  */
 
 static tree
-lookup_field_queue_p (binfo, data)
-     tree binfo;
-     void *data;
+lookup_field_queue_p (tree derived, int ix, void *data)
 {
+  tree binfo = BINFO_BASE_BINFO (derived, ix);
   struct lookup_field_info *lfi = (struct lookup_field_info *) data;
 
   /* Don't look for constructors or destructors in base classes.  */
@@ -1273,11 +971,14 @@ lookup_field_queue_p (binfo, data)
 
   /* 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
-      && is_subobject_of_p (binfo, lfi->rval_binfo, lfi->type))
+  if (lfi->rval_binfo && original_binfo (binfo, lfi->rval_binfo))
     return NULL_TREE;
 
-  return CANONICAL_BINFO (binfo, lfi->type);
+  /* If this is a dependent base, don't look in it.  */
+  if (BINFO_DEPENDENT_BASE_P (binfo))
+    return NULL_TREE;
+  
+  return binfo;
 }
 
 /* Within the scope of a template class, you can refer to the to the
@@ -1286,12 +987,10 @@ lookup_field_queue_p (binfo, data)
    
      template <typename T> struct S { S* sp; }
 
-   Returns non-zero if DECL is such a declaration in a class TYPE.  */
+   Returns nonzero if DECL is such a declaration in a class TYPE.  */
 
 static int
-template_self_reference_p (type, decl)
-     tree type;
-     tree decl;
+template_self_reference_p (tree type, tree decl)
 {
   return  (CLASSTYPE_USE_TEMPLATE (type)
           && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (type))
@@ -1312,8 +1011,7 @@ template_self_reference_p (type, decl)
    This function checks that T contains no nonstatic members.  */
 
 static int
-shared_member_p (t)
-     tree t;
+shared_member_p (tree t)
 {
   if (TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == TYPE_DECL \
       || TREE_CODE (t) == CONST_DECL)
@@ -1337,14 +1035,11 @@ shared_member_p (t)
    lookup_field via breadth_first_search.  */
 
 static tree
-lookup_field_r (binfo, data)
-     tree binfo;
-     void *data;
+lookup_field_r (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
@@ -1353,12 +1048,12 @@ lookup_field_r (binfo, data)
     {
       int idx = lookup_fnfields_1 (type, lfi->name);
       if (idx >= 0)
-       nval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx);
+       nval = VEC_index (tree, CLASSTYPE_METHOD_VEC (type), idx);
     }
 
   if (!nval)
     /* Look for a data member or type.  */
-    nval = lookup_field_1 (type, lfi->name);
+    nval = lookup_field_1 (type, lfi->name, lfi->want_type);
 
   /* If there is no declaration with the indicated name in this type,
      then there's nothing to do.  */
@@ -1367,7 +1062,8 @@ lookup_field_r (binfo, data)
 
   /* 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)
+  if (lfi->want_type && TREE_CODE (nval) != TYPE_DECL
+      && !DECL_CLASS_TEMPLATE_P (nval))
     {
       if (lfi->name == TYPE_IDENTIFIER (type))
        {
@@ -1382,11 +1078,12 @@ lookup_field_r (binfo, data)
        }
       else
        nval = NULL_TREE;
-      if (!nval)
+      if (!nval && CLASSTYPE_NESTED_UTDS (type) != NULL)
        {
-         nval = purpose_member (lfi->name, CLASSTYPE_TAGS (type));
-         if (nval)
-           nval = TYPE_MAIN_DECL (TREE_VALUE (nval));
+          binding_entry e = binding_table_find (CLASSTYPE_NESTED_UTDS (type),
+                                                lfi->name);
+         if (e != NULL)
+           nval = TYPE_MAIN_DECL (e->type);
          else 
            return NULL_TREE;
        }
@@ -1397,40 +1094,14 @@ lookup_field_r (binfo, data)
       && 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 && !is_subobject_of_p (lfi->rval_binfo, binfo, lfi->type))
+  if (lfi->rval_binfo && !original_binfo (lfi->rval_binfo, binfo))
     {
       if (nval == lfi->rval && shared_member_p (nval))
        /* The two things are really the same.  */
        ;
-      else if (is_subobject_of_p (binfo, lfi->rval_binfo, lfi->type))
+      else if (original_binfo (binfo, lfi->rval_binfo))
        /* The previous value hides the new one.  */
        ;
       else
@@ -1454,39 +1125,54 @@ lookup_field_r (binfo, data)
     }
   else
     {
-      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;
 }
 
+/* Return a "baselink" which BASELINK_BINFO, BASELINK_ACCESS_BINFO,
+   BASELINK_FUNCTIONS, and BASELINK_OPTYPE set to BINFO, ACCESS_BINFO,
+   FUNCTIONS, and OPTYPE respectively.  */
+
+tree
+build_baselink (tree binfo, tree access_binfo, tree functions, tree optype)
+{
+  tree baselink;
+
+  my_friendly_assert (TREE_CODE (functions) == FUNCTION_DECL
+                     || TREE_CODE (functions) == TEMPLATE_DECL
+                     || TREE_CODE (functions) == TEMPLATE_ID_EXPR
+                     || TREE_CODE (functions) == OVERLOAD,
+                     20020730);
+  my_friendly_assert (!optype || TYPE_P (optype), 20020730);
+  my_friendly_assert (TREE_TYPE (functions), 20020805);
+
+  baselink = make_node (BASELINK);
+  TREE_TYPE (baselink) = TREE_TYPE (functions);
+  BASELINK_BINFO (baselink) = binfo;
+  BASELINK_ACCESS_BINFO (baselink) = access_binfo;
+  BASELINK_FUNCTIONS (baselink) = functions;
+  BASELINK_OPTYPE (baselink) = optype;
+
+  return baselink;
+}
+
 /* Look for a member named NAME in an inheritance lattice dominated by
-   XBASETYPE.  If PROTECT is 0 or two, we do not check access.  If it is
-   1, we enforce accessibility.  If PROTECT is zero, then, for an
-   ambiguous lookup, we return NULL.  If PROTECT is 1, we issue an
-   error message.  If PROTECT is 2, we return a TREE_LIST whose
-   TREE_TYPE is error_mark_node and whose TREE_VALUEs are the list of
-   ambiguous candidates.
+   XBASETYPE.  If 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 error
+   messages about inaccessible or ambiguous lookup.  If PROTECT is 2,
+   we return a TREE_LIST whose TREE_TYPE is error_mark_node and whose
+   TREE_VALUEs are the list of ambiguous candidates.
+
+   WANT_TYPE is 1 when we should only return TYPE_DECLs.
 
-   WANT_TYPE is 1 when we should only return TYPE_DECLs, if no
-   TYPE_DECL can be found return NULL_TREE.  */
+   If nothing can be found return NULL_TREE and do not issue an error.  */
 
 tree
-lookup_member (xbasetype, name, protect, want_type)
-     register tree xbasetype, name;
-     int protect, want_type;
+lookup_member (tree xbasetype, tree name, int protect, bool want_type)
 {
   tree rval, rval_binfo = NULL_TREE;
   tree type = NULL_TREE, basetype_path = NULL_TREE;
@@ -1501,39 +1187,32 @@ lookup_member (xbasetype, name, protect, want_type)
 
   const char *errstr = 0;
 
-  if (xbasetype == current_class_type && TYPE_BEING_DEFINED (xbasetype)
-      && IDENTIFIER_CLASS_VALUE (name))
-    {
-      tree field = IDENTIFIER_CLASS_VALUE (name);
-      if (TREE_CODE (field) != FUNCTION_DECL
-         && ! (want_type && TREE_CODE (field) != TYPE_DECL))
-       /* We're in the scope of this class, and the value has already
-          been looked up.  Just return the cached value.  */
-       return field;
-    }
+  my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 20030624);
 
-  if (TREE_CODE (xbasetype) == TREE_VEC)
+  if (TREE_CODE (xbasetype) == TREE_BINFO)
     {
       type = BINFO_TYPE (xbasetype);
       basetype_path = xbasetype;
     }
-  else if (IS_AGGR_TYPE_CODE (TREE_CODE (xbasetype)))
+  else
     {
+      my_friendly_assert (IS_AGGR_TYPE_CODE (TREE_CODE (xbasetype)), 20030624);
       type = xbasetype;
-      basetype_path = TYPE_BINFO (type);
-      my_friendly_assert (BINFO_INHERITANCE_CHAIN (basetype_path) == NULL_TREE,
-                         980827);
+      xbasetype = NULL_TREE;
     }
-  else
-    my_friendly_abort (97);
 
-  complete_type (type);
+  type = complete_type (type);
+  if (!basetype_path)
+    basetype_path = TYPE_BINFO (type);
+
+  if (!basetype_path)
+    return NULL_TREE;
 
 #ifdef GATHER_STATISTICS
   n_calls_lookup_field++;
 #endif /* GATHER_STATISTICS */
 
-  memset ((PTR) &lfi, 0, sizeof (lfi));
+  memset (&lfi, 0, sizeof (lfi));
   lfi.type = type;
   lfi.name = name;
   lfi.want_type = want_type;
@@ -1561,39 +1240,21 @@ lookup_member (xbasetype, name, protect, want_type)
 
      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 (rval && protect && !is_overloaded_fn (rval))
+    perform_or_defer_access_check (basetype_path, rval);
 
   if (errstr && protect)
     {
-      cp_error (errstr, name, type);
+      error (errstr, name, type);
       if (lfi.ambiguous)
         print_candidates (lfi.ambiguous);
       rval = error_mark_node;
     }
 
-  /* 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)));
-
   if (rval && is_overloaded_fn (rval)) 
-    {
-      /* Note that the binfo we put in the baselink is the binfo where
-        we found the functions, which we need for overload
-        resolution, but which should not be passed to enforce_access;
-        rather, enforce_access wants a binfo which refers to the
-        scope in which we started looking for the function.  This
-        will generally be the binfo passed into this function as
-        xbasetype.  */
-
-      rval = tree_cons (rval_binfo, rval, NULL_TREE);
-      SET_BASELINK_P (rval);
-    }
-
+    rval = build_baselink (rval_binfo, basetype_path, rval,
+                          (IDENTIFIER_TYPENAME_P (name)
+                          ? TREE_TYPE (name): NULL_TREE));
   return rval;
 }
 
@@ -1601,14 +1262,13 @@ lookup_member (xbasetype, name, protect, want_type)
    return NULL_TREE.  */
 
 tree
-lookup_field (xbasetype, name, protect, want_type)
-     register tree xbasetype, name;
-     int protect, want_type;
+lookup_field (tree xbasetype, tree name, int protect, bool want_type)
 {
   tree rval = lookup_member (xbasetype, name, protect, want_type);
   
-  /* Ignore functions.  */
-  if (rval && TREE_CODE (rval) == TREE_LIST)
+  /* Ignore functions, but propagate the ambiguity list.  */
+  if (!error_operand_p (rval)
+      && (rval && BASELINK_P (rval)))
     return NULL_TREE;
 
   return rval;
@@ -1618,184 +1278,302 @@ lookup_field (xbasetype, name, protect, want_type)
    return NULL_TREE.  */
 
 tree
-lookup_fnfields (xbasetype, name, protect)
-     register tree xbasetype, name;
-     int protect;
+lookup_fnfields (tree xbasetype, tree name, int protect)
 {
-  tree rval = lookup_member (xbasetype, name, protect, /*want_type=*/0);
+  tree rval = lookup_member (xbasetype, name, protect, /*want_type=*/false);
 
-  /* Ignore non-functions.  */
-  if (rval && TREE_CODE (rval) != TREE_LIST)
+  /* Ignore non-functions, but propagate the ambiguity list.  */
+  if (!error_operand_p (rval)
+      && (rval && !BASELINK_P (rval)))
     return NULL_TREE;
 
   return rval;
 }
 
+/* Return the index in the CLASSTYPE_METHOD_VEC for CLASS_TYPE
+   corresponding to "operator TYPE ()", or -1 if there is no such
+   operator.  Only CLASS_TYPE itself is searched; this routine does
+   not scan the base classes of CLASS_TYPE.  */
+
+static int
+lookup_conversion_operator (tree class_type, tree type)
+{
+  int pass;
+  int i;
+  tree fn;
+  VEC(tree) *methods;
+
+  methods = CLASSTYPE_METHOD_VEC (class_type);
+
+  for (pass = 0; pass < 2; ++pass)
+    for (i = CLASSTYPE_FIRST_CONVERSION_SLOT; 
+        VEC_iterate (tree, methods, i, fn); ++i)
+      {
+       /* All the conversion operators come near the beginning of the
+          class.  Therefore, if FN is not a conversion operator, there
+          is no matching conversion operator in CLASS_TYPE.  */
+       fn = OVL_CURRENT (fn);
+       if (!DECL_CONV_FN_P (fn))
+         break;
+       
+       if (pass == 0)
+         {
+           /* On the first pass we only consider exact matches.  If
+              the types match, this slot is the one where the right
+              conversion operators can be found.  */
+           if (TREE_CODE (fn) != TEMPLATE_DECL
+               && same_type_p (DECL_CONV_FN_TYPE (fn), type))
+             return i;
+         }
+       else
+         {
+           /* On the second pass we look for template conversion
+              operators.  It may be possible to instantiate the
+              template to get the type desired.  All of the template
+              conversion operators share a slot.  By looking for
+              templates second we ensure that specializations are
+              preferred over templates.  */
+           if (TREE_CODE (fn) == TEMPLATE_DECL)
+             return i;
+         }
+      }
+
+  return -1;
+}
+
 /* 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.  */
 
 int
-lookup_fnfields_1 (type, name)
-     tree type, name;
+lookup_fnfields_1 (tree type, tree name)
 {
-  tree method_vec 
-    = CLASS_TYPE_P (type) ? CLASSTYPE_METHOD_VEC (type) : NULL_TREE;
+  VEC(tree) *method_vec;
+  tree fn;
+  tree tmp;
+  size_t i;
+  
+  if (!CLASS_TYPE_P (type))
+    return -1;
 
-  if (method_vec != 0)
+  if (COMPLETE_TYPE_P (type))
     {
-      register int i;
-      register tree *methods = &TREE_VEC_ELT (method_vec, 0);
-      int len = TREE_VEC_LENGTH (method_vec);
-      tree tmp;
+      if ((name == ctor_identifier
+          || name == base_ctor_identifier
+          || name == complete_ctor_identifier))
+       {
+         if (CLASSTYPE_LAZY_DEFAULT_CTOR (type))
+           lazily_declare_fn (sfk_constructor, type);
+         if (CLASSTYPE_LAZY_COPY_CTOR (type))
+           lazily_declare_fn (sfk_copy_constructor, type);
+       }
+      else if (name == ansi_assopname(NOP_EXPR)
+              && CLASSTYPE_LAZY_ASSIGNMENT_OP (type))
+       lazily_declare_fn (sfk_assignment_operator, type);
+    }
 
-#ifdef GATHER_STATISTICS
-      n_calls_lookup_fnfields_1++;
-#endif /* GATHER_STATISTICS */
+  method_vec = CLASSTYPE_METHOD_VEC (type);
+  if (!method_vec)
+    return -1;
 
-      /* Constructors are first...  */
-      if (name == ctor_identifier)
-       return (methods[CLASSTYPE_CONSTRUCTOR_SLOT] 
-               ? CLASSTYPE_CONSTRUCTOR_SLOT : -1);
-      /* and destructors are second.  */
-      if (name == dtor_identifier)
-       return (methods[CLASSTYPE_DESTRUCTOR_SLOT]
-               ? CLASSTYPE_DESTRUCTOR_SLOT : -1);
-
-      for (i = CLASSTYPE_FIRST_CONVERSION_SLOT; 
-          i < len && methods[i]; 
-          ++i)
-       {
 #ifdef GATHER_STATISTICS
-         n_outer_fields_searched++;
+  n_calls_lookup_fnfields_1++;
 #endif /* GATHER_STATISTICS */
 
-         tmp = OVL_CURRENT (methods[i]);
-         if (DECL_NAME (tmp) == name)
-           return i;
+  /* Constructors are first...  */
+  if (name == ctor_identifier)
+    {
+      fn = CLASSTYPE_CONSTRUCTORS (type);
+      return fn ? CLASSTYPE_CONSTRUCTOR_SLOT : -1;
+    }
+  /* and destructors are second.  */
+  if (name == dtor_identifier)
+    {
+      fn = CLASSTYPE_DESTRUCTORS (type);
+      return fn ? CLASSTYPE_DESTRUCTOR_SLOT : -1;
+    }
+  if (IDENTIFIER_TYPENAME_P (name))
+    return lookup_conversion_operator (type, TREE_TYPE (name));
 
-         /* If the type is complete and we're past the conversion ops,
-            switch to binary search.  */
-         if (! DECL_CONV_FN_P (tmp)
-             && COMPLETE_TYPE_P (type))
-           {
-             int lo = i + 1, hi = len;
+  /* Skip the conversion operators.  */
+  for (i = CLASSTYPE_FIRST_CONVERSION_SLOT;
+       VEC_iterate (tree, method_vec, i, fn);
+       ++i)
+    if (!DECL_CONV_FN_P (OVL_CURRENT (fn)))
+      break;
 
-             while (lo < hi)
-               {
-                 i = (lo + hi) / 2;
+  /* If the type is complete, use binary search.  */
+  if (COMPLETE_TYPE_P (type))
+    {
+      int lo;
+      int hi;
+
+      lo = i;
+      hi = VEC_length (tree, method_vec);
+      while (lo < hi)
+       {
+         i = (lo + hi) / 2;
 
 #ifdef GATHER_STATISTICS
-                 n_outer_fields_searched++;
+         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;
-           }
+         tmp = VEC_index (tree, method_vec, i);
+         tmp = DECL_NAME (OVL_CURRENT (tmp));
+         if (tmp > name)
+           hi = i;
+         else if (tmp < name)
+           lo = i + 1;
+         else
+           return i;
        }
+    }
+  else
+    for (; VEC_iterate (tree, method_vec, i, fn); ++i)
+      {
+#ifdef GATHER_STATISTICS
+       n_outer_fields_searched++;
+#endif /* GATHER_STATISTICS */
+       if (DECL_NAME (OVL_CURRENT (fn)) == name)
+         return i;
+      }
+
+  return -1;
+}
+
+/* DECL is the result of a qualified name lookup.  QUALIFYING_SCOPE is
+   the class or namespace used to qualify the name.  CONTEXT_CLASS is
+   the class corresponding to the object in which DECL will be used.
+   Return a possibly modified version of DECL that takes into account
+   the CONTEXT_CLASS.
 
-      /* 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 (IDENTIFIER_TYPENAME_P (name)) 
+   In particular, consider an expression like `B::m' in the context of
+   a derived class `D'.  If `B::m' has been resolved to a BASELINK,
+   then the most derived class indicated by the BASELINK_BINFO will be
+   `B', not `D'.  This function makes that adjustment.  */
+
+tree
+adjust_result_of_qualified_name_lookup (tree decl, 
+                                       tree qualifying_scope,
+                                       tree context_class)
+{
+  if (context_class && CLASS_TYPE_P (qualifying_scope) 
+      && DERIVED_FROM_P (qualifying_scope, context_class)
+      && BASELINK_P (decl))
+    {
+      tree base;
+
+      my_friendly_assert (CLASS_TYPE_P (context_class), 20020808);
+
+      /* Look for the QUALIFYING_SCOPE as a base of the CONTEXT_CLASS.
+        Because we do not yet know which function will be chosen by
+        overload resolution, we cannot yet check either accessibility
+        or ambiguity -- in either case, the choice of a static member
+        function might make the usage valid.  */
+      base = lookup_base (context_class, qualifying_scope,
+                         ba_ignore | ba_quiet, NULL);
+      if (base)
        {
-         for (i = CLASSTYPE_FIRST_CONVERSION_SLOT; 
-              i < len && methods[i]; 
-              ++i)
-           {
-             tmp = OVL_CURRENT (methods[i]);
-             if (! DECL_CONV_FN_P (tmp))
-               {
-                 /* Since all conversion operators come first, we know
-                    there is no such operator.  */
-                 break;
-               }
-             else if (TREE_CODE (tmp) == TEMPLATE_DECL)
-               return i;
-           }
+         BASELINK_ACCESS_BINFO (decl) = base;
+         BASELINK_BINFO (decl) 
+           = lookup_base (base, BINFO_TYPE (BASELINK_BINFO (decl)),
+                          ba_ignore | ba_quiet,
+                          NULL);
        }
     }
 
-  return -1;
+  return decl;
 }
+
 \f
 /* Walk the class hierarchy dominated by TYPE.  FN is called for each
-   type in the hierarchy, in a breadth-first preorder traversal.  .
+   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
+   returned and the walk is terminated.  At each node, FN is passed a
+   BINFO indicating the path from the currently visited base-class to
    TYPE.  Before each base-class is walked QFN is called.  If the
-   value returned is non-zero, the base-class is walked; otherwise it
+   value returned is nonzero, 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.  */
+   called.
+
+   Implementation notes: Uses a circular queue, which starts off on
+   the stack but gets moved to the malloc arena if it needs to be
+   enlarged.  The underflow and overflow conditions are
+   indistinguishable except by context: if head == tail and we just
+   moved the head pointer, the queue is empty, but if we just moved
+   the tail pointer, the queue is full.  
+   Start with enough room for ten concurrent base classes.  That
+   will be enough for most hierarchies.  */
+#define BFS_WALK_INITIAL_QUEUE_SIZE 10
 
 static tree
-bfs_walk (binfo, fn, qfn, data)
-     tree binfo;
-     tree (*fn) PARAMS ((tree, void *));
-     tree (*qfn) PARAMS ((tree, void *));
-     void *data;
+bfs_walk (tree binfo,
+         tree (*fn) (tree, void *),
+         tree (*qfn) (tree, int, void *),
+         void *data)
 {
-  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;
 
-  /* Start with enough room for ten base classes.  That will be enough
-     for most hierarchies.  */
-  VARRAY_TREE_INIT (bfs_bases, 10, "search_stack");
+  tree bases_initial[BFS_WALK_INITIAL_QUEUE_SIZE];
+  /* A circular queue of the base classes of BINFO.  These will be
+     built up in breadth-first order, except where QFN prunes the
+     search.  */
+  size_t head, tail;
+  size_t base_buffer_size = BFS_WALK_INITIAL_QUEUE_SIZE;
+  tree *base_buffer = bases_initial;
 
-  /* Put the first type into the stack.  */
-  VARRAY_TREE (bfs_bases, 0) = binfo;
-  tail = 1;
+  head = tail = 0;
+  base_buffer[tail++] = binfo;
 
-  for (head = 0; head < tail; ++head)
+  while (head != tail)
     {
-      int i;
-      int n_baselinks;
-      tree binfos;
-
-      /* Pull the next type out of the queue.  */
-      binfo = VARRAY_TREE (bfs_bases, head);
+      int n_bases, ix;
+      tree binfo = base_buffer[head++];
+      if (head == base_buffer_size)
+       head = 0;
 
-      /* If this is the one we're looking for, we're done.  */
-      rval = (*fn) (binfo, data);
+      /* Is this the one we're looking for?  If so, we're done.  */
+      rval = fn (binfo, data);
       if (rval)
-       break;
+       goto done;
 
-      /* Queue up the base types.  */
-      binfos = BINFO_BASETYPES (binfo);
-      n_baselinks = binfos ? TREE_VEC_LENGTH (binfos): 0;
-      for (i = 0; i < n_baselinks; i++)
+      n_bases = BINFO_N_BASE_BINFOS (binfo);
+      for (ix = 0; ix != n_bases; ix++)
        {
-         tree base_binfo = TREE_VEC_ELT (binfos, i);
-
+         tree base_binfo;
+         
          if (qfn)
-           base_binfo = (*qfn) (base_binfo, data);
-
-         if (base_binfo)
+           base_binfo = (*qfn) (binfo, ix, data);
+         else
+           base_binfo = BINFO_BASE_BINFO (binfo, ix);
+         
+         if (base_binfo)
            {
-             if (tail == VARRAY_SIZE (bfs_bases))
-               VARRAY_GROW (bfs_bases, 2 * VARRAY_SIZE (bfs_bases));
-             VARRAY_TREE (bfs_bases, tail) = base_binfo;
-             ++tail;
+             base_buffer[tail++] = base_binfo;
+             if (tail == base_buffer_size)
+               tail = 0;
+             if (tail == head)
+               {
+                 tree *new_buffer = xmalloc (2 * base_buffer_size
+                                             * sizeof (tree));
+                 memcpy (&new_buffer[0], &base_buffer[0],
+                         tail * sizeof (tree));
+                 memcpy (&new_buffer[head + base_buffer_size],
+                         &base_buffer[head],
+                         (base_buffer_size - head) * sizeof (tree));
+                 if (base_buffer_size != BFS_WALK_INITIAL_QUEUE_SIZE)
+                   free (base_buffer);
+                 base_buffer = new_buffer;
+                 head += base_buffer_size;
+                 base_buffer_size *= 2;
+               }
            }
        }
     }
 
-  /* Clean up.  */
-  VARRAY_FREE (bfs_bases);
-
+ done:
+  if (base_buffer_size != BFS_WALK_INITIAL_QUEUE_SIZE)
+    free (base_buffer);
   return rval;
 }
 
@@ -1804,16 +1582,14 @@ bfs_walk (binfo, fn, qfn, data)
    in postorder.  */
 
 tree
-dfs_walk_real (binfo, prefn, postfn, qfn, data)
-     tree binfo;
-     tree (*prefn) PARAMS ((tree, void *));
-     tree (*postfn) PARAMS ((tree, void *));
-     tree (*qfn) PARAMS ((tree, void *));
-     void *data;
+dfs_walk_real (tree binfo,
+              tree (*prefn) (tree, void *),
+              tree (*postfn) (tree, void *),
+              tree (*qfn) (tree, int, void *),
+              void *data)
 {
   int i;
-  int n_baselinks;
-  tree binfos;
+  tree base_binfo;
   tree rval = NULL_TREE;
 
   /* Call the pre-order walking function.  */
@@ -1825,21 +1601,17 @@ dfs_walk_real (binfo, prefn, postfn, qfn, data)
     }
 
   /* Process the basetypes.  */
-  binfos = BINFO_BASETYPES (binfo);
-  n_baselinks = BINFO_N_BASETYPES (binfo);
-  for (i = 0; i < n_baselinks; i++)
+  for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
     {
-      tree base_binfo = TREE_VEC_ELT (binfos, i);
-      
       if (qfn)
-       base_binfo = (*qfn) (base_binfo, data);
-
-      if (base_binfo)
        {
-         rval = dfs_walk_real (base_binfo, prefn, postfn, qfn, data);
-         if (rval)
-           return rval;
+         base_binfo = (*qfn) (binfo, i, data);
+         if (!base_binfo)
+           continue;
        }
+      rval = dfs_walk_real (base_binfo, prefn, postfn, qfn, data);
+      if (rval)
+       return rval;
     }
 
   /* Call the post-order walking function.  */
@@ -1853,75 +1625,19 @@ dfs_walk_real (binfo, prefn, postfn, qfn, data)
    performed.  */
 
 tree
-dfs_walk (binfo, fn, qfn, data)
-     tree binfo;
-     tree (*fn) PARAMS ((tree, void *));
-     tree (*qfn) PARAMS ((tree, void *));
-     void *data;
+dfs_walk (tree binfo,
+         tree (*fn) (tree, void *),
+         tree (*qfn) (tree, int, void *),
+         void *data)
 {
   return dfs_walk_real (binfo, 0, fn, qfn, data);
 }
 
-/* Returns > 0 if a function with type DRETTYPE overriding a function
-   with type BRETTYPE is covariant, as defined in [class.virtual].
-
-   Returns 1 if trivial covariance, 2 if non-trivial (requiring runtime
-   adjustment), or -1 if pedantically invalid covariance.  */
-
-static int
-covariant_return_p (brettype, drettype)
-     tree brettype, drettype;
-{
-  tree binfo;
-
-  if (TREE_CODE (brettype) == FUNCTION_DECL)
-    {
-      brettype = TREE_TYPE (TREE_TYPE (brettype));
-      drettype = TREE_TYPE (TREE_TYPE (drettype));
-    }
-  else if (TREE_CODE (brettype) == METHOD_TYPE)
-    {
-      brettype = TREE_TYPE (brettype);
-      drettype = TREE_TYPE (drettype);
-    }
-
-  if (same_type_p (brettype, drettype))
-    return 0;
-
-  if (! (TREE_CODE (brettype) == TREE_CODE (drettype)
-        && (TREE_CODE (brettype) == POINTER_TYPE
-            || TREE_CODE (brettype) == REFERENCE_TYPE)
-        && TYPE_QUALS (brettype) == TYPE_QUALS (drettype)))
-    return 0;
-
-  if (! can_convert (brettype, drettype))
-    return 0;
-
-  brettype = TREE_TYPE (brettype);
-  drettype = TREE_TYPE (drettype);
-
-  /* If not pedantic, allow any standard pointer conversion.  */
-  if (! IS_AGGR_TYPE (drettype) || ! IS_AGGR_TYPE (brettype))
-    return -1;
-
-  binfo = get_binfo (brettype, drettype, 1);
-
-  /* If we get an error_mark_node from get_binfo, it already complained,
-     so let's just succeed.  */
-  if (binfo == error_mark_node)
-    return 1;
-
-  if (! BINFO_OFFSET_ZEROP (binfo) || TREE_VIA_VIRTUAL (binfo))
-    return 2;
-  return 1;
-}
-
 /* 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;
+int
+check_final_overrider (tree overrider, tree basefn)
 {
   tree over_type = TREE_TYPE (overrider);
   tree base_type = TREE_TYPE (basefn);
@@ -1929,44 +1645,86 @@ check_final_overrider (overrider, basefn)
   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;
-  
+  int fail = 0;
+
+  if (DECL_INVALID_OVERRIDER_P (overrider))
+    return 0;
+
   if (same_type_p (base_return, over_return))
     /* OK */;
-  else if ((i = covariant_return_p (base_return, over_return)))
+  else if ((CLASS_TYPE_P (over_return) && CLASS_TYPE_P (base_return))
+          || (TREE_CODE (base_return) == TREE_CODE (over_return)
+              && POINTER_TYPE_P (base_return)))
     {
-      if (i == 2)
-       sorry ("adjusting pointers for covariant returns");
+      /* Potentially covariant.  */
+      unsigned base_quals, over_quals;
+      
+      fail = !POINTER_TYPE_P (base_return);
+      if (!fail)
+       {
+         fail = cp_type_quals (base_return) != cp_type_quals (over_return);
+         
+         base_return = TREE_TYPE (base_return);
+         over_return = TREE_TYPE (over_return);
+       }
+      base_quals = cp_type_quals (base_return);
+      over_quals = cp_type_quals (over_return);
 
-      if (pedantic && i == -1)
+      if ((base_quals & over_quals) != over_quals)
+       fail = 1;
+      
+      if (CLASS_TYPE_P (base_return) && CLASS_TYPE_P (over_return))
        {
-         cp_pedwarn_at ("invalid covariant return type for `%#D'", overrider);
-         cp_pedwarn_at ("  overriding `%#D' (must be pointer or reference to class)", basefn);
+         tree binfo = lookup_base (over_return, base_return,
+                                   ba_check | ba_quiet, NULL);
+
+         if (!binfo)
+           fail = 1;
        }
+      else if (!pedantic
+              && can_convert (TREE_TYPE (base_type), TREE_TYPE (over_type)))
+       /* GNU extension, allow trivial pointer conversions such as
+          converting to void *, or qualification conversion.  */
+       {
+         /* can_convert will permit user defined conversion from a
+            (reference to) class type. We must reject them.  */
+         over_return = non_reference (TREE_TYPE (over_type));
+         if (CLASS_TYPE_P (over_return))
+           fail = 2;
+       }
+      else
+       fail = 2;
     }
-  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 `%#D'", overrider);
-      cp_error_at ("  overriding `%#D' (must use pointer or reference)", basefn);
-      return 0;
-    }
-  else if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider)) == NULL_TREE)
+  else
+    fail = 2;
+  if (!fail)
+    /* OK */;
+  else
     {
-      cp_error_at ("conflicting return type specified for `%#D'", overrider);
-      cp_error_at ("  overriding `%#D'", basefn);
-      SET_IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider),
-                                  DECL_CONTEXT (overrider));
+      if (fail == 1)
+       {
+         cp_error_at ("invalid covariant return type for `%#D'", overrider);
+         cp_error_at ("  overriding `%#D'", basefn);
+       }
+      else
+       {
+         cp_error_at ("conflicting return type specified for `%#D'",
+                      overrider);
+         cp_error_at ("  overriding `%#D'", basefn);
+       }
+      DECL_INVALID_OVERRIDER_P (overrider) = 1;
       return 0;
     }
   
-  /* Check throw specifier is subset.  */
+  /* Check throw specifier is at least as strict.  */
   if (!comp_except_specs (base_throw, over_throw, 0))
     {
       cp_error_at ("looser throw specifier for `%#F'", overrider);
       cp_error_at ("  overriding `%#F'", basefn);
+      DECL_INVALID_OVERRIDER_P (overrider) = 1;
       return 0;
     }
+  
   return 1;
 }
 
@@ -1974,25 +1732,23 @@ check_final_overrider (overrider, basefn)
    virtual functions in TYPE's hierarchy which FNDECL overrides.
    We do not look in TYPE itself, only its bases.
    
-   Returns non-zero, if we find any. Set FNDECL's DECL_VIRTUAL_P, if we
+   Returns nonzero, if we find any. Set FNDECL's DECL_VIRTUAL_P, if we
    find that it overrides anything.
    
    We check that every function which is overridden, is correctly
    overridden.  */
 
 int
-look_for_overrides (type, fndecl)
-     tree type, fndecl;
+look_for_overrides (tree type, tree fndecl)
 {
   tree binfo = TYPE_BINFO (type);
-  tree basebinfos = BINFO_BASETYPES (binfo);
-  int nbasebinfos = basebinfos ? TREE_VEC_LENGTH (basebinfos) : 0;
+  tree base_binfo;
   int ix;
   int found = 0;
 
-  for (ix = 0; ix != nbasebinfos; ix++)
+  for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++)
     {
-      tree basetype = BINFO_TYPE (TREE_VEC_ELT (basebinfos, ix));
+      tree basetype = BINFO_TYPE (base_binfo);
       
       if (TYPE_POLYMORPHIC_P (basetype))
         found += look_for_overrides_r (basetype, fndecl);
@@ -2000,23 +1756,27 @@ look_for_overrides (type, fndecl)
   return found;
 }
 
-/* Look in TYPE for virtual functions with the same signature as FNDECL.
-   This differs from get_matching_virtual in that it will only return
-   a function from TYPE.  */
+/* Look in TYPE for virtual functions with the same signature as
+   FNDECL.  */
 
 tree
-look_for_overrides_here (type, fndecl)
-     tree type, fndecl;
+look_for_overrides_here (tree type, tree fndecl)
 {
   int ix;
 
+  /* If there are no methods in TYPE (meaning that only implicitly
+     declared methods will ever be provided for TYPE), then there are
+     no virtual functions.  */
+  if (!CLASSTYPE_METHOD_VEC (type))
+    return NULL_TREE;
+
   if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fndecl))
     ix = CLASSTYPE_DESTRUCTOR_SLOT;
   else
     ix = lookup_fnfields_1 (type, DECL_NAME (fndecl));
   if (ix >= 0)
     {
-      tree fns = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), ix);
+      tree fns = VEC_index (tree, CLASSTYPE_METHOD_VEC (type), ix);
   
       for (; fns; fns = OVL_NEXT (fns))
         {
@@ -2041,11 +1801,10 @@ look_for_overrides_here (type, fndecl)
 }
 
 /* Look in TYPE for virtual functions overridden by FNDECL. Check both
-   TYPE itself and its bases. */
+   TYPE itself and its bases.  */
 
 static int
-look_for_overrides_r (type, fndecl)
-     tree type, fndecl;
+look_for_overrides_r (tree type, tree fndecl)
 {
   tree fn = look_for_overrides_here (type, fndecl);
   if (fn)
@@ -2070,115 +1829,10 @@ look_for_overrides_r (type, fndecl)
   return look_for_overrides (type, fndecl);
 }
 
-/* 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_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_P (binfo))
-    /* This is a non-primary virtual base.  Skip it.  */
-    return NULL_TREE;
-
-  return markedp (binfo, NULL);
-}
-
-/* If BINFO is a non-primary virtual baseclass (in the hierarchy
-   dominated by TYPE), and no primary copy appears anywhere in the
-   hierarchy, return the shared copy.  If a primary copy appears
-   elsewhere, return NULL_TREE.  Otherwise, return BINFO itself; it is
-   either a non-virtual base or a primary virtual base.  */
-
-static tree
-get_shared_vbase_if_not_primary (binfo, data)
-     tree binfo;
-     void *data;
-{
-  if (TREE_VIA_VIRTUAL (binfo) && !BINFO_PRIMARY_P (binfo))
-    {
-      tree type = (tree) data;
-
-      if (TREE_CODE (type) == TREE_LIST)
-       type = TREE_PURPOSE (type);
-
-      /* 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_PRIMARY_P (binfo))
-       return NULL_TREE;
-    }
-
-  return binfo;
-}
-
-/* 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
-dfs_unmarked_real_bases_queue_p (binfo, data)
-     tree binfo;
-     void *data;
-{
-  binfo = get_shared_vbase_if_not_primary (binfo, data); 
-  return binfo ? unmarkedp (binfo, NULL) : NULL_TREE;
-}
-
-/* Like dfs_unmarked_real_bases_queue_p but walks only into things
-   that are marked, rather than unmarked.  */
-
-tree
-dfs_marked_real_bases_queue_p (binfo, data)
-     tree binfo;
-     void *data;
-{
-  binfo = get_shared_vbase_if_not_primary (binfo, data); 
-  return binfo ? markedp (binfo, NULL) : NULL_TREE;
-}
-
-/* A queue function that skips all virtual bases (and their 
-   bases).  */
-
-tree
-dfs_skip_vbases (binfo, data)
-     tree binfo;
-     void *data ATTRIBUTE_UNUSED;
-{
-  if (TREE_VIA_VIRTUAL (binfo))
-    return NULL_TREE;
-
-  return binfo;
-}
-
 /* Called via dfs_walk from dfs_get_pure_virtuals.  */
 
 static tree
-dfs_get_pure_virtuals (binfo, data)
-     tree binfo;
-     void *data;
+dfs_get_pure_virtuals (tree binfo, void *data)
 {
   tree type = (tree) data;
 
@@ -2198,7 +1852,7 @@ dfs_get_pure_virtuals (binfo, data)
                         CLASSTYPE_PURE_VIRTUALS (type));
     }
   
-  SET_BINFO_MARKED (binfo);
+  BINFO_MARKED (binfo) = 1;
 
   return NULL_TREE;
 }
@@ -2206,10 +1860,11 @@ dfs_get_pure_virtuals (binfo, data)
 /* Set CLASSTYPE_PURE_VIRTUALS for TYPE.  */
 
 void
-get_pure_virtuals (type)
-     tree type;
+get_pure_virtuals (tree type)
 {
-  tree vbases;
+  unsigned ix;
+  tree binfo;
+  VEC (tree) *vbases;
 
   /* Clear the CLASSTYPE_PURE_VIRTUALS list; whatever is already there
      is going to be overridden.  */
@@ -2220,27 +1875,23 @@ get_pure_virtuals (type)
      (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);
+  dfs_walk (TYPE_BINFO (type), dfs_get_pure_virtuals, unmarkedp, type);
+  dfs_walk (TYPE_BINFO (type), dfs_unmark, markedp, 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))
+  for (vbases = CLASSTYPE_VBASECLASSES (type), ix = 0;
+       VEC_iterate (tree, vbases, ix, binfo); ix++)
     {
       tree virtuals;
-
-      for (virtuals = BINFO_VIRTUALS (TREE_VALUE (vbases));
-          virtuals;
+      
+      for (virtuals = BINFO_VIRTUALS (binfo); virtuals;
           virtuals = TREE_CHAIN (virtuals))
        {
          tree base_fndecl = BV_FN (virtuals);
          if (DECL_NEEDS_FINAL_OVERRIDER_P (base_fndecl))
-           cp_error ("`%#D' needs a final overrider", base_fndecl);
+           error ("`%#D' needs a final overrider", base_fndecl);
        }
     }
 }
@@ -2248,53 +1899,19 @@ get_pure_virtuals (type)
 /* DEPTH-FIRST SEARCH ROUTINES.  */
 
 tree 
-markedp (binfo, data
-     tree binfo;
-     void *data ATTRIBUTE_UNUSED;
-{ 
+markedp (tree derived, int ix, void *data ATTRIBUTE_UNUSED
+{
+  tree binfo = BINFO_BASE_BINFO (derived, ix);
+  
   return BINFO_MARKED (binfo) ? binfo : NULL_TREE; 
 }
 
 tree
-unmarkedp (binfo, data) 
-     tree binfo;
-     void *data ATTRIBUTE_UNUSED;
+unmarkedp (tree derived, int ix, void *data ATTRIBUTE_UNUSED) 
 {
-  return !BINFO_MARKED (binfo) ? binfo : NULL_TREE;
-}
-
-tree
-marked_vtable_pathp (binfo, data) 
-     tree binfo;
-     void *data ATTRIBUTE_UNUSED;
-{ 
-  return BINFO_VTABLE_PATH_MARKED (binfo) ? binfo : NULL_TREE; 
-}
-
-tree
-unmarked_vtable_pathp (binfo, data) 
-     tree binfo;
-     void *data ATTRIBUTE_UNUSED;
-{ 
-  return !BINFO_VTABLE_PATH_MARKED (binfo) ? binfo : NULL_TREE; 
-}
-
-static tree
-marked_pushdecls_p (binfo, data) 
-     tree binfo;
-     void *data ATTRIBUTE_UNUSED;
-{
-  return (CLASS_TYPE_P (BINFO_TYPE (binfo))
-         && BINFO_PUSHDECLS_MARKED (binfo)) ? binfo : NULL_TREE; 
-}
-
-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;
+  tree binfo = BINFO_BASE_BINFO (derived, ix);
+  
+  return !BINFO_MARKED (binfo) ? binfo : NULL_TREE; 
 }
 
 /* The worker functions for `dfs_walk'.  These do not need to
@@ -2302,111 +1919,12 @@ unmarked_pushdecls_p (binfo, data)
    a predicate function (above).  */
 
 tree
-dfs_unmark (binfo, data) 
-     tree binfo;
-     void *data ATTRIBUTE_UNUSED;
-{ 
-  CLEAR_BINFO_MARKED (binfo); 
-  return NULL_TREE;
-}
-
-/* get virtual base class types.
-   This adds type to the vbase_types list in reverse dfs order.
-   Ordering is very important, so don't change it.  */
-
-static tree
-dfs_get_vbase_types (binfo, data)
-     tree binfo;
-     void *data;
-{
-  tree type = (tree) data;
-
-  if (TREE_VIA_VIRTUAL (binfo))
-    CLASSTYPE_VBASECLASSES (type)
-      = tree_cons (BINFO_TYPE (binfo), 
-                  binfo, 
-                  CLASSTYPE_VBASECLASSES (type));
-  SET_BINFO_MARKED (binfo);
-  return NULL_TREE;
-}
-
-/* Called via dfs_walk from mark_primary_bases.  Builds the
-   inheritance graph order list of BINFOs.  */
-
-static tree
-dfs_build_inheritance_graph_order (binfo, data)
-     tree binfo;
-     void *data;
-{
-  tree *last_binfo = (tree *) data;
-
-  if (*last_binfo)
-    TREE_CHAIN (*last_binfo) = binfo;
-  *last_binfo = binfo;
-  SET_BINFO_MARKED (binfo);
-  return NULL_TREE;
-}
-
-/* Set CLASSTYPE_VBASECLASSES for TYPE.  */
-
-void
-get_vbase_types (type)
-     tree type;
+dfs_unmark (tree binfo, void *data ATTRIBUTE_UNUSED)
 {
-  tree last_binfo;
-
-  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.  */
-  CLASSTYPE_VBASECLASSES (type) = nreverse (CLASSTYPE_VBASECLASSES (type));
-  dfs_walk (TYPE_BINFO (type), dfs_unmark, markedp, 0);
-  /* Thread the BINFOs in inheritance-graph order.  */
-  last_binfo = NULL;
-  dfs_walk_real (TYPE_BINFO (type),
-                dfs_build_inheritance_graph_order,
-                NULL,
-                unmarkedp,
-                &last_binfo);
-  dfs_walk (TYPE_BINFO (type), dfs_unmark, markedp, NULL);
-}
-
-/* Called from find_vbase_instance via dfs_walk.  */
-
-static tree
-dfs_find_vbase_instance (binfo, data)
-     tree binfo;
-     void *data;
-{
-  tree base = TREE_VALUE ((tree) data);
-
-  if (BINFO_PRIMARY_P (binfo)
-      && same_type_p (BINFO_TYPE (binfo), base))
-    return binfo;
-
+  BINFO_MARKED (binfo) = 0;
   return NULL_TREE;
 }
 
-/* Find the real occurrence of the virtual BASE (a class type) in the
-   hierarchy dominated by TYPE.  */
-
-tree
-find_vbase_instance (base, type)
-     tree base;
-     tree type;
-{
-  tree instance;
-
-  instance = binfo_for_vbase (base, type);
-  if (!BINFO_PRIMARY_P (instance))
-    return instance;
-
-  return dfs_walk (TYPE_BINFO (type), 
-                  dfs_find_vbase_instance, 
-                  NULL,
-                  build_tree_list (type, base));
-}
-
 \f
 /* Debug info for C++ classes can get very large; try to avoid
    emitting it everywhere.
@@ -2416,8 +1934,7 @@ find_vbase_instance (base, type)
    linker.  */
 
 void
-maybe_suppress_debug_info (t)
-     tree t;
+maybe_suppress_debug_info (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
@@ -2459,9 +1976,7 @@ maybe_suppress_debug_info (t)
    information anyway.  */
 
 static tree
-dfs_debug_mark (binfo, data)
-     tree binfo;
-     void *data ATTRIBUTE_UNUSED;
+dfs_debug_mark (tree binfo, void *data ATTRIBUTE_UNUSED)
 {
   tree t = BINFO_TYPE (binfo);
 
@@ -2474,10 +1989,10 @@ dfs_debug_mark (binfo, data)
    info for this base class.  */
 
 static tree 
-dfs_debug_unmarkedp (binfo, data) 
-     tree binfo;
-     void *data ATTRIBUTE_UNUSED;
-{ 
+dfs_debug_unmarkedp (tree derived, int ix, void *data ATTRIBUTE_UNUSED)
+{
+  tree binfo = BINFO_BASE_BINFO (derived, ix);
+  
   return (!CLASSTYPE_DEBUG_REQUESTED (BINFO_TYPE (binfo)) 
          ? binfo : NULL_TREE);
 }
@@ -2490,8 +2005,7 @@ dfs_debug_unmarkedp (binfo, data)
    the vtables themselves, were optimized away.  */
 
 void
-note_debug_info_needed (type)
-     tree type;
+note_debug_info_needed (tree type)
 {
   if (TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (type)))
     {
@@ -2502,220 +2016,8 @@ note_debug_info_needed (type)
   dfs_walk (TYPE_BINFO (type), dfs_debug_mark, dfs_debug_unmarkedp, 0);
 }
 \f
-/* Subroutines of push_class_decls ().  */
-
-/* Returns 1 iff BINFO is a base we shouldn't really be able to see into,
-   because it (or one of the intermediate bases) depends on template parms.  */
-
-static int
-dependent_base_p (binfo)
-     tree binfo;
-{
-  for (; binfo; binfo = BINFO_INHERITANCE_CHAIN (binfo))
-    {
-      if (currently_open_class (TREE_TYPE (binfo)))
-       break;
-      if (uses_template_parms (TREE_TYPE (binfo)))
-       return 1;
-    }
-  return 0;
-}
-
-static void
-setup_class_bindings (name, type_binding_p)
-     tree name;
-     int type_binding_p;
-{
-  tree type_binding = NULL_TREE;
-  tree value_binding;
-
-  /* If we've already done the lookup for this declaration, we're
-     done.  */
-  if (IDENTIFIER_CLASS_VALUE (name))
-    return;
-
-  /* First, deal with the type binding.  */
-  if (type_binding_p)
-    {
-      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
-       {
-         if (BASELINK_P (value_binding))
-           /* NAME is some overloaded functions.  */
-           value_binding = TREE_VALUE (value_binding);
-         pushdecl_class_level (value_binding);
-       }
-    }
-}
-
-/* Push class-level declarations for any names appearing in BINFO that
-   are TYPE_DECLS.  */
-
-static tree
-dfs_push_type_decls (binfo, data)
-     tree binfo;
-     void *data ATTRIBUTE_UNUSED;
-{
-  tree type;
-  tree fields;
-
-  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;
-}
-
-/* Push class-level declarations for any names appearing in BINFO that
-   are not TYPE_DECLS.  */
-
-static tree
-dfs_push_decls (binfo, data)
-     tree binfo;
-     void *data;
-{
-  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;
-
-         /* Farm out constructors and destructors.  */
-         end = TREE_VEC_END (method_vec);
-
-         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
-   fields that that class provides within its inheritance
-   lattice.  Where ambiguities result, we mark them
-   with `error_mark_node' so that if they are encountered
-   without explicit qualification, we can emit an error
-   message.  */
-
-void
-push_class_decls (type)
-     tree type;
-{
-  search_stack = push_search_level (search_stack, &search_obstack);
-
-  /* Enter type declarations and mark.  */
-  dfs_walk (TYPE_BINFO (type), dfs_push_type_decls, unmarked_pushdecls_p, 0);
-
-  /* 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 tree
-dfs_unuse_fields (binfo, data)
-     tree binfo;
-     void *data ATTRIBUTE_UNUSED;
-{
-  tree type = TREE_TYPE (binfo);
-  tree fields;
-
-  for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields))
-    {
-      if (TREE_CODE (fields) != FIELD_DECL)
-       continue;
-
-      TREE_USED (fields) = 0;
-      if (DECL_NAME (fields) == NULL_TREE
-         && 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, 0);
-}
-
-void
-pop_class_decls ()
-{
-  /* We haven't pushed a search level when dealing with cached classes,
-     so we'd better not try to pop it.  */
-  if (search_stack)
-    search_stack = pop_search_level (search_stack);
-}
-
-void
-print_search_statistics ()
+print_search_statistics (void)
 {
 #ifdef GATHER_STATISTICS
   fprintf (stderr, "%d fields searched in %d[%d] calls to lookup_field[_1]\n",
@@ -2729,13 +2031,7 @@ print_search_statistics ()
 }
 
 void
-init_search_processing ()
-{
-  gcc_obstack_init (&search_obstack);
-}
-
-void
-reinit_search_statistics ()
+reinit_search_statistics (void)
 {
 #ifdef GATHER_STATISTICS
   n_fields_searched = 0;
@@ -2748,24 +2044,24 @@ reinit_search_statistics ()
 }
 
 static tree
-add_conversions (binfo, data)
-     tree binfo;
-     void *data;
+add_conversions (tree binfo, void *data)
 {
-  int i;
-  tree method_vec = CLASSTYPE_METHOD_VEC (BINFO_TYPE (binfo));
+  size_t i;
+  VEC(tree) *method_vec = CLASSTYPE_METHOD_VEC (BINFO_TYPE (binfo));
   tree *conversions = (tree *) data;
+  tree tmp;
 
   /* 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)
+  for (i = CLASSTYPE_FIRST_CONVERSION_SLOT; 
+       VEC_iterate (tree, method_vec, i, tmp);
+       ++i)
     {
-      tree tmp = TREE_VEC_ELT (method_vec, i);
       tree name;
 
-      if (!tmp || ! DECL_CONV_FN_P (OVL_CURRENT (tmp)))
+      if (!DECL_CONV_FN_P (OVL_CURRENT (tmp)))
        break;
 
       name = DECL_NAME (OVL_CURRENT (tmp));
@@ -2773,8 +2069,27 @@ add_conversions (binfo, data)
       /* Make sure we don't already have this conversion.  */
       if (! IDENTIFIER_MARKED (name))
        {
-         *conversions = tree_cons (binfo, tmp, *conversions);
-         IDENTIFIER_MARKED (name) = 1;
+         tree t;
+
+         /* Make sure that we do not already have a conversion
+            operator for this type.  Merely checking the NAME is not
+            enough because two conversion operators to the same type
+            may not have the same NAME.  */
+         for (t = *conversions; t; t = TREE_CHAIN (t))
+           {
+             tree fn;
+             for (fn = TREE_VALUE (t); fn; fn = OVL_NEXT (fn))
+               if (same_type_p (TREE_TYPE (name),
+                                DECL_CONV_FN_TYPE (OVL_CURRENT (fn))))
+                 break;
+             if (fn)
+               break;
+           }
+         if (!t)
+           {
+             *conversions = tree_cons (binfo, tmp, *conversions);
+             IDENTIFIER_MARKED (name) = 1;
+           }
        }
     }
   return NULL_TREE;
@@ -2787,13 +2102,13 @@ add_conversions (binfo, data)
    from which the conversion functions in this node were selected.  */
 
 tree
-lookup_conversions (type)
-     tree type;
+lookup_conversions (tree type)
 {
   tree t;
   tree conversions = NULL_TREE;
 
-  if (COMPLETE_TYPE_P (type))
+  complete_type (type);
+  if (TYPE_BINFO (type))
     bfs_walk (TYPE_BINFO (type), add_conversions, 0, &conversions);
 
   for (t = conversions; t; t = TREE_CHAIN (t))
@@ -2812,22 +2127,21 @@ struct overlap_info
    at offset 0 in COMPARE_TYPE, and set found_overlap if so.  */
 
 static tree
-dfs_check_overlap (empty_binfo, data)
-     tree empty_binfo;
-     void *data;
+dfs_check_overlap (tree empty_binfo, void *data)
 {
   struct overlap_info *oi = (struct overlap_info *) data;
   tree binfo;
+  
   for (binfo = TYPE_BINFO (oi->compare_type); 
        ; 
-       binfo = BINFO_BASETYPE (binfo, 0))
+       binfo = BINFO_BASE_BINFO (binfo, 0))
     {
       if (BINFO_TYPE (binfo) == BINFO_TYPE (empty_binfo))
        {
          oi->found_overlap = 1;
          break;
        }
-      else if (BINFO_BASETYPES (binfo) == NULL_TREE)
+      else if (!BINFO_N_BASE_BINFOS (binfo))
        break;
     }
 
@@ -2837,11 +2151,11 @@ dfs_check_overlap (empty_binfo, data)
 /* Trivial function to stop base traversal when we find something.  */
 
 static tree
-dfs_no_overlap_yet (binfo, data)
-     tree binfo;
-     void *data;
+dfs_no_overlap_yet (tree derived, int ix, void *data)
 {
+  tree binfo = BINFO_BASE_BINFO (derived, ix);
   struct overlap_info *oi = (struct overlap_info *) data;
+  
   return !oi->found_overlap ? binfo : NULL_TREE;
 }
 
@@ -2849,8 +2163,7 @@ dfs_no_overlap_yet (binfo, data)
    offset 0 in NEXT_TYPE.  Used in laying out empty base class subobjects.  */
 
 int
-types_overlap_p (empty_type, next_type)
-     tree empty_type, next_type;
+types_overlap_p (tree empty_type, tree next_type)
 {
   struct overlap_info oi;
 
@@ -2863,45 +2176,15 @@ types_overlap_p (empty_type, next_type)
   return oi.found_overlap;
 }
 
-/* Given a vtable VAR, determine which of the inherited classes the vtable
-   inherits (in a loose sense) functions from.
-
-   FIXME: This does not work with the new ABI.  */
-
-tree
-binfo_for_vtable (var)
-     tree var;
-{
-  tree main_binfo = TYPE_BINFO (DECL_CONTEXT (var));
-  tree binfos = TYPE_BINFO_BASETYPES (BINFO_TYPE (main_binfo));
-  int n_baseclasses = CLASSTYPE_N_BASECLASSES (BINFO_TYPE (main_binfo));
-  int i;
-
-  for (i = 0; i < n_baseclasses; i++)
-    {
-      tree base_binfo = TREE_VEC_ELT (binfos, i);
-      if (base_binfo != NULL_TREE && BINFO_VTABLE (base_binfo) == var)
-       return base_binfo;
-    }
-
-  /* If no secondary base classes matched, return the primary base, if
-     there is one.   */
-  if (CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (main_binfo)))
-    return get_primary_binfo (main_binfo);
-
-  return main_binfo;
-}
-
 /* Returns the binfo of the first direct or indirect virtual base derived
    from BINFO, or NULL if binfo is not via virtual.  */
 
 tree
-binfo_from_vbase (binfo)
-     tree binfo;
+binfo_from_vbase (tree binfo)
 {
   for (; binfo; binfo = BINFO_INHERITANCE_CHAIN (binfo))
     {
-      if (TREE_VIA_VIRTUAL (binfo))
+      if (BINFO_VIRTUAL_P (binfo))
        return binfo;
     }
   return NULL_TREE;
@@ -2912,29 +2195,109 @@ binfo_from_vbase (binfo)
    via virtual.  */
 
 tree
-binfo_via_virtual (binfo, limit)
-     tree binfo;
-     tree limit;
+binfo_via_virtual (tree binfo, tree limit)
 {
   for (; binfo && (!limit || !same_type_p (BINFO_TYPE (binfo), limit));
        binfo = BINFO_INHERITANCE_CHAIN (binfo))
     {
-      if (TREE_VIA_VIRTUAL (binfo))
+      if (BINFO_VIRTUAL_P (binfo))
        return binfo;
     }
   return NULL_TREE;
 }
 
-/* Returns the BINFO (if any) for the virtual baseclass T of the class
-   C from the CLASSTYPE_VBASECLASSES list.  */
+/* BINFO is a base binfo in the complete type BINFO_TYPE (HERE).
+   Find the equivalent binfo within whatever graph HERE is located.
+   This is the inverse of original_binfo.  */
 
 tree
-binfo_for_vbase (basetype, classtype)
-     tree basetype;
-     tree classtype;
+copied_binfo (tree binfo, tree here)
 {
+  tree result = NULL_TREE;
+  
+  if (BINFO_VIRTUAL_P (binfo))
+    {
+      tree t;
+
+      for (t = here; BINFO_INHERITANCE_CHAIN (t);
+          t = BINFO_INHERITANCE_CHAIN (t))
+       continue;
+
+      result = binfo_for_vbase (BINFO_TYPE (binfo), BINFO_TYPE (t));
+    }
+  else if (BINFO_INHERITANCE_CHAIN (binfo))
+    {
+      tree cbinfo;
+      tree base_binfo;
+      int ix;
+      
+      cbinfo = copied_binfo (BINFO_INHERITANCE_CHAIN (binfo), here);
+      for (ix = 0; BINFO_BASE_ITERATE (cbinfo, ix, base_binfo); ix++)
+       if (BINFO_TYPE (base_binfo) == BINFO_TYPE (binfo))
+         {
+           result = base_binfo;
+           break;
+         }
+    }
+  else
+    {
+      my_friendly_assert (BINFO_TYPE (here) == BINFO_TYPE (binfo), 20030202);
+      result = here;
+    }
+
+  my_friendly_assert (result, 20030202);
+  return result;
+}
+
+tree
+binfo_for_vbase (tree base, tree t)
+{
+  unsigned ix;
   tree binfo;
+  VEC (tree) *vbases;
+  
+  for (vbases = CLASSTYPE_VBASECLASSES (t), ix = 0;
+       VEC_iterate (tree, vbases, ix, binfo); ix++)
+    if (BINFO_TYPE (binfo) == base)
+      return binfo;
+  return NULL;
+}
 
-  binfo = purpose_member (basetype, CLASSTYPE_VBASECLASSES (classtype));
-  return binfo ? TREE_VALUE (binfo) : NULL_TREE;
+/* BINFO is some base binfo of HERE, within some other
+   hierarchy. Return the equivalent binfo, but in the hierarchy
+   dominated by HERE.  This is the inverse of copied_binfo.  If BINFO
+   is not a base binfo of HERE, returns NULL_TREE.  */
+
+tree
+original_binfo (tree binfo, tree here)
+{
+  tree result = NULL;
+  
+  if (BINFO_TYPE (binfo) == BINFO_TYPE (here))
+    result = here;
+  else if (BINFO_VIRTUAL_P (binfo))
+    result = (CLASSTYPE_VBASECLASSES (BINFO_TYPE (here))
+             ? binfo_for_vbase (BINFO_TYPE (binfo), BINFO_TYPE (here))
+             : NULL_TREE);
+  else if (BINFO_INHERITANCE_CHAIN (binfo))
+    {
+      tree base_binfos;
+      
+      base_binfos = original_binfo (BINFO_INHERITANCE_CHAIN (binfo), here);
+      if (base_binfos)
+       {
+         int ix;
+         tree base_binfo;
+         
+         for (ix = 0; (base_binfo = BINFO_BASE_BINFO (base_binfos, ix)); ix++)
+           if (BINFO_TYPE (base_binfo) == BINFO_TYPE (binfo))
+             {
+               result = base_binfo;
+               break;
+             }
+       }
+    }
+  
+  return result;
 }
+