OSDN Git Service

revert mangling patch
[pf3gnuchains/gcc-fork.git] / gcc / cp / class.c
index 4be6f3e..77a5b7e 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,11 +62,31 @@ typedef struct class_stack_node {
   splay_tree names_used;
 }* class_stack_node_t;
 
+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 vtable index of the next vcall or vbase offset.  */
+  tree index;
+  /* Nonzero if we are building the initializer for the primary
+     vtable.  */
+  int primary_p;
+} vcall_offset_data;
+
 /* 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));
@@ -80,11 +94,11 @@ static tree build_vtable_entry PARAMS ((tree, tree, tree));
 static tree get_vtable_name PARAMS ((tree));
 static tree get_derived_offset PARAMS ((tree, tree));
 static tree get_basefndecls PARAMS ((tree, tree));
-static void set_rtti_entry PARAMS ((tree, 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));
@@ -109,7 +123,7 @@ static tree fixed_type_or_null PARAMS ((tree, int *));
 static tree resolve_address_of_overloaded_function PARAMS ((tree, 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));
@@ -133,29 +147,48 @@ 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 propagate_binfo_offsets PARAMS ((tree, tree));
-static void layout_basetypes PARAMS ((tree));
-static void layout_virtual_bases PARAMS ((tree));
+static void layout_virtual_bases PARAMS ((tree, varray_type *));
 static tree dfs_set_offset_for_shared_vbases PARAMS ((tree, void *));
 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 void build_vbase_offset_vtbl_entries PARAMS ((tree, vcall_offset_data *));
 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 start_vtable PARAMS ((tree, int *));
+static void build_vcall_offset_vtbl_entries PARAMS ((tree, vcall_offset_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));
+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, tree, tree, tree));
+static void set_vindex PARAMS ((tree, tree, int *));
+static tree build_rtti_vtbl_entries PARAMS ((tree, tree));
+static void build_vcall_and_vbase_vtbl_entries PARAMS ((tree, 
+                                                       vcall_offset_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, tree *, tree *));
+static tree dfs_build_vtt_inits PARAMS ((tree, void *));
+static tree dfs_fixup_binfo_vtbls PARAMS ((tree, void *));
+static int indirect_primary_base_p PARAMS ((tree, tree));
 
 /* Variables shared between class.c and call.c.  */
 
@@ -225,7 +258,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);
@@ -237,7 +270,7 @@ build_vbase_pointer_fields (rli, empty_p)
                                            empty_p);
          BINFO_VPTR_FIELD (base_binfo) = decl;
          TREE_CHAIN (decl) = vbase_decls;
-         layout_field (rli, decl);
+         place_field (rli, decl);
          vbase_decls = decl;
          *empty_p = 0;
 
@@ -250,236 +283,6 @@ build_vbase_pointer_fields (rli, empty_p)
   return vbase_decls;
 }
 
-/* Called from build_vbase_offset_vtbl_entries via dfs_walk.  */
-
-static tree
-dfs_build_vbase_offset_vtbl_entries (binfo, data)
-     tree binfo;
-     void *data;
-{
-  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 (TREE_TYPE (binfo), TREE_PURPOSE (list));
-      if (!TREE_VALUE (list))
-       BINFO_VPTR_FIELD (vbase) = build_int_2 (-1, 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));
-       }
-
-      /* 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));
-    }
-
-  SET_BINFO_VTABLE_PATH_MARKED (binfo);
-  
-  return NULL_TREE;
-}
-
-/* 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.  */
-
-static tree
-build_vbase_offset_vtbl_entries (binfo, t)
-     tree binfo;
-     tree t;
-{
-  tree inits;
-  tree init;
-  tree list;
-
-  /* Under the old ABI, pointers to virtual bases are stored in each
-     object.  */
-  if (!vbase_offsets_in_vtable_p ())
-    return NULL_TREE;
-
-  /* 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,
-           dfs_vtable_path_unmarked_real_bases_queue_p,
-           list);
-  dfs_walk (binfo,
-           dfs_vtable_path_unmark,
-           dfs_vtable_path_marked_real_bases_queue_p,
-           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;
-}
-
-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 build_vcall_offset_vtbl_entries via dfs_walk.  */
-
-static tree
-dfs_vcall_offset_queue_p (binfo, data)
-     tree binfo;
-     void *data;
-{
-  vcall_offset_data* vod = (vcall_offset_data *) data;
-
-  return (binfo == vod->vbase) ? binfo : dfs_skip_vbases (binfo, NULL);
-}
-
-/* Called from build_vcall_offset_vtbl_entries via dfs_walk.  */
-
-static tree
-dfs_build_vcall_offset_vtbl_entries (binfo, data)
-     tree binfo;
-     void *data;
-{
-  vcall_offset_data* vod;
-  tree virtuals;
-  tree binfo_inits;
-
-  /* Primary bases are not interesting; all of the virtual
-     function table entries have been overridden.  */
-  if (BINFO_PRIMARY_MARKED_P (binfo))
-     return NULL_TREE;
-
-  vod = (vcall_offset_data *) data;
-  binfo_inits = NULL_TREE;
-
-  /* We chain the offsets on in reverse order.  That's correct --
-     build_vtbl_initializer will straighten them out.  */
-  for (virtuals = skip_rtti_stuff (binfo,
-                                  BINFO_TYPE (binfo),
-                                  NULL);
-       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);
-
-      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);
-    }
-
-  /* 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.  */
-
-static tree
-build_vcall_offset_vtbl_entries (binfo, t)
-     tree binfo;
-     tree t;
-{
-  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;
-
-  /* We only need these entries if this base is a virtual base.  */
-  if (!TREE_VIA_VIRTUAL (binfo))
-    return NULL_TREE;
-
-  /* We need a vcall offset for each of the virtual functions in this
-     vtable.  For example:
-
-       class A { virtual void f (); };
-       class B : virtual public A { };
-       class C: virtual public A, public B {};
-      
-     Now imagine:
-
-       B* b = new C;
-       b->f();
-
-     The location of `A' is not at a fixed offset relative to `B'; the
-     offset depends on the complete object derived from `B'.  So, 
-     `B' vtable contains an entry for `f' that indicates by what
-     amount the `this' pointer for `B' needs to be adjusted to arrive
-     at `A'.  
-
-     We need entries for all the functions in our primary vtable and
-     in our non-virtual bases vtables.  For each base, the entries
-     appear in the same order as in the base; but the bases themselves
-     appear in reverse depth-first, left-to-right order.  */
-  vod.derived = t;
-  vod.vbase = binfo;
-  vod.inits = NULL_TREE;
-  dfs_walk (binfo,
-           dfs_build_vcall_offset_vtbl_entries,
-           dfs_vcall_offset_queue_p,
-           &vod);
-
-  return vod.inits;
-}
-
 /* Returns a pointer to the virtual base class of EXP that has the
    indicated TYPE.  EXP is of class type, not a pointer type.  */
 
@@ -494,13 +297,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);
@@ -672,75 +476,6 @@ build_vbase_path (code, type, expr, path, nonnull)
 \f
 /* Virtual function things.  */
 
-/* Build an entry in the virtual function table.  DELTA is the offset
-   for the `this' pointer.  VCALL_INDEX is the vtable index containing
-   the vcall offset; zero if none.  ENTRY is the virtual function
-   table entry itself.  It's TREE_TYPE must be VFUNC_PTR_TYPE_NODE,
-   but it may not actually be a virtual function table pointer.  (For
-   example, it might be the address of the RTTI object, under the new
-   ABI.)  */
-
-static tree
-build_vtable_entry (delta, vcall_index, entry)
-     tree delta;
-     tree vcall_index;
-     tree entry;
-{
-  if (flag_vtable_thunks)
-    {
-      HOST_WIDE_INT idelta;
-      HOST_WIDE_INT ivindex;
-
-      idelta = tree_low_cst (delta, 0);
-      ivindex = tree_low_cst (vcall_index, 0);
-      if ((idelta || ivindex) 
-         && ! DECL_PURE_VIRTUAL_P (TREE_OPERAND (entry, 0)))
-       {
-         entry = make_thunk (entry, idelta, ivindex);
-         entry = build1 (ADDR_EXPR, vtable_entry_type, entry);
-         TREE_READONLY (entry) = 1;
-         TREE_CONSTANT (entry) = 1;
-       }
-#ifdef GATHER_STATISTICS
-      n_vtable_entries += 1;
-#endif
-      return 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);
-
-      /* DELTA used to be constructed by `size_int' and/or size_binop,
-        which caused overflow problems when it was negative.  That should
-        be fixed now.  */
-
-      if (! int_fits_type_p (delta, delta_type_node))
-       {
-         if (flag_huge_objects)
-           sorry ("object size exceeds built-in limit for virtual function table implementation");
-         else
-           sorry ("object size exceeds normal limit for virtual function table implementation, recompile all source and use -fhuge-objects");
-       }
-      
-      TREE_CONSTANT (entry) = 1;
-      TREE_STATIC (entry) = 1;
-      TREE_READONLY (entry) = 1;
-
-#ifdef GATHER_STATISTICS
-      n_vtable_entries += 1;
-#endif
-
-      return entry;
-    }
-}
-
 /* We want to give the assembler the vtable identifier as well as
    the offset to the function pointer.  So we generate
 
@@ -755,7 +490,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);
@@ -826,7 +563,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);
     }
@@ -882,22 +635,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.  */
@@ -906,13 +662,9 @@ tree
 get_vfield_offset (binfo)
      tree binfo;
 {
-  tree tmp
-    = size_binop (FLOOR_DIV_EXPR,
-                 bit_position (TYPE_VFIELD (BINFO_TYPE (binfo))),
-                 bitsize_int (BITS_PER_UNIT));
-
-  return size_binop (PLUS_EXPR, convert (sizetype, tmp),
-                    BINFO_OFFSET (binfo));
+  return
+    size_binop (PLUS_EXPR, byte_position (TYPE_VFIELD (BINFO_TYPE (binfo))),
+               BINFO_OFFSET (binfo));
 }
 
 /* Get the offset to the start of the original binfo that we derived
@@ -943,50 +695,9 @@ get_derived_offset (binfo, type)
   return size_binop (MINUS_EXPR, offset1, offset2);
 }
 
-/* Update the rtti info for this class.  */
-
-static void
-set_rtti_entry (virtuals, offset, type)
-     tree virtuals, offset, type;
-{
-  tree decl;
-
-  if (CLASSTYPE_COM_INTERFACE (type))
-    return;
-
-  if (flag_rtti)
-    decl = get_tinfo_decl (type);
-  else if (!new_abi_rtti_p ())
-    /* If someone tries to get RTTI information for a type compiled
-       without RTTI, they're out of luck.  By calling __pure_virtual
-       in this case, we give a small clue as to what went wrong.  We
-       could consider having a __no_typeinfo function as well, for a
-       more specific hint.  */
-    decl = abort_fndecl;
-  else
-    /* For the new-abi, we just point to the type_info object.  */
-    decl = NULL_TREE;
-
-  if (flag_vtable_thunks)
-    {
-      /* The first slot holds the offset.  */
-      BV_DELTA (virtuals) = offset;
-      BV_VCALL_INDEX (virtuals) = integer_zero_node;
-
-      /* The next node holds the decl.  */
-      virtuals = TREE_CHAIN (virtuals);
-      offset = integer_zero_node;
-    }
-
-  /* This slot holds the function to call.  */
-  BV_DELTA (virtuals) = offset;
-  BV_VCALL_INDEX (virtuals) = integer_zero_node;
-  BV_FN (virtuals) = decl;
-}
-
-/* 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.  Use NAME for the name of the vtable, and VTABLE_TYPE
+   for its type.  */
 
 static tree
 build_vtable (class_type, name, vtable_type)
