OSDN Git Service

Make DECL_CONTEXT mean the class in which a member function was
[pf3gnuchains/gcc-fork.git] / gcc / cp / search.c
index 74b9c2d..7886f48 100644 (file)
@@ -1,6 +1,6 @@
 /* Breadth-first and depth-first routines for
    searching multiple-inheritance lattice for GNU C++.
-   Copyright (C) 1987, 89, 92-97, 1998, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1987, 89, 92-97, 1998, 1999, 2000 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
@@ -31,13 +31,11 @@ Boston, MA 02111-1307, USA.  */
 #include "rtl.h"
 #include "output.h"
 #include "toplev.h"
-#include "varray.h"
 
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
 
 extern struct obstack *current_obstack;
-extern tree abort_fndecl;
 
 #include "stack.h"
 
@@ -77,80 +75,79 @@ pop_stack_level (stack)
 #define search_level stack_level
 static struct search_level *search_stack;
 
-static tree get_abstract_virtuals_1 PROTO((tree, int, tree));
-static tree next_baselink PROTO((tree));
-static tree get_vbase_1 PROTO((tree, tree, unsigned int *));
-static tree convert_pointer_to_vbase PROTO((tree, tree));
-static tree lookup_field_1 PROTO((tree, tree));
-static tree convert_pointer_to_single_level PROTO((tree, tree));
-static int lookup_fnfields_here PROTO((tree, tree));
-static int is_subobject_of_p PROTO((tree, tree));
-static int hides PROTO((tree, tree));
-static tree virtual_context PROTO((tree, tree, tree));
-static tree dfs_check_overlap PROTO((tree, void *));
-static tree dfs_no_overlap_yet PROTO((tree, void *));
+static tree next_baselink PARAMS ((tree));
+static tree get_vbase_1 PARAMS ((tree, tree, unsigned int *));
+static tree lookup_field_1 PARAMS ((tree, tree));
+static tree convert_pointer_to_single_level PARAMS ((tree, tree));
+static int lookup_fnfields_here PARAMS ((tree, tree));
+static int is_subobject_of_p PARAMS ((tree, tree));
+static int hides PARAMS ((tree, tree));
+static tree virtual_context PARAMS ((tree, tree, tree));
+static tree dfs_check_overlap PARAMS ((tree, void *));
+static tree dfs_no_overlap_yet PARAMS ((tree, void *));
 static int get_base_distance_recursive
-       PROTO((tree, int, int, int, int *, tree *, tree,
+       PARAMS ((tree, int, int, int, int *, tree *, tree,
               int, int *, int, int));
+static int dynamic_cast_base_recurse PARAMS ((tree, tree, int, tree *));
 static void expand_upcast_fixups 
-       PROTO((tree, tree, tree, tree, tree, tree, tree *));
+       PARAMS ((tree, tree, tree, tree, tree, tree, tree *));
 static void fixup_virtual_upcast_offsets
-       PROTO((tree, tree, int, int, tree, tree, tree, tree,
+       PARAMS ((tree, tree, int, int, tree, tree, tree, tree,
               tree *));
-static tree unmarkedp PROTO((tree, void *));
-static tree marked_vtable_pathp PROTO((tree, void *));
-static tree unmarked_vtable_pathp PROTO((tree, void *));
-static tree marked_new_vtablep PROTO((tree, void *));
-static tree unmarked_new_vtablep PROTO((tree, void *));
-static tree marked_pushdecls_p PROTO((tree, void *));
-static tree unmarked_pushdecls_p PROTO((tree, void *));
-static tree dfs_debug_unmarkedp PROTO((tree, void *));
-static tree dfs_debug_mark PROTO((tree, void *));
-static tree dfs_find_vbases PROTO((tree, void *));
-static tree dfs_clear_vbase_slots PROTO((tree, void *));
-static tree dfs_init_vbase_pointers PROTO((tree, void *));
-static tree dfs_get_vbase_types PROTO((tree, void *));
-static tree dfs_push_type_decls PROTO((tree, void *));
-static tree dfs_push_decls PROTO((tree, void *));
-static tree dfs_unuse_fields PROTO((tree, void *));
-static tree add_conversions PROTO((tree, void *));
-static tree get_virtuals_named_this PROTO((tree, tree));
-static tree get_virtual_destructor PROTO((tree, void *));
-static tree tree_has_any_destructor_p PROTO((tree, void *));
-static int covariant_return_p PROTO((tree, tree));
+static tree marked_vtable_pathp PARAMS ((tree, void *));
+static tree unmarked_vtable_pathp PARAMS ((tree, void *));
+static tree marked_new_vtablep PARAMS ((tree, void *));
+static tree unmarked_new_vtablep PARAMS ((tree, void *));
+static tree marked_pushdecls_p PARAMS ((tree, void *));
+static tree unmarked_pushdecls_p PARAMS ((tree, void *));
+#if 0
+static tree dfs_debug_unmarkedp PARAMS ((tree, void *));
+static tree dfs_debug_mark PARAMS ((tree, void *));
+#endif
+static tree dfs_find_vbases PARAMS ((tree, void *));
+static tree dfs_clear_vbase_slots PARAMS ((tree, void *));
+static tree dfs_init_vbase_pointers PARAMS ((tree, void *));
+static tree dfs_get_vbase_types PARAMS ((tree, void *));
+static tree dfs_push_type_decls PARAMS ((tree, void *));
+static tree dfs_push_decls PARAMS ((tree, void *));
+static tree dfs_unuse_fields PARAMS ((tree, void *));
+static tree add_conversions PARAMS ((tree, void *));
+static tree get_virtuals_named_this PARAMS ((tree, tree));
+static tree get_virtual_destructor PARAMS ((tree, void *));
+static tree tree_has_any_destructor_p PARAMS ((tree, void *));
+static int covariant_return_p PARAMS ((tree, tree));
+static int check_final_overrider PARAMS ((tree, tree));
 static struct search_level *push_search_level
-       PROTO((struct stack_level *, struct obstack *));
+       PARAMS ((struct stack_level *, struct obstack *));
 static struct search_level *pop_search_level
-       PROTO((struct stack_level *));
+       PARAMS ((struct stack_level *));
 static tree bfs_walk
-       PROTO((tree, tree (*) (tree, void *), tree (*) (tree, void *),
+       PARAMS ((tree, tree (*) (tree, void *), tree (*) (tree, void *),
               void *));
-static tree lookup_field_queue_p PROTO((tree, void *));
-static tree lookup_field_r PROTO((tree, void *));
-static tree dfs_walk_real PROTO ((tree, 
-                                 tree (*) (tree, void *),
-                                 tree (*) (tree, void *),
-                                 tree (*) (tree, void *),
-                                 void *));
-static tree dfs_bfv_queue_p PROTO ((tree, void *));
-static tree dfs_bfv_helper PROTO ((tree, void *));
-static tree get_virtuals_named_this_r PROTO ((tree, void *));
-static tree context_for_name_lookup PROTO ((tree));
-static tree canonical_binfo PROTO ((tree));
-static tree shared_marked_p PROTO ((tree, void *));
-static tree shared_unmarked_p PROTO ((tree, void *));
-static int  dependent_base_p PROTO ((tree));
-static tree dfs_accessible_queue_p PROTO ((tree, void *));
-static tree dfs_accessible_p PROTO ((tree, void *));
-static tree dfs_access_in_type PROTO ((tree, void *));
-static tree access_in_type PROTO ((tree, tree));
-static tree dfs_canonical_queue PROTO ((tree, void *));
-static tree dfs_assert_unmarked_p PROTO ((tree, void *));
-static void assert_canonical_unmarked PROTO ((tree));
-static int protected_accessible_p PROTO ((tree, tree, tree, tree));
-static int friend_accessible_p PROTO ((tree, tree, tree, tree));
-static void setup_class_bindings PROTO ((tree, int));
-static int template_self_reference_p PROTO ((tree, tree));
+static tree lookup_field_queue_p PARAMS ((tree, void *));
+static tree lookup_field_r PARAMS ((tree, void *));
+static tree get_virtuals_named_this_r PARAMS ((tree, void *));
+static tree context_for_name_lookup PARAMS ((tree));
+static tree canonical_binfo PARAMS ((tree));
+static tree shared_marked_p PARAMS ((tree, void *));
+static tree shared_unmarked_p PARAMS ((tree, void *));
+static int  dependent_base_p PARAMS ((tree));
+static tree dfs_accessible_queue_p PARAMS ((tree, void *));
+static tree dfs_accessible_p PARAMS ((tree, void *));
+static tree dfs_access_in_type PARAMS ((tree, void *));
+static tree access_in_type PARAMS ((tree, tree));
+static tree dfs_canonical_queue PARAMS ((tree, void *));
+static tree dfs_assert_unmarked_p PARAMS ((tree, void *));
+static void assert_canonical_unmarked PARAMS ((tree));
+static int protected_accessible_p PARAMS ((tree, tree, tree, tree));
+static int friend_accessible_p PARAMS ((tree, tree, tree, tree));
+static void setup_class_bindings PARAMS ((tree, int));
+static int template_self_reference_p PARAMS ((tree, tree));
+static void fixup_all_virtual_upcast_offsets PARAMS ((tree, tree));
+static tree dfs_mark_primary_bases PARAMS ((tree, void *));
+static tree get_shared_vbase_if_not_primary PARAMS ((tree, void *));
+static tree dfs_find_vbase_instance PARAMS ((tree, void *));
+static tree dfs_get_pure_virtuals PARAMS ((tree, void *));
 
 /* Allocate a level of searching.  */
 
@@ -176,8 +173,6 @@ pop_search_level (obstack)
   return stack;
 }
 \f
-static tree _vptr_name;
-
 /* Variables for gathering statistics.  */
 #ifdef GATHER_STATISTICS
 static int n_fields_searched;
@@ -250,7 +245,7 @@ get_vbase (parent, binfo)
    EXPR is a non-null POINTER_TYPE to RECORD_TYPE.  We also know that
    the type of what expr points to has a virtual base of type TYPE.  */
 
-static tree
+tree
 convert_pointer_to_vbase (type, expr)
      tree type;
      tree expr;
@@ -486,8 +481,7 @@ get_base_distance (parent, binfo, protect, path_ptr)
      tree, deal with it.  This happens when we are called from
      expand_upcast_fixups.  */
   if (rval == -1 && TREE_CODE (parent) == TREE_VEC
-      && parent == binfo_member (BINFO_TYPE (parent),
-                                CLASSTYPE_VBASECLASSES (type)))
+      && parent == BINFO_FOR_VBASE (BINFO_TYPE (parent), type))
     {
       my_friendly_assert (BINFO_INHERITANCE_CHAIN (parent) == binfo, 980827);
       new_binfo = parent;
@@ -499,6 +493,79 @@ get_base_distance (parent, binfo, protect, path_ptr)
   return rval;
 }
 
+/* Worker function for get_dynamic_cast_base_type.  */
+
+static int
+dynamic_cast_base_recurse (subtype, binfo, via_virtual, offset_ptr)
+     tree subtype;
+     tree binfo;
+     int via_virtual;
+     tree *offset_ptr;
+{
+  tree binfos;
+  int i, n_baselinks;
+  int worst = -2;
+  
+  if (BINFO_TYPE (binfo) == subtype)
+    {
+      if (via_virtual)
+        return -1;
+      else
+        {
+          *offset_ptr = BINFO_OFFSET (binfo);
+          return 0;
+        }
+    }
+  
+  binfos = BINFO_BASETYPES (binfo);
+  n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+  for (i = 0; i < n_baselinks; i++)
+    {
+      tree base_binfo = TREE_VEC_ELT (binfos, i);
+      int rval;
+      
+      if (!TREE_VIA_PUBLIC (base_binfo))
+        continue;
+      rval = dynamic_cast_base_recurse
+             (subtype, base_binfo,
+              via_virtual || TREE_VIA_VIRTUAL (base_binfo), offset_ptr);
+      if (worst == -2)
+        worst = rval;
+      else if (rval >= 0)
+        worst = worst >= 0 ? -3 : worst;
+      else if (rval == -1)
+        worst = -1;
+      else if (rval == -3 && worst != -1)
+        worst = -3;
+    }
+  return worst;
+}
+
+/* The dynamic cast runtime needs a hint about how the static SUBTYPE type
+   started from is related to the required TARGET type, in order to optimize
+   the inheritance graph search. This information is independant of the
+   current context, and ignores private paths, hence get_base_distance is
+   inappropriate. Return a TREE specifying the base offset, BOFF.
+   BOFF >= 0, there is only one public non-virtual SUBTYPE base at offset BOFF,
+      and there are no public virtual SUBTYPE bases.
+   BOFF == -1, SUBTYPE occurs as multiple public virtual or non-virtual bases.
+   BOFF == -2, SUBTYPE is not a public base.
+   BOFF == -3, SUBTYPE occurs as multiple public non-virtual bases.  */
+
+tree
+get_dynamic_cast_base_type (subtype, target)
+     tree subtype;
+     tree target;
+{
+  tree offset = NULL_TREE;
+  int boff = dynamic_cast_base_recurse (subtype, TYPE_BINFO (target),
+                                        0, &offset);
+  
+  if (!boff)
+    return offset;
+  return build_int_2 (boff, -1);
+}
+
 /* Search for a member with name NAME in a multiple inheritance lattice
    specified by TYPE.  If it does not exist, return NULL_TREE.
    If the member is ambiguously referenced, return `error_mark_node'.
@@ -522,6 +589,41 @@ lookup_field_1 (type, name)
        of fields!)  */
     return NULL_TREE;
 
+  if (TYPE_NAME (type)
+      && DECL_LANG_SPECIFIC (TYPE_NAME (type))
+      && DECL_SORTED_FIELDS (TYPE_NAME (type)))
+    {
+      tree *fields = &TREE_VEC_ELT (DECL_SORTED_FIELDS (TYPE_NAME (type)), 0);
+      int lo = 0, hi = TREE_VEC_LENGTH (DECL_SORTED_FIELDS (TYPE_NAME (type)));
+      int i;
+
+      while (lo < hi)
+       {
+         i = (lo + hi) / 2;
+
+#ifdef GATHER_STATISTICS
+         n_fields_searched++;
+#endif /* GATHER_STATISTICS */
+
+         if (DECL_NAME (fields[i]) > name)
+           hi = i;
+         else if (DECL_NAME (fields[i]) < name)
+           lo = i + 1;
+         else
+           {
+             /* We might have a nested class and a field with the
+                same name; we sorted them appropriately via
+                field_decl_cmp, so just look for the last field with
+                this name.  */
+             while (i + 1 < hi
+                    && DECL_NAME (fields[i+1]) == name)
+               ++i;
+             return fields[i];
+           }
+       }
+      return NULL_TREE;
+    }
+
   field = TYPE_FIELDS (type);
 
 #ifdef GATHER_STATISTICS
@@ -534,7 +636,7 @@ lookup_field_1 (type, name)
 #endif /* GATHER_STATISTICS */
       my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (field)) == 'd', 0);
       if (DECL_NAME (field) == NULL_TREE
-         && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
+         && ANON_AGGR_TYPE_P (TREE_TYPE (field)))
        {
          tree temp = lookup_field_1 (TREE_TYPE (field), name);
          if (temp)
@@ -558,11 +660,11 @@ lookup_field_1 (type, name)
       field = TREE_CHAIN (field);
     }
   /* Not found.  */
-  if (name == _vptr_name)
+  if (name == vptr_identifier)
     {
       /* Give the user what s/he thinks s/he wants.  */
-      if (TYPE_VIRTUAL_P (type))
-       return CLASSTYPE_VFIELD (type);
+      if (TYPE_POLYMORPHIC_P (type))
+       return TYPE_VFIELD (type);
     }
   return NULL_TREE;
 }
@@ -590,12 +692,28 @@ current_scope ()
     return current_class_type;
   if (current_class_type == NULL_TREE)
     return current_function_decl;
-  if (DECL_CLASS_CONTEXT (current_function_decl) == current_class_type)
+  if ((DECL_FUNCTION_MEMBER_P (current_function_decl)
+       && same_type_p (DECL_CONTEXT (current_function_decl),
+                      current_class_type))
+      || (DECL_FRIEND_CONTEXT (current_function_decl)
+         && same_type_p (DECL_FRIEND_CONTEXT (current_function_decl),
+                         current_class_type)))
     return current_function_decl;
 
   return current_class_type;
 }
 
