OSDN Git Service

* class.c (pushclass): Remove #if 0'd code.
[pf3gnuchains/gcc-fork.git] / gcc / cp / class.c
index 5d8390f..db4b480 100644 (file)
@@ -62,8 +62,10 @@ typedef struct class_stack_node {
   splay_tree names_used;
 }* class_stack_node_t;
 
-typedef struct vcall_offset_data_s
+typedef struct vtbl_init_data_s
 {
+  /* The base for which we're building initializers.  */
+  tree binfo;
   /* The binfo for the most-derived type.  */
   tree derived;
   /* The negative-index vtable initializers built up so far.  These
@@ -72,7 +74,7 @@ typedef struct vcall_offset_data_s
   /* The last (i.e., most negative entry in INITS.  */
   tree* last_init;
   /* The binfo for the virtual base for which we're building
-     initializers.  */
+     vcall offset initializers.  */
   tree vbase;
   /* The functions in vbase for which we have already provided vcall
      offsets.  */
@@ -81,8 +83,14 @@ typedef struct vcall_offset_data_s
   tree index;
   /* Nonzero if we are building the initializer for the primary
      vtable.  */
-  int primary_p;
-} vcall_offset_data;
+  int primary_vtbl_p;
+  /* Nonzero if we are building the initializer for a construction
+     vtable.  */
+  int ctor_vtbl_p;
+} vtbl_init_data;
+
+/* The type of a function passed to walk_subobject_offsets.  */
+typedef int (*subobject_offset_fn) PARAMS ((tree, tree, splay_tree));
 
 /* The stack itself.  This is an dynamically resized array.  The
    number of elements allocated is CURRENT_CLASS_STACK_SIZE.  */
@@ -96,7 +104,7 @@ varray_type local_classes;
 static tree get_vfield_name PARAMS ((tree));
 static void finish_struct_anon PARAMS ((tree));
 static tree build_vbase_pointer PARAMS ((tree, tree));
-static tree build_vtable_entry PARAMS ((tree, tree, tree));
+static tree build_vtable_entry PARAMS ((tree, tree, tree, int));
 static tree get_vtable_name PARAMS ((tree));
 static tree get_derived_offset PARAMS ((tree, tree));
 static tree get_basefndecls PARAMS ((tree, tree));
@@ -127,7 +135,7 @@ static int method_name_cmp PARAMS ((const tree *, const tree *));
 static tree add_implicitly_declared_members PARAMS ((tree, int, int, int));
 static tree fixed_type_or_null PARAMS ((tree, int *));
 static tree resolve_address_of_overloaded_function PARAMS ((tree, tree, int,
-                                                         int, tree));
+                                                         int, int, tree));
 static void build_vtable_entry_ref PARAMS ((tree, tree, tree));
 static tree build_vtbl_initializer PARAMS ((tree, tree, tree, tree, int *));
 static int count_fields PARAMS ((tree));
@@ -137,8 +145,9 @@ static void check_field_decl PARAMS ((tree, tree, int *, int *, int *, int *));
 static void check_field_decls PARAMS ((tree, tree *, int *, int *, int *, 
                                     int *));
 static void build_base_field PARAMS ((record_layout_info, tree, int *,
-                                     unsigned int *, varray_type *));
-static varray_type build_base_fields PARAMS ((record_layout_info, int *));
+                                     unsigned int *, splay_tree));
+static void build_base_fields PARAMS ((record_layout_info, int *,
+                                      splay_tree));
 static tree build_vbase_pointer_fields PARAMS ((record_layout_info, int *));
 static tree build_vtbl_or_vbase_field PARAMS ((tree, tree, tree, tree, tree,
                                               int *));
@@ -148,21 +157,19 @@ static void check_bases PARAMS ((tree, int *, int *, int *));
 static void check_bases_and_members PARAMS ((tree, int *));
 static tree create_vtable_ptr PARAMS ((tree, int *, int *, tree *, tree *));
 static void layout_class_type PARAMS ((tree, int *, int *, tree *, tree *));
-static void fixup_pending_inline PARAMS ((struct pending_inline *));
+static void fixup_pending_inline PARAMS ((tree));
 static void fixup_inline_methods PARAMS ((tree));
-static void set_primary_base PARAMS ((tree, int, int *));
-static tree dfs_propagate_binfo_offsets PARAMS ((tree, void *));
+static void set_primary_base PARAMS ((tree, tree, int *));
 static void propagate_binfo_offsets PARAMS ((tree, tree));
-static void layout_virtual_bases PARAMS ((tree, varray_type *));
-static tree dfs_set_offset_for_shared_vbases PARAMS ((tree, void *));
+static void layout_virtual_bases PARAMS ((tree, splay_tree));
 static tree dfs_set_offset_for_unshared_vbases PARAMS ((tree, void *));
-static void build_vbase_offset_vtbl_entries PARAMS ((tree, vcall_offset_data *));
-static tree dfs_build_vcall_offset_vtbl_entries PARAMS ((tree, void *));
-static void build_vcall_offset_vtbl_entries PARAMS ((tree, vcall_offset_data *));
+static void build_vbase_offset_vtbl_entries PARAMS ((tree, vtbl_init_data *));
+static void add_vcall_offset_vtbl_entries_r PARAMS ((tree, vtbl_init_data *));
+static void add_vcall_offset_vtbl_entries_1 PARAMS ((tree, vtbl_init_data *));
+static void build_vcall_offset_vtbl_entries PARAMS ((tree, vtbl_init_data *));
 static void layout_vtable_decl PARAMS ((tree, int));
 static tree dfs_find_final_overrider PARAMS ((tree, void *));
 static tree find_final_overrider PARAMS ((tree, tree, tree));
-static tree dfs_find_base PARAMS ((tree, void *));
 static int make_new_vtable PARAMS ((tree, tree));
 static void dump_class_hierarchy_r PARAMS ((tree, tree, int));
 extern void dump_class_hierarchy PARAMS ((tree));
@@ -171,18 +178,14 @@ static void initialize_vtable PARAMS ((tree, tree));
 static void initialize_array PARAMS ((tree, tree));
 static void layout_nonempty_base_or_field PARAMS ((record_layout_info,
                                                   tree, tree,
-                                                  varray_type));
-static tree dfs_record_base_offsets PARAMS ((tree, void *));
-static void record_base_offsets PARAMS ((tree, varray_type *));
-static tree dfs_search_base_offsets PARAMS ((tree, void *));
-static int layout_conflict_p PARAMS ((tree, varray_type));
+                                                  splay_tree));
 static unsigned HOST_WIDE_INT end_of_class PARAMS ((tree, int));
-static void layout_empty_base PARAMS ((tree, tree, varray_type));
+static void layout_empty_base PARAMS ((tree, tree, splay_tree));
 static void accumulate_vtbl_inits PARAMS ((tree, tree, tree, tree, tree));
 static void set_vindex PARAMS ((tree, tree, int *));
-static void build_rtti_vtbl_entries PARAMS ((tree, tree, vcall_offset_data *));
+static void build_rtti_vtbl_entries PARAMS ((tree, tree, vtbl_init_data *));
 static void build_vcall_and_vbase_vtbl_entries PARAMS ((tree, 
-                                                       vcall_offset_data *));
+                                                       vtbl_init_data *));
 static tree dfs_mark_primary_bases PARAMS ((tree, void *));
 static void mark_primary_bases PARAMS ((tree));
 static void clone_constructors_and_destructors PARAMS ((tree));
@@ -191,10 +194,19 @@ static void update_vtable_entry_for_fn PARAMS ((tree, tree, tree, tree *));
 static tree copy_virtuals PARAMS ((tree));
 static void build_ctor_vtbl_group PARAMS ((tree, tree));
 static void build_vtt PARAMS ((tree));
-static tree *build_vtt_inits PARAMS ((tree, tree, tree *, tree *));
-static tree dfs_build_vtt_inits PARAMS ((tree, void *));
+static tree *build_vtt_inits PARAMS ((tree, tree, int, tree *, tree *));
+static tree dfs_build_secondary_vptr_vtt_inits PARAMS ((tree, void *));
 static tree dfs_fixup_binfo_vtbls PARAMS ((tree, void *));
-static int indirect_primary_base_p PARAMS ((tree, tree));
+static tree get_matching_base PARAMS ((tree, tree));
+static tree dfs_get_primary_binfo PARAMS ((tree, void*));
+static int record_subobject_offset PARAMS ((tree, tree, splay_tree));
+static int check_subobject_offset PARAMS ((tree, tree, splay_tree));
+static int walk_subobject_offsets PARAMS ((tree, subobject_offset_fn,
+                                          tree, splay_tree, int));
+static void record_subobject_offsets PARAMS ((tree, tree, splay_tree, int));
+static int layout_conflict_p PARAMS ((tree, tree, splay_tree, int));
+static int splay_tree_compare_integer_csts PARAMS ((splay_tree_key k1,
+                                                   splay_tree_key k2));
 
 /* Variables shared between class.c and call.c.  */
 
@@ -507,7 +519,7 @@ build_vtable_entry_ref (basetype, vtbl, idx)
   i = build_c_cast (ptrdiff_type_node, build_unary_op (ADDR_EXPR, i, 0));
   i2 = build_array_ref (vtbl, build_int_2(0,0));
   i2 = build_c_cast (ptrdiff_type_node, build_unary_op (ADDR_EXPR, i2, 0));
-  i = build_binary_op (MINUS_EXPR, i, i2);
+  i = cp_build_binary_op (MINUS_EXPR, i, i2);
   i = build_tree_list (build_string (1, "i"), i);
 
   finish_asm_stmt (ridpointers[RID_VOLATILE],
@@ -685,16 +697,9 @@ get_derived_offset (binfo, type)
 {
   tree offset1 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
   tree offset2;
-  int i;
 
-  while (BINFO_BASETYPES (binfo)
-        && (i = CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo))) != -1)
-    {
-      tree binfos = BINFO_BASETYPES (binfo);
-      if (BINFO_TYPE (binfo) == type)
-       break;
-      binfo = TREE_VEC_ELT (binfos, i);
-    }
+  while (!same_type_p (BINFO_TYPE (binfo), type))
+    binfo = get_primary_binfo (binfo);
 
   offset2 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
   return size_binop (MINUS_EXPR, offset1, offset2);
@@ -778,7 +783,11 @@ copy_virtuals (binfo)
 
   copies = copy_list (BINFO_VIRTUALS (binfo));
   for (t = copies; t; t = TREE_CHAIN (t))
-    BV_VCALL_INDEX (t) = NULL_TREE;
+    {
+      BV_VCALL_INDEX (t) = NULL_TREE;
+      BV_USE_VCALL_INDEX_P (t) = 0;
+      BV_GENERATE_THUNK_WITH_VTABLE_P (t) = 0;
+    }
 
   return copies;
 }
@@ -793,7 +802,8 @@ static int
 build_primary_vtable (binfo, type)
      tree binfo, type;
 {
-  tree virtuals, decl;
+  tree decl;
+  tree virtuals;
 
   decl = get_vtable_decl (type, /*complete=*/0);
   
@@ -825,9 +835,7 @@ build_primary_vtable (binfo, type)
      on our first approximation.  */
   TYPE_BINFO_VTABLE (type) = decl;
   TYPE_BINFO_VIRTUALS (type) = virtuals;
-
-  binfo = TYPE_BINFO (type);
-  SET_BINFO_NEW_VTABLE_MARKED (binfo, type);
+  SET_BINFO_NEW_VTABLE_MARKED (TYPE_BINFO (type), type);
   return 1;
 }
 
@@ -855,7 +863,8 @@ build_secondary_vtable (binfo, for_type)
   tree new_decl;
   tree offset;
   tree path = binfo;
-  char *buf, *buf2;
+  char *buf;
+  const char *buf2;
   char joiner = '_';
   int i;
 
@@ -1126,7 +1135,8 @@ add_virtual_function (new_virtuals_p, overridden_virtuals_p,
     /* We've already dealt with this function.  */
     return;
 
-  new_virtual = build_tree_list (NULL_TREE, fndecl);
+  new_virtual = make_node (TREE_LIST);
+  BV_FN (new_virtual) = fndecl;
   BV_DELTA (new_virtual) = integer_zero_node;
 
   if (DECL_VINDEX (fndecl) == error_mark_node)
@@ -1153,192 +1163,199 @@ add_virtual_function (new_virtuals_p, overridden_virtuals_p,
     }
 }
 \f
-extern struct obstack *current_obstack;
-
-/* Add method METHOD to class TYPE.
-
-   If non-NULL, FIELDS is the entry in the METHOD_VEC vector entry of
-   the class type where the method should be added.  */
+/* Add method METHOD to class TYPE.  If ERROR_P is true, we are adding
+   the method after the class has already been defined because a
+   declaration for it was seen.  (Even though that is erroneous, we
+   add the method for improved error recovery.)  */
 
 void
-add_method (type, fields, method)
-     tree type, *fields, method;
+add_method (type, method, error_p)
+     tree type;
+     tree method;
+     int error_p;
 {
   int using = (DECL_CONTEXT (method) != type);
-  
-  if (fields && *fields)
-    *fields = build_overload (method, *fields);
-  else 
+  int len;
+  int slot;
+  tree method_vec;
+
+  if (!CLASSTYPE_METHOD_VEC (type))
+    /* Make a new method vector.  We start with 8 entries.  We must
+       allocate at least two (for constructors and destructors), and
+       we're going to end up with an assignment operator at some point
+       as well.
+       
+       We could use a TREE_LIST for now, and convert it to a TREE_VEC
+       in finish_struct, but we would probably waste more memory
+       making the links in the list than we would by over-allocating
+       the size of the vector here.  Furthermore, we would complicate
+       all the code that expects this to be a vector.  */
+    CLASSTYPE_METHOD_VEC (type) = make_tree_vec (8);
+
+  method_vec = CLASSTYPE_METHOD_VEC (type);
+  len = TREE_VEC_LENGTH (method_vec);
+
+  /* Constructors and destructors go in special slots.  */
+  if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (method))
+    slot = CLASSTYPE_CONSTRUCTOR_SLOT;
+  else if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (method))
+    slot = CLASSTYPE_DESTRUCTOR_SLOT;
+  else
     {
-      int len;
-      int slot;
-      tree method_vec;
-
-      if (!CLASSTYPE_METHOD_VEC (type))
-       /* Make a new method vector.  We start with 8 entries.  We must
-          allocate at least two (for constructors and destructors), and
-          we're going to end up with an assignment operator at some
-          point as well.  
-
-          We could use a TREE_LIST for now, and convert it to a
-          TREE_VEC in finish_struct, but we would probably waste more
-          memory making the links in the list than we would by
-          over-allocating the size of the vector here.  Furthermore,
-          we would complicate all the code that expects this to be a
-          vector.  */
-       CLASSTYPE_METHOD_VEC (type) = make_tree_vec (8);
-
-      method_vec = CLASSTYPE_METHOD_VEC (type);
-      len = TREE_VEC_LENGTH (method_vec);
-
-      /* Constructors and destructors go in special slots.  */
-      if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (method))
-       slot = CLASSTYPE_CONSTRUCTOR_SLOT;
-      else if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (method))
-       slot = CLASSTYPE_DESTRUCTOR_SLOT;
-      else
-       {
-         /* See if we already have an entry with this name.  */
-         for (slot = CLASSTYPE_FIRST_CONVERSION_SLOT; slot < len; ++slot)
-           if (!TREE_VEC_ELT (method_vec, slot)
-               || (DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (method_vec, 
-                                                         slot))) 
-                   == DECL_NAME (method)))
-             break;
+      /* See if we already have an entry with this name.  */
+      for (slot = CLASSTYPE_FIRST_CONVERSION_SLOT; slot < len; ++slot)
+       if (!TREE_VEC_ELT (method_vec, slot)
+           || (DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (method_vec, 
+                                                     slot))) 
+               == DECL_NAME (method)))
+         break;
                
-         if (slot == len)
-           {
-             /* We need a bigger method vector.  */
-             tree new_vec = make_tree_vec (2 * len);
-             bcopy ((PTR) &TREE_VEC_ELT (method_vec, 0),
-                    (PTR) &TREE_VEC_ELT (new_vec, 0),
-                    len * sizeof (tree));
-             len = 2 * len;
-             method_vec = CLASSTYPE_METHOD_VEC (type) = new_vec;
-           }
+      if (slot == len)
+       {
+         /* We need a bigger method vector.  */
+         int new_len;
+         tree new_vec;
+
+         /* In the non-error case, we are processing a class
+            definition.  Double the size of the vector to give room
+            for new methods.  */
+         if (!error_p)
+           new_len = 2 * len;
+         /* In the error case, the vector is already complete.  We
+            don't expect many errors, and the rest of the front-end
+            will get confused if there are empty slots in the vector.  */
+         else
+           new_len = len + 1;
+
+         new_vec = make_tree_vec (new_len);
+         bcopy ((PTR) &TREE_VEC_ELT (method_vec, 0),
+                (PTR) &TREE_VEC_ELT (new_vec, 0),
+                len * sizeof (tree));
+         len = new_len;
+         method_vec = CLASSTYPE_METHOD_VEC (type) = new_vec;
+       }
 
