OSDN Git Service

* class.c: Reorganize to put virtual function table initialization
authormmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 29 Mar 2000 07:36:39 +0000 (07:36 +0000)
committermmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 29 Mar 2000 07:36:39 +0000 (07:36 +0000)
machinery at the end of the file.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@32798 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/class.c

index 1b89343..e92612d 100644 (file)
@@ -1,3 +1,8 @@
+2000-03-28  Mark Mitchell  <mark@codesourcery.com>
+
+       * class.c: Reorganize to put virtual function table initialization
+       machinery at the end of the file.
+
 2000-03-28  Jason Merrill  <jason@casey.cygnus.com>
 
        * class.c (finish_struct): Use bitsize_zero_node.
index 881c66d..f3a94dc 100644 (file)
@@ -256,438 +256,134 @@ build_vbase_pointer_fields (rli, empty_p)
   return vbase_decls;
 }
 
-/* Called from build_vbase_offset_vtbl_entries via dfs_walk.  */
+/* Returns a pointer to the virtual base class of EXP that has the
+   indicated TYPE.  EXP is of class type, not a pointer type.  */
 
 static tree
-dfs_build_vbase_offset_vtbl_entries (binfo, data)
-     tree binfo;
-     void *data;
+build_vbase_pointer (exp, type)
+     tree exp, type;
 {
-  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))
+  if (vbase_offsets_in_vtable_p ())
     {
-      tree init;
       tree vbase;
+      tree vbase_ptr;
 
-      /* Remember the index to the vbase offset for this virtual
-        base.  */
-      vbase = BINFO_FOR_VBASE (BINFO_TYPE (binfo), TREE_PURPOSE (list));
-      if (!TREE_VALUE (list))
-       BINFO_VPTR_FIELD (vbase) = build_int_2 (-3, 0);
-      else
-       {
-         BINFO_VPTR_FIELD (vbase) = TREE_PURPOSE (TREE_VALUE (list));
-         BINFO_VPTR_FIELD (vbase)
-           = fold (build (MINUS_EXPR, integer_type_node,
-                          BINFO_VPTR_FIELD (vbase), integer_one_node));
-       }
-
-      /* 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));
+      /* Find the shared copy of TYPE; that's where the vtable offset
+        is recorded.  */
+      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 = build1 (NOP_EXPR, 
+                         build_pointer_type (ptrdiff_type_node),
+                         vbase_ptr);
+      /* Add the contents of this location to EXP.  */
+      return build (PLUS_EXPR,
+                   build_pointer_type (type),
+                   build_unary_op (ADDR_EXPR, exp, /*noconvert=*/0),
+                   build1 (INDIRECT_REF, ptrdiff_type_node, vbase_ptr));
     }
-
-  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,
-           unmarked_vtable_pathp,
-           list);
-  dfs_walk (binfo,
-           dfs_vtable_path_unmark,
-           marked_vtable_pathp,
-           list);
-  inits = nreverse (TREE_VALUE (list));
-
-  /* We've now got offsets in the right order.  However, the offsets
-     we've stored are offsets from the beginning of the complete
-     object, and we need offsets from this BINFO.  */
-  for (init = inits; init; init = TREE_CHAIN (init))
+  else
     {
-      /* The dfs_build_vbase_offset_vtbl_entries routine uses the
-        TREE_PURPOSE to scribble in.  But, we need to clear it now so
-        that the values are not perceived as labeled initializers.  */
-      TREE_PURPOSE (init) = NULL_TREE;
-      TREE_VALUE (init)
-       = fold (build1 (NOP_EXPR, vtable_entry_type,
-                       size_diffop (TREE_VALUE (init),
-                                    BINFO_OFFSET (binfo))));
+      char *name;
+      FORMAT_VBASE_NAME (name, type);
+      return build_component_ref (exp, get_identifier (name), NULL_TREE, 0);
     }
-
-  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;
+/* Build multi-level access to EXPR using hierarchy path PATH.
+   CODE is PLUS_EXPR if we are going with the grain,
+   and MINUS_EXPR if we are not (in which case, we cannot traverse
+   virtual baseclass links).
 
-/* Called from build_vcall_offset_vtbl_entries via dfs_walk.  */
+   TYPE is the type we want this path to have on exit.
 
-static tree
-dfs_vcall_offset_queue_p (binfo, data)
-     tree binfo;
-     void *data;
+   NONNULL is non-zero if  we know (for any reason) that EXPR is
+   not, in fact, zero.  */
+
+tree
+build_vbase_path (code, type, expr, path, nonnull)
+     enum tree_code code;
+     tree type, expr, path;
+     int nonnull;
 {
-  vcall_offset_data* vod = (vcall_offset_data *) data;
+  register int changed = 0;
+  tree last = NULL_TREE, last_virtual = NULL_TREE;
+  int fixed_type_p;
+  tree null_expr = 0, nonnull_expr;
+  tree basetype;
+  tree offset = integer_zero_node;
 
-  return (binfo == vod->vbase) ? binfo : dfs_skip_vbases (binfo, NULL);
-}
+  if (BINFO_INHERITANCE_CHAIN (path) == NULL_TREE)
+    return build1 (NOP_EXPR, type, expr);
 
-/* Called from build_vcall_offset_vtbl_entries via dfs_walk.  */
+  /* We could do better if we had additional logic to convert back to the
+     unconverted type (the static type of the complete object), and then
+     convert back to the type we want.  Until that is done, we only optimize
+     if the complete type is the same type as expr has.  */
+  fixed_type_p = resolves_to_fixed_type_p (expr, &nonnull);
 