+/* Returns non-zero if we are currently in a function scope.  Note
+   that this function returns zero if we are within a local class, but
+   not within a member function body of the local class.  */
+
+int
+at_function_scope_p ()
+{
+  tree cs = current_scope ();
+  return cs && TREE_CODE (cs) == FUNCTION_DECL;
+}
+
 /* Return the scope of DECL, as appropriate when doing name-lookup.  */
 
 static tree
@@ -608,9 +726,9 @@ context_for_name_lookup (decl)
      definition, the members of the anonymous union are considered to
      have been defined in the scope in which teh anonymous union is
      declared.  */ 
-  tree context = DECL_REAL_CONTEXT (decl);
+  tree context = CP_DECL_CONTEXT (decl);
 
-  while (TYPE_P (context) && ANON_UNION_TYPE_P (context))
+  while (TYPE_P (context) && ANON_AGGR_TYPE_P (context))
     context = TYPE_CONTEXT (context);
   if (!context)
     context = global_namespace;
@@ -670,7 +788,7 @@ shared_marked_p (binfo, data)
      void *data;
 {
   binfo = canonical_binfo (binfo);
-  return markedp (binfo, data) ? binfo : NULL_TREE;
+  return markedp (binfo, data);
 }
 
 /* If BINFO is not marked, return a canonical version of BINFO.
@@ -682,7 +800,7 @@ shared_unmarked_p (binfo, data)
      void *data;
 {
   binfo = canonical_binfo (binfo);
-  return unmarkedp (binfo, data) ? binfo : NULL_TREE;
+  return unmarkedp (binfo, data);
 }
 
 /* Called from access_in_type via dfs_walk.  Calculate the access to
@@ -939,13 +1057,21 @@ friend_accessible_p (scope, type, decl, binfo)
     if (protected_accessible_p (type, decl, TREE_VALUE (t), binfo))
       return 1;
 
+  /* Nested classes are implicitly friends of their enclosing types, as
+     per core issue 45 (this is a change from the standard).  */
+  if (TYPE_P (scope))
+    for (t = TYPE_CONTEXT (scope); t && TYPE_P (t); t = TYPE_CONTEXT (t))
+      if (protected_accessible_p (type, decl, t, binfo))
+       return 1;
+
   if (TREE_CODE (scope) == FUNCTION_DECL
       || DECL_FUNCTION_TEMPLATE_P (scope))
     {
       /* Perhaps this SCOPE is a member of a class which is a 
         friend.  */ 
-      if (friend_accessible_p (DECL_CLASS_CONTEXT (scope), type,
-                              decl, binfo))
+      if (DECL_CLASS_SCOPE_P (decl)
+         && friend_accessible_p (DECL_CONTEXT (scope), type,
+                                 decl, binfo))
        return 1;
 
       /* Or an instantiation of something which is a friend.  */
@@ -959,9 +1085,44 @@ friend_accessible_p (scope, type, decl, binfo)
 
   return 0;
 }
-   
+
+/* Perform access control on TYPE_DECL VAL, which was looked up in TYPE.
+   This is fairly complex, so here's the design:
+
+   The lang_extdef nonterminal sets type_lookups to NULL_TREE before we
+     start to process a top-level declaration.
+   As we process the decl-specifier-seq for the declaration, any types we
+     see that might need access control are passed to type_access_control,
+     which defers checking by adding them to type_lookups.
+   When we are done with the decl-specifier-seq, we record the lookups we've
+     seen in the lookups field of the typed_declspecs nonterminal.
+   When we process the first declarator, either in parse_decl or
+     begin_function_definition, we call initial_deferred_type_access_control,
+     which processes any lookups from within that declarator, stores the
+     lookups from the decl-specifier-seq in current_type_lookups, and sets
+     type_lookups to error_mark_node.
+   Subsequent declarators process current_type_lookups again to make sure
+     that the types are accessible to all of the declarators.  Any lookups
+     within subsequent declarators are processed immediately.
+   Within a function, type_lookups is error_mark_node, so all lookups are
+     processed immediately.  */
+
+void
+type_access_control (type, val)
+     tree type, val;
+{
+  if (val == NULL_TREE || TREE_CODE (val) != TYPE_DECL
+      || ! DECL_CLASS_SCOPE_P (val))
+    return;
+
+  if (type_lookups == error_mark_node)
+    enforce_access (type, val);
+  else if (! accessible_p (type, val))
+    type_lookups = tree_cons (type, val, type_lookups);
+}
+
 /* DECL is a declaration from a base class of TYPE, which was the
-   classs used to name DECL.  Return non-zero if, in the current
+   class used to name DECL.  Return non-zero if, in the current
    context, DECL is accessible.  If TYPE is actually a BINFO node,
    then we can tell in what context the access is occurring by looking
    at the most derived class along the path indicated by BINFO.  */
@@ -988,10 +1149,6 @@ accessible_p (type, decl)
   if (!TYPE_P (context_for_name_lookup (decl)))
     return 1;
 