-         if (DECL_CONV_FN_P (method) && !TREE_VEC_ELT (method_vec, slot))
+      if (DECL_CONV_FN_P (method) && !TREE_VEC_ELT (method_vec, slot))
+       {
+         /* Type conversion operators have to come before ordinary
+            methods; add_conversions depends on this to speed up
+            looking for conversion operators.  So, if necessary, we
+            slide some of the vector elements up.  In theory, this
+            makes this algorithm O(N^2) but we don't expect many
+            conversion operators.  */
+         for (slot = 2; slot < len; ++slot)
            {
-             /* Type conversion operators have to come before
-                ordinary methods; add_conversions depends on this to
-                speed up looking for conversion operators.  So, if
-                necessary, we slide some of the vector elements up.
-                In theory, this makes this algorithm O(N^2) but we
-                don't expect many conversion operators.  */
-             for (slot = 2; slot < len; ++slot)
-               {
-                 tree fn = TREE_VEC_ELT (method_vec, slot);
+             tree fn = TREE_VEC_ELT (method_vec, slot);
   
-                 if (!fn)
-                   /* There are no more entries in the vector, so we
-                      can insert the new conversion operator here.  */
-                   break;
+             if (!fn)
+               /* There are no more entries in the vector, so we
+                  can insert the new conversion operator here.  */
+               break;
                  
-                 if (!DECL_CONV_FN_P (OVL_CURRENT (fn)))
-                   /* We can insert the new function right at the
-                      SLOTth position.  */
-                   break;
-               }
+             if (!DECL_CONV_FN_P (OVL_CURRENT (fn)))
+               /* We can insert the new function right at the
+                  SLOTth position.  */
+               break;
+           }
   
-             if (!TREE_VEC_ELT (method_vec, slot))
-               /* There is nothing in the Ith slot, so we can avoid
-                  moving anything.  */
+         if (!TREE_VEC_ELT (method_vec, slot))
+           /* There is nothing in the Ith slot, so we can avoid
+              moving anything.  */
                ; 
-             else
-               {
-                 /* We know the last slot in the vector is empty
-                    because we know that at this point there's room
-                    for a new function.  */
-                 bcopy ((PTR) &TREE_VEC_ELT (method_vec, slot),
-                        (PTR) &TREE_VEC_ELT (method_vec, slot + 1),
-                        (len - slot - 1) * sizeof (tree));
-                 TREE_VEC_ELT (method_vec, slot) = NULL_TREE;
-               }
+         else
+           {
+             /* We know the last slot in the vector is empty
+                because we know that at this point there's room
+                for a new function.  */
+             bcopy ((PTR) &TREE_VEC_ELT (method_vec, slot),
+                    (PTR) &TREE_VEC_ELT (method_vec, slot + 1),
+                    (len - slot - 1) * sizeof (tree));
+             TREE_VEC_ELT (method_vec, slot) = NULL_TREE;
            }
        }
+    }
       
-      if (template_class_depth (type))
-       /* TYPE is a template class.  Don't issue any errors now; wait
-          until instantiation time to complain.  */
-         ;
-      else
-       {
-         tree fns;
+  if (template_class_depth (type))
+    /* TYPE is a template class.  Don't issue any errors now; wait
+       until instantiation time to complain.  */
+    ;
+  else
+    {
+      tree fns;
 
-         /* Check to see if we've already got this method.  */
-         for (fns = TREE_VEC_ELT (method_vec, slot);
-              fns;
-              fns = OVL_NEXT (fns))
-           {
-             tree fn = OVL_CURRENT (fns);
+      /* Check to see if we've already got this method.  */
+      for (fns = TREE_VEC_ELT (method_vec, slot);
+          fns;
+          fns = OVL_NEXT (fns))
+       {
+         tree fn = OVL_CURRENT (fns);
                 
-             if (TREE_CODE (fn) != TREE_CODE (method))
-               continue;
+         if (TREE_CODE (fn) != TREE_CODE (method))
+           continue;
 
-             if (TREE_CODE (method) != TEMPLATE_DECL)
+         if (TREE_CODE (method) != TEMPLATE_DECL)
+           {
+             /* [over.load] Member function declarations with the
+                same name and the same parameter types cannot be
+                overloaded if any of them is a static member
+                function declaration.  */
+             if ((DECL_STATIC_FUNCTION_P (fn)
+                  != DECL_STATIC_FUNCTION_P (method))
+                 || using)
                {
-                 /* [over.load] Member function declarations with the
-                    same name and the same parameter types cannot be
-                    overloaded if any of them is a static member
-                    function declaration.  */
-                 if ((DECL_STATIC_FUNCTION_P (fn)
-                      != DECL_STATIC_FUNCTION_P (method))
-                     || using)
+                 tree parms1 = TYPE_ARG_TYPES (TREE_TYPE (fn));
+                 tree parms2 = TYPE_ARG_TYPES (TREE_TYPE (method));
+
+                 if (! DECL_STATIC_FUNCTION_P (fn))
+                   parms1 = TREE_CHAIN (parms1);
+                 if (! DECL_STATIC_FUNCTION_P (method))
+                   parms2 = TREE_CHAIN (parms2);
+
+                 if (compparms (parms1, parms2))
                    {
-                     tree parms1 = TYPE_ARG_TYPES (TREE_TYPE (fn));
-                     tree parms2 = TYPE_ARG_TYPES (TREE_TYPE (method));
-
-                     if (! DECL_STATIC_FUNCTION_P (fn))
-                       parms1 = TREE_CHAIN (parms1);
-                     if (! DECL_STATIC_FUNCTION_P (method))
-                       parms2 = TREE_CHAIN (parms2);
-
-                     if (compparms (parms1, parms2))
-                       {
-                         if (using)
-                           /* Defer to the local function.  */
-                           return;
-                         else
-                           cp_error ("`%#D' and `%#D' cannot be overloaded",
-                                     fn, method);
-                       }
+                     if (using)
+                       /* Defer to the local function.  */
+                       return;
+                     else
+                       cp_error ("`%#D' and `%#D' cannot be overloaded",
+                                 fn, method);
                    }
-
-                 /* Since this is an ordinary function in a
-                    non-template class, it's mangled name can be used
-                    as a unique identifier.  This technique is only
-                    an optimization; we would get the same results if
-                    we just used decls_match here.  */
-                 if (DECL_ASSEMBLER_NAME (fn) 
-                     != DECL_ASSEMBLER_NAME (method))
-                   continue;
                }
-             else if (!decls_match (fn, method))
+
+             /* Since this is an ordinary function in a
+                non-template class, it's mangled name can be used
+                as a unique identifier.  This technique is only
+                an optimization; we would get the same results if
+                we just used decls_match here.  */
+             if (DECL_ASSEMBLER_NAME (fn) 
+                 != DECL_ASSEMBLER_NAME (method))
                continue;
+           }
+         else if (!decls_match (fn, method))
+           continue;
 
-             /* There has already been a declaration of this method
-                or member template.  */
-             cp_error_at ("`%D' has already been declared in `%T'", 
-                          method, type);
+         /* There has already been a declaration of this method
+            or member template.  */
+         cp_error_at ("`%D' has already been declared in `%T'", 
+                      method, type);
 
-             /* We don't call duplicate_decls here to merge the
-                declarations because that will confuse things if the
-                methods have inline definitions.  In particular, we
-                will crash while processing the definitions.  */
-             return;
-           }
+         /* We don't call duplicate_decls here to merge the
+            declarations because that will confuse things if the
+            methods have inline definitions.  In particular, we
+            will crash while processing the definitions.  */
+         return;
        }
+    }
 
-      /* Actually insert the new method.  */
-      TREE_VEC_ELT (method_vec, slot) 
-       = build_overload (method, TREE_VEC_ELT (method_vec, slot));
+  /* Actually insert the new method.  */
+  TREE_VEC_ELT (method_vec, slot) 
+    = build_overload (method, TREE_VEC_ELT (method_vec, slot));
 
       /* Add the new binding.  */ 
-      if (!DECL_CONSTRUCTOR_P (method)
-         && !DECL_DESTRUCTOR_P (method))
-       push_class_level_binding (DECL_NAME (method),
-                                 TREE_VEC_ELT (method_vec, slot));
-    }
+  if (!DECL_CONSTRUCTOR_P (method)
+      && !DECL_DESTRUCTOR_P (method))
+    push_class_level_binding (DECL_NAME (method),
+                             TREE_VEC_ELT (method_vec, slot));
 }
 
 /* Subroutines of finish_struct.  */
@@ -1567,7 +1584,7 @@ handle_using_decl (using_decl, t)
   if (flist)
     for (; flist; flist = OVL_NEXT (flist))
       {
-       add_method (t, 0, OVL_CURRENT (flist));
+       add_method (t, OVL_CURRENT (flist), /*error_p=*/0);
        alter_access (t, OVL_CURRENT (flist), access);
       }
   else
@@ -1704,19 +1721,14 @@ dfs_mark_primary_bases (binfo, data)
      tree binfo;
      void *data;
 {
-  int i;
   tree base_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);
+  base_binfo = get_primary_binfo (binfo);
 
-  if (!TREE_VIA_VIRTUAL (base_binfo))
-    /* Non-virtual base classes are easy.  */
-    BINFO_PRIMARY_MARKED_P (base_binfo) = 1;
-  else
+  if (TREE_VIA_VIRTUAL (base_binfo))
     {
       tree shared_binfo;
       tree type;
@@ -1726,7 +1738,7 @@ dfs_mark_primary_bases (binfo, data)
 
       /* 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))
+      if (!BINFO_PRIMARY_MARKED_P (shared_binfo))
        {
          /* Make sure the CLASSTYPE_VBASECLASSES list contains the
             primary copy; it's the one that really exists.  */
@@ -1734,12 +1746,14 @@ dfs_mark_primary_bases (binfo, data)
            TREE_VALUE (purpose_member (BINFO_TYPE (base_binfo),
                                        CLASSTYPE_VBASECLASSES (type)))
              = base_binfo;
-
-         BINFO_VBASE_PRIMARY_P (base_binfo) = 1;
-         BINFO_PRIMARY_MARKED_P (base_binfo) = 1;
        }
+      else
+       base_binfo = NULL_TREE;
     }
 
+  if (base_binfo)
+    BINFO_PRIMARY_BASE_OF (base_binfo) = binfo;
+
   return NULL_TREE;
 }
 
@@ -1777,36 +1791,29 @@ mark_primary_bases (type)
        continue;
 
       vbase = binfo_for_vbase (BINFO_TYPE (vbases), type);
-      if (BINFO_VBASE_PRIMARY_P (vbase))
+      if (BINFO_PRIMARY_MARKED_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_real (vbase, dfs_mark_primary_bases, NULL,
                     dfs_skip_nonprimary_vbases_unmarkedp, type);
-
-      /* VBASE wasn't really primary.  */
-      BINFO_PRIMARY_MARKED_P (vbase) = 0;
     }
 }
 
-/* Make the Ith baseclass of T its primary base.  */
+/* Make the BINFO the primary base of T.  */
 
 static void
-set_primary_base (t, i, vfuns_p)
+set_primary_base (t, binfo, vfuns_p)
      tree t;
-     int i;
+     tree binfo;
      int *vfuns_p;
 {
   tree basetype;
 
-  CLASSTYPE_VFIELD_PARENT (t) = i;
-  basetype = BINFO_TYPE (CLASSTYPE_PRIMARY_BINFO (t));
+  CLASSTYPE_PRIMARY_BINFO (t) = binfo;
+  basetype = BINFO_TYPE (binfo);
   TYPE_BINFO_VTABLE (t) = TYPE_BINFO_VTABLE (basetype);
   TYPE_BINFO_VIRTUALS (t) = TYPE_BINFO_VIRTUALS (basetype);
   TYPE_VFIELD (t) = TYPE_VFIELD (basetype);
@@ -1814,35 +1821,6 @@ set_primary_base (t, i, vfuns_p)
   *vfuns_p = CLASSTYPE_VSIZE (basetype);
 }
 
-/* Returns true iff BINFO (a direct virtual base of T) is an indirect
-   primary base.  */
-
-static int
-indirect_primary_base_p (t, binfo)
-     tree t;
-     tree binfo;
-{
-  int i;
-
-  for (i = 0; i < CLASSTYPE_N_BASECLASSES (t); ++i)
-    {
-      tree type;
-      tree b;
-
-      /* Figure out to which type the Ith base corresponds.  */
-      type = TYPE_BINFO_BASETYPE (t, i);
-      /* See if any of the primary bases have the same type as BINFO.  */
-      for (b = TYPE_BINFO (type); b; b = TREE_CHAIN (b))
-       /* If this base is primary, and has the same type as BINFO,
-          then BINFO is an indirect primary base.  */
-       if (BINFO_PRIMARY_MARKED_P (b)
-           && same_type_p (BINFO_TYPE (b), BINFO_TYPE (binfo)))
-         return 1;
-    }
-
-  return 0;
-}
-
 /* Determine the primary class for T.  */
 
 static void
@@ -1851,16 +1829,18 @@ determine_primary_base (t, vfuns_p)
      int *vfuns_p;
 {
   int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (t);
+  tree vbases;
+  tree type_binfo;
 
   /* If there are no baseclasses, there is certainly no primary base.  */
   if (n_baseclasses == 0)
     return;
 
-  *vfuns_p = 0;
+  type_binfo = TYPE_BINFO (t);
 
   for (i = 0; i < n_baseclasses; i++)
     {
-      tree base_binfo = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (t), i);
+      tree base_binfo = BINFO_BASETYPE (type_binfo, i);
       tree basetype = BINFO_TYPE (base_binfo);
 
       if (TYPE_CONTAINS_VPTR_P (basetype))
@@ -1879,7 +1859,7 @@ determine_primary_base (t, vfuns_p)
 
          if (!CLASSTYPE_HAS_PRIMARY_BASE_P (t))
            {
-             set_primary_base (t, i, vfuns_p);
+             set_primary_base (t, base_binfo, vfuns_p);
              CLASSTYPE_VFIELDS (t) = copy_list (CLASSTYPE_VFIELDS (basetype));
            }
          else
@@ -1898,60 +1878,93 @@ determine_primary_base (t, vfuns_p)
                                 CLASSTYPE_VFIELDS (t));
 
              if (!flag_new_abi && *vfuns_p == 0)
-               set_primary_base (t, i, vfuns_p);
+               set_primary_base (t, base_binfo, vfuns_p);
            }
        }
     }
 
   if (!TYPE_VFIELD (t))
