OSDN Git Service

* class.c (pushclass): Remove #if 0'd code.
[pf3gnuchains/gcc-fork.git] / gcc / cp / class.c
index f3a94dc..db4b480 100644 (file)
@@ -38,12 +38,6 @@ Boston, MA 02111-1307, USA.  */
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
 
-/* This is how we tell when two virtual member functions are really the
-   same.  */
-#define SAME_FN(FN1DECL, FN2DECL) (DECL_ASSEMBLER_NAME (FN1DECL) == DECL_ASSEMBLER_NAME (FN2DECL))
-
-extern void set_class_shadows PARAMS ((tree));
-
 /* The number of nested classes being processed.  If we are not in the
    scope of any class, this is zero.  */
 
@@ -68,22 +62,57 @@ typedef struct class_stack_node {
   splay_tree names_used;
 }* class_stack_node_t;
 
+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
+     are in order from least negative index to most negative index.  */
+  tree inits;
+  /* The last (i.e., most negative entry in INITS.  */
+  tree* last_init;
+  /* The binfo for the virtual base for which we're building
+     vcall offset initializers.  */
+  tree vbase;
+  /* The functions in vbase for which we have already provided vcall
+     offsets.  */
+  varray_type fns;
+  /* The vtable index of the next vcall or vbase offset.  */
+  tree index;
+  /* Nonzero if we are building the initializer for the primary
+     vtable.  */
+  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.  */
 static int current_class_stack_size;
 static class_stack_node_t current_class_stack;
 
+/* An array of all local classes present in this translation unit, in
+   declaration order.  */
+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));
 static int build_primary_vtable PARAMS ((tree, tree));
 static int build_secondary_vtable PARAMS ((tree, tree));
 static tree dfs_finish_vtbls PARAMS ((tree, void *));
-static tree dfs_accumulate_vtbl_inits PARAMS ((tree, void *));
+static tree dfs_accumulate_vtbl_inits PARAMS ((tree, tree, tree, tree,
+                                              tree));
 static void finish_vtbls PARAMS ((tree));
 static void modify_vtable_entry PARAMS ((tree, tree, tree, tree, tree *));
 static void add_virtual_function PARAMS ((tree *, tree *, int *, tree, tree));
@@ -92,7 +121,7 @@ static void delete_duplicate_fields PARAMS ((tree));
 static void finish_struct_bits PARAMS ((tree));
 static int alter_access PARAMS ((tree, tree, tree));
 static void handle_using_decl PARAMS ((tree, tree));
-static int overrides PARAMS ((tree, tree));
+static int same_signature_p PARAMS ((tree, tree));
 static int strictly_overrides PARAMS ((tree, tree));
 static void mark_overriders PARAMS ((tree, tree));
 static void check_for_override PARAMS ((tree, tree));
@@ -106,9 +135,9 @@ 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));
+static tree build_vtbl_initializer PARAMS ((tree, tree, tree, tree, int *));
 static int count_fields PARAMS ((tree));
 static int add_fields_to_vec PARAMS ((tree, tree, int));
 static void check_bitfield_decl PARAMS ((tree));
@@ -116,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 *));
@@ -127,41 +157,56 @@ 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 tree dfs_build_vbase_offset_vtbl_entries PARAMS ((tree, void *));
-static tree build_vbase_offset_vtbl_entries PARAMS ((tree, tree));
-static tree dfs_vcall_offset_queue_p PARAMS ((tree, void *));
-static tree dfs_build_vcall_offset_vtbl_entries PARAMS ((tree, void *));
-static tree build_vcall_offset_vtbl_entries PARAMS ((tree, tree));
-static tree dfs_count_virtuals PARAMS ((tree, void *));
+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 int num_vfun_entries PARAMS ((tree));
 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));
-extern void dump_class_hierarchy PARAMS ((tree, int));
+static void dump_class_hierarchy_r PARAMS ((tree, tree, int));
+extern void dump_class_hierarchy PARAMS ((tree));
 static tree build_vtable PARAMS ((tree, tree, tree));
 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 accumulate_vtbl_inits PARAMS ((tree, tree));
+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 tree build_rtti_vtbl_entries PARAMS ((tree, tree));
+static void build_rtti_vtbl_entries PARAMS ((tree, tree, vtbl_init_data *));
+static void build_vcall_and_vbase_vtbl_entries PARAMS ((tree, 
+                                                       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));
+static tree build_clone PARAMS ((tree, tree));
+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, int, tree *, tree *));
+static tree dfs_build_secondary_vptr_vtt_inits PARAMS ((tree, void *));
+static tree dfs_fixup_binfo_vtbls PARAMS ((tree, void *));
+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.  */
 
@@ -231,7 +276,7 @@ build_vbase_pointer_fields (rli, empty_p)
            {
              tree other_base_binfo = TREE_VEC_ELT (binfos, j);
              if (! TREE_VIA_VIRTUAL (other_base_binfo)
-                 && BINFO_FOR_VBASE (basetype, BINFO_TYPE (other_base_binfo)))
+                 && binfo_for_vbase (basetype, BINFO_TYPE (other_base_binfo)))
                goto got_it;
            }
          FORMAT_VBASE_NAME (name, basetype);
@@ -270,13 +315,14 @@ build_vbase_pointer (exp, type)
 
       /* Find the shared copy of TYPE; that's where the vtable offset
         is recorded.  */
-      vbase = BINFO_FOR_VBASE (type, TREE_TYPE (exp));
+      vbase = binfo_for_vbase (type, TREE_TYPE (exp));
       /* Find the virtual function table pointer.  */
       vbase_ptr = build_vfield_ref (exp, TREE_TYPE (exp));
       /* Compute the location where the offset will lie.  */
-      vbase_ptr = build_binary_op (PLUS_EXPR, 
-                                  vbase_ptr,
-                                  BINFO_VPTR_FIELD (vbase));
+      vbase_ptr = build (PLUS_EXPR, 
+                        TREE_TYPE (vbase_ptr),
+                        vbase_ptr,
+                        BINFO_VPTR_FIELD (vbase));
       vbase_ptr = build1 (NOP_EXPR, 
                          build_pointer_type (ptrdiff_type_node),
                          vbase_ptr);
@@ -462,7 +508,9 @@ build_vtable_entry_ref (basetype, vtbl, idx)
   static char asm_stmt[] = ".vtable_entry %c0, %c1";
   tree s, i, i2;
 
-  s = build_unary_op (ADDR_EXPR, TYPE_BINFO_VTABLE (basetype), 0);
+  s = build_unary_op (ADDR_EXPR, 
+                     get_vtbl_decl_for_binfo (TYPE_BINFO (basetype)), 
+                     0);
   s = build_tree_list (build_string (1, "s"), s);
 
   i = build_array_ref (vtbl, idx);
@@ -471,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],
@@ -533,7 +581,23 @@ build_vtbl_ref (instance, idx)
          && (TREE_CODE (instance) == RESULT_DECL
              || TREE_CODE (instance) == PARM_DECL
              || TREE_CODE (instance) == VAR_DECL))
-       vtbl = TYPE_BINFO_VTABLE (basetype);
+       {
+         vtbl = TYPE_BINFO_VTABLE (basetype);
+         /* Knowing the dynamic type of INSTANCE we can easily obtain
+            the correct vtable entry.  In the new ABI, we resolve
+            this back to be in terms of the primary vtable.  */
+         if (TREE_CODE (vtbl) == PLUS_EXPR)
+           {
+             idx = fold (build (PLUS_EXPR,
+                                TREE_TYPE (idx),
+                                idx,
+                                build (EXACT_DIV_EXPR,
+                                       TREE_TYPE (idx),
+                                       TREE_OPERAND (vtbl, 1),
+                                       TYPE_SIZE_UNIT (vtable_entry_type))));
+             vtbl = get_vtbl_decl_for_binfo (TYPE_BINFO (basetype));
+           }
+       }
       else
        vtbl = build_vfield_ref (instance, basetype);
     }
@@ -589,22 +653,25 @@ static tree
 get_vtable_name (type)
      tree type;
 {
-  tree type_id = build_typename_overload (type);
-  char *buf = (char *) alloca (strlen (VTABLE_NAME_PREFIX)
-                              + IDENTIFIER_LENGTH (type_id) + 2);
-  const char *ptr = IDENTIFIER_POINTER (type_id);
-  int i;
-  for (i = 0; ptr[i] == OPERATOR_TYPENAME_FORMAT[i]; i++) ;
-#if 0
-  /* We don't take off the numbers; build_secondary_vtable uses the
-     DECL_ASSEMBLER_NAME for the type, which includes the number
-     in `3foo'.  If we were to pull them off here, we'd end up with
-     something like `_vt.foo.3bar', instead of a uniform definition.  */
-  while (ptr[i] >= '0' && ptr[i] <= '9')
-    i += 1;
-#endif
-  sprintf (buf, "%s%s", VTABLE_NAME_PREFIX, ptr+i);
-  return get_identifier (buf);
+  if (flag_new_abi)
+    return mangle_vtbl_for_type (type);
+  else
+    return build_overload_with_type (get_identifier (VTABLE_NAME_PREFIX),
+                                    type);
+}
+
+/* Return an IDENTIFIER_NODE for the name of the virtual table table
+   for TYPE.  */
+
+tree
+get_vtt_name (type)
+     tree type;
+{
+  if (flag_new_abi)
+    return mangle_vtt_for_type (type);
+  else
+    return build_overload_with_type (get_identifier (VTT_NAME_PREFIX),
+                                    type);
 }
 
 /* Return the offset to the main vtable for a given base BINFO.  */
@@ -624,31 +691,23 @@ get_vfield_offset (binfo)
    on method calling is expected to point to a DECL_CONTEXT (fndecl)
    object, and not a baseclass of it.   */
 
-
 static tree
 get_derived_offset (binfo, type)
      tree 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);
 }
 
-/* Create a VAR_DECL for a primary or secondary vtable for
-   CLASS_TYPE.  Use NAME for the name of the vtable, and VTABLE_TYPE
-   for its type.  */
+/* Create a VAR_DECL for a primary or secondary vtable for CLASS_TYPE.
+   (For a secondary vtable for B-in-D, CLASS_TYPE should be D, not B.)
+   Use NAME for the name of the vtable, and VTABLE_TYPE for its type.  */
 
 static tree
 build_vtable (class_type, name, vtable_type)
@@ -695,7 +754,8 @@ get_vtable_decl (type, complete)
   
   decl = build_vtable (type, name, void_type_node);
   decl = pushdecl_top_level (decl);
-  SET_IDENTIFIER_GLOBAL_VALUE (name, decl);
+  my_friendly_assert (IDENTIFIER_GLOBAL_VALUE (name) == decl,
+                     20000517);
   
   /* At one time the vtable info was grabbed 2 words at a time.  This
      fails on sparc unless you have 8-byte alignment.  (tiemann) */
@@ -711,6 +771,27 @@ get_vtable_decl (type, complete)
   return decl;
 }
 
+/* Returns a copy of the BINFO_VIRTUALS list in BINFO.  The
+   BV_VCALL_INDEX for each entry is cleared.  */
+
+static tree
+copy_virtuals (binfo)
+     tree binfo;
+{
+  tree copies;
+  tree t;
+
+  copies = copy_list (BINFO_VIRTUALS (binfo));
+  for (t = copies; t; t = TREE_CHAIN (t))
+    {
+      BV_VCALL_INDEX (t) = NULL_TREE;
+      BV_USE_VCALL_INDEX_P (t) = 0;
+      BV_GENERATE_THUNK_WITH_VTABLE_P (t) = 0;
+    }
+
+  return copies;
+}
+      
 /* Build the primary virtual function table for TYPE.  If BINFO is
    non-NULL, build the vtable starting with the initial approximation
    that it is the same as the one which is the head of the association
@@ -721,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);
   
@@ -732,11 +814,10 @@ build_primary_vtable (binfo, type)
           no need to do it again.  */
        return 0;
       
-      virtuals = copy_list (BINFO_VIRTUALS (binfo));
-      TREE_TYPE (decl) = TREE_TYPE (BINFO_VTABLE (binfo));
-      DECL_SIZE (decl) = TYPE_SIZE (TREE_TYPE (BINFO_VTABLE (binfo)));
-      DECL_SIZE_UNIT (decl)
-       = TYPE_SIZE_UNIT (TREE_TYPE (BINFO_VTABLE (binfo)));
+      virtuals = copy_virtuals (binfo);
+      TREE_TYPE (decl) = TREE_TYPE (get_vtbl_decl_for_binfo (binfo));
+      DECL_SIZE (decl) = TYPE_SIZE (TREE_TYPE (decl));
+      DECL_SIZE_UNIT (decl) = TYPE_SIZE_UNIT (TREE_TYPE (decl));
     }
   else
     {
@@ -754,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;
 }
 
@@ -784,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;
 
@@ -793,7 +873,7 @@ build_secondary_vtable (binfo, for_type)
 #endif
 
   if (TREE_VIA_VIRTUAL (binfo))