@@ -1033,7 +744,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) */
@@ -1041,11 +753,31 @@ get_vtable_decl (type, complete)
                           DECL_ALIGN (decl));
 
   if (complete)
-    cp_finish_decl (decl, NULL_TREE, NULL_TREE, 0);
+    {
+      DECL_EXTERNAL (decl) = 1;
+      cp_finish_decl (decl, NULL_TREE, NULL_TREE, 0);
+    }
 
   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;
+
+  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
@@ -1062,23 +794,15 @@ build_primary_vtable (binfo, type)
   
   if (binfo)
     {
-      tree offset;
-
-      if (BINFO_NEW_VTABLE_MARKED (binfo))
+      if (BINFO_NEW_VTABLE_MARKED (binfo, type))
        /* We have already created a vtable for this base, so there's
           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)));
-
-      /* Now do rtti stuff.  */
-      offset = get_derived_offset (TYPE_BINFO (type), NULL_TREE);
-      offset = size_diffop (size_zero_node, offset);
-      set_rtti_entry (virtuals, offset, type);
+      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
     {
@@ -1098,7 +822,7 @@ build_primary_vtable (binfo, type)
   TYPE_BINFO_VIRTUALS (type) = virtuals;
 
   binfo = TYPE_BINFO (type);
-  SET_BINFO_NEW_VTABLE_MARKED (binfo);
+  SET_BINFO_NEW_VTABLE_MARKED (binfo, type);
   return 1;
 }
 
@@ -1135,25 +859,25 @@ 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);
 
-  if (BINFO_NEW_VTABLE_MARKED (binfo))
+  if (BINFO_NEW_VTABLE_MARKED (binfo, current_class_type))
     /* We already created a vtable for this base.  There's no need to
        do it again.  */
     return 0;
 
   /* Remember that we've created a vtable for this BINFO, so that we
      don't try to do so again.  */
-  SET_BINFO_NEW_VTABLE_MARKED (binfo);
+  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
@@ -1166,10 +890,6 @@ build_secondary_vtable (binfo, for_type)
   else
     offset = BINFO_OFFSET (binfo);
 
-  set_rtti_entry (BINFO_VIRTUALS (binfo),
-                 size_diffop (size_zero_node, offset),
-                 for_type);
-
   /* In the new ABI, secondary vtables are laid out as part of the
      same structure as the primary vtable.  */
   if (merge_primary_and_secondary_vtables_p ())
@@ -1293,9 +1013,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)
@@ -1305,15 +1025,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;
 
@@ -1331,7 +1048,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
@@ -1344,42 +1061,52 @@ modify_vtable_entry (t, binfo, fndecl, delta, virtuals)
     }
 }
 
-/* Call this function whenever its known that a vtable for T is going
-   to be needed.  It's safe to call it more than once.  *HAS_VIRTUAL_P
-   is initialized to the number of slots that are reserved at the
-   beginning of the vtable for RTTI information.  */
+/* Return the index (in the virtual function table) of the first
+   virtual function.  */
+
+int
+first_vfun_index (t)
+     tree t;
+{
+  /* Under the old ABI, the offset-to-top and RTTI entries are at
+     indices zero and one; under the new ABI, the first virtual
+     function is at index zero.  */
+  if (!CLASSTYPE_COM_INTERFACE (t) && !flag_new_abi)
+    return flag_vtable_thunks ? 2 : 1;
+
+  return 0;
+}
+
+/* Set DECL_VINDEX for DECL.  VINDEX_P is the number of virtual
+   functions present in the vtable so far.  */
 
 static void
-start_vtable (t, has_virtual_p)
+set_vindex (t, decl, vfuns_p)
      tree t;
-     int *has_virtual_p;
+     tree decl;
+     int *vfuns_p;
 {
-  if (*has_virtual_p == 0 && ! CLASSTYPE_COM_INTERFACE (t))
-    {
-      /* If we are using thunks, use two slots at the front, one
-        for the offset pointer, one for the tdesc pointer.
-         For ARM-style vtables, use the same slot for both.  */
-      if (flag_vtable_thunks)
-       *has_virtual_p = 2;
-      else
-       *has_virtual_p = 1;
-    }
+  int vindex;
+
+  vindex = (*vfuns_p)++;
+  vindex += first_vfun_index (t);
+  DECL_VINDEX (decl) = build_shared_int_cst (vindex);
 }
 
 /* Add a virtual function to all the appropriate vtables for the class
    T.  DECL_VINDEX(X) should be error_mark_node, if we want to
    allocate a new slot in our table.  If it is error_mark_node, we
    know that no other function from another vtable is overridden by X.
-   HAS_VIRTUAL keeps track of how many virtuals there are in our main
-   vtable for the type, and we build upon the NEW_VIRTUALS list
+   VFUNS_P keeps track of how many virtuals there are in our
+   main vtable for the type, and we build upon the NEW_VIRTUALS list
    and return it.  */
 
 static void
 add_virtual_function (new_virtuals_p, overridden_virtuals_p,
-                     has_virtual, fndecl, t)
+                     vfuns_p, fndecl, t)
      tree *new_virtuals_p;
      tree *overridden_virtuals_p;
-     int *has_virtual;
+     int *vfuns_p;
      tree fndecl;
      tree t; /* Structure type.  */
 {
@@ -1393,8 +1120,8 @@ 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 = build_tree_list (NULL_TREE, fndecl);
+  BV_DELTA (new_virtual) = integer_zero_node;
 
   if (DECL_VINDEX (fndecl) == error_mark_node)
     {
@@ -1404,10 +1131,8 @@ add_virtual_function (new_virtuals_p, overridden_virtuals_p,
       /* We remember that this was the base sub-object for rtti.  */
       CLASSTYPE_RTTI (t) = t;
 
-      start_vtable (t, has_virtual);
-
       /* Now assign virtual dispatch information.  */
-      DECL_VINDEX (fndecl) = build_shared_int_cst ((*has_virtual)++);
+      set_vindex (t, fndecl, vfuns_p);
       DECL_VIRTUAL_CONTEXT (fndecl) = t;
 
       /* Save the state we've computed on the NEW_VIRTUALS list.  */
@@ -1460,14 +1185,15 @@ add_method (type, fields, method)
       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;
+      /* Constructors and destructors go in special slots.  */
+      if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (method))
+       slot = CLASSTYPE_CONSTRUCTOR_SLOT;
+      else if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (method))
+       slot = CLASSTYPE_DESTRUCTOR_SLOT;
       else
        {
          /* See if we already have an entry with this name.  */
-         for (slot = 2; slot < len; ++slot)
+         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))) 
@@ -1722,7 +1448,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)
@@ -1803,8 +1534,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)
     ;
@@ -1961,13 +1690,112 @@ check_bases (t, cant_have_default_ctor_p, cant_have_const_ctor_p,
     }
 }
 
+/* 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;
+{
+  int i;
+  tree base_binfo;
+
+  if (!CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (binfo)))
+    return NULL_TREE;
+
+  i = CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
+  base_binfo = BINFO_BASETYPE (binfo, i);
+
+  if (!TREE_VIA_VIRTUAL (base_binfo))
+    /* Non-virtual base classes are easy.  */
+    BINFO_PRIMARY_MARKED_P (base_binfo) = 1;
+  else
+    {
+      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_VBASE_PRIMARY_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;
+
+         BINFO_VBASE_PRIMARY_P (base_binfo) = 1;
+         BINFO_PRIMARY_MARKED_P (base_binfo) = 1;
+       }
+    }
+
+  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_VBASE_PRIMARY_P (vbase))
+       /* This virtual base was already included in the hierarchy, so
+          there's nothing to do here.  */
+       continue;
+
+      /* Temporarily pretend that VBASE is primary so that its bases
+        will be walked; this is the real copy of VBASE.  */
+      BINFO_PRIMARY_MARKED_P (vbase) = 1;
+
+      /* Now, walk its bases.  */
+      dfs_walk_real (vbase, dfs_mark_primary_bases, NULL,
+                    dfs_skip_nonprimary_vbases_unmarkedp, type);
+
+      /* VBASE wasn't really primary.  */
+      BINFO_PRIMARY_MARKED_P (vbase) = 0;
+    }
+}
+
 /* Make the Ith baseclass of T its primary base.  */
 
 static void
-set_primary_base (t, i, has_virtual_p)
+set_primary_base (t, i, vfuns_p)
      tree t;
      int i;
-     int *has_virtual_p;
+     int *vfuns_p;
 {
   tree basetype;
 
@@ -1977,15 +1805,44 @@ set_primary_base (t, i, has_virtual_p)
   TYPE_BINFO_VIRTUALS (t) = TYPE_BINFO_VIRTUALS (basetype);
   TYPE_VFIELD (t) = TYPE_VFIELD (basetype);
   CLASSTYPE_RTTI (t) = CLASSTYPE_RTTI (basetype);
-  *has_virtual_p = CLASSTYPE_VSIZE (basetype);
+  *vfuns_p = CLASSTYPE_VSIZE (basetype);
+}
+
+/* Returns true iff BINFO (a direct virtual base of T) is an indirect
+   primary base.  */
+
+static int
+indirect_primary_base_p (t, binfo)
+     tree t;
+     tree binfo;
+{
+  int i;
+
+  for (i = 0; i < CLASSTYPE_N_BASECLASSES (t); ++i)
+    {
+      tree type;
+      tree b;
+
+      /* Figure out to which type the Ith base corresponds.  */
+      type = TYPE_BINFO_BASETYPE (t, i);
+      /* See if any of the primary bases have the same type as BINFO.  */
+      for (b = TYPE_BINFO (type); b; b = TREE_CHAIN (b))
+       /* If this base is primary, and has the same type as BINFO,
+          then BINFO is an indirect primary base.  */
+       if (BINFO_PRIMARY_MARKED_P (b)
+           && same_type_p (BINFO_TYPE (b), BINFO_TYPE (binfo)))
+         return 1;
+    }
+
+  return 0;
 }
 
 /* Determine the primary class for T.  */
 
 static void
-determine_primary_base (t, has_virtual_p)
+determine_primary_base (t, vfuns_p)
      tree t;
-     int *has_virtual_p;
+     int *vfuns_p;
 {
   int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (t);
 
@@ -1993,7 +1850,7 @@ determine_primary_base (t, has_virtual_p)
   if (n_baseclasses == 0)
     return;
 
-  *has_virtual_p = 0;
+  *vfuns_p = 0;
 
   for (i = 0; i < n_baseclasses; i++)
     {
@@ -2016,7 +1873,7 @@ determine_primary_base (t, has_virtual_p)
 
          if (!CLASSTYPE_HAS_PRIMARY_BASE_P (t))
            {
-             set_primary_base (t, i, has_virtual_p);
+             set_primary_base (t, i, vfuns_p);
              CLASSTYPE_VFIELDS (t) = copy_list (CLASSTYPE_VFIELDS (basetype));
            }
          else
@@ -2034,8 +1891,8 @@ determine_primary_base (t, has_virtual_p)
                                 VF_BASETYPE_VALUE (vfields),
                                 CLASSTYPE_VFIELDS (t));
 
-             if (*has_virtual_p == 0)
-               set_primary_base (t, i, has_virtual_p);
+             if (!flag_new_abi && *vfuns_p == 0)
+               set_primary_base (t, i, vfuns_p);
            }
        }
     }
@@ -2047,19 +1904,50 @@ determine_primary_base (t, has_virtual_p)
      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 -1, this is the index in TYPE_BINFO_BASETYPEs of the
+        best primary base candidate we have found so far.  */
+      int candidate = -1;
 