-    CLASSTYPE_VFIELD_PARENT (t) = -1;
+    CLASSTYPE_PRIMARY_BINFO (t) = NULL_TREE;
+
+  /* Mark the indirect primary bases.  */
+  for (vbases = CLASSTYPE_VBASECLASSES (t);
+       vbases;
+       vbases = TREE_CHAIN (vbases)) 
+    {
+      tree binfo = TREE_VALUE (vbases);
+
+      /* See if this virtual base is an indirect primary base.  If so,
+        it must be either a primary base or an indirect primary base
+        in one of the direct bases.  */
+      for (i = 0; i < n_baseclasses; ++i) 
+       {
+         tree basetype;
+         tree v;
+
+         basetype = TYPE_BINFO_BASETYPE (t, i);
+         for (v = CLASSTYPE_VBASECLASSES (basetype); 
+              v; 
+              v = TREE_CHAIN (v))
+           {
+             tree b = TREE_VALUE (v);
+             if ((BINFO_PRIMARY_MARKED_P (b)
+                  || BINFO_INDIRECT_PRIMARY_P (b))
+                 && same_type_p (BINFO_TYPE (b), BINFO_TYPE (binfo)))
+               {
+                 BINFO_INDIRECT_PRIMARY_P (binfo) = 1;
+                 break;
+               }
+           }
+
+         /* If we've discovered that this virtual base is an indirect
+            primary base, then we can move on to the next virtual
+            base.  */
+         if (BINFO_INDIRECT_PRIMARY_P (binfo))
+           break;
+       }
+    }
 
   /* The new ABI allows for the use of a "nearly-empty" virtual base
      class as the primary base class if no non-virtual polymorphic
      base can be found.  */
   if (flag_new_abi && !CLASSTYPE_HAS_PRIMARY_BASE_P (t))
     {
-      /* If not -1, this is the index in TYPE_BINFO_BASETYPEs of the
-        best primary base candidate we have found so far.  */
-      int candidate = -1;
+      /* If not NULL, this is the best primary base candidate we have
+         found so far.  */
+      tree candidate = NULL_TREE;
+      tree base_binfo;
 
       /* Loop over the baseclasses.  */
-      for (i = 0; i < n_baseclasses; ++i)
+      for (base_binfo = TYPE_BINFO (t);
+          base_binfo;
+          base_binfo = TREE_CHAIN (base_binfo))
        {
-         tree base_binfo = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (t), i);
          tree basetype = BINFO_TYPE (base_binfo);
 
          if (TREE_VIA_VIRTUAL (base_binfo) 
              && CLASSTYPE_NEARLY_EMPTY_P (basetype))
            {
-             int indirect_primary_p;
-
-             /* Figure out whether or not this base is an indirect
-                primary base.  */
-             indirect_primary_p = indirect_primary_base_p (t, base_binfo);
-
              /* If this is not an indirect primary base, then it's
                 definitely our primary base.  */
-             if (!indirect_primary_p) 
+             if (!BINFO_INDIRECT_PRIMARY_P (base_binfo))
                {
-                 candidate = i;
+                 candidate = base_binfo;
                  break;
                }
              /* If this was an indirect primary base, it's still our
                 primary base -- unless there's another nearly-empty
                 virtual base that isn't an indirect primary base.  */
-             else if (candidate == -1)
-               candidate = i;
+             else if (!candidate)
+               candidate = base_binfo;
            }
        }
 
       /* If we've got a primary base, use it.  */
-      if (candidate != -1) 
+      if (candidate)
        {
          set_primary_base (t, candidate, vfuns_p);
          CLASSTYPE_VFIELDS (t) 
-           = copy_list (CLASSTYPE_VFIELDS (TYPE_BINFO_BASETYPE (t, 
-                                                                candidate)));
+           = copy_list (CLASSTYPE_VFIELDS (BINFO_TYPE (candidate)));
        }       
     }
 
@@ -2338,7 +2351,7 @@ duplicate_tag_error (t)
       tree template_info = CLASSTYPE_TEMPLATE_INFO (t);
       int use_template = CLASSTYPE_USE_TEMPLATE (t);
 
-      bzero ((char *) TYPE_LANG_SPECIFIC (t), sizeof (struct lang_type));
+      memset ((char *) TYPE_LANG_SPECIFIC (t), 0, sizeof (struct lang_type));
       BINFO_BASETYPES(binfo) = NULL_TREE;
 
       TYPE_BINFO (t) = binfo;
@@ -2453,9 +2466,11 @@ dfs_find_final_overrider (binfo, data)
       tree path;
       tree method;
 
+      /* We haven't found an overrider yet.  */
+      method = NULL_TREE;
       /* We've found a path to the declaring base.  Walk down the path
         looking for an overrider for FN.  */
-      for (path = reverse_path (binfo); 
+      for (path = reverse_path (binfo);
           path; 
           path = TREE_CHAIN (path))
        {
@@ -2474,6 +2489,25 @@ dfs_find_final_overrider (binfo, data)
         the base from which it came.  */
       if (path)
        {
+         tree base;
+
+         /* Assume the path is non-virtual.  See if there are any
+            virtual bases from (but not including) the overrider up
+            to and including the base where the function is
+            defined. */
+         for (base = TREE_CHAIN (path); base; base = TREE_CHAIN (base))
+           if (TREE_VIA_VIRTUAL (TREE_VALUE (base)))
+             {
+               base = ffod->declaring_base;
+               while (BINFO_PRIMARY_MARKED_P (base))
+                 {
+                   BINFO_OVERRIDE_ALONG_VIRTUAL_PATH_P (base) = 1;
+                   base = BINFO_INHERITANCE_CHAIN (base);
+                 }
+               BINFO_OVERRIDE_ALONG_VIRTUAL_PATH_P (base) = 1;
+               break;
+             }
+
          if (ffod->overriding_fn && ffod->overriding_fn != method)
            {
              /* We've found a different overrider along a different
@@ -2570,18 +2604,6 @@ find_final_overrider (t, binfo, fn)
   return build_tree_list (ffod.overriding_fn, ffod.overriding_base);
 }
 
-/* Called via dfs_walk.  Returns BINFO if BINFO has the same type as
-   DATA (which is really an _TYPE node).  */
-
-static tree
-dfs_find_base (binfo, data)
-     tree binfo;
-     void *data;
-{
-  return (same_type_p (BINFO_TYPE (binfo), (tree) data)
-         ? binfo : NULL_TREE);
-}
-
 /* Update a entry in the vtable for BINFO, which is in the hierarchy
    dominated by T.  FN has been overridden in BINFO; VIRTUALS points
    to the corresponding position in the BINFO_VIRTUALS list.  */
@@ -2595,26 +2617,36 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals)
 {
   tree b;
   tree overrider;
-  tree vindex;
   tree delta;
-  HOST_WIDE_INT vindex_val;
-  HOST_WIDE_INT i;
+  tree virtual_base;
+  int generate_thunk_with_vtable_p;
 
   /* Find the function which originally caused this vtable
      entry to be present.  */
-  vindex = DECL_VINDEX (fn);
-  b = dfs_walk (binfo, dfs_find_base, NULL, DECL_VIRTUAL_CONTEXT (fn));
-  fn = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (b)));
-  i = first_vfun_index (BINFO_TYPE (b));
-  vindex_val = tree_low_cst (vindex, 0);
-  while (i < vindex_val)
+  b = binfo;
+  while (1)
     {
-      fn = TREE_CHAIN (fn);
-      ++i;
+      tree primary_base;
+      tree f;
+
+      primary_base = get_primary_binfo (b);
+      if (!primary_base)
+       break;
+
+      for (f = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (primary_base)));
+          f;
+          f = TREE_CHAIN (f))
+       if (same_signature_p (BV_FN (f), fn))
+         break;
+
+      if (!f)
+       break;
+
+      fn = BV_FN (f);
+      b = primary_base;
     }
-  fn = BV_FN (fn);
 
-  /* Handle the case of a virtual function defined in BINFO itself.  */
+  /* Find the final overrider.  */
   overrider = find_final_overrider (t, b, fn);
   if (overrider == error_mark_node)
     return;
@@ -2626,27 +2658,54 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals)
                      get_derived_offset (binfo,
                                          DECL_VIRTUAL_CONTEXT (fn)),
                      BINFO_OFFSET (binfo));
+
+  /* Assume that we will produce a thunk that convert all the way to
+     the final overrider, and not to an intermediate virtual base.  */
+  virtual_base = NULL_TREE;
+
+  /* Assume that we will always generate thunks with the vtables that
+     reference them.  */
+  generate_thunk_with_vtable_p = 1;
+
+  /* Under the new ABI, we will convert to an intermediate virtual
+     base first, and then use the vcall offset located there to finish
+     the conversion.  */
   if (flag_new_abi)
     {
-      /* Under the new ABI, we only need to adjust as far as the
-        nearest virtual base.  Then we use the vcall offset in the
-        virtual bases vtable.  */
-      for (b = binfo; b; b = BINFO_INHERITANCE_CHAIN (b))
+      while (b)
        {
-         if (TREE_VIA_VIRTUAL (b))
-           break;
+         /* If we find BINFO, then the final overrider is in a class
+            derived from BINFO, so the thunks can be generated with
+            the final overrider.  */
+         if (!virtual_base
+             && same_type_p (BINFO_TYPE (b), BINFO_TYPE (binfo)))
+           generate_thunk_with_vtable_p = 0;
+
+         /* If we find the final overrider, then we can stop
+            walking.  */
          if (same_type_p (BINFO_TYPE (b), 
                           BINFO_TYPE (TREE_VALUE (overrider))))
            break;
+
+         /* If we find a virtual base, and we haven't yet found the
+            overrider, then there is a virtual base between the
+            declaring base and the final overrider.  */
+         if (!virtual_base && TREE_VIA_VIRTUAL (b))
+           {
+             generate_thunk_with_vtable_p = 1;
+             virtual_base = b;
+           }
+
+         b = BINFO_INHERITANCE_CHAIN (b);
        }
     }
   else
-    b = NULL_TREE;
+    virtual_base = NULL_TREE;
 
-  if (b && TREE_VIA_VIRTUAL (b))
+  if (virtual_base)
     /* The `this' pointer needs to be adjusted to the nearest virtual
        base.  */
-    delta = size_diffop (BINFO_OFFSET (b), delta);
+    delta = size_diffop (BINFO_OFFSET (virtual_base), delta);
   else
     /* The `this' pointer needs to be adjusted from pointing to
        BINFO to pointing at the base where the final overrider
@@ -2658,6 +2717,11 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals)
                       TREE_PURPOSE (overrider),
                       delta,
                       virtuals);
+
+  if (virtual_base)
+    BV_USE_VCALL_INDEX_P (*virtuals) = 1;
+  if (generate_thunk_with_vtable_p)
+    BV_GENERATE_THUNK_WITH_VTABLE_P (*virtuals) = 1;
 }
 
 /* Called from modify_all_vtables via dfs_walk.  */