-    my_friendly_assert (binfo == BINFO_FOR_VBASE (BINFO_TYPE (binfo),
+    my_friendly_assert (binfo == binfo_for_vbase (BINFO_TYPE (binfo),
                                                  current_class_type),
                        170);
 
@@ -807,11 +887,11 @@ build_secondary_vtable (binfo, for_type)
   SET_BINFO_NEW_VTABLE_MARKED (binfo, current_class_type);
   
   /* Make fresh virtual list, so we can smash it later.  */
-  BINFO_VIRTUALS (binfo) = copy_list (BINFO_VIRTUALS (binfo));
+  BINFO_VIRTUALS (binfo) = copy_virtuals (binfo);
 
   if (TREE_VIA_VIRTUAL (binfo))
     {
-      tree binfo1 = BINFO_FOR_VBASE (BINFO_TYPE (binfo), for_type);
+      tree binfo1 = binfo_for_vbase (BINFO_TYPE (binfo), for_type);
 
       /* XXX - This should never happen, if it does, the caller should
         ensure that the binfo is from for_type's binfos, not from any
@@ -913,6 +993,7 @@ build_secondary_vtable (binfo, for_type)
 
   new_decl = build_vtable (for_type, name, TREE_TYPE (orig_decl));
   DECL_ALIGN (new_decl) = DECL_ALIGN (orig_decl);
+  DECL_USER_ALIGN (new_decl) = DECL_USER_ALIGN (orig_decl);
   BINFO_VTABLE (binfo) = pushdecl_top_level (new_decl);
 
 #ifdef GATHER_STATISTICS
@@ -947,9 +1028,9 @@ make_new_vtable (t, binfo)
 
 /* Make *VIRTUALS, an entry on the BINFO_VIRTUALS list for BINFO
    (which is in the hierarchy dominated by T) list FNDECL as its
-   BV_FN.  DELTA is the required adjustment from the `this' pointer
-   where the vtable entry appears to the `this' required when the
-   function is actually called.  */
+   BV_FN.  DELTA is the required constant adjustment from the `this'
+   pointer where the vtable entry appears to the `this' required when
+   the function is actually called.  */
 
 static void
 modify_vtable_entry (t, binfo, fndecl, delta, virtuals)
@@ -959,15 +1040,12 @@ modify_vtable_entry (t, binfo, fndecl, delta, virtuals)
      tree delta;
      tree *virtuals;
 {
-  tree vcall_index;
   tree v;
 
   v = *virtuals;
-  vcall_index = integer_zero_node;
 
   if (fndecl != BV_FN (v)
-      || !tree_int_cst_equal (delta, BV_DELTA (v))
-      || !tree_int_cst_equal (vcall_index, BV_VCALL_INDEX (v)))
+      || !tree_int_cst_equal (delta, BV_DELTA (v)))
     {
       tree base_fndecl;
 
@@ -985,7 +1063,7 @@ modify_vtable_entry (t, binfo, fndecl, delta, virtuals)
 
       base_fndecl = BV_FN (v);
       BV_DELTA (v) = delta;
-      BV_VCALL_INDEX (v) = vcall_index;
+      BV_VCALL_INDEX (v) = NULL_TREE;
       BV_FN (v) = fndecl;
 
       /* Now assign virtual dispatch information, if unset.  We can
@@ -1057,8 +1135,9 @@ add_virtual_function (new_virtuals_p, overridden_virtuals_p,
     /* We've already dealt with this function.  */
     return;
 
-  new_virtual = build_tree_list (integer_zero_node, fndecl);
-  BV_VCALL_INDEX (new_virtual) = integer_zero_node;
+  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)
     {
@@ -1084,191 +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);
-
-      if (DECL_NAME (method) == constructor_name (type))
-       /* A new constructor or destructor.  Constructors go in 
-          slot 0; destructors go in slot 1.  */
-       slot = DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (method)) ? 1 : 0;
-      else
-       {
-         /* See if we already have an entry with this name.  */
-         for (slot = 2; 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.  */
@@ -1384,7 +1471,12 @@ alter_access (t, fdecl, access)
      tree fdecl;
      tree access;
 {
-  tree elem = purpose_member (t, DECL_ACCESS (fdecl));
+  tree elem;
+
+  if (!DECL_LANG_SPECIFIC (fdecl))
+    retrofit_lang_decl (fdecl);
+
+  elem = purpose_member (t, DECL_ACCESS (fdecl));
   if (elem)
     {
       if (TREE_VALUE (elem) != access)
@@ -1465,8 +1557,6 @@ handle_using_decl (using_decl, t)
 
   if (is_overloaded_fn (fdecl))
     flist = fdecl;
-  else if (! DECL_LANG_SPECIFIC (fdecl))
-    my_friendly_abort (20000221);
 
   if (! old_value)
     ;
@@ -1494,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
@@ -1623,18 +1713,107 @@ check_bases (t, cant_have_default_ctor_p, cant_have_const_ctor_p,
     }
 }
 
-/* Make the Ith baseclass of T its primary base.  */
+/* Called via dfs_walk from mark_primary_bases.  Sets
+   BINFO_PRIMARY_MARKED_P for BINFO, if appropriate.  */
+
+static tree
+dfs_mark_primary_bases (binfo, data)
+     tree binfo;
+     void *data;
+{
+  tree base_binfo;
+
+  if (!CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (binfo)))
+    return NULL_TREE;
+
+  base_binfo = get_primary_binfo (binfo);
+
+  if (TREE_VIA_VIRTUAL (base_binfo))
+    {
+      tree shared_binfo;
+      tree type;
+
+      type = (tree) data;
+      shared_binfo = binfo_for_vbase (BINFO_TYPE (base_binfo), type);
+
+      /* If this virtual base is not already primary somewhere else in
+        the hiearchy, then we'll be using this copy.  */
+      if (!BINFO_PRIMARY_MARKED_P (shared_binfo))
+       {
+         /* Make sure the CLASSTYPE_VBASECLASSES list contains the
+            primary copy; it's the one that really exists.  */
+         if (base_binfo != shared_binfo)
+           TREE_VALUE (purpose_member (BINFO_TYPE (base_binfo),
+                                       CLASSTYPE_VBASECLASSES (type)))
+             = base_binfo;
+       }
+      else
+       base_binfo = NULL_TREE;
+    }
+
+  if (base_binfo)
+    BINFO_PRIMARY_BASE_OF (base_binfo) = binfo;
+
+  return NULL_TREE;
+}
+
+/* Set BINFO_PRIMARY_MARKED_P for all binfos in the hierarchy
+   dominated by BINFO that are primary bases.  */
+
+static void
+mark_primary_bases (type)
+     tree type;
+{
+  tree vbases;
+
+  /* Mark the TYPE_BINFO hierarchy.  We need to mark primary bases in
+     pre-order to deal with primary virtual bases.  (The virtual base
+     would be skipped if it were not marked as primary, and that
+     requires getting to dfs_mark_primary_bases before
+     dfs_skip_nonprimary_vbases_unmarkedp has a chance to skip the
+     virtual base.)  */
+  dfs_walk_real (TYPE_BINFO (type), dfs_mark_primary_bases, NULL,
+                dfs_skip_nonprimary_vbases_unmarkedp, type);
+
+  /* Now go through the virtual base classes in inheritance graph
+     order.  Any that are not already primary will need to be
+     allocated in TYPE, and so we need to mark their primary bases.  */
+  for (vbases = TYPE_BINFO (type); vbases; vbases = TREE_CHAIN (vbases))
+    {
+      tree vbase;
+
+      /* Make sure that only BINFOs appear on this list.
+        Historically, the TREE_CHAIN was used for other purposes, and
+        we want to make sure that none of those uses remain.  */
+      my_friendly_assert (TREE_CODE (vbases) == TREE_VEC, 20000402);
+
+      if (!TREE_VIA_VIRTUAL (vbases))
+       continue;
+
+      vbase = binfo_for_vbase (BINFO_TYPE (vbases), type);
+      if (BINFO_PRIMARY_MARKED_P (vbase))
+       /* This virtual base was already included in the hierarchy, so
+          there's nothing to do here.  */
+       continue;
+
+      /* Now, walk its bases.  */
+      dfs_walk_real (vbase, dfs_mark_primary_bases, NULL,
+                    dfs_skip_nonprimary_vbases_unmarkedp, type);
+    }
+}
+
+/* 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);
@@ -1650,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))
@@ -1678,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
@@ -1696,32 +1877,96 @@ determine_primary_base (t, vfuns_p)
                                 VF_BASETYPE_VALUE (vfields),
                                 CLASSTYPE_VFIELDS (t));
 
-             if (*vfuns_p == 0)
-               set_primary_base (t, i, vfuns_p);
+             if (!flag_new_abi && *vfuns_p == 0)
+               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))
-    for (i = 0; i < n_baseclasses; ++i)
-      {
-       tree base_binfo = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (t), i);
-       tree basetype = BINFO_TYPE (base_binfo);
+    {
+      /* If not NULL, this is the best primary base candidate we have
+         found so far.  */
+      tree candidate = NULL_TREE;
+      tree base_binfo;
 
-       if (TREE_VIA_VIRTUAL (base_binfo) 
-           && CLASSTYPE_NEARLY_EMPTY_P (basetype))
-         {
-           set_primary_base (t, i, vfuns_p);
-           CLASSTYPE_VFIELDS (t) = copy_list (CLASSTYPE_VFIELDS (basetype));
-           break;
-         }
-      }
+      /* Loop over the baseclasses.  */
+      for (base_binfo = TYPE_BINFO (t);
+          base_binfo;
+          base_binfo = TREE_CHAIN (base_binfo))
+       {
+         tree basetype = BINFO_TYPE (base_binfo);
+
+         if (TREE_VIA_VIRTUAL (base_binfo) 
+             && CLASSTYPE_NEARLY_EMPTY_P (basetype))
+           {
+             /* If this is not an indirect primary base, then it's
+                definitely our primary base.  */
+             if (!BINFO_INDIRECT_PRIMARY_P (base_binfo))
+               {
+                 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)
+               candidate = base_binfo;
+           }
+       }
+
+      /* If we've got a primary base, use it.  */
+      if (candidate)
+       {
+         set_primary_base (t, candidate, vfuns_p);
+         CLASSTYPE_VFIELDS (t) 
+           = copy_list (CLASSTYPE_VFIELDS (BINFO_TYPE (candidate)));
+       }       
+    }
 
   /* Mark the primary base classes at this point.  */
   mark_primary_bases (t);
@@ -2003,14 +2248,9 @@ method_name_cmp (m1, m2)
    list.  That allows them to be quickly deleted, and requires no
    extra storage.
 
-   If there are any constructors/destructors, they are moved to the
-   front of the list.  This makes pushclass more efficient.
-
-   @@ The above comment is obsolete.  It mostly describes what add_method
-   @@ and add_implicitly_declared_members do.
-
-   Sort methods that are not special (i.e., constructors, destructors, and
-   type conversion operators) so that we can find them faster in search.  */
+   Sort methods that are not special (i.e., constructors, destructors,
+   and type conversion operators) so that we can find them faster in
+   search.  */
 
 static void
 finish_struct_methods (t)
@@ -2018,7 +2258,6 @@ finish_struct_methods (t)
 {
   tree fn_fields;
   tree method_vec;
-  tree ctor_name = constructor_name (t);
   int slot, len;
 
   if (!TYPE_METHODS (t))
@@ -2039,52 +2278,10 @@ finish_struct_methods (t)
      and the next few with type conversion operators (if any).  */
   for (fn_fields = TYPE_METHODS (t); fn_fields; 
        fn_fields = TREE_CHAIN (fn_fields))
-    {
-      tree fn_name = DECL_NAME (fn_fields);
-
-      /* Clear out this flag.
-
-        @@ Doug may figure out how to break
-        @@ this with nested classes and friends.  */
-      DECL_IN_AGGR_P (fn_fields) = 0;
-
-      /* Note here that a copy ctor is private, so we don't dare generate
-        a default copy constructor for a class that has a member
-        of this type without making sure they have access to it.  */
-      if (fn_name == ctor_name)
-       {
-         tree parmtypes = FUNCTION_ARG_CHAIN (fn_fields);
-         tree parmtype = parmtypes ? TREE_VALUE (parmtypes) : void_type_node;
-         
-         if (TREE_CODE (parmtype) == REFERENCE_TYPE
-             && TYPE_MAIN_VARIANT (TREE_TYPE (parmtype)) == t)
-           {
-             if (TREE_CHAIN (parmtypes) == NULL_TREE
-                 || TREE_CHAIN (parmtypes) == void_list_node
-                 || TREE_PURPOSE (TREE_CHAIN (parmtypes)))
-               {
-                 if (TREE_PROTECTED (fn_fields))
-                   TYPE_HAS_NONPUBLIC_CTOR (t) = 1;
-                 else if (TREE_PRIVATE (fn_fields))
-                   TYPE_HAS_NONPUBLIC_CTOR (t) = 2;
-               }
-           }
-       }
-      else if (fn_name == ansi_opname[(int) MODIFY_EXPR])
-       {
-         tree parmtype = TREE_VALUE (FUNCTION_ARG_CHAIN (fn_fields));
-
-         if (copy_assignment_arg_p (parmtype, DECL_VIRTUAL_P (fn_fields)))
-           {
-             if (TREE_PROTECTED (fn_fields))
-               TYPE_HAS_NONPUBLIC_ASSIGN_REF (t) = 1;
-             else if (TREE_PRIVATE (fn_fields))
-               TYPE_HAS_NONPUBLIC_ASSIGN_REF (t) = 2;
-           }
-       }
-    }
+    /* Clear out this flag.  */
+    DECL_IN_AGGR_P (fn_fields) = 0;
 
-  if (TYPE_HAS_DESTRUCTOR (t) && !TREE_VEC_ELT (method_vec, 1))
+  if (TYPE_HAS_DESTRUCTOR (t) && !CLASSTYPE_DESTRUCTORS (t))
     /* We thought there was a destructor, but there wasn't.  Some
        parse errors cause this anomalous situation.  */
     TYPE_HAS_DESTRUCTOR (t) = 0;
@@ -2154,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;
@@ -2184,6 +2381,7 @@ layout_vtable_decl (binfo, n)
 {
   tree itype;
   tree atype;
+  tree vtable;
 
   itype = size_int (n);
   atype = build_cplus_array_type (vtable_entry_type, 
@@ -2191,12 +2389,11 @@ layout_vtable_decl (binfo, n)
   layout_type (atype);
 
   /* We may have to grow the vtable.  */
-  if (!same_type_p (TREE_TYPE (BINFO_VTABLE (binfo)), atype))
+  vtable = get_vtbl_decl_for_binfo (binfo);
+  if (!same_type_p (TREE_TYPE (vtable), atype))
     {
-      tree vtable = BINFO_VTABLE (binfo);
-
       TREE_TYPE (vtable) = atype;
-      DECL_SIZE (vtable) = DECL_SIZE_UNIT (vtable) = 0;
+      DECL_SIZE (vtable) = DECL_SIZE_UNIT (vtable) = NULL_TREE;
       layout_decl (vtable, 0);
 
       /* At one time the vtable info was grabbed 2 words at a time.  This
@@ -2206,125 +2403,28 @@ layout_vtable_decl (binfo, n)
     }
 }
 
-/* Returns the number of virtual function table entries (excluding
-   RTTI information, vbase and vcall offests, etc.) in the vtable for
-   BINFO.  */
-
-static int
-num_vfun_entries (binfo)
-     tree binfo;
-{
-  return list_length (BINFO_VIRTUALS (binfo));
-}
-
-typedef struct vcall_offset_data_s
-{
-  /* The binfo for the most-derived type.  */
-  tree derived;
-  /* The binfo for the virtual base for which we're building
-     initializers.  */
-  tree vbase;
-  /* The vcall offset initializers built up so far.  */
-  tree inits;
-  /* The number of vcall offsets accumulated.  */
-  int offsets;
-} vcall_offset_data;
-
-/* Called from num_extra_vtbl_entries via dfs_walk.  */
-
-static tree
-dfs_count_virtuals (binfo, data)
-     tree binfo;
-     void *data;
-{
-  /* Non-primary bases are not interesting; all of the virtual
-     function table entries have been overridden.  */
-  if (!BINFO_PRIMARY_MARKED_P (binfo))
-    ((vcall_offset_data *) data)->offsets += num_vfun_entries (binfo);
-  
-  return NULL_TREE;
-}
-
-/* Returns the number of extra entries (at negative indices) required
-   for BINFO's vtable.  */
-
-tree
-num_extra_vtbl_entries (binfo)
-     tree binfo;
-{
-  tree type;
-  int entries;
-
-  type = BINFO_TYPE (binfo);
-  entries = 0;
-
-  /* There is an entry for the offset to each virtual base.  */
-  if (vbase_offsets_in_vtable_p ())
-    entries += list_length (CLASSTYPE_VBASECLASSES (type));
-
-  /* If this is a virtual base, there are entries for each virtual
-     function defined in this class or its bases.  */
-  if (vcall_offsets_in_vtable_p () && TREE_VIA_VIRTUAL (binfo))
-    {
-      vcall_offset_data vod;
-
-      vod.vbase = binfo;
-      vod.offsets = 0;
-      dfs_walk (binfo,
-               dfs_count_virtuals,
-               dfs_vcall_offset_queue_p,
-               &vod);
-      entries += vod.offsets;
-    }
-      
-  /* When laying out COM-compatible classes, there are no RTTI
-     entries.  */
-  if (CLASSTYPE_COM_INTERFACE (type))
-    ;
-  /* When using vtable thunks, there are two RTTI entries: the "offset
-     to top" value and the RTTI entry itself.  */
-  else if (flag_vtable_thunks)
-    entries += 2;
-  /* When not using vtable thunks there is only a single entry.  */
-  else
-    entries += 1;
-
-  return size_int (entries);
-}
-
-/* Returns the offset (in bytes) from the beginning of BINFO's vtable
-   where the vptr should actually point.  */
-
-tree
-size_extra_vtbl_entries (binfo)
-     tree binfo;
-{
-  tree offset = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (vtable_entry_type),
-                           num_extra_vtbl_entries (binfo));
-  return fold (offset);
-}
-
-/* True if we should override the given BASE_FNDECL with the given
-   FNDECL.  */
+/* True iff FNDECL and BASE_FNDECL (both non-static member functions)
+   have the same signature.  */
 
 static int
-overrides (fndecl, base_fndecl)
+same_signature_p (fndecl, base_fndecl)
      tree fndecl, base_fndecl;
 {
-  /* Destructors have special names.  */
-  if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (base_fndecl))
-      && DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
+  /* One destructor overrides another if they are the same kind of
+     destructor.  */
+  if (DECL_DESTRUCTOR_P (base_fndecl) && DECL_DESTRUCTOR_P (fndecl)
+      && special_function_p (base_fndecl) == special_function_p (fndecl))
     return 1;
-  if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (base_fndecl))
-      || DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
+  /* But a non-destructor never overrides a destructor, nor vice
+     versa, nor do different kinds of destructors override
+     one-another.  For example, a complete object destructor does not
+     override a deleting destructor.  */
+  if (DECL_DESTRUCTOR_P (base_fndecl) || DECL_DESTRUCTOR_P (fndecl))
     return 0;
+
   if (DECL_NAME (fndecl) == DECL_NAME (base_fndecl))
     {
       tree types, base_types;
-#if 0
-      retypes = TREE_TYPE (TREE_TYPE (fndecl));
-      base_retypes = TREE_TYPE (TREE_TYPE (base_fndecl));
-#endif
       types = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
       base_types = TYPE_ARG_TYPES (TREE_TYPE (base_fndecl));
       if ((TYPE_QUALS (TREE_TYPE (TREE_VALUE (base_types)))
@@ -2366,16 +2466,19 @@ 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))
        {
          for (method = TYPE_METHODS (BINFO_TYPE (TREE_VALUE (path)));
               method;
               method = TREE_CHAIN (method))
-           if (DECL_VIRTUAL_P (method) && overrides (method, ffod->fn))
+           if (DECL_VIRTUAL_P (method) 
+               && same_signature_p (method, ffod->fn))
              break;
 
          if (method)
@@ -2386,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
@@ -2482,16 +2604,124 @@ 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).  */
+/* 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.  */
 
-static tree
-dfs_find_base (binfo, data)
+static void
+update_vtable_entry_for_fn (t, binfo, fn, virtuals)
+     tree t;
      tree binfo;
-     void *data;
+     tree fn;
+     tree *virtuals;
 {
-  return (same_type_p (BINFO_TYPE (binfo), (tree) data)
-         ? binfo : NULL_TREE);
+  tree b;
+  tree overrider;
+  tree delta;
+  tree virtual_base;
+  int generate_thunk_with_vtable_p;
+
+  /* Find the function which originally caused this vtable
+     entry to be present.  */
+  b = binfo;
+  while (1)
+    {
+      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;
+    }
+
+  /* Find the final overrider.  */
+  overrider = find_final_overrider (t, b, fn);
+  if (overrider == error_mark_node)
+    return;
+
+  /* Compute the constant adjustment to the `this' pointer.  The
+     `this' pointer, when this function is called, will point at the
+     class whose vtable this is.  */
+  delta = size_binop (PLUS_EXPR,
+                     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)
+    {
+      while (b)
+       {
+         /* 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
+    virtual_base = NULL_TREE;
+
+  if (virtual_base)
+    /* The `this' pointer needs to be adjusted to the nearest virtual
+       base.  */
+    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
+       appears.  */
+    delta = size_diffop (BINFO_OFFSET (TREE_VALUE (overrider)), delta);
+
+  modify_vtable_entry (t, 
+                      binfo, 
+                      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.  */
@@ -2527,51 +2757,10 @@ dfs_modify_vtables (binfo, data)
           virtuals;
           virtuals = TREE_CHAIN (virtuals),
             old_virtuals = TREE_CHAIN (old_virtuals))
-       {
-         tree b;
-         tree fn;
-         tree overrider;
-         tree vindex;
-         tree delta;
-         HOST_WIDE_INT vindex_val;
-         HOST_WIDE_INT i;
-
-         /* Find the function which originally caused this vtable
-            entry to be present.  */
-         fn = BV_FN (old_virtuals);
-         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)
-           {
-             fn = TREE_CHAIN (fn);
-             ++i;
-           }
-         fn = BV_FN (fn);
-
-         /* Handle the case of a virtual function defined in BINFO
-            itself.  */
-         overrider = find_final_overrider (t, b, fn);
-         if (overrider == error_mark_node)
-           continue;
-
-         /* The `this' pointer needs to be adjusted from pointing to
-            BINFO to pointing at the base where the final overrider
-            appears.  */
-         delta = size_binop (PLUS_EXPR,
-                             get_derived_offset (binfo,
-                                                 DECL_VIRTUAL_CONTEXT (fn)),
-                             BINFO_OFFSET (binfo));
-         delta = size_diffop (BINFO_OFFSET (TREE_VALUE (overrider)), delta);
-
-         modify_vtable_entry (t, 
-                              binfo, 
-                              TREE_PURPOSE (overrider),
-                              delta,
-                              &virtuals);
-       }
+       update_vtable_entry_for_fn (t, 
+                                   binfo, 
+                                   BV_FN (old_virtuals),
+                                   &virtuals);
     }
 
   SET_BINFO_MARKED (binfo);
@@ -2615,8 +2804,8 @@ modify_all_vtables (t, vfuns_p, overridden_virtuals)
        {
          tree fn = TREE_VALUE (*fnsp);
 
-         if (BINFO_VIRTUALS (binfo)
-             && !value_member (fn, BINFO_VIRTUALS (binfo)))
+         if (!BINFO_VIRTUALS (binfo)
+             || !value_member (fn, BINFO_VIRTUALS (binfo)))
            {
              /* Set the vtable index.  */
              set_vindex (t, fn, vfuns_p);
@@ -2627,7 +2816,7 @@ modify_all_vtables (t, vfuns_p, overridden_virtuals)
              /* We don't need to adjust the `this' pointer when
                 calling this function.  */
              BV_DELTA (*fnsp) = integer_zero_node;
-             BV_VCALL_INDEX (*fnsp) = integer_zero_node;
+             BV_VCALL_INDEX (*fnsp) = NULL_TREE;
 
              /* This is an overridden function not already in our
                 vtable.  Keep it.  */
@@ -2709,10 +2898,8 @@ mark_overriders (fndecl, base_fndecls)
      tree fndecl, base_fndecls;
 {
   for (; base_fndecls; base_fndecls = TREE_CHAIN (base_fndecls))
-    {
-      if (overrides (fndecl, TREE_VALUE (base_fndecls)))
-       TREE_PURPOSE (base_fndecls) = fndecl;
-    }
+    if (same_signature_p (fndecl, TREE_VALUE (base_fndecls)))
+      TREE_PURPOSE (base_fndecls) = fndecl;
 }
 
 /* If this declaration supersedes the declaration of
@@ -2723,57 +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,
-            DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (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;
@@ -2839,15 +2993,13 @@ warn_hidden (t)
       /* Now give a warning for all base functions without overriders,
         as they are hidden.  */
       for (; base_fndecls; base_fndecls = TREE_CHAIN (base_fndecls))
-       {
-         if (! overrides (TREE_PURPOSE (base_fndecls),
-                          TREE_VALUE (base_fndecls)))
-           {
-             /* Here we know it is a hider, and no overrider exists.  */
-             cp_warning_at ("`%D' was hidden", TREE_VALUE (base_fndecls));
-             cp_warning_at ("  by `%D'", TREE_PURPOSE (base_fndecls));
-           }
-       }
+       if (!same_signature_p (TREE_PURPOSE (base_fndecls),
+                              TREE_VALUE (base_fndecls)))
+         {
+           /* Here we know it is a hider, and no overrider exists.  */
+           cp_warning_at ("`%D' was hidden", TREE_VALUE (base_fndecls));
+           cp_warning_at ("  by `%D'", TREE_PURPOSE (base_fndecls));
+         }
     }
 }
 
@@ -2901,36 +3053,33 @@ finish_struct_anon (t)
     }
 }
 
-extern int interface_only, interface_unknown;
-
 /* Create default constructors, assignment operators, and so forth for
    the type indicated by T, if they are needed.
    CANT_HAVE_DEFAULT_CTOR, CANT_HAVE_CONST_CTOR, and
-   CANT_HAVE_ASSIGNMENT are nonzero if, for whatever reason, the class
-   cannot have a default constructor, copy constructor taking a const
-   reference argument, or an assignment operator, respectively.  If a
-   virtual destructor is created, its DECL is returned; otherwise the
-   return value is NULL_TREE.  */
+   CANT_HAVE_CONST_ASSIGNMENT are nonzero if, for whatever reason, the
+   class cannot have a default constructor, copy constructor taking a
+   const reference argument, or an assignment operator taking a const
+   reference, respectively.  If a virtual destructor is created, its
+   DECL is returned; otherwise the return value is NULL_TREE.  */
 
 static tree
 add_implicitly_declared_members (t, cant_have_default_ctor,
                                 cant_have_const_cctor,
-                                cant_have_assignment)
+                                cant_have_const_assignment)
      tree t;
      int cant_have_default_ctor;
      int cant_have_const_cctor;
-     int cant_have_assignment;
+     int cant_have_const_assignment;
 {
   tree default_fn;
   tree implicit_fns = NULL_TREE;
-  tree name = TYPE_IDENTIFIER (t);
   tree virtual_dtor = NULL_TREE;
   tree *f;
 
   /* Destructor.  */
   if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) && !TYPE_HAS_DESTRUCTOR (t))
     {
-      default_fn = cons_up_default_function (t, name, 0);
+      default_fn = implicitly_declare_fn (sfk_destructor, t, /*const_p=*/0);
       check_for_override (default_fn, t);
 
       /* If we couldn't make it work, then pretend we didn't need it.  */
@@ -2952,7 +3101,7 @@ add_implicitly_declared_members (t, cant_have_default_ctor,
   /* Default constructor.  */
   if (! TYPE_HAS_CONSTRUCTOR (t) && ! cant_have_default_ctor)
     {
-      default_fn = cons_up_default_function (t, name, 2);
+      default_fn = implicitly_declare_fn (sfk_constructor, t, /*const_p=*/0);
       TREE_CHAIN (default_fn) = implicit_fns;
       implicit_fns = default_fn;
     }
@@ -2962,8 +3111,9 @@ add_implicitly_declared_members (t, cant_have_default_ctor,
     {
       /* ARM 12.18: You get either X(X&) or X(const X&), but
         not both.  --Chip  */
-      default_fn = cons_up_default_function (t, name,
-                                            3 + cant_have_const_cctor);
+      default_fn 
+       = implicitly_declare_fn (sfk_copy_constructor, t,
+                                /*const_p=*/!cant_have_const_cctor);
       TREE_CHAIN (default_fn) = implicit_fns;
       implicit_fns = default_fn;
     }
@@ -2971,8 +3121,9 @@ add_implicitly_declared_members (t, cant_have_default_ctor,
   /* Assignment operator.  */
   if (! TYPE_HAS_ASSIGN_REF (t) && ! TYPE_FOR_JAVA (t))
     {
-      default_fn = cons_up_default_function (t, name,
-                                            5 + cant_have_assignment);
+      default_fn 
+       = implicitly_declare_fn (sfk_assignment_operator, t,
+                                /*const_p=*/!cant_have_const_assignment);
       TREE_CHAIN (default_fn) = implicit_fns;
       implicit_fns = default_fn;
     }
@@ -2980,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;
 
@@ -3055,7 +3206,7 @@ check_bitfield_decl (field)
       /* detect invalid field size.  */
       if (TREE_CODE (w) == CONST_DECL)
        w = DECL_INITIAL (w);
-      else if (TREE_READONLY_DECL_P (w))
+      else
        w = decl_constant_value (w);
 
       if (TREE_CODE (w) != INTEGER_CST)
@@ -3107,8 +3258,11 @@ check_bitfield_decl (field)
 #endif
 #ifdef PCC_BITFIELD_TYPE_MATTERS
          if (PCC_BITFIELD_TYPE_MATTERS)
-           DECL_ALIGN (field) = MAX (DECL_ALIGN (field), 
-                                     TYPE_ALIGN (type));
+           {
+             DECL_ALIGN (field) = MAX (DECL_ALIGN (field), 
+                                       TYPE_ALIGN (type));
+             DECL_USER_ALIGN (field) |= TYPE_USER_ALIGN (type);
+           }
 #endif
        }
     }
@@ -3118,6 +3272,7 @@ check_bitfield_decl (field)
       DECL_BIT_FIELD (field) = 0;
       CLEAR_DECL_C_BIT_FIELD (field);
       DECL_ALIGN (field) = MAX (DECL_ALIGN (field), TYPE_ALIGN (type));
+      DECL_USER_ALIGN (field) |= TYPE_USER_ALIGN (type);
     }
 }
 
@@ -3208,6 +3363,8 @@ check_field_decl (field, t, cant_have_const_ctor,
                            (DECL_PACKED (field) 
                             ? BITS_PER_UNIT
                             : TYPE_ALIGN (TREE_TYPE (field))));
+  if (! DECL_PACKED (field))
+    DECL_USER_ALIGN (field) |= TYPE_USER_ALIGN (TREE_TYPE (field));
 }
 
 /* Check the data members (both static and non-static), class-scoped
@@ -3380,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);
@@ -3417,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))
@@ -3432,6 +3579,13 @@ check_field_decls (t, access_decls, empty_p,
            |= CLASSTYPE_READONLY_FIELDS_NEED_INIT (type);
        }
 
+      /* Core issue 80: A nonstatic data member is required to have a
+        different name from the class iff the class has a
+        user-defined constructor.  */
+      if (DECL_NAME (x) == constructor_name (t)
+         && TYPE_HAS_CONSTRUCTOR (t))
+       cp_pedwarn_at ("field `%#D' with same name as class", x);
+
       /* We set DECL_C_BIT_FIELD in grokbitfield.
         If the type and width are valid, we'll also set DECL_BIT_FIELD.  */
       if (DECL_C_BIT_FIELD (x))
@@ -3493,128 +3647,221 @@ build_vtbl_or_vbase_field (name, assembler_name, type, class_type, fcontext,
   *empty_p = 0;
 
   /* Build the FIELD_DECL.  */
-  field = build_lang_decl (FIELD_DECL, name, type);
+  field = build_decl (FIELD_DECL, name, type);
   DECL_ASSEMBLER_NAME (field) = assembler_name;
   DECL_VIRTUAL_P (field) = 1;
   DECL_ARTIFICIAL (field) = 1;
   DECL_FIELD_CONTEXT (field) = class_type;
   DECL_FCONTEXT (field) = fcontext;
   DECL_ALIGN (field) = TYPE_ALIGN (type);
+  DECL_USER_ALIGN (field) = TYPE_USER_ALIGN (type);
 
   /* Return it.  */
   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;
 
-  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));
+  if (!is_empty_class (type))
+    return 0;
 