-       if (TREE_VIA_VIRTUAL (base_binfo) 
-           && CLASSTYPE_NEARLY_EMPTY_P (basetype))
-         {
-           set_primary_base (t, i, has_virtual_p);
-           CLASSTYPE_VFIELDS (t) = copy_list (CLASSTYPE_VFIELDS (basetype));
-           break;
-         }
-      }
+      /* Loop over the baseclasses.  */
+      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 (TREE_VIA_VIRTUAL (base_binfo) 
+             && CLASSTYPE_NEARLY_EMPTY_P (basetype))
+           {
+             int indirect_primary_p;
+
+             /* Figure out whether or not this base is an indirect
+                primary base.  */
+             indirect_primary_p = indirect_primary_base_p (t, base_binfo);
+
+             /* If this is not an indirect primary base, then it's
+                definitely our primary base.  */
+             if (!indirect_primary_p) 
+               {
+                 candidate = i;
+                 break;
+               }
+             /* If this was an indirect primary base, it's still our
+                primary base -- unless there's another nearly-empty
+                virtual base that isn't an indirect primary base.  */
+             else if (candidate == -1)
+               candidate = i;
+           }
+       }
+
+      /* If we've got a primary base, use it.  */
+      if (candidate != -1) 
+       {
+         set_primary_base (t, candidate, vfuns_p);
+         CLASSTYPE_VFIELDS (t) 
+           = copy_list (CLASSTYPE_VFIELDS (TYPE_BINFO_BASETYPE (t, 
+                                                                candidate)));
+       }       
+    }
 
   /* Mark the primary base classes at this point.  */
   mark_primary_bases (t);
@@ -2341,14 +2229,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)
@@ -2356,7 +2239,6 @@ finish_struct_methods (t)
 {
   tree fn_fields;
   tree method_vec;
-  tree ctor_name = constructor_name (t);
   int slot, len;
 
   if (!TYPE_METHODS (t))
@@ -2377,52 +2259,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.
+    /* Clear out this flag.  */
+    DECL_IN_AGGR_P (fn_fields) = 0;
 
-        @@ 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;
-           }
-       }
-    }
-
-  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;
@@ -2522,6 +2362,7 @@ layout_vtable_decl (binfo, n)
 {
   tree itype;
   tree atype;
+  tree vtable;
 
   itype = size_int (n);
   atype = build_cplus_array_type (vtable_entry_type, 
@@ -2529,12 +2370,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
@@ -2544,382 +2384,84 @@ 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.  */
+/* True if we should override the given BASE_FNDECL with the given
+   FNDECL.  */
 
 static int
-num_vfun_entries (binfo)
-     tree binfo;
-{
-  return list_length (skip_rtti_stuff (binfo,
-                                      BINFO_TYPE (binfo),
-                                      NULL));
-}
-
-/* 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;
+overrides (fndecl, base_fndecl)
+     tree fndecl, base_fndecl;
 {
-  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));
+  /* 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;
+  /* 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 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))
+  if (DECL_NAME (fndecl) == DECL_NAME (base_fndecl))
     {
-      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;
+      tree types, base_types;
+      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)))
+          == TYPE_QUALS (TREE_TYPE (TREE_VALUE (types))))
+         && compparms (TREE_CHAIN (base_types), TREE_CHAIN (types)))
+       return 1;
     }
-      
-  return entries ? size_int (entries) : size_zero_node;
+  return 0;
 }
 
-/* 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);
-}
+typedef struct find_final_overrider_data_s {
+  /* The function for which we are trying to find a final overrider.  */
+  tree fn;
+  /* The base class in which the function was declared.  */
+  tree declaring_base;
+  /* The most derived class in the hierarchy.  */
+  tree most_derived_type;
+  /* The final overriding function.  */
+  tree overriding_fn;
+  /* The BINFO for the class in which the final overriding function
+     appears.  */
+  tree overriding_base;
+} find_final_overrider_data;
 
-/* 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.  */
+/* Called from find_final_overrider via dfs_walk.  */
 
 static tree
-build_vtbl_initializer (binfo, t)
+dfs_find_final_overrider (binfo, data)
      tree binfo;
-     tree t;
+     void *data;
 {
-  tree v = BINFO_VIRTUALS (binfo);
-  tree inits = NULL_TREE;
-  tree type = BINFO_TYPE (binfo);
-
-  /* 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);
-
-  /* Add entries to the vtable for offsets to our virtual bases.  */
-  inits = chainon (build_vbase_offset_vtbl_entries (binfo, t),
-                  inits);
+  find_final_overrider_data *ffod = (find_final_overrider_data *) data;
 
-  /* Process the RTTI stuff at the head of the list.  If we're not
-     using vtable thunks, then the RTTI entry is just an ordinary
-     function, and we can process it just like the other virtual
-     function entries.  */
-  if (!CLASSTYPE_COM_INTERFACE (type) && flag_vtable_thunks)
+  if (same_type_p (BINFO_TYPE (binfo), 
+                  BINFO_TYPE (ffod->declaring_base))
+      && tree_int_cst_equal (BINFO_OFFSET (binfo),
+                            BINFO_OFFSET (ffod->declaring_base)))
     {
-      tree offset;
-      tree init;
-
-      /* The first entry is an offset.  */
-      offset = TREE_PURPOSE (v);
-      my_friendly_assert (TREE_CODE (offset) == INTEGER_CST,
-                         19990727);
-
-      /* 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);
-
-      v = TREE_CHAIN (v);
-      
-      if (new_abi_rtti_p ())
-        {
-          tree decl = TREE_VALUE (v);
-          
-          if (decl)
-            decl = build_unary_op (ADDR_EXPR, decl, 0);
-          else
-            decl = integer_zero_node;
-          decl = build1 (NOP_EXPR, vfunc_ptr_type_node, decl);
-          TREE_CONSTANT (decl) = 1;
-          decl = build_vtable_entry (integer_zero_node, integer_zero_node,
-                                     decl);
-          inits = tree_cons (NULL_TREE, decl, inits);
-          
-          v = TREE_CHAIN (v);
-        }
-      /* In the old abi the second entry (the tdesc pointer) is
-        just an ordinary function, so it can be dealt with like the
-        virtual functions.  */
-    }
+      tree path;
+      tree method;
 
-  /* Go through all the ordinary virtual functions, building up
-     initializers.  */
-  while (v)
-    {
-      tree delta;
-      tree vcall_index;
-      tree fn;
-      tree pfn;
-      tree init;
+      /* We've found a path to the declaring base.  Walk down the path
+        looking for an overrider for FN.  */
+      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))
+             break;
 
-      /* Pull the offset for `this', and the function to call, out of
-        the list.  */
-      delta = BV_DELTA (v);
-      vcall_index = BV_VCALL_INDEX (v);
-      fn = BV_FN (v);
-      my_friendly_assert (TREE_CODE (delta) == INTEGER_CST, 19990727);
-      my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727);
-
-      /* You can't call an abstract virtual function; it's abstract.
-        So, we replace these functions with __pure_virtual.  */
-      if (DECL_PURE_VIRTUAL_P (fn))
-       fn = abort_fndecl;
-
-      /* Take the address of the function, considering it to be of an
-        appropriate generic type.  */
-      pfn = build1 (ADDR_EXPR, vfunc_ptr_type_node, fn);
-      /* 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);
-      /* And add it to the chain of initializers.  */
-      inits = tree_cons (NULL_TREE, init, inits);
-
-      /* Keep going.  */
-      v = TREE_CHAIN (v);
-    }
-
-  /* The initializers were built up in reverse order; straighten them
-     out now.  */
-  return nreverse (inits);
-}
-
-/* Initialize the vtable for BINFO with the INITS.  */
-
-static void
-initialize_vtable (binfo, inits)
-     tree binfo;
-     tree inits;
-{
-  tree context;
-  tree decl;
-
-  layout_vtable_decl (binfo, list_length (inits));
-  decl = BINFO_VTABLE (binfo);
-  context = DECL_CONTEXT (decl);
-  DECL_CONTEXT (decl) = 0;
-  DECL_INITIAL (decl) = build_nt (CONSTRUCTOR, NULL_TREE, inits);
-  cp_finish_decl (decl, DECL_INITIAL (decl), NULL_TREE, 0);
-  DECL_CONTEXT (decl) = context;
-}
-
-/* Called from finish_vtbls via dfs_walk.  */
-
-static tree
-dfs_finish_vtbls (binfo, data)
-     tree binfo;
-     void *data;
-{
-  if (!BINFO_PRIMARY_MARKED_P (binfo)
-      && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))
-      && BINFO_NEW_VTABLE_MARKED (binfo))
-    initialize_vtable (binfo, 
-                      build_vtbl_initializer (binfo, (tree) data));
-
-  CLEAR_BINFO_NEW_VTABLE_MARKED (binfo);
-  SET_BINFO_MARKED (binfo);
-
-  return NULL_TREE;
-}
-
-/* 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).  */
-
-static tree
-dfs_accumulate_vtbl_inits (binfo, data)
-     tree binfo;
-     void *data;
-{
-  if (!BINFO_PRIMARY_MARKED_P (binfo)
-      && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))
-      && BINFO_NEW_VTABLE_MARKED (binfo))
-    {
-      tree l;
-      tree t;
-
-      l = (tree) data;
-      t = TREE_PURPOSE (l);
-
-      /* 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)))));
-       }
-
-      /* Add the initializers for this vtable to the initailizers for
-        the other vtables we've already got.  */
-      TREE_VALUE (l) 
-       = chainon (TREE_VALUE (l),
-                  build_vtbl_initializer (binfo, t));
-    }
-
-  CLEAR_BINFO_NEW_VTABLE_MARKED (binfo);
-  SET_BINFO_MARKED (binfo);
-
-  return NULL_TREE;
-}
-
-/* Create all the necessary vtables for T and its base classes.  */
-
-static void
-finish_vtbls (t)
-     tree t;
-{
-  if (merge_primary_and_secondary_vtables_p ())
-    {
-      tree list;
-
-      /* Under the new ABI, we lay out the primary and secondary
-        vtables in one contiguous vtable.  The primary vtable is
-        first, followed by the secondary vtables as encountered in a
-        pre-order depth-first left-to-right traversal.  */
-      list = build_tree_list (t, NULL_TREE);
-      dfs_walk_real (TYPE_BINFO (t), 
-                    dfs_accumulate_vtbl_inits,
-                    NULL, 
-                    dfs_unmarked_real_bases_queue_p, 
-                    list);
-      if (TYPE_BINFO_VTABLE (t))
-       initialize_vtable (TYPE_BINFO (t), TREE_VALUE (list));
-    }
-  else
-    dfs_walk (TYPE_BINFO (t), dfs_finish_vtbls, 
-             dfs_unmarked_real_bases_queue_p, t);
-
-  dfs_walk (TYPE_BINFO (t), dfs_unmark, 
-           dfs_marked_real_bases_queue_p, t);
-}
-
-/* True if we should override the given BASE_FNDECL with the given
-   FNDECL.  */
-
-static int
-overrides (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)))
-    return 1;
-  if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (base_fndecl))
-      || DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (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)))
-          == TYPE_QUALS (TREE_TYPE (TREE_VALUE (types))))
-         && compparms (TREE_CHAIN (base_types), TREE_CHAIN (types)))
-       return 1;
-    }
-  return 0;
-}
-
-typedef struct find_final_overrider_data_s {
-  /* The function for which we are trying to find a final overrider.  */
-  tree fn;
-  /* The base class in which the function was declared.  */
-  tree declaring_base;
-  /* The most derived class in the hierarchy.  */
-  tree most_derived_type;
-  /* The final overriding function.  */
-  tree overriding_fn;
-  /* The BINFO for the class in which the final overriding function
-     appears.  */
-  tree overriding_base;
-} find_final_overrider_data;
-
-/* Called from find_final_overrider via dfs_walk.  */
-
-static tree
-dfs_find_final_overrider (binfo, data)
-     tree binfo;
-     void *data;
-{
-  find_final_overrider_data *ffod = (find_final_overrider_data *) data;
-
-  if (same_type_p (BINFO_TYPE (binfo), 
-                  BINFO_TYPE (ffod->declaring_base))
-      && tree_int_cst_equal (BINFO_OFFSET (binfo),
-                            BINFO_OFFSET (ffod->declaring_base)))
-    {
-      tree path;
-      tree method;
-
-      /* We've found a path to the declaring base.  Walk down the path
-        looking for an overrider for FN.  */
-      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))
-             break;
-
-         if (method)
-           break;
-       }
+         if (method)
+           break;
+       }
 
       /* If we found an overrider, record the overriding function, and
         the base from which it came.  */