@@ -2846,56 +2910,24 @@ static void
 check_for_override (decl, ctype)
      tree decl, ctype;
 {
-  tree binfos = BINFO_BASETYPES (TYPE_BINFO (ctype));
-  int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-  int virtualp = DECL_VIRTUAL_P (decl);
-  int found_overriden_fn = 0;
+  if (TREE_CODE (decl) == TEMPLATE_DECL)
+    /* In [temp.mem] we have:
 
-  for (i = 0; i < n_baselinks; i++)
+         A specialization of a member function template does not
+         override a virtual function from a base class.  */
+    return;
+  if ((DECL_DESTRUCTOR_P (decl)
+       || IDENTIFIER_VIRTUAL_P (DECL_NAME (decl)))
+      && look_for_overrides (ctype, decl)
+      && !DECL_STATIC_FUNCTION_P (decl))
     {
-      tree base_binfo = TREE_VEC_ELT (binfos, i);
-      if (TYPE_POLYMORPHIC_P (BINFO_TYPE (base_binfo)))
-       {
-         tree tmp = get_matching_virtual
-           (base_binfo, decl, DECL_DESTRUCTOR_P (decl));
-
-         if (tmp && !found_overriden_fn)
-           {
-             /* If this function overrides some virtual in some base
-                class, then the function itself is also necessarily
-                virtual, even if the user didn't explicitly say so.  */
-             DECL_VIRTUAL_P (decl) = 1;
-
-             /* The TMP we really want is the one from the deepest
-                baseclass on this path, taking care not to
-                duplicate if we have already found it (via another
-                path to its virtual baseclass.  */
-             if (TREE_CODE (TREE_TYPE (decl)) == FUNCTION_TYPE)
-               {
-                 cp_error_at ("`static %#D' cannot be declared", decl);
-                 cp_error_at ("  since `virtual %#D' declared in base class",
-                              tmp);
-                 break;
-               }
-             virtualp = 1;
-
-             /* Set DECL_VINDEX to a value that is neither an
-                INTEGER_CST nor the error_mark_node so that
-                add_virtual_function will realize this is an
-                overridden function.  */
-             DECL_VINDEX (decl) 
-               = tree_cons (tmp, NULL_TREE, DECL_VINDEX (decl));
-             
-             /* We now know that DECL overrides something,
-                which is all that is important.  But, we must
-                continue to iterate through all the base-classes
-                in order to allow get_matching_virtual to check for
-                various illegal overrides.  */
-             found_overriden_fn = 1;
-           }
-       }
+      /* Set DECL_VINDEX to a value that is neither an
+        INTEGER_CST nor the error_mark_node so that
+        add_virtual_function will realize this is an
+        overriding function.  */
+      DECL_VINDEX (decl) = decl;
     }
-  if (virtualp)
+  if (DECL_VIRTUAL_P (decl))
     {
       if (DECL_VINDEX (decl) == NULL_TREE)
        DECL_VINDEX (decl) = error_mark_node;
@@ -3099,7 +3131,7 @@ add_implicitly_declared_members (t, cant_have_default_ctor,
   /* Now, hook all of the new functions on to TYPE_METHODS,
      and add them to the CLASSTYPE_METHOD_VEC.  */
   for (f = &implicit_fns; *f; f = &TREE_CHAIN (*f))
-    add_method (t, 0, *f);
+    add_method (t, *f, /*error_p=*/0);
   *f = TYPE_METHODS (t);
   TYPE_METHODS (t) = implicit_fns;
 
@@ -3505,12 +3537,7 @@ check_field_decls (t, access_decls, empty_p,
          TYPE_HAS_COMPLEX_ASSIGN_REF (t) = 1;
 
          if (! TYPE_HAS_CONSTRUCTOR (t) && extra_warnings)
-           {
-             if (DECL_NAME (x))
-               cp_warning_at ("non-static reference `%#D' in class without a constructor", x);
-             else
-               cp_warning_at ("non-static reference in class without a constructor", x);
-           }
+            cp_warning_at ("non-static reference `%#D' in class without a constructor", x);
        }
 
       type = strip_array_types (type);
@@ -3542,12 +3569,7 @@ check_field_decls (t, access_decls, empty_p,
          TYPE_HAS_COMPLEX_ASSIGN_REF (t) = 1;
 
          if (! TYPE_HAS_CONSTRUCTOR (t) && extra_warnings)
-           {
-             if (DECL_NAME (x))
-               cp_warning_at ("non-static const member `%#D' in class without a constructor", x);
-             else
-               cp_warning_at ("non-static const member in class without a constructor", x);
-           }
+            cp_warning_at ("non-static const member `%#D' in class without a constructor", x);
        }
       /* A field that is pseudo-const makes the structure likewise.  */
       else if (IS_AGGR_TYPE (type))
@@ -3638,116 +3660,208 @@ build_vtbl_or_vbase_field (name, assembler_name, type, class_type, fcontext,
   return field;
 }
 
-/* Record the type of BINFO in the slot in DATA (which is really a
-   `varray_type *') corresponding to the BINFO_OFFSET.  */
+/* If TYPE is an empty class type, records its OFFSET in the table of
+   OFFSETS.  */
 
-static tree
-dfs_record_base_offsets (binfo, data)
-     tree binfo;
-     void *data;
+static int
+record_subobject_offset (type, offset, offsets)
+     tree type;
+     tree offset;
+     splay_tree offsets;
 {
-  varray_type *v;
-  unsigned HOST_WIDE_INT offset = tree_low_cst (BINFO_OFFSET (binfo), 1);
+  splay_tree_node n;
+
+  if (!is_empty_class (type))
+    return 0;
 
-  v = (varray_type *) data;
-  while (VARRAY_SIZE (*v) <= offset)
-    VARRAY_GROW (*v, 2 * VARRAY_SIZE (*v));
-  VARRAY_TREE (*v, offset) = tree_cons (NULL_TREE,
-                                       BINFO_TYPE (binfo),
-                                       VARRAY_TREE (*v, offset));
+  /* Record the location of this empty object in OFFSETS.  */
+  n = splay_tree_lookup (offsets, (splay_tree_key) offset);
+  if (!n)
+    n = splay_tree_insert (offsets, 
+                          (splay_tree_key) offset,
+                          (splay_tree_value) NULL_TREE);
+  n->value = ((splay_tree_value) 
+             tree_cons (NULL_TREE,
+                        type,
+                        (tree) n->value));
 
-  return NULL_TREE;
+  return 0;
 }
 
-/* Add the offset of BINFO and its bases to BASE_OFFSETS.  */
+/* Returns non-zero if TYPE is an empty class type and there is
+   already an entry in OFFSETS for the same TYPE as the same OFFSET.  */
 
-static void
-record_base_offsets (binfo, base_offsets)
-     tree binfo;
-     varray_type *base_offsets;
+static int
+check_subobject_offset (type, offset, offsets)
+     tree type;
+     tree offset;
+     splay_tree offsets;
 {
-  dfs_walk (binfo,
-           dfs_record_base_offsets,
-           dfs_skip_vbases,
-           base_offsets);
+  splay_tree_node n;
+  tree t;
+
+  if (!is_empty_class (type))
+    return 0;
+
+  /* Record the location of this empty object in OFFSETS.  */
+  n = splay_tree_lookup (offsets, (splay_tree_key) offset);
+  if (!n)
+    return 0;
+
+  for (t = (tree) n->value; t; t = TREE_CHAIN (t))
+    if (same_type_p (TREE_VALUE (t), type))
+      return 1;
+
+  return 0;
 }
 
-/* Returns non-NULL if there is already an entry in DATA (which is
-   really a `varray_type') indicating that an object with the same
-   type of BINFO is already at the BINFO_OFFSET for BINFO.  */
+/* Walk through all the subobjects of TYPE (located at OFFSET).  Call
+   F for every subobject, passing it the type, offset, and table of
+   OFFSETS.  If VBASES_P is non-zero, then even non-virtual primary
+   bases should be traversed; otherwise, they are ignored.  If F
+   returns a non-zero value, the traversal ceases, and that value is
+   returned.  Otherwise, returns zero.  */
 
-static tree
-dfs_search_base_offsets (binfo, data)
-     tree binfo;
-     void *data;
+static int
+walk_subobject_offsets (type, f, offset, offsets, vbases_p)
+     tree type;
+     subobject_offset_fn f;
+     tree offset;
+     splay_tree offsets;
+     int vbases_p;
 {
-  if (is_empty_class (BINFO_TYPE (binfo)))
+  int r = 0;
+
+  if (CLASS_TYPE_P (type))
     {
-      varray_type v = (varray_type) data;
-      /* Find the offset for this BINFO.  */
-      unsigned HOST_WIDE_INT offset = tree_low_cst (BINFO_OFFSET (binfo), 1);
-      tree t;
+      tree field;
+      int i;
 
-      /* If we haven't yet encountered any objects at offsets that
-        big, then there's no conflict.  */
-      if (VARRAY_SIZE (v) <= offset)
-       return NULL_TREE;
-      /* Otherwise, go through the objects already allocated at this
-        offset.  */
-      for (t = VARRAY_TREE (v, offset); t; t = TREE_CHAIN (t))
-       if (same_type_p (TREE_VALUE (t), BINFO_TYPE (binfo)))
-         return binfo;
+      /* Record the location of TYPE.  */
+      r = (*f) (type, offset, offsets);
+      if (r)
+       return r;
+
+      /* Iterate through the direct base classes of TYPE.  */
+      for (i = 0; i < CLASSTYPE_N_BASECLASSES (type); ++i)
+       {
+         tree binfo = BINFO_BASETYPE (TYPE_BINFO (type), i);
+
+         if (!vbases_p 
+             && TREE_VIA_VIRTUAL (binfo) 
+             && !BINFO_PRIMARY_MARKED_P (binfo))
+           continue;
+
+         r = walk_subobject_offsets (BINFO_TYPE (binfo),
+                                     f,
+                                     size_binop (PLUS_EXPR,
+                                                 offset,
+                                                 BINFO_OFFSET (binfo)),
+                                     offsets,
+                                     vbases_p);
+         if (r)
+           return r;
+       }
+
+      /* Iterate through the fields of TYPE.  */
+      for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+       if (TREE_CODE (field) == FIELD_DECL)
+         {
+           r = walk_subobject_offsets (TREE_TYPE (field),
+                                       f,
+                                       size_binop (PLUS_EXPR,
+                                                   offset,
+                                                   DECL_FIELD_OFFSET (field)),
+                                       offsets,
+                                       /*vbases_p=*/1);
+           if (r)
+             return r;
+         }
     }
+  else if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      tree domain = TYPE_DOMAIN (type);
+      tree index;
 
-  return NULL_TREE;
+      /* Step through each of the elements in the array.  */
+      for (index = size_zero_node; 
+          INT_CST_LT (index, TYPE_MAX_VALUE (domain));
+          index = size_binop (PLUS_EXPR, index, size_one_node))
+       {
+         r = walk_subobject_offsets (TREE_TYPE (type),
+                                     f,
+                                     offset,
+                                     offsets,
+                                     /*vbases_p=*/1);
+         if (r)
+           return r;
+         offset = size_binop (PLUS_EXPR, offset, 
+                              TYPE_SIZE_UNIT (TREE_TYPE (type)));
+       }
+    }
+
+  return 0;
+}
+
+/* Record all of the empty subobjects of TYPE (located at OFFSET) in
+   OFFSETS.  If VBASES_P is non-zero, virtual bases of TYPE are
+   examined.  */
+
+static void
+record_subobject_offsets (type, offset, offsets, vbases_p)
+     tree type;
+     tree offset;
+     splay_tree offsets;
+     int vbases_p;
+{
+  walk_subobject_offsets (type, record_subobject_offset, offset,
+                         offsets, vbases_p);
 }
 
-/* Returns non-zero if there's a conflict between BINFO and a base
-   already mentioned in BASE_OFFSETS if BINFO is placed at its current
-   BINFO_OFFSET.  */
+/* Returns non-zero if any of the empty subobjects of TYPE (located at
+   OFFSET) conflict with entries in OFFSETS.  If VBASES_P is non-zero,
+   virtual bases of TYPE are examined.  */
 
 static int
-layout_conflict_p (binfo, base_offsets)
-     tree binfo;
-     varray_type base_offsets;
+layout_conflict_p (type, offset, offsets, vbases_p)
+     tree type;
+     tree offset;
+     splay_tree offsets;
+     int vbases_p;
 {
-  return dfs_walk (binfo, dfs_search_base_offsets, dfs_skip_vbases,
-                  base_offsets) != NULL_TREE;
+  return walk_subobject_offsets (type, check_subobject_offset, offset,
+                                offsets, vbases_p);
 }
 
 /* DECL is a FIELD_DECL corresponding either to a base subobject of a
    non-static data member of the type indicated by RLI.  BINFO is the
-   binfo corresponding to the base subobject, or, if this is a
-   non-static data-member, a dummy BINFO for the type of the data
-   member.  BINFO may be NULL if checks to see if the field overlaps
-   an existing field with the same type are not required.  V maps
-   offsets to types already located at those offsets.  This function
-   determines the position of the DECL.  */
+   binfo corresponding to the base subobject, OFFSETS maps offsets to
+   types already located at those offsets.  This function determines
+   the position of the DECL.  */
 
 static void
-layout_nonempty_base_or_field (rli, decl, binfo, v)
+layout_nonempty_base_or_field (rli, decl, binfo, offsets)
      record_layout_info rli;
      tree decl;
      tree binfo;
-     varray_type v;
+     splay_tree offsets;
 {
+  tree offset = NULL_TREE;
+  tree type = TREE_TYPE (decl);
+  /* If we are laying out a base class, rather than a field, then
+     DECL_ARTIFICIAL will be set on the FIELD_DECL.  */
+  int field_p = !DECL_ARTIFICIAL (decl);
+
   /* Try to place the field.  It may take more than one try if we have
      a hard time placing the field without putting two objects of the
      same type at the same address.  */
   while (1)
     {
-      tree offset;
       struct record_layout_info_s old_rli = *rli;
 
       /* Place this field.  */
       place_field (rli, decl);
-      
-      /* Now that we know where it wil be placed, update its
-        BINFO_OFFSET.  */
       offset = byte_position (decl);
-      if (binfo)
-       propagate_binfo_offsets (binfo, 
-                                convert (ssizetype, offset));
  
       /* We have to check to see whether or not there is already
         something of the same type at the offset we're about to use.
@@ -3764,40 +3878,46 @@ layout_nonempty_base_or_field (rli, decl, binfo, v)
         empty class, have non-zero size, any overlap can happen only
         with a direct or indirect base-class -- it can't happen with
         a data member.  */
-      if (binfo && flag_new_abi && layout_conflict_p (binfo, v))
+      if (flag_new_abi && layout_conflict_p (TREE_TYPE (decl),
+                                            offset,
+                                            offsets, 
+                                            field_p))
        {
-         /* Undo the propagate_binfo_offsets call.  */
-         offset = size_diffop (size_zero_node, offset);
-         propagate_binfo_offsets (binfo, convert (ssizetype, offset));
-        
          /* Strip off the size allocated to this field.  That puts us
             at the first place we could have put the field with
             proper alignment.  */
          *rli = old_rli;
 
-         /* Bump up by the alignment required for the type, without
-            virtual base classes.  */
+         /* Bump up by the alignment required for the type.  */
          rli->bitpos
-           = size_binop (PLUS_EXPR, rli->bitpos,
-                         bitsize_int (CLASSTYPE_ALIGN (BINFO_TYPE (binfo))));
+           = size_binop (PLUS_EXPR, rli->bitpos, 
+                         bitsize_int (binfo 
+                                      ? CLASSTYPE_ALIGN (type)
+                                      : TYPE_ALIGN (type)));
          normalize_rli (rli);
        }
       else
        /* There was no conflict.  We're done laying out this field.  */
        break;
     }
+
+  /* Now that we know where it wil be placed, update its
+     BINFO_OFFSET.  */
+  if (binfo && CLASS_TYPE_P (BINFO_TYPE (binfo)))
+    propagate_binfo_offsets (binfo, 
+                            convert (ssizetype, offset));
 }
 
 /* Layout the empty base BINFO.  EOC indicates the byte currently just
    past the end of the class, and should be correctly aligned for a
-   class of the type indicated by BINFO; BINFO_OFFSETS gives the
-   offsets of the other bases allocated so far.  */
+   class of the type indicated by BINFO; OFFSETS gives the offsets of
+   the empty bases allocated so far.  */
 
 static void
-layout_empty_base (binfo, eoc, binfo_offsets)
+layout_empty_base (binfo, eoc, offsets)
      tree binfo;
      tree eoc;
-     varray_type binfo_offsets;
+     splay_tree offsets;
 {
   tree alignment;
   tree basetype = BINFO_TYPE (binfo);
@@ -3808,14 +3928,20 @@ layout_empty_base (binfo, eoc, binfo_offsets)
 
   /* This is an empty base class.  We first try to put it at offset
      zero.  */
-  if (layout_conflict_p (binfo, binfo_offsets))
+  if (layout_conflict_p (BINFO_TYPE (binfo),
+                        BINFO_OFFSET (binfo),
+                        offsets, 
+                        /*vbases_p=*/0))
     {
       /* That didn't work.  Now, we move forward from the next
         available spot in the class.  */
       propagate_binfo_offsets (binfo, convert (ssizetype, eoc));
       while (1) 
        {
-         if (!layout_conflict_p (binfo, binfo_offsets))
+         if (!layout_conflict_p (BINFO_TYPE (binfo),
+                                 BINFO_OFFSET (binfo), 
+                                 offsets,
+                                 /*vbases_p=*/0))
            /* We finally found a spot where there's no overlap.  */
            break;
 
@@ -3828,15 +3954,15 @@ layout_empty_base (binfo, eoc, binfo_offsets)
 /* Build a FIELD_DECL for the base given by BINFO in the class
    indicated by RLI.  If the new object is non-empty, clear *EMPTY_P.
    *BASE_ALIGN is a running maximum of the alignments of any base
-   class.  */
+   class.  OFFSETS gives the location of empty base subobjects.  */
 
 static void
-build_base_field (rli, binfo, empty_p, base_align, v)
+build_base_field (rli, binfo, empty_p, base_align, offsets)
      record_layout_info rli;
      tree binfo;
      int *empty_p;
      unsigned int *base_align;
-     varray_type *v;
+     splay_tree offsets;
 {
   tree basetype = BINFO_TYPE (binfo);
   tree decl;
@@ -3877,7 +4003,7 @@ build_base_field (rli, binfo, empty_p, base_align, v)
       /* Try to place the field.  It may take more than one try if we
         have a hard time placing the field without putting two
         objects of the same type at the same address.  */
-      layout_nonempty_base_or_field (rli, decl, binfo, *v);
+      layout_nonempty_base_or_field (rli, decl, binfo, offsets);
     }
   else
     {
@@ -3886,8 +4012,8 @@ build_base_field (rli, binfo, empty_p, base_align, v)
       /* On some platforms (ARM), even empty classes will not be
         byte-aligned.  */
       eoc = tree_low_cst (rli_size_unit_so_far (rli), 0);
-      eoc = CEIL (eoc, DECL_ALIGN (decl)) * DECL_ALIGN (decl);
-      layout_empty_base (binfo, size_int (eoc), *v);
+      eoc = CEIL (eoc, DECL_ALIGN_UNIT (decl)) * DECL_ALIGN_UNIT (decl);
+      layout_empty_base (binfo, size_int (eoc), offsets);
     }
 
   /* Check for inaccessible base classes.  If the same base class
@@ -3898,46 +4024,46 @@ build_base_field (rli, binfo, empty_p, base_align, v)
                basetype, rli->t);
   
   /* Record the offsets of BINFO and its base subobjects.  */
-  record_base_offsets (binfo, v);
+  record_subobject_offsets (BINFO_TYPE (binfo), 
+                           BINFO_OFFSET (binfo),
+                           offsets, 
+                           /*vbases_p=*/0);
 }
 
-/* Layout all of the non-virtual base classes.  Returns a map from
-   offsets to types present at those offsets.  */
+/* Layout all of the non-virtual base classes.  Record empty
+   subobjects in OFFSETS.  */
 
-static varray_type
-build_base_fields (rli, empty_p)
+static void
+build_base_fields (rli, empty_p, offsets)
      record_layout_info rli;
      int *empty_p;
+     splay_tree offsets;
 {
   /* Chain to hold all the new FIELD_DECLs which stand in for base class
      subobjects.  */
   tree rec = rli->t;
   int n_baseclasses = CLASSTYPE_N_BASECLASSES (rec);
   int i;
-  varray_type v;
   unsigned int base_align = 0;
 
-  /* Create the table mapping offsets to empty base classes.  */
-  VARRAY_TREE_INIT (v, 32, "v");
-
   /* Under the new ABI, the primary base class is always allocated
      first.  */
   if (flag_new_abi && CLASSTYPE_HAS_PRIMARY_BASE_P (rec))
     build_base_field (rli, CLASSTYPE_PRIMARY_BINFO (rec), 
-                     empty_p, &base_align, &v);
+                     empty_p, &base_align, offsets);
 
   /* Now allocate the rest of the bases.  */
   for (i = 0; i < n_baseclasses; ++i)
     {
       tree base_binfo;
 
+      base_binfo = BINFO_BASETYPE (TYPE_BINFO (rec), i);
+
       /* Under the new ABI, the primary base was already allocated
         above, so we don't need to allocate it again here.  */
-      if (flag_new_abi && i == CLASSTYPE_VFIELD_PARENT (rec))
+      if (flag_new_abi && base_binfo == CLASSTYPE_PRIMARY_BINFO (rec))
        continue;
 
-      base_binfo = BINFO_BASETYPE (TYPE_BINFO (rec), i);
-
       /* A primary virtual base class is allocated just like any other
         base class, but a non-primary virtual base is allocated
         later, in layout_virtual_bases.  */
@@ -3945,10 +4071,8 @@ build_base_fields (rli, empty_p)
          && !BINFO_PRIMARY_MARKED_P (base_binfo))
        continue;
 
-      build_base_field (rli, base_binfo, empty_p, &base_align, &v);
+      build_base_field (rli, base_binfo, empty_p, &base_align, offsets);
     }
-
-  return v;
 }
 
 /* Go through the TYPE_METHODS of T issuing any appropriate
@@ -4150,16 +4274,22 @@ clone_function_decl (fn, update_method_vec_p)
 {
   tree clone;
 
+  /* Avoid inappropriate cloning.  */
+  if (! flag_new_abi
+      || (TREE_CHAIN (fn)
+         && DECL_CLONED_FUNCTION (TREE_CHAIN (fn))))
+    return;
+
   if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn))
     {
       /* For each constructor, we need two variants: an in-charge version
         and a not-in-charge version.  */
       clone = build_clone (fn, complete_ctor_identifier);
       if (update_method_vec_p)
-       add_method (DECL_CONTEXT (clone), NULL, clone);
+       add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
       clone = build_clone (fn, base_ctor_identifier);
       if (update_method_vec_p)
-       add_method (DECL_CONTEXT (clone), NULL, clone);
+       add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
     }
   else
     {
@@ -4173,13 +4303,13 @@ clone_function_decl (fn, update_method_vec_p)
         function table.  */
       clone = build_clone (fn, deleting_dtor_identifier);
       if (update_method_vec_p)
-       add_method (DECL_CONTEXT (clone), NULL, clone);
+       add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
       clone = build_clone (fn, complete_dtor_identifier);
       if (update_method_vec_p)
-       add_method (DECL_CONTEXT (clone), NULL, clone);
+       add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
       clone = build_clone (fn, base_dtor_identifier);
       if (update_method_vec_p)
-       add_method (DECL_CONTEXT (clone), NULL, clone);
+       add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
     }
 }
 