-  /* We don't do access control for types yet.  */
-  if (TREE_CODE (decl) == TYPE_DECL)
-    return 1;
-
   if (!TYPE_P (type))
     {
       binfo = type;
@@ -1032,8 +1189,8 @@ accessible_p (type, decl)
     protected_ok = friend_accessible_p (current_scope (),
                                        type, decl, binfo);
 
-  /* Standardize on the same that will access_in_type will use.  We
-     don't need to know what path was chosen from this point onwards.  */ 
+  /* Standardize the binfo that access_in_type will use.  We don't
+     need to know what path was chosen from this point onwards.  */
   binfo = TYPE_BINFO (type);
 
   /* Compute the accessibility of DECL in the class hierarchy
@@ -1062,21 +1219,31 @@ static int
 is_subobject_of_p (parent, binfo)
      tree parent, binfo;
 {
-  tree binfos = BINFO_BASETYPES (binfo);
-  int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+  tree binfos;
+  int i, n_baselinks;
 
-  if (TREE_VIA_VIRTUAL (parent))
-    parent = TYPE_BINFO (TREE_TYPE (parent));
-  if (TREE_VIA_VIRTUAL (binfo))
-    binfo = TYPE_BINFO (TREE_TYPE (binfo));
+  /* We want to canonicalize for comparison purposes.  But, when we
+     iterate through basetypes later, we want the binfos from the
+     original hierarchy.  That's why we have to calculate BINFOS
+     first, and then canonicalize.  */
+  binfos = BINFO_BASETYPES (binfo);
+  parent = canonical_binfo (parent);
+  binfo = canonical_binfo (binfo);
 
   if (parent == binfo)
     return 1;
 
+  n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+
   /* Process and/or queue base types.  */
   for (i = 0; i < n_baselinks; i++)
     {
-      tree base_binfo = canonical_binfo (TREE_VEC_ELT (binfos, i));
+      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, base_binfo))
        return 1;
     }
@@ -1119,7 +1286,7 @@ lookup_fnfields_here (type, name)
   fndecls = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx);
   while (fndecls)
     {
-      if (TYPE_MAIN_VARIANT (DECL_CLASS_CONTEXT (OVL_CURRENT (fndecls)))
+      if (TYPE_MAIN_VARIANT (DECL_CONTEXT (OVL_CURRENT (fndecls)))
          == TYPE_MAIN_VARIANT (type))
        return idx;
       fndecls = OVL_CHAIN (fndecls);
@@ -1170,15 +1337,14 @@ lookup_field_queue_p (binfo, data)
     return NULL_TREE;
 
   if (TREE_VIA_VIRTUAL (binfo))
-    return binfo_member (BINFO_TYPE (binfo),
-                        CLASSTYPE_VBASECLASSES (lfi->type));
+    return BINFO_FOR_VBASE (BINFO_TYPE (binfo), lfi->type);
   else
     return binfo;
 }
 
-/* Within the scope of a template class, you can refer to the
-   particular to the current specialization with the name of the
-   template itself.  For example:
+/* Within the scope of a template class, you can refer to the to the
+   current specialization with the name of the template itself.  For
+   example:
    
      template <typename T> struct S { S* sp; }
 
@@ -1287,14 +1453,17 @@ lookup_field_r (binfo, data)
          /* We have a real ambiguity.  We keep a chain of all the
             candidates.  */
          if (!lfi->ambiguous && lfi->rval)
-           /* This is the first time we noticed an ambiguity.  Add
-              what we previously thought was a reasonable candidate
-              to the list.  */
-           lfi->ambiguous = scratch_tree_cons (NULL_TREE, lfi->rval,
-                                               NULL_TREE);
+           {
+             /* This is the first time we noticed an ambiguity.  Add
+                what we previously thought was a reasonable candidate
+                to the list.  */
+             lfi->ambiguous = tree_cons (NULL_TREE, lfi->rval, NULL_TREE);
+             TREE_TYPE (lfi->ambiguous) = error_mark_node;
+           }
+
          /* Add the new value.  */
-         lfi->ambiguous = scratch_tree_cons (NULL_TREE, nval, 
-                                             lfi->ambiguous);
+         lfi->ambiguous = tree_cons (NULL_TREE, nval, lfi->ambiguous);
+         TREE_TYPE (lfi->ambiguous) = error_mark_node;
          lfi->errstr = "request for member `%D' is ambiguous";
        }
     }
@@ -1331,8 +1500,8 @@ lookup_field_r (binfo, data)
    XBASETYPE.  PROTECT is 0 or two, we do not check access.  If it is
    1, we enforce accessibility.  If PROTECT is zero, then, for an
    ambiguous lookup, we return NULL.  If PROTECT is 1, we issue an
-   error message.  If PROTECT is two 2, we return a TREE_LIST whose
-   TREE_PURPOSE is error_mark_node and whose TREE_VALUE is the list of
+   error message.  If PROTECT is 2, we return a TREE_LIST whose
+   TREE_TYPE is error_mark_node and whose TREE_VALUEs are the list of
    ambiguous candidates.
 
    WANT_TYPE is 1 when we should only return TYPE_DECLs, if no
@@ -1362,6 +1531,8 @@ lookup_member (xbasetype, name, protect, want_type)
       tree field = IDENTIFIER_CLASS_VALUE (name);
       if (TREE_CODE (field) != FUNCTION_DECL
          && ! (want_type && TREE_CODE (field) != TYPE_DECL))
+       /* We're in the scope of this class, and the value has already
+          been looked up.  Just return the cached value.  */
        return field;
     }
 
@@ -1405,14 +1576,7 @@ lookup_member (xbasetype, name, protect, want_type)
   if (protect == 2) 
     {
       if (lfi.ambiguous)
-       {
-         /* An ERROR_MARK for the TREE_TYPE tells hack_identifier
-            that the lookup is ambiguous.  */
-         TREE_TYPE (lfi.ambiguous) = error_mark_node;
-         return scratch_tree_cons (error_mark_node,
-                                   lfi.ambiguous,
-                                   NULL_TREE);
-       }
+       return lfi.ambiguous;
       else
        protect = 0;
     }
@@ -1422,8 +1586,6 @@ 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)
-      && !IS_SIGNATURE_POINTER (DECL_REAL_CONTEXT (rval))
-      && !IS_SIGNATURE_REFERENCE (DECL_REAL_CONTEXT (rval))
       && !enforce_access (xbasetype, rval))
     return error_mark_node;
 
@@ -1444,7 +1606,7 @@ lookup_member (xbasetype, name, protect, want_type)
 
   if (rval && is_overloaded_fn (rval)) 
     {
-      rval = scratch_tree_cons (basetype_path, rval, NULL_TREE);
+      rval = tree_cons (basetype_path, rval, NULL_TREE);
       SET_BASELINK_P (rval);
     }
 
@@ -1492,61 +1654,84 @@ int
 lookup_fnfields_1 (type, name)
      tree type, name;
 {
-  register tree method_vec 
+  tree method_vec 
     = CLASS_TYPE_P (type) ? CLASSTYPE_METHOD_VEC (type) : NULL_TREE;
 
   if (method_vec != 0)
     {
+      register int i;
       register tree *methods = &TREE_VEC_ELT (method_vec, 0);
-      register tree *end = TREE_VEC_END (method_vec);
+      int len = TREE_VEC_LENGTH (method_vec);
+      tree tmp;
 
 #ifdef GATHER_STATISTICS
       n_calls_lookup_fnfields_1++;
 #endif /* GATHER_STATISTICS */
 
       /* Constructors are first...  */
-      if (*methods && name == ctor_identifier)
-       return 0;
+      if (name == ctor_identifier)
+       return methods[0] ? 0 : -1;
 
       /* and destructors are second.  */
-      if (*++methods && name == dtor_identifier)
-       return 1;
+      if (name == dtor_identifier)
+       return methods[1] ? 1 : -1;
 
-      while (++methods != end && *methods)
+      for (i = 2; i < len && methods[i]; ++i)
        {
 #ifdef GATHER_STATISTICS
          n_outer_fields_searched++;
 #endif /* GATHER_STATISTICS */
-         if (DECL_NAME (OVL_CURRENT (*methods)) == name)
-           break;
+
+         tmp = OVL_CURRENT (methods[i]);
+         if (DECL_NAME (tmp) == name)
+           return i;
+
+         /* If the type is complete and we're past the conversion ops,
+            switch to binary search.  */
+         if (! DECL_CONV_FN_P (tmp)
+             && TYPE_SIZE (type))
+           {
+             int lo = i + 1, hi = len;
+
+             while (lo < hi)
+               {
+                 i = (lo + hi) / 2;
+
+#ifdef GATHER_STATISTICS
+                 n_outer_fields_searched++;
+#endif /* GATHER_STATISTICS */
+
+                 tmp = DECL_NAME (OVL_CURRENT (methods[i]));
+
+                 if (tmp > name)
+                   hi = i;
+                 else if (tmp < name)
+                   lo = i + 1;
+                 else
+                   return i;
+               }
+             break;
+           }
        }
 
       /* If we didn't find it, it might have been a template
         conversion operator.  (Note that we don't look for this case
         above so that we will always find specializations first.)  */
-      if ((methods == end || !*methods)
-         && IDENTIFIER_TYPENAME_P (name)) 
+      if (IDENTIFIER_TYPENAME_P (name)) 
        {
-         methods = &TREE_VEC_ELT (method_vec, 0) + 1;
-         
-         while (++methods != end && *methods)
+         for (i = 2; i < len && methods[i]; ++i)
            {
-             tree method_name = DECL_NAME (OVL_CURRENT (*methods));
-
-             if (!IDENTIFIER_TYPENAME_P (method_name))
+             tmp = OVL_CURRENT (methods[i]);
+             if (! DECL_CONV_FN_P (tmp))
                {
                  /* Since all conversion operators come first, we know
                     there is no such operator.  */
-                 methods = end;
                  break;
                }
-             else if (TREE_CODE (OVL_CURRENT (*methods)) == TEMPLATE_DECL)
-               break;
+             else if (TREE_CODE (tmp) == TEMPLATE_DECL)
+               return i;
            }
        }
-
-      if (methods != end && *methods)
-       return methods - &TREE_VEC_ELT (method_vec, 0);
     }
 
   return -1;
@@ -1567,8 +1752,8 @@ lookup_fnfields_1 (type, name)
 static tree
 bfs_walk (binfo, fn, qfn, data)
      tree binfo;
-     tree (*fn) PROTO((tree, void *));
-     tree (*qfn) PROTO((tree, void *));
+     tree (*fn) PARAMS ((tree, void *));
+     tree (*qfn) PARAMS ((tree, void *));
      void *data;
 {
   size_t head;
@@ -1630,12 +1815,12 @@ bfs_walk (binfo, fn, qfn, data)
    performed, and PREFN is called in preorder, while POSTFN is called
    in postorder.  */
 
-static tree
+tree
 dfs_walk_real (binfo, prefn, postfn, qfn, data)
      tree binfo;
-     tree (*prefn) PROTO((tree, void *));
-     tree (*postfn) PROTO((tree, void *));
-     tree (*qfn) PROTO((tree, void *));
+     tree (*prefn) PARAMS ((tree, void *));
+     tree (*postfn) PARAMS ((tree, void *));
+     tree (*qfn) PARAMS ((tree, void *));
      void *data;
 {
   int i;
@@ -1682,8 +1867,8 @@ dfs_walk_real (binfo, prefn, postfn, qfn, data)
 tree
 dfs_walk (binfo, fn, qfn, data)
      tree binfo;
-     tree (*fn) PROTO((tree, void *));
-     tree (*qfn) PROTO((tree, void *));
+     tree (*fn) PARAMS ((tree, void *));
+     tree (*qfn) PARAMS ((tree, void *));
      void *data;
 {
   return dfs_walk_real (binfo, 0, fn, qfn, data);
@@ -1711,10 +1896,9 @@ get_virtuals_named_this_r (binfo, data)
   idx = lookup_fnfields_here (BINFO_TYPE (binfo), gvnti->name);
   if (idx >= 0)
     gvnti->fields
-      = scratch_tree_cons (binfo, 
-                          TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type),
-                                        idx),
-                          gvnti->fields);
+      = tree_cons (binfo, 
+                  TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx),
+                  gvnti->fields);
 
   return NULL_TREE;
 }