@@ -3021,43 +2563,6 @@ find_final_overrider (t, binfo, fn)
   return build_tree_list (ffod.overriding_fn, ffod.overriding_base);
 }
 
-/* Return the BINFO_VIRTUALS list for BINFO, without the RTTI stuff at
-   the front.  If non-NULL, N is set to the number of entries
-   skipped.  */
-
-tree
-skip_rtti_stuff (binfo, t, n)
-     tree binfo;
-     tree t;
-     HOST_WIDE_INT *n;
-{
-  tree virtuals;
-
-  if (CLASSTYPE_COM_INTERFACE (t))
-    return 0;
-
-  if (n)
-    *n = 0;
-  virtuals = BINFO_VIRTUALS (binfo);
-  if (virtuals)
-    {
-      /* We always reserve a slot for the offset/tdesc entry.  */
-      if (n)
-       ++*n;
-      virtuals = TREE_CHAIN (virtuals);
-    }
-  if (flag_vtable_thunks && virtuals)
-    {
-      /* The second slot is reserved for the tdesc pointer when thunks
-         are used.  */
-      if (n)
-       ++*n;
-      virtuals = TREE_CHAIN (virtuals);
-    }
-
-  return virtuals;
-}
-
 /* Called via dfs_walk.  Returns BINFO if BINFO has the same type as
    DATA (which is really an _TYPE node).  */
 
@@ -3070,6 +2575,84 @@ dfs_find_base (binfo, data)
          ? binfo : NULL_TREE);
 }
 
+/* Update a entry in the vtable for BINFO, which is in the hierarchy
+   dominated by T.  FN has been overridden in BINFO; VIRTUALS points
+   to the corresponding position in the BINFO_VIRTUALS list.  */
+
+static void
+update_vtable_entry_for_fn (t, binfo, fn, virtuals)
+     tree t;
+     tree binfo;
+     tree fn;
+     tree *virtuals;
+{
+  tree b;
+  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.  */
+  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)
+    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));
+  if (flag_new_abi)
+    {
+      /* Under the new ABI, we only need to adjust as far as the
+        nearest virtual base.  Then we use the vcall offset in the
+        virtual bases vtable.  */
+      for (b = binfo; b; b = BINFO_INHERITANCE_CHAIN (b))
+       {
+         if (TREE_VIA_VIRTUAL (b))
+           break;
+         if (same_type_p (BINFO_TYPE (b), 
+                          BINFO_TYPE (TREE_VALUE (overrider))))
+           break;
+       }
+    }
+  else
+    b = NULL_TREE;
+
+  if (b && TREE_VIA_VIRTUAL (b))
+    /* The `this' pointer needs to be adjusted to the nearest virtual
+       base.  */
+    delta = size_diffop (BINFO_OFFSET (b), 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);
+}
+
 /* Called from modify_all_vtables via dfs_walk.  */
 
 static tree
@@ -3098,59 +2681,15 @@ dfs_modify_vtables (binfo, data)
       /* Now, go through each of the virtual functions in the virtual
         function table for BINFO.  Find the final overrider, and
         update the BINFO_VIRTUALS list appropriately.  */
-      for (virtuals = skip_rtti_stuff (binfo, BINFO_TYPE (binfo), NULL),
-            old_virtuals = skip_rtti_stuff (TYPE_BINFO (BINFO_TYPE (binfo)),
-                                            BINFO_TYPE (binfo),
-                                            NULL);
+      for (virtuals = BINFO_VIRTUALS (binfo),
+            old_virtuals = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (binfo)));
           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, 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 = skip_rtti_stuff (TYPE_BINFO (BINFO_TYPE (b)),
-                               BINFO_TYPE (b),
-                               &i);
-         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);
@@ -3168,9 +2707,9 @@ dfs_modify_vtables (binfo, data)
    which should therefore be appended to the end of the vtable for T.  */
 
 static tree
-modify_all_vtables (t, has_virtual_p, overridden_virtuals)
+modify_all_vtables (t, vfuns_p, overridden_virtuals)
      tree t;
-     int *has_virtual_p;
+     int *vfuns_p;
      tree overridden_virtuals;
 {
   tree binfo;
@@ -3194,14 +2733,11 @@ modify_all_vtables (t, has_virtual_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)))
            {
-             /* We know we need a vtable for this class now.  */
-             start_vtable (t, has_virtual_p);
              /* Set the vtable index.  */
-             DECL_VINDEX (fn) 
-               = build_shared_int_cst ((*has_virtual_p)++);
+             set_vindex (t, fn, vfuns_p);
              /* We don't need to convert to a base class when calling
                 this function.  */
              DECL_VIRTUAL_CONTEXT (fn) = t;
@@ -3209,7 +2745,7 @@ modify_all_vtables (t, has_virtual_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.  */
@@ -3316,8 +2852,7 @@ check_for_override (decl, ctype)
       if (TYPE_POLYMORPHIC_P (BINFO_TYPE (base_binfo)))
        {
          tree tmp = get_matching_virtual
-           (base_binfo, decl,
-            DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl)));
+           (base_binfo, decl, DECL_DESTRUCTOR_P (decl));
 
          if (tmp && !found_overriden_fn)
            {
@@ -3483,36 +3018,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.  */
@@ -3534,7 +3066,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;
     }
@@ -3544,8 +3076,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;
     }
@@ -3553,8 +3086,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;
     }
@@ -3637,7 +3171,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)
@@ -3731,7 +3265,7 @@ check_field_decl (field, t, cant_have_const_ctor,
       tree fields;
 
       for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields))
-       if (TREE_CODE (field) == FIELD_DECL && !DECL_C_BIT_FIELD (field))
+       if (TREE_CODE (fields) == FIELD_DECL && !DECL_C_BIT_FIELD (field))
          check_field_decl (fields, t, cant_have_const_ctor,
                            cant_have_default_ctor, no_const_asn_ref,
                            any_default_members);
@@ -3895,7 +3429,7 @@ check_field_decls (t, access_decls, empty_p,
       /* If we've gotten this far, it's a data member, possibly static,
         or an enumerator.  */
 
-      DECL_FIELD_CONTEXT (x) = t;
+      DECL_CONTEXT (x) = t;
 
       /* ``A local class cannot have static data members.'' ARM 9.4 */
       if (current_function_decl && TREE_STATIC (x))
@@ -3926,8 +3460,6 @@ check_field_decls (t, access_decls, empty_p,
       if (type == error_mark_node)
        continue;
          
-      DECL_SAVED_INSNS (x) = 0;
-
       /* When this goes into scope, it will be a non-local reference.  */
       DECL_NONLOCAL (x) = 1;
 
@@ -4016,6 +3548,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))
@@ -4077,35 +3616,18 @@ 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_SAVED_INSNS (field) = 0;
   DECL_ALIGN (field) = TYPE_ALIGN (type);
 
   /* Return it.  */
   return field;
 }
 
-/* Return the BINFO_OFFSET for BINFO as a native integer, not an
-   INTEGER_CST.  */
-
-static unsigned HOST_WIDE_INT
-get_binfo_offset_as_int (binfo)
-     tree binfo;
-{
-  tree offset;
-
-  offset = BINFO_OFFSET (binfo);
-  my_friendly_assert (TREE_CODE (offset) == INTEGER_CST, 20000313);
-  my_friendly_assert (TREE_INT_CST_HIGH (offset) == 0, 20000313);
-
-  return (unsigned HOST_WIDE_INT) TREE_INT_CST_LOW (offset);
-}
-
 /* Record the type of BINFO in the slot in DATA (which is really a
    `varray_type *') corresponding to the BINFO_OFFSET.  */
 
@@ -4115,7 +3637,7 @@ dfs_record_base_offsets (binfo, data)
      void *data;
 {
   varray_type *v;
-  unsigned HOST_WIDE_INT offset = get_binfo_offset_as_int (binfo);
+  unsigned HOST_WIDE_INT offset = tree_low_cst (BINFO_OFFSET (binfo), 1);
 
   v = (varray_type *) data;
   while (VARRAY_SIZE (*v) <= offset)
@@ -4127,6 +3649,19 @@ dfs_record_base_offsets (binfo, data)
   return NULL_TREE;
 }
 
+/* Add the offset of BINFO and its bases to BASE_OFFSETS.  */
+
+static void
+record_base_offsets (binfo, base_offsets)
+     tree binfo;
+     varray_type *base_offsets;
+{
+  dfs_walk (binfo,
+           dfs_record_base_offsets,
+           dfs_skip_vbases,
+           base_offsets);
+}
+
 /* 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.  */
@@ -4139,11 +3674,10 @@ dfs_search_base_offsets (binfo, data)
   if (is_empty_class (BINFO_TYPE (binfo)))
     {
       varray_type v = (varray_type) data;
-      unsigned HOST_WIDE_INT offset;
+      /* Find the offset for this BINFO.  */
+      unsigned HOST_WIDE_INT offset = tree_low_cst (BINFO_OFFSET (binfo), 1);
       tree t;
 
-      /* Find the offset for this BINFO.  */
-      offset = get_binfo_offset_as_int (binfo);
       /* If we haven't yet encountered any objects at offsets that
         big, then there's no conflict.  */
       if (VARRAY_SIZE (v) <= offset)
@@ -4158,6 +3692,19 @@ dfs_search_base_offsets (binfo, data)
   return NULL_TREE;
 }
 
+/* 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.  */
+
+static int
+layout_conflict_p (binfo, base_offsets)
+     tree binfo;
+     varray_type base_offsets;
+{
+  return dfs_walk (binfo, dfs_search_base_offsets, dfs_skip_vbases,
+                  base_offsets) != NULL_TREE;
+}
+
 /* 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
@@ -4180,16 +3727,17 @@ layout_nonempty_base_or_field (rli, decl, binfo, v)
   while (1)
     {
       tree offset;
+      struct record_layout_info_s old_rli = *rli;
 
-      /* Layout this field.  */
-      layout_field (rli, decl);
+      /* Place this field.  */
+      place_field (rli, decl);
       
       /* Now that we know where it wil be placed, update its
         BINFO_OFFSET.  */
-      offset = size_int (CEIL (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (decl)),
-                              BITS_PER_UNIT));
+      offset = byte_position (decl);
       if (binfo)
-       propagate_binfo_offsets (binfo, offset);
+       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.
@@ -4206,23 +3754,23 @@ 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 && dfs_walk (binfo,
-                                            dfs_search_base_offsets,
-                                            dfs_skip_vbases,
-                                            v))
+      if (binfo && flag_new_abi && layout_conflict_p (binfo, v))
        {
-         /* Undo the propogate_binfo_offsets call.  */
-         offset = convert (sizetype,
-                           size_diffop (size_zero_node, offset));
-         propagate_binfo_offsets (binfo, offset);
-
+         /* Undo the propagate_binfo_offsets call.  */
+         offset = size_diffop (size_zero_node, offset);
+         propagate_binfo_offsets (binfo, convert (ssizetype, offset));
+        
          /* Strip off the size allocated to this field.  That puts us
             at the first place we could have put the field with
             proper alignment.  */
-         rli->const_size -= TREE_INT_CST_LOW (DECL_SIZE (decl));
-         /* Bump up by th alignment required for the type, without
+         *rli = old_rli;
+
+         /* Bump up by the alignment required for the type, without
             virtual base classes.  */
-         rli->const_size += CLASSTYPE_ALIGN (BINFO_TYPE (binfo));
+         rli->bitpos
+           = size_binop (PLUS_EXPR, rli->bitpos,
+                         bitsize_int (CLASSTYPE_ALIGN (BINFO_TYPE (binfo))));
+         normalize_rli (rli);
        }
       else
        /* There was no conflict.  We're done laying out this field.  */