@@ -4391,15 +4521,12 @@ create_vtable_ptr (t, empty_p, vfuns_p,
    complete.  */
 
 static void
-fixup_pending_inline (info)
-     struct pending_inline *info;
+fixup_pending_inline (fn)
+     tree fn;
 {
-  if (info)
+  if (DECL_PENDING_INLINE_INFO (fn))
     {
-      tree args;
-      tree fn = info->fndecl;
-
-      args = DECL_ARGUMENTS (fn);
+      tree args = DECL_ARGUMENTS (fn);
       while (args)
        {
          DECL_CONTEXT (args) = fn;
@@ -4429,76 +4556,70 @@ fixup_inline_methods (type)
 
   /* Do inline member functions.  */
   for (; method; method = TREE_CHAIN (method))
-    fixup_pending_inline (DECL_PENDING_INLINE_INFO (method));
+    fixup_pending_inline (method);
 
   /* Do friends.  */
   for (method = CLASSTYPE_INLINE_FRIENDS (type); 
        method; 
        method = TREE_CHAIN (method))
-    fixup_pending_inline (DECL_PENDING_INLINE_INFO (TREE_VALUE (method)));
+    fixup_pending_inline (TREE_VALUE (method));
   CLASSTYPE_INLINE_FRIENDS (type) = NULL_TREE;
 }
 
-/* Called from propagate_binfo_offsets via dfs_walk.  */
-
-static tree
-dfs_propagate_binfo_offsets (binfo, data)
-     tree binfo; 
-     void *data;
-{
-  tree offset = (tree) data;
-
-  /* Update the BINFO_OFFSET for this base.  Allow for the case where it
-     might be negative.  */
-  BINFO_OFFSET (binfo)
-    = convert (sizetype, size_binop (PLUS_EXPR,
-                                    convert (ssizetype, BINFO_OFFSET (binfo)),
-                                             offset));
-  SET_BINFO_MARKED (binfo);
-
-  return NULL_TREE;
-}
-
 /* Add OFFSET to all base types of BINFO which is a base in the
    hierarchy dominated by T.
 
-   OFFSET, which is a type offset, is number of bytes.
-
-   Note that we don't have to worry about having two paths to the
-   same base type, since this type owns its association list.  */
+   OFFSET, which is a type offset, is number of bytes.  */
 
 static void
 propagate_binfo_offsets (binfo, offset)
      tree binfo;
      tree offset;
 {
-  dfs_walk (binfo, 
-           dfs_propagate_binfo_offsets, 
-           dfs_skip_nonprimary_vbases_unmarkedp,
-           offset);
-  dfs_walk (binfo,
-           dfs_unmark,
-           dfs_skip_nonprimary_vbases_markedp,
-           NULL);
-}
+  int i;
+  tree primary_binfo;
 
-/* Called via dfs_walk from layout_virtual bases.  */
+  /* Update BINFO's offset.  */
+  BINFO_OFFSET (binfo)
+    = convert (sizetype, 
+              size_binop (PLUS_EXPR,
+                          convert (ssizetype, BINFO_OFFSET (binfo)),
+                          offset));
 
-static tree
-dfs_set_offset_for_shared_vbases (binfo, data)
-     tree binfo;
-     void *data;
-{
-  if (TREE_VIA_VIRTUAL (binfo) && BINFO_PRIMARY_MARKED_P (binfo))
+  /* Find the primary base class.  */
+  primary_binfo = get_primary_binfo (binfo);
+
+  /* Scan all of the bases, pushing the BINFO_OFFSET adjust
+     downwards.  */
+  for (i = -1; i < BINFO_N_BASETYPES (binfo); ++i)
     {
-      /* Update the shared copy.  */
-      tree shared_binfo;
+      tree base_binfo;
 
-      shared_binfo = binfo_for_vbase (BINFO_TYPE (binfo), (tree) data);
-      BINFO_OFFSET (shared_binfo) = BINFO_OFFSET (binfo);
-    }
+      /* On the first through the loop, do the primary base.  Because
+        the primary base need not be an immediate base, we must
+        handle the primary base specially.  */
+      if (i == -1) 
+       {
+         if (!primary_binfo) 
+           continue;
 
-  return NULL_TREE;
+         base_binfo = primary_binfo;
+       }
+      else
+       {
+         base_binfo = BINFO_BASETYPE (binfo, i);
+         /* Don't do the primary base twice.  */
+         if (base_binfo == primary_binfo)
+           continue;
+       }
+
+      /* Skip virtual bases that aren't our primary base.  */
+      if (TREE_VIA_VIRTUAL (base_binfo)
+         && BINFO_PRIMARY_BASE_OF (base_binfo) != binfo)
+       continue;
+
+      propagate_binfo_offsets (base_binfo, offset);
+    }
 }
 
 /* Called via dfs_walk from layout_virtual bases.  */
@@ -4526,13 +4647,13 @@ dfs_set_offset_for_unshared_vbases (binfo, data)
 }
 
 /* Set BINFO_OFFSET for all of the virtual bases for T.  Update
-   TYPE_ALIGN and TYPE_SIZE for T.  BASE_OFFSETS is a varray mapping
-   offsets to the types at those offsets.  */
+   TYPE_ALIGN and TYPE_SIZE for T.  OFFSETS gives the location of
+   empty subobjects of T.  */
 
 static void
-layout_virtual_bases (t, base_offsets)
+layout_virtual_bases (t, offsets)
      tree t;
-     varray_type *base_offsets;
+     splay_tree offsets;
 {
   tree vbases;
   unsigned HOST_WIDE_INT dsize;
@@ -4575,7 +4696,7 @@ layout_virtual_bases (t, base_offsets)
       else
        vbase = TREE_VALUE (vbases);
 
-      if (!BINFO_VBASE_PRIMARY_P (vbase))
+      if (!BINFO_PRIMARY_MARKED_P (vbase))
        {
          /* This virtual base is not a primary base of any class in the
             hierarchy, so we have to add space for it.  */
@@ -4602,7 +4723,7 @@ layout_virtual_bases (t, base_offsets)
          if (flag_new_abi && is_empty_class (basetype))
            layout_empty_base (vbase,
                               size_int (CEIL (dsize, BITS_PER_UNIT)),
-                              *base_offsets);
+                              offsets);
          else
            {
              tree offset;
@@ -4622,20 +4743,14 @@ layout_virtual_bases (t, base_offsets)
            }
 
          /* Keep track of the offsets assigned to this virtual base.  */
-         record_base_offsets (vbase, base_offsets);
+         record_subobject_offsets (BINFO_TYPE (vbase), 
+                                   BINFO_OFFSET (vbase),
+                                   offsets,
+                                   /*vbases_p=*/0);
        }
     }
 
-  /* Make sure that all of the CLASSTYPE_VBASECLASSES have their
-     BINFO_OFFSET set correctly.  Those we just allocated certainly
-     will.  The others are primary baseclasses; we walk the hierarchy
-     to find the primary copies and update the shared copy.  */
-  dfs_walk (TYPE_BINFO (t), 
-           dfs_set_offset_for_shared_vbases, 
-           dfs_unmarked_real_bases_queue_p,
-           t);
-
-  /* Now, go through the TYPE_BINFO hierarchy again, setting the
+  /* Now, go through the TYPE_BINFO hierarchy, setting the
      BINFO_OFFSETs correctly for all non-primary copies of the virtual
      bases and their direct and indirect bases.  The ambiguity checks
      in get_base_distance depend on the BINFO_OFFSETs being set
@@ -4706,6 +4821,16 @@ end_of_class (t, include_virtuals_p)
   return result;
 }
 
+/* Compare two INTEGER_CSTs K1 and K2.  */
+
+static int
+splay_tree_compare_integer_csts (k1, k2)
+     splay_tree_key k1;
+     splay_tree_key k2;
+{
+  return tree_int_cst_compare ((tree) k1, (tree) k2);
+}
+
 /* Calculate the TYPE_SIZE, TYPE_ALIGN, etc for T.  Calculate
    BINFO_OFFSETs for all of the base-classes.  Position the vtable
    pointer.  */
@@ -4723,8 +4848,10 @@ layout_class_type (t, empty_p, vfuns_p,
   tree field;
   tree vptr;
   record_layout_info rli;
-  varray_type v;
   unsigned HOST_WIDE_INT eoc;
+  /* Maps offsets (represented as INTEGER_CSTs) to a TREE_LIST of
+     types that appear at that offset.  */
+  splay_tree empty_base_offsets;
 
   /* Keep track of the first non-static data member.  */
   non_static_data_members = TYPE_FIELDS (t);
@@ -4748,11 +4875,13 @@ layout_class_type (t, empty_p, vfuns_p,
       place_field (rli, vptr);
     }
 
+  /* Build FIELD_DECLs for all of the non-virtual base-types.  */
+  empty_base_offsets = splay_tree_new (splay_tree_compare_integer_csts, 
+                                      NULL, NULL);
+  build_base_fields (rli, empty_p, empty_base_offsets);
   /* Add pointers to all of our virtual base-classes.  */
   TYPE_FIELDS (t) = chainon (build_vbase_pointer_fields (rli, empty_p),
                             TYPE_FIELDS (t));
-  /* Build FIELD_DECLs for all of the non-virtual base-types.  */
-  v = build_base_fields (rli, empty_p);
 
   /* CLASSTYPE_INLINE_FRIENDS is really TYPE_NONCOPIED_PARTS.  Thus,
      we have to save this before we start modifying
@@ -4762,7 +4891,6 @@ layout_class_type (t, empty_p, vfuns_p,
   /* Layout the non-static data members.  */
   for (field = non_static_data_members; field; field = TREE_CHAIN (field))
     {
-      tree binfo;
       tree type;
       tree padding;
 
@@ -4814,10 +4942,8 @@ layout_class_type (t, empty_p, vfuns_p,
       else
        padding = NULL_TREE;
 
-      /* Create a dummy BINFO corresponding to this field.  */
-      binfo = make_binfo (size_zero_node, type, NULL_TREE, NULL_TREE);
-      unshare_base_binfos (binfo);
-      layout_nonempty_base_or_field (rli, field, binfo, v);
+      layout_nonempty_base_or_field (rli, field, NULL_TREE,
+                                    empty_base_offsets);
 
       /* If we needed additional padding after this field, add it
         now.  */
@@ -4832,7 +4958,9 @@ layout_class_type (t, empty_p, vfuns_p,
          DECL_SIZE (padding_field) = padding;
          DECL_ALIGN (padding_field) = 1;
          DECL_USER_ALIGN (padding_field) = 0;
-         layout_nonempty_base_or_field (rli, padding_field, NULL_TREE, v);
+         layout_nonempty_base_or_field (rli, padding_field,
+                                        NULL_TREE, 
+                                        empty_base_offsets);
        }
     }
 
@@ -4895,8 +5023,7 @@ layout_class_type (t, empty_p, vfuns_p,
       CLASSTYPE_SIZE (t) = bitsize_zero_node;
       CLASSTYPE_SIZE_UNIT (t) = size_zero_node;
     }
-  else if (flag_new_abi && TYPE_HAS_COMPLEX_INIT_REF (t)
-          && TYPE_HAS_COMPLEX_ASSIGN_REF (t))
+  else if (flag_new_abi)
     {
       CLASSTYPE_SIZE (t) = TYPE_BINFO_SIZE (t);
       CLASSTYPE_SIZE_UNIT (t) = TYPE_BINFO_SIZE_UNIT (t);
@@ -4919,10 +5046,10 @@ layout_class_type (t, empty_p, vfuns_p,
      around.  We must get these done before we try to lay out the
      virtual function table.  As a side-effect, this will remove the
      base subobject fields.  */
-  layout_virtual_bases (t, &v);
+  layout_virtual_bases (t, empty_base_offsets);
 
   /* Clean up.  */
-  VARRAY_FREE (v);
+  splay_tree_delete (empty_base_offsets);
 }
 
 /* Create a RECORD_TYPE or UNION_TYPE node for a C struct or union declaration
@@ -4987,7 +5114,7 @@ finish_struct_1 (t)
      make sure we lay it out again.  */
   TYPE_SIZE (t) = NULL_TREE;
   CLASSTYPE_GOT_SEMICOLON (t) = 0;
-  CLASSTYPE_VFIELD_PARENT (t) = -1;
+  CLASSTYPE_PRIMARY_BINFO (t) = NULL_TREE;
   vfuns = 0;
   CLASSTYPE_RTTI (t) = NULL_TREE;
 
@@ -5054,17 +5181,9 @@ finish_struct_1 (t)
     {
       tree binfo = CLASSTYPE_PRIMARY_BINFO (t);
 
-      /* This class contributes nothing new to the virtual function
-        table.  However, it may have declared functions which
-        went into the virtual function table "inherited" from the
-        base class.  If so, we grab a copy of those updated functions,
-        and pretend they are ours.  */
-
-      /* See if we should steal the virtual info from base class.  */
-      if (TYPE_BINFO_VTABLE (t) == NULL_TREE)
-       TYPE_BINFO_VTABLE (t) = BINFO_VTABLE (binfo);
-      if (TYPE_BINFO_VIRTUALS (t) == NULL_TREE)
-       TYPE_BINFO_VIRTUALS (t) = BINFO_VIRTUALS (binfo);
+      /* If this class uses a different vtable than its primary base
+        then when we will need to initialize our vptr after the base
+        class constructor runs.  */
       if (TYPE_BINFO_VTABLE (t) != BINFO_VTABLE (binfo))
        CLASSTYPE_NEEDS_VIRTUAL_REINIT (t) = 1;
     }
@@ -5167,7 +5286,7 @@ finish_struct_1 (t)
   maybe_suppress_debug_info (t);
 
   /* Finish debugging output for this type.  */
-  rest_of_type_compilation (t, toplevel_bindings_p ());
+  rest_of_type_compilation (t, ! LOCAL_CLASS_P (t));
 }
 
 /* When T was built up, the member declarations were added in reverse
@@ -5234,7 +5353,7 @@ finish_struct (t, attributes)
     {
       tree scope = current_scope ();
       if (scope && TREE_CODE (scope) == FUNCTION_DECL)
-       add_tree (build_min (TAG_DEFN, t));
+       add_stmt (build_min (TAG_DEFN, t));
     }
 
   return t;
@@ -5392,6 +5511,10 @@ init_class_processing ()
   access_public_virtual_node = build_int_2 (4 | ak_public, 0);
   access_protected_virtual_node = build_int_2 (4 | ak_protected, 0);
   access_private_virtual_node = build_int_2 (4 | ak_private, 0);
+
+  ridpointers[(int) RID_PUBLIC] = access_public_node;
+  ridpointers[(int) RID_PRIVATE] = access_private_node;
+  ridpointers[(int) RID_PROTECTED] = access_protected_node;
 }
 
 /* Set current scope to NAME. CODE tells us if this is a
@@ -5480,11 +5603,6 @@ pushclass (type, modify)
 
   pushlevel_class ();
 
-#if 0
-  if (CLASSTYPE_TEMPLATE_INFO (type))
-    overload_template_name (type);
-#endif
-
   if (modify)
     {
       if (type != previous_class_type || current_class_depth > 1)
@@ -5610,7 +5728,7 @@ push_nested_class (type, modify)
       || TREE_CODE (type) == NAMESPACE_DECL
       || ! IS_AGGR_TYPE (type)
       || TREE_CODE (type) == TEMPLATE_TYPE_PARM
-      || TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM)
+      || TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM)
     return;
   
   context = DECL_CONTEXT (TYPE_MAIN_DECL (type));
@@ -5651,29 +5769,26 @@ push_lang_context (name)
 
   if (name == lang_name_cplusplus)
     {
-      strict_prototype = strict_prototypes_lang_cplusplus;
       current_lang_name = name;
     }
   else if (name == lang_name_java)
     {
-      strict_prototype = strict_prototypes_lang_cplusplus;
       current_lang_name = name;
       /* DECL_IGNORED_P is initially set for these types, to avoid clutter.
         (See record_builtin_java_type in decl.c.)  However, that causes
         incorrect debug entries if these types are actually used.
         So we re-enable debug output after extern "Java". */
-      DECL_IGNORED_P (java_byte_type_node) = 0;
-      DECL_IGNORED_P (java_short_type_node) = 0;
-      DECL_IGNORED_P (java_int_type_node) = 0;
-      DECL_IGNORED_P (java_long_type_node) = 0;
-      DECL_IGNORED_P (java_float_type_node) = 0;
-      DECL_IGNORED_P (java_double_type_node) = 0;
-      DECL_IGNORED_P (java_char_type_node) = 0;
-      DECL_IGNORED_P (java_boolean_type_node) = 0;
+      DECL_IGNORED_P (TYPE_NAME (java_byte_type_node)) = 0;
+      DECL_IGNORED_P (TYPE_NAME (java_short_type_node)) = 0;
+      DECL_IGNORED_P (TYPE_NAME (java_int_type_node)) = 0;
+      DECL_IGNORED_P (TYPE_NAME (java_long_type_node)) = 0;
+      DECL_IGNORED_P (TYPE_NAME (java_float_type_node)) = 0;
+      DECL_IGNORED_P (TYPE_NAME (java_double_type_node)) = 0;
+      DECL_IGNORED_P (TYPE_NAME (java_char_type_node)) = 0;
+      DECL_IGNORED_P (TYPE_NAME (java_boolean_type_node)) = 0;
     }
   else if (name == lang_name_c)
     {
-      strict_prototype = strict_prototypes_lang_c;
       current_lang_name = name;
     }
   else
@@ -5689,11 +5804,6 @@ pop_lang_context ()
      to it.  */
   *current_lang_stack = NULL_TREE;
   current_lang_name = *--current_lang_stack;
-  if (current_lang_name == lang_name_cplusplus
-      || current_lang_name == lang_name_java)
-    strict_prototype = strict_prototypes_lang_cplusplus;
-  else if (current_lang_name == lang_name_c)
-    strict_prototype = strict_prototypes_lang_c;
 }
 \f
 /* Type instantiation routines.  */
