OSDN Git Service

2000-08-28 Daniel Berlin <dberlin@redhat.com>
[pf3gnuchains/gcc-fork.git] / gcc / cp / class.c
index f3f39eb..dfbdc94 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,31 +62,63 @@ typedef struct class_stack_node {
   splay_tree names_used;
 }* class_stack_node_t;
 
+typedef struct vtbl_init_data_s
+{
+  /* The base for which we're building initializers.  */
+  tree binfo;
+  /* The binfo for the most-derived type.  */
+  tree derived;
+  /* The negative-index vtable initializers built up so far.  These
+     are in order from least negative index to most negative index.  */
+  tree inits;
+  /* The last (i.e., most negative entry in INITS.  */
+  tree* last_init;
+  /* The binfo for the virtual base for which we're building
+     vcall offset initializers.  */
+  tree vbase;
+  /* The functions in vbase for which we have already provided vcall
+     offsets.  */
+  varray_type fns;
+  /* The vtable index of the next vcall or vbase offset.  */
+  tree index;
+  /* Nonzero if we are building the initializer for the primary
+     vtable.  */
+  int primary_vtbl_p;
+  /* Nonzero if we are building the initializer for a construction
+     vtable.  */
+  int ctor_vtbl_p;
+} vtbl_init_data;
+
 /* The stack itself.  This is an dynamically resized array.  The
    number of elements allocated is CURRENT_CLASS_STACK_SIZE.  */
 static int current_class_stack_size;
 static class_stack_node_t current_class_stack;
 
+/* An array of all local classes present in this translation unit, in
+   declaration order.  */
+varray_type local_classes;
+
 static tree get_vfield_name PARAMS ((tree));
 static void finish_struct_anon PARAMS ((tree));
 static tree build_vbase_pointer PARAMS ((tree, tree));
-static tree build_vtable_entry PARAMS ((tree, tree, tree));
+static tree build_vtable_entry PARAMS ((tree, tree, tree, int));
 static tree get_vtable_name PARAMS ((tree));
 static tree get_derived_offset PARAMS ((tree, tree));
 static tree get_basefndecls PARAMS ((tree, tree));
-static 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, 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));
 static tree delete_duplicate_fields_1 PARAMS ((tree, tree));
 static void delete_duplicate_fields PARAMS ((tree));
 static void finish_struct_bits PARAMS ((tree));
-static int alter_access PARAMS ((tree, tree, tree, tree));
+static int alter_access PARAMS ((tree, tree, tree));
 static void handle_using_decl PARAMS ((tree, tree));
-static int overrides PARAMS ((tree, tree));
+static int same_signature_p PARAMS ((tree, tree));
 static int strictly_overrides PARAMS ((tree, tree));
 static void mark_overriders PARAMS ((tree, tree));
 static void check_for_override PARAMS ((tree, tree));
@@ -106,52 +132,73 @@ static int method_name_cmp PARAMS ((const tree *, const tree *));
 static tree add_implicitly_declared_members PARAMS ((tree, int, int, int));
 static tree fixed_type_or_null PARAMS ((tree, int *));
 static tree resolve_address_of_overloaded_function PARAMS ((tree, tree, int,
-                                                         int, tree));
+                                                         int, int, tree));
 static void build_vtable_entry_ref PARAMS ((tree, tree, tree));
-static tree build_vtbl_initializer PARAMS ((tree, tree));
+static tree build_vtbl_initializer PARAMS ((tree, tree, tree, tree, int *));
 static int count_fields PARAMS ((tree));
 static int add_fields_to_vec PARAMS ((tree, tree, int));
 static void check_bitfield_decl PARAMS ((tree));
 static void check_field_decl PARAMS ((tree, tree, int *, int *, int *, int *));
 static void check_field_decls PARAMS ((tree, tree *, int *, int *, int *, 
                                     int *));
-static int avoid_overlap PARAMS ((tree, tree, int *));
-static tree build_base_field PARAMS ((tree, tree, int *, int *, unsigned int *));
-static tree build_base_fields PARAMS ((tree, int *));
-static tree build_vbase_pointer_fields PARAMS ((tree, int *));
+static void build_base_field PARAMS ((record_layout_info, tree, int *,
+                                     unsigned int *, varray_type *));
+static varray_type build_base_fields PARAMS ((record_layout_info, int *));
+static tree build_vbase_pointer_fields PARAMS ((record_layout_info, int *));
 static tree build_vtbl_or_vbase_field PARAMS ((tree, tree, tree, tree, tree,
                                               int *));
 static void check_methods PARAMS ((tree));
 static void remove_zero_width_bit_fields PARAMS ((tree));
 static void check_bases PARAMS ((tree, int *, int *, int *));
 static void check_bases_and_members PARAMS ((tree, int *));
-static void create_vtable_ptr PARAMS ((tree, int *, int *, tree *, tree *));
+static tree create_vtable_ptr PARAMS ((tree, int *, int *, tree *, tree *));
 static void layout_class_type PARAMS ((tree, int *, int *, tree *, tree *));
 static void fixup_pending_inline PARAMS ((struct pending_inline *));
 static void fixup_inline_methods PARAMS ((tree));
-static void set_primary_base PARAMS ((tree, int, int *));
-static tree dfs_propagate_binfo_offsets PARAMS ((tree, void *));
+static void set_primary_base PARAMS ((tree, tree, int *));
 static void propagate_binfo_offsets PARAMS ((tree, tree));
-static void layout_basetypes PARAMS ((tree));
-static void layout_virtual_bases PARAMS ((tree));
-static void remove_base_field PARAMS ((tree, tree, tree *));
-static void remove_base_fields PARAMS ((tree));
-static tree dfs_set_offset_for_shared_vbases PARAMS ((tree, void *));
+static void layout_virtual_bases PARAMS ((tree, varray_type *));
 static tree dfs_set_offset_for_unshared_vbases PARAMS ((tree, void *));
-static tree dfs_build_vbase_offset_vtbl_entries PARAMS ((tree, void *));
-static tree build_vbase_offset_vtbl_entries PARAMS ((tree, tree));
-static tree dfs_vcall_offset_queue_p PARAMS ((tree, void *));
-static tree dfs_build_vcall_offset_vtbl_entries PARAMS ((tree, void *));
-static tree build_vcall_offset_vtbl_entries PARAMS ((tree, tree));
-static tree dfs_count_virtuals PARAMS ((tree, void *));
-static void start_vtable PARAMS ((tree, int *));
+static void build_vbase_offset_vtbl_entries PARAMS ((tree, vtbl_init_data *));
+static void add_vcall_offset_vtbl_entries_r PARAMS ((tree, vtbl_init_data *));
+static void add_vcall_offset_vtbl_entries_1 PARAMS ((tree, vtbl_init_data *));
+static void build_vcall_offset_vtbl_entries PARAMS ((tree, vtbl_init_data *));
 static void layout_vtable_decl PARAMS ((tree, int));
-static int num_vfun_entries PARAMS ((tree));
 static tree dfs_find_final_overrider PARAMS ((tree, void *));
 static tree find_final_overrider PARAMS ((tree, tree, tree));
-static tree dfs_find_base PARAMS ((tree, void *));
 static int make_new_vtable PARAMS ((tree, tree));
-extern void dump_class_hierarchy PARAMS ((tree, int));
+static void dump_class_hierarchy_r PARAMS ((tree, tree, int));
+extern void dump_class_hierarchy PARAMS ((tree));
+static tree build_vtable PARAMS ((tree, tree, tree));
+static void initialize_vtable PARAMS ((tree, tree));
+static void initialize_array PARAMS ((tree, tree));
+static void layout_nonempty_base_or_field PARAMS ((record_layout_info,
+                                                  tree, tree,
+                                                  varray_type));
+static tree dfs_record_base_offsets PARAMS ((tree, void *));
+static void record_base_offsets PARAMS ((tree, varray_type *));
+static tree dfs_search_base_offsets PARAMS ((tree, void *));
+static int layout_conflict_p PARAMS ((tree, varray_type));
+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 void build_rtti_vtbl_entries PARAMS ((tree, tree, vtbl_init_data *));
+static void build_vcall_and_vbase_vtbl_entries PARAMS ((tree, 
+                                                       vtbl_init_data *));
+static tree dfs_mark_primary_bases PARAMS ((tree, void *));
+static void mark_primary_bases PARAMS ((tree));
+static void clone_constructors_and_destructors PARAMS ((tree));
+static tree build_clone PARAMS ((tree, tree));
+static void update_vtable_entry_for_fn PARAMS ((tree, tree, tree, tree *));
+static tree copy_virtuals PARAMS ((tree));
+static void build_ctor_vtbl_group PARAMS ((tree, tree));
+static void build_vtt PARAMS ((tree));
+static tree *build_vtt_inits PARAMS ((tree, tree, int, tree *, tree *));
+static tree dfs_build_secondary_vptr_vtt_inits PARAMS ((tree, void *));
+static tree dfs_fixup_binfo_vtbls PARAMS ((tree, void *));
+static tree get_matching_base PARAMS ((tree, tree));
+static tree dfs_get_primary_binfo PARAMS ((tree, void*));
 
 /* Variables shared between class.c and call.c.  */
 
@@ -172,12 +219,13 @@ int n_inner_fields_searched = 0;
    FIELD_DECLS.  */
 
 static tree
-build_vbase_pointer_fields (rec, empty_p)
-     tree rec;
+build_vbase_pointer_fields (rli, empty_p)
+     record_layout_info rli;
      int *empty_p;
 {
   /* Chain to hold all the new FIELD_DECLs which point at virtual
      base classes.  */
+  tree rec = rli->t;
   tree vbase_decls = NULL_TREE;
   tree binfos = TYPE_BINFO_BASETYPES (rec);
   int n_baseclasses = CLASSTYPE_N_BASECLASSES (rec);
@@ -195,7 +243,7 @@ build_vbase_pointer_fields (rec, empty_p)
       register tree base_binfo = TREE_VEC_ELT (binfos, i);
       register tree basetype = BINFO_TYPE (base_binfo);
 
-      if (TYPE_SIZE (basetype) == 0)
+      if (!COMPLETE_TYPE_P (basetype))
        /* This error is now reported in xref_tag, thus giving better
           location information.  */
        continue;
@@ -220,7 +268,7 @@ build_vbase_pointer_fields (rec, 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);
@@ -232,6 +280,7 @@ build_vbase_pointer_fields (rec, empty_p)
                                            empty_p);
          BINFO_VPTR_FIELD (base_binfo) = decl;
          TREE_CHAIN (decl) = vbase_decls;
+         place_field (rli, decl);
          vbase_decls = decl;
          *empty_p = 0;
 
@@ -244,246 +293,6 @@ build_vbase_pointer_fields (rec, 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) = ssize_binop (MINUS_EXPR,
-                                                 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))
-    {
-      tree exp = TREE_VALUE (init);
-
-      exp = ssize_binop (MINUS_EXPR, exp, BINFO_OFFSET (binfo));
-      exp = build1 (NOP_EXPR, vtable_entry_type, exp);
-      exp = fold (exp);
-      TREE_CONSTANT (exp) = 1;
-      /* 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) = exp;
-    }
-
-  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))
-    {
-      tree fn;
-      tree base;
-      tree base_binfo;
-      tree offset;
-
-      /* Figure out what function we're looking at.  */
-      fn = TREE_VALUE (virtuals);
-      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.  */
-      base_binfo = get_binfo (base, vod->derived, /*protect=*/0);
-      offset = ssize_binop (MINUS_EXPR,
-                           BINFO_OFFSET (base_binfo),
-                           BINFO_OFFSET (vod->vbase));
-      offset = build1 (NOP_EXPR, vtable_entry_type, offset);
-      offset = fold (offset);
-      TREE_CONSTANT (offset) = 1;
-      binfo_inits = tree_cons (NULL_TREE, offset, 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.  */
 
@@ -498,13 +307,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);
@@ -631,23 +441,18 @@ build_vbase_path (code, type, expr, path, nonnull)
   if (changed)
     {
       tree intype = TREE_TYPE (TREE_TYPE (expr));
+
       if (TYPE_MAIN_VARIANT (intype) != BINFO_TYPE (last))
-       {
-         tree binfo = get_binfo (last, TYPE_MAIN_VARIANT (intype), 0);
-         offset = BINFO_OFFSET (binfo);
-       }
+       offset
+         = BINFO_OFFSET (get_binfo (last, TYPE_MAIN_VARIANT (intype), 0));
     }
   else
     offset = BINFO_OFFSET (last);
 
-  if (TREE_INT_CST_LOW (offset))
+  if (! integer_zerop (offset))
     {
       /* Bash types to make the backend happy.  */
       offset = cp_convert (type, offset);
-#if 0
-      /* This shouldn't be necessary.  (mrs) */
-      expr = build1 (NOP_EXPR, type, expr);
-#endif
 
       /* If expr might be 0, we need to preserve that zeroness.  */
       if (nonnull == 0)
@@ -681,75 +486,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_INT_CST_LOW (delta);
-      ivindex = TREE_INT_CST_LOW (vcall_index);
-      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
 
@@ -764,7 +500,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);
@@ -773,7 +511,7 @@ build_vtable_entry_ref (basetype, vtbl, idx)
   i = build_c_cast (ptrdiff_type_node, build_unary_op (ADDR_EXPR, i, 0));
   i2 = build_array_ref (vtbl, build_int_2(0,0));
   i2 = build_c_cast (ptrdiff_type_node, build_unary_op (ADDR_EXPR, i2, 0));
-  i = build_binary_op (MINUS_EXPR, i, i2);
+  i = cp_build_binary_op (MINUS_EXPR, i, i2);
   i = build_tree_list (build_string (1, "i"), i);
 
   finish_asm_stmt (ridpointers[RID_VOLATILE],
@@ -835,7 +573,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);
     }
@@ -891,22 +645,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.  */
@@ -915,19 +672,16 @@ tree
 get_vfield_offset (binfo)
      tree binfo;
 {
-  tree tmp
-    = size_binop (FLOOR_DIV_EXPR,
-                 DECL_FIELD_BITPOS (TYPE_VFIELD (BINFO_TYPE (binfo))),
-                 size_int (BITS_PER_UNIT));
-  tmp = convert (sizetype, tmp);
-  return size_binop (PLUS_EXPR, 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
    this binfo from.  If we find TYPE first, return the offset only
    that far.  The shortened search is useful because the this pointer
    on method calling is expected to point to a DECL_CONTEXT (fndecl)
-   object, and not a baseclass of it.  */
+   object, and not a baseclass of it.   */
 
 static tree
 get_derived_offset (binfo, type)
@@ -935,59 +689,39 @@ get_derived_offset (binfo, type)
 {
   tree offset1 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
   tree offset2;
-  int i;
-  while (BINFO_BASETYPES (binfo)
-        && (i=CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo))) != -1)
-    {
-      tree binfos = BINFO_BASETYPES (binfo);
-      if (BINFO_TYPE (binfo) == type)
-       break;
-      binfo = TREE_VEC_ELT (binfos, i);
-    }
+
+  while (!same_type_p (BINFO_TYPE (binfo), type))
+    binfo = get_primary_binfo (binfo);
+
   offset2 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
   return size_binop (MINUS_EXPR, offset1, offset2);
 }
 
-/* Update the rtti info for this class.  */
+/* Create a VAR_DECL for a primary or secondary vtable for CLASS_TYPE.
+   (For a secondary vtable for B-in-D, CLASS_TYPE should be D, not B.)
+   Use NAME for the name of the vtable, and VTABLE_TYPE for its type.  */
 
-static void
-set_rtti_entry (virtuals, offset, type)
-     tree virtuals, offset, type;
+static tree
+build_vtable (class_type, name, vtable_type)
+     tree class_type;
+     tree name;
+     tree vtable_type;
 {
   tree decl;
 
-  if (CLASSTYPE_COM_INTERFACE (type))
-    return;
+  decl = build_lang_decl (VAR_DECL, name, vtable_type);
+  DECL_CONTEXT (decl) = class_type;
+  DECL_ARTIFICIAL (decl) = 1;
+  TREE_STATIC (decl) = 1;
+#ifndef WRITABLE_VTABLES
+  /* Make them READONLY by default. (mrs) */
+  TREE_READONLY (decl) = 1;
+#endif
+  DECL_VIRTUAL_P (decl) = 1;
+  import_export_vtable (decl, class_type, 0);
 
-  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;
-}
+  return decl;
+}
 
 /* Get the VAR_DECL of the vtable for TYPE. TYPE need not be polymorphic,
    or even complete.  If this does not exist, create it.  If COMPLETE is
@@ -1010,34 +744,46 @@ get_vtable_decl (type, complete)
       return decl;
     }
   
-  decl = build_lang_decl (VAR_DECL, name, void_type_node);
-  
-  /* Set TREE_PUBLIC and TREE_EXTERN as appropriate.  */
-  import_export_vtable (decl, type, 0);
-
+  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);
   
-  DECL_ARTIFICIAL (decl) = 1;
-  TREE_STATIC (decl) = 1;
-#ifndef WRITABLE_VTABLES
-  /* Make them READONLY by default. (mrs) */
-  TREE_READONLY (decl) = 1;
-#endif
   /* At one time the vtable info was grabbed 2 words at a time.  This
      fails on sparc unless you have 8-byte alignment.  (tiemann) */
   DECL_ALIGN (decl) = MAX (TYPE_ALIGN (double_type_node),
                           DECL_ALIGN (decl));
 
-  DECL_VIRTUAL_P (decl) = 1;
-  
   if (complete)
-    cp_finish_decl (decl, NULL_TREE, NULL_TREE, 0);
+    {
+      DECL_EXTERNAL (decl) = 1;
+      cp_finish_decl (decl, NULL_TREE, NULL_TREE, 0);
+    }
 
-  DECL_CONTEXT (decl) = type;
   return decl;
 }
 
+/* Returns a copy of the BINFO_VIRTUALS list in BINFO.  The
+   BV_VCALL_INDEX for each entry is cleared.  */
+
+static tree
+copy_virtuals (binfo)
+     tree binfo;
+{
+  tree copies;
+  tree t;
+
+  copies = copy_list (BINFO_VIRTUALS (binfo));
+  for (t = copies; t; t = TREE_CHAIN (t))
+    {
+      BV_VCALL_INDEX (t) = NULL_TREE;
+      BV_USE_VCALL_INDEX_P (t) = 0;
+      BV_GENERATE_THUNK_WITH_VTABLE_P (t) = 0;
+    }
+
+  return copies;
+}
+      
 /* Build the primary virtual function table for TYPE.  If BINFO is
    non-NULL, build the vtable starting with the initial approximation
    that it is the same as the one which is the head of the association
@@ -1048,29 +794,22 @@ static int
 build_primary_vtable (binfo, type)
      tree binfo, type;
 {
-  tree virtuals, decl;
+  tree decl;
+  tree virtuals;
 
   decl = get_vtable_decl (type, /*complete=*/0);
   
   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 = ssize_binop (MINUS_EXPR, integer_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
     {
@@ -1088,9 +827,7 @@ build_primary_vtable (binfo, type)
      on our first approximation.  */
   TYPE_BINFO_VTABLE (type) = decl;
   TYPE_BINFO_VIRTUALS (type) = virtuals;
-
-  binfo = TYPE_BINFO (type);
-  SET_BINFO_NEW_VTABLE_MARKED (binfo);
+  SET_BINFO_NEW_VTABLE_MARKED (TYPE_BINFO (type), type);
   return 1;
 }
 
@@ -1126,13 +863,48 @@ build_secondary_vtable (binfo, for_type)
   joiner = JOINER;
 #endif
 
-  if (BINFO_NEW_VTABLE_MARKED (binfo))
+  if (TREE_VIA_VIRTUAL (binfo))
+    my_friendly_assert (binfo == binfo_for_vbase (BINFO_TYPE (binfo),
+                                                 current_class_type),
+                       170);
+
+  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;
 
-  basetype = TYPE_MAIN_VARIANT (BINFO_TYPE (binfo));
+  /* 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, current_class_type);
+  
+  /* Make fresh virtual list, so we can smash it later.  */
+  BINFO_VIRTUALS (binfo) = copy_virtuals (binfo);
+
+  if (TREE_VIA_VIRTUAL (binfo))
+    {
+      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
+        base type's.  We can remove all this code after a while.  */
+      if (binfo1 != binfo)
+       warning ("internal inconsistency: binfo offset error for rtti");
+
+      offset = BINFO_OFFSET (binfo1);
+    }
+  else
+    offset = BINFO_OFFSET (binfo);
+
+  /* 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 ())
+    {
+      BINFO_VTABLE (binfo) = NULL_TREE;
+      return 1;
+    }
 
+  /* Create the declaration for the secondary vtable.  */
+  basetype = TYPE_MAIN_VARIANT (BINFO_TYPE (binfo));
   buf2 = TYPE_ASSEMBLER_NAME_STRING (basetype);
   i = TYPE_ASSEMBLER_NAME_LENGTH (basetype) + 1;
 
@@ -1210,55 +982,16 @@ build_secondary_vtable (binfo, for_type)
       buf2 = new_buf2;
     }
 