-static tree
-dfs_build_vcall_offset_vtbl_entries (binfo, data)
-     tree binfo;
-     void *data;
-{
-  vcall_offset_data* vod;
-  tree virtuals;
-  tree binfo_inits;
+  if (!fixed_type_p && TREE_SIDE_EFFECTS (expr))
+    expr = save_expr (expr);
+  nonnull_expr = expr;
 
-  /* Primary bases are not interesting; all of the virtual
-     function table entries have been overridden.  */
-  if (BINFO_PRIMARY_MARKED_P (binfo))
-     return NULL_TREE;
+  path = reverse_path (path);
 
-  vod = (vcall_offset_data *) data;
-  binfo_inits = NULL_TREE;
+  basetype = BINFO_TYPE (path);
 
-  /* We chain the offsets on in reverse order.  That's correct --
-     build_vtbl_initializer will straighten them out.  */
-  for (virtuals = BINFO_VIRTUALS (binfo);
-       virtuals;
-       virtuals = TREE_CHAIN (virtuals))
+  while (path)
     {
-      /* Figure out what function we're looking at.  */
-      tree fn = TREE_VALUE (virtuals);
-      tree base = DECL_CONTEXT (fn);
-      /* The FN comes from BASE.  So, we must caculate the adjustment
-        from the virtual base that derived from BINFO to BASE.  */
-      tree base_binfo = get_binfo (base, vod->derived, /*protect=*/0);
+      if (TREE_VIA_VIRTUAL (TREE_VALUE (path)))
+       {
+         last_virtual = BINFO_TYPE (TREE_VALUE (path));
+         if (code == PLUS_EXPR)
+           {
+             changed = ! fixed_type_p;
 
-      binfo_inits
-       = tree_cons (NULL_TREE,
-                    fold (build1 (NOP_EXPR, vtable_entry_type,
-                                  size_diffop (BINFO_OFFSET (base_binfo),
-                                               BINFO_OFFSET (vod->vbase)))),
-                    binfo_inits);
-    }
+             if (changed)
+               {
+                 tree ind;
 
-  /* 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);
+                 /* We already check for ambiguous things in the caller, just
+                    find a path.  */
+                 if (last)
+                   {
+                     tree binfo = get_binfo (last, TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (nonnull_expr))), 0);
+                     nonnull_expr = convert_pointer_to_real (binfo, nonnull_expr);
+                   }
+                 ind = build_indirect_ref (nonnull_expr, NULL_PTR);
+                 nonnull_expr = build_vbase_pointer (ind, last_virtual);
+                 if (nonnull == 0
+                     && TREE_CODE (type) == POINTER_TYPE
+                     && null_expr == NULL_TREE)
+                   {
+                     null_expr = build1 (NOP_EXPR, build_pointer_type (last_virtual), integer_zero_node);
+                     expr = build (COND_EXPR, build_pointer_type (last_virtual),
+                                   build (EQ_EXPR, boolean_type_node, expr,
+                                          integer_zero_node),
+                                   null_expr, nonnull_expr);
+                   }
+               }
+             /* else we'll figure out the offset below.  */
 
-  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;
-}
-
-/* Return vtbl initializers for the RTTI entries coresponding to the
-   BINFO's vtable.  BINFO is a part of the hierarchy dominated by 
-   T.  */
-
-static tree
-build_rtti_vtbl_entries (binfo, t)
-     tree binfo;
-     tree t;
-{
-  tree b;
-  tree basetype;
-  tree inits;
-  tree offset;
-  tree decl;
-  tree init;
-
-  basetype = BINFO_TYPE (binfo);
-  inits = NULL_TREE;
-
-  /* For a COM object there is no RTTI entry.  */
-  if (CLASSTYPE_COM_INTERFACE (basetype))
-    return inits;
-
-  /* To find the complete object, we will first convert to our most
-     primary base, and then add the offset in the vtbl to that value.  */
-  b = binfo;
-  while (CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (b)))
-    b = BINFO_BASETYPE (b, 
-                       CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (b)));
-  offset = size_diffop (size_zero_node, BINFO_OFFSET (b));
-
-  /* Add the offset-to-top entry.  */
-  if (flag_vtable_thunks)
-    {
-      /* Convert the offset to look like a function pointer, so that
-        we can put it in the vtable.  */
-      init = build1 (NOP_EXPR, vfunc_ptr_type_node, offset);
-      TREE_CONSTANT (init) = 1;
-      inits = tree_cons (NULL_TREE, init, inits);
-    }
-
-  /* The second entry is, in the case of the new ABI, the address of
-     the typeinfo object, or, in the case of the old ABI, a function
-     which returns a typeinfo object.  */
-  if (new_abi_rtti_p ())
-    {
-      if (flag_rtti)
-       decl = build_unary_op (ADDR_EXPR, get_tinfo_decl (t), 0);
-      else
-       decl = integer_zero_node;
-
-      /* Convert the declaration to a type that can be stored in the
-        vtable.  */
-      init = build1 (NOP_EXPR, vfunc_ptr_type_node, decl);
-      TREE_CONSTANT (init) = 1;
-    }
-  else
-    {
-      if (flag_rtti)
-       decl = get_tinfo_decl (t);
-      else
-       decl = abort_fndecl;
-
-      /* Convert the declaration to a type that can be stored in the
-        vtable.  */
-      init = build1 (ADDR_EXPR, vfunc_ptr_type_node, decl);
-      TREE_CONSTANT (init) = 1;
-      init = build_vtable_entry (offset, integer_zero_node, init);
-    }
-
-  /* Hook the RTTI declaration onto the list.  */
-  inits = tree_cons (NULL_TREE, init, inits);
-
-  return 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.  */
-
-static tree
-build_vbase_pointer (exp, type)
-     tree exp, type;
-{
-  if (vbase_offsets_in_vtable_p ())
-    {
-      tree vbase;
-      tree vbase_ptr;
-
-      /* Find the shared copy of TYPE; that's where the vtable offset
-        is recorded.  */
-      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 = build1 (NOP_EXPR, 
-                         build_pointer_type (ptrdiff_type_node),
-                         vbase_ptr);
-      /* Add the contents of this location to EXP.  */
-      return build (PLUS_EXPR,
-                   build_pointer_type (type),
-                   build_unary_op (ADDR_EXPR, exp, /*noconvert=*/0),
-                   build1 (INDIRECT_REF, ptrdiff_type_node, vbase_ptr));
-    }
-  else
-    {
-      char *name;
-      FORMAT_VBASE_NAME (name, type);
-      return build_component_ref (exp, get_identifier (name), NULL_TREE, 0);
-    }
-}
-
-/* Build multi-level access to EXPR using hierarchy path PATH.
-   CODE is PLUS_EXPR if we are going with the grain,
-   and MINUS_EXPR if we are not (in which case, we cannot traverse
-   virtual baseclass links).
-
-   TYPE is the type we want this path to have on exit.
-
-   NONNULL is non-zero if  we know (for any reason) that EXPR is
-   not, in fact, zero.  */
-
-tree
-build_vbase_path (code, type, expr, path, nonnull)
-     enum tree_code code;
-     tree type, expr, path;
-     int nonnull;
-{
-  register int changed = 0;
-  tree last = NULL_TREE, last_virtual = NULL_TREE;
-  int fixed_type_p;
-  tree null_expr = 0, nonnull_expr;
-  tree basetype;
-  tree offset = integer_zero_node;
-
-  if (BINFO_INHERITANCE_CHAIN (path) == NULL_TREE)
-    return build1 (NOP_EXPR, type, expr);
-
-  /* We could do better if we had additional logic to convert back to the
-     unconverted type (the static type of the complete object), and then
-     convert back to the type we want.  Until that is done, we only optimize
-     if the complete type is the same type as expr has.  */
-  fixed_type_p = resolves_to_fixed_type_p (expr, &nonnull);
-
-  if (!fixed_type_p && TREE_SIDE_EFFECTS (expr))
-    expr = save_expr (expr);
-  nonnull_expr = expr;
-
-  path = reverse_path (path);
-
-  basetype = BINFO_TYPE (path);
-
-  while (path)
-    {
-      if (TREE_VIA_VIRTUAL (TREE_VALUE (path)))
-       {
-         last_virtual = BINFO_TYPE (TREE_VALUE (path));
-         if (code == PLUS_EXPR)
-           {
-             changed = ! fixed_type_p;
-
-             if (changed)
-               {
-                 tree ind;
-
-                 /* We already check for ambiguous things in the caller, just
-                    find a path.  */
-                 if (last)
-                   {
-                     tree binfo = get_binfo (last, TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (nonnull_expr))), 0);
-                     nonnull_expr = convert_pointer_to_real (binfo, nonnull_expr);
-                   }
-                 ind = build_indirect_ref (nonnull_expr, NULL_PTR);
-                 nonnull_expr = build_vbase_pointer (ind, last_virtual);
-                 if (nonnull == 0
-                     && TREE_CODE (type) == POINTER_TYPE
-                     && null_expr == NULL_TREE)
-                   {
-                     null_expr = build1 (NOP_EXPR, build_pointer_type (last_virtual), integer_zero_node);
-                     expr = build (COND_EXPR, build_pointer_type (last_virtual),
-                                   build (EQ_EXPR, boolean_type_node, expr,
-                                          integer_zero_node),
-                                   null_expr, nonnull_expr);
-                   }
-               }
-             /* else we'll figure out the offset below.  */
-
-             /* Happens in the case of parse errors.  */
-             if (nonnull_expr == error_mark_node)
-               return error_mark_node;
-           }
-         else
-           {
-             cp_error ("cannot cast up from virtual baseclass `%T'",
-                         last_virtual);
-             return error_mark_node;
-           }
-       }
-      last = TREE_VALUE (path);
-      path = TREE_CHAIN (path);
-    }
-  /* LAST is now the last basetype assoc on the path.  */
+             /* Happens in the case of parse errors.  */
+             if (nonnull_expr == error_mark_node)
+               return error_mark_node;
+           }
+         else
+           {
+             cp_error ("cannot cast up from virtual baseclass `%T'",
+                         last_virtual);
+             return error_mark_node;
+           }
+       }
+      last = TREE_VALUE (path);
+      path = TREE_CHAIN (path);
+    }
+  /* LAST is now the last basetype assoc on the path.  */
 
   /* A pointer to a virtual base member of a non-null object
      is non-null.  Therefore, we only need to test for zeroness once.
@@ -752,75 +448,6 @@ build_vbase_path (code, type, expr, path, nonnull)
 \f
 /* Virtual function things.  */
 