-  return NULL_TREE;
+  /* 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 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 old_rli = *rli;
+      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.
@@ -3631,58 +3878,70 @@ 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 propogate_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);
   
   /* This routine should only be used for empty classes.  */
   my_friendly_assert (is_empty_class (basetype), 20000321);
-  alignment = ssize_int (CLASSTYPE_ALIGN (basetype));
+  alignment = ssize_int (CLASSTYPE_ALIGN_UNIT (basetype));
 
   /* 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;
 
@@ -3693,17 +3952,17 @@ 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.
+   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;
@@ -3713,12 +3972,13 @@ build_base_field (rli, binfo, empty_p, base_align, v)
        location information.  */
     return;
   
-  decl = build_lang_decl (FIELD_DECL, NULL_TREE, basetype);
+  decl = build_decl (FIELD_DECL, NULL_TREE, basetype);
   DECL_ARTIFICIAL (decl) = 1;
   DECL_FIELD_CONTEXT (decl) = rli->t;
   DECL_SIZE (decl) = CLASSTYPE_SIZE (basetype);
   DECL_SIZE_UNIT (decl) = CLASSTYPE_SIZE_UNIT (basetype);
   DECL_ALIGN (decl) = CLASSTYPE_ALIGN (basetype);
+  DECL_USER_ALIGN (decl) = CLASSTYPE_USER_ALIGN (basetype);
   
   if (! flag_new_abi)
     {
@@ -3743,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
     {
@@ -3752,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
@@ -3764,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.  */
@@ -3811,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
@@ -3883,6 +4141,202 @@ check_methods (t)
     }
 }
 