-  new_decl = build_lang_decl (VAR_DECL, name, TREE_TYPE (orig_decl));
-  /* Remember which class this vtable is really for.  */
-  DECL_CONTEXT (new_decl) = for_type;
-
-  DECL_ARTIFICIAL (new_decl) = 1;
-  TREE_STATIC (new_decl) = 1;
-  BINFO_VTABLE (binfo) = pushdecl_top_level (new_decl);
-  DECL_VIRTUAL_P (new_decl) = 1;
-#ifndef WRITABLE_VTABLES
-  /* Make them READONLY by default. (mrs) */
-  TREE_READONLY (new_decl) = 1;
-#endif
+  new_decl = build_vtable (for_type, name, TREE_TYPE (orig_decl));
   DECL_ALIGN (new_decl) = DECL_ALIGN (orig_decl);
-
-  /* Make fresh virtual list, so we can smash it later.  */
-  BINFO_VIRTUALS (binfo) = copy_list (BINFO_VIRTUALS (binfo));
-
-  if (TREE_VIA_VIRTUAL (binfo))
-    {
-      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
-        base type's.  We can remove all this code after a while.  */
-      if (binfo1 != binfo)
-       warning ("internal inconsistency: binfo offset error for rtti");
-
-      offset = BINFO_OFFSET (binfo1);
-    }
-  else
-    offset = BINFO_OFFSET (binfo);
-
-  set_rtti_entry (BINFO_VIRTUALS (binfo),
-                 ssize_binop (MINUS_EXPR, integer_zero_node, offset),
-                 for_type);
+  DECL_USER_ALIGN (new_decl) = DECL_USER_ALIGN (orig_decl);
+  BINFO_VTABLE (binfo) = pushdecl_top_level (new_decl);
 
 #ifdef GATHER_STATISTICS
   n_vtables += 1;
   n_vtable_elems += list_length (BINFO_VIRTUALS (binfo));
 #endif
 
-  /* Set TREE_PUBLIC and TREE_EXTERN as appropriate.  */
-  import_export_vtable (new_decl, for_type, 0);
-
-  if (TREE_VIA_VIRTUAL (binfo))
-    my_friendly_assert (binfo == BINFO_FOR_VBASE (BINFO_TYPE (binfo),
-                                                 current_class_type),
-                       170);
-  SET_BINFO_NEW_VTABLE_MARKED (binfo);
   return 1;
 }
 
@@ -1286,9 +1019,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)
@@ -1298,15 +1031,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;
 
@@ -1324,7 +1054,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
@@ -1337,42 +1067,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.  */
 {
@@ -1386,8 +1126,9 @@ add_virtual_function (new_virtuals_p, overridden_virtuals_p,
     /* We've already dealt with this function.  */
     return;
 
-  new_virtual = build_tree_list (integer_zero_node, fndecl);
-  BV_VCALL_INDEX (new_virtual) = integer_zero_node;
+  new_virtual = make_node (TREE_LIST);
+  BV_FN (new_virtual) = fndecl;
+  BV_DELTA (new_virtual) = integer_zero_node;
 
   if (DECL_VINDEX (fndecl) == error_mark_node)
     {
@@ -1397,10 +1138,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.  */
@@ -1417,183 +1156,199 @@ add_virtual_function (new_virtuals_p, overridden_virtuals_p,
 \f
 extern struct obstack *current_obstack;
 
-/* Add method METHOD to class TYPE.
-
-   If non-NULL, FIELDS is the entry in the METHOD_VEC vector entry of
-   the class type where the method should be added.  */
+/* Add method METHOD to class TYPE.  If ERROR_P is true, we are adding
+   the method after the class has already been defined because a
+   declaration for it was seen.  (Even though that is erroneous, we
+   add the method for improved error recovery.)  */
 
 void
-add_method (type, fields, method)
-     tree type, *fields, method;
+add_method (type, method, error_p)
+     tree type;
+     tree method;
+     int error_p;
 {
-  /* Setting the DECL_CONTEXT here is probably redundant.  */
-  DECL_CONTEXT (method) = type;
-  
-  if (fields && *fields)
-    *fields = build_overload (method, *fields);
-  else 
+  int using = (DECL_CONTEXT (method) != type);
+  int len;
+  int slot;
+  tree method_vec;
+
+  if (!CLASSTYPE_METHOD_VEC (type))
+    /* Make a new method vector.  We start with 8 entries.  We must
+       allocate at least two (for constructors and destructors), and
+       we're going to end up with an assignment operator at some point
+       as well.
+       
+       We could use a TREE_LIST for now, and convert it to a TREE_VEC
+       in finish_struct, but we would probably waste more memory
+       making the links in the list than we would by over-allocating
+       the size of the vector here.  Furthermore, we would complicate
+       all the code that expects this to be a vector.  */
+    CLASSTYPE_METHOD_VEC (type) = make_tree_vec (8);
+
+  method_vec = CLASSTYPE_METHOD_VEC (type);
+  len = TREE_VEC_LENGTH (method_vec);
+
+  /* Constructors and destructors go in special slots.  */
+  if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (method))
+    slot = CLASSTYPE_CONSTRUCTOR_SLOT;
+  else if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (method))
+    slot = CLASSTYPE_DESTRUCTOR_SLOT;
+  else
     {
-      int len;
-      int slot;
-      tree method_vec;
-
-      if (!CLASSTYPE_METHOD_VEC (type))
-       /* Make a new method vector.  We start with 8 entries.  We must
-          allocate at least two (for constructors and destructors), and
-          we're going to end up with an assignment operator at some
-          point as well.  
-
-          We could use a TREE_LIST for now, and convert it to a
-          TREE_VEC in finish_struct, but we would probably waste more
-          memory making the links in the list than we would by
-          over-allocating the size of the vector here.  Furthermore,
-          we would complicate all the code that expects this to be a
-          vector.  */
-       CLASSTYPE_METHOD_VEC (type) = make_tree_vec (8);
-
-      method_vec = CLASSTYPE_METHOD_VEC (type);
-      len = TREE_VEC_LENGTH (method_vec);
-
-      if (DECL_NAME (method) == constructor_name (type))
-       /* A new constructor or destructor.  Constructors go in 
-          slot 0; destructors go in slot 1.  */
-       slot = DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (method)) ? 1 : 0;
-      else
-       {
-         /* See if we already have an entry with this name.  */
-         for (slot = 2; slot < len; ++slot)
-           if (!TREE_VEC_ELT (method_vec, slot)
-               || (DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (method_vec, 
-                                                         slot))) 
-                   == DECL_NAME (method)))
-             break;
+      /* See if we already have an entry with this name.  */
+      for (slot = CLASSTYPE_FIRST_CONVERSION_SLOT; slot < len; ++slot)
+       if (!TREE_VEC_ELT (method_vec, slot)
+           || (DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (method_vec, 
+                                                     slot))) 
+               == DECL_NAME (method)))
+         break;
                
-         if (slot == len)
-           {
-             /* We need a bigger method vector.  */
-             tree new_vec = make_tree_vec (2 * len);
-             bcopy ((PTR) &TREE_VEC_ELT (method_vec, 0),
-                    (PTR) &TREE_VEC_ELT (new_vec, 0),
-                    len * sizeof (tree));
-             len = 2 * len;
-             method_vec = CLASSTYPE_METHOD_VEC (type) = new_vec;
-           }
+      if (slot == len)
+       {
+         /* We need a bigger method vector.  */
+         int new_len;
+         tree new_vec;
+
+         /* In the non-error case, we are processing a class
+            definition.  Double the size of the vector to give room
+            for new methods.  */
+         if (!error_p)
+           new_len = 2 * len;
+         /* In the error case, the vector is already complete.  We
+            don't expect many errors, and the rest of the front-end
+            will get confused if there are empty slots in the vector.  */
+         else
+           new_len = len + 1;
+
+         new_vec = make_tree_vec (new_len);
+         bcopy ((PTR) &TREE_VEC_ELT (method_vec, 0),
+                (PTR) &TREE_VEC_ELT (new_vec, 0),
+                len * sizeof (tree));
+         len = new_len;
+         method_vec = CLASSTYPE_METHOD_VEC (type) = new_vec;
+       }
 
-         if (DECL_CONV_FN_P (method) && !TREE_VEC_ELT (method_vec, slot))
+      if (DECL_CONV_FN_P (method) && !TREE_VEC_ELT (method_vec, slot))
+       {
+         /* Type conversion operators have to come before ordinary
+            methods; add_conversions depends on this to speed up
+            looking for conversion operators.  So, if necessary, we
+            slide some of the vector elements up.  In theory, this
+            makes this algorithm O(N^2) but we don't expect many
+            conversion operators.  */
+         for (slot = 2; slot < len; ++slot)
            {
-             /* Type conversion operators have to come before
-                ordinary methods; add_conversions depends on this to
-                speed up looking for conversion operators.  So, if
-                necessary, we slide some of the vector elements up.
-                In theory, this makes this algorithm O(N^2) but we
-                don't expect many conversion operators.  */
-             for (slot = 2; slot < len; ++slot)
-               {
-                 tree fn = TREE_VEC_ELT (method_vec, slot);
+             tree fn = TREE_VEC_ELT (method_vec, slot);
   
-                 if (!fn)
-                   /* There are no more entries in the vector, so we
-                      can insert the new conversion operator here.  */
-                   break;
+             if (!fn)
+               /* There are no more entries in the vector, so we
+                  can insert the new conversion operator here.  */
+               break;
                  
-                 if (!DECL_CONV_FN_P (OVL_CURRENT (fn)))
-                   /* We can insert the new function right at the
-                      SLOTth position.  */
-                   break;
-               }
+             if (!DECL_CONV_FN_P (OVL_CURRENT (fn)))
+               /* We can insert the new function right at the
+                  SLOTth position.  */
+               break;
+           }
   
-             if (!TREE_VEC_ELT (method_vec, slot))
-               /* There is nothing in the Ith slot, so we can avoid
-                  moving anything.  */
+         if (!TREE_VEC_ELT (method_vec, slot))
+           /* There is nothing in the Ith slot, so we can avoid
+              moving anything.  */
                ; 
-             else
-               {
-                 /* We know the last slot in the vector is empty
-                    because we know that at this point there's room
-                    for a new function.  */
-                 bcopy ((PTR) &TREE_VEC_ELT (method_vec, slot),
-                        (PTR) &TREE_VEC_ELT (method_vec, slot + 1),
-                        (len - slot - 1) * sizeof (tree));
-                 TREE_VEC_ELT (method_vec, slot) = NULL_TREE;
-               }
+         else
+           {
+             /* We know the last slot in the vector is empty
+                because we know that at this point there's room
+                for a new function.  */
+             bcopy ((PTR) &TREE_VEC_ELT (method_vec, slot),
+                    (PTR) &TREE_VEC_ELT (method_vec, slot + 1),
+                    (len - slot - 1) * sizeof (tree));
+             TREE_VEC_ELT (method_vec, slot) = NULL_TREE;
            }
        }
+    }
       
-      if (template_class_depth (type))
-       /* TYPE is a template class.  Don't issue any errors now; wait
-          until instantiation time to complain.  */
-         ;
-      else
-       {
-         tree fns;
+  if (template_class_depth (type))
+    /* TYPE is a template class.  Don't issue any errors now; wait
+       until instantiation time to complain.  */
+    ;
+  else
+    {
+      tree fns;
 
-         /* Check to see if we've already got this method.  */
-         for (fns = TREE_VEC_ELT (method_vec, slot);
-              fns;
-              fns = OVL_NEXT (fns))
-           {
-             tree fn = OVL_CURRENT (fns);
+      /* Check to see if we've already got this method.  */
+      for (fns = TREE_VEC_ELT (method_vec, slot);
+          fns;
+          fns = OVL_NEXT (fns))
+       {
+         tree fn = OVL_CURRENT (fns);
                 
-             if (TREE_CODE (fn) != TREE_CODE (method))
-               continue;
+         if (TREE_CODE (fn) != TREE_CODE (method))
+           continue;
 
-             if (TREE_CODE (method) != TEMPLATE_DECL)
+         if (TREE_CODE (method) != TEMPLATE_DECL)
+           {
+             /* [over.load] Member function declarations with the
+                same name and the same parameter types cannot be
+                overloaded if any of them is a static member
+                function declaration.  */
+             if ((DECL_STATIC_FUNCTION_P (fn)
+                  != DECL_STATIC_FUNCTION_P (method))
+                 || using)
                {
-                 /* [over.load] Member function declarations with the
-                    same name and the same parameter types cannot be
-                    overloaded if any of them is a static member
-                    function declaration.  */
-                 if (DECL_STATIC_FUNCTION_P (fn)
-                     != DECL_STATIC_FUNCTION_P (method))
-                   {
-                     tree parms1 = TYPE_ARG_TYPES (TREE_TYPE (fn));
-                     tree parms2 = TYPE_ARG_TYPES (TREE_TYPE (method));
+                 tree parms1 = TYPE_ARG_TYPES (TREE_TYPE (fn));
+                 tree parms2 = TYPE_ARG_TYPES (TREE_TYPE (method));
 
-                     if (! DECL_STATIC_FUNCTION_P (fn))
-                       parms1 = TREE_CHAIN (parms1);
-                     else
-                       parms2 = TREE_CHAIN (parms2);
+                 if (! DECL_STATIC_FUNCTION_P (fn))
+                   parms1 = TREE_CHAIN (parms1);
+                 if (! DECL_STATIC_FUNCTION_P (method))
+                   parms2 = TREE_CHAIN (parms2);
 
-                     if (compparms (parms1, parms2))
+                 if (compparms (parms1, parms2))
+                   {
+                     if (using)
+                       /* Defer to the local function.  */
+                       return;
+                     else
                        cp_error ("`%#D' and `%#D' cannot be overloaded",
                                  fn, method);
                    }
-
-                 /* Since this is an ordinary function in a
-                    non-template class, it's mangled name can be used
-                    as a unique identifier.  This technique is only
-                    an optimization; we would get the same results if
-                    we just used decls_match here.  */
-                 if (DECL_ASSEMBLER_NAME (fn) 
-                     != DECL_ASSEMBLER_NAME (method))
-                   continue;
                }
-             else if (!decls_match (fn, method))
+
+             /* Since this is an ordinary function in a
+                non-template class, it's mangled name can be used
+                as a unique identifier.  This technique is only
+                an optimization; we would get the same results if
+                we just used decls_match here.  */
+             if (DECL_ASSEMBLER_NAME (fn) 
+                 != DECL_ASSEMBLER_NAME (method))
                continue;
+           }
+         else if (!decls_match (fn, method))
+           continue;
 
-             /* There has already been a declaration of this method
-                or member template.  */
-             cp_error_at ("`%D' has already been declared in `%T'", 
-                          method, type);
+         /* There has already been a declaration of this method
+            or member template.  */
+         cp_error_at ("`%D' has already been declared in `%T'", 
+                      method, type);
 
-             /* We don't call duplicate_decls here to merge the
-                declarations because that will confuse things if the
-                methods have inline definitions.  In particular, we
-                will crash while processing the definitions.  */
-             return;
-           }
+         /* We don't call duplicate_decls here to merge the
+            declarations because that will confuse things if the
+            methods have inline definitions.  In particular, we
+            will crash while processing the definitions.  */
+         return;
        }
+    }
 
-      /* Actually insert the new method.  */
-      TREE_VEC_ELT (method_vec, slot) 
-       = build_overload (method, TREE_VEC_ELT (method_vec, slot));
+  /* Actually insert the new method.  */
+  TREE_VEC_ELT (method_vec, slot) 
+    = build_overload (method, TREE_VEC_ELT (method_vec, slot));
 
       /* Add the new binding.  */ 
-      if (!DECL_CONSTRUCTOR_P (method)
-         && !DECL_DESTRUCTOR_P (method))
-       push_class_level_binding (DECL_NAME (method),
-                                 TREE_VEC_ELT (method_vec, slot));
-    }
+  if (!DECL_CONSTRUCTOR_P (method)
+      && !DECL_DESTRUCTOR_P (method))
+    push_class_level_binding (DECL_NAME (method),
+                             TREE_VEC_ELT (method_vec, slot));
 }
 
 /* Subroutines of finish_struct.  */
@@ -1700,18 +1455,21 @@ delete_duplicate_fields (fields)
     TREE_CHAIN (x) = delete_duplicate_fields_1 (x, TREE_CHAIN (x));
 }
 
-/* Change the access of FDECL to ACCESS in T.  The access to FDECL is
-   along the path given by BINFO.  Return 1 if change was legit,
-   otherwise return 0.  */
+/* Change the access of FDECL to ACCESS in T.  Return 1 if change was
+   legit, otherwise return 0.  */
 
 static int
-alter_access (t, binfo, fdecl, access)
+alter_access (t, fdecl, access)
      tree t;
-     tree binfo;
      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)
@@ -1731,7 +1489,7 @@ alter_access (t, binfo, fdecl, access)
     }
   else
     {
-      enforce_access (binfo, fdecl);
+      enforce_access (t, fdecl);
       DECL_ACCESS (fdecl) = tree_cons (t, access, DECL_ACCESS (fdecl));
       return 1;
     }
@@ -1753,11 +1511,7 @@ handle_using_decl (using_decl, t)
     : access_public_node;
   tree fdecl, binfo;
   tree flist = NULL_TREE;
-  tree fields = TYPE_FIELDS (t);
-  tree method_vec = CLASSTYPE_METHOD_VEC (t);
-  tree tmp;
-  int i;
-  int n_methods;
+  tree old_value;
 
   binfo = binfo_or_else (ctype, t);
   if (! binfo)
@@ -1778,57 +1532,56 @@ handle_using_decl (using_decl, t)
       return;
     }
 
-  /* Functions are represented as TREE_LIST, with the purpose
-     being the type and the value the functions. Other members
-     come as themselves. */
-  if (TREE_CODE (fdecl) == TREE_LIST)
+  if (BASELINK_P (fdecl))
     /* Ignore base type this came from. */
     fdecl = TREE_VALUE (fdecl);
 
-  if (TREE_CODE (fdecl) == OVERLOAD)
+  old_value = IDENTIFIER_CLASS_VALUE (name);
+  if (old_value)
     {
-      /* We later iterate over all functions. */
-      flist = fdecl;
-      fdecl = OVL_FUNCTION (flist);
+      if (is_overloaded_fn (old_value))
+       old_value = OVL_CURRENT (old_value);
+
+      if (DECL_P (old_value) && DECL_CONTEXT (old_value) == t)
+       /* OK */;
+      else
+       old_value = NULL_TREE;
     }
-  
-  name = DECL_NAME (fdecl);
-  n_methods = method_vec ? TREE_VEC_LENGTH (method_vec) : 0;
-  for (i = 2; i < n_methods && TREE_VEC_ELT (method_vec, i); i++)
-    if (DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (method_vec, i)))
-       == name)
-      {
-       cp_error ("cannot adjust access to `%#D' in `%#T'", fdecl, t);
-       cp_error_at ("  because of local method `%#D' with same name",
-                    OVL_CURRENT (TREE_VEC_ELT (method_vec, i)));
-       return;
-      }
 
-  if (! DECL_LANG_SPECIFIC (fdecl))
-    /* We don't currently handle DECL_ACCESS for TYPE_DECLs; just return.  */
-    return;
-  
-  for (tmp = fields; tmp; tmp = TREE_CHAIN (tmp))
-    if (DECL_NAME (tmp) == name)
-      {
-       cp_error ("cannot adjust access to `%#D' in `%#T'", fdecl, t);
-       cp_error_at ("  because of local field `%#D' with same name", tmp);
-       return;
-      }
-  
-  /* Make type T see field decl FDECL with access ACCESS.*/
-  if (flist)
+  if (is_overloaded_fn (fdecl))
+    flist = fdecl;
+
+  if (! old_value)
+    ;
+  else if (is_overloaded_fn (old_value))
     {
-      while (flist)
+      if (flist)
+       /* It's OK to use functions from a base when there are functions with
+          the same name already present in the current class.  */;
+      else
        {
-         if (alter_access (t, binfo, OVL_FUNCTION (flist), 
-                           access) == 0)
-           return;
-         flist = OVL_CHAIN (flist);
+         cp_error ("`%D' invalid in `%#T'", using_decl, t);
+         cp_error_at ("  because of local method `%#D' with same name",
+                      OVL_CURRENT (old_value));
+         return;
        }
     }
   else