-/* Build an entry in the virtual function table.  DELTA is the offset
-   for the `this' pointer.  VCALL_INDEX is the vtable index containing
-   the vcall offset; zero if none.  ENTRY is the virtual function
-   table entry itself.  It's TREE_TYPE must be VFUNC_PTR_TYPE_NODE,
-   but it may not actually be a virtual function table pointer.  (For
-   example, it might be the address of the RTTI object, under the new
-   ABI.)  */
-
-static tree
-build_vtable_entry (delta, vcall_index, entry)
-     tree delta;
-     tree vcall_index;
-     tree entry;
-{
-  if (flag_vtable_thunks)
-    {
-      HOST_WIDE_INT idelta;
-      HOST_WIDE_INT ivindex;
-
-      idelta = tree_low_cst (delta, 0);
-      ivindex = tree_low_cst (vcall_index, 0);
-      if ((idelta || ivindex) 
-         && ! DECL_PURE_VIRTUAL_P (TREE_OPERAND (entry, 0)))
-       {
-         entry = make_thunk (entry, idelta, ivindex);
-         entry = build1 (ADDR_EXPR, vtable_entry_type, entry);
-         TREE_READONLY (entry) = 1;
-         TREE_CONSTANT (entry) = 1;
-       }
-#ifdef GATHER_STATISTICS
-      n_vtable_entries += 1;
-#endif
-      return entry;
-    }
-  else
-    {
-      extern int flag_huge_objects;
-      tree elems = tree_cons (NULL_TREE, delta,
-                             tree_cons (NULL_TREE, integer_zero_node,
-                                        build_tree_list (NULL_TREE, entry)));
-      tree entry = build (CONSTRUCTOR, vtable_entry_type, NULL_TREE, elems);
-
-      /* We don't use vcall offsets when not using vtable thunks.  */
-      my_friendly_assert (integer_zerop (vcall_index), 20000125);
-
-      /* DELTA used to be constructed by `size_int' and/or size_binop,
-        which caused overflow problems when it was negative.  That should
-        be fixed now.  */
-
-      if (! int_fits_type_p (delta, delta_type_node))
-       {
-         if (flag_huge_objects)
-           sorry ("object size exceeds built-in limit for virtual function table implementation");
-         else
-           sorry ("object size exceeds normal limit for virtual function table implementation, recompile all source and use -fhuge-objects");
-       }
-      
-      TREE_CONSTANT (entry) = 1;
-      TREE_STATIC (entry) = 1;
-      TREE_READONLY (entry) = 1;
-
-#ifdef GATHER_STATISTICS
-      n_vtable_entries += 1;
-#endif
-
-      return entry;
-    }
-}
-
 /* We want to give the assembler the vtable identifier as well as
    the offset to the function pointer.  So we generate
 
@@ -2590,6 +2217,19 @@ num_vfun_entries (binfo)
   return list_length (BINFO_VIRTUALS (binfo));
 }
 
+typedef struct vcall_offset_data_s
+{
+  /* The binfo for the most-derived type.  */
+  tree derived;
+  /* The binfo for the virtual base for which we're building
+     initializers.  */
+  tree vbase;
+  /* The vcall offset initializers built up so far.  */
+  tree inits;
+  /* The number of vcall offsets accumulated.  */
+  int offsets;
+} vcall_offset_data;
+
 /* Called from num_extra_vtbl_entries via dfs_walk.  */
 
 static tree
@@ -2664,284 +2304,79 @@ size_extra_vtbl_entries (binfo)
   return fold (offset);
 }
 
-/* Construct the initializer for BINFOs virtual function table.  BINFO
-   is part of the hierarchy dominated by T.  The value returned is a
-   TREE_LIST suitable for wrapping in a CONSTRUCTOR to use as the
-   DECL_INITIAL for a vtable.  */
+/* True if we should override the given BASE_FNDECL with the given
+   FNDECL.  */
 
-static tree
-build_vtbl_initializer (binfo, t)
-     tree binfo;
-     tree t;
+static int
+overrides (fndecl, base_fndecl)
+     tree fndecl, base_fndecl;
 {
-  tree v = BINFO_VIRTUALS (binfo);
-  tree inits = NULL_TREE;
-
-  /* Add entries to the vtable that indicate how to adjust the this
-     pointer when calling a virtual function in this class.  */
-  inits = build_vcall_offset_vtbl_entries (binfo, t);
-
-  /* Add entries to the vtable for offsets to our virtual bases.  */
-  inits = chainon (build_vbase_offset_vtbl_entries (binfo, t),
-                  inits);
-
-  /* Add entries to the vtable for RTTI.  */
-  inits = chainon (build_rtti_vtbl_entries (binfo, t), inits);
-
-  /* Go through all the ordinary virtual functions, building up
-     initializers.  */
-  while (v)
+  /* Destructors have special names.  */
+  if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (base_fndecl))
+      && DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
+    return 1;
+  if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (base_fndecl))
+      || DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
+    return 0;
+  if (DECL_NAME (fndecl) == DECL_NAME (base_fndecl))
     {
-      tree 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);
+      tree types, base_types;
+#if 0
+      retypes = TREE_TYPE (TREE_TYPE (fndecl));
+      base_retypes = TREE_TYPE (TREE_TYPE (base_fndecl));
+#endif
+      types = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
+      base_types = TYPE_ARG_TYPES (TREE_TYPE (base_fndecl));
+      if ((TYPE_QUALS (TREE_TYPE (TREE_VALUE (base_types)))
+          == TYPE_QUALS (TREE_TYPE (TREE_VALUE (types))))
+         && compparms (TREE_CHAIN (base_types), TREE_CHAIN (types)))
+       return 1;
     }
-
-  /* The initializers were built up in reverse order; straighten them
-     out now.  */
-  return nreverse (inits);
-}
-
-/* Initialize the vtable for BINFO with the INITS.  */
-
-static void
-initialize_vtable (binfo, inits)
-     tree binfo;
-     tree inits;
-{
-  tree context;
-  tree decl;
-
-  layout_vtable_decl (binfo, list_length (inits));
-  decl = BINFO_VTABLE (binfo);
-  context = DECL_CONTEXT (decl);
-  DECL_CONTEXT (decl) = 0;
-  DECL_INITIAL (decl) = build_nt (CONSTRUCTOR, NULL_TREE, inits);
-  cp_finish_decl (decl, DECL_INITIAL (decl), NULL_TREE, 0);
-  DECL_CONTEXT (decl) = context;
+  return 0;
 }
 