@@ -1826,6 +2010,63 @@ covariant_return_p (brettype, drettype)
   return 1;
 }
 
+/* Check that virtual overrider OVERRIDER is acceptable for base function
+   BASEFN. Issue diagnostic, and return zero, if unacceptable.  */
+
+static int
+check_final_overrider (overrider, basefn)
+     tree overrider, basefn;
+{
+  tree over_type = TREE_TYPE (overrider);
+  tree base_type = TREE_TYPE (basefn);
+  tree over_return = TREE_TYPE (over_type);
+  tree base_return = TREE_TYPE (base_type);
+  tree over_throw = TYPE_RAISES_EXCEPTIONS (over_type);
+  tree base_throw = TYPE_RAISES_EXCEPTIONS (base_type);
+  int i;
+  
+  if (same_type_p (base_return, over_return))
+    /* OK */;
+  else if ((i = covariant_return_p (base_return, over_return)))
+    {
+      if (i == 2)
+       sorry ("adjusting pointers for covariant returns");
+
+      if (pedantic && i == -1)
+       {
+         cp_pedwarn_at ("invalid covariant return type for `virtual %#D'", overrider);
+         cp_pedwarn_at ("  overriding `virtual %#D' (must be pointer or reference to class)", basefn);
+       }
+    }
+  else if (IS_AGGR_TYPE_2 (base_return, over_return)
+          && same_or_base_type_p (base_return, over_return))
+    {
+      cp_error_at ("invalid covariant return type for `virtual %#D'", overrider);
+      cp_error_at ("  overriding `virtual %#D' (must use pointer or reference)", basefn);
+      return 0;
+    }
+  else if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider)) == NULL_TREE)
+    {
+      cp_error_at ("conflicting return type specified for `virtual %#D'", overrider);
+      cp_error_at ("  overriding `virtual %#D'", basefn);
+      SET_IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider),
+                                  DECL_CONTEXT (overrider));
+      return 0;
+    }
+  
+  /* Check throw specifier is subset.  */
+  /* XXX At the moment, punt on an overriding artificial function. We
+     don't generate its exception specifier, so can't check it properly.  */
+  if (! DECL_ARTIFICIAL (overrider)
+      && !comp_except_specs (base_throw, over_throw, 0))
+    {
+      cp_error_at ("looser throw specifier for `virtual %#F'", overrider);
+      cp_error_at ("  overriding `virtual %#F'", basefn);
+      return 0;
+    }
+  return 1;
+}
+
 /* Given a class type TYPE, and a function decl FNDECL, look for a
    virtual function in TYPE's hierarchy which FNDECL could match as a
    virtual function.  It doesn't matter which one we find.
@@ -1839,7 +2080,6 @@ get_matching_virtual (binfo, fndecl, dtorp)
      int dtorp;
 {
   tree tmp = NULL_TREE;
-  int i;
 
   if (TREE_CODE (fndecl) == TEMPLATE_DECL)
     /* In [temp.mem] we have:
@@ -1856,9 +2096,7 @@ get_matching_virtual (binfo, fndecl, dtorp)
   else
     {
       tree drettype, dtypes, btypes, instptr_type;
-      tree basetype = DECL_CLASS_CONTEXT (fndecl);
       tree baselink, best = NULL_TREE;
-      tree name = DECL_ASSEMBLER_NAME (fndecl);
       tree declarator = DECL_NAME (fndecl);
       if (IDENTIFIER_VIRTUAL_P (declarator) == 0)
        return NULL_TREE;
@@ -1900,33 +2138,7 @@ get_matching_virtual (binfo, fndecl, dtorp)
                   == TYPE_QUALS (instptr_type))
                  && compparms (TREE_CHAIN (btypes), TREE_CHAIN (dtypes)))
                {
-                 tree brettype = TREE_TYPE (TREE_TYPE (tmp));
-                 if (same_type_p (brettype, drettype))
-                   /* OK */;
-                 else if ((i = covariant_return_p (brettype, drettype)))
-                   {
-                     if (i == 2)
-                       sorry ("adjusting pointers for covariant returns");
-
-                     if (pedantic && i == -1)
-                       {
-                         cp_pedwarn_at ("invalid covariant return type for `%#D' (must be pointer or reference to class)", fndecl);
-                         cp_pedwarn_at ("  overriding `%#D'", tmp);
-                       }
-                   }
-                 else if (IS_AGGR_TYPE_2 (brettype, drettype)
-                          && same_or_base_type_p (brettype, drettype))
-                   {
-                     error ("invalid covariant return type (must use pointer or reference)");
-                     cp_error_at ("  overriding `%#D'", tmp);
-                     cp_error_at ("  with `%#D'", fndecl);
-                   }
-                 else if (IDENTIFIER_ERROR_LOCUS (name) == NULL_TREE)
-                   {
-                     cp_error_at ("conflicting return type specified for virtual function `%#D'", fndecl);
-                     cp_error_at ("  overriding definition as `%#D'", tmp);
-                     SET_IDENTIFIER_ERROR_LOCUS (name, basetype);
-                   }
+                 check_final_overrider (fndecl, tmp);
 
                  /* FNDECL overrides this function.  We continue to
                     check all the other functions in order to catch
@@ -1942,81 +2154,296 @@ get_matching_virtual (binfo, fndecl, dtorp)
     }
 }
 
-/* Return the list of virtual functions which are abstract in type
-   TYPE that come from non virtual base classes.  See
-   expand_direct_vtbls_init for the style of search we do.  */
+/* A queue function for dfs_walk that skips any nonprimary virtual
+   bases and any already marked bases.  */
+
+tree
+dfs_skip_nonprimary_vbases_unmarkedp (binfo, data)
+     tree binfo;
+     void *data ATTRIBUTE_UNUSED;
+{
+  if (TREE_VIA_VIRTUAL (binfo) && !BINFO_PRIMARY_MARKED_P (binfo))
+    /* This is a non-primary virtual base.  SKip it.  */
+    return NULL_TREE;
+
+  return unmarkedp (binfo, NULL);
+}
+
+/* A queue function for dfs_walk that skips any nonprimary virtual
+   bases and any unmarked bases.  */
+
+tree
+dfs_skip_nonprimary_vbases_markedp (binfo, data)
+     tree binfo;
+     void *data ATTRIBUTE_UNUSED;
+{
+  if (TREE_VIA_VIRTUAL (binfo) && !BINFO_PRIMARY_MARKED_P (binfo))
+    /* This is a non-primary virtual base.  SKip it.  */
+    return NULL_TREE;
+
+  return markedp (binfo, NULL);
+}
+
+/* Called via dfs_walk from mark_primary_bases.  */
 
 static tree
-get_abstract_virtuals_1 (binfo, do_self, abstract_virtuals)
+dfs_mark_primary_bases (binfo, data)
      tree binfo;
-     int do_self;
-     tree abstract_virtuals;
+     void *data;
 {
-  tree binfos = BINFO_BASETYPES (binfo);
-  int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+  int i;
+  tree base_binfo;
 
-  for (i = 0; i < n_baselinks; i++)
-    {
-      tree base_binfo = TREE_VEC_ELT (binfos, i);
-      int is_not_base_vtable
-       = i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
-      if (! TREE_VIA_VIRTUAL (base_binfo))
-       abstract_virtuals
-         = get_abstract_virtuals_1 (base_binfo, is_not_base_vtable,
-                                    abstract_virtuals);
-    }
-  /* Should we use something besides CLASSTYPE_VFIELDS? */
-  if (do_self && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
+  if (!CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (binfo)))
+    return NULL_TREE;
+
+  i = CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
+  base_binfo = BINFO_BASETYPE (binfo, i);
+
+  if (!TREE_VIA_VIRTUAL (base_binfo))
+    /* Non-virtual base classes are easy.  */
+    BINFO_PRIMARY_MARKED_P (base_binfo) = 1;
+  else
     {
-      tree virtuals = BINFO_VIRTUALS (binfo);
+      tree shared_binfo;
 
-      skip_rtti_stuff (&virtuals, BINFO_TYPE (binfo));
+      shared_binfo 
+       = BINFO_FOR_VBASE (BINFO_TYPE (base_binfo), (tree) data);
 
-      while (virtuals)
+      /* If this virtual base is not already primary somewhere else in
+        the hiearchy, then we'll be using this copy.  */
+      if (!BINFO_VBASE_PRIMARY_P (shared_binfo)
+         && !BINFO_VBASE_MARKED (shared_binfo))
        {
-         tree base_pfn = FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals));
-         tree base_fndecl = TREE_OPERAND (base_pfn, 0);
-         if (DECL_ABSTRACT_VIRTUAL_P (base_fndecl))
-           abstract_virtuals = tree_cons (NULL_TREE, base_fndecl, abstract_virtuals);
-         virtuals = TREE_CHAIN (virtuals);
+         BINFO_VBASE_PRIMARY_P (shared_binfo) = 1;
+         BINFO_PRIMARY_MARKED_P (base_binfo) = 1;
        }
     }