-    alter_access (t, binfo, fdecl, access);
+    {
+      cp_error ("`%D' invalid in `%#T'", using_decl, t);
+      cp_error_at ("  because of local field `%#D' with same name", old_value);
+      return;
+    }
+  
+  /* Make type T see field decl FDECL with access ACCESS.*/
+  if (flist)
+    for (; flist; flist = OVL_NEXT (flist))
+      {
+       add_method (t, OVL_CURRENT (flist), /*error_p=*/0);
+       alter_access (t, OVL_CURRENT (flist), access);
+      }
+  else
+    alter_access (t, fdecl, access);
 }
 \f
 /* Run through the base clases of T, updating
@@ -1868,7 +1621,7 @@ check_bases (t, cant_have_default_ctor_p, cant_have_const_ctor_p,
       /* If the type of basetype is incomplete, then we already
         complained about that fact (and we should have fixed it up as
         well).  */
-      if (TYPE_SIZE (basetype) == 0)
+      if (!COMPLETE_TYPE_P (basetype))
        {
          int j;
          /* The base type is of incomplete type.  It is
@@ -1908,11 +1661,8 @@ check_bases (t, cant_have_default_ctor_p, cant_have_const_ctor_p,
        {
          *cant_have_default_ctor_p = 1;
          if (! TYPE_HAS_CONSTRUCTOR (t))
-           {
-             cp_pedwarn ("base `%T' with only non-default constructor",
-                         basetype);
-             cp_pedwarn ("in class without a constructor");
-           }
+            cp_pedwarn ("base `%T' with only non-default constructor in class without a constructor",
+                        basetype);
        }
 
       /* If the base class is not empty or nearly empty, then this
@@ -1932,7 +1682,8 @@ check_bases (t, cant_have_default_ctor_p, cant_have_const_ctor_p,
       /* A lot of properties from the bases also apply to the derived
         class.  */
       TYPE_NEEDS_CONSTRUCTING (t) |= TYPE_NEEDS_CONSTRUCTING (basetype);
-      TYPE_NEEDS_DESTRUCTOR (t) |= TYPE_NEEDS_DESTRUCTOR (basetype);
+      TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) 
+       |= TYPE_HAS_NONTRIVIAL_DESTRUCTOR (basetype);
       TYPE_HAS_COMPLEX_ASSIGN_REF (t) 
        |= TYPE_HAS_COMPLEX_ASSIGN_REF (basetype);
       TYPE_HAS_COMPLEX_INIT_REF (t) |= TYPE_HAS_COMPLEX_INIT_REF (basetype);
@@ -1955,43 +1706,134 @@ check_bases (t, cant_have_default_ctor_p, cant_have_const_ctor_p,
     }
 }
 
-/* Make the Ith baseclass of T its primary base.  */
+/* Called via dfs_walk from mark_primary_bases.  Sets
+   BINFO_PRIMARY_MARKED_P for BINFO, if appropriate.  */
+
+static tree
+dfs_mark_primary_bases (binfo, data)
+     tree binfo;
+     void *data;
+{
+  tree base_binfo;
+
+  if (!CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (binfo)))
+    return NULL_TREE;
+
+  base_binfo = get_primary_binfo (binfo);
+
+  if (TREE_VIA_VIRTUAL (base_binfo))
+    {
+      tree shared_binfo;
+      tree type;
+
+      type = (tree) data;
+      shared_binfo = binfo_for_vbase (BINFO_TYPE (base_binfo), type);
+
+      /* If this virtual base is not already primary somewhere else in
+        the hiearchy, then we'll be using this copy.  */
+      if (!BINFO_PRIMARY_MARKED_P (shared_binfo))
+       {
+         /* Make sure the CLASSTYPE_VBASECLASSES list contains the
+            primary copy; it's the one that really exists.  */
+         if (base_binfo != shared_binfo)
+           TREE_VALUE (purpose_member (BINFO_TYPE (base_binfo),
+                                       CLASSTYPE_VBASECLASSES (type)))
+             = base_binfo;
+       }
+      else
+       base_binfo = NULL_TREE;
+    }
+
+  if (base_binfo)
+    BINFO_PRIMARY_BASE_OF (base_binfo) = binfo;
+
+  return NULL_TREE;
+}
+
+/* Set BINFO_PRIMARY_MARKED_P for all binfos in the hierarchy
+   dominated by BINFO that are primary bases.  */
+
+static void
+mark_primary_bases (type)
+     tree type;
+{
+  tree vbases;
+
+  /* Mark the TYPE_BINFO hierarchy.  We need to mark primary bases in
+     pre-order to deal with primary virtual bases.  (The virtual base
+     would be skipped if it were not marked as primary, and that
+     requires getting to dfs_mark_primary_bases before
+     dfs_skip_nonprimary_vbases_unmarkedp has a chance to skip the
+     virtual base.)  */
+  dfs_walk_real (TYPE_BINFO (type), dfs_mark_primary_bases, NULL,
+                dfs_skip_nonprimary_vbases_unmarkedp, type);
+
+  /* Now go through the virtual base classes in inheritance graph
+     order.  Any that are not already primary will need to be
+     allocated in TYPE, and so we need to mark their primary bases.  */
+  for (vbases = TYPE_BINFO (type); vbases; vbases = TREE_CHAIN (vbases))
+    {
+      tree vbase;
+
+      /* Make sure that only BINFOs appear on this list.
+        Historically, the TREE_CHAIN was used for other purposes, and
+        we want to make sure that none of those uses remain.  */
+      my_friendly_assert (TREE_CODE (vbases) == TREE_VEC, 20000402);
+
+      if (!TREE_VIA_VIRTUAL (vbases))
+       continue;
+
+      vbase = binfo_for_vbase (BINFO_TYPE (vbases), type);
+      if (BINFO_PRIMARY_MARKED_P (vbase))
+       /* This virtual base was already included in the hierarchy, so
+          there's nothing to do here.  */
+       continue;
+
+      /* Now, walk its bases.  */
+      dfs_walk_real (vbase, dfs_mark_primary_bases, NULL,
+                    dfs_skip_nonprimary_vbases_unmarkedp, type);
+    }
+}
+
+/* Make the BINFO the primary base of T.  */
 
 static void
-set_primary_base (t, i, has_virtual_p)
+set_primary_base (t, binfo, vfuns_p)
      tree t;
-     int i;
-     int *has_virtual_p;
+     tree binfo;
+     int *vfuns_p;
 {
   tree basetype;
 
-  CLASSTYPE_VFIELD_PARENT (t) = i;
-  basetype = BINFO_TYPE (CLASSTYPE_PRIMARY_BINFO (t));
+  CLASSTYPE_PRIMARY_BINFO (t) = binfo;
+  basetype = BINFO_TYPE (binfo);
   TYPE_BINFO_VTABLE (t) = TYPE_BINFO_VTABLE (basetype);
   TYPE_BINFO_VIRTUALS (t) = TYPE_BINFO_VIRTUALS (basetype);
   TYPE_VFIELD (t) = TYPE_VFIELD (basetype);
   CLASSTYPE_RTTI (t) = CLASSTYPE_RTTI (basetype);
-  *has_virtual_p = CLASSTYPE_VSIZE (basetype);
+  *vfuns_p = CLASSTYPE_VSIZE (basetype);
 }
 
 /* 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);
+  tree vbases;
+  tree type_binfo;
 
   /* If there are no baseclasses, there is certainly no primary base.  */
   if (n_baseclasses == 0)
     return;
 
-  *has_virtual_p = 0;
+  type_binfo = TYPE_BINFO (t);
 
   for (i = 0; i < n_baseclasses; i++)
     {
-      tree base_binfo = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (t), i);
+      tree base_binfo = BINFO_BASETYPE (type_binfo, i);
       tree basetype = BINFO_TYPE (base_binfo);
 
       if (TYPE_CONTAINS_VPTR_P (basetype))
@@ -2010,7 +1852,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, base_binfo, vfuns_p);
              CLASSTYPE_VFIELDS (t) = copy_list (CLASSTYPE_VFIELDS (basetype));
            }
          else
@@ -2028,35 +1870,99 @@ 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, base_binfo, vfuns_p);
            }
        }
     }
 
   if (!TYPE_VFIELD (t))
-    CLASSTYPE_VFIELD_PARENT (t) = -1;
+    CLASSTYPE_PRIMARY_BINFO (t) = NULL_TREE;
+
+  /* Mark the indirect primary bases.  */
+  for (vbases = CLASSTYPE_VBASECLASSES (t);
+       vbases;
+       vbases = TREE_CHAIN (vbases)) 
+    {
+      tree binfo = TREE_VALUE (vbases);
+
+      /* See if this virtual base is an indirect primary base.  If so,
+        it must be either a primary base or an indirect primary base
+        in one of the direct bases.  */
+      for (i = 0; i < n_baseclasses; ++i) 
+       {
+         tree basetype;
+         tree v;
+
+         basetype = TYPE_BINFO_BASETYPE (t, i);
+         for (v = CLASSTYPE_VBASECLASSES (basetype); 
+              v; 
+              v = TREE_CHAIN (v))
+           {
+             tree b = TREE_VALUE (v);
+             if ((BINFO_PRIMARY_MARKED_P (b)
+                  || BINFO_INDIRECT_PRIMARY_P (b))
+                 && same_type_p (BINFO_TYPE (b), BINFO_TYPE (binfo)))
+               {
+                 BINFO_INDIRECT_PRIMARY_P (binfo) = 1;
+                 break;
+               }
+           }
+
+         /* If we've discovered that this virtual base is an indirect
+            primary base, then we can move on to the next virtual
+            base.  */
+         if (BINFO_INDIRECT_PRIMARY_P (binfo))
+           break;
+       }
+    }
 
   /* The new ABI allows for the use of a "nearly-empty" virtual base
      class as the primary base class if no non-virtual polymorphic
      base can be found.  */
   if (flag_new_abi && !CLASSTYPE_HAS_PRIMARY_BASE_P (t))
-    for (i = 0; i < n_baseclasses; ++i)
-      {
-       tree base_binfo = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (t), i);
-       tree basetype = BINFO_TYPE (base_binfo);
+    {
+      /* If not NULL, this is the best primary base candidate we have
+         found so far.  */
+      tree candidate = NULL_TREE;
+      tree base_binfo;
 
-       if (TREE_VIA_VIRTUAL (base_binfo) 
-           && CLASSTYPE_NEARLY_EMPTY_P (basetype))
-         {
-           set_primary_base (t, i, has_virtual_p);
-           CLASSTYPE_VFIELDS (t) = copy_list (CLASSTYPE_VFIELDS (basetype));
-           break;
-         }
-      }
+      /* Loop over the baseclasses.  */
+      for (base_binfo = TYPE_BINFO (t);
+          base_binfo;
+          base_binfo = TREE_CHAIN (base_binfo))
+       {
+         tree basetype = BINFO_TYPE (base_binfo);
 
-  /* Mark the primary base classes at this point.  */
-  mark_primary_bases (t);
+         if (TREE_VIA_VIRTUAL (base_binfo) 
+             && CLASSTYPE_NEARLY_EMPTY_P (basetype))
+           {
+             /* If this is not an indirect primary base, then it's
+                definitely our primary base.  */
+             if (!BINFO_INDIRECT_PRIMARY_P (base_binfo))
+               {
+                 candidate = base_binfo;
+                 break;
+               }
+             /* If this was an indirect primary base, it's still our
+                primary base -- unless there's another nearly-empty
+                virtual base that isn't an indirect primary base.  */
+             else if (!candidate)
+               candidate = base_binfo;
+           }
+       }
+
+      /* If we've got a primary base, use it.  */
+      if (candidate)
+       {
+         set_primary_base (t, candidate, vfuns_p);
+         CLASSTYPE_VFIELDS (t) 
+           = copy_list (CLASSTYPE_VFIELDS (BINFO_TYPE (candidate)));
+       }       
+    }
+
+  /* Mark the primary base classes at this point.  */
+  mark_primary_bases (t);
 }
 \f
 /* Set memoizing fields and bits of T (and its variants) for later
@@ -2077,7 +1983,8 @@ finish_struct_bits (t)
       TYPE_HAS_CONSTRUCTOR (variants) = TYPE_HAS_CONSTRUCTOR (t);
       TYPE_HAS_DESTRUCTOR (variants) = TYPE_HAS_DESTRUCTOR (t);
       TYPE_NEEDS_CONSTRUCTING (variants) = TYPE_NEEDS_CONSTRUCTING (t);
-      TYPE_NEEDS_DESTRUCTOR (variants) = TYPE_NEEDS_DESTRUCTOR (t);
+      TYPE_HAS_NONTRIVIAL_DESTRUCTOR (variants) 
+       = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t);
 
       TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (variants) 
        = TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (t);
@@ -2334,14 +2241,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)
@@ -2349,7 +2251,6 @@ finish_struct_methods (t)
 {
   tree fn_fields;
   tree method_vec;
-  tree ctor_name = constructor_name (t);
   int slot, len;
 
   if (!TYPE_METHODS (t))
@@ -2370,52 +2271,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;
@@ -2504,9 +2363,9 @@ duplicate_tag_error (t)
   TYPE_NONCOPIED_PARTS (t) = NULL_TREE;
 }
 
-/* Make the BINFO's vtablehave N entries, including RTTI entries, but
-   not including vbase and vcall offsets.  Set its type and call the
-   backend to lay it out.  */
+/* Make the BINFO's vtablehave N entries, including RTTI entries,
+   vbase and vcall offsets, etc.  Set its type and call the backend
+   to lay it out.  */
 
 static void
 layout_vtable_decl (binfo, n)
@@ -2515,22 +2374,19 @@ layout_vtable_decl (binfo, n)
 {
   tree itype;
   tree atype;
+  tree vtable;
 
   itype = size_int (n);
-  itype = size_binop (PLUS_EXPR, 
-                     itype,
-                     num_extra_vtbl_entries (binfo));
   atype = build_cplus_array_type (vtable_entry_type, 
                                  build_index_type (itype));
   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
@@ -2540,254 +2396,28 @@ layout_vtable_decl (binfo, n)
     }
 }
 
-/* Returns the number of virtual function table entries (excluding
-   RTTI information, vbase and vcall offests, etc.) in the vtable for
-   BINFO.  */
-
-static int
-num_vfun_entries (binfo)
-     tree binfo;
-{
-  return list_length (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;
-{
-  tree type;
-  int entries;
-
-  type = BINFO_TYPE (binfo);
-  entries = 0;
-
-  /* There is an entry for the offset to each virtual base.  */
-  if (vbase_offsets_in_vtable_p ())
-    entries += list_length (CLASSTYPE_VBASECLASSES (type));
-
-  /* If this is a virtual base, there are entries for each virtual
-     function defined in this class or its bases.  */
-  if (vcall_offsets_in_vtable_p () && TREE_VIA_VIRTUAL (binfo))
-    {
-      vcall_offset_data vod;
-
-      vod.vbase = binfo;
-      vod.offsets = 0;
-      dfs_walk (binfo,
-               dfs_count_virtuals,
-               dfs_vcall_offset_queue_p,
-               &vod);
-      entries += vod.offsets;
-    }
-      
-  return entries ? size_int (entries) : size_zero_node;
-}
-
-/* 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;
-
-  offset = size_binop (EXACT_DIV_EXPR,
-                      TYPE_SIZE (vtable_entry_type),
-                      size_int (BITS_PER_UNIT));
-  offset = size_binop (MULT_EXPR, offset, num_extra_vtbl_entries (binfo));
-  return fold (offset);
-}
-
-/* Construct the initializer for BINFOs virtual function table.  BINFO
-   is part of the hierarchy dominated by T.  */
-
-static tree
-build_vtbl_initializer (binfo, t)
-     tree binfo;
-     tree t;
-{
-  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);
-
-  /* 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)
-    {
-      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.  */
-    }
-
-  /* Go through all the ordinary virtual functions, building up
-     initializers.  */
-  while (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.  */
-      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.  */
-  inits = nreverse (inits);
-  /* Package all the initializers up as an array initializer.  */
-  return build_nt (CONSTRUCTOR, NULL_TREE, inits);
-}
-
-/* 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))
-    {
-      tree decl;
-      tree context;
-      
-      layout_vtable_decl (binfo, list_length (BINFO_VIRTUALS (binfo)));
-      decl = BINFO_VTABLE (binfo);
-      context = DECL_CONTEXT (decl);
-      DECL_CONTEXT (decl) = 0;
-      DECL_INITIAL (decl) = build_vtbl_initializer (binfo, (tree) data);
-      cp_finish_decl (decl, DECL_INITIAL (decl), NULL_TREE, 0);
-      DECL_CONTEXT (decl) = context;
-    }
-
-  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;
-{
-  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.  */
+/* True iff FNDECL and BASE_FNDECL (both non-static member functions)
+   have the same signature.  */
 
 static int
-overrides (fndecl, base_fndecl)
+same_signature_p (fndecl, base_fndecl)
      tree fndecl, base_fndecl;
 {
-  /* Destructors have special names.  */
-  if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (base_fndecl))
-      && DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
+  /* One destructor overrides another if they are the same kind of
+     destructor.  */
+  if (DECL_DESTRUCTOR_P (base_fndecl) && DECL_DESTRUCTOR_P (fndecl)
+      && special_function_p (base_fndecl) == special_function_p (fndecl))
     return 1;
-  if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (base_fndecl))
-      || DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
+  /* But a non-destructor never overrides a destructor, nor vice
+     versa, nor do different kinds of destructors override
+     one-another.  For example, a complete object destructor does not
+     override a deleting destructor.  */
+  if (DECL_DESTRUCTOR_P (base_fndecl) || DECL_DESTRUCTOR_P (fndecl))
     return 0;