+/* FN is a constructor or destructor.  Clone the declaration to create
+   a specialized in-charge or not-in-charge version, as indicated by
+   NAME.  */
+
+static tree
+build_clone (fn, name)
+     tree fn;
+     tree name;
+{
+  tree parms;
+  tree clone;
+
+  /* Copy the function.  */
+  clone = copy_decl (fn);
+  /* Remember where this function came from.  */
+  DECL_CLONED_FUNCTION (clone) = fn;
+  /* Reset the function name.  */
+  DECL_NAME (clone) = name;
+  DECL_ASSEMBLER_NAME (clone) = DECL_NAME (clone);
+  /* There's no pending inline data for this function.  */
+  DECL_PENDING_INLINE_INFO (clone) = NULL;
+  DECL_PENDING_INLINE_P (clone) = 0;
+  /* And it hasn't yet been deferred.  */
+  DECL_DEFERRED_FN (clone) = 0;
+  /* There's no magic VTT parameter in the clone.  */
+  DECL_VTT_PARM (clone) = NULL_TREE;
+
+  /* The base-class destructor is not virtual.  */
+  if (name == base_dtor_identifier)
+    {
+      DECL_VIRTUAL_P (clone) = 0;
+      if (TREE_CODE (clone) != TEMPLATE_DECL)
+       DECL_VINDEX (clone) = NULL_TREE;
+    }
+
+  /* If there was an in-charge parameter, drop it from the function
+     type.  */
+  if (DECL_HAS_IN_CHARGE_PARM_P (clone))
+    {
+      tree basetype;
+      tree parmtypes;
+      tree exceptions;
+
+      exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (clone));
+      basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (clone));
+      parmtypes = TYPE_ARG_TYPES (TREE_TYPE (clone));
+      /* Skip the `this' parameter.  */
+      parmtypes = TREE_CHAIN (parmtypes);
+      /* Skip the in-charge parameter.  */
+      parmtypes = TREE_CHAIN (parmtypes);
+       /* If this is subobject constructor or destructor, add the vtt
+        parameter.  */
+      if (DECL_NEEDS_VTT_PARM_P (clone))
+       parmtypes = hash_tree_chain (vtt_parm_type, parmtypes);
+      TREE_TYPE (clone) 
+       = build_cplus_method_type (basetype,
+                                  TREE_TYPE (TREE_TYPE (clone)),
+                                  parmtypes);
+      if (exceptions)
+       TREE_TYPE (clone) = build_exception_variant (TREE_TYPE (clone),
+                                                    exceptions);
+    }
+
+  /* Copy the function parameters.  But, DECL_ARGUMENTS aren't
+     function parameters; instead, those are the template parameters.  */
+  if (TREE_CODE (clone) != TEMPLATE_DECL)
+    {
+      DECL_ARGUMENTS (clone) = copy_list (DECL_ARGUMENTS (clone));
+      /* Remove the in-charge parameter.  */
+      if (DECL_HAS_IN_CHARGE_PARM_P (clone))
+       {
+         TREE_CHAIN (DECL_ARGUMENTS (clone))
+           = TREE_CHAIN (TREE_CHAIN (DECL_ARGUMENTS (clone)));
+         DECL_HAS_IN_CHARGE_PARM_P (clone) = 0;
+       }
+
+      /* Add the VTT parameter.  */
+      if (DECL_NEEDS_VTT_PARM_P (clone))
+       {
+         tree parm;
+
+         parm = build_artificial_parm (vtt_parm_identifier,
+                                       vtt_parm_type);
+         TREE_CHAIN (parm) = TREE_CHAIN (DECL_ARGUMENTS (clone));
+         TREE_CHAIN (DECL_ARGUMENTS (clone)) = parm;
+       }
+
+      for (parms = DECL_ARGUMENTS (clone); parms; parms = TREE_CHAIN (parms))
+       {
+         DECL_CONTEXT (parms) = clone;
+         copy_lang_decl (parms);
+       }
+    }
+
+  /* Mangle the function name.  */
+  set_mangled_name_for_decl (clone);
+
+  /* Create the RTL for this function.  */
+  DECL_RTL (clone) = NULL_RTX;
+  rest_of_decl_compilation (clone, NULL, /*top_level=*/1, at_eof);
+  
+  /* Make it easy to find the CLONE given the FN.  */
+  TREE_CHAIN (clone) = TREE_CHAIN (fn);
+  TREE_CHAIN (fn) = clone;
+
+  /* If this is a template, handle the DECL_TEMPLATE_RESULT as well.  */
+  if (TREE_CODE (clone) == TEMPLATE_DECL)
+    {
+      tree result;
+
+      DECL_TEMPLATE_RESULT (clone) 
+       = build_clone (DECL_TEMPLATE_RESULT (clone), name);
+      result = DECL_TEMPLATE_RESULT (clone);
+      DECL_TEMPLATE_INFO (result) = copy_node (DECL_TEMPLATE_INFO (result));
+      DECL_TI_TEMPLATE (result) = clone;
+    }
+  else if (DECL_DEFERRED_FN (fn))
+    defer_fn (clone);
+
+  return clone;
+}
+
+/* Produce declarations for all appropriate clones of FN.  If
+   UPDATE_METHOD_VEC_P is non-zero, the clones are added to the
+   CLASTYPE_METHOD_VEC as well.  */
+
+void
+clone_function_decl (fn, update_method_vec_p)
+     tree fn;
+     int 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), clone, /*error_p=*/0);
+      clone = build_clone (fn, base_ctor_identifier);
+      if (update_method_vec_p)
+       add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
+    }
+  else
+    {
+      my_friendly_assert (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn), 20000411);
+
+      /* For each destructor, we need three variants: an in-charge
+        version, a not-in-charge version, and an in-charge deleting
+        version.  We clone the deleting version first because that
+        means it will go second on the TYPE_METHODS list -- and that
+        corresponds to the correct layout order in the virtual
+        function table.  */
+      clone = build_clone (fn, deleting_dtor_identifier);
+      if (update_method_vec_p)
+       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), clone, /*error_p=*/0);
+      clone = build_clone (fn, base_dtor_identifier);
+      if (update_method_vec_p)
+       add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
+    }
+}
+
+/* For each of the constructors and destructors in T, create an
+   in-charge and not-in-charge variant.  */
+
+static void
+clone_constructors_and_destructors (t)
+     tree t;
+{
+  tree fns;
+
+  /* We only clone constructors and destructors under the new ABI.  */
+  if (!flag_new_abi)
+    return;
+
+  /* If for some reason we don't have a CLASSTYPE_METHOD_VEC, we bail
+     out now.  */
+  if (!CLASSTYPE_METHOD_VEC (t))
+    return;
+
+  for (fns = CLASSTYPE_CONSTRUCTORS (t); fns; fns = OVL_NEXT (fns))
+    clone_function_decl (OVL_CURRENT (fns), /*update_method_vec_p=*/1);
+  for (fns = CLASSTYPE_DESTRUCTORS (t); fns; fns = OVL_NEXT (fns))
+    clone_function_decl (OVL_CURRENT (fns), /*update_method_vec_p=*/1);
+}
+
 /* Remove all zero-width bit-fields from T.  */
 
 static void