@@ -4230,10 +3778,47 @@ layout_nonempty_base_or_field (rli, decl, binfo, v)
     }
 }
 
+/* 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.  */
+
+static void
+layout_empty_base (binfo, eoc, binfo_offsets)
+     tree binfo;
+     tree eoc;
+     varray_type binfo_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_UNIT (basetype));
+
+  /* This is an empty base class.  We first try to put it at offset
+     zero.  */
+  if (layout_conflict_p (binfo, binfo_offsets))
+    {
+      /* 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))
+           /* We finally found a spot where there's no overlap.  */
+           break;
+
+         /* There's overlap here, too.  Bump along to the next spot.  */
+         propagate_binfo_offsets (binfo, alignment);
+       }
+    }
+}
+
 /* 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.  */
 
 static void
 build_base_field (rli, binfo, empty_p, base_align, v)
@@ -4251,7 +3836,7 @@ 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);
@@ -4261,10 +3846,9 @@ build_base_field (rli, binfo, empty_p, base_align, v)
   if (! flag_new_abi)
     {
       /* Brain damage for backwards compatibility.  For no good
-        reason, the old layout_basetypes made every base at least
+        reason, the old basetype layout made every base have at least
         as large as the alignment for the bases up to that point,
-        gratuitously wasting space.  So we do the same thing
-        here.  */
+        gratuitously wasting space.  So we do the same thing here.  */
       *base_align = MAX (*base_align, DECL_ALIGN (decl));
       DECL_SIZE (decl)
        = size_binop (MAX_EXPR, DECL_SIZE (decl), bitsize_int (*base_align));
@@ -4286,32 +3870,14 @@ build_base_field (rli, binfo, empty_p, base_align, v)
     }
   else
     {
-      /* This code assumes that zero-sized classes have one-byte
-        alignment.  There might someday be a system where that's not
-        true.  */
-      my_friendly_assert (TYPE_ALIGN (basetype) == BITS_PER_UNIT, 
-                         20000314);
+      unsigned HOST_WIDE_INT eoc;
 
-      /* This is an empty base class.  We first try to put it at
-        offset zero.  */
-      if (dfs_walk (binfo, dfs_search_base_offsets, dfs_skip_vbases, *v))
-       {
-         /* That didn't work.  Now, we move forward from the next
-            available spot in the class.  */
-         propagate_binfo_offsets (binfo, size_int (rli->const_size));
-         while (1) 
-           {
-             if (!dfs_walk (binfo, dfs_search_base_offsets, 
-                            dfs_skip_vbases, *v))
-               /* We finally found a spot where there's no overlap.  */
-               break;
-
-             /* There's overlap here, too.  Bump along to the next
-                spot.  */
-             propagate_binfo_offsets (binfo, size_one_node);
-           }
-       }
-    }
+      /* 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);
+    }
 
   /* Check for inaccessible base classes.  If the same base class
      appears more than once in the hierarchy, but isn't virtual, then
@@ -4321,10 +3887,7 @@ build_base_field (rli, binfo, empty_p, base_align, v)
                basetype, rli->t);
   
   /* Record the offsets of BINFO and its base subobjects.  */
-  dfs_walk (binfo,
-           dfs_record_base_offsets,
-           dfs_skip_vbases,
-           v);
+  record_base_offsets (binfo, v);
 }
 
 /* Layout all of the non-virtual base classes.  Returns a map from
@@ -4366,7 +3929,7 @@ build_base_fields (rli, empty_p)
 
       /* A primary virtual base class is allocated just like any other
         base class, but a non-primary virtual base is allocated
-        later, in layout_basetypes.  */
+        later, in layout_virtual_bases.  */
       if (TREE_VIA_VIRTUAL (base_binfo) 
          && !BINFO_PRIMARY_MARKED_P (base_binfo))
        continue;
@@ -4396,7 +3959,6 @@ check_methods (t)
       if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (x)))
        continue;
 
-      DECL_SAVED_INSNS (x) = 0;
       check_for_override (x, t);
       if (DECL_PURE_VIRTUAL_P (x) && ! DECL_VINDEX (x))
        cp_error_at ("initializer specified for non-virtual method `%D'", x);
@@ -4444,6 +4006,196 @@ 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;
+
+  if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn))
+    {
+      /* For each constructor, we need two variants: an in-charge version
+        and a not-in-charge version.  */
+      clone = build_clone (fn, complete_ctor_identifier);
+      if (update_method_vec_p)
+       add_method (DECL_CONTEXT (clone), NULL, clone);
+      clone = build_clone (fn, base_ctor_identifier);
+      if (update_method_vec_p)
+       add_method (DECL_CONTEXT (clone), NULL, clone);
+    }
+  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), NULL, clone);
+      clone = build_clone (fn, complete_dtor_identifier);
+      if (update_method_vec_p)
+       add_method (DECL_CONTEXT (clone), NULL, clone);
+      clone = build_clone (fn, base_dtor_identifier);
+      if (update_method_vec_p)
+       add_method (DECL_CONTEXT (clone), NULL, clone);
+    }
+}
+
+/* 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
@@ -4539,6 +4291,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);
@@ -4550,15 +4306,15 @@ 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
-create_vtable_ptr (t, empty_p, has_virtual_p, 
+create_vtable_ptr (t, empty_p, vfuns_p,
                   new_virtuals_p, overridden_virtuals_p)
      tree t;
      int *empty_p;
-     int *has_virtual_p;
+     int *vfuns_p;
      tree *new_virtuals_p;
      tree *overridden_virtuals_p;
 {
@@ -4567,19 +4323,18 @@ create_vtable_ptr (t, empty_p, has_virtual_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,
-                           has_virtual_p, fn, t);
+                           vfuns_p, fn, t);
 
-  /* Even if there weren't any new virtual functions, we might need a
+  /* If we couldn't find an appropriate base class, create a new field
+     here.  Even if there weren't any new virtual functions, we might need a
      new virtual function table if we're supposed to include vptrs in
      all classes that need them.  */
-  if (TYPE_CONTAINS_VPTR_P (t) && vptrs_present_everywhere_p ())
-    start_vtable (t, has_virtual_p);
-    
-  /* If we couldn't find an appropriate base class, create a new field
-     here.  */
-  if (*has_virtual_p && !TYPE_VFIELD (t))
+  if (!TYPE_VFIELD (t)
+      && (*vfuns_p 
+         || (TYPE_CONTAINS_VPTR_P (t) && vptrs_present_everywhere_p ())))
     {
       /* We build this decl with vtbl_ptr_type_node, which is a
         `vtable_entry_type*'.  It might seem more precise to use
@@ -4682,12 +4437,12 @@ dfs_propagate_binfo_offsets (binfo, data)
 {
   tree offset = (tree) data;
 
-  /* Update the BINFO_OFFSET for this base.  */
-  BINFO_OFFSET (binfo) = fold (build (PLUS_EXPR,
-                                     sizetype,
-                                     BINFO_OFFSET (binfo), 
-                                     offset));
-
+  /* 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;
@@ -4728,7 +4483,7 @@ dfs_set_offset_for_shared_vbases (binfo, data)
       /* Update the shared copy.  */
       tree shared_binfo;
 
-      shared_binfo = BINFO_FOR_VBASE (BINFO_TYPE (binfo), (tree) data);
+      shared_binfo = binfo_for_vbase (BINFO_TYPE (binfo), (tree) data);
       BINFO_OFFSET (shared_binfo) = BINFO_OFFSET (binfo);
     }
 
@@ -4751,7 +4506,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);
     }
@@ -4760,14 +4515,26 @@ 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.  */
+   TYPE_ALIGN and TYPE_SIZE for T.  BASE_OFFSETS is a varray mapping
+   offsets to the types at those offsets.  */
 
 static void
-layout_virtual_bases (t)
+layout_virtual_bases (t, base_offsets)
      tree t;
+     varray_type *base_offsets;
 {
-  tree vbase;
+  tree vbases;
   unsigned HOST_WIDE_INT dsize;
+  unsigned HOST_WIDE_INT eoc;
+
+  if (CLASSTYPE_N_BASECLASSES (t) == 0)
+    return;
+
+#ifdef STRUCTURE_SIZE_BOUNDARY
+  /* Packed structures don't need to have minimum size.  */
+  if (! TYPE_PACKED (t))
+    TYPE_ALIGN (t) = MAX (TYPE_ALIGN (t), STRUCTURE_SIZE_BOUNDARY);
+#endif
 
   /* DSIZE is the size of the class without the virtual bases.  */
   dsize = tree_low_cst (TYPE_SIZE (t), 1);
@@ -4776,32 +4543,77 @@ layout_virtual_bases (t)
   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;
-
-       basetype = BINFO_TYPE (vbase);
-       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;
-       /* And compute the offset of the virtual base.  */
-       propagate_binfo_offsets (vbase, 
-                                size_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));
-      }
+     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;
+
+      if (flag_new_abi)
+       {
+         if (!TREE_VIA_VIRTUAL (vbases))
+           continue;
+         vbase = binfo_for_vbase (BINFO_TYPE (vbases), t);
+       }
+      else
+       vbase = TREE_VALUE (vbases);
+
+      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;
+
+         basetype = BINFO_TYPE (vbase);
+
+         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
+           {
+             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));
+           }
+
+         /* Keep track of the offsets assigned to this virtual base.  */
+         record_base_offsets (vbase, base_offsets);
+       }
+    }
 
   /* Make sure that all of the CLASSTYPE_VBASECLASSES have their
      BINFO_OFFSET set correctly.  Those we just allocated certainly
@@ -4818,56 +4630,69 @@ layout_virtual_bases (t)
      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
+     multiple such bases at the same location.  */
+  eoc = end_of_class (t, /*include_virtuals_p=*/1);
+  if (eoc * BITS_PER_UNIT > dsize)
+    dsize = (eoc + 1) * BITS_PER_UNIT;
 
   /* Now, make sure that the total size of the type is a multiple of
      its alignment.  */
   dsize = CEIL (dsize, TYPE_ALIGN (t)) * TYPE_ALIGN (t);
   TYPE_SIZE (t) = bitsize_int (dsize);
   TYPE_SIZE_UNIT (t) = convert (sizetype,
-                               size_binop (FLOOR_DIV_EXPR, TYPE_SIZE (t),
-                                           bitsize_int (BITS_PER_UNIT)));
+                               size_binop (CEIL_DIV_EXPR, TYPE_SIZE (t),
+                                           bitsize_unit_node));
+
+  /* Check for ambiguous virtual bases.  */
+  if (extra_warnings)
+    for (vbases = CLASSTYPE_VBASECLASSES (t); 
+        vbases; 
+        vbases = TREE_CHAIN (vbases))
+      {
+       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);
+      }
 }
 
-/* Finish the work of layout_record, now taking virtual bases into account.
-   Also compute the actual offsets that our base classes will have.
-   This must be performed after the fields are laid out, since virtual
-   baseclasses must lay down at the end of the record.  */
+/* Returns the offset of the byte just past the end of the base class
+   with the highest offset in T.  If INCLUDE_VIRTUALS_P is zero, then
+   only non-virtual bases are included.  */
 