+
   if (DECL_NAME (fndecl) == DECL_NAME (base_fndecl))
     {
       tree types, base_types;
-#if 0
-      retypes = TREE_TYPE (TREE_TYPE (fndecl));
-      base_retypes = TREE_TYPE (TREE_TYPE (base_fndecl));
-#endif
       types = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
       base_types = TYPE_ARG_TYPES (TREE_TYPE (base_fndecl));
       if ((TYPE_QUALS (TREE_TYPE (TREE_VALUE (base_types)))
@@ -2829,16 +2459,19 @@ dfs_find_final_overrider (binfo, data)
       tree path;
       tree method;
 
+      /* We haven't found an overrider yet.  */
+      method = NULL_TREE;
       /* We've found a path to the declaring base.  Walk down the path
         looking for an overrider for FN.  */
-      for (path = reverse_path (binfo); 
+      for (path = reverse_path (binfo);
           path; 
           path = TREE_CHAIN (path))
        {
          for (method = TYPE_METHODS (BINFO_TYPE (TREE_VALUE (path)));
               method;
               method = TREE_CHAIN (method))
-           if (DECL_VIRTUAL_P (method) && overrides (method, ffod->fn))
+           if (DECL_VIRTUAL_P (method) 
+               && same_signature_p (method, ffod->fn))
              break;
 
          if (method)
@@ -2849,6 +2482,25 @@ dfs_find_final_overrider (binfo, data)
         the base from which it came.  */
       if (path)
        {
+         tree base;
+
+         /* Assume the path is non-virtual.  See if there are any
+            virtual bases from (but not including) the overrider up
+            to and including the base where the function is
+            defined. */
+         for (base = TREE_CHAIN (path); base; base = TREE_CHAIN (base))
+           if (TREE_VIA_VIRTUAL (TREE_VALUE (base)))
+             {
+               base = ffod->declaring_base;
+               while (BINFO_PRIMARY_MARKED_P (base))
+                 {
+                   BINFO_OVERRIDE_ALONG_VIRTUAL_PATH_P (base) = 1;
+                   base = BINFO_INHERITANCE_CHAIN (base);
+                 }
+               BINFO_OVERRIDE_ALONG_VIRTUAL_PATH_P (base) = 1;
+               break;
+             }
+
          if (ffod->overriding_fn && ffod->overriding_fn != method)
            {
              /* We've found a different overrider along a different
@@ -2945,53 +2597,124 @@ 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.  */
+/* 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.  */
 
-tree
-skip_rtti_stuff (binfo, t, n)
-     tree binfo;
+static void
+update_vtable_entry_for_fn (t, binfo, fn, virtuals)
      tree t;
-     unsigned HOST_WIDE_INT *n;
+     tree binfo;
+     tree fn;
+     tree *virtuals;
 {
-  tree virtuals;
+  tree b;
+  tree overrider;
+  tree delta;
+  tree virtual_base;
+  int generate_thunk_with_vtable_p;
+
+  /* Find the function which originally caused this vtable
+     entry to be present.  */
+  b = binfo;
+  while (1)
+    {
+      tree primary_base;
+      tree f;
 
-  if (CLASSTYPE_COM_INTERFACE (t))
-    return 0;
+      primary_base = get_primary_binfo (b);
+      if (!primary_base)
+       break;
 
-  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);
+      for (f = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (primary_base)));
+          f;
+          f = TREE_CHAIN (f))
+       if (same_signature_p (BV_FN (f), fn))
+         break;
+
+      if (!f)
+       break;
+
+      fn = BV_FN (f);
+      b = primary_base;
     }
-  if (flag_vtable_thunks && virtuals)
+
+  /* Find the final overrider.  */
+  overrider = find_final_overrider (t, b, fn);
+  if (overrider == error_mark_node)
+    return;
+
+  /* Compute the constant adjustment to the `this' pointer.  The
+     `this' pointer, when this function is called, will point at the
+     class whose vtable this is.  */
+  delta = size_binop (PLUS_EXPR,
+                     get_derived_offset (binfo,
+                                         DECL_VIRTUAL_CONTEXT (fn)),
+                     BINFO_OFFSET (binfo));
+
+  /* Assume that we will produce a thunk that convert all the way to
+     the final overrider, and not to an intermediate virtual base.  */
+  virtual_base = NULL_TREE;
+
+  /* Assume that we will always generate thunks with the vtables that
+     reference them.  */
+  generate_thunk_with_vtable_p = 1;
+
+  /* Under the new ABI, we will convert to an intermediate virtual
+     base first, and then use the vcall offset located there to finish
+     the conversion.  */
+  if (flag_new_abi)
     {
-      /* The second slot is reserved for the tdesc pointer when thunks
-         are used.  */
-      if (n)
-       ++*n;
-      virtuals = TREE_CHAIN (virtuals);
-    }
+      while (b)
+       {
+         /* If we find BINFO, then the final overrider is in a class
+            derived from BINFO, so the thunks can be generated with
+            the final overrider.  */
+         if (!virtual_base
+             && same_type_p (BINFO_TYPE (b), BINFO_TYPE (binfo)))
+           generate_thunk_with_vtable_p = 0;
+
+         /* If we find the final overrider, then we can stop
+            walking.  */
+         if (same_type_p (BINFO_TYPE (b), 
+                          BINFO_TYPE (TREE_VALUE (overrider))))
+           break;
 
-  return virtuals;
-}
+         /* If we find a virtual base, and we haven't yet found the
+            overrider, then there is a virtual base between the
+            declaring base and the final overrider.  */
+         if (!virtual_base && TREE_VIA_VIRTUAL (b))
+           {
+             generate_thunk_with_vtable_p = 1;
+             virtual_base = b;
+           }
 
-/* Called via dfs_walk.  Returns BINFO if BINFO has the same type as
-   DATA (which is really an _TYPE node).  */
+         b = BINFO_INHERITANCE_CHAIN (b);
+       }
+    }
+  else
+    virtual_base = NULL_TREE;
 
-static tree
-dfs_find_base (binfo, data)
-     tree binfo;
-     void *data;
-{
-  return (same_type_p (BINFO_TYPE (binfo), (tree) data)
-         ? binfo : NULL_TREE);
+  if (virtual_base)
+    /* The `this' pointer needs to be adjusted to the nearest virtual
+       base.  */
+    delta = size_diffop (BINFO_OFFSET (virtual_base), delta);
+  else
+    /* The `this' pointer needs to be adjusted from pointing to
+       BINFO to pointing at the base where the final overrider
+       appears.  */
+    delta = size_diffop (BINFO_OFFSET (TREE_VALUE (overrider)), delta);
+
+  modify_vtable_entry (t, 
+                      binfo, 
+                      TREE_PURPOSE (overrider),
+                      delta,
+                      virtuals);
+
+  if (virtual_base)
+    BV_USE_VCALL_INDEX_P (*virtuals) = 1;
+  if (generate_thunk_with_vtable_p)
+    BV_GENERATE_THUNK_WITH_VTABLE_P (*virtuals) = 1;
 }
 
 /* Called from modify_all_vtables via dfs_walk.  */
@@ -3022,59 +2745,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;
-         int i;
-
-         /* Find the function which originally caused this vtable
-            entry to be present.  */
-         fn = BV_FN (old_virtuals);
-         vindex = DECL_VINDEX (fn);
-         b = dfs_walk (binfo, dfs_find_base, NULL, DECL_VIRTUAL_CONTEXT (fn));
-         fn = skip_rtti_stuff (TYPE_BINFO (BINFO_TYPE (b)),
-                               BINFO_TYPE (b),
-                               &i);
-         while (i < TREE_INT_CST_LOW (vindex))
-           {
-             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 = ssize_binop (MINUS_EXPR,
-                              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);
@@ -3092,9 +2771,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;
@@ -3118,14 +2797,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;
@@ -3133,7 +2809,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.  */
@@ -3215,10 +2891,8 @@ mark_overriders (fndecl, base_fndecls)
      tree fndecl, base_fndecls;
 {
   for (; base_fndecls; base_fndecls = TREE_CHAIN (base_fndecls))
-    {
-      if (overrides (fndecl, TREE_VALUE (base_fndecls)))
-       TREE_PURPOSE (base_fndecls) = fndecl;
-    }
+    if (same_signature_p (fndecl, TREE_VALUE (base_fndecls)))
+      TREE_PURPOSE (base_fndecls) = fndecl;
 }
 
 /* If this declaration supersedes the declaration of
@@ -3240,8 +2914,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)
            {
@@ -3345,15 +3018,13 @@ warn_hidden (t)
       /* Now give a warning for all base functions without overriders,
         as they are hidden.  */
       for (; base_fndecls; base_fndecls = TREE_CHAIN (base_fndecls))
-       {
-         if (! overrides (TREE_PURPOSE (base_fndecls),
-                          TREE_VALUE (base_fndecls)))
-           {
-             /* Here we know it is a hider, and no overrider exists.  */
-             cp_warning_at ("`%D' was hidden", TREE_VALUE (base_fndecls));
-             cp_warning_at ("  by `%D'", TREE_PURPOSE (base_fndecls));
-           }
-       }
+       if (!same_signature_p (TREE_PURPOSE (base_fndecls),
+                              TREE_VALUE (base_fndecls)))
+         {
+           /* Here we know it is a hider, and no overrider exists.  */
+           cp_warning_at ("`%D' was hidden", TREE_VALUE (base_fndecls));
+           cp_warning_at ("  by `%D'", TREE_PURPOSE (base_fndecls));
+         }
     }
 }
 
@@ -3383,7 +3054,7 @@ finish_struct_anon (t)
                continue;
 
              if (DECL_NAME (elt) == constructor_name (t))
-               cp_pedwarn_at ("ANSI C++ forbids member `%D' with same name as enclosing class",
+               cp_pedwarn_at ("ISO C++ forbids member `%D' with same name as enclosing class",
                               elt);
 
              if (TREE_CODE (elt) != FIELD_DECL)
@@ -3407,41 +3078,38 @@ 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_NEEDS_DESTRUCTOR (t) && !TYPE_HAS_DESTRUCTOR (t))
+  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.  */
       if (default_fn == void_type_node)
-       TYPE_NEEDS_DESTRUCTOR (t) = 0;
+       TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = 0;
       else
        {
          TREE_CHAIN (default_fn) = implicit_fns;
@@ -3451,12 +3119,14 @@ add_implicitly_declared_members (t, cant_have_default_ctor,
            virtual_dtor = default_fn;
        }
     }
-  TYPE_NEEDS_DESTRUCTOR (t) |= TYPE_HAS_DESTRUCTOR (t);
+  else
+    /* Any non-implicit destructor is non-trivial.  */
+    TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) |= TYPE_HAS_DESTRUCTOR (t);
 
   /* 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;
     }
@@ -3466,8 +3136,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;
     }
@@ -3475,8 +3146,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;
     }
@@ -3484,7 +3156,7 @@ add_implicitly_declared_members (t, cant_have_default_ctor,
   /* Now, hook all of the new functions on to TYPE_METHODS,
      and add them to the CLASSTYPE_METHOD_VEC.  */
   for (f = &implicit_fns; *f; f = &TREE_CHAIN (*f))
-    add_method (t, 0, *f);
+    add_method (t, *f, /*error_p=*/0);
   *f = TYPE_METHODS (t);
   TYPE_METHODS (t) = implicit_fns;
 
@@ -3538,23 +3210,20 @@ check_bitfield_decl (field)
      tree field;
 {
   tree type = TREE_TYPE (field);
+  tree w = NULL_TREE;
 
-  /* Invalid bit-field size done by grokfield.  */
-  /* Detect invalid bit-field type. Simply checking if TYPE is
-     integral is insufficient, as that is the array core of the field
-     type. If TREE_TYPE (field) is integral, then TYPE must be the same.  */
+  /* Detect invalid bit-field type.  */
   if (DECL_INITIAL (field)
       && ! INTEGRAL_TYPE_P (TREE_TYPE (field)))
     {
       cp_error_at ("bit-field `%#D' with non-integral type", field);
-      DECL_INITIAL (field) = NULL;
+      w = error_mark_node;
     }
 
   /* Detect and ignore out of range field width.  */
   if (DECL_INITIAL (field))
     {
-      tree w = DECL_INITIAL (field);
-      register int width = 0;
+      w = DECL_INITIAL (field);
 
       /* Avoid the non_lvalue wrapper added by fold for PLUS_EXPRs.  */
       STRIP_NOPS (w);
@@ -3562,71 +3231,74 @@ 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)
        {
          cp_error_at ("bit-field `%D' width not an integer constant",
                       field);
-         DECL_INITIAL (field) = NULL_TREE;
+         w = error_mark_node;
        }
-      else if (width = TREE_INT_CST_LOW (w),
-              width < 0)
+      else if (tree_int_cst_sgn (w) < 0)
        {
-         DECL_INITIAL (field) = NULL;
          cp_error_at ("negative width in bit-field `%D'", field);
+         w = error_mark_node;
        }
-      else if (width == 0 && DECL_NAME (field) != 0)
+      else if (integer_zerop (w) && DECL_NAME (field) != 0)
        {
-         DECL_INITIAL (field) = NULL;
          cp_error_at ("zero width for bit-field `%D'", field);
+         w = error_mark_node;
        }
-      else if (width
-              > TYPE_PRECISION (long_long_unsigned_type_node))
-       {
-         /* The backend will dump if you try to use something too
-            big; avoid that.  */
-         DECL_INITIAL (field) = NULL;
-         sorry ("bit-fields larger than %d bits",
-                TYPE_PRECISION (long_long_unsigned_type_node));
-         cp_error_at ("  in declaration of `%D'", field);
-       }
-      else if (width > TYPE_PRECISION (type)
+      else if (compare_tree_int (w, TYPE_PRECISION (type)) > 0
               && TREE_CODE (type) != ENUMERAL_TYPE
               && TREE_CODE (type) != BOOLEAN_TYPE)
        cp_warning_at ("width of `%D' exceeds its type", field);
       else if (TREE_CODE (type) == ENUMERAL_TYPE
-              && ((min_precision (TYPE_MIN_VALUE (type),
-                                  TREE_UNSIGNED (type)) > width)
-                  || (min_precision (TYPE_MAX_VALUE (type),
-                                     TREE_UNSIGNED (type)) > width)))
+              && (0 > compare_tree_int (w,
+                                        min_precision (TYPE_MIN_VALUE (type),
+                                                       TREE_UNSIGNED (type)))
+                  ||  0 > compare_tree_int (w,
+                                            min_precision
+                                            (TYPE_MAX_VALUE (type),
+                                             TREE_UNSIGNED (type)))))
        cp_warning_at ("`%D' is too small to hold all values of `%#T'",
                       field, type);
+    }
+  
+  /* Remove the bit-field width indicator so that the rest of the
+     compiler does not treat that value as an initializer.  */
+  DECL_INITIAL (field) = NULL_TREE;
 
-      if (DECL_INITIAL (field))
-       {
-         DECL_INITIAL (field) = NULL_TREE;
-         DECL_FIELD_SIZE (field) = width;
-         DECL_BIT_FIELD (field) = 1;
+  if (w != error_mark_node)
+    {
+      DECL_SIZE (field) = convert (bitsizetype, w);
+      DECL_BIT_FIELD (field) = 1;
 
-         if (width == 0)
-           {
+      if (integer_zerop (w))
+       {
 #ifdef EMPTY_FIELD_BOUNDARY
-             DECL_ALIGN (field) = MAX (DECL_ALIGN (field), 
-                                       EMPTY_FIELD_BOUNDARY);
+         DECL_ALIGN (field) = MAX (DECL_ALIGN (field), 
+                                   EMPTY_FIELD_BOUNDARY);
 #endif
 #ifdef PCC_BITFIELD_TYPE_MATTERS
-             if (PCC_BITFIELD_TYPE_MATTERS)
-               DECL_ALIGN (field) = MAX (DECL_ALIGN (field), 
-                                         TYPE_ALIGN (type));
-#endif
+         if (PCC_BITFIELD_TYPE_MATTERS)
+           {
+             DECL_ALIGN (field) = MAX (DECL_ALIGN (field), 
+                                       TYPE_ALIGN (type));
+             DECL_USER_ALIGN (field) |= TYPE_USER_ALIGN (type);
            }
+#endif
        }
     }
   else
-    /* Non-bit-fields are aligned for their type.  */
-    DECL_ALIGN (field) = MAX (DECL_ALIGN (field), TYPE_ALIGN (type));
+    {
+      /* Non-bit-fields are aligned for their type.  */
+      DECL_BIT_FIELD (field) = 0;
+      CLEAR_DECL_C_BIT_FIELD (field);
+      DECL_ALIGN (field) = MAX (DECL_ALIGN (field), TYPE_ALIGN (type));
+      DECL_USER_ALIGN (field) |= TYPE_USER_ALIGN (type);
+    }
 }
 
 /* FIELD is a non bit-field.  We are finishing the processing for its
@@ -3657,7 +3329,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);
@@ -3675,7 +3347,7 @@ check_field_decl (field, t, cant_have_const_ctor,
          if (TYPE_NEEDS_CONSTRUCTING (type))
            cp_error_at ("member `%#D' with constructor not allowed in union",
                         field);
-         if (TYPE_NEEDS_DESTRUCTOR (type))
+         if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
            cp_error_at ("member `%#D' with destructor not allowed in union",
                         field);
          if (TYPE_HAS_COMPLEX_ASSIGN_REF (type))
@@ -3685,7 +3357,8 @@ check_field_decl (field, t, cant_have_const_ctor,
       else
        {
          TYPE_NEEDS_CONSTRUCTING (t) |= TYPE_NEEDS_CONSTRUCTING (type);
-         TYPE_NEEDS_DESTRUCTOR (t) |= TYPE_NEEDS_DESTRUCTOR (type);
+         TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) 
+           |= TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type);
          TYPE_HAS_COMPLEX_ASSIGN_REF (t) |= TYPE_HAS_COMPLEX_ASSIGN_REF (type);
          TYPE_HAS_COMPLEX_INIT_REF (t) |= TYPE_HAS_COMPLEX_INIT_REF (type);
        }
@@ -3715,6 +3388,8 @@ check_field_decl (field, t, cant_have_const_ctor,
                            (DECL_PACKED (field) 
                             ? BITS_PER_UNIT
                             : TYPE_ALIGN (TREE_TYPE (field))));
+  if (! DECL_PACKED (field))
+    DECL_USER_ALIGN (field) |= TYPE_USER_ALIGN (TREE_TYPE (field));
 }
 
 /* Check the data members (both static and non-static), class-scoped
@@ -3820,7 +3495,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))
@@ -3851,9 +3526,6 @@ check_field_decls (t, access_decls, empty_p,
       if (type == error_mark_node)
        continue;
          
-      DECL_SAVED_INSNS (x) = 0;
-      DECL_FIELD_SIZE (x) = 0;
-
       /* When this goes into scope, it will be a non-local reference.  */
       DECL_NONLOCAL (x) = 1;
 
@@ -3942,6 +3614,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))
@@ -4003,193 +3682,330 @@ 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_FIELD_SIZE (field) = 0;
   DECL_ALIGN (field) = TYPE_ALIGN (type);
+  DECL_USER_ALIGN (field) = TYPE_USER_ALIGN (type);
 
   /* Return it.  */
   return field;
 }
 
-/* If the empty base field in DECL overlaps with a base of the same type in
-   NEWDECL, which is either another base field or the first data field of
-   the class, pad the base just before NEWDECL and return 1.  Otherwise,
-   return 0.  */
+/* Record the type of BINFO in the slot in DATA (which is really a
+   `varray_type *') corresponding to the BINFO_OFFSET.  */
 
-static int
-avoid_overlap (decl, newdecl, empty_p)
-     tree decl, newdecl;
-     int *empty_p;
+static tree
+dfs_record_base_offsets (binfo, data)
+     tree binfo;
+     void *data;
 {
-  tree field;
+  varray_type *v;
+  unsigned HOST_WIDE_INT offset = tree_low_cst (BINFO_OFFSET (binfo), 1);
 
-  if (newdecl == NULL_TREE
-      || ! types_overlap_p (TREE_TYPE (decl), TREE_TYPE (newdecl)))
-    return 0;
+  v = (varray_type *) data;
+  while (VARRAY_SIZE (*v) <= offset)
+    VARRAY_GROW (*v, 2 * VARRAY_SIZE (*v));
+  VARRAY_TREE (*v, offset) = tree_cons (NULL_TREE,
+                                       BINFO_TYPE (binfo),
+                                       VARRAY_TREE (*v, offset));
 
-  for (field = decl; TREE_CHAIN (field) && TREE_CHAIN (field) != newdecl;
-       field = TREE_CHAIN (field))
-    ;
+  return NULL_TREE;
+}
 
-  DECL_SIZE (field) = bitsize_int (1);
-  DECL_SIZE_UNIT (field) = 0;
-  /* The containing class cannot be empty; this field takes up space.  */
-  *empty_p = 0;
+/* Add the offset of BINFO and its bases to BASE_OFFSETS.  */
 
-  return 1;
+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);
 }
 
-/* Build a FIELD_DECL for the base given by BINFO in T.  If the new
-   object is non-empty, clear *EMPTY_P.  Otherwise, set *SAW_EMPTY_P.
-   *BASE_ALIGN is a running maximum of the alignments of any base
-   class.  */
+/* 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.  */
 
 static tree
-build_base_field (t, binfo, empty_p, saw_empty_p, base_align)
-     tree t;
+dfs_search_base_offsets (binfo, data)
      tree binfo;