-/* Called from finish_vtbls via dfs_walk.  */
-
-static tree
-dfs_finish_vtbls (binfo, data)
-     tree binfo;
-     void *data;
-{
-  tree t = (tree) data;
-
-  if (!BINFO_PRIMARY_MARKED_P (binfo)
-      && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))
-      && BINFO_NEW_VTABLE_MARKED (binfo, t))
-    initialize_vtable (binfo, 
-                      build_vtbl_initializer (binfo, t));
-
-  CLEAR_BINFO_NEW_VTABLE_MARKED (binfo, t);
-  SET_BINFO_MARKED (binfo);
-
-  return NULL_TREE;
-}
+typedef struct find_final_overrider_data_s {
+  /* The function for which we are trying to find a final overrider.  */
+  tree fn;
+  /* The base class in which the function was declared.  */
+  tree declaring_base;
+  /* The most derived class in the hierarchy.  */
+  tree most_derived_type;
+  /* The final overriding function.  */
+  tree overriding_fn;
+  /* The BINFO for the class in which the final overriding function
+     appears.  */
+  tree overriding_base;
+} find_final_overrider_data;
 
-/* Called from finish_vtbls via dfs_walk when using the new ABI.
-   Accumulates the vtable initializers for all of the vtables into
-   TREE_VALUE (DATA).  */
+/* Called from find_final_overrider via dfs_walk.  */
 
 static tree