@@ -3978,6 +4432,10 @@ check_bases_and_members (t, empty_p)
                                   cant_have_const_ctor,
                                   no_const_asn_ref);
 
+  /* Create the in-charge and not-in-charge variants of constructors
+     and destructors.  */
+  clone_constructors_and_destructors (t);
+
   /* Process the using-declarations.  */
   for (; access_decls; access_decls = TREE_CHAIN (access_decls))
     handle_using_decl (TREE_VALUE (access_decls), t);
@@ -3989,7 +4447,7 @@ check_bases_and_members (t, empty_p)
 /* If T needs a pointer to its virtual function table, set TYPE_VFIELD
    accordingly.  If a new vfield was created (because T doesn't have a
    primary base class), then the newly created field is returned.  It
-   is not added to the TYPE_FIELDS list; it is the callers
+   is not added to the TYPE_FIELDS list; it is the caller's
    responsibility to do that.  */
 
 static tree
@@ -4006,7 +4464,8 @@ create_vtable_ptr (t, empty_p, vfuns_p,
   /* Loop over the virtual functions, adding them to our various
      vtables.  */
   for (fn = TYPE_METHODS (t); fn; fn = TREE_CHAIN (fn))
-    if (DECL_VINDEX (fn))
+    if (DECL_VINDEX (fn) 
+       && !(flag_new_abi && DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn)))
       add_virtual_function (new_virtuals_p, overridden_virtuals_p,
                            vfuns_p, fn, t);
 
@@ -4062,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;
@@ -4100,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.  */
@@ -4188,7 +4638,7 @@ dfs_set_offset_for_unshared_vbases (binfo, data)
       tree vbase;
       tree offset;
       
-      vbase = BINFO_FOR_VBASE (BINFO_TYPE (binfo), t);
+      vbase = binfo_for_vbase (BINFO_TYPE (binfo), t);
       offset = size_diffop (BINFO_OFFSET (vbase), BINFO_OFFSET (binfo));
       propagate_binfo_offsets (binfo, offset);
     }
@@ -4197,15 +4647,15 @@ 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 vbase;
+  tree vbases;
   unsigned HOST_WIDE_INT dsize;
   unsigned HOST_WIDE_INT eoc;
 
@@ -4225,73 +4675,87 @@ layout_virtual_bases (t, base_offsets)
   TYPE_ALIGN (t) = MAX (TYPE_ALIGN (t), BITS_PER_UNIT);
 
   /* Go through the virtual bases, allocating space for each virtual
-     base that is not already a primary base class.  */
-  for (vbase = CLASSTYPE_VBASECLASSES (t); 
-       vbase; 
-       vbase = TREE_CHAIN (vbase))
-    if (!BINFO_VBASE_PRIMARY_P (vbase))
-      {
-       /* This virtual base is not a primary base of any class in the
-          hierarchy, so we have to add space for it.  */
-       tree basetype;
-       unsigned int desired_align;
+     base that is not already a primary base class.  Under the new
+     ABI, these are allocated according to a depth-first left-to-right
+     postorder traversal; in the new ABI, inheritance graph order is
+     used instead.  */
+  for (vbases = (flag_new_abi 
+                ? TYPE_BINFO (t) 
+                : CLASSTYPE_VBASECLASSES (t));
+       vbases; 
+       vbases = TREE_CHAIN (vbases))
+    {
+      tree vbase;
 
-       basetype = BINFO_TYPE (vbase);
+      if (flag_new_abi)
+       {
+         if (!TREE_VIA_VIRTUAL (vbases))
+           continue;
+         vbase = binfo_for_vbase (BINFO_TYPE (vbases), t);
+       }
+      else
+       vbase = TREE_VALUE (vbases);
 
-       if (flag_new_abi)
-         desired_align = CLASSTYPE_ALIGN (basetype);
-       else
-         /* Under the old ABI, virtual bases were aligned as for the
-            entire base object (including its virtual bases).  That's
-            wasteful, in general.  */
-         desired_align = TYPE_ALIGN (basetype);
-       TYPE_ALIGN (t) = MAX (TYPE_ALIGN (t), desired_align);
-
-       /* Add padding so that we can put the virtual base class at an
-          appropriately aligned offset.  */
-       dsize = CEIL (dsize, desired_align) * desired_align;
-
-       /* Under the new ABI, we try to squish empty virtual bases in
-          just like ordinary empty bases.  */
-       if (flag_new_abi && is_empty_class (basetype))
-         layout_empty_base (vbase,
-                            size_int (CEIL (dsize, BITS_PER_UNIT)),
-                            *base_offsets);
-       else
-         {
-           /* And compute the offset of the virtual base.  */
-           propagate_binfo_offsets (vbase, 
-                                    ssize_int (CEIL (dsize, BITS_PER_UNIT)));
-           /* Every virtual baseclass takes a least a UNIT, so that
-              we can take it's address and get something different
-              for each base.  */
-           dsize += MAX (BITS_PER_UNIT,
-                         tree_low_cst (CLASSTYPE_SIZE (basetype), 0));
-         }
+      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.  */
+         tree basetype;
+         unsigned int desired_align;
 
-       /* Keep track of the offsets assigned to this virtual base.  */
-       record_base_offsets (vbase, base_offsets);
-      }
+         basetype = BINFO_TYPE (vbase);
 
-  /* 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);
+         if (flag_new_abi)
+           desired_align = CLASSTYPE_ALIGN (basetype);
+         else
+           /* Under the old ABI, virtual bases were aligned as for the
+            entire base object (including its virtual bases).  That's
+            wasteful, in general.  */
+           desired_align = TYPE_ALIGN (basetype);
+         TYPE_ALIGN (t) = MAX (TYPE_ALIGN (t), desired_align);
+
+         /* Add padding so that we can put the virtual base class at an
+            appropriately aligned offset.  */
+         dsize = CEIL (dsize, desired_align) * desired_align;
+
+         /* Under the new ABI, we try to squish empty virtual bases in
+            just like ordinary empty bases.  */
+         if (flag_new_abi && is_empty_class (basetype))
+           layout_empty_base (vbase,
+                              size_int (CEIL (dsize, BITS_PER_UNIT)),
+                              offsets);
+         else
+           {
+             tree offset;
+
+             offset = ssize_int (CEIL (dsize, BITS_PER_UNIT));
+             offset = size_diffop (offset, 
+                                   convert (ssizetype, 
+                                            BINFO_OFFSET (vbase)));
+
+             /* And compute the offset of the virtual base.  */
+             propagate_binfo_offsets (vbase, offset);
+             /* Every virtual baseclass takes a least a UNIT, so that
+                we can take it's address and get something different
+                for each base.  */
+             dsize += MAX (BITS_PER_UNIT,
+                           tree_low_cst (CLASSTYPE_SIZE (basetype), 0));
+           }
 
-  /* Now, go through the TYPE_BINFO hierarchy again, setting the
+         /* Keep track of the offsets assigned to this virtual base.  */
+         record_subobject_offsets (BINFO_TYPE (vbase), 
+                                   BINFO_OFFSET (vbase),
+                                   offsets,
+                                   /*vbases_p=*/0);
+       }
+    }
+
+  /* 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
      correctly.  */
   dfs_walk (TYPE_BINFO (t), dfs_set_offset_for_unshared_vbases, NULL, t);
-  for (vbase = CLASSTYPE_VBASECLASSES (t);
-       vbase;
-       vbase = TREE_CHAIN (vbase))
-    dfs_walk (vbase, dfs_set_offset_for_unshared_vbases, NULL, t);
 
   /* If we had empty base classes that protruded beyond the end of the
      class, we didn't update DSIZE above; we were hoping to overlay
@@ -4310,11 +4774,11 @@ layout_virtual_bases (t, base_offsets)
 
   /* Check for ambiguous virtual bases.  */
   if (extra_warnings)
-    for (vbase = CLASSTYPE_VBASECLASSES (t); 
-        vbase; 
-        vbase = TREE_CHAIN (vbase))
+    for (vbases = CLASSTYPE_VBASECLASSES (t); 
+        vbases
+        vbases = TREE_CHAIN (vbases))
       {
-       tree basetype = BINFO_TYPE (vbase);
+       tree basetype = BINFO_TYPE (TREE_VALUE (vbases));
        if (get_base_distance (basetype, t, 0, (tree*)0) == -2)
          cp_warning ("virtual base `%T' inaccessible in `%T' due to ambiguity",
                      basetype, t);
@@ -4357,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.  */
@@ -4374,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);
@@ -4399,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
@@ -4413,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;
 
@@ -4460,14 +4937,13 @@ layout_class_type (t, empty_p, vfuns_p,
                                TYPE_SIZE (integer_type));
          DECL_SIZE (field) = TYPE_SIZE (integer_type);
          DECL_ALIGN (field) = TYPE_ALIGN (integer_type);
+         DECL_USER_ALIGN (field) = TYPE_USER_ALIGN (integer_type);
        }
       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.  */
@@ -4481,7 +4957,10 @@ layout_class_type (t, empty_p, vfuns_p,
          DECL_BIT_FIELD (padding_field) = 1;
          DECL_SIZE (padding_field) = padding;
          DECL_ALIGN (padding_field) = 1;
-         layout_nonempty_base_or_field (rli, padding_field, NULL_TREE, v);
+         DECL_USER_ALIGN (padding_field) = 0;
+         layout_nonempty_base_or_field (rli, padding_field,
+                                        NULL_TREE, 
+                                        empty_base_offsets);
        }
     }
 
@@ -4511,7 +4990,7 @@ layout_class_type (t, empty_p, vfuns_p,
     {
       tree padding;
 
-      padding = build_lang_decl (FIELD_DECL, NULL_TREE, char_type_node);
+      padding = build_decl (FIELD_DECL, NULL_TREE, char_type_node);
       place_field (rli, padding);
       TYPE_NONCOPIED_PARTS (t) 
        = tree_cons (NULL_TREE, padding, TYPE_NONCOPIED_PARTS (t));
@@ -4544,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);
@@ -4557,6 +5035,7 @@ layout_class_type (t, empty_p, vfuns_p,
     }
 
   CLASSTYPE_ALIGN (t) = TYPE_ALIGN (t);
+  CLASSTYPE_USER_ALIGN (t) = TYPE_USER_ALIGN (t);
 
   /* Set the TYPE_DECL for this type to contain the right
      value for DECL_OFFSET, so that we can use it as part
@@ -4567,12 +5046,12 @@ 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
    (or C++ class declaration).
 
@@ -4635,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;
 
@@ -4656,8 +5135,7 @@ finish_struct_1 (t)
     {
       tree binfo = get_binfo (DECL_FIELD_CONTEXT (vfield), t, 0);
 
-      vfield = copy_node (vfield);
-      copy_lang_decl (vfield);
+      vfield = copy_decl (vfield);
 
       DECL_FIELD_CONTEXT (vfield) = t;
       DECL_FIELD_OFFSET (vfield)
@@ -4670,6 +5148,12 @@ finish_struct_1 (t)
   overridden_virtuals 
     = modify_all_vtables (t, &vfuns, nreverse (overridden_virtuals));
 
+  /* If we created a new vtbl pointer for this class, add it to the
+     list.  */
+  if (TYPE_VFIELD (t) && !CLASSTYPE_HAS_PRIMARY_BASE_P (t))
+    CLASSTYPE_VFIELDS (t) 
+      = chainon (CLASSTYPE_VFIELDS (t), build_tree_list (NULL_TREE, t));
+
   /* If necessary, create the primary vtable for this class.  */
   if (new_virtuals
       || overridden_virtuals
@@ -4697,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;
     }
@@ -4732,12 +5208,6 @@ finish_struct_1 (t)
        = chainon (TYPE_BINFO_VIRTUALS (t), overridden_virtuals);
     }
 