-     int *empty_p;
-     int *saw_empty_p;
-     unsigned int *base_align;
+     void *data;
 {
-  tree basetype = BINFO_TYPE (binfo);
-  tree decl;
+  if (is_empty_class (BINFO_TYPE (binfo)))
+    {
+      varray_type v = (varray_type) data;
+      /* Find the offset for this BINFO.  */
+      unsigned HOST_WIDE_INT offset = tree_low_cst (BINFO_OFFSET (binfo), 1);
+      tree t;
 
-  if (TYPE_SIZE (basetype) == 0)
-    /* This error is now reported in xref_tag, thus giving better
-       location information.  */
-    return NULL_TREE;
+      /* If we haven't yet encountered any objects at offsets that
+        big, then there's no conflict.  */
+      if (VARRAY_SIZE (v) <= offset)
+       return NULL_TREE;
+      /* Otherwise, go through the objects already allocated at this
+        offset.  */
+      for (t = VARRAY_TREE (v, offset); t; t = TREE_CHAIN (t))
+       if (same_type_p (TREE_VALUE (t), BINFO_TYPE (binfo)))
+         return binfo;
+    }
+
+  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
+   non-static data-member, a dummy BINFO for the type of the data
+   member.  BINFO may be NULL if checks to see if the field overlaps
+   an existing field with the same type are not required.  V maps
+   offsets to types already located at those offsets.  This function
+   determines the position of the DECL.  */
+
+static void
+layout_nonempty_base_or_field (rli, decl, binfo, v)
+     record_layout_info rli;
+     tree decl;
+     tree binfo;
+     varray_type v;
+{
+  /* Try to place the field.  It may take more than one try if we have
+     a hard time placing the field without putting two objects of the
+     same type at the same address.  */
+  while (1)
+    {
+      tree offset;
+      struct record_layout_info_s old_rli = *rli;
+
+      /* Place this field.  */
+      place_field (rli, decl);
+      
+      /* Now that we know where it wil be placed, update its
+        BINFO_OFFSET.  */
+      offset = byte_position (decl);
+      if (binfo && CLASS_TYPE_P (BINFO_TYPE (binfo)))
+       propagate_binfo_offsets (binfo, 
+                                convert (ssizetype, offset));
+      /* We have to check to see whether or not there is already
+        something of the same type at the offset we're about to use.
+        For example:
+        
+        struct S {};
+        struct T : public S { int i; };
+        struct U : public S, public T {};
+        
+        Here, we put S at offset zero in U.  Then, we can't put T at
+        offset zero -- its S component would be at the same address
+        as the S we already allocated.  So, we have to skip ahead.
+        Since all data members, including those whose type is an
+        empty class, have non-zero size, any overlap can happen only
+        with a direct or indirect base-class -- it can't happen with
+        a data member.  */
+      if (binfo && flag_new_abi && layout_conflict_p (binfo, v))
+       {
+         /* Undo the propagate_binfo_offsets call.  */
+         offset = size_diffop (size_zero_node, offset);
+         propagate_binfo_offsets (binfo, convert (ssizetype, offset));
+        
+         /* Strip off the size allocated to this field.  That puts us
+            at the first place we could have put the field with
+            proper alignment.  */
+         *rli = old_rli;
+
+         /* Bump up by the alignment required for the type, without
+            virtual base classes.  */
+         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.  */
+       break;
+    }
+}
+
+/* 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.
+   *BASE_ALIGN is a running maximum of the alignments of any base
+   class.  */
+
+static void
+build_base_field (rli, binfo, empty_p, base_align, v)
+     record_layout_info rli;
+     tree binfo;
+     int *empty_p;
+     unsigned int *base_align;
+     varray_type *v;
+{
+  tree basetype = BINFO_TYPE (binfo);
+  tree decl;
+
+  if (!COMPLETE_TYPE_P (basetype))
+    /* This error is now reported in xref_tag, thus giving better
+       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) = t;
+  DECL_FIELD_CONTEXT (decl) = rli->t;
   DECL_SIZE (decl) = CLASSTYPE_SIZE (basetype);
   DECL_SIZE_UNIT (decl) = CLASSTYPE_SIZE_UNIT (basetype);
   DECL_ALIGN (decl) = CLASSTYPE_ALIGN (basetype);
+  DECL_USER_ALIGN (decl) = CLASSTYPE_USER_ALIGN (basetype);
   
-  if (flag_new_abi && integer_zerop (DECL_SIZE (decl)))
-    {
-      *saw_empty_p = 1;
-      return decl;
-    }
-
-  /* The containing class is non-empty because it has a non-empty base
-     class.  */
-  *empty_p = 0;
-      
   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_int (MAX (TREE_INT_CST_LOW (DECL_SIZE (decl)),
-                        (int) (*base_align)));
+       = size_binop (MAX_EXPR, DECL_SIZE (decl), bitsize_int (*base_align));
       DECL_SIZE_UNIT (decl)
-       = size_int (MAX (TREE_INT_CST_LOW (DECL_SIZE_UNIT (decl)),
-                        (int) *base_align / BITS_PER_UNIT));
+       = size_binop (MAX_EXPR, DECL_SIZE_UNIT (decl),
+                     size_int (*base_align / BITS_PER_UNIT));
     }
 
-  return decl;
+  if (!integer_zerop (DECL_SIZE (decl)))
+    {
+      /* The containing class is non-empty because it has a non-empty
+        base class.  */
+      *empty_p = 0;
+
+      /* Try to place the field.  It may take more than one try if we
+        have a hard time placing the field without putting two
+        objects of the same type at the same address.  */
+      layout_nonempty_base_or_field (rli, decl, binfo, *v);
+    }
+  else
+    {
+      unsigned HOST_WIDE_INT eoc;
+
+      /* 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
+     it's ambiguous.  */
+  if (get_base_distance (basetype, rli->t, 0, NULL) == -2)
+    cp_warning ("direct base `%T' inaccessible in `%T' due to ambiguity",
+               basetype, rli->t);
+  
+  /* Record the offsets of BINFO and its base subobjects.  */
+  record_base_offsets (binfo, v);
 }
 
-/* Returns a list of fields to stand in for the base class subobjects
-   of REC.  These fields are later removed by layout_basetypes.  */
+/* Layout all of the non-virtual base classes.  Returns a map from
+   offsets to types present at those offsets.  */
 
-static tree
-build_base_fields (rec, empty_p)
-     tree rec;
+static varray_type
+build_base_fields (rli, empty_p)
+     record_layout_info rli;
      int *empty_p;
 {
   /* Chain to hold all the new FIELD_DECLs which stand in for base class
      subobjects.  */
-  tree base_decls = NULL_TREE;
+  tree rec = rli->t;
   int n_baseclasses = CLASSTYPE_N_BASECLASSES (rec);
-  tree decl, nextdecl;
-  int i, saw_empty = 0;
+  int i;
+  varray_type v;
   unsigned int base_align = 0;
 
+  /* Create the table mapping offsets to empty base classes.  */
+  VARRAY_TREE_INIT (v, 32, "v");
+
   /* Under the new ABI, the primary base class is always allocated
      first.  */
   if (flag_new_abi && CLASSTYPE_HAS_PRIMARY_BASE_P (rec))
-    {
-      tree primary_base;
-
-      primary_base = CLASSTYPE_PRIMARY_BINFO (rec);
-      base_decls = chainon (build_base_field (rec, 
-                                             primary_base,
-                                             empty_p,
-                                             &saw_empty,
-                                             &base_align),
-                           base_decls);
-    }
+    build_base_field (rli, CLASSTYPE_PRIMARY_BINFO (rec), 
+                     empty_p, &base_align, &v);
 
   /* Now allocate the rest of the bases.  */
   for (i = 0; i < n_baseclasses; ++i)
     {
       tree base_binfo;
 
+      base_binfo = BINFO_BASETYPE (TYPE_BINFO (rec), i);
+
       /* Under the new ABI, the primary base was already allocated
         above, so we don't need to allocate it again here.  */
-      if (flag_new_abi && i == CLASSTYPE_VFIELD_PARENT (rec))
+      if (flag_new_abi && base_binfo == CLASSTYPE_PRIMARY_BINFO (rec))
        continue;
 
-      base_binfo = BINFO_BASETYPE (TYPE_BINFO (rec), i);
-
       /* A primary virtual base class is allocated just like any other
         base class, but a non-primary virtual base is allocated
-        later, in layout_basetypes.  */
+        later, in layout_virtual_bases.  */
       if (TREE_VIA_VIRTUAL (base_binfo) 
          && !BINFO_PRIMARY_MARKED_P (base_binfo))
        continue;
 
-      base_decls = chainon (build_base_field (rec, base_binfo,
-                                             empty_p,
-                                             &saw_empty,
-                                             &base_align),
-                           base_decls);
+      build_base_field (rli, base_binfo, empty_p, &base_align, &v);
     }
 
-  /* Reverse the list of fields so we allocate the bases in the proper
-     order.  */
-  base_decls = nreverse (base_decls);
-
-  /* In the presence of empty base classes, we run the risk of allocating
-     two objects of the same class on top of one another.  Avoid that.  */
-  if (flag_new_abi && saw_empty)
-    for (decl = base_decls; decl; decl = TREE_CHAIN (decl))
-      {
-       if (integer_zerop (DECL_SIZE (decl)))
-         {
-           /* First step through the following bases until we find
-              an overlap or a non-empty base.  */
-           for (nextdecl = TREE_CHAIN (decl); nextdecl;
-                nextdecl = TREE_CHAIN (nextdecl))
-             if (avoid_overlap (decl, nextdecl, empty_p)
-                 || ! integer_zerop (DECL_SIZE (nextdecl)))
-               goto nextbase;
-
-           /* If we're still looking, also check against the first
-              field.  */
-           for (nextdecl = TYPE_FIELDS (rec);
-                nextdecl && TREE_CODE (nextdecl) != FIELD_DECL;
-                nextdecl = TREE_CHAIN (nextdecl))
-             /* keep looking */;
-           avoid_overlap (decl, nextdecl, empty_p);
-         }
-      nextbase:;
-      }
-
-  return base_decls;
+  return v;
 }
 
 /* Go through the TYPE_METHODS of T issuing any appropriate
@@ -4201,6 +4017,7 @@ check_methods (t)
      tree t;
 {
   tree x;
+  int seen_one_arg_array_delete_p = 0;
 
   for (x = TYPE_METHODS (t); x; x = TREE_CHAIN (x))
     {
@@ -4210,13 +4027,6 @@ check_methods (t)
       if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (x)))
        continue;
 
-      /* Do both of these, even though they're in the same union;
-        if the insn `r' member and the size `i' member are
-        different sizes, as on the alpha, the larger of the two
-        will end up with garbage in it.  */
-      DECL_SAVED_INSNS (x) = 0;
-      DECL_FIELD_SIZE (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);
@@ -4230,9 +4040,230 @@ check_methods (t)
            CLASSTYPE_PURE_VIRTUALS (t)
              = tree_cons (NULL_TREE, x, CLASSTYPE_PURE_VIRTUALS (t));
        }
+
+      if (DECL_ARRAY_DELETE_OPERATOR_P (x))
+       {
+         tree second_parm;
+
+         /* When dynamically allocating an array of this type, we
+            need a "cookie" to record how many elements we allocated,
+            even if the array elements have no non-trivial
+            destructor, if the usual array deallocation function
+            takes a second argument of type size_t.  The standard (in
+            [class.free]) requires that the second argument be set
+            correctly.  */
+         second_parm = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (x)));
+         /* This is overly conservative, but we must maintain this
+            behavior for backwards compatibility.  */
+         if (!flag_new_abi && second_parm != void_list_node)
+           TYPE_VEC_DELETE_TAKES_SIZE (t) = 1;
+         /* Under the new ABI, we choose only those function that are
+            explicitly declared as `operator delete[] (void *,
+            size_t)'.  */
+         else if (flag_new_abi 
+                  && !seen_one_arg_array_delete_p
+                  && second_parm
+                  && TREE_CHAIN (second_parm) == void_list_node
+                  && same_type_p (TREE_VALUE (second_parm), sizetype))
+           TYPE_VEC_DELETE_TAKES_SIZE (t) = 1;
+         /* If there's no second parameter, then this is the usual
+            deallocation function.  */
+         else if (second_parm == void_list_node)
+           seen_one_arg_array_delete_p = 1;
+       }
+    }
+}
+
+/* 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), clone, /*error_p=*/0);
+      clone = build_clone (fn, base_ctor_identifier);
+      if (update_method_vec_p)
+       add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
+    }
+  else
+    {
+      my_friendly_assert (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn), 20000411);
+
+      /* For each destructor, we need three variants: an in-charge
+        version, a not-in-charge version, and an in-charge deleting
+        version.  We clone the deleting version first because that
+        means it will go second on the TYPE_METHODS list -- and that
+        corresponds to the correct layout order in the virtual
+        function table.  */
+      clone = build_clone (fn, deleting_dtor_identifier);
+      if (update_method_vec_p)
+       add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
+      clone = build_clone (fn, complete_dtor_identifier);
+      if (update_method_vec_p)
+       add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
+      clone = build_clone (fn, base_dtor_identifier);
+      if (update_method_vec_p)
+       add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
     }
 }
 
+/* For each of the constructors and destructors in T, create an
+   in-charge and not-in-charge variant.  */
+
+static void
+clone_constructors_and_destructors (t)
+     tree t;
+{
+  tree fns;
+
+  /* We only clone constructors and destructors under the new ABI.  */
+  if (!flag_new_abi)
+    return;
+
+  /* If for some reason we don't have a CLASSTYPE_METHOD_VEC, we bail
+     out now.  */
+  if (!CLASSTYPE_METHOD_VEC (t))
+    return;
+
+  for (fns = CLASSTYPE_CONSTRUCTORS (t); fns; fns = OVL_NEXT (fns))
+    clone_function_decl (OVL_CURRENT (fns), /*update_method_vec_p=*/1);
+  for (fns = CLASSTYPE_DESTRUCTORS (t); fns; fns = OVL_NEXT (fns))
+    clone_function_decl (OVL_CURRENT (fns), /*update_method_vec_p=*/1);
+}
+
 /* Remove all zero-width bit-fields from T.  */
 
 static void
@@ -4328,29 +4359,30 @@ 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);
+
   /* Build and sort the CLASSTYPE_METHOD_VEC.  */
   finish_struct_methods (t);
-
-  /* Process the access-declarations.  We wait until now to do this
-     because handle_using_decls requires that the CLASSTYPE_METHOD_VEC
-     be set up correctly.  */
-  while (access_decls)
-    {
-      handle_using_decl (TREE_VALUE (access_decls), t);
-      access_decls = TREE_CHAIN (access_decls);
-    }
 }
 
 /* If T needs a pointer to its virtual function table, set TYPE_VFIELD
-   accordingly, and, if necessary, add the TYPE_VFIELD to the
-   TYPE_FIELDS list.  */
+   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 caller's
+   responsibility to do that.  */
 
-static void
-create_vtable_ptr (t, empty_p, has_virtual_p, 
+static tree
+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;
 {
@@ -4359,19 +4391,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
@@ -4400,29 +4431,17 @@ create_vtable_ptr (t, empty_p, has_virtual_p,
                                     t,
                                     empty_p);
 
-      /* Add the new field to the list of fields in this class.  */
-      if (!flag_new_abi)
-       /* In the old ABI, the vtable pointer goes at the end of the
-          class.  */
-       TYPE_FIELDS (t) = chainon (TYPE_FIELDS (t), TYPE_VFIELD (t));
-      else
-       {
-         /* But in the new ABI, the vtable pointer is the first thing
-            in the class.  */
-         TYPE_FIELDS (t) = chainon (TYPE_VFIELD (t), TYPE_FIELDS (t));
-         /* If there were any baseclasses, they can't possibly be at
-            offset zero any more, because that's where the vtable
-            pointer is.  So, converting to a base class is going to
-            take work.  */
-         if (CLASSTYPE_N_BASECLASSES (t))
-           TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (t) = 1;
-       }
+      if (flag_new_abi && CLASSTYPE_N_BASECLASSES (t))
+       /* If there were any baseclasses, they can't possibly be at
+          offset zero any more, because that's where the vtable
+          pointer is.  So, converting to a base class is going to
+          take work.  */
+       TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (t) = 1;
 
-      /* We can't yet add this new field to the list of all virtual
-        function table pointers in this class.  The
-        modify_all_vtables function depends on this not being done.
-        So, it is done later, in finish_struct_1.  */
+      return TYPE_VFIELD (t);
     }
+
+  return NULL_TREE;
 }
 
 /* Fixup the inline function given by INFO now that the class is
@@ -4477,143 +4496,60 @@ fixup_inline_methods (type)
   CLASSTYPE_INLINE_FRIENDS (type) = NULL_TREE;
 }
 
-/* Called from propagate_binfo_offsets via dfs_walk.  */
-
-static tree
-dfs_propagate_binfo_offsets (binfo, data)
-     tree binfo; 
-     void *data;
-{
-  tree offset = (tree) data;
-
-  /* Update the BINFO_OFFSET for this base.  */
-  BINFO_OFFSET (binfo) 
-    = size_binop (PLUS_EXPR, BINFO_OFFSET (binfo), offset);
-
-  SET_BINFO_MARKED (binfo);
-
-  return NULL_TREE;
-}
-
 /* Add OFFSET to all base types of BINFO which is a base in the
    hierarchy dominated by T.
 
-   OFFSET, which is a type offset, is number of bytes.
-
-   Note that we don't have to worry about having two paths to the
-   same base type, since this type owns its association list.  */
+   OFFSET, which is a type offset, is number of bytes.  */
 
 static void
 propagate_binfo_offsets (binfo, offset)
      tree binfo;
      tree offset;
 {
-  dfs_walk (binfo, 
-           dfs_propagate_binfo_offsets, 
-           dfs_skip_nonprimary_vbases_unmarkedp,
-           offset);
-  dfs_walk (binfo,
-           dfs_unmark,
-           dfs_skip_nonprimary_vbases_markedp,
-           NULL);
-}
-
-/* Remove *FIELD (which corresponds to the base given by BINFO) from
-   the field list for T.  */
-
-static void
-remove_base_field (t, binfo, field)
-     tree t;
-     tree binfo;
-     tree *field;
-{
-  tree basetype = BINFO_TYPE (binfo);
-  tree offset;
-
-  my_friendly_assert (TREE_TYPE (*field) == basetype, 23897);
-
-  if (get_base_distance (basetype, t, 0, (tree*)0) == -2)
-    cp_warning ("direct base `%T' inaccessible in `%T' due to ambiguity",
-               basetype, t);
-
-  offset
-    = size_int (CEIL (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (*field)),
-                     BITS_PER_UNIT));
-  propagate_binfo_offsets (binfo, offset);
-
-  /* Remove this field.  */
-  *field = TREE_CHAIN (*field);
-}
-
-/* Remove the FIELD_DECLs created for T's base classes in
-   build_base_fields.  Simultaneously, update BINFO_OFFSET for all the
-   bases, except for non-primary virtual baseclasses.  */
-
-static void
-remove_base_fields (t)
-     tree t;
-{
   int i;
-  tree *field;
+  tree primary_binfo;
 
-  /* Now propagate offset information throughout the lattice.
-     Simultaneously, remove the temporary FIELD_DECLS we created in
-     build_base_fields to refer to base types.  */
-  field = &TYPE_FIELDS (t);
-  if (TYPE_VFIELD (t) == *field)
-    {
-      /* If this class did not have a primary base, we create a
-        virtual function table pointer.  It will be the first thing
-        in the class, under the new ABI.  Skip it; the base fields
-        will follow it.  */
-      my_friendly_assert (flag_new_abi 
-                         && !CLASSTYPE_HAS_PRIMARY_BASE_P (t),
-                         19991218);
-      field = &TREE_CHAIN (*field);
-    }
+  /* Update BINFO's offset.  */
+  BINFO_OFFSET (binfo)
+    = convert (sizetype, 
+              size_binop (PLUS_EXPR,
+                          convert (ssizetype, BINFO_OFFSET (binfo)),
+                          offset));
 
-  /* Under the new ABI, the primary base is always allocated first.  */
-  if (flag_new_abi && CLASSTYPE_HAS_PRIMARY_BASE_P (t))
-    remove_base_field (t, CLASSTYPE_PRIMARY_BINFO (t), field);
+  /* Find the primary base class.  */
+  primary_binfo = get_primary_binfo (binfo);
 
-  /* Now remove the rest of the bases.  */
-  for (i = 0; i < CLASSTYPE_N_BASECLASSES (t); i++)
+  /* Scan all of the bases, pushing the BINFO_OFFSET adjust
+     downwards.  */
+  for (i = -1; i < BINFO_N_BASETYPES (binfo); ++i)
     {
-      tree binfo;
+      tree base_binfo;
 
-      /* Under the new ABI, we've already removed the primary base
-        above.  */
-      if (flag_new_abi && i == CLASSTYPE_VFIELD_PARENT (t))
-       continue;
+      /* On the first through the loop, do the primary base.  Because
+        the primary base need not be an immediate base, we must
+        handle the primary base specially.  */
+      if (i == -1) 
+       {
+         if (!primary_binfo) 
+           continue;
 
-      binfo = BINFO_BASETYPE (TYPE_BINFO (t), i);
+         base_binfo = primary_binfo;
+       }
+      else
+       {
+         base_binfo = BINFO_BASETYPE (binfo, i);
+         /* Don't do the primary base twice.  */
+         if (base_binfo == primary_binfo)
+           continue;
+       }
 
-      /* We treat a primary virtual base class just like an ordinary base
-        class.  But, non-primary virtual bases are laid out later.  */
-      if (TREE_VIA_VIRTUAL (binfo) && !BINFO_PRIMARY_MARKED_P (binfo))
+      /* Skip virtual bases that aren't our primary base.  */
+      if (TREE_VIA_VIRTUAL (base_binfo)
+         && BINFO_PRIMARY_BASE_OF (base_binfo) != binfo)
        continue;
 
-      remove_base_field (t, binfo, field);
-    }
-}
-
-/* Called via dfs_walk from layout_virtual bases.  */
-
-static tree
-dfs_set_offset_for_shared_vbases (binfo, data)
-     tree binfo;
-     void *data;
-{
-  if (TREE_VIA_VIRTUAL (binfo) && BINFO_PRIMARY_MARKED_P (binfo))
-    {
-      /* Update the shared copy.  */
-      tree shared_binfo;
-
-      shared_binfo = BINFO_FOR_VBASE (BINFO_TYPE (binfo), (tree) data);
-      BINFO_OFFSET (shared_binfo) = BINFO_OFFSET (binfo);
+      propagate_binfo_offsets (base_binfo, offset);
     }
-
-  return NULL_TREE;
 }
 
 /* Called via dfs_walk from layout_virtual bases.  */