-dfs_accumulate_vtbl_inits (binfo, data)
+dfs_find_final_overrider (binfo, data)
      tree binfo;
      void *data;
 {
-  tree l;
-  tree t;
-
-  l = (tree) data;
-  t = TREE_PURPOSE (l);
+  find_final_overrider_data *ffod = (find_final_overrider_data *) data;
 
-  if (!BINFO_PRIMARY_MARKED_P (binfo)
-      && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))
-      && BINFO_NEW_VTABLE_MARKED (binfo, t))
+  if (same_type_p (BINFO_TYPE (binfo), 
+                  BINFO_TYPE (ffod->declaring_base))
+      && tree_int_cst_equal (BINFO_OFFSET (binfo),
+                            BINFO_OFFSET (ffod->declaring_base)))
     {
-      /* If this is a secondary vtable, record its location.  */
-      if (binfo != TYPE_BINFO (t))
+      tree path;
+      tree method;
+
+      /* We've found a path to the declaring base.  Walk down the path
+        looking for an overrider for FN.  */
+      for (path = reverse_path (binfo); 
+          path; 
+          path = TREE_CHAIN (path))
        {
-         tree vtbl;
-
-         vtbl = TYPE_BINFO_VTABLE (t);
-         vtbl = build1 (ADDR_EXPR, 
-                        build_pointer_type (TREE_TYPE (vtbl)),
-                        vtbl);
-         BINFO_VTABLE (binfo)
-           = build (PLUS_EXPR, TREE_TYPE (vtbl), vtbl,
-                    size_binop (MULT_EXPR,
-                                TYPE_SIZE_UNIT (TREE_TYPE (vtbl)),
-                                size_int (list_length (TREE_VALUE (l)))));
-       }
-
-      /* Add the initializers for this vtable to the initializers for
-        the other vtables we've already got.  */
-      TREE_VALUE (l) 
-       = chainon (TREE_VALUE (l),
-                  build_vtbl_initializer (binfo, t));
-    }
-
-  CLEAR_BINFO_NEW_VTABLE_MARKED (binfo, t);
-
-  return NULL_TREE;
-}
-
-/* Add the vtbl initializers for BINFO (and its non-primary,
-   non-virtual bases) to the list of INITS.  */
-
-static void
-accumulate_vtbl_inits (binfo, inits)
-     tree binfo;
-     tree inits;
-{
-  /* Walk the BINFO and its bases.  */
-  dfs_walk_real (binfo,
-                dfs_accumulate_vtbl_inits,
-                NULL, 
-                dfs_skip_vbases,
-                inits);
-}
-
-/* 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 (t, NULL_TREE);
-      accumulate_vtbl_inits (TYPE_BINFO (t), list);
-      /* Then come the virtual bases, also in inheritance graph
-        order.  */
-      for (vbase = CLASSTYPE_VBASECLASSES (t);
-          vbase;
-          vbase = TREE_CHAIN (vbase))
-       accumulate_vtbl_inits (vbase, list);
-
-      if (TYPE_BINFO_VTABLE (t))
-       initialize_vtable (TYPE_BINFO (t), TREE_VALUE (list));
-    }
-  else
-    {
-      dfs_walk (TYPE_BINFO (t), dfs_finish_vtbls, 
-               dfs_unmarked_real_bases_queue_p, t);
-      dfs_walk (TYPE_BINFO (t), dfs_unmark, 
-               dfs_marked_real_bases_queue_p, t);
-    }
-}
-
-/* True if we should override the given BASE_FNDECL with the given
-   FNDECL.  */
-
-static int
-overrides (fndecl, base_fndecl)
-     tree fndecl, base_fndecl;
-{
-  /* Destructors have special names.  */
-  if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (base_fndecl))
-      && DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
-    return 1;
-  if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (base_fndecl))
-      || DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
-    return 0;
-  if (DECL_NAME (fndecl) == DECL_NAME (base_fndecl))
-    {
-      tree types, base_types;
-#if 0
-      retypes = TREE_TYPE (TREE_TYPE (fndecl));
-      base_retypes = TREE_TYPE (TREE_TYPE (base_fndecl));
-#endif
-      types = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
-      base_types = TYPE_ARG_TYPES (TREE_TYPE (base_fndecl));
-      if ((TYPE_QUALS (TREE_TYPE (TREE_VALUE (base_types)))
-          == TYPE_QUALS (TREE_TYPE (TREE_VALUE (types))))
-         && compparms (TREE_CHAIN (base_types), TREE_CHAIN (types)))
-       return 1;
-    }
-  return 0;
-}
-
-typedef struct find_final_overrider_data_s {
-  /* The function for which we are trying to find a final overrider.  */
-  tree fn;
-  /* The base class in which the function was declared.  */
-  tree declaring_base;
-  /* The most derived class in the hierarchy.  */
-  tree most_derived_type;
-  /* The final overriding function.  */
-  tree overriding_fn;
-  /* The BINFO for the class in which the final overriding function
-     appears.  */
-  tree overriding_base;
-} find_final_overrider_data;
-
-/* Called from find_final_overrider via dfs_walk.  */
-
-static tree
-dfs_find_final_overrider (binfo, data)
-     tree binfo;
-     void *data;
-{
-  find_final_overrider_data *ffod = (find_final_overrider_data *) data;
-
-  if (same_type_p (BINFO_TYPE (binfo), 
-                  BINFO_TYPE (ffod->declaring_base))
-      && tree_int_cst_equal (BINFO_OFFSET (binfo),
-                            BINFO_OFFSET (ffod->declaring_base)))
-    {
-      tree path;
-      tree method;
-
-      /* We've found a path to the declaring base.  Walk down the path
-        looking for an overrider for FN.  */
-      for (path = reverse_path (binfo); 
-          path; 
-          path = TREE_CHAIN (path))
-       {
-         for (method = TYPE_METHODS (BINFO_TYPE (TREE_VALUE (path)));
-              method;
-              method = TREE_CHAIN (method))
-           if (DECL_VIRTUAL_P (method) && overrides (method, ffod->fn))
-             break;
+         for (method = TYPE_METHODS (BINFO_TYPE (TREE_VALUE (path)));
+              method;
+              method = TREE_CHAIN (method))
+           if (DECL_VIRTUAL_P (method) && overrides (method, ffod->fn))
+             break;
 
          if (method)
            break;
@@ -5299,7 +4734,7 @@ finish_struct_1 (t)
 
   /* If we created a new vtbl pointer for this class, add it to the
      list.  */
-  if (TYPE_VFIELD (t) && CLASSTYPE_VFIELD_PARENT (t) == -1)
+  if (TYPE_VFIELD (t) && !CLASSTYPE_HAS_PRIMARY_BASE_P (t))
     CLASSTYPE_VFIELDS (t) 
       = chainon (CLASSTYPE_VFIELDS (t), build_tree_list (NULL_TREE, t));
 
@@ -6367,270 +5802,837 @@ instantiate_type (lhstype, rhs, flags)
        error ("not enough type information");
       return error_mark_node;
 
-    case COND_EXPR:
-      if (type_unknown_p (TREE_OPERAND (rhs, 0)))
+    case COND_EXPR:
+      if (type_unknown_p (TREE_OPERAND (rhs, 0)))
+       {
+         if (complain)
+           error ("not enough type information");
+         return error_mark_node;
+       }
+      TREE_OPERAND (rhs, 1)
+       = instantiate_type (lhstype, TREE_OPERAND (rhs, 1), flags);
+      if (TREE_OPERAND (rhs, 1) == error_mark_node)
+       return error_mark_node;
+      TREE_OPERAND (rhs, 2)
+       = instantiate_type (lhstype, TREE_OPERAND (rhs, 2), flags);
+      if (TREE_OPERAND (rhs, 2) == error_mark_node)
+       return error_mark_node;
+
+      TREE_TYPE (rhs) = lhstype;
+      return rhs;
+
+    case MODIFY_EXPR:
+      TREE_OPERAND (rhs, 1)
+       = instantiate_type (lhstype, TREE_OPERAND (rhs, 1), flags);
+      if (TREE_OPERAND (rhs, 1) == error_mark_node)
+       return error_mark_node;
+
+      TREE_TYPE (rhs) = lhstype;
+      return rhs;
+      
+    case ADDR_EXPR:
+      return instantiate_type (lhstype, TREE_OPERAND (rhs, 0), flags);
+
+    case ENTRY_VALUE_EXPR:
+      my_friendly_abort (184);
+      return error_mark_node;
+
+    case ERROR_MARK:
+      return error_mark_node;
+
+    default:
+      my_friendly_abort (185);
+      return error_mark_node;
+    }
+}
+\f
+/* Return the name of the virtual function pointer field
+   (as an IDENTIFIER_NODE) for the given TYPE.  Note that
+   this may have to look back through base types to find the
+   ultimate field name.  (For single inheritance, these could
+   all be the same name.  Who knows for multiple inheritance).  */
+
+static tree
+get_vfield_name (type)
+     tree type;
+{
+  tree binfo = TYPE_BINFO (type);
+  char *buf;
+
+  while (BINFO_BASETYPES (binfo)
+        && TYPE_CONTAINS_VPTR_P (BINFO_TYPE (BINFO_BASETYPE (binfo, 0)))
+        && ! TREE_VIA_VIRTUAL (BINFO_BASETYPE (binfo, 0)))
+    binfo = BINFO_BASETYPE (binfo, 0);
+
+  type = BINFO_TYPE (binfo);
+  buf = (char *) alloca (sizeof (VFIELD_NAME_FORMAT)
+                        + TYPE_NAME_LENGTH (type) + 2);
+  sprintf (buf, VFIELD_NAME_FORMAT, TYPE_NAME_STRING (type));
+  return get_identifier (buf);
+}
+
+void
+print_class_statistics ()
+{
+#ifdef GATHER_STATISTICS
+  fprintf (stderr, "convert_harshness = %d\n", n_convert_harshness);
+  fprintf (stderr, "compute_conversion_costs = %d\n", n_compute_conversion_costs);
+  fprintf (stderr, "build_method_call = %d (inner = %d)\n",
+          n_build_method_call, n_inner_fields_searched);
+  if (n_vtables)
+    {
+      fprintf (stderr, "vtables = %d; vtable searches = %d\n",
+              n_vtables, n_vtable_searches);
+      fprintf (stderr, "vtable entries = %d; vtable elems = %d\n",
+              n_vtable_entries, n_vtable_elems);
+    }
+#endif
+}
+
+/* Build a dummy reference to ourselves so Derived::Base (and A::A) works,
+   according to [class]:
+                                          The class-name is also inserted
+   into  the scope of the class itself.  For purposes of access checking,
+   the inserted class name is treated as if it were a public member name.  */
+
+void
+build_self_reference ()
+{
+  tree name = constructor_name (current_class_type);
+  tree value = build_lang_decl (TYPE_DECL, name, current_class_type);
+  tree saved_cas;
+
+  DECL_NONLOCAL (value) = 1;
+  DECL_CONTEXT (value) = current_class_type;
+  DECL_ARTIFICIAL (value) = 1;
+
+  if (processing_template_decl)
+    value = push_template_decl (value);
+
+  saved_cas = current_access_specifier;
+  current_access_specifier = access_public_node;
+  finish_member_declaration (value);
+  current_access_specifier = saved_cas;
+}
+
+/* Returns 1 if TYPE contains only padding bytes.  */
+
+int
+is_empty_class (type)
+     tree type;
+{
+  tree t;
+
+  if (type == error_mark_node)
+    return 0;
+
+  if (! IS_AGGR_TYPE (type))
+    return 0;
+
+  if (flag_new_abi)
+    return integer_zerop (CLASSTYPE_SIZE (type));
+
+  if (TYPE_BINFO_BASETYPES (type))
+    return 0;
+  t = TYPE_FIELDS (type);
+  while (t && TREE_CODE (t) != FIELD_DECL)
+    t = TREE_CHAIN (t);
+  return (t == NULL_TREE);
+}
+
+/* Find the enclosing class of the given NODE.  NODE can be a *_DECL or
+   a *_TYPE node.  NODE can also be a local class.  */
+
+tree
+get_enclosing_class (type)
+     tree type;
+{
+  tree node = type;
+
+  while (node && TREE_CODE (node) != NAMESPACE_DECL)
+    {
+      switch (TREE_CODE_CLASS (TREE_CODE (node)))
+       {
+       case 'd':
+         node = DECL_CONTEXT (node);
+         break;
+
+       case 't':
+         if (node != type)
+           return node;
+         node = TYPE_CONTEXT (node);
+         break;
+
+       default:
+         my_friendly_abort (0);
+       }
+    }
+  return NULL_TREE;
+}
+
+/* Return 1 if TYPE or one of its enclosing classes is derived from BASE.  */
+
+int
+is_base_of_enclosing_class (base, type)
+     tree base, type;
+{
+  while (type)
+    {
+      if (get_binfo (base, type, 0))
+       return 1;
+
+      type = get_enclosing_class (type);
+    }
+  return 0;
+}
+
+/* Note that NAME was looked up while the current class was being
+   defined and that the result of that lookup was DECL.  */
+
+void
+maybe_note_name_used_in_class (name, decl)
+     tree name;
+     tree decl;
+{
+  splay_tree names_used;
+
+  /* If we're not defining a class, there's nothing to do.  */
+  if (!current_class_type || !TYPE_BEING_DEFINED (current_class_type))
+    return;
+  
+  /* If there's already a binding for this NAME, then we don't have
+     anything to worry about.  */
+  if (IDENTIFIER_CLASS_VALUE (name))
+    return;
+
+  if (!current_class_stack[current_class_depth - 1].names_used)
+    current_class_stack[current_class_depth - 1].names_used
+      = splay_tree_new (splay_tree_compare_pointers, 0, 0);
+  names_used = current_class_stack[current_class_depth - 1].names_used;
+
+  splay_tree_insert (names_used,
+                    (splay_tree_key) name, 
+                    (splay_tree_value) decl);
+}
+
+/* Note that NAME was declared (as DECL) in the current class.  Check
+   to see that the declaration is legal.  */
+
+void
+note_name_declared_in_class (name, decl)
+     tree name;
+     tree decl;
+{
+  splay_tree names_used;
+  splay_tree_node n;
+
+  /* Look to see if we ever used this name.  */
+  names_used 
+    = current_class_stack[current_class_depth - 1].names_used;
+  if (!names_used)
+    return;
+
+  n = splay_tree_lookup (names_used, (splay_tree_key) name);
+  if (n)
+    {
+      /* [basic.scope.class]
+        
+        A name N used in a class S shall refer to the same declaration
+        in its context and when re-evaluated in the completed scope of
+        S.  */
+      cp_error ("declaration of `%#D'", decl);
+      cp_error_at ("changes meaning of `%s' from `%+#D'", 
+                  IDENTIFIER_POINTER (DECL_NAME (OVL_CURRENT (decl))),
+                  (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.  */
+
+void
+dump_class_hierarchy (binfo, indent)
+     tree binfo;
+     int indent;
+{
+  int i;
+
+  fprintf (stderr, "%*s0x%lx (%s) ", indent, "",
+          (unsigned long) binfo,
+          type_as_string (binfo, TS_PLAIN));
+  fprintf (stderr, HOST_WIDE_INT_PRINT_DEC,
+          tree_low_cst (BINFO_OFFSET (binfo), 0));
+  fprintf (stderr, " %s\n",
+          BINFO_PRIMARY_MARKED_P (binfo) ? "primary" : "");
+
+  for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
+    dump_class_hierarchy (BINFO_BASETYPE (binfo, i), indent + 2);
+}
+
+/* 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 (t, NULL_TREE);
+      accumulate_vtbl_inits (TYPE_BINFO (t), list);
+      /* Then come the virtual bases, also in inheritance graph
+        order.  */
+      for (vbase = CLASSTYPE_VBASECLASSES (t);
+          vbase;
+          vbase = TREE_CHAIN (vbase))
+       accumulate_vtbl_inits (vbase, list);
+
+      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_PRIMARY_MARKED_P (binfo)
+      && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))
+      && BINFO_NEW_VTABLE_MARKED (binfo, t))
+    initialize_vtable (binfo, 
+                      build_vtbl_initializer (binfo, t));
+
+  CLEAR_BINFO_NEW_VTABLE_MARKED (binfo, t);
+  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 context;
+  tree decl;
+
+  layout_vtable_decl (binfo, list_length (inits));
+  decl = BINFO_VTABLE (binfo);
+  context = DECL_CONTEXT (decl);
+  DECL_CONTEXT (decl) = 0;
+  DECL_INITIAL (decl) = build_nt (CONSTRUCTOR, NULL_TREE, inits);
+  cp_finish_decl (decl, DECL_INITIAL (decl), NULL_TREE, 0);
+  DECL_CONTEXT (decl) = context;
+}
+
+/* Add the vtbl initializers for BINFO (and its non-primary,
+   non-virtual bases) to the list of INITS.  */
+
+static void
+accumulate_vtbl_inits (binfo, inits)
+     tree binfo;
+     tree inits;
+{
+  /* Walk the BINFO and its bases.  */
+  dfs_walk_real (binfo,
+                dfs_accumulate_vtbl_inits,
+                NULL, 
+                dfs_skip_vbases,
+                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).  */
+
+static tree
+dfs_accumulate_vtbl_inits (binfo, data)
+     tree binfo;
+     void *data;
+{
+  tree l;
+  tree t;
+
+  l = (tree) data;
+  t = TREE_PURPOSE (l);
+
+  if (!BINFO_PRIMARY_MARKED_P (binfo)
+      && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))
+      && BINFO_NEW_VTABLE_MARKED (binfo, t))
+    {
+      /* If this is a secondary vtable, record its location.  */
+      if (binfo != TYPE_BINFO (t))
+       {
+         tree vtbl;
+
+         vtbl = TYPE_BINFO_VTABLE (t);
+         vtbl = build1 (ADDR_EXPR, 
+                        build_pointer_type (TREE_TYPE (vtbl)),
+                        vtbl);
+         BINFO_VTABLE (binfo)
+           = build (PLUS_EXPR, TREE_TYPE (vtbl), vtbl,
+                    size_binop (MULT_EXPR,
+                                TYPE_SIZE_UNIT (TREE_TYPE (vtbl)),
+                                size_int (list_length (TREE_VALUE (l)))));
+       }
+
+      /* Add the initializers for this vtable to the initializers for
+        the other vtables we've already got.  */
+      TREE_VALUE (l) 
+       = chainon (TREE_VALUE (l),
+                  build_vtbl_initializer (binfo, t));
+    }
+
+  CLEAR_BINFO_NEW_VTABLE_MARKED (binfo, t);
+
+  return NULL_TREE;
+}
+
+/* Construct the initializer for BINFOs virtual function table.  BINFO
+   is part of the hierarchy dominated by T.  The value returned is a
+   TREE_LIST suitable for wrapping in a CONSTRUCTOR to use as the
+   DECL_INITIAL for a vtable.  */
+
+static tree
+build_vtbl_initializer (binfo, t)
+     tree binfo;
+     tree t;
+{
+  tree v = BINFO_VIRTUALS (binfo);
+  tree inits = NULL_TREE;
+
+  /* Add entries to the vtable that indicate how to adjust the this
+     pointer when calling a virtual function in this class.  */
+  inits = build_vcall_offset_vtbl_entries (binfo, t);
+
+  /* Add entries to the vtable for offsets to our virtual bases.  */
+  inits = chainon (build_vbase_offset_vtbl_entries (binfo, t),
+                  inits);
+
+  /* Add entries to the vtable for RTTI.  */
+  inits = chainon (build_rtti_vtbl_entries (binfo, t), inits);
+
+  /* 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.  */
+  return nreverse (inits);
+}
+
+/* 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 (BINFO_TYPE (binfo), TREE_PURPOSE (list));
+      if (!TREE_VALUE (list))
+       BINFO_VPTR_FIELD (vbase) = build_int_2 (-3, 0);
+      else
        {
-         if (complain)
-           error ("not enough type information");
-         return error_mark_node;
+         BINFO_VPTR_FIELD (vbase) = TREE_PURPOSE (TREE_VALUE (list));
+         BINFO_VPTR_FIELD (vbase)
+           = fold (build (MINUS_EXPR, integer_type_node,
+                          BINFO_VPTR_FIELD (vbase), integer_one_node));
        }
-      TREE_OPERAND (rhs, 1)
-       = instantiate_type (lhstype, TREE_OPERAND (rhs, 1), flags);
-      if (TREE_OPERAND (rhs, 1) == error_mark_node)
-       return error_mark_node;
-      TREE_OPERAND (rhs, 2)
-       = instantiate_type (lhstype, TREE_OPERAND (rhs, 2), flags);
-      if (TREE_OPERAND (rhs, 2) == error_mark_node)
-       return error_mark_node;
 
-      TREE_TYPE (rhs) = lhstype;
-      return rhs;
+      /* 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));
+    }
 
-    case MODIFY_EXPR:
-      TREE_OPERAND (rhs, 1)
-       = instantiate_type (lhstype, TREE_OPERAND (rhs, 1), flags);
-      if (TREE_OPERAND (rhs, 1) == error_mark_node)
-       return error_mark_node;
+  SET_BINFO_VTABLE_PATH_MARKED (binfo);
+  
+  return NULL_TREE;
+}
 
-      TREE_TYPE (rhs) = lhstype;
-      return rhs;
-      
-    case ADDR_EXPR:
-      return instantiate_type (lhstype, TREE_OPERAND (rhs, 0), flags);
+/* 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.  */
 