-static void
-layout_basetypes (rec)
-     tree rec;
+static unsigned HOST_WIDE_INT
+end_of_class (t, include_virtuals_p)
+     tree t;
+     int include_virtuals_p;
 {
-  tree vbase_types;
+  unsigned HOST_WIDE_INT result = 0;
+  int i;
 
-  if (CLASSTYPE_N_BASECLASSES (rec) == 0)
-    return;
+  for (i = 0; i < CLASSTYPE_N_BASECLASSES (t); ++i)
+    {
+      tree base_binfo;
+      tree offset;
+      unsigned HOST_WIDE_INT end_of_base;
 
-#ifdef STRUCTURE_SIZE_BOUNDARY
-  /* Packed structures don't need to have minimum size.  */
-  if (! TYPE_PACKED (rec))
-    TYPE_ALIGN (rec) = MAX (TYPE_ALIGN (rec), STRUCTURE_SIZE_BOUNDARY);
-#endif
+      base_binfo = BINFO_BASETYPE (TYPE_BINFO (t), i);
 
-  /* Allocate the virtual base classes.  */
-  layout_virtual_bases (rec);
+      if (!include_virtuals_p
+         && TREE_VIA_VIRTUAL (base_binfo) 
+         && !BINFO_PRIMARY_MARKED_P (base_binfo))
+       continue;
 
-  /* Get all the virtual base types that this type uses.  The
-     TREE_VALUE slot holds the virtual baseclass type.  Note that
-     get_vbase_types makes copies of the virtual base BINFOs, so that
-     the vbase_types are unshared.  */
-  for (vbase_types = CLASSTYPE_VBASECLASSES (rec); vbase_types;
-       vbase_types = TREE_CHAIN (vbase_types))
-    if (extra_warnings)
-      {
-       tree basetype = BINFO_TYPE (vbase_types);
-       if (get_base_distance (basetype, rec, 0, (tree*)0) == -2)
-         cp_warning ("virtual base `%T' inaccessible in `%T' due to ambiguity",
-                     basetype, rec);
-      }
+      offset = size_binop (PLUS_EXPR, 
+                          BINFO_OFFSET (base_binfo),
+                          CLASSTYPE_SIZE_UNIT (BINFO_TYPE (base_binfo)));
+      end_of_base = tree_low_cst (offset, /*pos=*/1);
+      if (end_of_base > result)
+       result = end_of_base;
+    }
+
+  return result;
 }
 
 /* Calculate the TYPE_SIZE, TYPE_ALIGN, etc for T.  Calculate
@@ -4875,11 +4700,11 @@ layout_basetypes (rec)
    pointer.  */
 
 static void