@@ -5701,19 +5811,22 @@ pop_lang_context ()
 /* Given an OVERLOAD and a TARGET_TYPE, return the function that
    matches the TARGET_TYPE.  If there is no satisfactory match, return
    error_mark_node, and issue an error message if COMPLAIN is
-   non-zero.  If TEMPLATE_ONLY, the name of the overloaded function
+   non-zero.  Permit pointers to member function if PTRMEM is non-zero.
+   If TEMPLATE_ONLY, the name of the overloaded function
    was a template-id, and EXPLICIT_TARGS are the explicitly provided
    template arguments.  */
 
 static tree
 resolve_address_of_overloaded_function (target_type, 
                                        overload,
-                                       complain, 
+                                       complain,
+                                       ptrmem,
                                        template_only,
                                        explicit_targs)
      tree target_type;
      tree overload;
      int complain;
+     int ptrmem;
      int template_only;
      tree explicit_targs;
 {
@@ -5835,6 +5948,10 @@ resolve_address_of_overloaded_function (target_type,
        target_fn_type = TREE_TYPE (target_type);
       target_arg_types = TYPE_ARG_TYPES (target_fn_type);
       target_ret_type = TREE_TYPE (target_fn_type);
+
+      /* Never do unification on the 'this' parameter.  */
+      if (TREE_CODE (target_fn_type) == METHOD_TYPE)
+       target_arg_types = TREE_CHAIN (target_arg_types);
          
       for (fns = overload; fns; fns = OVL_CHAIN (fns))
        {
@@ -5857,7 +5974,7 @@ resolve_address_of_overloaded_function (target_type,
          targs = make_tree_vec (DECL_NTPARMS (fn));
          if (fn_type_unification (fn, explicit_targs, targs,
                                   target_arg_types, target_ret_type,
-                                  DEDUCE_EXACT) != 0)
+                                  DEDUCE_EXACT, -1) != 0)
            /* Argument deduction failed.  */
            continue;
 
@@ -5881,8 +5998,7 @@ resolve_address_of_overloaded_function (target_type,
       /* Now, remove all but the most specialized of the matches.  */
       if (matches)
        {
-         tree match = most_specialized_instantiation (matches, 
-                                                      explicit_targs);
+         tree match = most_specialized_instantiation (matches);
 
          if (match != error_mark_node)
            matches = tree_cons (match, NULL_TREE, NULL_TREE);
@@ -5936,6 +6052,21 @@ resolve_address_of_overloaded_function (target_type,
   /* Good, exactly one match.  Now, convert it to the correct type.  */
   fn = TREE_PURPOSE (matches);
 
+  if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)
+      && !ptrmem && !flag_ms_extensions)
+    {
+      static int explained;
+      
+      if (!complain)
+        return error_mark_node;
+
+      cp_pedwarn ("assuming pointer to member `%D'", fn);
+      if (!explained)
+        {
+          cp_pedwarn ("(a pointer to member can only be formed with `&%E')", fn);
+          explained = 1;
+        }
+    }
   mark_used (fn);
 
   if (TYPE_PTRFN_P (target_type) || TYPE_PTRMEMFUNC_P (target_type))
@@ -5953,25 +6084,26 @@ resolve_address_of_overloaded_function (target_type,
 
 /* This function will instantiate the type of the expression given in
    RHS to match the type of LHSTYPE.  If errors exist, then return
-   error_mark_node.  We only complain is COMPLAIN is set.  If we are
-   not complaining, never modify rhs, as overload resolution wants to
-   try many possible instantiations, in hopes that at least one will
-   work.
-
-   FLAGS is a bitmask, as we see at the top of the function.
-
+   error_mark_node. FLAGS is a bit mask.  If ITF_COMPLAIN is set, then
+   we complain on errors.  If we are not complaining, never modify rhs,
+   as overload resolution wants to try many possible instantiations, in
+   the hope that at least one will work.
+   
    For non-recursive calls, LHSTYPE should be a function, pointer to
    function, or a pointer to member function.  */
 
 tree
 instantiate_type (lhstype, rhs, flags)
      tree lhstype, rhs;
-     int flags;
+     enum instantiate_type_flags flags;
 {
-  int complain = (flags & 1);
-  int strict = (flags & 2) ? COMPARE_NO_ATTRIBUTES : COMPARE_STRICT;
-  tree r;
-
+  int complain = (flags & itf_complain);
+  int strict = (flags & itf_no_attributes)
+               ? COMPARE_NO_ATTRIBUTES : COMPARE_STRICT;
+  int allow_ptrmem = flags & itf_ptrmem_ok;
+  
+  flags &= ~itf_ptrmem_ok;
+  
   if (TREE_CODE (lhstype) == UNKNOWN_TYPE)
     {
       if (complain)
@@ -6030,36 +6162,13 @@ instantiate_type (lhstype, rhs, flags)
       return instantiate_type (lhstype, rhs, flags);
 
     case COMPONENT_REF:
-      {
-       r = instantiate_type (lhstype, TREE_OPERAND (rhs, 1), flags);
-
-      comp:
-       if (r != error_mark_node && TYPE_PTRMEMFUNC_P (lhstype)
-           && complain && !flag_ms_extensions)
-         {
-           /* Note: we check this after the recursive call to avoid
-              complaining about cases where overload resolution fails.  */
-
-           tree t = TREE_TYPE (TREE_OPERAND (rhs, 0));
-           tree fn = PTRMEM_CST_MEMBER (r);
-
-           my_friendly_assert (TREE_CODE (r) == PTRMEM_CST, 990811);
-
-           cp_pedwarn
-             ("object-dependent reference to `%E' can only be used in a call",
-              DECL_NAME (fn));
-           cp_pedwarn
-             ("  to form a pointer to member function, say `&%T::%E'",
-              t, DECL_NAME (fn));
-         }
-
-       return r;
-      }
+      return instantiate_type (lhstype, TREE_OPERAND (rhs, 1), flags);
 
     case OFFSET_REF:
       rhs = TREE_OPERAND (rhs, 1);
       if (BASELINK_P (rhs))
-       return instantiate_type (lhstype, TREE_VALUE (rhs), flags);
+       return instantiate_type (lhstype, TREE_VALUE (rhs),
+                                flags | allow_ptrmem);
 
       /* This can happen if we are forming a pointer-to-member for a
         member template.  */
@@ -6072,18 +6181,13 @@ instantiate_type (lhstype, rhs, flags)
        tree fns = TREE_OPERAND (rhs, 0);
        tree args = TREE_OPERAND (rhs, 1);
 
-       r =
+       return
          resolve_address_of_overloaded_function (lhstype,
                                                  fns,
                                                  complain,
+                                                 allow_ptrmem,
                                                  /*template_only=*/1,
                                                  args);
-       if (TREE_CODE (fns) == COMPONENT_REF)
-         {
-           rhs = fns;
-           goto comp;
-         }
-       return r;
       }
 
     case OVERLOAD:
@@ -6091,6 +6195,7 @@ instantiate_type (lhstype, rhs, flags)
        resolve_address_of_overloaded_function (lhstype, 
                                                rhs,
                                                complain,
+                                               allow_ptrmem,
                                                /*template_only=*/0,
                                                /*explicit_targs=*/NULL_TREE);
 
@@ -6202,8 +6307,12 @@ instantiate_type (lhstype, rhs, flags)
       return rhs;
       
     case ADDR_EXPR:
+    {
+      if (PTRMEM_OK_P (rhs))
+        flags |= itf_ptrmem_ok;
+      
       return instantiate_type (lhstype, TREE_OPERAND (rhs, 0), flags);
-
+    }
     case ENTRY_VALUE_EXPR:
       my_friendly_abort (184);
       return error_mark_node;
@@ -6412,8 +6521,8 @@ note_name_declared_in_class (name, decl)
         in its context and when re-evaluated in the completed scope of
         S.  */
       cp_error ("declaration of `%#D'", decl);
-      cp_error_at ("changes meaning of `%s' from `%+#D'", 
-                  IDENTIFIER_POINTER (DECL_NAME (OVL_CURRENT (decl))),
+      cp_error_at ("changes meaning of `%D' from `%+#D'", 
+                  DECL_NAME (OVL_CURRENT (decl)),
                   (tree) n->value);
     }
 }
@@ -6441,6 +6550,69 @@ get_vtbl_decl_for_binfo (binfo)
   return decl;
 }
 
+/* Called from get_primary_binfo via dfs_walk.  */
+
+static tree
+dfs_get_primary_binfo (binfo, data)
+     tree binfo;
+     void *data;
+{
+  tree primary_base = (tree) data;
+
+  if (TREE_VIA_VIRTUAL (binfo) 
+      && same_type_p (TREE_TYPE (binfo), TREE_TYPE (primary_base)))
+    return binfo;
+  
+  return NULL_TREE;
+}
+
+/* Returns the binfo for the primary base of BINFO.  Note that in a
+   complex hierarchy the resulting BINFO may not actually *be*
+   primary.  In particular if the resulting BINFO is a virtual base,
+   and it occurs elsewhere in the hierarchy, then this occurrence may
+   not actually be a primary base in the complete object.  Check
+   BINFO_PRIMARY_MARKED_P to be sure.  */
+
+tree
+get_primary_binfo (binfo)
+     tree binfo;
+{
+  tree primary_base;
+  tree result;
+
+  primary_base = CLASSTYPE_PRIMARY_BINFO (BINFO_TYPE (binfo));
+  if (!primary_base)
+    return NULL_TREE;
+
+  /* A non-virtual primary base is always a direct base, and easy to
+     find.  */
+  if (!TREE_VIA_VIRTUAL (primary_base))
+    {
+      int i;
+
+      /* Scan the direct basetypes until we find a base with the same
+        type as the primary base.  */
+      for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
+       {
+         tree base_binfo = BINFO_BASETYPE (binfo, i);
+         
+         if (same_type_p (BINFO_TYPE (base_binfo),
+                          BINFO_TYPE (primary_base)))
+           return base_binfo;
+       }
+
+      /* We should always find the primary base.  */
+      my_friendly_abort (20000729);
+    }
+
+  /* For a primary virtual base, we have to scan the entire hierarchy
+     rooted at BINFO; the virtual base could be an indirect virtual
+     base.  */
+  result = dfs_walk (binfo, dfs_get_primary_binfo, NULL, primary_base);
+  my_friendly_assert (result != NULL_TREE, 20000730);
+  return result;
+}
+
 /* Dump the offsets of all the bases rooted at BINFO (in the hierarchy
    dominated by T) to stderr.  INDENT should be zero when called from
    the top level; it is incremented recursively.  */
@@ -6455,15 +6627,15 @@ dump_class_hierarchy_r (t, binfo, indent)
 
   fprintf (stderr, "%*s0x%lx (%s) ", indent, "",
           (unsigned long) binfo,
-          type_as_string (binfo, TS_PLAIN));
+          type_as_string (binfo, TFF_PLAIN_IDENTIFIER));
   fprintf (stderr, HOST_WIDE_INT_PRINT_DEC,
           tree_low_cst (BINFO_OFFSET (binfo), 0));
   if (TREE_VIA_VIRTUAL (binfo))
     fprintf (stderr, " virtual");
   if (BINFO_PRIMARY_MARKED_P (binfo)
       || (TREE_VIA_VIRTUAL (binfo) 
-         && BINFO_VBASE_PRIMARY_P (binfo_for_vbase (BINFO_TYPE (binfo), 
-                                                    t))))
+         && BINFO_PRIMARY_MARKED_P (binfo_for_vbase (BINFO_TYPE (binfo), 
+                                                     t))))
     fprintf (stderr, " primary");
   fprintf (stderr, "\n");
 
@@ -6590,7 +6762,8 @@ build_vtt (t)
   /* Build up the initializers for the VTT.  */
   inits = NULL_TREE;
   index = size_zero_node;
-  build_vtt_inits (TYPE_BINFO (t), t, &inits, &index);
+  build_vtt_inits (TYPE_BINFO (t), t, /*virtual_vtts_p=*/1, 
+                  &inits, &index);
 
   /* If we didn't need a VTT, we're done.  */
   if (!inits)
@@ -6606,15 +6779,45 @@ build_vtt (t)
   initialize_array (vtt, inits);
 }
 
+/* The type corresponding to BINFO is a base class of T, but BINFO is
+   in the base class hierarchy of a class derived from T.  Return the
+   base, in T's hierarchy, that corresponds to BINFO.  */
+
+static tree
+get_matching_base (binfo, t)
+     tree binfo;
+     tree t;
+{
+  tree derived;
+  int i;
+
+  if (same_type_p (BINFO_TYPE (binfo), t))
+    return binfo;
+
+  if (TREE_VIA_VIRTUAL (binfo))
+    return binfo_for_vbase (BINFO_TYPE (binfo), t);
+
+  derived = get_matching_base (BINFO_INHERITANCE_CHAIN (binfo), t);
+  for (i = 0; i < BINFO_N_BASETYPES (derived); ++i)
+    if (same_type_p (BINFO_TYPE (BINFO_BASETYPE (derived, i)),
+                    BINFO_TYPE (binfo)))
+      return BINFO_BASETYPE (derived, i);
+
+  my_friendly_abort (20000628);
+  return NULL_TREE;
+}
+
 /* Recursively build the VTT-initializer for BINFO (which is in the
-   hierarchy dominated by T).  INITS points to the end of the
-   initializer list to date.  INDEX is the VTT index where the next
-   element will be placed.  */
+   hierarchy dominated by T).  If VIRTUAL_VTTS_P is non-zero, then
+   sub-VTTs for virtual bases are included.  INITS points to the end
+   of the initializer list to date.  INDEX is the VTT index where the
+   next element will be placed.  */
 
 static tree *
-build_vtt_inits (binfo, t, inits, index)
+build_vtt_inits (binfo, t, virtual_vtts_p, inits, index)
      tree binfo;
      tree t;