-  return abstract_virtuals;
+
+  return NULL_TREE;
+}
+
+/* Set BINFO_PRIMARY_MARKED_P for all binfos in the hierarchy
+   dominated by BINFO that are primary bases.  */
+
+void
+mark_primary_bases (type)
+     tree type;
+{
+  tree vbase;
+
+  /* Mark the TYPE_BINFO hierarchy.  We need to mark primary bases in
+     pre-order to deal with primary virtual bases.  (The virtual base
+     would be skipped if it were not marked as primary, and that
+     requires getting to dfs_mark_primary_bases before
+     dfs_skip_nonprimary_vbases_unmarkedp has a chance to skip the
+     virtual base.)  */
+  dfs_walk_real (TYPE_BINFO (type), dfs_mark_primary_bases, NULL,
+                dfs_skip_nonprimary_vbases_unmarkedp, type);
+
+  /* Now go through the virtual base classes.  Any that are not
+     already primary will need to be allocated in TYPE, and so we need
+     to mark their primary bases.  */
+  for (vbase = CLASSTYPE_VBASECLASSES (type); 
+       vbase; 
+       vbase = TREE_CHAIN (vbase))
+    {
+      if (BINFO_VBASE_PRIMARY_P (vbase))
+       /* This virtual base was already included in the hierarchy, so
+          there's nothing to do here.  */
+       continue;
+
+      /* Temporarily pretend that VBASE is primary so that its bases
+        will be walked; this is the real copy of VBASE.  */
+      BINFO_PRIMARY_MARKED_P (vbase) = 1;
+
+      /* Now, walk its bases.  */
+      dfs_walk (vbase, dfs_mark_primary_bases,
+               dfs_skip_nonprimary_vbases_unmarkedp, type);
+
+      /* VBASE wasn't really primary.  */
+      BINFO_PRIMARY_MARKED_P (vbase) = 0;
+      /* And we don't want to allow it to *become* primary if it is a
+        base of some subsequent base class.  */
+      SET_BINFO_VBASE_MARKED (vbase);
+    }
+
+  /* Clear the VBASE_MARKED bits we set above.  */
+  for (vbase = CLASSTYPE_VBASECLASSES (type); 
+       vbase; 
+       vbase = TREE_CHAIN (vbase))
+    CLEAR_BINFO_VBASE_MARKED (vbase);
+}
+
+/* If BINFO is a non-primary virtual baseclass (in the hierarchy
+   dominated by TYPE), and no primary copy appears anywhere in the
+   hierarchy, return the shared copy.  If a primary copy appears
+   elsewhere, return NULL_TREE.  Otherwise, return BINFO itself; it is
+   either a non-virtual base or a primary virtual base.  */
+
+static tree
+get_shared_vbase_if_not_primary (binfo, data)
+     tree binfo;
+     void *data;
+{
+  if (TREE_VIA_VIRTUAL (binfo) && !BINFO_PRIMARY_MARKED_P (binfo))
+    {
+      tree 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_VBASE_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;
+}
+
+/* Like dfs_unmarked_real_bases_queue_p but walks only into things
+   that are not BINFO_VTABLE_PATH_MARKED.  */
+
+tree
+dfs_vtable_path_unmarked_real_bases_queue_p (binfo, data)
+     tree binfo;
+     void *data;
+{
+  binfo = get_shared_vbase_if_not_primary (binfo, data); 
+  return binfo ? unmarked_vtable_pathp (binfo, NULL): NULL_TREE;
+}
+
+/* Like dfs_unmarked_real_bases_queue_p but walks only into things
+   that are BINFO_VTABLE_PATH_MARKED.  */
+
+tree
+dfs_vtable_path_marked_real_bases_queue_p (binfo, data)
+     tree binfo;
+     void *data;
+{
+  binfo = get_shared_vbase_if_not_primary (binfo, data); 
+  return binfo ? marked_vtable_pathp (binfo, NULL): NULL_TREE;
 }
 
-/* Return the list of virtual functions which are abstract in type TYPE.
-   This information is cached, and so must be built on a
-   non-temporary obstack.  */
+/* A queue function that skips all virtual bases (and their 
+   bases).  */
 
 tree
-get_abstract_virtuals (type)
+dfs_skip_vbases (binfo, data)
+     tree binfo;
+     void *data ATTRIBUTE_UNUSED;
+{
+  if (TREE_VIA_VIRTUAL (binfo))
+    return NULL_TREE;
+
+  return binfo;
+}
+
+/* Called via dfs_walk from dfs_get_pure_virtuals.  */
+
+static tree
+dfs_get_pure_virtuals (binfo, data)
+     tree binfo;
+     void *data;
+{
+  tree type = (tree) data;
+
+  /* We're not interested in primary base classes; the derived class
+     of which they are a primary base will contain the information we
+     need.  */
+  if (!BINFO_PRIMARY_MARKED_P (binfo))
+    {
+      tree virtuals;
+      
+      for (virtuals = skip_rtti_stuff (binfo, 
+                                      BINFO_TYPE (binfo), 
+                                      NULL);
+          virtuals;
+          virtuals = TREE_CHAIN (virtuals))
+       if (DECL_PURE_VIRTUAL_P (TREE_VALUE (virtuals)))
+         CLASSTYPE_PURE_VIRTUALS (type) 
+           = tree_cons (NULL_TREE, TREE_VALUE (virtuals),
+                        CLASSTYPE_PURE_VIRTUALS (type));
+    }
+  
+  SET_BINFO_MARKED (binfo);
+
+  return NULL_TREE;
+}
+
+/* Set CLASSTYPE_PURE_VIRTUALS for TYPE.  */
+
+void
+get_pure_virtuals (type)
      tree type;
 {
   tree vbases;
-  tree abstract_virtuals = NULL;
 
-  /* First get all from non-virtual bases.  */
-  abstract_virtuals
-    = get_abstract_virtuals_1 (TYPE_BINFO (type), 1, abstract_virtuals);
-                                              
-  for (vbases = CLASSTYPE_VBASECLASSES (type); vbases; vbases = TREE_CHAIN (vbases))
+  /* Clear the CLASSTYPE_PURE_VIRTUALS list; whatever is already there
+     is going to be overridden.  */
+  CLASSTYPE_PURE_VIRTUALS (type) = NULL_TREE;
+  /* Now, run through all the bases which are not primary bases, and
+     collect the pure virtual functions.  We look at the vtable in
+     each class to determine what pure virtual functions are present.
+     (A primary base is not interesting because the derived class of
+     which it is a primary base will contain vtable entries for the
+     pure virtuals in the base class.  */
+  dfs_walk (TYPE_BINFO (type), dfs_get_pure_virtuals, 
+           dfs_unmarked_real_bases_queue_p, type);
+  dfs_walk (TYPE_BINFO (type), dfs_unmark, 
+           dfs_marked_real_bases_queue_p, type);
+
+  /* Put the pure virtuals in dfs order.  */
+  CLASSTYPE_PURE_VIRTUALS (type) = nreverse (CLASSTYPE_PURE_VIRTUALS (type));
+
+  for (vbases = CLASSTYPE_VBASECLASSES (type); 
+       vbases; 
+       vbases = TREE_CHAIN (vbases))
     {
-      tree virtuals = BINFO_VIRTUALS (vbases);
+      tree virtuals;
 
-      skip_rtti_stuff (&virtuals, type);
-
-      while (virtuals)
+      for (virtuals = skip_rtti_stuff (vbases, BINFO_TYPE (vbases), NULL);
+          virtuals;
+          virtuals = TREE_CHAIN (virtuals))
        {
-         tree base_pfn = FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals));
-         tree base_fndecl = TREE_OPERAND (base_pfn, 0);
+         tree base_fndecl = TREE_VALUE (virtuals);
          if (DECL_NEEDS_FINAL_OVERRIDER_P (base_fndecl))
            cp_error ("`%#D' needs a final overrider", base_fndecl);
-         else if (DECL_ABSTRACT_VIRTUAL_P (base_fndecl))
-           abstract_virtuals = tree_cons (NULL_TREE, base_fndecl, abstract_virtuals);
-         virtuals = TREE_CHAIN (virtuals);
        }
     }
-  return nreverse (abstract_virtuals);
 }
 
 static tree
@@ -2047,27 +2474,40 @@ static tree
 convert_pointer_to_single_level (to_type, expr)
      tree to_type, expr;
 {
+  tree derived;
   tree binfo_of_derived;
-  tree last;
+  int i;
 
-  binfo_of_derived = TYPE_BINFO (TREE_TYPE (TREE_TYPE (expr)));
-  last = get_binfo (to_type, TREE_TYPE (TREE_TYPE (expr)), 0);
-  my_friendly_assert (BINFO_INHERITANCE_CHAIN (last) == binfo_of_derived,
-                     980827);
+  derived = TREE_TYPE (TREE_TYPE (expr));
+  binfo_of_derived = TYPE_BINFO (derived);
   my_friendly_assert (BINFO_INHERITANCE_CHAIN (binfo_of_derived) == NULL_TREE,
                      980827);
-  return build_vbase_path (PLUS_EXPR, build_pointer_type (to_type), expr,
-                          last, 1);
+  for (i = CLASSTYPE_N_BASECLASSES (derived) - 1; i >= 0; --i)
+    {
+      tree binfo = BINFO_BASETYPE (binfo_of_derived, i);
+      my_friendly_assert (BINFO_INHERITANCE_CHAIN (binfo) == binfo_of_derived,
+                         980827);
+      if (same_type_p (BINFO_TYPE (binfo), to_type))
+       return build_vbase_path (PLUS_EXPR, 
+                                build_pointer_type (to_type), 
+                                expr, binfo, 1);
+    }
+
+  my_friendly_abort (19990607);
+
+  /* NOTREACHED */
+  return NULL_TREE;
 }
 
-tree markedp (binfo, data) 
+tree 
+markedp (binfo, data) 
      tree binfo;
      void *data ATTRIBUTE_UNUSED;
 { 
   return BINFO_MARKED (binfo) ? binfo : NULL_TREE; 
 }
 
-static tree
+tree
 unmarkedp (binfo, data) 
      tree binfo;
      void *data ATTRIBUTE_UNUSED;
@@ -2112,7 +2552,8 @@ marked_pushdecls_p (binfo, data)
      tree binfo;
      void *data ATTRIBUTE_UNUSED;
 {
-  return BINFO_PUSHDECLS_MARKED (binfo) ? binfo : NULL_TREE; 
+  return (CLASS_TYPE_P (BINFO_TYPE (binfo))
+         && BINFO_PUSHDECLS_MARKED (binfo)) ? binfo : NULL_TREE; 
 }
 
 static tree
@@ -2120,13 +2561,13 @@ unmarked_pushdecls_p (binfo, data)
      tree binfo;
      void *data ATTRIBUTE_UNUSED;
 { 
-  return !BINFO_PUSHDECLS_MARKED (binfo) ? binfo : NULL_TREE;
+  return (CLASS_TYPE_P (BINFO_TYPE (binfo))
+         && !BINFO_PUSHDECLS_MARKED (binfo)) ? binfo : NULL_TREE;
 }
 
 #if 0
 static int dfs_search_slot_nonempty_p (binfo) tree binfo;
 { return CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (binfo)) != 0; }
-#endif
 
 static tree 
 dfs_debug_unmarkedp (binfo, data) 
@@ -2136,6 +2577,7 @@ dfs_debug_unmarkedp (binfo, data)
   return (!CLASSTYPE_DEBUG_REQUESTED (BINFO_TYPE (binfo)) 
          ? binfo : NULL_TREE);
 }