@@ -4632,10 +4568,8 @@ dfs_set_offset_for_unshared_vbases (binfo, data)
       tree vbase;
       tree offset;
       
-      vbase = BINFO_FOR_VBASE (BINFO_TYPE (binfo), t);
-      offset = ssize_binop (MINUS_EXPR, 
-                           BINFO_OFFSET (vbase),
-                           BINFO_OFFSET (binfo));
+      vbase = binfo_for_vbase (BINFO_TYPE (binfo), t);
+      offset = size_diffop (BINFO_OFFSET (vbase), BINFO_OFFSET (binfo));
       propagate_binfo_offsets (binfo, offset);
     }
 
@@ -4643,114 +4577,175 @@ 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;
-  int dsize;
+  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_INT_CST_LOW (TYPE_SIZE (t));
+  dsize = tree_low_cst (TYPE_SIZE (t), 1);
+
   /* Make every class have alignment of at least one.  */
   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_INT_CST_LOW (CLASSTYPE_SIZE (basetype)));
-      }
+     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;
 
-  /* Make sure that all of the CLASSTYPE_VBASECLASSES have their
-     BINFO_OFFSET set correctly.  Those we just allocated certainly
-     will.  The others are primary baseclasses; we walk the hierarchy
-     to find the primary copies and update the shared copy.  */
-  dfs_walk (TYPE_BINFO (t), 
-           dfs_set_offset_for_shared_vbases, 
-           dfs_unmarked_real_bases_queue_p,
-           t);
+      if (flag_new_abi)
+       {
+         if (!TREE_VIA_VIRTUAL (vbases))
+           continue;
+         vbase = binfo_for_vbase (BINFO_TYPE (vbases), t);
+       }
+      else
+       vbase = TREE_VALUE (vbases);
 
-  /* Now, go through the TYPE_BINFO hierarchy again, setting the
-     BINFO_OFFSETs correctly for all non-primary copies of the virtual
-     bases and their direct and indirect bases.  The ambiguity checks
-     in get_base_distance depend on the BINFO_OFFSETs being set
-     correctly.  */
-  dfs_walk (TYPE_BINFO (t), dfs_set_offset_for_unshared_vbases, NULL, t);
-  for (vbase = CLASSTYPE_VBASECLASSES (t);
-       vbase;
-       vbase = TREE_CHAIN (vbase))
-    dfs_walk (vbase, dfs_set_offset_for_unshared_vbases, NULL, t);
+      if (!BINFO_PRIMARY_MARKED_P (vbase))
+       {
+         /* This virtual base is not a primary base of any class in the
+            hierarchy, so we have to add space for it.  */
+         tree basetype;
+         unsigned int desired_align;
 
-  /* Now, make sure that the total size of the type is a multiple of
+         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);
+       }
+    }
+
+  /* Now, go through the TYPE_BINFO hierarchy, setting the
+     BINFO_OFFSETs correctly for all non-primary copies of the virtual
+     bases and their direct and indirect bases.  The ambiguity checks
+     in get_base_distance depend on the BINFO_OFFSETs being set
+     correctly.  */
+  dfs_walk (TYPE_BINFO (t), dfs_set_offset_for_unshared_vbases, NULL, t);
+
+  /* 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) = size_int (dsize);
-  TYPE_SIZE_UNIT (t) = size_binop (FLOOR_DIV_EXPR, TYPE_SIZE (t),
-                                  size_int (BITS_PER_UNIT));
+  TYPE_SIZE (t) = bitsize_int (dsize);
+  TYPE_SIZE_UNIT (t) = convert (sizetype,
+                               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;
 
-#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
+  for (i = 0; i < CLASSTYPE_N_BASECLASSES (t); ++i)
+    {
+      tree base_binfo;
+      tree offset;
+      unsigned HOST_WIDE_INT end_of_base;
 
-  /* Remove the FIELD_DECLs we created for baseclasses in
-     build_base_fields.  Simultaneously, update the BINFO_OFFSETs for
-     everything in the hierarcy except non-primary virtual bases.  */
-  remove_base_fields (rec);
-
-  /* Allocate the virtual base classes.  */
-  layout_virtual_bases (rec);
-
-  /* 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);
-      }
+      base_binfo = BINFO_BASETYPE (TYPE_BINFO (t), i);
+
+      if (!include_virtuals_p
+         && TREE_VIA_VIRTUAL (base_binfo) 
+         && !BINFO_PRIMARY_MARKED_P (base_binfo))
+       continue;
+
+      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
@@ -4758,72 +4753,178 @@ 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;
 {
-  tree padding = NULL_TREE;
+  tree non_static_data_members;
+  tree field;
+  tree vptr;
+  record_layout_info rli;
+  varray_type v;
+  unsigned HOST_WIDE_INT eoc;
+
+  /* Keep track of the first non-static data member.  */
+  non_static_data_members = TYPE_FIELDS (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, vfuns_p,
+                           new_virtuals_p, overridden_virtuals_p);
+
+  /* Under the new ABI, the vptr is always the first thing in the
+     class.  */
+  if (flag_new_abi && vptr)
+    {
+      TYPE_FIELDS (t) = chainon (vptr, TYPE_FIELDS (t));
+      place_field (rli, vptr);
+    }
 
-  /* Add pointers to all of our virtual base-classes.  */
-  TYPE_FIELDS (t) = chainon (build_vbase_pointer_fields (t, empty_p),
-                            TYPE_FIELDS (t));
   /* Build FIELD_DECLs for all of the non-virtual base-types.  */
-  TYPE_FIELDS (t) = chainon (build_base_fields (t, empty_p), 
+  v = build_base_fields (rli, empty_p);
+  /* Add pointers to all of our virtual base-classes.  */
+  TYPE_FIELDS (t) = chainon (build_vbase_pointer_fields (rli, empty_p),
                             TYPE_FIELDS (t));
 
-  /* Create a pointer to our virtual function table.  */
-  create_vtable_ptr (t, empty_p, has_virtual_p,
-                    new_virtuals_p, overridden_virtuals_p);
-
   /* CLASSTYPE_INLINE_FRIENDS is really TYPE_NONCOPIED_PARTS.  Thus,
      we have to save this before we start modifying
      TYPE_NONCOPIED_PARTS.  */
   fixup_inline_methods (t);
 
+  /* Layout the non-static data members.  */
+  for (field = non_static_data_members; field; field = TREE_CHAIN (field))
+    {
+      tree binfo;
+      tree type;
+      tree padding;
+
+      /* We still pass things that aren't non-static data members to
+        the back-end, in case it wants to do something with them.  */
+      if (TREE_CODE (field) != FIELD_DECL)
+       {
+         place_field (rli, field);
+         continue;
+       }
+
+      type = TREE_TYPE (field);
+
+      /* If this field is a bit-field whose width is greater than its
+        type, then there are some special rules for allocating it
+        under the new ABI.  Under the old ABI, there were no special
+        rules, but the back-end can't handle bitfields longer than a
+        `long long', so we use the same mechanism.  */
+      if (DECL_C_BIT_FIELD (field)
+         && ((flag_new_abi 
+              && INT_CST_LT (TYPE_SIZE (type), DECL_SIZE (field)))
+             || (!flag_new_abi
+                 && 0 < compare_tree_int (DECL_SIZE (field),
+                                          TYPE_PRECISION
+                                          (long_long_unsigned_type_node)))))
+       {
+         integer_type_kind itk;
+         tree integer_type;
+
+         /* We must allocate the bits as if suitably aligned for the
+            longest integer type that fits in this many bits.  type
+            of the field.  Then, we are supposed to use the left over
+            bits as additional padding.  */
+         for (itk = itk_char; itk != itk_none; ++itk)
+           if (INT_CST_LT (DECL_SIZE (field), 
+                           TYPE_SIZE (integer_types[itk])))
+             break;
+
+         /* ITK now indicates a type that is too large for the
+            field.  We have to back up by one to find the largest
+            type that fits.  */
+         integer_type = integer_types[itk - 1];
+         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);
+         DECL_USER_ALIGN (field) = TYPE_USER_ALIGN (integer_type);
+       }
+      else
+       padding = NULL_TREE;
+
+      /* Create a dummy BINFO corresponding to this field.  */
+      binfo = make_binfo (size_zero_node, type, NULL_TREE, NULL_TREE);
+      unshare_base_binfos (binfo);
+      layout_nonempty_base_or_field (rli, field, binfo, v);
+
+      /* If we needed additional padding after this field, add it
+        now.  */
+      if (padding)
+       {
+         tree padding_field;
+
+         padding_field = build_decl (FIELD_DECL, 
+                                     NULL_TREE,
+                                     char_type_node); 
+         DECL_BIT_FIELD (padding_field) = 1;
+         DECL_SIZE (padding_field) = padding;
+         DECL_ALIGN (padding_field) = 1;
+         DECL_USER_ALIGN (padding_field) = 0;
+         layout_nonempty_base_or_field (rli, padding_field, NULL_TREE, v);
+       }
+    }
+
+  /* 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.  */
+  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)
+    {
+      /* 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
-     have non-zero size.  The field that we add here is fake, in the
-     sense that, for example, we don't want people to be able to
-     initialize it later.  So, we add it just long enough to let the
-     back-end lay out the type, and then remove it.  In the new ABI,
-     the class may be empty even if it has basetypes.  Therefore, we
-     add the fake field at the end of the fields list; if there are
-     already FIELD_DECLs on the list, their offsets will not be
-     disturbed.  */
+     have non-zero size.  In the new ABI, the class may be empty even
+     if it has basetypes.  Therefore, we add the fake field after all
+     the other fields; if there are already FIELD_DECLs on the list,
+     their offsets will not be disturbed.  */
   if (*empty_p)
     {
-      padding = build_lang_decl (FIELD_DECL, NULL_TREE, char_type_node);
-      TYPE_FIELDS (t) = chainon (TYPE_FIELDS (t), padding);
+      tree 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;
     }
 
+  /* Under the old ABI, the vptr comes at the very end of the 
+     class.   */
+  if (!flag_new_abi && vptr)
+    {
+      place_field (rli, vptr);
+      TYPE_FIELDS (t) = chainon (TYPE_FIELDS (t), vptr);
+    }
+  
   /* Let the back-end lay out the type. Note that at this point we
      have only included non-virtual base-classes; we will lay out the
      virtual base classes later.  So, the TYPE_SIZE/TYPE_ALIGN after
      this call are not necessarily correct; they are just the size and
      alignment when no virtual base clases are used.  */
-  layout_type (t);
-
-  /* If we added an extra field to make this class non-empty, remove
-     it now.  */
-  if (*empty_p)
-    {
-      tree *declp;
-
-      declp = &TYPE_FIELDS (t);
-      while (*declp != padding)
-       declp = &TREE_CHAIN (*declp);
-      *declp = TREE_CHAIN (*declp);
-    }
+  finish_record_layout (rli);
 
   /* Delete all zero-width bit-fields from the list of fields.  Now
      that the type is laid out they are no longer important.  */
@@ -4833,11 +4934,10 @@ 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_UNIT (t) = size_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)
-          && TYPE_HAS_COMPLEX_ASSIGN_REF (t))
+  else if (flag_new_abi)
     {
       CLASSTYPE_SIZE (t) = TYPE_BINFO_SIZE (t);
       CLASSTYPE_SIZE_UNIT (t) = TYPE_BINFO_SIZE_UNIT (t);
@@ -4849,6 +4949,7 @@ layout_class_type (t, empty_p, has_virtual_p,
     }
 
   CLASSTYPE_ALIGN (t) = TYPE_ALIGN (t);
+  CLASSTYPE_USER_ALIGN (t) = TYPE_USER_ALIGN (t);
 
   /* Set the TYPE_DECL for this type to contain the right
      value for DECL_OFFSET, so that we can use it as part
@@ -4857,19 +4958,21 @@ layout_class_type (t, empty_p, has_virtual_p,
 
   /* Now fix up any virtual base class types that we left lying
      around.  We must get these done before we try to lay out the
-     virtual function table.  */
-  if (CLASSTYPE_N_BASECLASSES (t))
-    /* layout_basetypes will remove the base subobject fields.  */
-    layout_basetypes (t);
+     virtual function table.  As a side-effect, this will remove the
+     base subobject fields.  */
+  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).
 
    For C++, we must handle the building of derived classes.
    Also, C++ allows static class members.  The way that this is
    handled is to keep the field name where it is (as the DECL_NAME
-   of the field), and place the overloaded decl in the DECL_FIELD_BITPOS
+   of the field), and place the overloaded decl in the bit position
    of the field.  layout_record and layout_union will know about this.
 
    More C++ hair: inline functions have text in their
@@ -4895,7 +4998,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
@@ -4909,7 +5012,7 @@ finish_struct_1 (t)
   tree vfield;
   int empty = 1;
 
-  if (TYPE_SIZE (t))
+  if (COMPLETE_TYPE_P (t))
     {
       if (IS_AGGR_TYPE (t))
        cp_error ("redefinition of `%#T'", t);
@@ -4925,8 +5028,8 @@ finish_struct_1 (t)
      make sure we lay it out again.  */
   TYPE_SIZE (t) = NULL_TREE;
   CLASSTYPE_GOT_SEMICOLON (t) = 0;
-  CLASSTYPE_VFIELD_PARENT (t) = -1;
-  has_virtual = 0;
+  CLASSTYPE_PRIMARY_BINFO (t) = NULL_TREE;
+  vfuns = 0;
   CLASSTYPE_RTTI (t) = NULL_TREE;
 
   /* Do end-of-class semantic processing: checking the validity of the
@@ -4934,7 +5037,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
@@ -4945,21 +5048,25 @@ finish_struct_1 (t)
       && DECL_FIELD_CONTEXT (vfield) != t)
     {
       tree binfo = get_binfo (DECL_FIELD_CONTEXT (vfield), t, 0);
-      tree offset = BINFO_OFFSET (binfo);
 
-      vfield = copy_node (vfield);
-      copy_lang_decl (vfield);
+      vfield = copy_decl (vfield);
 
-      if (! integer_zerop (offset))
-       offset = size_binop (MULT_EXPR, offset, size_int (BITS_PER_UNIT));
       DECL_FIELD_CONTEXT (vfield) = t;
-      DECL_FIELD_BITPOS (vfield)
-       = size_binop (PLUS_EXPR, offset, DECL_FIELD_BITPOS (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
@@ -4969,23 +5076,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);
@@ -5003,17 +5095,9 @@ finish_struct_1 (t)
     {
       tree binfo = CLASSTYPE_PRIMARY_BINFO (t);
 
-      /* This class contributes nothing new to the virtual function
-        table.  However, it may have declared functions which
-        went into the virtual function table "inherited" from the
-        base class.  If so, we grab a copy of those updated functions,
-        and pretend they are ours.  */
-
-      /* See if we should steal the virtual info from base class.  */
-      if (TYPE_BINFO_VTABLE (t) == NULL_TREE)
-       TYPE_BINFO_VTABLE (t) = BINFO_VTABLE (binfo);
-      if (TYPE_BINFO_VIRTUALS (t) == NULL_TREE)
-       TYPE_BINFO_VIRTUALS (t) = BINFO_VIRTUALS (binfo);
+      /* If this class uses a different vtable than its primary base
+        then when we will need to initialize our vptr after the base
+        class constructor runs.  */
       if (TYPE_BINFO_VTABLE (t) != BINFO_VTABLE (binfo))
        CLASSTYPE_NEEDS_VIRTUAL_REINIT (t) = 1;
     }
@@ -5027,7 +5111,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) 
@@ -5038,16 +5122,6 @@ finish_struct_1 (t)
        = chainon (TYPE_BINFO_VIRTUALS (t), overridden_virtuals);
     }
 
-  /* Now lay out the virtual function table.  */
-  if (has_virtual)
-    layout_vtable_decl (TYPE_BINFO (t), has_virtual);
-
-  /* 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
@@ -5097,7 +5171,13 @@ finish_struct_1 (t)
        }
     }
 
-  if (CLASSTYPE_VSIZE (t) != 0)
+  /* 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 (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
@@ -5112,9 +5192,6 @@ finish_struct_1 (t)
                    t);
     }
 
-  /* Make the rtl for any new vtables we have created, and unmark
-     the base types we marked.  */
-  finish_vtbls (t);
   hack_incomplete_structures (t);
 
   if (warn_overloaded_virtual)
@@ -5123,7 +5200,7 @@ finish_struct_1 (t)
   maybe_suppress_debug_info (t);
 
   /* Finish debugging output for this type.  */
-  rest_of_type_compilation (t, toplevel_bindings_p ());
+  rest_of_type_compilation (t, ! LOCAL_CLASS_P (t));
 }
 
 /* When T was built up, the member declarations were added in reverse
@@ -5174,7 +5251,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);
@@ -5325,7 +5402,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
@@ -5337,15 +5414,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
@@ -5420,7 +5499,7 @@ pushclass (type, modify)
 
   if (previous_class_type != NULL_TREE
       && (type != previous_class_type 
-         || TYPE_SIZE (previous_class_type) == NULL_TREE)
+         || !COMPLETE_TYPE_P (previous_class_type))
       && current_class_depth == 1)
     {
       /* Forcibly remove any old class remnants.  */
@@ -5605,29 +5684,26 @@ push_lang_context (name)
 
   if (name == lang_name_cplusplus)
     {
-      strict_prototype = strict_prototypes_lang_cplusplus;
       current_lang_name = name;
     }
   else if (name == lang_name_java)
     {
-      strict_prototype = strict_prototypes_lang_cplusplus;
       current_lang_name = name;
       /* DECL_IGNORED_P is initially set for these types, to avoid clutter.
         (See record_builtin_java_type in decl.c.)  However, that causes
         incorrect debug entries if these types are actually used.
         So we re-enable debug output after extern "Java". */
-      DECL_IGNORED_P (java_byte_type_node) = 0;
-      DECL_IGNORED_P (java_short_type_node) = 0;
-      DECL_IGNORED_P (java_int_type_node) = 0;
-      DECL_IGNORED_P (java_long_type_node) = 0;
-      DECL_IGNORED_P (java_float_type_node) = 0;
-      DECL_IGNORED_P (java_double_type_node) = 0;
-      DECL_IGNORED_P (java_char_type_node) = 0;
-      DECL_IGNORED_P (java_boolean_type_node) = 0;
+      DECL_IGNORED_P (TYPE_NAME (java_byte_type_node)) = 0;
+      DECL_IGNORED_P (TYPE_NAME (java_short_type_node)) = 0;
+      DECL_IGNORED_P (TYPE_NAME (java_int_type_node)) = 0;
+      DECL_IGNORED_P (TYPE_NAME (java_long_type_node)) = 0;
+      DECL_IGNORED_P (TYPE_NAME (java_float_type_node)) = 0;
+      DECL_IGNORED_P (TYPE_NAME (java_double_type_node)) = 0;
+      DECL_IGNORED_P (TYPE_NAME (java_char_type_node)) = 0;
+      DECL_IGNORED_P (TYPE_NAME (java_boolean_type_node)) = 0;
     }
   else if (name == lang_name_c)
     {
-      strict_prototype = strict_prototypes_lang_c;
       current_lang_name = name;
     }
   else
@@ -5643,11 +5719,6 @@ pop_lang_context ()
      to it.  */
   *current_lang_stack = NULL_TREE;
   current_lang_name = *--current_lang_stack;
-  if (current_lang_name == lang_name_cplusplus
-      || current_lang_name == lang_name_java)
-    strict_prototype = strict_prototypes_lang_cplusplus;
-  else if (current_lang_name == lang_name_c)
-    strict_prototype = strict_prototypes_lang_c;
 }
 \f
 /* Type instantiation routines.  */