-    case ENTRY_VALUE_EXPR:
-      my_friendly_abort (184);
-      return error_mark_node;
+static tree
+build_vbase_offset_vtbl_entries (binfo, t)
+     tree binfo;
+     tree t;
+{
+  tree inits;
+  tree init;
+  tree list;
 
-    case ERROR_MARK:
-      return error_mark_node;
+  /* Under the old ABI, pointers to virtual bases are stored in each
+     object.  */
+  if (!vbase_offsets_in_vtable_p ())
+    return NULL_TREE;
 
-    default:
-      my_friendly_abort (185);
-      return error_mark_node;
+  /* If there are no virtual baseclasses, then there is nothing to
+     do.  */
+  if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo)))
+    return NULL_TREE;
+
+  inits = NULL_TREE;
+
+  /* The offsets are allocated in the reverse order of a
+     depth-first left-to-right traversal of the hierarchy.  We use
+     BINFO_VTABLE_PATH_MARKED because we are ourselves during a
+     dfs_walk, and so BINFO_MARKED is already in use.  */
+  list = build_tree_list (t, NULL_TREE);
+  TREE_TYPE (list) = binfo;
+  dfs_walk (binfo,
+           dfs_build_vbase_offset_vtbl_entries,
+           unmarked_vtable_pathp,
+           list);
+  dfs_walk (binfo,
+           dfs_vtable_path_unmark,
+           marked_vtable_pathp,
+           list);
+  inits = nreverse (TREE_VALUE (list));
+
+  /* We've now got offsets in the right order.  However, the offsets
+     we've stored are offsets from the beginning of the complete
+     object, and we need offsets from this BINFO.  */
+  for (init = inits; init; init = TREE_CHAIN (init))
+    {
+      /* The dfs_build_vbase_offset_vtbl_entries routine uses the
+        TREE_PURPOSE to scribble in.  But, we need to clear it now so
+        that the values are not perceived as labeled initializers.  */
+      TREE_PURPOSE (init) = NULL_TREE;
+      TREE_VALUE (init)
+       = fold (build1 (NOP_EXPR, vtable_entry_type,
+                       size_diffop (TREE_VALUE (init),
+                                    BINFO_OFFSET (binfo))));
     }