+#endif
 
 /* The worker functions for `dfs_walk'.  These do not need to
    test anything (vis a vis marking) if they are paired with
@@ -2156,16 +2598,34 @@ dfs_unmark (binfo, data)
   return NULL_TREE;
 }
 
+/* Clear both BINFO_MARKED and BINFO_VBASE_MARKED.  */
+
+tree
+dfs_vbase_unmark (binfo, data)
+     tree binfo;
+     void *data ATTRIBUTE_UNUSED;
+{
+  CLEAR_BINFO_VBASE_MARKED (binfo);
+  return dfs_unmark (binfo, data);
+}
+
+/* Clear BINFO_VTABLE_PATH_MARKED.  */
+
+tree
+dfs_vtable_path_unmark (binfo, data)
+     tree binfo;
+     void *data ATTRIBUTE_UNUSED;
+{ 
+  CLEAR_BINFO_VTABLE_PATH_MARKED (binfo); 
+  return NULL_TREE;
+}
+
 #if 0
 static void
 dfs_mark_vtable_path (binfo) tree binfo;
 { SET_BINFO_VTABLE_PATH_MARKED (binfo); }
 
 static void
-dfs_unmark_vtable_path (binfo) tree binfo;
-{ CLEAR_BINFO_VTABLE_PATH_MARKED (binfo); }
-
-static void
 dfs_mark_new_vtable (binfo) tree binfo;
 { SET_BINFO_NEW_VTABLE_MARKED (binfo); }
 
@@ -2176,8 +2636,10 @@ dfs_unmark_new_vtable (binfo) tree binfo;
 static void
 dfs_clear_search_slot (binfo) tree binfo;
 { CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (binfo)) = 0; }
-#endif
 
+/* Keep this code around in case we later want to control debug info
+   based on whether a type is "used".  Currently, we only suppress debug
+   info if we can emit it with the vtable.  jason 1999-11-11) */
 static tree
 dfs_debug_mark (binfo, data)
      tree binfo;
@@ -2185,47 +2647,18 @@ dfs_debug_mark (binfo, data)
 {
   tree t = BINFO_TYPE (binfo);
 
-  /* Use heuristic that if there are virtual functions,
-     ignore until we see a non-inline virtual function.  */
-  tree methods = CLASSTYPE_METHOD_VEC (t);
-
   CLASSTYPE_DEBUG_REQUESTED (t) = 1;
 
-  if (methods == 0)
-    return NULL_TREE;
-
   /* If interface info is known, either we've already emitted the debug
      info or we don't need to.  */
   if (CLASSTYPE_INTERFACE_KNOWN (t))
     return NULL_TREE;
 
-  /* If debug info is requested from this context for this type, supply it.
-     If debug info is requested from another context for this type,
-     see if some third context can supply it.  */
-  if (current_function_decl == NULL_TREE
-      || DECL_CLASS_CONTEXT (current_function_decl) != t)
-    {
-      if (TREE_VEC_ELT (methods, 1))
-       methods = TREE_VEC_ELT (methods, 1);
-      else if (TREE_VEC_ELT (methods, 0))
-       methods = TREE_VEC_ELT (methods, 0);
-      else
-       methods = TREE_VEC_ELT (methods, 2);
-      methods = OVL_CURRENT (methods);
-      while (methods)
-       {
-         if (DECL_VINDEX (methods)
-             && DECL_THIS_INLINE (methods) == 0
-             && DECL_ABSTRACT_VIRTUAL_P (methods) == 0)
-           {
-             /* Somebody, somewhere is going to have to define this
-                virtual function.  When they do, they will provide
-                the debugging info.  */
-             return NULL_TREE;
-           }
-         methods = TREE_CHAIN (methods);
-       }
-    }
+  /* If the class has virtual functions, we'll emit the debug info
+     with the vtable.  */
+  if (TYPE_POLYMORPHIC_P (t))
+    return NULL_TREE;
+
   /* We cannot rely on some alien method to solve our problems,
      so we must write out the debug info ourselves.  */
   TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (t)) = 0;
@@ -2233,6 +2666,7 @@ dfs_debug_mark (binfo, data)
 
   return NULL_TREE;
 }