+     int virtual_vtts_p;
      tree *inits;
      tree *index;
 {
@@ -6642,7 +6845,7 @@ build_vtt_inits (binfo, t, inits, index)
   /* Add the address of the primary vtable for the complete object.  */
   init = BINFO_VTABLE (binfo);
   if (TREE_CODE (init) == TREE_LIST)
-    init = TREE_PURPOSE (init);
+    init = TREE_VALUE (init);
   *inits = build_tree_list (NULL_TREE, init);
   inits = &TREE_CHAIN (*inits);
   BINFO_VPTR_INDEX (binfo) = *index;
@@ -6653,23 +6856,23 @@ build_vtt_inits (binfo, t, inits, index)
     {
       b = BINFO_BASETYPE (binfo, i);
       if (!TREE_VIA_VIRTUAL (b))
-       inits = build_vtt_inits (BINFO_BASETYPE (binfo, i), t, inits,
-                                index);
+       inits = build_vtt_inits (BINFO_BASETYPE (binfo, i), t, 
+                                /*virtuals_vtts_p=*/0,
+                                inits, index);
     }
       
   /* Add secondary virtual pointers for all subobjects of BINFO with
      either virtual bases or virtual functions overridden along a
      virtual path between the declaration and D, except subobjects
      that are non-virtual primary bases.  */
-  secondary_vptrs = build_tree_list (BINFO_TYPE (binfo), NULL_TREE);
+  secondary_vptrs = tree_cons (t, NULL_TREE, BINFO_TYPE (binfo));
   TREE_TYPE (secondary_vptrs) = *index;
   dfs_walk_real (binfo,
-                dfs_build_vtt_inits,
+                dfs_build_secondary_vptr_vtt_inits,
                 NULL,
                 dfs_unmarked_real_bases_queue_p,
                 secondary_vptrs);
-  dfs_walk (binfo, dfs_fixup_binfo_vtbls, dfs_marked_real_bases_queue_p,
-           BINFO_TYPE (binfo));
+  dfs_walk (binfo, dfs_unmark, dfs_marked_real_bases_queue_p, t);
   *index = TREE_TYPE (secondary_vptrs);
 
   /* The secondary vptrs come back in reverse order.  After we reverse
@@ -6684,16 +6887,22 @@ build_vtt_inits (binfo, t, inits, index)
     }
 
   /* Add the secondary VTTs for virtual bases.  */
-  for (b = TYPE_BINFO (BINFO_TYPE (binfo)); b; b = TREE_CHAIN (b))
-    {
-      tree vbase;
-
-      if (!TREE_VIA_VIRTUAL (b))
-       continue;
+  if (virtual_vtts_p)
+    for (b = TYPE_BINFO (BINFO_TYPE (binfo)); b; b = TREE_CHAIN (b))
+      {
+       tree vbase;
+       
+       if (!TREE_VIA_VIRTUAL (b))
+         continue;
+       
+       vbase = binfo_for_vbase (BINFO_TYPE (b), t);
+       inits = build_vtt_inits (vbase, t, /*virtual_vtts_p=*/0, 
+                                inits, index);
+      }
 
-      vbase = binfo_for_vbase (BINFO_TYPE (b), t);
-      inits = build_vtt_inits (vbase, t, inits, index);
-    }
+  dfs_walk (binfo, dfs_fixup_binfo_vtbls,
+           dfs_unmarked_real_bases_queue_p,
+           build_tree_list (t, binfo));
 
   return inits;
 }
@@ -6701,7 +6910,7 @@ build_vtt_inits (binfo, t, inits, index)
 /* Called from build_vtt_inits via dfs_walk.  */
 
 static tree
-dfs_build_vtt_inits (binfo, data)
+dfs_build_secondary_vptr_vtt_inits (binfo, data)
      tree binfo;
      void *data;
 {
@@ -6711,7 +6920,7 @@ dfs_build_vtt_inits (binfo, data)
   tree index;
 
   l = (tree) data;
-  t = TREE_PURPOSE (l);
+  t = TREE_CHAIN (l);
 
   SET_BINFO_MARKED (binfo);
 
@@ -6729,10 +6938,19 @@ dfs_build_vtt_inits (binfo, data)
 
   /* If BINFO doesn't have virtual bases, then we have to look to see
      whether or not any virtual functions were overidden along a
-     virtual path between the declaration and T.  */
-  if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo)))
-    /* FIXME: Implement this.  */
-    ;
+     virtual path.  The point is that given:
+
+       struct V { virtual void f(); int i; };
+       struct C : public virtual V { void f (); };
+
+     when we constrct C we need a secondary vptr for V-in-C because we
+     don't know what the vcall offset for `f' should be.  If `V' ends
+     up in a different place in the complete object, then we'll need a
+     different vcall offset than that present in the normal V-in-C
+     vtable.  */
+  if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo))
+      && !BINFO_OVERRIDE_ALONG_VIRTUAL_PATH_P (get_matching_base (binfo, t)))
+    return NULL_TREE;
 
   /* Record the index where this secondary vptr can be found.  */
   index = TREE_TYPE (l);
@@ -6743,7 +6961,7 @@ dfs_build_vtt_inits (binfo, data)
   /* Add the initializer for the secondary vptr itself.  */
   init = BINFO_VTABLE (binfo);
   if (TREE_CODE (init) == TREE_LIST)
-    init = TREE_PURPOSE (init);
+    init = TREE_VALUE (init);
   TREE_VALUE (l) = tree_cons (NULL_TREE, init, TREE_VALUE (l));
 
   return NULL_TREE;
@@ -6754,7 +6972,7 @@ dfs_build_vtt_inits (binfo, data)
 static tree
 dfs_fixup_binfo_vtbls (binfo, data)
      tree binfo;
-     void *data ATTRIBUTE_UNUSED;
+     void *data;
 {
   CLEAR_BINFO_MARKED (binfo);
 
@@ -6764,8 +6982,10 @@ dfs_fixup_binfo_vtbls (binfo, data)
 
   /* If we scribbled the construction vtable vptr into BINFO, clear it
      out now.  */
-  if (TREE_CODE (BINFO_VTABLE (binfo)) == TREE_LIST)
-    BINFO_VTABLE (binfo) = TREE_VALUE (BINFO_VTABLE (binfo));
+  if (TREE_CODE (BINFO_VTABLE (binfo)) == TREE_LIST
+      && (TREE_PURPOSE (BINFO_VTABLE (binfo)) 
+         == TREE_VALUE ((tree) data)))
+    BINFO_VTABLE (binfo) = TREE_CHAIN (BINFO_VTABLE (binfo));
 
   return NULL_TREE;
 }
@@ -6783,6 +7003,7 @@ build_ctor_vtbl_group (binfo, t)
   tree vtbl;
   tree inits;
   tree id;
+  tree vbase;
 
   /* See if we've already create this construction vtable group.  */
   if (flag_new_abi)
@@ -6799,6 +7020,19 @@ build_ctor_vtbl_group (binfo, t)
   list = build_tree_list (vtbl, NULL_TREE);
   accumulate_vtbl_inits (binfo, TYPE_BINFO (TREE_TYPE (binfo)),
                         binfo, t, list);
+  for (vbase = TYPE_BINFO (TREE_TYPE (binfo)); 
+       vbase; 
+       vbase = TREE_CHAIN (vbase))
+    {
+      tree b;
+
+      if (!TREE_VIA_VIRTUAL (vbase))
+       continue;
+
+      b = binfo_for_vbase (BINFO_TYPE (vbase), t);
+      accumulate_vtbl_inits (b, vbase, binfo, t, list);
+    }
+
   inits = TREE_VALUE (list);
 
   /* Figure out the type of the construction vtable.  */
@@ -6840,7 +7074,9 @@ accumulate_vtbl_inits (binfo, orig_binfo, rtti_binfo, t, inits)
   /* If we're building a construction vtable, we're not interested in
      subobjects that don't require construction vtables.  */
   if (ctor_vtbl_p 
-      && !TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo)))
+      && !TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo))
+      && !(BINFO_OVERRIDE_ALONG_VIRTUAL_PATH_P 
+          (get_matching_base (binfo, BINFO_TYPE (rtti_binfo)))))
     return;
 
   /* Build the initializers for the BINFO-in-T vtable.  */
@@ -6883,16 +7119,8 @@ dfs_accumulate_vtbl_inits (binfo, orig_binfo, rtti_binfo, t, l)
      tree l;
 {
   tree inits = NULL_TREE;
-  int ctor_vtbl_p;
-
-  /* This is a construction vtable if the RTTI type is not the most
-     derived type in the hierarchy.  */
-  ctor_vtbl_p = !same_type_p (BINFO_TYPE (rtti_binfo), t);
 
-  if (BINFO_NEW_VTABLE_MARKED (binfo, t)
-      /* We need a new vtable, even for a primary base, when we're
-        building a construction vtable.  */
-      || (ctor_vtbl_p && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))))
+  if (BINFO_NEW_VTABLE_MARKED (orig_binfo, t))
     {
       tree vtbl;
       tree index;
@@ -6917,14 +7145,14 @@ dfs_accumulate_vtbl_inits (binfo, orig_binfo, rtti_binfo, t, l)
       TREE_CONSTANT (vtbl) = 1;
 
       /* For an ordinary vtable, set BINFO_VTABLE.  */
-      if (!ctor_vtbl_p)
+      if (same_type_p (BINFO_TYPE (rtti_binfo), t))
        BINFO_VTABLE (binfo) = vtbl;
       /* For a construction vtable, we can't overwrite BINFO_VTABLE.
         So, we make a TREE_LIST.  Later, dfs_fixup_binfo_vtbls will
         straighten this out.  */
       else
-       BINFO_VTABLE (binfo) = build_tree_list (vtbl,
-                                               BINFO_VTABLE (binfo));
+       BINFO_VTABLE (binfo) = 
+         tree_cons (rtti_binfo, vtbl, BINFO_VTABLE (binfo));
     }
 
   return inits;
@@ -6934,7 +7162,7 @@ dfs_accumulate_vtbl_inits (binfo, orig_binfo, rtti_binfo, t, l)
    is part of the hierarchy dominated by T.  If we're building a
    construction vtable, the ORIG_BINFO is the binfo we should use to
    find the actual function pointers to put in the vtable.  Otherwise,
-   ORIG_BINFO should be the same as BINFO.  The RTTI_DOMINATOR is the
+   ORIG_BINFO should be the same as BINFO.  The RTTI_BINFO is the
    BINFO that should be indicated by the RTTI information in the
    vtable; it will be a base class of T, rather than T itself, if we
    are building a construction vtable.
@@ -6942,7 +7170,14 @@ dfs_accumulate_vtbl_inits (binfo, orig_binfo, rtti_binfo, t, l)
    The value returned is a TREE_LIST suitable for wrapping in a
    CONSTRUCTOR to use as the DECL_INITIAL for a vtable.  If
    NON_FN_ENTRIES_P is not NULL, *NON_FN_ENTRIES_P is set to the
-   number of non-function entries in the vtable.  */
+   number of non-function entries in the vtable.  
+
+   It might seem that this function should never be called with a
+   BINFO for which BINFO_PRIMARY_MARKED_P holds, the vtable for such a
+   base is always subsumed by a derived class vtable.  However, when
+   we are building construction vtables we do build vtables for
+   primary bases; we need these while the primary base is being
+   constructed.  */
 
 static tree
 build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)
@@ -6953,24 +7188,32 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)
      int *non_fn_entries_p;
 {
   tree v;
-   tree vfun_inits;
+  tree vfun_inits;
   tree vbase;
-  vcall_offset_data vod;
-
-  /* Initialize those parts of VOD that matter.  */
-  vod.derived = t;
-  vod.inits = NULL_TREE;
-  vod.last_init = &vod.inits;
-  vod.primary_p = (binfo == TYPE_BINFO (t));
+  vtbl_init_data vid;
+
+  /* Initialize VID.  */
+  memset (&vid, 0, sizeof (vid));
+  vid.binfo = binfo;
+  vid.derived = t;
+  vid.last_init = &vid.inits;
+  vid.primary_vtbl_p = (binfo == TYPE_BINFO (t));
+  vid.ctor_vtbl_p = !same_type_p (BINFO_TYPE (rtti_binfo), t);
   /* The first vbase or vcall offset is at index -3 in the vtable.  */
-  vod.index = build_int_2 (-3, -1);
+  vid.index = ssize_int (-3);
 
   /* Add entries to the vtable for RTTI.  */
-  build_rtti_vtbl_entries (binfo, rtti_binfo, &vod);
+  build_rtti_vtbl_entries (binfo, rtti_binfo, &vid);
 
+  /* Create an array for keeping track of the functions we've
+     processed.  When we see multiple functions with the same
+     signature, we share the vcall offsets.  */
+  VARRAY_TREE_INIT (vid.fns, 32, "fns");
   /* Add the vcall and vbase offset entries.  */
-  build_vcall_and_vbase_vtbl_entries (binfo, &vod);
-   /* Clear BINFO_VTABLE_PAATH_MARKED; it's set by
+  build_vcall_and_vbase_vtbl_entries (binfo, &vid);
+  /* Clean up.  */
+  VARRAY_FREE (vid.fns);
+  /* Clear BINFO_VTABLE_PATH_MARKED; it's set by
      build_vbase_offset_vtbl_entries.  */
   for (vbase = CLASSTYPE_VBASECLASSES (t); 
        vbase; 
@@ -6978,7 +7221,7 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)
     CLEAR_BINFO_VTABLE_PATH_MARKED (TREE_VALUE (vbase));
 
   if (non_fn_entries_p)
-    *non_fn_entries_p = list_length (vod.inits);
+    *non_fn_entries_p = list_length (vid.inits);
 
   /* Go through all the ordinary virtual functions, building up
      initializers.  */
@@ -6994,7 +7237,15 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)
       /* Pull the offset for `this', and the function to call, out of
         the list.  */
       delta = BV_DELTA (v);
-      vcall_index = BV_VCALL_INDEX (v);
+
+      if (BV_USE_VCALL_INDEX_P (v))
+       {
+         vcall_index = BV_VCALL_INDEX (v);
+         my_friendly_assert (vcall_index != NULL_TREE, 20000621);
+       }
+      else
+       vcall_index = NULL_TREE;
+
       fn = BV_FN (v);
       my_friendly_assert (TREE_CODE (delta) == INTEGER_CST, 19990727);
       my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727);
@@ -7010,7 +7261,8 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)
       /* The address of a function can't change.  */
       TREE_CONSTANT (pfn) = 1;
       /* Enter it in the vtable.  */
-      init = build_vtable_entry (delta, vcall_index, pfn);
+      init = build_vtable_entry (delta, vcall_index, pfn,
+                                BV_GENERATE_THUNK_WITH_VTABLE_P (v));
       /* And add it to the chain of initializers.  */
       vfun_inits = tree_cons (NULL_TREE, init, vfun_inits);
     }
@@ -7020,32 +7272,32 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)
   vfun_inits = nreverse (vfun_inits);
   
   /* The negative offset initializers are also in reverse order.  */
-  vod.inits = nreverse (vod.inits);
+  vid.inits = nreverse (vid.inits);
 
   /* Chain the two together.  */
-  return chainon (vod.inits, vfun_inits);
+  return chainon (vid.inits, vfun_inits);
 }
 
-/* Sets vod->inits to be the initializers for the vbase and vcall
+/* Sets vid->inits to be the initializers for the vbase and vcall
    offsets in BINFO, which is in the hierarchy dominated by T.  */
 
 static void
-build_vcall_and_vbase_vtbl_entries (binfo, vod)
+build_vcall_and_vbase_vtbl_entries (binfo, vid)
      tree binfo;
-     vcall_offset_data *vod;
+     vtbl_init_data *vid;
 {
   tree b;
 
   /* If this is a derived class, we must first create entries
      corresponding to the primary base class.  */
-  b = BINFO_PRIMARY_BINFO (binfo);
+  b = get_primary_binfo (binfo);
   if (b)
-    build_vcall_and_vbase_vtbl_entries (b, vod);
+    build_vcall_and_vbase_vtbl_entries (b, vid);
 
   /* Add the vbase entries for this base.  */
-  build_vbase_offset_vtbl_entries (binfo, vod);
+  build_vbase_offset_vtbl_entries (binfo, vid);
   /* Add the vcall entries for this base.  */
-  build_vcall_offset_vtbl_entries (binfo, vod);
+  build_vcall_offset_vtbl_entries (binfo, vid);
 }
 
 /* Returns the initializers for the vbase offset entries in the vtable
@@ -7054,9 +7306,9 @@ build_vcall_and_vbase_vtbl_entries (binfo, vod)
    where the next vbase offset will go.  */
 
 static void
-build_vbase_offset_vtbl_entries (binfo, vod)
+build_vbase_offset_vtbl_entries (binfo, vid)
      tree binfo;
-     vcall_offset_data *vod;
+     vtbl_init_data *vid;
 {
   tree vbase;
   tree t;
@@ -7071,7 +7323,7 @@ build_vbase_offset_vtbl_entries (binfo, vod)
   if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo)))
     return;
 
-  t = vod->derived;
+  t = vid->derived;
 
   /* Go through the virtual bases, adding the offsets.  */
   for (vbase = TYPE_BINFO (BINFO_TYPE (binfo));
@@ -7096,10 +7348,10 @@ build_vbase_offset_vtbl_entries (binfo, vod)
 
       /* Figure out where we can find this vbase offset.  */
       delta = size_binop (MULT_EXPR, 
-                         convert (ssizetype, vod->index),
+                         vid->index,
                          convert (ssizetype,
                                   TYPE_SIZE_UNIT (vtable_entry_type)));
-      if (vod->primary_p)
+      if (vid->primary_vtbl_p)
        BINFO_VPTR_FIELD (b) = delta;
 
       if (binfo != TYPE_BINFO (t))
@@ -7117,177 +7369,216 @@ build_vbase_offset_vtbl_entries (binfo, vod)
        }
 
       /* The next vbase will come at a more negative offset.  */