@@ -5655,19 +5726,22 @@ pop_lang_context ()
 /* Given an OVERLOAD and a TARGET_TYPE, return the function that
    matches the TARGET_TYPE.  If there is no satisfactory match, return
    error_mark_node, and issue an error message if COMPLAIN is
-   non-zero.  If TEMPLATE_ONLY, the name of the overloaded function
+   non-zero.  Permit pointers to member function if PTRMEM is non-zero.
+   If TEMPLATE_ONLY, the name of the overloaded function
    was a template-id, and EXPLICIT_TARGS are the explicitly provided
    template arguments.  */
 
 static tree
 resolve_address_of_overloaded_function (target_type, 
                                        overload,
-                                       complain, 
+                                       complain,
+                                       ptrmem,
                                        template_only,
                                        explicit_targs)
      tree target_type;
      tree overload;
      int complain;
+     int ptrmem;
      int template_only;
      tree explicit_targs;
 {
@@ -5712,6 +5786,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.  */
@@ -5776,6 +5853,7 @@ resolve_address_of_overloaded_function (target_type,
     {
       tree target_fn_type;
       tree target_arg_types;
+      tree target_ret_type;
       tree fns;
 
       if (is_ptrmem)
@@ -5784,6 +5862,7 @@ resolve_address_of_overloaded_function (target_type,
       else
        target_fn_type = TREE_TYPE (target_type);
       target_arg_types = TYPE_ARG_TYPES (target_fn_type);
+      target_ret_type = TREE_TYPE (target_fn_type);
          
       for (fns = overload; fns; fns = OVL_CHAIN (fns))
        {
@@ -5805,7 +5884,7 @@ resolve_address_of_overloaded_function (target_type,
          /* Try to do argument deduction.  */
          targs = make_tree_vec (DECL_NTPARMS (fn));
          if (fn_type_unification (fn, explicit_targs, targs,
-                                  target_arg_types, NULL_TREE,
+                                  target_arg_types, target_ret_type,
                                   DEDUCE_EXACT) != 0)
            /* Argument deduction failed.  */
            continue;
@@ -5885,6 +5964,14 @@ resolve_address_of_overloaded_function (target_type,
   /* Good, exactly one match.  Now, convert it to the correct type.  */
   fn = TREE_PURPOSE (matches);
 
+  if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE
+      && !ptrmem && !flag_ms_extensions)
+    {
+      if (!complain)
+        return error_mark_node;
+
+      cp_pedwarn ("assuming pointer to member `%D'", fn);
+    }
   mark_used (fn);
 
   if (TYPE_PTRFN_P (target_type) || TYPE_PTRMEMFUNC_P (target_type))
@@ -5902,24 +5989,26 @@ resolve_address_of_overloaded_function (target_type,
 
 /* This function will instantiate the type of the expression given in
    RHS to match the type of LHSTYPE.  If errors exist, then return
-   error_mark_node.  We only complain is COMPLAIN is set.  If we are
-   not complaining, never modify rhs, as overload resolution wants to
-   try many possible instantiations, in hopes that at least one will
-   work.
-
-   FLAGS is a bitmask, as we see at the top of the function.
-
+   error_mark_node. FLAGS is a bit mask.  If ITF_COMPLAIN is set, then
+   we complain on errors.  If we are not complaining, never modify rhs,
+   as overload resolution wants to try many possible instantiations, in
+   the hope that at least one will work.
+   
    For non-recursive calls, LHSTYPE should be a function, pointer to
    function, or a pointer to member function.  */
 
 tree
 instantiate_type (lhstype, rhs, flags)
      tree lhstype, rhs;
-     int flags;
+     enum instantiate_type_flags flags;
 {
-  int complain = (flags & 1);
-  int strict = (flags & 2) ? COMPARE_NO_ATTRIBUTES : COMPARE_STRICT;
-
+  int complain = (flags & itf_complain);
+  int strict = (flags & itf_no_attributes)
+               ? COMPARE_NO_ATTRIBUTES : COMPARE_STRICT;
+  int allow_ptrmem = flags & itf_ptrmem_ok;
+  
+  flags &= ~itf_ptrmem_ok;
+  
   if (TREE_CODE (lhstype) == UNKNOWN_TYPE)
     {
       if (complain)
@@ -5978,35 +6067,13 @@ instantiate_type (lhstype, rhs, flags)
       return instantiate_type (lhstype, rhs, flags);
 
     case COMPONENT_REF:
-      {
-       tree r = instantiate_type (lhstype, TREE_OPERAND (rhs, 1), flags);
-
-       if (r != error_mark_node && TYPE_PTRMEMFUNC_P (lhstype)
-           && complain && !flag_ms_extensions)
-         {
-           /* Note: we check this after the recursive call to avoid
-              complaining about cases where overload resolution fails.  */
-
-           tree t = TREE_TYPE (TREE_OPERAND (rhs, 0));
-           tree fn = PTRMEM_CST_MEMBER (r);
-
-           my_friendly_assert (TREE_CODE (r) == PTRMEM_CST, 990811);
-
-           cp_pedwarn
-             ("object-dependent reference to `%E' can only be used in a call",
-              DECL_NAME (fn));
-           cp_pedwarn
-             ("  to form a pointer to member function, say `&%T::%E'",
-              t, DECL_NAME (fn));
-         }
-
-       return r;
-      }
+      return instantiate_type (lhstype, TREE_OPERAND (rhs, 1), flags);
 
     case OFFSET_REF:
       rhs = TREE_OPERAND (rhs, 1);
       if (BASELINK_P (rhs))
-       return instantiate_type (lhstype, TREE_VALUE (rhs), flags);
+       return instantiate_type (lhstype, TREE_VALUE (rhs),
+                                flags | allow_ptrmem);
 
       /* This can happen if we are forming a pointer-to-member for a
         member template.  */
@@ -6015,18 +6082,25 @@ instantiate_type (lhstype, rhs, flags)
       /* Fall through.  */
 
     case TEMPLATE_ID_EXPR:
-      return 
-       resolve_address_of_overloaded_function (lhstype,
-                                               TREE_OPERAND (rhs, 0),
-                                               complain,
-                                               /*template_only=*/1,
-                                               TREE_OPERAND (rhs, 1));
+      {
+       tree fns = TREE_OPERAND (rhs, 0);
+       tree args = TREE_OPERAND (rhs, 1);
+
+       return
+         resolve_address_of_overloaded_function (lhstype,
+                                                 fns,
+                                                 complain,
+                                                 allow_ptrmem,
+                                                 /*template_only=*/1,
+                                                 args);
+      }
 
     case OVERLOAD:
       return 
        resolve_address_of_overloaded_function (lhstype, 
                                                rhs,
                                                complain,
+                                               allow_ptrmem,
                                                /*template_only=*/0,
                                                /*explicit_targs=*/NULL_TREE);
 
@@ -6138,8 +6212,12 @@ instantiate_type (lhstype, rhs, flags)
       return rhs;
       
     case ADDR_EXPR:
+    {
+      if (PTRMEM_OK_P (rhs))
+        flags |= itf_ptrmem_ok;
+      
       return instantiate_type (lhstype, TREE_OPERAND (rhs, 0), flags);
-
+    }
     case ENTRY_VALUE_EXPR:
       my_friendly_abort (184);
       return error_mark_node;
@@ -6349,17 +6427,104 @@ note_name_declared_in_class (name, decl)
         S.  */
       cp_error ("declaration of `%#D'", decl);
       cp_error_at ("changes meaning of `%s' from `%+#D'", 
-                  IDENTIFIER_POINTER (DECL_NAME (decl)),
+                  IDENTIFIER_POINTER (DECL_NAME (OVL_CURRENT (decl))),
                   (tree) n->value);
     }
 }
 
-/* Dump the offsets of all the bases rooted at BINFO to stderr.
-   INDENT should be zero when called from the top level; it is
-   incremented recursively.  */
+/* Returns the VAR_DECL for the complete vtable associated with
+   BINFO.  (Under the new ABI, secondary vtables are merged with
+   primary vtables; this function will return the VAR_DECL for the
+   primary vtable.)  */
 
-void
-dump_class_hierarchy (binfo, indent)
+tree
+get_vtbl_decl_for_binfo (binfo)
+     tree binfo;
+{
+  tree decl;
+
+  decl = BINFO_VTABLE (binfo);
+  if (decl && TREE_CODE (decl) == PLUS_EXPR)
+    {
+      my_friendly_assert (TREE_CODE (TREE_OPERAND (decl, 0)) == ADDR_EXPR,
+                         2000403);
+      decl = TREE_OPERAND (TREE_OPERAND (decl, 0), 0);
+    }
+  if (decl)
+    my_friendly_assert (TREE_CODE (decl) == VAR_DECL, 20000403);
+  return decl;
+}
+
+/* Called from get_primary_binfo via dfs_walk.  */
+
+static tree
+dfs_get_primary_binfo (binfo, data)
+     tree binfo;
+     void *data;
+{
+  tree primary_base = (tree) data;
+
+  if (TREE_VIA_VIRTUAL (binfo) 
+      && same_type_p (TREE_TYPE (binfo), TREE_TYPE (primary_base)))
+    return binfo;
+  
+  return NULL_TREE;
+}
+
+/* Returns the binfo for the primary base of BINFO.  Note that in a
+   complex hierarchy the resulting BINFO may not actually *be*
+   primary.  In particular if the resulting BINFO is a virtual base,
+   and it occurs elsewhere in the hierarchy, then this occurrence may
+   not actually be a primary base in the complete object.  Check
+   BINFO_PRIMARY_MARKED_P to be sure.  */
+
+tree
+get_primary_binfo (binfo)
+     tree binfo;
+{
+  tree primary_base;
+  tree result;
+
+  primary_base = CLASSTYPE_PRIMARY_BINFO (BINFO_TYPE (binfo));
+  if (!primary_base)
+    return NULL_TREE;
+
+  /* A non-virtual primary base is always a direct base, and easy to
+     find.  */
+  if (!TREE_VIA_VIRTUAL (primary_base))
+    {
+      int i;
+
+      /* Scan the direct basetypes until we find a base with the same
+        type as the primary base.  */
+      for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
+       {
+         tree base_binfo = BINFO_BASETYPE (binfo, i);
+         
+         if (same_type_p (BINFO_TYPE (base_binfo),
+                          BINFO_TYPE (primary_base)))
+           return base_binfo;
+       }
+
+      /* We should always find the primary base.  */
+      my_friendly_abort (20000729);
+    }
+
+  /* For a primary virtual base, we have to scan the entire hierarchy
+     rooted at BINFO; the virtual base could be an indirect virtual
+     base.  */
+  result = dfs_walk (binfo, dfs_get_primary_binfo, NULL, primary_base);
+  my_friendly_assert (result != NULL_TREE, 20000730);
+  return result;
+}
+
+/* Dump the offsets of all the bases rooted at BINFO (in the hierarchy
+   dominated by T) to stderr.  INDENT should be zero when called from
+   the top level; it is incremented recursively.  */
+
+static void
+dump_class_hierarchy_r (t, binfo, indent)
+     tree t;
      tree binfo;
      int indent;
 {
@@ -6369,10 +6534,1106 @@ dump_class_hierarchy (binfo, indent)
           (unsigned long) binfo,
           type_as_string (binfo, TS_PLAIN));
   fprintf (stderr, HOST_WIDE_INT_PRINT_DEC,
-          TREE_INT_CST_LOW (BINFO_OFFSET (binfo)));
-  fprintf (stderr, " %s\n",
-          BINFO_PRIMARY_MARKED_P (binfo) ? "primary" : "");
+          tree_low_cst (BINFO_OFFSET (binfo), 0));
+  if (TREE_VIA_VIRTUAL (binfo))
+    fprintf (stderr, " virtual");
+  if (BINFO_PRIMARY_MARKED_P (binfo)
+      || (TREE_VIA_VIRTUAL (binfo) 
+         && BINFO_PRIMARY_MARKED_P (binfo_for_vbase (BINFO_TYPE (binfo), 
+                                                     t))))
+    fprintf (stderr, " primary");
+  fprintf (stderr, "\n");
 
   for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
-    dump_class_hierarchy (BINFO_BASETYPE (binfo, i), indent + 2);
+    dump_class_hierarchy_r (t, BINFO_BASETYPE (binfo, i), indent + 2);
+}
+
+/* Dump the BINFO hierarchy for T.  */
+
+void
+dump_class_hierarchy (t)
+     tree t;
+{
+  dump_class_hierarchy_r (t, TYPE_BINFO (t), 0);
+}
+
+/* Virtual function table initialization.  */
+
+/* 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, /*virtual_vtts_p=*/1, 
+                  &inits, &index);
+
+  /* If we didn't need a VTT, we're done.  */
+  if (!inits)
+    return;
+
+  /* Figure out the type of the VTT.  */
+  type = build_index_type (size_int (list_length (inits)));
+  type = build_cplus_array_type (const_ptr_type_node, type);
+                                
+  /* Now, build the VTT object itself.  */
+  vtt = build_vtable (t, get_vtt_name (t), type);
+  pushdecl_top_level (vtt);
+  initialize_array (vtt, inits);
+}
+
+/* The type corresponding to BINFO is a base class of T, but BINFO is
+   in the base class hierarchy of a class derived from T.  Return the
+   base, in T's hierarchy, that corresponds to BINFO.  */
+
+static tree
+get_matching_base (binfo, t)
+     tree binfo;
+     tree t;
+{
+  tree derived;
+  int i;
+
+  if (same_type_p (BINFO_TYPE (binfo), t))
+    return binfo;
+
+  if (TREE_VIA_VIRTUAL (binfo))
+    return binfo_for_vbase (BINFO_TYPE (binfo), t);
+
+  derived = get_matching_base (BINFO_INHERITANCE_CHAIN (binfo), t);
+  for (i = 0; i < BINFO_N_BASETYPES (derived); ++i)
+    if (same_type_p (BINFO_TYPE (BINFO_BASETYPE (derived, i)),
+                    BINFO_TYPE (binfo)))
+      return BINFO_BASETYPE (derived, i);
+
+  my_friendly_abort (20000628);
+  return NULL_TREE;
+}
+
+/* Recursively build the VTT-initializer for BINFO (which is in the
+   hierarchy dominated by T).  If VIRTUAL_VTTS_P is non-zero, then
+   sub-VTTs for virtual bases are included.  INITS points to the end
+   of the initializer list to date.  INDEX is the VTT index where the
+   next element will be placed.  */
+
+static tree *
+build_vtt_inits (binfo, t, virtual_vtts_p, inits, index)
+     tree binfo;
+     tree t;
+     int virtual_vtts_p;
+     tree *inits;
+     tree *index;
+{
+  int i;
+  tree b;
+  tree init;
+  tree secondary_vptrs;
+  int ctor_vtbl_p;
+
+  /* We only need VTTs for subobjects with virtual bases.  */
+  if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo)))
+    return inits;
+
+  /* We need to use a construction vtable if this is not the primary
+     VTT.  */
+  ctor_vtbl_p = !same_type_p (TREE_TYPE (binfo), t);
+  if (ctor_vtbl_p)
+    {
+      build_ctor_vtbl_group (binfo, t);
+
+      /* Record the offset in the VTT where this sub-VTT can be found.  */
+      BINFO_SUBVTT_INDEX (binfo) = *index;
+    }
+
+  /* Add the address of the primary vtable for the complete object.  */
+  init = BINFO_VTABLE (binfo);
+  if (TREE_CODE (init) == TREE_LIST)
+    init = TREE_VALUE (init);
+  *inits = build_tree_list (NULL_TREE, init);
+  inits = &TREE_CHAIN (*inits);
+  BINFO_VPTR_INDEX (binfo) = *index;
+  *index = size_binop (PLUS_EXPR, *index, TYPE_SIZE_UNIT (ptr_type_node));
+                      
+  /* Recursively add the secondary VTTs for non-virtual bases.  */
+  for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
+    {
+      b = BINFO_BASETYPE (binfo, i);
+      if (!TREE_VIA_VIRTUAL (b))
+       inits = build_vtt_inits (BINFO_BASETYPE (binfo, i), t, 
+                                /*virtuals_vtts_p=*/0,
+                                inits, index);
+    }
+      
+  /* Add secondary virtual pointers for all subobjects of BINFO with
+     either virtual bases or virtual functions overridden along a
+     virtual path between the declaration and D, except subobjects
+     that are non-virtual primary bases.  */
+  secondary_vptrs = tree_cons (t, NULL_TREE, BINFO_TYPE (binfo));
+  TREE_TYPE (secondary_vptrs) = *index;
+  dfs_walk_real (binfo,
+                dfs_build_secondary_vptr_vtt_inits,
+                NULL,
+                dfs_unmarked_real_bases_queue_p,
+                secondary_vptrs);
+  dfs_walk (binfo, dfs_unmark, dfs_marked_real_bases_queue_p, t);
+  *index = TREE_TYPE (secondary_vptrs);
+
+  /* The secondary vptrs come back in reverse order.  After we reverse
+     them, and add the INITS, the last init will be the first element
+     of the chain.  */
+  secondary_vptrs = TREE_VALUE (secondary_vptrs);
+  if (secondary_vptrs)
+    {
+      *inits = nreverse (secondary_vptrs);
+      inits = &TREE_CHAIN (secondary_vptrs);
+      my_friendly_assert (*inits == NULL_TREE, 20000517);
+    }
+
+  /* Add the secondary VTTs for virtual bases.  */
+  if (virtual_vtts_p)
+    for (b = TYPE_BINFO (BINFO_TYPE (binfo)); b; b = TREE_CHAIN (b))
+      {
+       tree vbase;
+       
+       if (!TREE_VIA_VIRTUAL (b))
+         continue;
+       
+       vbase = binfo_for_vbase (BINFO_TYPE (b), t);
+       inits = build_vtt_inits (vbase, t, /*virtual_vtts_p=*/0, 
+                                inits, index);
+      }
+
+  dfs_walk (binfo, dfs_fixup_binfo_vtbls,
+           dfs_unmarked_real_bases_queue_p,
+           build_tree_list (t, binfo));
+
+  return inits;
+}
+
+/* Called from build_vtt_inits via dfs_walk.  */
+
+static tree
+dfs_build_secondary_vptr_vtt_inits (binfo, data)
+     tree binfo;
+     void *data;
+{
+  tree l; 
+  tree t;
+  tree init;
+  tree index;
+
+  l = (tree) data;
+  t = TREE_CHAIN (l);
+
+  SET_BINFO_MARKED (binfo);
+
+  /* We don't care about bases that don't have vtables.  */
+  if (!TYPE_VFIELD (BINFO_TYPE (binfo)))
+    return NULL_TREE;
+
+  /* We're only interested in proper subobjects of T.  */
+  if (same_type_p (BINFO_TYPE (binfo), t))
+    return NULL_TREE;
+
+  /* We're not interested in non-virtual primary bases.  */
+  if (!TREE_VIA_VIRTUAL (binfo) && BINFO_PRIMARY_MARKED_P (binfo))
+    return NULL_TREE;
+
+  /* If BINFO doesn't have virtual bases, then we have to look to see
+     whether or not any virtual functions were overidden along a
+     virtual path.  The point is that given:
+
+       struct V { virtual void f(); int i; };
+       struct C : public virtual V { void f (); };
+
+     when we constrct C we need a secondary vptr for V-in-C because we
+     don't know what the vcall offset for `f' should be.  If `V' ends
+     up in a different place in the complete object, then we'll need a
+     different vcall offset than that present in the normal V-in-C
+     vtable.  */
+  if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo))
+      && !BINFO_OVERRIDE_ALONG_VIRTUAL_PATH_P (get_matching_base (binfo, t)))
+    return NULL_TREE;
+
+  /* Record the index where this secondary vptr can be found.  */
+  index = TREE_TYPE (l);
+  BINFO_VPTR_INDEX (binfo) = index;
+  TREE_TYPE (l) = size_binop (PLUS_EXPR, index, 
+                             TYPE_SIZE_UNIT (ptr_type_node));
+
+  /* Add the initializer for the secondary vptr itself.  */
+  init = BINFO_VTABLE (binfo);
+  if (TREE_CODE (init) == TREE_LIST)
+    init = TREE_VALUE (init);
+  TREE_VALUE (l) = tree_cons (NULL_TREE, init, TREE_VALUE (l));
+
+  return NULL_TREE;
+}
+
+/* Called from build_vtt_inits via dfs_walk.  */
+
+static tree
+dfs_fixup_binfo_vtbls (binfo, data)
+     tree binfo;
+     void *data;
+{
+  CLEAR_BINFO_MARKED (binfo);
+
+  /* We don't care about bases that don't have vtables.  */
+  if (!TYPE_VFIELD (BINFO_TYPE (binfo)))
+    return NULL_TREE;
+
+  /* If we scribbled the construction vtable vptr into BINFO, clear it
+     out now.  */
+  if (TREE_CODE (BINFO_VTABLE (binfo)) == TREE_LIST
+      && (TREE_PURPOSE (BINFO_VTABLE (binfo)) 
+         == TREE_VALUE ((tree) data)))
+    BINFO_VTABLE (binfo) = TREE_CHAIN (BINFO_VTABLE (binfo));
+
+  return NULL_TREE;
+}
+
+/* Build the construction vtable group for BINFO which is in the
+   hierarchy dominated by T.  */
+
+static void
+build_ctor_vtbl_group (binfo, t)
+     tree binfo;
+     tree t;
+{
+  tree list;
+  tree type;
+  tree vtbl;
+  tree inits;
+  tree id;
+  tree vbase;
+
+  /* See if we've already create this construction vtable group.  */
+  if (flag_new_abi)
+    id = mangle_ctor_vtbl_for_type (t, binfo);
+  else
+    id = get_ctor_vtbl_name (t, binfo);
+  if (IDENTIFIER_GLOBAL_VALUE (id))
+    return;
+
+  /* Build a version of VTBL (with the wrong type) for use in
+     constructing the addresses of secondary vtables in the
+     construction vtable group.  */
+  vtbl = build_vtable (t, id, ptr_type_node);
+  list = build_tree_list (vtbl, NULL_TREE);
+  accumulate_vtbl_inits (binfo, TYPE_BINFO (TREE_TYPE (binfo)),
+                        binfo, t, list);
+  for (vbase = TYPE_BINFO (TREE_TYPE (binfo)); 
+       vbase; 
+       vbase = TREE_CHAIN (vbase))
+    {
+      tree b;
+
+      if (!TREE_VIA_VIRTUAL (vbase))
+       continue;
+
+      b = binfo_for_vbase (BINFO_TYPE (vbase), t);
+      accumulate_vtbl_inits (b, vbase, binfo, t, list);
+    }
+
+  inits = TREE_VALUE (list);
+
+  /* Figure out the type of the construction vtable.  */
+  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))
+      && !(BINFO_OVERRIDE_ALONG_VIRTUAL_PATH_P 
+          (get_matching_base (binfo, BINFO_TYPE (rtti_binfo)))))
+    return;
+
+  /* Build the initializers for the BINFO-in-T vtable.  */
+  TREE_VALUE (inits) 
+    = chainon (TREE_VALUE (inits),
+              dfs_accumulate_vtbl_inits (binfo, orig_binfo,
+                                         rtti_binfo, t, inits));
+                     
+  /* Walk the BINFO and its bases.  We walk in preorder so that as we
+     initialize each vtable we can figure out at what offset the
+     secondary vtable lies from the primary vtable.  We can't use
+     dfs_walk here because we need to iterate through bases of BINFO
+     and RTTI_BINFO simultaneously.  */
+  for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
+    {
+      tree base_binfo;
+
+      base_binfo = BINFO_BASETYPE (binfo, i);
+      /* Skip virtual bases.  */
+      if (TREE_VIA_VIRTUAL (base_binfo))
+       continue;
+      accumulate_vtbl_inits (base_binfo,
+                            BINFO_BASETYPE (orig_binfo, i),
+                            rtti_binfo,
+                            t,
+                            inits);
+    }
+}
+
+/* Called from finish_vtbls via dfs_walk when using the new ABI.
+   Accumulates the vtable initializers for all of the vtables into
+   TREE_VALUE (DATA).  Returns the initializers for the BINFO vtable.  */
+
+static tree
+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;
+
+  if (BINFO_NEW_VTABLE_MARKED (orig_binfo, t))
+    {
+      tree vtbl;
+      tree index;
+      int non_fn_entries;
+
+      /* Compute the initializer for this vtable.  */
+      inits = build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo,
+                                     &non_fn_entries);
+
+      /* Figure out the position to which the VPTR should point.  */
+      vtbl = TREE_PURPOSE (l);
+      vtbl = build1 (ADDR_EXPR, 
+                    vtbl_ptr_type_node,
+                    vtbl);
+      index = size_binop (PLUS_EXPR,
+                         size_int (non_fn_entries),
+                         size_int (list_length (TREE_VALUE (l))));
+      index = size_binop (MULT_EXPR,
+                         TYPE_SIZE_UNIT (vtable_entry_type),
+                         index);
+      vtbl = build (PLUS_EXPR, TREE_TYPE (vtbl), vtbl, index);
+      TREE_CONSTANT (vtbl) = 1;
+
+      /* For an ordinary vtable, set BINFO_VTABLE.  */
+      if (same_type_p (BINFO_TYPE (rtti_binfo), t))
+       BINFO_VTABLE (binfo) = vtbl;
+      /* For a construction vtable, we can't overwrite BINFO_VTABLE.
+        So, we make a TREE_LIST.  Later, dfs_fixup_binfo_vtbls will
+        straighten this out.  */
+      else
+       BINFO_VTABLE (binfo) = 
+         tree_cons (rtti_binfo, vtbl, BINFO_VTABLE (binfo));
+    }
+
+  return inits;
+}
+
+/* Construct the initializer for BINFOs virtual function table.  BINFO
+   is part of the hierarchy dominated by T.  If we're building a
+   construction vtable, the ORIG_BINFO is the binfo we should use to
+   find the actual function pointers to put in the vtable.  Otherwise,
+   ORIG_BINFO should be the same as BINFO.  The RTTI_BINFO is the
+   BINFO that should be indicated by the RTTI information in the
+   vtable; it will be a base class of T, rather than T itself, if we
+   are building a construction vtable.
+
+   The value returned is a TREE_LIST suitable for wrapping in a
+   CONSTRUCTOR to use as the DECL_INITIAL for a vtable.  If
+   NON_FN_ENTRIES_P is not NULL, *NON_FN_ENTRIES_P is set to the
+   number of non-function entries in the vtable.  
+
+   It might seem that this function should never be called with a
+   BINFO for which BINFO_PRIMARY_MARKED_P holds, the vtable for such a
+   base is always subsumed by a derived class vtable.  However, when
+   we are building construction vtables we do build vtables for
+   primary bases; we need these while the primary base is being
+   constructed.  */
+
+static tree
+build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)
+     tree binfo;
+     tree orig_binfo;
+     tree t;
+     tree rtti_binfo;
+     int *non_fn_entries_p;
+{
+  tree v;
+  tree vfun_inits;
+  tree vbase;
+  vtbl_init_data vid;
+
+  /* Initialize VID.  */
+  bzero (&vid, sizeof (vid));
+  vid.binfo = binfo;
+  vid.derived = t;
+  vid.last_init = &vid.inits;
+  vid.primary_vtbl_p = (binfo == TYPE_BINFO (t));
+  vid.ctor_vtbl_p = !same_type_p (BINFO_TYPE (rtti_binfo), t);
+  /* The first vbase or vcall offset is at index -3 in the vtable.  */
+  vid.index = ssize_int (-3);
+
+  /* Add entries to the vtable for RTTI.  */
+  build_rtti_vtbl_entries (binfo, rtti_binfo, &vid);
+
+  /* Create an array for keeping track of the functions we've
+     processed.  When we see multiple functions with the same
+     signature, we share the vcall offsets.  */
+  VARRAY_TREE_INIT (vid.fns, 32, "fns");
+  /* Add the vcall and vbase offset entries.  */
+  build_vcall_and_vbase_vtbl_entries (binfo, &vid);
+  /* Clean up.  */
+  VARRAY_FREE (vid.fns);
+  /* Clear BINFO_VTABLE_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));
+
+  if (non_fn_entries_p)
+    *non_fn_entries_p = list_length (vid.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);
+
+      if (BV_USE_VCALL_INDEX_P (v))
+       {
+         vcall_index = BV_VCALL_INDEX (v);
+         my_friendly_assert (vcall_index != NULL_TREE, 20000621);
+       }
+      else
+       vcall_index = NULL_TREE;
+
+      fn = BV_FN (v);
+      my_friendly_assert (TREE_CODE (delta) == INTEGER_CST, 19990727);
+      my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727);
+
+      /* 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,
+                                BV_GENERATE_THUNK_WITH_VTABLE_P (v));
+      /* 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 negative offset initializers are also in reverse order.  */
+  vid.inits = nreverse (vid.inits);
+
+  /* Chain the two together.  */
+  return chainon (vid.inits, vfun_inits);
+}
+
+/* Sets vid->inits to be the initializers for the vbase and vcall
+   offsets in BINFO, which is in the hierarchy dominated by T.  */
+
+static void
+build_vcall_and_vbase_vtbl_entries (binfo, vid)
+     tree binfo;
+     vtbl_init_data *vid;
+{
+  tree b;
+
+  /* If this is a derived class, we must first create entries
+     corresponding to the primary base class.  */
+  b = get_primary_binfo (binfo);
+  if (b)
+    build_vcall_and_vbase_vtbl_entries (b, vid);
+
+  /* Add the vbase entries for this base.  */
+  build_vbase_offset_vtbl_entries (binfo, vid);
+  /* Add the vcall entries for this base.  */
+  build_vcall_offset_vtbl_entries (binfo, vid);
+}
+
+/* Returns the initializers for the vbase offset entries in the vtable
+   for BINFO (which is part of the class hierarchy dominated by T), in
+   reverse order.  VBASE_OFFSET_INDEX gives the vtable index
+   where the next vbase offset will go.  */
+
+static void
+build_vbase_offset_vtbl_entries (binfo, vid)
+     tree binfo;
+     vtbl_init_data *vid;
+{
+  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 = vid->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, 
+                         vid->index,
+                         convert (ssizetype,
+                                  TYPE_SIZE_UNIT (vtable_entry_type)));
+      if (vid->primary_vtbl_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.  */
+      vid->index = size_binop (MINUS_EXPR, vid->index, ssize_int (1));
+
+      /* The initializer is the delta from BINFO to this virtual base.
+        The vbase offsets go in reverse inheritance-graph order, and
+        we are walking in inheritance graph order so these end up in
+        the right order.  */
+      delta = size_diffop (BINFO_OFFSET (b), BINFO_OFFSET (binfo));
+      *vid->last_init 
+       = build_tree_list (NULL_TREE,
+                          fold (build1 (NOP_EXPR, 
+                                        vtable_entry_type,
+                                        delta)));
+      vid->last_init = &TREE_CHAIN (*vid->last_init);
+    }
+}
+
+/* Adds the initializers for the vcall offset entries in the vtable
+   for BINFO (which is part of the class hierarchy dominated by T) to
+   VID->INITS.  */
+
+static void
+build_vcall_offset_vtbl_entries (binfo, vid)
+     tree binfo;
+     vtbl_init_data *vid;
+{
+  /* Under the old ABI, the adjustments to the `this' pointer were made
+     elsewhere.  */
+  if (!vcall_offsets_in_vtable_p ())
+    return;
+
+  /* We only need these entries if this base is a virtual base.  */
+  if (!TREE_VIA_VIRTUAL (binfo))
+    return;
+
+  /* We need a vcall offset for each of the virtual functions in this
+     vtable.  For example:
+
+       class A { virtual void f (); };
+       class B : virtual public A { };
+       class C: virtual public A, public B {};
+      
+     Now imagine:
+
+       B* b = new C;
+       b->f();
+
+     The location of `A' is not at a fixed offset relative to `B'; the
+     offset depends on the complete object derived from `B'.  So, 
+     `B' vtable contains an entry for `f' that indicates by what
+     amount the `this' pointer for `B' needs to be adjusted to arrive
+     at `A'.  
+
+     We need entries for all the functions in our primary vtable and
+     in our non-virtual bases vtables.  */
+  vid->vbase = binfo;
+  /* Now, walk through the non-virtual bases, adding vcall offsets.  */
+  add_vcall_offset_vtbl_entries_r (binfo, vid);
+}
+
+/* Build vcall offsets, starting with those for BINFO.  */
+
+static void
+add_vcall_offset_vtbl_entries_r (binfo, vid)
+     tree binfo;
+     vtbl_init_data *vid;
+{
+  int i;
+  tree primary_binfo;
+
+  /* Don't walk into virtual bases -- except, of course, for the
+     virtual base for which we are building vcall offsets.  */
+  if (TREE_VIA_VIRTUAL (binfo) && vid->vbase != binfo)
+    return;
+  
+  /* If BINFO has a primary base, process it first.  */
+  primary_binfo = get_primary_binfo (binfo);
+  if (primary_binfo)
+    add_vcall_offset_vtbl_entries_r (primary_binfo, vid);
+
+  /* Add BINFO itself to the list.  */
+  add_vcall_offset_vtbl_entries_1 (binfo, vid);
+
+  /* Scan the non-primary bases of BINFO.  */
+  for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i) 
+    {
+      tree base_binfo;
+      
+      base_binfo = BINFO_BASETYPE (binfo, i);
+      if (base_binfo != primary_binfo)
+       add_vcall_offset_vtbl_entries_r (base_binfo, vid);
+    }
+}
+
+/* Called from build_vcall_offset_vtbl_entries via dfs_walk.  */
+
+static void
+add_vcall_offset_vtbl_entries_1 (binfo, vid)
+     tree binfo;
+     vtbl_init_data* vid;
+{
+  tree derived_virtuals;
+  tree base_virtuals;
+  tree orig_virtuals;
+  tree binfo_inits;
+  /* If BINFO is a primary base, this is the least derived class of
+     BINFO that is not a primary base.  */
+  tree non_primary_binfo;
+
+  binfo_inits = NULL_TREE;
+
+  /* We might be a primary base class.  Go up the inheritance
+     hierarchy until we find the class of which we are a primary base:
+     it is the BINFO_VIRTUALS there that we need to consider.  */
+  non_primary_binfo = binfo;
+  while (BINFO_INHERITANCE_CHAIN (non_primary_binfo))
+    {
+      tree b;
+
+      /* If we have reached a virtual base, then it must be the
+        virtual base for which we are building vcall offsets.  In
+        turn, the virtual base must be a (possibly indirect) primary
+        base of the class that we are initializing, or we wouldn't
+        care about its vtable offsets.  */
+      if (TREE_VIA_VIRTUAL (non_primary_binfo))
+       {
+         non_primary_binfo = vid->binfo;
+         break;
+       }
+
+      b = BINFO_INHERITANCE_CHAIN (non_primary_binfo);
+      if (get_primary_binfo (b) != non_primary_binfo)
+       break;
+      non_primary_binfo = b;
+    }
+
+  /* Make entries for the rest of the virtuals.  */
+  for (base_virtuals = BINFO_VIRTUALS (binfo),
+        derived_virtuals = BINFO_VIRTUALS (non_primary_binfo),
+        orig_virtuals = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (binfo)));
+       base_virtuals;
+       base_virtuals = TREE_CHAIN (base_virtuals),
+        derived_virtuals = TREE_CHAIN (derived_virtuals),
+        orig_virtuals = TREE_CHAIN (orig_virtuals))
+    {
+      tree orig_fn;
+      tree fn;
+      tree base;
+      tree base_binfo;
+      size_t i;
+
+      /* Find the declaration that originally caused this function to
+        be present.  */
+      orig_fn = BV_FN (orig_virtuals);
+
+      /* We do not need an entry if this function is declared in a
+        virtual base (or one of its virtual bases), and not
+        overridden in the section of the hierarchy dominated by the
+        virtual base for which we are building vcall offsets.  */
+      if (!same_type_p (DECL_CONTEXT (orig_fn), BINFO_TYPE (binfo)))
+       continue;
+
+      /* Find the overriding function.  */
+      fn = BV_FN (derived_virtuals);
+
+      /* If there is already an entry for a function with the same
+        signature as FN, then we do not need a second vcall offset.
+        Check the list of functions already present in the derived
+        class vtable.  */
+      for (i = 0; i < VARRAY_ACTIVE_SIZE (vid->fns); ++i) 
+       {
+         tree derived_entry;
+
+         derived_entry = VARRAY_TREE (vid->fns, i);
+         if (same_signature_p (BV_FN (derived_entry), fn))
+           {
+             BV_VCALL_INDEX (derived_virtuals) 
+               = BV_VCALL_INDEX (derived_entry);
+             break;
+           }
+       }
+      if (i != VARRAY_ACTIVE_SIZE (vid->fns))
+       continue;
+
+      /* The FN comes from BASE.  So, we must caculate the adjustment
+        from the virtual base that derived from BINFO to BASE.  */
+      base = DECL_CONTEXT (fn);
+      base_binfo = get_binfo (base, vid->derived, /*protect=*/0);
+
+      /* Compute the vcall offset.  */
+      *vid->last_init 
+       = (build_tree_list 
+          (NULL_TREE,
+           fold (build1 (NOP_EXPR, vtable_entry_type,
+                         size_diffop (BINFO_OFFSET (base_binfo),
+                                      BINFO_OFFSET (vid->vbase))))));
+      vid->last_init = &TREE_CHAIN (*vid->last_init);
+
+      /* Keep track of the vtable index where this vcall offset can be
+        found.  For a construction vtable, we already made this
+        annotation when we build the original vtable.  */
+      if (!vid->ctor_vtbl_p)
+       BV_VCALL_INDEX (derived_virtuals) = vid->index;
+
+      /* The next vcall offset will be found at a more negative
+        offset.  */
+      vid->index = size_binop (MINUS_EXPR, vid->index, ssize_int (1));
+
+      /* Keep track of this function.  */
+      VARRAY_PUSH_TREE (vid->fns, derived_virtuals);
+    }
+}
+
+/* Return vtbl initializers for the RTTI entries coresponding to the
+   BINFO's vtable.  The RTTI entries should indicate the object given
+   by RTTI_BINFO.  */
+
+static void
+build_rtti_vtbl_entries (binfo, rtti_binfo, vid)
+     tree binfo;
+     tree rtti_binfo;
+     vtbl_init_data *vid;
+{
+  tree b;
+  tree t;
+  tree basetype;
+  tree offset;
+  tree decl;
+  tree init;
+
+  basetype = BINFO_TYPE (binfo);
+  t = BINFO_TYPE (rtti_binfo);
+
+  /* For a COM object there is no RTTI entry.  */
+  if (CLASSTYPE_COM_INTERFACE (basetype))
+    return;
+
+  /* To find the complete object, we will first convert to our most
+     primary base, and then add the offset in the vtbl to that value.  */
+  b = binfo;
+  while (CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (b)))
+    {
+      tree primary_base;
+
+      primary_base = get_primary_binfo (b);
+      if (!BINFO_PRIMARY_MARKED_P (primary_base))
+       break;
+      b = primary_base;
+    }
+  offset = size_diffop (BINFO_OFFSET (rtti_binfo), BINFO_OFFSET (b));
+
+  /* The second entry is, in the case of the new ABI, the address of
+     the typeinfo object, or, in the case of the old ABI, a function
+     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, NULL_TREE, init, 
+                                /*generate_with_vtable_p=*/0);
+    }
+  *vid->last_init = build_tree_list (NULL_TREE, init);
+  vid->last_init = &TREE_CHAIN (*vid->last_init);
+
+  /* Add the offset-to-top entry.  It comes earlier in the vtable that
+     the the typeinfo entry.  */
+  if (flag_vtable_thunks)
+    {
+      /* Convert the offset to look like a function pointer, so that
+        we can put it in the vtable.  */
+      init = build1 (NOP_EXPR, vfunc_ptr_type_node, offset);
+      TREE_CONSTANT (init) = 1;
+      *vid->last_init = build_tree_list (NULL_TREE, init);
+      vid->last_init = &TREE_CHAIN (*vid->last_init);
+    }
+}
+
+/* Build an entry in the virtual function table.  DELTA is the offset
+   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, generate_with_vtable_p)
+     tree delta;
+     tree vcall_index;
+     tree entry;
+     int generate_with_vtable_p;
+{
+  if (flag_vtable_thunks)
+    {
+      tree fn;
+
+      fn = TREE_OPERAND (entry, 0);
+      if ((!integer_zerop (delta) || vcall_index != NULL_TREE)
+         && fn != abort_fndecl
+         && !DECL_TINFO_FN_P (fn))
+       {
+         entry = make_thunk (entry, delta, vcall_index,
+                             generate_with_vtable_p);
+         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 (vcall_index == NULL_TREE, 20000125);
+
+      /* DELTA used to be constructed by `size_int' and/or size_binop,
+        which caused overflow problems when it was negative.  That should
+        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;
+    }
 }