+#endif
 \f
 struct vbase_info 
 {
@@ -2281,18 +2715,11 @@ dfs_init_vbase_pointers (binfo, data)
 {
   struct vbase_info *vi = (struct vbase_info *) data;
   tree type = BINFO_TYPE (binfo);
-  tree fields = TYPE_FIELDS (type);
+  tree fields;
   tree this_vbase_ptr;
 
   CLEAR_BINFO_VTABLE_PATH_MARKED (binfo);
 
-#if 0
-  /* See finish_struct_1 for when we can enable this.  */
-  /* If we have a vtable pointer first, skip it.  */
-  if (VFIELD_NAME_P (DECL_NAME (fields)))
-    fields = TREE_CHAIN (fields);
-#endif
-
   if (BINFO_INHERITANCE_CHAIN (binfo))
     {
       this_vbase_ptr = TREE_CHAIN (BINFO_INHERITANCE_CHAIN (binfo));
@@ -2306,6 +2733,14 @@ dfs_init_vbase_pointers (binfo, data)
   else
     this_vbase_ptr = TREE_CHAIN (binfo);
 
+  /* We're going to iterate through all the pointers to virtual
+     base-classes.  They come at the beginning of the class.  */
+  fields = TYPE_FIELDS (type);
+  if (fields == TYPE_VFIELD (type))
+    /* If the first field is the vtbl pointer (as happens in the new
+       ABI), skip it.  */
+    fields = TREE_CHAIN (fields);
+
   if (fields == NULL_TREE
       || DECL_NAME (fields) == NULL_TREE
       || ! VBASE_NAME_P (DECL_NAME (fields)))
@@ -2381,11 +2816,11 @@ init_vbase_pointers (type, decl_ptr)
 }
 
 /* get the virtual context (the vbase that directly contains the
-   DECL_CLASS_CONTEXT of the FNDECL) that the given FNDECL is declared in,
+   DECL_CONTEXT of the FNDECL) that the given FNDECL is declared in,
    or NULL_TREE if there is none.
 
-   FNDECL must come from a virtual table from a virtual base to ensure that
-   there is only one possible DECL_CLASS_CONTEXT.
+   FNDECL must come from a virtual table from a virtual base to ensure
+   that there is only one possible DECL_CONTEXT.
 
    We know that if there is more than one place (binfo) the fndecl that the
    declared, they all refer to the same binfo.  See get_class_offset_1 for
@@ -2396,17 +2831,17 @@ virtual_context (fndecl, t, vbase)
      tree fndecl, t, vbase;
 {
   tree path;
-  if (get_base_distance (DECL_CLASS_CONTEXT (fndecl), t, 0, &path) < 0)
+  if (get_base_distance (DECL_CONTEXT (fndecl), t, 0, &path) < 0)
     {
-      /* DECL_CLASS_CONTEXT can be ambiguous in t.  */
-      if (get_base_distance (DECL_CLASS_CONTEXT (fndecl), vbase, 0, &path) >= 0)
+      /* DECL_CONTEXT can be ambiguous in t.  */
+      if (get_base_distance (DECL_CONTEXT (fndecl), vbase, 0, &path) >= 0)
        {
          while (path)
            {
              /* Not sure if checking path == vbase is necessary here, but just in
                 case it is.  */
              if (TREE_VIA_VIRTUAL (path) || path == vbase)
-               return binfo_member (BINFO_TYPE (path), CLASSTYPE_VBASECLASSES (t));
+               return BINFO_FOR_VBASE (BINFO_TYPE (path), t);
              path = BINFO_INHERITANCE_CHAIN (path);
            }
        }
@@ -2449,11 +2884,18 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
                      vbase_offsets)
      tree binfo, addr, orig_addr, vbase, vbase_addr, t, *vbase_offsets;
 {
-  tree virtuals = BINFO_VIRTUALS (binfo);
+  tree virtuals;
   tree vc;
   tree delta;
   unsigned HOST_WIDE_INT n;
-  
+
+  while (BINFO_PRIMARY_MARKED_P (binfo))
+    {
+      binfo = BINFO_INHERITANCE_CHAIN (binfo);
+      if (TREE_VIA_VIRTUAL (binfo))
+       return;
+    }
+
   delta = purpose_member (vbase, *vbase_offsets);
   if (! delta)
     {
@@ -2464,13 +2906,12 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
       *vbase_offsets = delta;
     }
 
-  n = skip_rtti_stuff (&virtuals, t);
+  virtuals = skip_rtti_stuff (binfo, BINFO_TYPE (binfo), &n);
 
   while (virtuals)
     {
       tree current_fndecl = TREE_VALUE (virtuals);
-      current_fndecl = FNADDR_FROM_VTABLE_ENTRY (current_fndecl);
-      current_fndecl = TREE_OPERAND (current_fndecl, 0);
+
       if (current_fndecl
          && current_fndecl != abort_fndecl
          && (vc=virtual_context (current_fndecl, t, vbase)) != vbase)
@@ -2496,7 +2937,7 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
              DECL_ARTIFICIAL (nvtbl) = 1;
              nvtbl = pushdecl (nvtbl);
              init = NULL_TREE;
-             cp_finish_decl (nvtbl, init, NULL_TREE, 0,
+             cp_finish_decl (nvtbl, init, NULL_TREE,
                              LOOKUP_ONLYCONVERTING);
 
              /* We don't set DECL_VIRTUAL_P and DECL_CONTEXT on nvtbl
@@ -2507,13 +2948,12 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
 
              init = build (MODIFY_EXPR, TREE_TYPE (nvtbl),
                            nvtbl, vtbl);
-             TREE_SIDE_EFFECTS (init) = 1;
-             expand_expr_stmt (init);
+             finish_expr_stmt (init);
              /* Update the vtable pointers as necessary.  */
              ref = build_vfield_ref
                (build_indirect_ref (addr, NULL_PTR),
-                DECL_CONTEXT (CLASSTYPE_VFIELD (BINFO_TYPE (binfo))));
-             expand_expr_stmt
+                DECL_CONTEXT (TYPE_VFIELD (BINFO_TYPE (binfo))));
+             finish_expr_stmt
                (build_modify_expr (ref, NOP_EXPR, nvtbl));
            }
          assemble_external (vtbl);
@@ -2527,7 +2967,7 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
          /* This is a upcast, so we have to add the offset for the
             virtual base.  */
          old_delta = build_binary_op (PLUS_EXPR, old_delta,
-                                      TREE_VALUE (delta), 0);
+                                      TREE_VALUE (delta));
          if (vc)
            {
              /* If this is set, we need to subtract out the delta
@@ -2548,7 +2988,7 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
    
              /* This is a downcast, so we have to subtract the offset
                 for the virtual base.  */
-             old_delta = build_binary_op (MINUS_EXPR, old_delta, vc_delta, 0);
+             old_delta = build_binary_op (MINUS_EXPR, old_delta, vc_delta);
            }
 
          TREE_READONLY (new_delta) = 0;
@@ -2556,7 +2996,7 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
            cp_build_qualified_type (TREE_TYPE (new_delta),
                                     CP_TYPE_QUALS (TREE_TYPE (new_delta))
                                     & ~TYPE_QUAL_CONST);
-         expand_expr_stmt (build_modify_expr (new_delta, NOP_EXPR,
+         finish_expr_stmt (build_modify_expr (new_delta, NOP_EXPR,
                                               old_delta));
        }
       ++n;
@@ -2582,7 +3022,7 @@ fixup_virtual_upcast_offsets (real_binfo, binfo, init_self, can_elide, addr, ori
       tree real_base_binfo = TREE_VEC_ELT (real_binfos, i);
       tree base_binfo = TREE_VEC_ELT (binfos, i);
       int is_not_base_vtable
-       = i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (real_binfo));
+       = !BINFO_PRIMARY_MARKED_P (real_base_binfo);
       if (! TREE_VIA_VIRTUAL (real_base_binfo))
        fixup_virtual_upcast_offsets (real_base_binfo, base_binfo,
                                      is_not_base_vtable, can_elide, addr,
@@ -2602,23 +3042,69 @@ fixup_virtual_upcast_offsets (real_binfo, binfo, init_self, can_elide, addr, ori
     }
 }
 
-/* Build a COMPOUND_EXPR which when expanded will generate the code
-   needed to initialize all the virtual function table slots of all
-   the virtual baseclasses.  MAIN_BINFO is the binfo which determines
-   the virtual baseclasses to use; TYPE is the type of the object to
-   which the initialization applies.  TRUE_EXP is the true object we
-   are initializing, and DECL_PTR is the pointer to the sub-object we
-   are initializing.
+/* Fixup all the virtual upcast offsets for TYPE.  DECL_PTR is the
+   address of the sub-object being initialized.  */
+
+static void
+fixup_all_virtual_upcast_offsets (type, decl_ptr)
+     tree type;
+     tree decl_ptr;
+{
+  tree if_stmt;
+  tree in_charge_node;
+  tree vbases;
+
+  /* Only tweak the vtables if we're in charge.  */
+  in_charge_node = current_in_charge_parm;
+  if (!in_charge_node)
+    /* There's no need for any fixups in this case.  */
+    return;
+  in_charge_node = build_binary_op (EQ_EXPR, 
+                                   in_charge_node, integer_zero_node);
+  if_stmt = begin_if_stmt ();
+  finish_if_stmt_cond (in_charge_node, if_stmt);
+  
+  /* Iterate through the virtual bases, fixing up the upcast offset
+     for each one.  */
+  for (vbases = CLASSTYPE_VBASECLASSES (type);
+       vbases;
+       vbases = TREE_CHAIN (vbases))
+    {
+      if (flag_vtable_thunks)
+       /* We don't have dynamic thunks yet!  So for now, just fail
+          silently.  */
+       ;
+      else
+       {
+         tree vbase;
+         tree vbase_offsets;
+         tree addr;
 
-   When USE_COMPUTED_OFFSETS is non-zero, we can assume that the
-   object was laid out by a top-level constructor and the computed
-   offsets are valid to store vtables.  When zero, we must store new
-   vtables through virtual baseclass pointers.  */
+         vbase = find_vbase_instance (BINFO_TYPE (vbases), type);
+         vbase_offsets = NULL_TREE;
+         addr = convert_pointer_to_vbase (BINFO_TYPE (vbases), decl_ptr);
+         fixup_virtual_upcast_offsets (vbase,
+                                       TYPE_BINFO (BINFO_TYPE (vbases)),
+                                       1, 0, addr, decl_ptr,
+                                       type, vbase, &vbase_offsets);
+       }
+    }
+
+  /* Close out the if-statement.  */
+  finish_then_clause (if_stmt);
+  finish_if_stmt ();
+}
+
+/* Generate the code needed to initialize all the virtual function
+   table slots of all the virtual baseclasses.  BINFO is the binfo
+   which determines the virtual baseclasses to use.  TRUE_EXP is the
+   true object we are initializing, and DECL_PTR is the pointer to the
+   sub-object we are initializing.  */
 
 void
-expand_indirect_vtbls_init (binfo, true_exp, decl_ptr)
+expand_indirect_vtbls_init (binfo, decl_ptr)
      tree binfo;
-     tree true_exp, decl_ptr;
+     tree decl_ptr;
 {
   tree type = BINFO_TYPE (binfo);
 
@@ -2635,67 +3121,13 @@ expand_indirect_vtbls_init (binfo, true_exp, decl_ptr)
 
   if (TYPE_USES_VIRTUAL_BASECLASSES (type))
     {
-      rtx fixup_insns = NULL_RTX;
       tree vbases = CLASSTYPE_VBASECLASSES (type);
       struct vbase_info vi;
-      vi.decl_ptr = (true_exp ? build_unary_op (ADDR_EXPR, true_exp, 0) 
-                    : decl_ptr);
+      vi.decl_ptr = decl_ptr;
       vi.vbase_types = vbases;
 
       dfs_walk (binfo, dfs_find_vbases, unmarked_new_vtablep, &vi);
-
-      /* Initialized with vtables of type TYPE.  */
-      for (; vbases; vbases = TREE_CHAIN (vbases))
-       {
-         tree addr;
-
-         addr = convert_pointer_to_vbase (TREE_TYPE (vbases), vi.decl_ptr);
-
-         /* Do all vtables from this virtual base.  */
-         /* This assumes that virtual bases can never serve as parent
-            binfos.  (in the CLASSTYPE_VFIELD_PARENT sense)  */
-         expand_direct_vtbls_init (vbases, TYPE_BINFO (BINFO_TYPE (vbases)),
-                                   1, 0, addr);
-
-         /* Now we adjust the offsets for virtual functions that
-            cross virtual boundaries on an implicit upcast on vf call
-            so that the layout of the most complete type is used,
-            instead of assuming the layout of the virtual bases from
-            our current type.  */
-
-         if (flag_vtable_thunks)
-           {
-             /* We don't have dynamic thunks yet!
-                So for now, just fail silently.  */
-           }
-         else
-           {
-             tree vbase_offsets = NULL_TREE;
-             push_to_sequence (fixup_insns);
-             fixup_virtual_upcast_offsets (vbases,
-                                           TYPE_BINFO (BINFO_TYPE (vbases)),
-                                           1, 0, addr, vi.decl_ptr,
-                                           type, vbases, &vbase_offsets);
-             fixup_insns = get_insns ();
-             end_sequence ();
-           }
-       }
-
-      if (fixup_insns)
-       {
-         extern tree in_charge_identifier;
-         tree in_charge_node = lookup_name (in_charge_identifier, 0);
-         if (! in_charge_node)
-           {
-             warning ("recoverable internal compiler error, nobody's in charge!");
-             in_charge_node = integer_zero_node;
-           }
-         in_charge_node = build_binary_op (EQ_EXPR, in_charge_node, integer_zero_node, 1);
-         expand_start_cond (in_charge_node, 0);
-         emit_insns (fixup_insns);
-         expand_end_cond ();
-       }
-
+      fixup_all_virtual_upcast_offsets (type, vi.decl_ptr);
       dfs_walk (binfo, dfs_clear_vbase_slots, marked_new_vtablep, 0);
     }
 }
@@ -2709,49 +3141,120 @@ dfs_get_vbase_types (binfo, data)
      tree binfo;
      void *data;
 {
-  tree *vbase_types = (tree *) data;
+  tree type = (tree) data;
 
   if (TREE_VIA_VIRTUAL (binfo) && ! BINFO_VBASE_MARKED (binfo))
     {
-      tree new_vbase = make_binfo (integer_zero_node, binfo,
+      tree new_vbase = make_binfo (integer_zero_node, 
+                                  BINFO_TYPE (binfo),
                                   BINFO_VTABLE (binfo),
                                   BINFO_VIRTUALS (binfo));
-      TREE_CHAIN (new_vbase) = *vbase_types;
+      unshare_base_binfos (new_vbase);
       TREE_VIA_VIRTUAL (new_vbase) = 1;
-      *vbase_types = new_vbase;
+      BINFO_INHERITANCE_CHAIN (new_vbase) = TYPE_BINFO (type);
+      TREE_CHAIN (new_vbase) = CLASSTYPE_VBASECLASSES (type);
+      CLASSTYPE_VBASECLASSES (type) = new_vbase;
       SET_BINFO_VBASE_MARKED (binfo);
     }
   SET_BINFO_MARKED (binfo);
   return NULL_TREE;
 }
 
-/* Return a list of binfos for the virtual base classes for TYPE, in
-   depth-first search order.  The list is freshly allocated, so
-   no modification is made to  the current binfo hierarchy.  */
+/* Set CLASSTYPE_VBASECLASSES for TYPE.  */
 
-tree
+void
 get_vbase_types (type)
      tree type;
 {
-  tree vbase_types;
-  tree vbases;
-  tree binfo;
-
-  binfo = TYPE_BINFO (type);
-  vbase_types = NULL_TREE;
-  dfs_walk (binfo, dfs_get_vbase_types, unmarkedp, &vbase_types);
-  dfs_walk (binfo, dfs_unmark, markedp, 0);
+  CLASSTYPE_VBASECLASSES (type) = NULL_TREE;
+  dfs_walk (TYPE_BINFO (type), dfs_get_vbase_types, unmarkedp, type);
   /* Rely upon the reverse dfs ordering from dfs_get_vbase_types, and now
      reverse it so that we get normal dfs ordering.  */
-  vbase_types = nreverse (vbase_types);
+  CLASSTYPE_VBASECLASSES (type) = nreverse (CLASSTYPE_VBASECLASSES (type));
+  dfs_walk (TYPE_BINFO (type), dfs_vbase_unmark, markedp, 0);
+}
+
+/* Called from find_vbase_instance via dfs_walk.  */
+
+static tree
+dfs_find_vbase_instance (binfo, data)
+     tree binfo;
+     void *data;
+{
+  tree base = TREE_VALUE ((tree) data);
+
+  if (BINFO_PRIMARY_MARKED_P (binfo)
+      && same_type_p (BINFO_TYPE (binfo), base))
+    return binfo;
+
+  return NULL_TREE;
+}
+
+/* Find the real occurrence of the virtual BASE (a class type) in the
+   hierarchy dominated by TYPE.  */
 
-  /* unmark marked vbases */
-  for (vbases = vbase_types; vbases; vbases = TREE_CHAIN (vbases))
-    CLEAR_BINFO_VBASE_MARKED (vbases);
+tree
+find_vbase_instance (base, type)
+     tree base;
+     tree type;
+{
+  tree instance;
+
+  instance = BINFO_FOR_VBASE (base, type);
+  if (!BINFO_VBASE_PRIMARY_P (instance))
+    return instance;
 
-  return vbase_types;
+  return dfs_walk (TYPE_BINFO (type), 
+                  dfs_find_vbase_instance, 
+                  NULL,
+                  build_tree_list (type, base));
 }
+
 \f
+/* Debug info for C++ classes can get very large; try to avoid
+   emitting it everywhere.
+
+   Note that this optimization wins even when the target supports
+   BINCL (if only slightly), and reduces the amount of work for the
+   linker.  */
+
+void
+maybe_suppress_debug_info (t)
+     tree t;
+{
+  /* We can't do the usual TYPE_DECL_SUPPRESS_DEBUG thing with DWARF, which
+     does not support name references between translation units.  It supports
+     symbolic references between translation units, but only within a single
+     executable or shared library.
+
+     For DWARF 2, we handle TYPE_DECL_SUPPRESS_DEBUG by pretending
+     that the type was never defined, so we only get the members we
+     actually define.  */
+  if (write_symbols == DWARF_DEBUG || write_symbols == NO_DEBUG)
+    return;
+
+  /* We might have set this earlier in cp_finish_decl.  */
+  TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 0;
+
+  /* If we already know how we're handling this class, handle debug info
+     the same way.  */
+  if (CLASSTYPE_INTERFACE_ONLY (t))
+    TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1;
+  else if (CLASSTYPE_INTERFACE_KNOWN (t))
+    /* Don't set it.  */;
+  /* If the class has a vtable, write out the debug info along with
+     the vtable.  */
+  else if (TYPE_CONTAINS_VPTR_P (t))
+    TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1;
+
+  /* Otherwise, just emit the debug info normally.  */
+}
+
+#if 0
+/* Keep this code around in case we later want to control debug info
+   based on whether a type is "used".  Currently, we only suppress debug
+   info if we can emit it with the vtable.  jason 1999-11-11) */
+
 /* If we want debug info for a type TYPE, make sure all its base types
    are also marked as being potentially interesting.  This avoids
    the problem of not writing any debug info for intermediate basetypes
@@ -2770,12 +3273,8 @@ note_debug_info_needed (type)
     /* We can't go looking for the base types and fields just yet.  */
     return;
 
-  /* We can't do the TYPE_DECL_SUPPRESS_DEBUG thing with DWARF, which
-     does not support name references between translation units.  Well, we
-     could, but that would mean putting global labels in the debug output
-     before each exported type and each of its functions and static data
-     members.  */
-  if (write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG)
+  /* See the comment in maybe_suppress_debug_info.  */
+  if (write_symbols == DWARF_DEBUG || write_symbols == NO_DEBUG)
     return;
 
   dfs_walk (TYPE_BINFO (type), dfs_debug_mark, dfs_debug_unmarkedp, 0);
@@ -2788,6 +3287,7 @@ note_debug_info_needed (type)
        note_debug_info_needed (ttype);
     }
 }
+#endif
 \f
 /* Subroutines of push_class_decls ().  */
 
@@ -2828,9 +3328,9 @@ setup_class_bindings (name, type_binding_p)
                                    /*protect=*/2,
                                    /*want_type=*/1);
       if (TREE_CODE (type_binding) == TREE_LIST 
-         && TREE_PURPOSE (type_binding) == error_mark_node)
+         && TREE_TYPE (type_binding) == error_mark_node)
        /* NAME is ambiguous.  */