-  /* If we created a new vtbl pointer for this class, add it to the
-     list.  */
-  if (TYPE_VFIELD (t) && !CLASSTYPE_HAS_PRIMARY_BASE_P (t))
-    CLASSTYPE_VFIELDS (t) 
-      = chainon (CLASSTYPE_VFIELDS (t), build_tree_list (NULL_TREE, t));
-
   finish_struct_bits (t);
 
   /* Complete the rtl for any static member objects of the type we're
@@ -4790,8 +5260,10 @@ finish_struct_1 (t)
   /* Make the rtl for any new vtables we have created, and unmark
      the base types we marked.  */
   finish_vtbls (t);
+  /* Build the VTT for T.  */
+  build_vtt (t);
 
-  if (CLASSTYPE_VSIZE (t) != 0)
+  if (TYPE_VFIELD (t))
     {
       /* In addition to this one, all the other vfields should be listed.  */
       /* Before that can be done, we have to have FIELD_DECLs for them, and
@@ -4814,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
@@ -4881,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;
@@ -5016,7 +5488,7 @@ resolves_to_fixed_type_p (instance, nonnull)
     return 0;
   if (POINTER_TYPE_P (t))
     t = TREE_TYPE (t);
-  return same_type_p (TYPE_MAIN_VARIANT (t), TYPE_MAIN_VARIANT (fixed));
+  return same_type_ignoring_top_level_qualifiers_p (t, fixed);
 }
 
 \f
@@ -5028,15 +5500,21 @@ init_class_processing ()
   current_class_stack 
     = (class_stack_node_t) xmalloc (current_class_stack_size 
                                    * sizeof (struct class_stack_node));
+  VARRAY_TREE_INIT (local_classes, 8, "local_classes");
+  ggc_add_tree_varray_root (&local_classes, 1);
 
   access_default_node = build_int_2 (0, 0);
-  access_public_node = build_int_2 (1, 0);
-  access_protected_node = build_int_2 (2, 0);
-  access_private_node = build_int_2 (3, 0);
+  access_public_node = build_int_2 (ak_public, 0);
+  access_protected_node = build_int_2 (ak_protected, 0);
+  access_private_node = build_int_2 (ak_private, 0);
   access_default_virtual_node = build_int_2 (4, 0);
-  access_public_virtual_node = build_int_2 (5, 0);
-  access_protected_virtual_node = build_int_2 (6, 0);
-  access_private_virtual_node = build_int_2 (7, 0);
+  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
@@ -5125,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)
@@ -5255,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));
@@ -5296,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
@@ -5334,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.  */
@@ -5346,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;
 {
@@ -5403,6 +5871,9 @@ resolve_address_of_overloaded_function (target_type,
                        && (TREE_CODE (TREE_TYPE (target_type)) 
                            == METHOD_TYPE)), 0);
 
+  if (TREE_CODE (overload) == COMPONENT_REF)
+    overload = TREE_OPERAND (overload, 1);
+
   /* Check that the TARGET_TYPE is reasonable.  */
   if (TYPE_PTRFN_P (target_type))
     /* This is OK.  */
@@ -5477,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))
        {
@@ -5499,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;
 
@@ -5523,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);
@@ -5578,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))
@@ -5595,24 +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;
-
+  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)
@@ -5671,35 +6162,13 @@ instantiate_type (lhstype, rhs, flags)
       return instantiate_type (lhstype, rhs, flags);
 
     case COMPONENT_REF:
-      {
-       tree r = instantiate_type (lhstype, TREE_OPERAND (rhs, 1), flags);
-
-       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.  */
@@ -5708,18 +6177,25 @@ instantiate_type (lhstype, rhs, flags)
       /* Fall through.  */
 
     case TEMPLATE_ID_EXPR:
-      return 
-       resolve_address_of_overloaded_function (lhstype,
-                                               TREE_OPERAND (rhs, 0),
-                                               complain,
-                                               /*template_only=*/1,
-                                               TREE_OPERAND (rhs, 1));
+      {
+       tree fns = TREE_OPERAND (rhs, 0);
+       tree args = TREE_OPERAND (rhs, 1);
+
+       return
+         resolve_address_of_overloaded_function (lhstype,
+                                                 fns,
+                                                 complain,
+                                                 allow_ptrmem,
+                                                 /*template_only=*/1,
+                                                 args);
+      }
 
     case OVERLOAD:
       return 
        resolve_address_of_overloaded_function (lhstype, 
                                                rhs,
                                                complain,
+                                               allow_ptrmem,
                                                /*template_only=*/0,
                                                /*explicit_targs=*/NULL_TREE);
 
@@ -5831,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;
@@ -6041,18 +6521,105 @@ 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);
     }
 }
 
-/* Dump the offsets of all the bases rooted at BINFO to stderr.
-   INDENT should be zero when called from the top level; it is
-   incremented recursively.  */
+/* Returns the VAR_DECL for the complete vtable associated with
+   BINFO.  (Under the new ABI, secondary vtables are merged with
+   primary vtables; this function will return the VAR_DECL for the
+   primary vtable.)  */
 
-void
-dump_class_hierarchy (binfo, indent)
+tree
+get_vtbl_decl_for_binfo (binfo)
+     tree binfo;
+{
+  tree decl;
+
+  decl = BINFO_VTABLE (binfo);
+  if (decl && TREE_CODE (decl) == PLUS_EXPR)
+    {
+      my_friendly_assert (TREE_CODE (TREE_OPERAND (decl, 0)) == ADDR_EXPR,
+                         2000403);
+      decl = TREE_OPERAND (TREE_OPERAND (decl, 0), 0);
+    }
+  if (decl)
+    my_friendly_assert (TREE_CODE (decl) == VAR_DECL, 20000403);
+  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.  */
+
+static void
+dump_class_hierarchy_r (t, binfo, indent)
+     tree t;
      tree binfo;
      int indent;
 {
@@ -6060,14 +6627,29 @@ dump_class_hierarchy (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));
-  fprintf (stderr, " %s\n",
-          BINFO_PRIMARY_MARKED_P (binfo) ? "primary" : "");
+  if (TREE_VIA_VIRTUAL (binfo))
+    fprintf (stderr, " virtual");
+  if (BINFO_PRIMARY_MARKED_P (binfo)
+      || (TREE_VIA_VIRTUAL (binfo) 
+         && BINFO_PRIMARY_MARKED_P (binfo_for_vbase (BINFO_TYPE (binfo), 
+                                                     t))))
+    fprintf (stderr, " primary");
+  fprintf (stderr, "\n");
 
   for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
-    dump_class_hierarchy (BINFO_BASETYPE (binfo, i), indent + 2);
+    dump_class_hierarchy_r (t, BINFO_BASETYPE (binfo, i), indent + 2);
+}
+
+/* Dump the BINFO hierarchy for T.  */
+
+void
+dump_class_hierarchy (t)
+     tree t;
+{
+  dump_class_hierarchy_r (t, TYPE_BINFO (t), 0);
 }
 
 /* Virtual function table initialization.  */
@@ -6087,14 +6669,18 @@ finish_vtbls (t)
         vtables in one contiguous vtable.  The primary vtable is
         first, followed by the non-virtual secondary vtables in
         inheritance graph order.  */
-      list = build_tree_list (t, NULL_TREE);
-      accumulate_vtbl_inits (TYPE_BINFO (t), list);
+      list = build_tree_list (TYPE_BINFO_VTABLE (t), NULL_TREE);
+      accumulate_vtbl_inits (TYPE_BINFO (t), TYPE_BINFO (t),
+                            TYPE_BINFO (t), t, list);
       /* Then come the virtual bases, also in inheritance graph
         order.  */
-      for (vbase = CLASSTYPE_VBASECLASSES (t);
-          vbase;
-          vbase = TREE_CHAIN (vbase))
-       accumulate_vtbl_inits (vbase, list);
+      for (vbase = TYPE_BINFO (t); vbase; vbase = TREE_CHAIN (vbase))
+       {
+         if (!TREE_VIA_VIRTUAL (vbase))
+           continue;
+
+         accumulate_vtbl_inits (vbase, vbase, TYPE_BINFO (t), t, list);
+       }
 
       if (TYPE_BINFO_VTABLE (t))
        initialize_vtable (TYPE_BINFO (t), TREE_VALUE (list));
@@ -6117,13 +6703,11 @@ dfs_finish_vtbls (binfo, data)
 {
   tree t = (tree) data;
 
-  if (!BINFO_PRIMARY_MARKED_P (binfo)
-      && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))
-      && BINFO_NEW_VTABLE_MARKED (binfo, t))
+  if (BINFO_NEW_VTABLE_MARKED (binfo, t))
     initialize_vtable (binfo, 
-                      build_vtbl_initializer (binfo, t));
+                      build_vtbl_initializer (binfo, binfo, t, 
+                                              TYPE_BINFO (t), NULL));
 
-  CLEAR_BINFO_NEW_VTABLE_MARKED (binfo, t);
   SET_BINFO_MARKED (binfo);
 
   return NULL_TREE;
@@ -6136,108 +6720,513 @@ initialize_vtable (binfo, inits)
      tree binfo;
      tree inits;
 {
-  tree context;
   tree decl;
 
   layout_vtable_decl (binfo, list_length (inits));
-  decl = BINFO_VTABLE (binfo);
+  decl = get_vtbl_decl_for_binfo (binfo);
+  initialize_array (decl, inits);
+}
+
+/* Initialize DECL (a declaration for a namespace-scope array) with
+   the INITS.  */
+
+static void
+initialize_array (decl, inits)
+  tree decl;
+  tree inits;
+{
+  tree context;
+
   context = DECL_CONTEXT (decl);
-  DECL_CONTEXT (decl) = 0;
+  DECL_CONTEXT (decl) = NULL_TREE;
   DECL_INITIAL (decl) = build_nt (CONSTRUCTOR, NULL_TREE, inits);
   cp_finish_decl (decl, DECL_INITIAL (decl), NULL_TREE, 0);
   DECL_CONTEXT (decl) = context;
 }
 
-/* Add the vtbl initializers for BINFO (and its non-primary,
-   non-virtual bases) to the list of INITS.  */
+/* Build the VTT (virtual table table) for T.  */
 
 static void
-accumulate_vtbl_inits (binfo, inits)
+build_vtt (t)
+     tree t;
+{
+  tree inits;
+  tree type;
+  tree vtt;
+  tree index;
+
+  /* Under the old ABI, we don't use VTTs.  */
+  if (!flag_new_abi)
+    return;
+
+  /* Build up the initializers for the VTT.  */
+  inits = NULL_TREE;
+  index = size_zero_node;
+  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)
+    return;
+
+  /* Figure out the type of the VTT.  */
+  type = build_index_type (size_int (list_length (inits)));
+  type = build_cplus_array_type (const_ptr_type_node, type);
+                                
+  /* Now, build the VTT object itself.  */
+  vtt = build_vtable (t, get_vtt_name (t), type);
+  pushdecl_top_level (vtt);
+  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 inits;
+     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).  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, virtual_vtts_p, inits, index)
+     tree binfo;
+     tree t;
+     int virtual_vtts_p;
+     tree *inits;
+     tree *index;
 {
-  /* Walk the BINFO and its bases.  */
+  int i;
+  tree b;
+  tree init;
+  tree secondary_vptrs;
+  int ctor_vtbl_p;
+
+  /* We only need VTTs for subobjects with virtual bases.  */
+  if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo)))
+    return inits;
+
+  /* We need to use a construction vtable if this is not the primary
+     VTT.  */
+  ctor_vtbl_p = !same_type_p (TREE_TYPE (binfo), t);
+  if (ctor_vtbl_p)
+    {
+      build_ctor_vtbl_group (binfo, t);
+
+      /* Record the offset in the VTT where this sub-VTT can be found.  */
+      BINFO_SUBVTT_INDEX (binfo) = *index;
+    }
+
+  /* Add the address of the primary vtable for the complete object.  */
+  init = BINFO_VTABLE (binfo);
+  if (TREE_CODE (init) == TREE_LIST)
+    init = TREE_VALUE (init);
+  *inits = build_tree_list (NULL_TREE, init);
+  inits = &TREE_CHAIN (*inits);
+  BINFO_VPTR_INDEX (binfo) = *index;
+  *index = size_binop (PLUS_EXPR, *index, TYPE_SIZE_UNIT (ptr_type_node));
+                      
+  /* Recursively add the secondary VTTs for non-virtual bases.  */
+  for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
+    {
+      b = BINFO_BASETYPE (binfo, i);
+      if (!TREE_VIA_VIRTUAL (b))
+       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 = tree_cons (t, NULL_TREE, BINFO_TYPE (binfo));
+  TREE_TYPE (secondary_vptrs) = *index;
   dfs_walk_real (binfo,
-                dfs_accumulate_vtbl_inits,
-                NULL, 
-                dfs_skip_vbases,
-                inits);
+                dfs_build_secondary_vptr_vtt_inits,
+                NULL,
+                dfs_unmarked_real_bases_queue_p,
+                secondary_vptrs);
+  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
+     them, and add the INITS, the last init will be the first element
+     of the chain.  */
+  secondary_vptrs = TREE_VALUE (secondary_vptrs);
+  if (secondary_vptrs)
+    {
+      *inits = nreverse (secondary_vptrs);
+      inits = &TREE_CHAIN (secondary_vptrs);
+      my_friendly_assert (*inits == NULL_TREE, 20000517);
+    }
+
+  /* Add the secondary VTTs for virtual bases.  */
+  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);
+      }
+
+  dfs_walk (binfo, dfs_fixup_binfo_vtbls,
+           dfs_unmarked_real_bases_queue_p,
+           build_tree_list (t, binfo));
+
+  return inits;
 }
 