-layout_class_type (t, empty_p, has_virtual_p, 
+layout_class_type (t, empty_p, vfuns_p, 
                   new_virtuals_p, overridden_virtuals_p)
      tree t;
      int *empty_p;
-     int *has_virtual_p;
+     int *vfuns_p;
      tree *new_virtuals_p;
      tree *overridden_virtuals_p;
 {
@@ -4888,20 +4713,20 @@ layout_class_type (t, empty_p, has_virtual_p,
   tree vptr;
   record_layout_info rli;
   varray_type v;
-  int i;
+  unsigned HOST_WIDE_INT eoc;
 
   /* Keep track of the first non-static data member.  */
   non_static_data_members = TYPE_FIELDS (t);
 
-  /* Initialize the layout information.  */
-  rli = new_record_layout_info (t);
+  /* Start laying out the record.  */
+  rli = start_record_layout (t);
 
   /* If possible, we reuse the virtual function table pointer from one
      of our base classes.  */
-  determine_primary_base (t, has_virtual_p);
+  determine_primary_base (t, vfuns_p);
 
   /* Create a pointer to our virtual function table.  */
-  vptr = create_vtable_ptr (t, empty_p, has_virtual_p,
+  vptr = create_vtable_ptr (t, empty_p, vfuns_p,
                            new_virtuals_p, overridden_virtuals_p);
 
   /* Under the new ABI, the vptr is always the first thing in the
@@ -4909,7 +4734,7 @@ layout_class_type (t, empty_p, has_virtual_p,
   if (flag_new_abi && vptr)
     {
       TYPE_FIELDS (t) = chainon (vptr, TYPE_FIELDS (t));
-      layout_field (rli, vptr);
+      place_field (rli, vptr);
     }
 
   /* Add pointers to all of our virtual base-classes.  */
@@ -4924,9 +4749,7 @@ layout_class_type (t, empty_p, has_virtual_p,
   fixup_inline_methods (t);
 
   /* Layout the non-static data members.  */
-  for (field = non_static_data_members; 
-       field; 
-       field = TREE_CHAIN (field))
+  for (field = non_static_data_members; field; field = TREE_CHAIN (field))
     {
       tree binfo;
       tree type;
@@ -4936,7 +4759,7 @@ layout_class_type (t, empty_p, has_virtual_p,
         the back-end, in case it wants to do something with them.  */
       if (TREE_CODE (field) != FIELD_DECL)
        {
-         layout_field (rli, field);
+         place_field (rli, field);
          continue;
        }
 
@@ -4951,9 +4774,9 @@ layout_class_type (t, empty_p, has_virtual_p,
          && ((flag_new_abi 
               && INT_CST_LT (TYPE_SIZE (type), DECL_SIZE (field)))
              || (!flag_new_abi
-                 && compare_tree_int (DECL_SIZE (field),
-                                      TYPE_PRECISION
-                                      (long_long_unsigned_type_node)) > 0)))
+                 && 0 < compare_tree_int (DECL_SIZE (field),
+                                          TYPE_PRECISION
+                                          (long_long_unsigned_type_node)))))
        {
          integer_type_kind itk;
          tree integer_type;
@@ -4971,8 +4794,8 @@ layout_class_type (t, empty_p, has_virtual_p,
             field.  We have to back up by one to find the largest
             type that fits.  */
          integer_type = integer_types[itk - 1];
-         padding = size_diffop (DECL_SIZE (field), 
-                                TYPE_SIZE (integer_type));
+         padding = size_binop (MINUS_EXPR, DECL_SIZE (field), 
+                               TYPE_SIZE (integer_type));
          DECL_SIZE (field) = TYPE_SIZE (integer_type);
          DECL_ALIGN (field) = TYPE_ALIGN (integer_type);
        }
@@ -5000,23 +4823,21 @@ layout_class_type (t, empty_p, has_virtual_p,
        }
     }
 
-  /* Clean up.  */
-  VARRAY_FREE (v);
-  
   /* It might be the case that we grew the class to allocate a
      zero-sized base class.  That won't be reflected in RLI, yet,
      because we are willing to overlay multiple bases at the same
      offset.  However, now we need to make sure that RLI is big enough
      to reflect the entire class.  */
-  for (i = 0; i < CLASSTYPE_N_BASECLASSES (t); ++i)
+  eoc = end_of_class (t, /*include_virtuals_p=*/0);
+  if (TREE_CODE (rli_size_unit_so_far (rli)) == INTEGER_CST
+      && compare_tree_int (rli_size_unit_so_far (rli), eoc) < 0)
     {
-      tree base_binfo;
-      unsigned HOST_WIDE_INT offset;
-
-      base_binfo = BINFO_BASETYPE (TYPE_BINFO (t), i);
-      offset = get_binfo_offset_as_int (base_binfo);
-      if (offset * BITS_PER_UNIT > rli->const_size)
-       rli->const_size = (offset + 1) * BITS_PER_UNIT;
+      /* We don't handle zero-sized base classes specially under the
+        old ABI, so if we get here, we had better be operating under
+        the new ABI rules.  */
+      my_friendly_assert (flag_new_abi, 20000321);
+      rli->offset = size_binop (MAX_EXPR, rli->offset, size_int (eoc + 1));
+      rli->bitpos = bitsize_zero_node;
     }
 
   /* We make all structures have at least one element, so that they
@@ -5028,8 +4849,8 @@ layout_class_type (t, empty_p, has_virtual_p,
     {
       tree padding;
 
-      padding = build_lang_decl (FIELD_DECL, NULL_TREE, char_type_node);
-      layout_field (rli, padding);
+      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));
       TREE_STATIC (TYPE_NONCOPIED_PARTS (t)) = 1;
@@ -5039,7 +4860,7 @@ layout_class_type (t, empty_p, has_virtual_p,
      class.   */
   if (!flag_new_abi && vptr)
     {
-      layout_field (rli, vptr);
+      place_field (rli, vptr);
       TYPE_FIELDS (t) = chainon (TYPE_FIELDS (t), vptr);
     }
   
@@ -5058,7 +4879,7 @@ layout_class_type (t, empty_p, has_virtual_p,
      the virtual bases.  */
   if (*empty_p && flag_new_abi)
     {
-      CLASSTYPE_SIZE (t) = bitsize_int (0);
+      CLASSTYPE_SIZE (t) = bitsize_zero_node;
       CLASSTYPE_SIZE_UNIT (t) = size_zero_node;
     }
   else if (flag_new_abi && TYPE_HAS_COMPLEX_INIT_REF (t)
@@ -5084,9 +4905,12 @@ layout_class_type (t, empty_p, has_virtual_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_basetypes (t);
+  layout_virtual_bases (t, &v);
+
+  /* Clean up.  */
+  VARRAY_FREE (v);
 }
-     
+
 /* Create a RECORD_TYPE or UNION_TYPE node for a C struct or union declaration
    (or C++ class declaration).
 
@@ -5119,7 +4943,7 @@ finish_struct_1 (t)
      tree t;
 {
   tree x;
-  int has_virtual;
+  int vfuns;
   /* The NEW_VIRTUALS is a TREE_LIST.  The TREE_VALUE of each node is
      a FUNCTION_DECL.  Each of these functions is a virtual function
      declared in T that does not override any virtual function from a
@@ -5150,7 +4974,7 @@ finish_struct_1 (t)
   TYPE_SIZE (t) = NULL_TREE;
   CLASSTYPE_GOT_SEMICOLON (t) = 0;
   CLASSTYPE_VFIELD_PARENT (t) = -1;
-  has_virtual = 0;
+  vfuns = 0;
   CLASSTYPE_RTTI (t) = NULL_TREE;
 
   /* Do end-of-class semantic processing: checking the validity of the
@@ -5158,7 +4982,7 @@ finish_struct_1 (t)
   check_bases_and_members (t, &empty);
 
   /* Layout the class itself.  */
-  layout_class_type (t, &empty, &has_virtual,
+  layout_class_type (t, &empty, &vfuns,
                     &new_virtuals, &overridden_virtuals);
 
   /* Set up the DECL_FIELD_BITPOS of the vfield if we need to, as we
@@ -5169,22 +4993,25 @@ finish_struct_1 (t)
       && DECL_FIELD_CONTEXT (vfield) != t)
     {
       tree binfo = get_binfo (DECL_FIELD_CONTEXT (vfield), t, 0);
-      tree offset = convert (bitsizetype, BINFO_OFFSET (binfo));
 
-      vfield = copy_node (vfield);
-      copy_lang_decl (vfield);
-
-      if (! integer_zerop (offset))
-       offset = size_binop (MULT_EXPR, offset, bitsize_int (BITS_PER_UNIT));
+      vfield = copy_decl (vfield);
 
       DECL_FIELD_CONTEXT (vfield) = t;
-      DECL_FIELD_BITPOS (vfield)
-       = size_binop (PLUS_EXPR, offset, bit_position (vfield));
+      DECL_FIELD_OFFSET (vfield)
+       = size_binop (PLUS_EXPR,
+                     BINFO_OFFSET (binfo),
+                     DECL_FIELD_OFFSET (vfield));
       TYPE_VFIELD (t) = vfield;
     }
 
   overridden_virtuals 
-    = modify_all_vtables (t, &has_virtual, nreverse (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
@@ -5194,23 +5021,8 @@ finish_struct_1 (t)
       new_virtuals = nreverse (new_virtuals);
       /* We must enter these virtuals into the table.  */
       if (!CLASSTYPE_HAS_PRIMARY_BASE_P (t))
-       {
-         if (! CLASSTYPE_COM_INTERFACE (t))
-           {
-             /* The second slot is for the tdesc pointer when thunks
-                are used.  */
-             if (flag_vtable_thunks)
-               new_virtuals = tree_cons (NULL_TREE, NULL_TREE, new_virtuals);
-
-             /* The first slot is for the rtti offset.  */
-             new_virtuals = tree_cons (NULL_TREE, NULL_TREE, new_virtuals);
-
-             set_rtti_entry (new_virtuals,
-                             convert (ssizetype, integer_zero_node), t);
-           }
-         build_primary_vtable (NULL_TREE, t);
-       }
-      else if (! BINFO_NEW_VTABLE_MARKED (TYPE_BINFO (t)))
+       build_primary_vtable (NULL_TREE, t);
+      else if (! BINFO_NEW_VTABLE_MARKED (TYPE_BINFO (t), t))
        /* Here we know enough to change the type of our virtual
           function table, but we will wait until later this function.  */
        build_primary_vtable (CLASSTYPE_PRIMARY_BINFO (t), t);
@@ -5252,7 +5064,7 @@ finish_struct_1 (t)
        my_friendly_assert (TYPE_BINFO_VIRTUALS (t) == NULL_TREE,
                            20000116);
 
-      CLASSTYPE_VSIZE (t) = has_virtual;
+      CLASSTYPE_VSIZE (t) = vfuns;
       /* Entries for virtual functions defined in the primary base are
         followed by entries for new functions unique to this class.  */
       TYPE_BINFO_VIRTUALS (t) 
@@ -5263,12 +5075,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_VFIELD_PARENT (t) == -1)
-    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
@@ -5321,8 +5127,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
@@ -5396,7 +5204,7 @@ finish_struct (t, attributes)
   if (processing_template_decl)
     {
       finish_struct_methods (t);
-      TYPE_SIZE (t) = integer_zero_node;
+      TYPE_SIZE (t) = bitsize_zero_node;
     }
   else
     finish_struct_1 (t);
@@ -5547,7 +5355,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
@@ -5559,15 +5367,17 @@ 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);
 }
 
 /* Set current scope to NAME. CODE tells us if this is a
@@ -5934,6 +5744,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.  */
@@ -6143,6 +5956,7 @@ instantiate_type (lhstype, rhs, flags)
 {
   int complain = (flags & 1);
   int strict = (flags & 2) ? COMPARE_NO_ATTRIBUTES : COMPARE_STRICT;
+  tree r;
 
   if (TREE_CODE (lhstype) == UNKNOWN_TYPE)
     {
@@ -6203,8 +6017,9 @@ instantiate_type (lhstype, rhs, flags)
 
     case COMPONENT_REF:
       {
-       tree r = instantiate_type (lhstype, TREE_OPERAND (rhs, 1), flags);
+       r = instantiate_type (lhstype, TREE_OPERAND (rhs, 1), flags);
 
+      comp:
        if (r != error_mark_node && TYPE_PTRMEMFUNC_P (lhstype)
            && complain && !flag_ms_extensions)
          {
@@ -6239,12 +6054,23 @@ 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);
+
+       r =
+         resolve_address_of_overloaded_function (lhstype,
+                                                 fns,
+                                                 complain,
+                                                 /*template_only=*/1,
+                                                 args);
+       if (TREE_CODE (fns) == COMPONENT_REF)
+         {
+           rhs = fns;
+           goto comp;
+         }
+       return r;
+      }
 
     case OVERLOAD:
       return 
@@ -6578,12 +6404,36 @@ note_name_declared_in_class (name, decl)
     }
 }
 
-/* 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;
+}
+
+/* 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;
 {
@@ -6594,9 +6444,989 @@ dump_class_hierarchy (binfo, indent)
           type_as_string (binfo, TS_PLAIN));
   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_VBASE_PRIMARY_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.  */
+
+/* Create all the necessary vtables for T and its base classes.  */
+
+static void
+finish_vtbls (t)
+     tree t;
+{
+  if (merge_primary_and_secondary_vtables_p ())
+    {
+      tree list;
+      tree vbase;
+
+      /* Under the new ABI, we lay out the primary and secondary
+        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 (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 = 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));
+    }
+  else
+    {
+      dfs_walk (TYPE_BINFO (t), dfs_finish_vtbls, 
+               dfs_unmarked_real_bases_queue_p, t);
+      dfs_walk (TYPE_BINFO (t), dfs_unmark, 
+               dfs_marked_real_bases_queue_p, t);
+    }
+}
+
+/* Called from finish_vtbls via dfs_walk.  */
+
+static tree
+dfs_finish_vtbls (binfo, data)
+     tree binfo;
+     void *data;
+{
+  tree t = (tree) data;
+
+  if (BINFO_NEW_VTABLE_MARKED (binfo, t))
+    initialize_vtable (binfo, 
+                      build_vtbl_initializer (binfo, binfo, t, 
+                                              TYPE_BINFO (t), NULL));
+
+  SET_BINFO_MARKED (binfo);
+
+  return NULL_TREE;
+}
+
+/* Initialize the vtable for BINFO with the INITS.  */
+
+static void
+initialize_vtable (binfo, inits)
+     tree binfo;
+     tree inits;
+{
+  tree decl;
+
+  layout_vtable_decl (binfo, list_length (inits));
+  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) = 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;
+}
+
+/* Build the VTT (virtual table table) for T.  */
+
+static void
+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, &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);
+}
+
+/* Recursively build the VTT-initializer for BINFO (which is in the
+   hierarchy dominated by T).  INITS points to the end of the
+   initializer list to date.  INDEX is the VTT index where the next
+   element will be placed.  */
+
+static tree *
+build_vtt_inits (binfo, t, inits, index)
+     tree binfo;
+     tree t;
+     tree *inits;
+     tree *index;
+{
+  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_PURPOSE (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, inits,
+                                index);
+    }
+      
+  /* Add secondary virtual pointers for all subobjects of BINFO with
+     either virtual bases or virtual functions overridden along a
+     virtual path between the declaration and D, except subobjects
+     that are non-virtual primary bases.  */
+  secondary_vptrs = build_tree_list (BINFO_TYPE (binfo), NULL_TREE);
+  TREE_TYPE (secondary_vptrs) = *index;
+  dfs_walk_real (binfo,
+                dfs_build_vtt_inits,
+                NULL,
+                dfs_unmarked_real_bases_queue_p,
+                secondary_vptrs);
+  dfs_walk (binfo, dfs_fixup_binfo_vtbls, dfs_marked_real_bases_queue_p,
+           BINFO_TYPE (binfo));
+  *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.  */
+  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, inits, index);
+    }
+
+  return inits;
+}
+
+/* Called from build_vtt_inits via dfs_walk.  */
+
+static tree
+dfs_build_vtt_inits (binfo, data)
+     tree binfo;
+     void *data;
+{
+  tree l; 
+  tree t;
+  tree init;
+  tree index;
+
+  l = (tree) data;
+  t = TREE_PURPOSE (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 between the declaration and T.  */
+  if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo)))
+    /* FIXME: Implement this.  */
+    ;
+
+  /* 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_PURPOSE (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 ATTRIBUTE_UNUSED;
+{
+  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)
+    BINFO_VTABLE (binfo) = TREE_VALUE (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;
+
+  /* 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 (BINFO_TYPE (binfo), id, ptr_type_node);
+  list = build_tree_list (vtbl, NULL_TREE);
+  accumulate_vtbl_inits (binfo, TYPE_BINFO (TREE_TYPE (binfo)),
+                        binfo, t, list);
+  inits = TREE_VALUE (list);
+
+  /* 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);
+}
+
+/* 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)))
+    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
+dfs_accumulate_vtbl_inits (binfo, orig_binfo, rtti_binfo, t, l)
+     tree binfo;
+     tree orig_binfo;
+     tree rtti_binfo;
+     tree t;
+     tree l;
+{
+  tree inits = NULL_TREE;
+  int ctor_vtbl_p;
+
+  /* This is a construction vtable if the RTTI type is not the most
+     derived type in the hierarchy.  */
+  ctor_vtbl_p = !same_type_p (BINFO_TYPE (rtti_binfo), t);
+
+  if (BINFO_NEW_VTABLE_MARKED (binfo, t)
+      /* We need a new vtable, even for a primary base, when we're
+        building a construction vtable.  */
+      || (ctor_vtbl_p && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))))
+    {
+      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 (!ctor_vtbl_p)
+       BINFO_VTABLE (binfo) = vtbl;
+      /* For a construction vtable, we can't overwrite BINFO_VTABLE.
+        So, we make a TREE_LIST.  Later, dfs_fixup_binfo_vtbls will
+        straighten this out.  */
+      else
+       BINFO_VTABLE (binfo) = build_tree_list (vtbl,
+                                               BINFO_VTABLE (binfo));
+    }
+
+  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_DOMINATOR 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.  */
+
+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 inits;
+  tree vfun_inits;
+  tree vbase;
+  vcall_offset_data vod;
+
+  /* Initialize those parts of VOD that matter.  */
+  vod.derived = t;
+  vod.inits = NULL_TREE;
+  vod.primary_p = (binfo == TYPE_BINFO (t));
+  /* The first vbase or vcall offset is at index -3 in the vtable.  */
+  vod.index = build_int_2 (-3, -1);
+
+  /* Add the vcall and vbase offset entries.  */
+  build_vcall_and_vbase_vtbl_entries (binfo, &vod);
+  inits = vod.inits;
+  /* Clear BINFO_VTABLE_PAATH_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));
+
+  /* Add entries to the vtable for RTTI.  */
+  inits = chainon (inits, build_rtti_vtbl_entries (binfo, rtti_binfo));
+
+  if (non_fn_entries_p)
+    *non_fn_entries_p = list_length (inits);
+
+  /* Go through all the ordinary virtual functions, building up
+     initializers.  */
+  vfun_inits = NULL_TREE;
+  for (v = BINFO_VIRTUALS (orig_binfo); v; v = TREE_CHAIN (v))
+    {
+      tree delta;
+      tree vcall_index;
+      tree fn;
+      tree pfn;
+      tree init;
+
+      /* Pull the offset for `this', and the function to call, out of
+        the list.  */
+      delta = BV_DELTA (v);
+      vcall_index = BV_VCALL_INDEX (v);
+      fn = BV_FN (v);
+      my_friendly_assert (TREE_CODE (delta) == INTEGER_CST, 19990727);
+      my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727);
+
+      /* You can't call an abstract virtual function; it's abstract.
+        So, we replace these functions with __pure_virtual.  */
+      if (DECL_PURE_VIRTUAL_P (fn))
+       fn = abort_fndecl;
+
+      /* Take the address of the function, considering it to be of an
+        appropriate generic type.  */
+      pfn = build1 (ADDR_EXPR, vfunc_ptr_type_node, fn);
+      /* 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);
+      /* And add it to the chain of initializers.  */
+      vfun_inits = tree_cons (NULL_TREE, init, vfun_inits);
+    }
+
+  /* The initializers for virtual functions were built up in reverse
+     order; straighten them out now.  */
+  vfun_inits = nreverse (vfun_inits);
+  
+  /* The complete initializer is the INITS, followed by the
+     VFUN_INITS.  */
+  return chainon (inits, vfun_inits);
+}
+
+/* Sets vod->inits to be the initializers for the vbase and vcall
+   offsets in BINFO, which is in the hierarchy dominated by T.  */
+
+static void
+build_vcall_and_vbase_vtbl_entries (binfo, vod)
+     tree binfo;
+     vcall_offset_data *vod;
+{
+  tree b;
+  tree inits;
+
+  /* If this is a derived class, we must first create entries
+     corresponding to the base class.  These entries must go closer to
+     the vptr, so we save them up and add them to the end of the list
+     later.  */
+  inits = vod->inits;
+  vod->inits = NULL_TREE;
+  b = BINFO_PRIMARY_BINFO (binfo);
+  if (b)
+    build_vcall_and_vbase_vtbl_entries (b, vod);
+
+  /* Add the vbase entries for this base.  */
+  build_vbase_offset_vtbl_entries (binfo, vod);
+  /* Add the vcall entries for this base.  */
+  build_vcall_offset_vtbl_entries (binfo, vod);
+
+  vod->inits = chainon (vod->inits, inits);
+}
+
+/* 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.  VBASE_OFFSET_INDEX gives the vtable index
+   where the next vbase offset will go.  */
+
+static void
+build_vbase_offset_vtbl_entries (binfo, vod)
+     tree binfo;
+     vcall_offset_data *vod;
+{
+  tree vbase;
+  tree t;
+
+  /* Under the old ABI, pointers to virtual bases are stored in each
+     object.  */
+  if (!vbase_offsets_in_vtable_p ())
+    return;
+
+  /* If there are no virtual baseclasses, then there is nothing to
+     do.  */
+  if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo)))
+    return;
+
+  t = vod->derived;
+
+  /* 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;
+
+      /* Find the instance of this virtual base in the complete
+        object.  */
+      b = binfo_for_vbase (BINFO_TYPE (vbase), t);
+
+      /* 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);
+
+      /* Figure out where we can find this vbase offset.  */
+      delta = size_binop (MULT_EXPR, 
+                         convert (ssizetype, vod->index),
+                         convert (ssizetype,
+                                  TYPE_SIZE_UNIT (vtable_entry_type)));
+      if (vod->primary_p)
+       BINFO_VPTR_FIELD (b) = delta;
+
+      if (binfo != TYPE_BINFO (t))
+       {
+         tree orig_vbase;
+
+         /* Find the instance of this virtual base in the type of BINFO.  */
+         orig_vbase = binfo_for_vbase (BINFO_TYPE (vbase),
+                                       BINFO_TYPE (binfo));
+
+         /* The vbase offset had better be the same.  */
+         if (!tree_int_cst_equal (delta,
+                                  BINFO_VPTR_FIELD (orig_vbase)))
+           my_friendly_abort (20000403);
+       }
+
+      /* The next vbase will come at a more negative offset.  */
+      vod->index = fold (build (MINUS_EXPR, integer_type_node,
+                               vod->index, integer_one_node));
+
+      /* The initializer is the delta from BINFO to this virtual base.
+        The vbase offsets go in reverse inheritance-graph order, and
+        we are walking in inheritance graph order so these end up in
+        the right order.  */
+      delta = size_diffop (BINFO_OFFSET (b), BINFO_OFFSET (binfo));
+      vod->inits = tree_cons (NULL_TREE, 
+                             fold (build1 (NOP_EXPR, 
+                                           vtable_entry_type,
+                                           delta)),
+                             vod->inits);
+    }
+}
+
+/* Called from build_vcall_offset_vtbl_entries via dfs_walk.  */
+
+static tree
+dfs_build_vcall_offset_vtbl_entries (binfo, data)
+     tree binfo;
+     void *data;
+{
+  vcall_offset_data* vod;
+  tree derived_virtuals;
+  tree base_virtuals;
+  tree binfo_inits;
+  tree non_primary_binfo;
+  tree b;
+  int i;
+
+  vod = (vcall_offset_data *) data;
+  binfo_inits = NULL_TREE;
+
+  /* We might be a primary base class.  Go up the inheritance
+     hierarchy until we find the class of which we are a primary base:
+     it is the BINFO_VIRTUALS there that we need to consider.  */
+  non_primary_binfo = binfo;
+  while (BINFO_PRIMARY_MARKED_P (non_primary_binfo))
+    non_primary_binfo = BINFO_INHERITANCE_CHAIN (non_primary_binfo);
+
+  /* Skip virtuals that we have already handled in a primary base
+     class.  */
+  base_virtuals = BINFO_VIRTUALS (binfo);
+  derived_virtuals = BINFO_VIRTUALS (non_primary_binfo);
+  b = BINFO_PRIMARY_BINFO (binfo);
+  if (b)
+    for (i = 0; i < CLASSTYPE_VSIZE (BINFO_TYPE (b)); ++i)
+      {
+       base_virtuals = TREE_CHAIN (base_virtuals);
+       derived_virtuals = TREE_CHAIN (derived_virtuals);
+      }
+
+  /* Make entries for the rest of the virtuals.  */
+  while (base_virtuals)
+    {
+      /* Figure out what function we're looking at.  */
+      tree fn = TREE_VALUE (derived_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);
+
+      /* Compute the vcall offset.  */
+      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);
+
+      /* If there is already a vcall index, then we are processing a
+        construction vtable.  The index should be the same as it was
+        when we processed the vtable for the base class.  */
+      if (BV_VCALL_INDEX (derived_virtuals))
+       my_friendly_assert (tree_int_cst_equal (BV_VCALL_INDEX
+                                               (derived_virtuals),
+                                               vod->index),
+                           20000516);
+      /* Keep track of the vtable index where this vcall offset can be
+        found.  */
+      else
+       BV_VCALL_INDEX (derived_virtuals) = vod->index;
+
+      /* The next vcall offset will be found at a more negative
+        offset.  */
+      vod->index = fold (build (MINUS_EXPR, integer_type_node,
+                               vod->index, integer_one_node));
+
+      /* Go to the next entries in the list.  */
+      derived_virtuals = TREE_CHAIN (derived_virtuals);
+      base_virtuals = TREE_CHAIN (base_virtuals);
+    }
+
+  /* The offests are built up in reverse order, so we straighten them
+     here.  We simultaneously add them to VOD->INITS; we're walking
+     the bases in inheritance graph order, and the initializers are
+     supposed to appear in reverse inheritance order, so that's
+     correct.  */
+  while (binfo_inits)
+    {
+      tree next;
+
+      next = TREE_CHAIN (binfo_inits);
+      TREE_CHAIN (binfo_inits) = vod->inits;
+      vod->inits = binfo_inits;
+      binfo_inits = next;
+    }
+
+  return NULL_TREE;
+}
+
+/* Adds the initializers for the vcall offset entries in the vtable
+   for BINFO (which is part of the class hierarchy dominated by T) to
+   VOD->INITS.  */
+
+static void
+build_vcall_offset_vtbl_entries (binfo, vod)
+     tree binfo;
+     vcall_offset_data *vod;
+{
+  tree inits;
+
+  /* Under the old ABI, the adjustments to the `this' pointer were made
+     elsewhere.  */
+  if (!vcall_offsets_in_vtable_p ())
+    return;
+
+  /* We only need these entries if this base is a virtual base.  */
+  if (!TREE_VIA_VIRTUAL (binfo))
+    return;
+
+  /* We need a vcall offset for each of the virtual functions in this
+     vtable.  For example:
+
+       class A { virtual void f (); };
+       class B : virtual public A { };
+       class C: virtual public A, public B {};
+      
+     Now imagine:
+
+       B* b = new C;
+       b->f();
+
+     The location of `A' is not at a fixed offset relative to `B'; the
+     offset depends on the complete object derived from `B'.  So, 
+     `B' vtable contains an entry for `f' that indicates by what
+     amount the `this' pointer for `B' needs to be adjusted to arrive
+     at `A'.  
+
+     We need entries for all the functions in our primary vtable and
+     in our non-virtual bases vtables.  For each base, the entries
+     appear in the same order as in the base; but the bases themselves
+     appear in reverse depth-first, left-to-right order.  */
+  vod->vbase = binfo;
+  inits = vod->inits;
+  vod->inits = NULL_TREE;
+  dfs_walk_real (binfo,
+                dfs_build_vcall_offset_vtbl_entries,
+                NULL,
+                dfs_skip_vbases,
+                vod);
+  vod->inits = chainon (vod->inits, inits);
+}
+
+/* Return vtbl initializers for the RTTI entries coresponding to the
+   BINFO's vtable.  The RTTI entries should indicate the object given
+   by RTTI_BINFO.  */
+
+static tree
+build_rtti_vtbl_entries (binfo, rtti_binfo)
+     tree binfo;
+     tree rtti_binfo;
+{
+  tree b;
+  tree t;
+  tree basetype;
+  tree offset;
+  tree decl;
+  tree init;
+  tree inits;
+
+  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;
+
+  /* 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)))
+    {
+      tree primary_base;
+
+      primary_base = BINFO_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
+     which returns a typeinfo object.  */
+  if (new_abi_rtti_p ())
+    {
+      if (flag_rtti)
+       decl = build_unary_op (ADDR_EXPR, get_tinfo_decl (t), 0);
+      else
+       decl = integer_zero_node;
+
+      /* Convert the declaration to a type that can be stored in the
+        vtable.  */
+      init = build1 (NOP_EXPR, vfunc_ptr_type_node, decl);
+      TREE_CONSTANT (init) = 1;
+    }
+  else
+    {
+      if (flag_rtti)
+       decl = get_tinfo_decl (t);
+      else
+       decl = abort_fndecl;
+
+      /* Convert the declaration to a type that can be stored in the
+        vtable.  */
+      init = build1 (ADDR_EXPR, vfunc_ptr_type_node, decl);
+      TREE_CONSTANT (init) = 1;
+      init = build_vtable_entry (offset, integer_zero_node, init);
+    }
+  inits = tree_cons (NULL_TREE, init, 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;
+      inits = tree_cons (NULL_TREE, init, inits);
+    }
+
+  return inits;
+}
+
+/* Build an entry in the virtual function table.  DELTA is the offset
+   for the `this' pointer.  VCALL_INDEX is the vtable index containing
+   the vcall offset; zero if none.  ENTRY is the virtual function
+   table entry itself.  It's TREE_TYPE must be VFUNC_PTR_TYPE_NODE,
+   but it may not actually be a virtual function table pointer.  (For
+   example, it might be the address of the RTTI object, under the new
+   ABI.)  */
+
+static tree
+build_vtable_entry (delta, vcall_index, entry)
+     tree delta;
+     tree vcall_index;
+     tree entry;
+{
+  if (!vcall_index)
+    vcall_index = integer_zero_node;
+
+  if (flag_vtable_thunks)
+    {
+      HOST_WIDE_INT idelta;
+      HOST_WIDE_INT ivindex;
+      tree fn;
+
+      idelta = tree_low_cst (delta, 0);
+      ivindex = tree_low_cst (vcall_index, 0);
+      fn = TREE_OPERAND (entry, 0);
+      if ((idelta || ivindex) 
+         && fn != abort_fndecl
+         && !DECL_TINFO_FN_P (fn))
+       {
+         entry = make_thunk (entry, idelta, ivindex);
+         entry = build1 (ADDR_EXPR, vtable_entry_type, entry);
+         TREE_READONLY (entry) = 1;
+         TREE_CONSTANT (entry) = 1;
+       }
+#ifdef GATHER_STATISTICS
+      n_vtable_entries += 1;
+#endif
+      return entry;
+    }
+  else
+    {
+      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);
+
+      /* DELTA used to be constructed by `size_int' and/or size_binop,
+        which caused overflow problems when it was negative.  That should
+        be fixed now.  */
+
+      if (! int_fits_type_p (delta, delta_type_node))
+       {
+         if (flag_huge_objects)
+           sorry ("object size exceeds built-in limit for virtual function table implementation");
+         else
+           sorry ("object size exceeds normal limit for virtual function table implementation, recompile all source and use -fhuge-objects");
+       }
+      
+      TREE_CONSTANT (entry) = 1;
+      TREE_STATIC (entry) = 1;
+      TREE_READONLY (entry) = 1;
+
+#ifdef GATHER_STATISTICS
+      n_vtable_entries += 1;
+#endif
+
+      return entry;
+    }
 }