+
+  return inits;
 }
-\f
-/* Return the name of the virtual function pointer field
-   (as an IDENTIFIER_NODE) for the given TYPE.  Note that
-   this may have to look back through base types to find the
-   ultimate field name.  (For single inheritance, these could
-   all be the same name.  Who knows for multiple inheritance).  */
+
+/* Called from build_vcall_offset_vtbl_entries via dfs_walk.  */
 
 static tree
-get_vfield_name (type)
-     tree type;
+dfs_vcall_offset_queue_p (binfo, data)
+     tree binfo;
+     void *data;
 {
-  tree binfo = TYPE_BINFO (type);
-  char *buf;
-
-  while (BINFO_BASETYPES (binfo)
-        && TYPE_CONTAINS_VPTR_P (BINFO_TYPE (BINFO_BASETYPE (binfo, 0)))
-        && ! TREE_VIA_VIRTUAL (BINFO_BASETYPE (binfo, 0)))
-    binfo = BINFO_BASETYPE (binfo, 0);
+  vcall_offset_data* vod = (vcall_offset_data *) data;
 
-  type = BINFO_TYPE (binfo);
-  buf = (char *) alloca (sizeof (VFIELD_NAME_FORMAT)
-                        + TYPE_NAME_LENGTH (type) + 2);
-  sprintf (buf, VFIELD_NAME_FORMAT, TYPE_NAME_STRING (type));
-  return get_identifier (buf);
+  return (binfo == vod->vbase) ? binfo : dfs_skip_vbases (binfo, NULL);
 }
 
-void
-print_class_statistics ()
+/* Called from build_vcall_offset_vtbl_entries via dfs_walk.  */
+
+static tree
+dfs_build_vcall_offset_vtbl_entries (binfo, data)
+     tree binfo;
+     void *data;
 {
-#ifdef GATHER_STATISTICS
-  fprintf (stderr, "convert_harshness = %d\n", n_convert_harshness);
-  fprintf (stderr, "compute_conversion_costs = %d\n", n_compute_conversion_costs);
-  fprintf (stderr, "build_method_call = %d (inner = %d)\n",
-          n_build_method_call, n_inner_fields_searched);
-  if (n_vtables)
+  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 = BINFO_VIRTUALS (binfo);
+       virtuals;
+       virtuals = TREE_CHAIN (virtuals))
     {
-      fprintf (stderr, "vtables = %d; vtable searches = %d\n",
-              n_vtables, n_vtable_searches);
-      fprintf (stderr, "vtable entries = %d; vtable elems = %d\n",
-              n_vtable_entries, n_vtable_elems);
+      /* Figure out what function we're looking at.  */
+      tree fn = TREE_VALUE (virtuals);
+      tree base = DECL_CONTEXT (fn);
+      /* The FN comes from BASE.  So, we must caculate the adjustment
+        from the virtual base that derived from BINFO to BASE.  */
+      tree base_binfo = get_binfo (base, vod->derived, /*protect=*/0);
+
+      binfo_inits
+       = tree_cons (NULL_TREE,
+                    fold (build1 (NOP_EXPR, vtable_entry_type,
+                                  size_diffop (BINFO_OFFSET (base_binfo),
+                                               BINFO_OFFSET (vod->vbase)))),
+                    binfo_inits);
     }
-#endif
+
+  /* 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;
 }
 
-/* Build a dummy reference to ourselves so Derived::Base (and A::A) works,
-   according to [class]:
-                                          The class-name is also inserted
-   into  the scope of the class itself.  For purposes of access checking,
-   the inserted class name is treated as if it were a public member name.  */
+/* 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.  */
 
-void
-build_self_reference ()
+static tree
+build_vcall_offset_vtbl_entries (binfo, t)
+     tree binfo;
+     tree t;
 {
-  tree name = constructor_name (current_class_type);
-  tree value = build_lang_decl (TYPE_DECL, name, current_class_type);
-  tree saved_cas;
-
-  DECL_NONLOCAL (value) = 1;
-  DECL_CONTEXT (value) = current_class_type;
-  DECL_ARTIFICIAL (value) = 1;
+  vcall_offset_data vod;
 
-  if (processing_template_decl)
-    value = push_template_decl (value);
+  /* Under the old ABI, the adjustments to the `this' pointer were made
+     elsewhere.  */
+  if (!vcall_offsets_in_vtable_p ())
+    return NULL_TREE;
 
-  saved_cas = current_access_specifier;
-  current_access_specifier = access_public_node;
-  finish_member_declaration (value);
-  current_access_specifier = saved_cas;
-}
+  /* We only need these entries if this base is a virtual base.  */
+  if (!TREE_VIA_VIRTUAL (binfo))
+    return NULL_TREE;
 