-/* Called from finish_vtbls via dfs_walk when using the new ABI.
-   Accumulates the vtable initializers for all of the vtables into
-   TREE_VALUE (DATA).  */
+/* Called from build_vtt_inits via dfs_walk.  */
 
 static tree
-dfs_accumulate_vtbl_inits (binfo, data)
+dfs_build_secondary_vptr_vtt_inits (binfo, data)
      tree binfo;
      void *data;
 {
-  tree l;
+  tree l; 
   tree t;
+  tree init;
+  tree index;
 
   l = (tree) data;
-  t = TREE_PURPOSE (l);
+  t = TREE_CHAIN (l);
+
+  SET_BINFO_MARKED (binfo);
+
+  /* We don't care about bases that don't have vtables.  */
+  if (!TYPE_VFIELD (BINFO_TYPE (binfo)))
+    return NULL_TREE;
+
+  /* We're only interested in proper subobjects of T.  */
+  if (same_type_p (BINFO_TYPE (binfo), t))
+    return NULL_TREE;
+
+  /* We're not interested in non-virtual primary bases.  */
+  if (!TREE_VIA_VIRTUAL (binfo) && BINFO_PRIMARY_MARKED_P (binfo))
+    return NULL_TREE;
+
+  /* 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.  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);
+  BINFO_VPTR_INDEX (binfo) = index;
+  TREE_TYPE (l) = size_binop (PLUS_EXPR, index, 
+                             TYPE_SIZE_UNIT (ptr_type_node));
+
+  /* Add the initializer for the secondary vptr itself.  */
+  init = BINFO_VTABLE (binfo);
+  if (TREE_CODE (init) == TREE_LIST)
+    init = TREE_VALUE (init);
+  TREE_VALUE (l) = tree_cons (NULL_TREE, init, TREE_VALUE (l));
+
+  return NULL_TREE;
+}
+
+/* Called from build_vtt_inits via dfs_walk.  */
+
+static tree
+dfs_fixup_binfo_vtbls (binfo, data)
+     tree binfo;
+     void *data;
+{
+  CLEAR_BINFO_MARKED (binfo);
+
+  /* We don't care about bases that don't have vtables.  */
+  if (!TYPE_VFIELD (BINFO_TYPE (binfo)))
+    return NULL_TREE;
+
+  /* If we scribbled the construction vtable vptr into BINFO, clear it
+     out now.  */
+  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;
+}
+
+/* Build the construction vtable group for BINFO which is in the
+   hierarchy dominated by T.  */
+
+static void
+build_ctor_vtbl_group (binfo, t)
+     tree binfo;
+     tree t;
+{
+  tree list;
+  tree type;
+  tree vtbl;
+  tree inits;
+  tree id;
+  tree vbase;
 
-  if (!BINFO_PRIMARY_MARKED_P (binfo)
-      && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))
-      && BINFO_NEW_VTABLE_MARKED (binfo, t))
+  /* See if we've already create this construction vtable group.  */
+  if (flag_new_abi)
+    id = mangle_ctor_vtbl_for_type (t, binfo);
+  else
+    id = get_ctor_vtbl_name (t, binfo);
+  if (IDENTIFIER_GLOBAL_VALUE (id))
+    return;
+
+  /* Build a version of VTBL (with the wrong type) for use in
+     constructing the addresses of secondary vtables in the
+     construction vtable group.  */
+  vtbl = build_vtable (t, id, ptr_type_node);
+  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))
     {
-      /* If this is a secondary vtable, record its location.  */
-      if (binfo != TYPE_BINFO (t))
-       {
-         tree vtbl;
-
-         vtbl = TYPE_BINFO_VTABLE (t);
-         vtbl = build1 (ADDR_EXPR, 
-                        build_pointer_type (TREE_TYPE (vtbl)),
-                        vtbl);
-         BINFO_VTABLE (binfo)
-           = build (PLUS_EXPR, TREE_TYPE (vtbl), vtbl,
-                    size_binop (MULT_EXPR,
-                                TYPE_SIZE_UNIT (TREE_TYPE (vtbl)),
-                                size_int (list_length (TREE_VALUE (l)))));
-       }
+      tree b;
+
+      if (!TREE_VIA_VIRTUAL (vbase))
+       continue;
 
-      /* Add the initializers for this vtable to the initializers for
-        the other vtables we've already got.  */
-      TREE_VALUE (l) 
-       = chainon (TREE_VALUE (l),
-                  build_vtbl_initializer (binfo, t));
+      b = binfo_for_vbase (BINFO_TYPE (vbase), t);
+      accumulate_vtbl_inits (b, vbase, binfo, t, list);
     }
 
-  CLEAR_BINFO_NEW_VTABLE_MARKED (binfo, t);
+  inits = TREE_VALUE (list);
 
-  return NULL_TREE;
+  /* Figure out the type of the construction vtable.  */
+  type = build_index_type (size_int (list_length (inits)));
+  type = build_cplus_array_type (vtable_entry_type, type);
+  TREE_TYPE (vtbl) = type;
+
+  /* Initialize the construction vtable.  */
+  pushdecl_top_level (vtbl);
+  initialize_array (vtbl, inits);
 }
 
-/* Construct the initializer for BINFOs virtual function table.  BINFO
-   is part of the hierarchy dominated by T.  The value returned is a
-   TREE_LIST suitable for wrapping in a CONSTRUCTOR to use as the
-   DECL_INITIAL for a vtable.  */
+/* Add the vtbl initializers for BINFO (and its non-primary,
+   non-virtual bases) to the list of INITS.  BINFO is in the hierarchy
+   dominated by T.  ORIG_BINFO must have the same type as BINFO, but
+   may be different from BINFO if we are building a construction
+   vtable.  RTTI_BINFO gives the object that should be used as the
+   complete object for BINFO.  */
+
+static void
+accumulate_vtbl_inits (binfo, orig_binfo, rtti_binfo, t, inits)
+     tree binfo;
+     tree orig_binfo;
+     tree rtti_binfo;
+     tree t;
+     tree inits;
+{
+  int i;
+  int ctor_vtbl_p;
+
+  my_friendly_assert (same_type_p (BINFO_TYPE (binfo),
+                                  BINFO_TYPE (orig_binfo)),
+                     20000517);
+
+  /* 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 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))
+      && !(BINFO_OVERRIDE_ALONG_VIRTUAL_PATH_P 
+          (get_matching_base (binfo, BINFO_TYPE (rtti_binfo)))))
+    return;
+
+  /* Build the initializers for the BINFO-in-T vtable.  */
+  TREE_VALUE (inits) 
+    = chainon (TREE_VALUE (inits),
+              dfs_accumulate_vtbl_inits (binfo, orig_binfo,
+                                         rtti_binfo, t, inits));
+                     
+  /* Walk the BINFO and its bases.  We walk in preorder so that as we
+     initialize each vtable we can figure out at what offset the
+     secondary vtable lies from the primary vtable.  We can't use
+     dfs_walk here because we need to iterate through bases of BINFO
+     and RTTI_BINFO simultaneously.  */
+  for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
+    {
+      tree base_binfo;
+
+      base_binfo = BINFO_BASETYPE (binfo, i);
+      /* Skip virtual bases.  */
+      if (TREE_VIA_VIRTUAL (base_binfo))
+       continue;
+      accumulate_vtbl_inits (base_binfo,
+                            BINFO_BASETYPE (orig_binfo, i),
+                            rtti_binfo,
+                            t,
+                            inits);
+    }
+}
+
+/* Called from finish_vtbls via dfs_walk when using the new ABI.
+   Accumulates the vtable initializers for all of the vtables into
+   TREE_VALUE (DATA).  Returns the initializers for the BINFO vtable.  */
 
 static tree
-build_vtbl_initializer (binfo, t)
+dfs_accumulate_vtbl_inits (binfo, orig_binfo, rtti_binfo, t, l)
      tree binfo;
+     tree orig_binfo;
+     tree rtti_binfo;
      tree t;
+     tree l;
 {
-  tree v = BINFO_VIRTUALS (binfo);
   tree inits = NULL_TREE;
 
-  /* Add entries to the vtable that indicate how to adjust the this
-     pointer when calling a virtual function in this class.  */
-  inits = build_vcall_offset_vtbl_entries (binfo, t);
+  if (BINFO_NEW_VTABLE_MARKED (orig_binfo, t))
+    {
+      tree vtbl;
+      tree index;
+      int non_fn_entries;
+
+      /* Compute the initializer for this vtable.  */
+      inits = build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo,
+                                     &non_fn_entries);
+
+      /* Figure out the position to which the VPTR should point.  */
+      vtbl = TREE_PURPOSE (l);
+      vtbl = build1 (ADDR_EXPR, 
+                    vtbl_ptr_type_node,
+                    vtbl);
+      index = size_binop (PLUS_EXPR,
+                         size_int (non_fn_entries),
+                         size_int (list_length (TREE_VALUE (l))));
+      index = size_binop (MULT_EXPR,
+                         TYPE_SIZE_UNIT (vtable_entry_type),
+                         index);
+      vtbl = build (PLUS_EXPR, TREE_TYPE (vtbl), vtbl, index);
+      TREE_CONSTANT (vtbl) = 1;
+
+      /* For an ordinary vtable, set BINFO_VTABLE.  */
+      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) = 
+         tree_cons (rtti_binfo, vtbl, BINFO_VTABLE (binfo));
+    }
+
+  return inits;
+}
+
+/* Construct the initializer for BINFOs virtual function table.  BINFO
+   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_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.
+
+   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.  
+
+   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.  */
 
-  /* Add entries to the vtable for offsets to our virtual bases.  */
-  inits = chainon (build_vbase_offset_vtbl_entries (binfo, t),
-                  inits);
+static tree
+build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)
+     tree binfo;
+     tree orig_binfo;
+     tree t;
+     tree rtti_binfo;
+     int *non_fn_entries_p;
+{
+  tree v;
+  tree vfun_inits;
+  tree vbase;
+  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.  */
+  vid.index = ssize_int (-3);
 
   /* Add entries to the vtable for RTTI.  */
-  inits = chainon (build_rtti_vtbl_entries (binfo, t), inits);
+  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, &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; 
+       vbase = TREE_CHAIN (vbase))
+    CLEAR_BINFO_VTABLE_PATH_MARKED (TREE_VALUE (vbase));
+
+  if (non_fn_entries_p)
+    *non_fn_entries_p = list_length (vid.inits);
 
   /* Go through all the ordinary virtual functions, building up
      initializers.  */
-  while (v)
+  vfun_inits = NULL_TREE;
+  for (v = BINFO_VIRTUALS (orig_binfo); v; v = TREE_CHAIN (v))
     {
       tree delta;
       tree vcall_index;
@@ -6248,7 +7237,15 @@ build_vtbl_initializer (binfo, t)
       /* 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);
@@ -6264,200 +7261,147 @@ build_vtbl_initializer (binfo, t)
       /* 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.  */
-      inits = tree_cons (NULL_TREE, init, inits);
-
-      /* Keep going.  */
-      v = TREE_CHAIN (v);
+      vfun_inits = tree_cons (NULL_TREE, init, vfun_inits);
     }
 
-  /* The initializers were built up in reverse order; straighten them
-     out now.  */
-  return nreverse (inits);
+  /* The initializers for virtual functions were built up in reverse
+     order; straighten them out now.  */
+  vfun_inits = nreverse (vfun_inits);
+  
+  /* The negative offset initializers are also in reverse order.  */
+  vid.inits = nreverse (vid.inits);
+
+  /* Chain the two together.  */
+  return chainon (vid.inits, vfun_inits);
 }
 
-/* Called from build_vbase_offset_vtbl_entries via dfs_walk.  */
+/* Sets vid->inits to be the initializers for the vbase and vcall
+   offsets in BINFO, which is in the hierarchy dominated by T.  */
 
-static tree
-dfs_build_vbase_offset_vtbl_entries (binfo, data)
+static void
+build_vcall_and_vbase_vtbl_entries (binfo, vid)
      tree binfo;