-       push_class_level_binding (name, TREE_VALUE (type_binding));
+       push_class_level_binding (name, type_binding);
       else
        pushdecl_class_level (type_binding);
     }
@@ -2843,22 +3343,22 @@ setup_class_bindings (name, type_binding_p)
   if (type_binding_p
       && (TREE_CODE (value_binding) == TYPE_DECL
          || (TREE_CODE (value_binding) == TREE_LIST
-             && TREE_PURPOSE (value_binding) == error_mark_node
-             && (TREE_CODE (TREE_VALUE (TREE_VALUE (value_binding)))
+             && 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
+  else if (value_binding)
     {
       if (TREE_CODE (value_binding) == TREE_LIST 
-         && TREE_PURPOSE (value_binding) == error_mark_node)
+         && TREE_TYPE (value_binding) == error_mark_node)
        /* NAME is ambiguous.  */
-       push_class_level_binding (name, TREE_VALUE (value_binding));
+       push_class_level_binding (name, value_binding);
       else
        {
-         if (TREE_CODE (value_binding) == TREE_LIST)
+         if (BASELINK_P (value_binding))
            /* NAME is some overloaded functions.  */
            value_binding = TREE_VALUE (value_binding);
          pushdecl_class_level (value_binding);
@@ -2915,7 +3415,7 @@ dfs_push_decls (binfo, data)
            && TREE_CODE (fields) != USING_DECL)
          setup_class_bindings (DECL_NAME (fields), /*type_binding_p=*/0);
        else if (TREE_CODE (fields) == FIELD_DECL
-                && ANON_UNION_TYPE_P (TREE_TYPE (fields)))
+                && ANON_AGGR_TYPE_P (TREE_TYPE (fields)))
          dfs_push_decls (TYPE_BINFO (TREE_TYPE (fields)), data);
          
       method_vec = (CLASS_TYPE_P (type) 
@@ -2952,25 +3452,13 @@ void
 push_class_decls (type)
      tree type;
 {
-  struct obstack *ambient_obstack = current_obstack;
   search_stack = push_search_level (search_stack, &search_obstack);
 
-  /* Build up all the relevant bindings and such on the cache
-     obstack.  That way no memory is wasted when we throw away the
-     cache later.  */
-  maybe_push_cache_obstack ();
-
-  /* Push class fields into CLASS_VALUE scope, and mark.  */
+  /* Enter type declarations and mark.  */
   dfs_walk (TYPE_BINFO (type), dfs_push_type_decls, unmarked_pushdecls_p, 0);
 
-  /* Compress fields which have only a single entry
-     by a given name, and unmark.  */
+  /* Enter non-type declarations and unmark.  */
   dfs_walk (TYPE_BINFO (type), dfs_push_decls, marked_pushdecls_p, 0);
-
-  /* Undo the call to maybe_push_cache_obstack above.  */
-  pop_obstacks ();
-
-  current_obstack = ambient_obstack;
 }
 
 /* Here's a subroutine we need because C lacks lambdas.  */
@@ -2990,7 +3478,7 @@ dfs_unuse_fields (binfo, data)
 
       TREE_USED (fields) = 0;
       if (DECL_NAME (fields) == NULL_TREE
-         && TREE_CODE (TREE_TYPE (fields)) == UNION_TYPE)
+         && ANON_AGGR_TYPE_P (TREE_TYPE (fields)))
        unuse_fields (TREE_TYPE (fields));
     }
 
@@ -3031,7 +3519,7 @@ void
 init_search_processing ()
 {
   gcc_obstack_init (&search_obstack);
-  _vptr_name = get_identifier ("_vptr");
+  vptr_identifier = get_identifier ("_vptr");
 }
 
 void
@@ -3047,8 +3535,6 @@ reinit_search_statistics ()
 #endif /* GATHER_STATISTICS */
 }
 
-#define scratch_tree_cons expr_tree_cons
-
 static tree
 add_conversions (binfo, data)
      tree binfo;
@@ -3058,6 +3544,10 @@ add_conversions (binfo, data)
   tree method_vec = CLASSTYPE_METHOD_VEC (BINFO_TYPE (binfo));
   tree *conversions = (tree *) data;
 
+  /* Some builtin types have no method vector, not even an empty one.  */
+  if (!method_vec)
+    return NULL_TREE;
+
   for (i = 2; i < TREE_VEC_LENGTH (method_vec); ++i)
     {
       tree tmp = TREE_VEC_ELT (method_vec, i);
@@ -3071,13 +3561,19 @@ add_conversions (binfo, data)
       /* Make sure we don't already have this conversion.  */
       if (! IDENTIFIER_MARKED (name))
        {
-         *conversions = scratch_tree_cons (binfo, tmp, *conversions);
+         *conversions = tree_cons (binfo, tmp, *conversions);
          IDENTIFIER_MARKED (name) = 1;
        }
     }
   return NULL_TREE;
 }
 
+/* Return a TREE_LIST containing all the non-hidden user-defined
+   conversion functions for TYPE (and its base-classes).  The
+   TREE_VALUE of each node is a FUNCTION_DECL or an OVERLOAD
+   containing the conversion functions.  The TREE_PURPOSE is the BINFO
+   from which the conversion functions in this node were selected.  */
+
 tree
 lookup_conversions (type)
      tree type;
@@ -3155,52 +3651,44 @@ types_overlap_p (empty_type, next_type)
   return oi.found_overlap;
 }
 
-struct bfv_info {
-  tree vbases;
-  tree var;
-};
+/* Given a vtable VAR, determine which binfo it comes from.
 
-static tree
-dfs_bfv_queue_p (binfo, data)
-     tree binfo;
-     void *data;
+   FIXME What about secondary vtables?  */
+
+tree
+binfo_for_vtable (var)
+     tree var;
 {
-  struct bfv_info *bfvi = (struct bfv_info *) data;
+  tree binfo = TYPE_BINFO (DECL_CONTEXT (var));
+  tree binfos;
+  int i;
 
-  /* Use the real virtual base class objects, not the placeholders in
-     the usual hierarchy.  */
-  if (TREE_VIA_VIRTUAL (binfo))
-    return binfo_member (BINFO_TYPE (binfo), bfvi->vbases);
-  
-  return binfo;
-}
+  while (1)
+    {
+      binfos = BINFO_BASETYPES (binfo);
+      if (binfos == NULL_TREE)
+       break;
 
-/* Passed to dfs_walk_real by binfo_for_vtable; determine if bvtable
-   comes from BINFO.  */
+      i = CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
+      if (i == -1)
+       break;
 
-static tree
-dfs_bfv_helper (binfo, data)
-     tree binfo;
-     void *data;
-{
-  struct bfv_info *bfvi = (struct bfv_info *) data;
+      binfo = TREE_VEC_ELT (binfos, i);
+    }
 
-  if (BINFO_VTABLE (binfo) == bfvi->var)
-    return binfo;
-  return NULL_TREE;
+  return binfo;
 }
 
-/* Given a vtable VAR, determine which binfo it comes from.  */
+/* Returns 1 iff BINFO is from a direct or indirect virtual base.  */
 
-tree
-binfo_for_vtable (var)
-     tree var;
+int
+binfo_from_vbase (binfo)
+     tree binfo;
 {
-  tree type;
-  struct bfv_info bfvi;
-
-  type = DECL_CONTEXT (var);
-  bfvi.vbases = CLASSTYPE_VBASECLASSES (type);
-  return dfs_walk_real (TYPE_BINFO (type),
-                       0, dfs_bfv_helper, dfs_bfv_queue_p, &bfvi);
+  for (; binfo; binfo = BINFO_INHERITANCE_CHAIN (binfo))
+    {
+      if (TREE_VIA_VIRTUAL (binfo))
+       return 1;
+    }
+  return 0;
 }