-/* Returns 1 if TYPE contains only padding bytes.  */
+  /* We need a vcall offset for each of the virtual functions in this
+     vtable.  For example:
 
-int
-is_empty_class (type)
-     tree type;
-{
-  tree t;
+       class A { virtual void f (); };
+       class B : virtual public A { };
+       class C: virtual public A, public B {};
+      
+     Now imagine:
 
-  if (type == error_mark_node)
-    return 0;
+       B* b = new C;
+       b->f();
 
-  if (! IS_AGGR_TYPE (type))
-    return 0;
+     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'.  
 
-  if (flag_new_abi)
-    return integer_zerop (CLASSTYPE_SIZE (type));
+     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);
 
-  if (TYPE_BINFO_BASETYPES (type))
-    return 0;
-  t = TYPE_FIELDS (type);
-  while (t && TREE_CODE (t) != FIELD_DECL)
-    t = TREE_CHAIN (t);
-  return (t == NULL_TREE);
+  return vod.inits;
 }
 
-/* Find the enclosing class of the given NODE.  NODE can be a *_DECL or
-   a *_TYPE node.  NODE can also be a local class.  */
+/* Return vtbl initializers for the RTTI entries coresponding to the
+   BINFO's vtable.  BINFO is a part of the hierarchy dominated by 
+   T.  */
 
-tree
-get_enclosing_class (type)
-     tree type;
+static tree
+build_rtti_vtbl_entries (binfo, t)
+     tree binfo;
+     tree t;
 {
-  tree node = type;
-
-  while (node && TREE_CODE (node) != NAMESPACE_DECL)
-    {
-      switch (TREE_CODE_CLASS (TREE_CODE (node)))
-       {
-       case 'd':
-         node = DECL_CONTEXT (node);
-         break;
+  tree b;
+  tree basetype;
+  tree inits;
+  tree offset;
+  tree decl;
+  tree init;
 
-       case 't':
-         if (node != type)
-           return node;
-         node = TYPE_CONTEXT (node);
-         break;
+  basetype = BINFO_TYPE (binfo);
+  inits = NULL_TREE;
 
-       default:
-         my_friendly_abort (0);
-       }
-    }
-  return NULL_TREE;
-}
+  /* For a COM object there is no RTTI entry.  */
+  if (CLASSTYPE_COM_INTERFACE (basetype))
+    return inits;
 
-/* Return 1 if TYPE or one of its enclosing classes is derived from BASE.  */
+  /* To find the complete object, we will first convert to our most
+     primary base, and then add the offset in the vtbl to that value.  */
+  b = binfo;
+  while (CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (b)))
+    b = BINFO_BASETYPE (b, 
+                       CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (b)));
+  offset = size_diffop (size_zero_node, BINFO_OFFSET (b));
 
-int
-is_base_of_enclosing_class (base, type)
-     tree base, type;
-{
-  while (type)
+  /* Add the offset-to-top entry.  */
+  if (flag_vtable_thunks)
     {
-      if (get_binfo (base, type, 0))
-       return 1;
-
-      type = get_enclosing_class (type);
+      /* Convert the offset to look like a function pointer, so that
+        we can put it in the vtable.  */
+      init = build1 (NOP_EXPR, vfunc_ptr_type_node, offset);
+      TREE_CONSTANT (init) = 1;
+      inits = tree_cons (NULL_TREE, init, inits);
     }
-  return 0;
-}
 
-/* Note that NAME was looked up while the current class was being
-   defined and that the result of that lookup was DECL.  */
+  /* 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;
 
-void
-maybe_note_name_used_in_class (name, decl)
-     tree name;
-     tree decl;
-{
-  splay_tree names_used;
+      /* 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;
 
-  /* If we're not defining a class, there's nothing to do.  */
-  if (!current_class_type || !TYPE_BEING_DEFINED (current_class_type))
-    return;
-  
-  /* If there's already a binding for this NAME, then we don't have
-     anything to worry about.  */
-  if (IDENTIFIER_CLASS_VALUE (name))
-    return;
+      /* Convert the declaration to a type that can be stored in the
+        vtable.  */
+      init = build1 (ADDR_EXPR, vfunc_ptr_type_node, decl);
+      TREE_CONSTANT (init) = 1;
+      init = build_vtable_entry (offset, integer_zero_node, init);
+    }
 
-  if (!current_class_stack[current_class_depth - 1].names_used)
-    current_class_stack[current_class_depth - 1].names_used
-      = splay_tree_new (splay_tree_compare_pointers, 0, 0);
-  names_used = current_class_stack[current_class_depth - 1].names_used;
+  /* Hook the RTTI declaration onto the list.  */
+  inits = tree_cons (NULL_TREE, init, inits);
 
-  splay_tree_insert (names_used,
-                    (splay_tree_key) name, 
-                    (splay_tree_value) decl);
+  return inits;
 }
 
-/* Note that NAME was declared (as DECL) in the current class.  Check
-   to see that the declaration is legal.  */
+/* 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.)  */
 
-void
-note_name_declared_in_class (name, decl)
-     tree name;
-     tree decl;
+static tree
+build_vtable_entry (delta, vcall_index, entry)
+     tree delta;
+     tree vcall_index;
+     tree entry;
 {
-  splay_tree names_used;
-  splay_tree_node n;
-
-  /* Look to see if we ever used this name.  */
-  names_used 
-    = current_class_stack[current_class_depth - 1].names_used;
-  if (!names_used)
-    return;
-
-  n = splay_tree_lookup (names_used, (splay_tree_key) name);
-  if (n)
+  if (flag_vtable_thunks)
     {
-      /* [basic.scope.class]
-        
-        A name N used in a class S shall refer to the same declaration
-        in its context and when re-evaluated in the completed scope of
-        S.  */
-      cp_error ("declaration of `%#D'", decl);
-      cp_error_at ("changes meaning of `%s' from `%+#D'", 
-                  IDENTIFIER_POINTER (DECL_NAME (OVL_CURRENT (decl))),
-                  (tree) n->value);
+      HOST_WIDE_INT idelta;
+      HOST_WIDE_INT ivindex;
+
+      idelta = tree_low_cst (delta, 0);
+      ivindex = tree_low_cst (vcall_index, 0);
+      if ((idelta || ivindex) 
+         && ! DECL_PURE_VIRTUAL_P (TREE_OPERAND (entry, 0)))
+       {
+         entry = make_thunk (entry, idelta, ivindex);
+         entry = build1 (ADDR_EXPR, vtable_entry_type, entry);
+         TREE_READONLY (entry) = 1;
+         TREE_CONSTANT (entry) = 1;
+       }
+#ifdef GATHER_STATISTICS
+      n_vtable_entries += 1;
+#endif
+      return entry;
     }
-}
+  else
+    {
+      extern int flag_huge_objects;
+      tree elems = tree_cons (NULL_TREE, delta,
+                             tree_cons (NULL_TREE, integer_zero_node,
+                                        build_tree_list (NULL_TREE, entry)));
+      tree entry = build (CONSTRUCTOR, vtable_entry_type, NULL_TREE, elems);
 
-/* 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.  */
+      /* We don't use vcall offsets when not using vtable thunks.  */
+      my_friendly_assert (integer_zerop (vcall_index), 20000125);
 
-void
-dump_class_hierarchy (binfo, indent)
-     tree binfo;
-     int indent;
-{
-  int i;
+      /* 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.  */
 
-  fprintf (stderr, "%*s0x%lx (%s) ", indent, "",
-          (unsigned long) binfo,
-          type_as_string (binfo, TS_PLAIN));
-  fprintf (stderr, HOST_WIDE_INT_PRINT_DEC,
-          tree_low_cst (BINFO_OFFSET (binfo), 0));
-  fprintf (stderr, " %s\n",
-          BINFO_PRIMARY_MARKED_P (binfo) ? "primary" : "");
+      if (! 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;
 
-  for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
-    dump_class_hierarchy (BINFO_BASETYPE (binfo, i), indent + 2);
+#ifdef GATHER_STATISTICS
+      n_vtable_entries += 1;
+#endif
+
+      return entry;
+    }
 }