-     void *data;
+     vtbl_init_data *vid;
 {
-  tree list = (tree) data;
-
-  if (TREE_TYPE (list) == binfo)
-    /* The TREE_TYPE of LIST is the base class from which we started
-       walking.  If that BINFO is virtual it's not a virtual baseclass
-       of itself.  */
-    ;
-  else if (TREE_VIA_VIRTUAL (binfo))
-    {
-      tree init;
-      tree vbase;
-
-      /* Remember the index to the vbase offset for this virtual
-        base.  */
-      vbase = BINFO_FOR_VBASE (BINFO_TYPE (binfo), TREE_PURPOSE (list));
-      if (!TREE_VALUE (list))
-       BINFO_VPTR_FIELD (vbase) = build_int_2 (-3, 0);
-      else
-       {
-         BINFO_VPTR_FIELD (vbase) = TREE_PURPOSE (TREE_VALUE (list));
-         BINFO_VPTR_FIELD (vbase)
-           = fold (build (MINUS_EXPR, integer_type_node,
-                          BINFO_VPTR_FIELD (vbase), integer_one_node));
-       }
+  tree b;
 
-      /* And record the offset at which this virtual base lies in the
-        vtable.  */
-      init = BINFO_OFFSET (binfo);
-      TREE_VALUE (list) = tree_cons (BINFO_VPTR_FIELD (vbase),
-                                    init, TREE_VALUE (list));
-    }
+  /* If this is a derived class, we must first create entries
+     corresponding to the primary base class.  */
+  b = get_primary_binfo (binfo);
+  if (b)
+    build_vcall_and_vbase_vtbl_entries (b, vid);
 
-  SET_BINFO_VTABLE_PATH_MARKED (binfo);
-  
-  return NULL_TREE;
+  /* Add the vbase entries for this base.  */
+  build_vbase_offset_vtbl_entries (binfo, vid);
+  /* Add the vcall entries for this base.  */
+  build_vcall_offset_vtbl_entries (binfo, vid);
 }
 
 /* Returns the initializers for the vbase offset entries in the vtable
    for BINFO (which is part of the class hierarchy dominated by T), in
-   reverse order.  */
+   reverse order.  VBASE_OFFSET_INDEX gives the vtable index
+   where the next vbase offset will go.  */
 
-static tree
-build_vbase_offset_vtbl_entries (binfo, t)
+static void
+build_vbase_offset_vtbl_entries (binfo, vid)
      tree binfo;
-     tree t;
+     vtbl_init_data *vid;
 {
-  tree inits;
-  tree init;
-  tree list;
+  tree vbase;
+  tree t;
 
   /* Under the old ABI, pointers to virtual bases are stored in each
      object.  */
   if (!vbase_offsets_in_vtable_p ())
-    return NULL_TREE;
+    return;
 
   /* If there are no virtual baseclasses, then there is nothing to
      do.  */
   if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo)))
-    return NULL_TREE;
-
-  inits = NULL_TREE;
-
-  /* The offsets are allocated in the reverse order of a
-     depth-first left-to-right traversal of the hierarchy.  We use
-     BINFO_VTABLE_PATH_MARKED because we are ourselves during a
-     dfs_walk, and so BINFO_MARKED is already in use.  */
-  list = build_tree_list (t, NULL_TREE);
-  TREE_TYPE (list) = binfo;
-  dfs_walk (binfo,
-           dfs_build_vbase_offset_vtbl_entries,
-           unmarked_vtable_pathp,
-           list);
-  dfs_walk (binfo,
-           dfs_vtable_path_unmark,
-           marked_vtable_pathp,
-           list);
-  inits = nreverse (TREE_VALUE (list));
-
-  /* We've now got offsets in the right order.  However, the offsets
-     we've stored are offsets from the beginning of the complete
-     object, and we need offsets from this BINFO.  */
-  for (init = inits; init; init = TREE_CHAIN (init))
-    {
-      /* The dfs_build_vbase_offset_vtbl_entries routine uses the
-        TREE_PURPOSE to scribble in.  But, we need to clear it now so
-        that the values are not perceived as labeled initializers.  */
-      TREE_PURPOSE (init) = NULL_TREE;
-      TREE_VALUE (init)
-       = fold (build1 (NOP_EXPR, vtable_entry_type,
-                       size_diffop (TREE_VALUE (init),
-                                    BINFO_OFFSET (binfo))));
-    }
-
-  return inits;
-}
+    return;
 
-/* Called from build_vcall_offset_vtbl_entries via dfs_walk.  */
+  t = vid->derived;
 
-static tree
-dfs_vcall_offset_queue_p (binfo, data)
-     tree binfo;
-     void *data;
-{
-  vcall_offset_data* vod = (vcall_offset_data *) data;
+  /* Go through the virtual bases, adding the offsets.  */
+  for (vbase = TYPE_BINFO (BINFO_TYPE (binfo));
+       vbase;
+       vbase = TREE_CHAIN (vbase))
+    {
+      tree b;
+      tree delta;
+      
+      if (!TREE_VIA_VIRTUAL (vbase))
+       continue;
 
-  return (binfo == vod->vbase) ? binfo : dfs_skip_vbases (binfo, NULL);
-}
+      /* Find the instance of this virtual base in the complete
+        object.  */
+      b = binfo_for_vbase (BINFO_TYPE (vbase), t);
 
-/* Called from build_vcall_offset_vtbl_entries via dfs_walk.  */
+      /* If we've already got an offset for this virtual base, we
+        don't need another one.  */
+      if (BINFO_VTABLE_PATH_MARKED (b))
+       continue;
+      SET_BINFO_VTABLE_PATH_MARKED (b);
 
-static tree
-dfs_build_vcall_offset_vtbl_entries (binfo, data)
-     tree binfo;
-     void *data;
-{
-  vcall_offset_data* vod;
-  tree virtuals;
-  tree binfo_inits;
+      /* Figure out where we can find this vbase offset.  */
+      delta = size_binop (MULT_EXPR, 
+                         vid->index,
+                         convert (ssizetype,
+                                  TYPE_SIZE_UNIT (vtable_entry_type)));
+      if (vid->primary_vtbl_p)
+       BINFO_VPTR_FIELD (b) = delta;
 
-  /* Primary bases are not interesting; all of the virtual
-     function table entries have been overridden.  */
-  if (BINFO_PRIMARY_MARKED_P (binfo))
-     return NULL_TREE;
+      if (binfo != TYPE_BINFO (t))
+       {
+         tree orig_vbase;
 
-  vod = (vcall_offset_data *) data;
-  binfo_inits = NULL_TREE;
+         /* Find the instance of this virtual base in the type of BINFO.  */
+         orig_vbase = binfo_for_vbase (BINFO_TYPE (vbase),
+                                       BINFO_TYPE (binfo));
 
-  /* We chain the offsets on in reverse order.  That's correct --
-     build_vtbl_initializer will straighten them out.  */
-  for (virtuals = BINFO_VIRTUALS (binfo);
-       virtuals;
-       virtuals = TREE_CHAIN (virtuals))
-    {
-      /* Figure out what function we're looking at.  */
-      tree fn = TREE_VALUE (virtuals);
-      tree base = DECL_CONTEXT (fn);
-      /* The FN comes from BASE.  So, we must caculate the adjustment
-        from the virtual base that derived from BINFO to BASE.  */
-      tree base_binfo = get_binfo (base, vod->derived, /*protect=*/0);
+         /* The vbase offset had better be the same.  */
+         if (!tree_int_cst_equal (delta,
+                                  BINFO_VPTR_FIELD (orig_vbase)))
+           my_friendly_abort (20000403);
+       }
 
-      binfo_inits
-       = tree_cons (NULL_TREE,
-                    fold (build1 (NOP_EXPR, vtable_entry_type,
-                                  size_diffop (BINFO_OFFSET (base_binfo),
-                                               BINFO_OFFSET (vod->vbase)))),
-                    binfo_inits);
+      /* The next vbase will come at a more negative offset.  */
+      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));
+      *vid->last_init 
+       = build_tree_list (NULL_TREE,
+                          fold (build1 (NOP_EXPR, 
+                                        vtable_entry_type,
+                                        delta)));
+      vid->last_init = &TREE_CHAIN (*vid->last_init);
     }
-
-  /* Now add the initializers we've just created to the list that will
-     be returned to our caller.  */
-  vod->inits = chainon (vod->inits, binfo_inits);
-
-  return NULL_TREE;
 }
 
-/* Returns the initializers for the vcall offset entries in the vtable
-   for BINFO (which is part of the class hierarchy dominated by T), in
-   reverse order.  */
+/* 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 tree
-build_vcall_offset_vtbl_entries (binfo, t)
+static void
+build_vcall_offset_vtbl_entries (binfo, vid)
      tree binfo;
-     tree t;
+     vtbl_init_data *vid;
 {
-  vcall_offset_data vod;
-
   /* Under the old ABI, the adjustments to the `this' pointer were made
      elsewhere.  */
   if (!vcall_offsets_in_vtable_p ())
-    return NULL_TREE;
+    return;
 
   /* We only need these entries if this base is a virtual base.  */
   if (!TREE_VIA_VIRTUAL (binfo))
-    return NULL_TREE;
+    return;
 
   /* We need a vcall offset for each of the virtual functions in this
      vtable.  For example:
@@ -6478,60 +7422,202 @@ build_vcall_offset_vtbl_entries (binfo, t)
      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.derived = t;
-  vod.vbase = binfo;
-  vod.inits = NULL_TREE;
-  dfs_walk (binfo,
-           dfs_build_vcall_offset_vtbl_entries,
-           dfs_vcall_offset_queue_p,
-           &vod);
+     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 void
+add_vcall_offset_vtbl_entries_1 (binfo, vid)
+     tree binfo;
+     vtbl_init_data* vid;
+{
+  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;
+
+  binfo_inits = NULL_TREE;
 
-  return vod.inits;
+  /* 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_INHERITANCE_CHAIN (non_primary_binfo))
+    {
+      tree b;
+
+      /* 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 = 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 (vid->fns); ++i) 
+       {
+         tree derived_entry;
+
+         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 (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, vid->derived, /*protect=*/0);
+
+      /* Compute the vcall offset.  */
+      *vid->last_init 
+       = (build_tree_list 
+          (NULL_TREE,
+           fold (build1 (NOP_EXPR, vtable_entry_type,
+                         size_diffop (BINFO_OFFSET (base_binfo),
+                                      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.  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.  */
+      vid->index = size_binop (MINUS_EXPR, vid->index, ssize_int (1));
+
+      /* Keep track of this function.  */
+      VARRAY_PUSH_TREE (vid->fns, derived_virtuals);
+    }
 }
 
 /* Return vtbl initializers for the RTTI entries coresponding to the
-   BINFO's vtable.  BINFO is a part of the hierarchy dominated by 
-   T.  */
+   BINFO's vtable.  The RTTI entries should indicate the object given
+   by RTTI_BINFO.  */
 
-static tree
-build_rtti_vtbl_entries (binfo, t)
+static void
+build_rtti_vtbl_entries (binfo, rtti_binfo, vid)
      tree binfo;
-     tree t;
+     tree rtti_binfo;
+     vtbl_init_data *vid;
 {
   tree b;
+  tree t;
   tree basetype;
-  tree inits;
   tree offset;
   tree decl;
   tree init;
 
   basetype = BINFO_TYPE (binfo);
-  inits = NULL_TREE;
+  t = BINFO_TYPE (rtti_binfo);
 
   /* For a COM object there is no RTTI entry.  */
   if (CLASSTYPE_COM_INTERFACE (basetype))
-    return inits;
+    return;
 
   /* To find the complete object, we will first convert to our most
      primary base, and then add the offset in the vtbl to that value.  */
   b = binfo;
   while (CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (b)))
-    b = BINFO_BASETYPE (b, 
-                       CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (b)));
-  offset = size_diffop (size_zero_node, BINFO_OFFSET (b));
-
-  /* Add the offset-to-top entry.  */
-  if (flag_vtable_thunks)
     {
-      /* Convert the offset to look like a function pointer, so that
-        we can put it in the vtable.  */
-      init = build1 (NOP_EXPR, vfunc_ptr_type_node, offset);
-      TREE_CONSTANT (init) = 1;
-      inits = tree_cons (NULL_TREE, init, inits);
+      tree primary_base;
+
+      primary_base = get_primary_binfo (b);
+      if (!BINFO_PRIMARY_MARKED_P (primary_base))
+       break;
+      b = primary_base;
     }
+  offset = size_diffop (BINFO_OFFSET (rtti_binfo), BINFO_OFFSET (b));
 
   /* The second entry is, in the case of the new ABI, the address of
      the typeinfo object, or, in the case of the old ABI, a function
@@ -6559,13 +7645,23 @@ build_rtti_vtbl_entries (binfo, t)
         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);
     }
+  *vid->last_init = build_tree_list (NULL_TREE, init);
+  vid->last_init = &TREE_CHAIN (*vid->last_init);
 
-  /* Hook the RTTI declaration onto the list.  */
-  inits = tree_cons (NULL_TREE, init, inits);
-
-  return inits;
+  /* Add the offset-to-top entry.  It comes earlier in the vtable that
+     the the typeinfo entry.  */
+  if (flag_vtable_thunks)
+    {
+      /* Convert the offset to look like a function pointer, so that
+        we can put it in the vtable.  */
+      init = build1 (NOP_EXPR, vfunc_ptr_type_node, offset);
+      TREE_CONSTANT (init) = 1;
+      *vid->last_init = build_tree_list (NULL_TREE, init);
+      vid->last_init = &TREE_CHAIN (*vid->last_init);
+    }
 }
 
 /* Build an entry in the virtual function table.  DELTA is the offset
@@ -6577,22 +7673,23 @@ build_rtti_vtbl_entries (binfo, t)
    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 (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);
-      if ((idelta || ivindex) 
-         && ! DECL_PURE_VIRTUAL_P (TREE_OPERAND (entry, 0)))
+      fn = TREE_OPERAND (entry, 0);
+      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;
@@ -6604,14 +7701,13 @@ build_vtable_entry (delta, vcall_index, entry)
     }
   else
     {
-      extern int flag_huge_objects;
       tree elems = tree_cons (NULL_TREE, delta,
                              tree_cons (NULL_TREE, integer_zero_node,
                                         build_tree_list (NULL_TREE, 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