-      vod->index = fold (build (MINUS_EXPR, integer_type_node,
-                               vod->index, integer_one_node));
+      vid->index = size_binop (MINUS_EXPR, vid->index, ssize_int (1));
 
       /* The initializer is the delta from BINFO to this virtual base.
         The vbase offsets go in reverse inheritance-graph order, and
         we are walking in inheritance graph order so these end up in
         the right order.  */
       delta = size_diffop (BINFO_OFFSET (b), BINFO_OFFSET (binfo));
-      *vod->last_init 
+      *vid->last_init 
        = build_tree_list (NULL_TREE,
                           fold (build1 (NOP_EXPR, 
                                         vtable_entry_type,
                                         delta)));
-      vod->last_init = &TREE_CHAIN (*vod->last_init);
+      vid->last_init = &TREE_CHAIN (*vid->last_init);
+    }
+}
+
+/* Adds the initializers for the vcall offset entries in the vtable
+   for BINFO (which is part of the class hierarchy dominated by T) to
+   VID->INITS.  */
+
+static void
+build_vcall_offset_vtbl_entries (binfo, vid)
+     tree binfo;
+     vtbl_init_data *vid;
+{
+  /* Under the old ABI, the adjustments to the `this' pointer were made
+     elsewhere.  */
+  if (!vcall_offsets_in_vtable_p ())
+    return;
+
+  /* We only need these entries if this base is a virtual base.  */
+  if (!TREE_VIA_VIRTUAL (binfo))
+    return;
+
+  /* We need a vcall offset for each of the virtual functions in this
+     vtable.  For example:
+
+       class A { virtual void f (); };
+       class B : virtual public A { };
+       class C: virtual public A, public B {};
+      
+     Now imagine:
+
+       B* b = new C;
+       b->f();
+
+     The location of `A' is not at a fixed offset relative to `B'; the
+     offset depends on the complete object derived from `B'.  So, 
+     `B' vtable contains an entry for `f' that indicates by what
+     amount the `this' pointer for `B' needs to be adjusted to arrive
+     at `A'.  
+
+     We need entries for all the functions in our primary vtable and
+     in our non-virtual bases vtables.  */
+  vid->vbase = binfo;
+  /* Now, walk through the non-virtual bases, adding vcall offsets.  */
+  add_vcall_offset_vtbl_entries_r (binfo, vid);
+}
+
+/* Build vcall offsets, starting with those for BINFO.  */
+
+static void
+add_vcall_offset_vtbl_entries_r (binfo, vid)
+     tree binfo;
+     vtbl_init_data *vid;
+{
+  int i;
+  tree primary_binfo;
+
+  /* Don't walk into virtual bases -- except, of course, for the
+     virtual base for which we are building vcall offsets.  */
+  if (TREE_VIA_VIRTUAL (binfo) && vid->vbase != binfo)
+    return;
+  
+  /* If BINFO has a primary base, process it first.  */
+  primary_binfo = get_primary_binfo (binfo);
+  if (primary_binfo)
+    add_vcall_offset_vtbl_entries_r (primary_binfo, vid);
+
+  /* Add BINFO itself to the list.  */
+  add_vcall_offset_vtbl_entries_1 (binfo, vid);
+
+  /* Scan the non-primary bases of BINFO.  */
+  for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i) 
+    {
+      tree base_binfo;
+      
+      base_binfo = BINFO_BASETYPE (binfo, i);
+      if (base_binfo != primary_binfo)
+       add_vcall_offset_vtbl_entries_r (base_binfo, vid);
     }
 }
 
 /* Called from build_vcall_offset_vtbl_entries via dfs_walk.  */
 
-static tree
-dfs_build_vcall_offset_vtbl_entries (binfo, data)
+static void
+add_vcall_offset_vtbl_entries_1 (binfo, vid)
      tree binfo;
-     void *data;
+     vtbl_init_data* vid;
 {
-  vcall_offset_data* vod;
   tree derived_virtuals;
   tree base_virtuals;
+  tree orig_virtuals;
   tree binfo_inits;
+  /* If BINFO is a primary base, this is the least derived class of
+     BINFO that is not a primary base.  */
   tree non_primary_binfo;
-  tree b;
-  int i;
 
-  vod = (vcall_offset_data *) data;
   binfo_inits = NULL_TREE;
 
   /* We might be a primary base class.  Go up the inheritance
      hierarchy until we find the class of which we are a primary base:
      it is the BINFO_VIRTUALS there that we need to consider.  */
   non_primary_binfo = binfo;
-  while (BINFO_PRIMARY_MARKED_P (non_primary_binfo))
-    non_primary_binfo = BINFO_INHERITANCE_CHAIN (non_primary_binfo);
+  while (BINFO_INHERITANCE_CHAIN (non_primary_binfo))
+    {
+      tree b;
 
-  /* Skip virtuals that we have already handled in a primary base
-     class.  */
-  base_virtuals = BINFO_VIRTUALS (binfo);
-  derived_virtuals = BINFO_VIRTUALS (non_primary_binfo);
-  b = BINFO_PRIMARY_BINFO (binfo);
-  if (b)
-    for (i = 0; i < CLASSTYPE_VSIZE (BINFO_TYPE (b)); ++i)
-      {
-       base_virtuals = TREE_CHAIN (base_virtuals);
-       derived_virtuals = TREE_CHAIN (derived_virtuals);
-      }
+      /* If we have reached a virtual base, then it must be the
+        virtual base for which we are building vcall offsets.  In
+        turn, the virtual base must be a (possibly indirect) primary
+        base of the class that we are initializing, or we wouldn't
+        care about its vtable offsets.  */
+      if (TREE_VIA_VIRTUAL (non_primary_binfo))
+       {
+         non_primary_binfo = vid->binfo;
+         break;
+       }
+
+      b = BINFO_INHERITANCE_CHAIN (non_primary_binfo);
+      if (get_primary_binfo (b) != non_primary_binfo)
+       break;
+      non_primary_binfo = b;
+    }
 
   /* Make entries for the rest of the virtuals.  */
-  for (; base_virtuals;
-       derived_virtuals = TREE_CHAIN (derived_virtuals),
-        base_virtuals = TREE_CHAIN (base_virtuals))
-    {
-      /* Figure out what function we're looking at.  */
-      tree fn = TREE_VALUE (derived_virtuals);
+  for (base_virtuals = BINFO_VIRTUALS (binfo),
+        derived_virtuals = BINFO_VIRTUALS (non_primary_binfo),
+        orig_virtuals = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (binfo)));
+       base_virtuals;
+       base_virtuals = TREE_CHAIN (base_virtuals),
+        derived_virtuals = TREE_CHAIN (derived_virtuals),
+        orig_virtuals = TREE_CHAIN (orig_virtuals))
+    {
+      tree orig_fn;
+      tree fn;
       tree base;
       tree base_binfo;
       size_t i;
 
+      /* Find the declaration that originally caused this function to
+        be present.  */
+      orig_fn = BV_FN (orig_virtuals);
+
+      /* We do not need an entry if this function is declared in a
+        virtual base (or one of its virtual bases), and not
+        overridden in the section of the hierarchy dominated by the
+        virtual base for which we are building vcall offsets.  */
+      if (!same_type_p (DECL_CONTEXT (orig_fn), BINFO_TYPE (binfo)))
+       continue;
+
+      /* Find the overriding function.  */
+      fn = BV_FN (derived_virtuals);
+
       /* If there is already an entry for a function with the same
         signature as FN, then we do not need a second vcall offset.
         Check the list of functions already present in the derived
         class vtable.  */
-      for (i = 0; i < VARRAY_ACTIVE_SIZE (vod->fns); ++i) 
+      for (i = 0; i < VARRAY_ACTIVE_SIZE (vid->fns); ++i) 
        {
          tree derived_entry;
 
-         derived_entry = VARRAY_TREE (vod->fns, i);
-         if (same_signature_p (TREE_VALUE (derived_entry), fn))
+         derived_entry = VARRAY_TREE (vid->fns, i);
+         if (same_signature_p (BV_FN (derived_entry), fn))
            {
              BV_VCALL_INDEX (derived_virtuals) 
                = BV_VCALL_INDEX (derived_entry);
              break;
            }
        }
-      if (i != VARRAY_ACTIVE_SIZE (vod->fns))
+      if (i != VARRAY_ACTIVE_SIZE (vid->fns))
        continue;
 
       /* The FN comes from BASE.  So, we must caculate the adjustment
         from the virtual base that derived from BINFO to BASE.  */
       base = DECL_CONTEXT (fn);
-      base_binfo = get_binfo (base, vod->derived, /*protect=*/0);
+      base_binfo = get_binfo (base, vid->derived, /*protect=*/0);
 
       /* Compute the vcall offset.  */
-      *vod->last_init 
+      *vid->last_init 
        = (build_tree_list 
           (NULL_TREE,
            fold (build1 (NOP_EXPR, vtable_entry_type,
                          size_diffop (BINFO_OFFSET (base_binfo),
-                                      BINFO_OFFSET (vod->vbase))))));
-      vod->last_init = &TREE_CHAIN (*vod->last_init);
-
-      /* If there is already a vcall index, then we are processing a
-        construction vtable.  The index should be the same as it was
-        when we processed the vtable for the base class.  */
-      if (BV_VCALL_INDEX (derived_virtuals))
-       my_friendly_assert (tree_int_cst_equal (BV_VCALL_INDEX
-                                               (derived_virtuals),
-                                               vod->index),
-                           20000516);
+                                      BINFO_OFFSET (vid->vbase))))));
+      vid->last_init = &TREE_CHAIN (*vid->last_init);
+
       /* Keep track of the vtable index where this vcall offset can be
-        found.  */
-      else
-       BV_VCALL_INDEX (derived_virtuals) = vod->index;
+        found.  For a construction vtable, we already made this
+        annotation when we build the original vtable.  */
+      if (!vid->ctor_vtbl_p)
+       BV_VCALL_INDEX (derived_virtuals) = vid->index;
 
       /* The next vcall offset will be found at a more negative
         offset.  */
-      vod->index = fold (build (MINUS_EXPR, integer_type_node,
-                               vod->index, integer_one_node));
+      vid->index = size_binop (MINUS_EXPR, vid->index, ssize_int (1));
 
       /* Keep track of this function.  */
-      VARRAY_PUSH_TREE (vod->fns, derived_virtuals);
+      VARRAY_PUSH_TREE (vid->fns, derived_virtuals);
     }
-
-  return NULL_TREE;
-}
-
-/* Adds the initializers for the vcall offset entries in the vtable
-   for BINFO (which is part of the class hierarchy dominated by T) to
-   VOD->INITS.  */
-
-static void
-build_vcall_offset_vtbl_entries (binfo, vod)
-     tree binfo;
-     vcall_offset_data *vod;
-{
-  /* Under the old ABI, the adjustments to the `this' pointer were made
-     elsewhere.  */
-  if (!vcall_offsets_in_vtable_p ())
-    return;
-
-  /* We only need these entries if this base is a virtual base.  */
-  if (!TREE_VIA_VIRTUAL (binfo))
-    return;
-
-  /* We need a vcall offset for each of the virtual functions in this
-     vtable.  For example:
-
-       class A { virtual void f (); };
-       class B : virtual public A { };
-       class C: virtual public A, public B {};
-      
-     Now imagine:
-
-       B* b = new C;
-       b->f();
-
-     The location of `A' is not at a fixed offset relative to `B'; the
-     offset depends on the complete object derived from `B'.  So, 
-     `B' vtable contains an entry for `f' that indicates by what
-     amount the `this' pointer for `B' needs to be adjusted to arrive
-     at `A'.  
-
-     We need entries for all the functions in our primary vtable and
-     in our non-virtual bases vtables.  For each base, the entries
-     appear in the same order as in the base; but the bases themselves
-     appear in reverse depth-first, left-to-right order.  */
-  vod->vbase = binfo;
-  VARRAY_TREE_INIT (vod->fns, 32, "fns");
-  dfs_walk_real (binfo,
-                dfs_build_vcall_offset_vtbl_entries,
-                NULL,
-                dfs_skip_vbases,
-                vod);
-  VARRAY_FREE (vod->fns);
 }
 
 /* Return vtbl initializers for the RTTI entries coresponding to the
@@ -7295,10 +7586,10 @@ build_vcall_offset_vtbl_entries (binfo, vod)
    by RTTI_BINFO.  */
 
 static void
-build_rtti_vtbl_entries (binfo, rtti_binfo, vod)
+build_rtti_vtbl_entries (binfo, rtti_binfo, vid)
      tree binfo;
      tree rtti_binfo;
-     vcall_offset_data *vod;
+     vtbl_init_data *vid;
 {
   tree b;
   tree t;
@@ -7321,7 +7612,7 @@ build_rtti_vtbl_entries (binfo, rtti_binfo, vod)
     {
       tree primary_base;
 
-      primary_base = BINFO_PRIMARY_BINFO (b);
+      primary_base = get_primary_binfo (b);
       if (!BINFO_PRIMARY_MARKED_P (primary_base))
        break;
       b = primary_base;
@@ -7354,10 +7645,11 @@ build_rtti_vtbl_entries (binfo, rtti_binfo, vod)
         vtable.  */
       init = build1 (ADDR_EXPR, vfunc_ptr_type_node, decl);
       TREE_CONSTANT (init) = 1;
-      init = build_vtable_entry (offset, integer_zero_node, init);
+      init = build_vtable_entry (offset, NULL_TREE, init, 
+                                /*generate_with_vtable_p=*/0);
     }
-  *vod->last_init = build_tree_list (NULL_TREE, init);
-  vod->last_init = &TREE_CHAIN (*vod->last_init);
+  *vid->last_init = build_tree_list (NULL_TREE, init);
+  vid->last_init = &TREE_CHAIN (*vid->last_init);
 
   /* Add the offset-to-top entry.  It comes earlier in the vtable that
      the the typeinfo entry.  */
@@ -7367,8 +7659,8 @@ build_rtti_vtbl_entries (binfo, rtti_binfo, vod)
         we can put it in the vtable.  */
       init = build1 (NOP_EXPR, vfunc_ptr_type_node, offset);
       TREE_CONSTANT (init) = 1;
-      *vod->last_init = build_tree_list (NULL_TREE, init);
-      vod->last_init = &TREE_CHAIN (*vod->last_init);
+      *vid->last_init = build_tree_list (NULL_TREE, init);
+      vid->last_init = &TREE_CHAIN (*vid->last_init);
     }
 }
 
@@ -7381,28 +7673,23 @@ build_rtti_vtbl_entries (binfo, rtti_binfo, vod)
    ABI.)  */
 
 static tree
-build_vtable_entry (delta, vcall_index, entry)
+build_vtable_entry (delta, vcall_index, entry, generate_with_vtable_p)
      tree delta;
      tree vcall_index;
      tree entry;
+     int generate_with_vtable_p;
 {
-  if (!vcall_index)
-    vcall_index = integer_zero_node;
-
   if (flag_vtable_thunks)
     {
-      HOST_WIDE_INT idelta;
-      HOST_WIDE_INT ivindex;
       tree fn;
 
-      idelta = tree_low_cst (delta, 0);
-      ivindex = tree_low_cst (vcall_index, 0);
       fn = TREE_OPERAND (entry, 0);
-      if ((idelta || ivindex) 
+      if ((!integer_zerop (delta) || vcall_index != NULL_TREE)
          && fn != abort_fndecl
          && !DECL_TINFO_FN_P (fn))
        {
-         entry = make_thunk (entry, idelta, ivindex);
+         entry = make_thunk (entry, delta, vcall_index,
+                             generate_with_vtable_p);
          entry = build1 (ADDR_EXPR, vtable_entry_type, entry);
          TREE_READONLY (entry) = 1;
          TREE_CONSTANT (entry) = 1;
@@ -7420,7 +7707,7 @@ build_vtable_entry (delta, vcall_index, entry)
       tree entry = build (CONSTRUCTOR, vtable_entry_type, NULL_TREE, elems);
 
       /* We don't use vcall offsets when not using vtable thunks.  */
-      my_friendly_assert (integer_zerop (vcall_index), 20000125);
+      my_friendly_assert (vcall_index == NULL_TREE, 20000125);
 
       /* DELTA used to be constructed by `size_int' and/or size_binop,
         which caused overflow problems when it was negative.  That should