C++ PATCH: New ABI thunks

Mark Mitchell mark@codesourcery.com
Thu Jun 22 18:05:00 GMT 2000


This patch fixes a regression in the virtual function resolution code.
It also brings us closer to full conformance with the new ABI by
emitting thunks with the functions to which they thunk, when possible.

I will be out of the office for a few days; back Monday.  If there are
serious problems with this patch, please let Alex know.

Thanks,

--
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

2000-06-22  Mark Mitchell  <mark@codesourcery.com>

	* cp-tree.h (BV_USE_VCALL_INDEX_P): New macro.
	(BV_GENERATE_THUNK_WITH_VTABLE_P): Likewise.
	(lang_decl_flags): Add generate_with_vtable_p.  Make vcall_offset
	a tree, not an int.
	(THUNK_GENERATE_WITH_VTABLE_P): New macro.
	(make_thunk): Change prototype.
	(emit_thunk): Rename to use_thunk.
	(mangle_thunk): Change prototype.
	* class.c (get_derived_offset): Simplify.
	(copy_virtuals): Clear BV_USE_VCALL_INDEX_P and
	BV_GENERATE_THUNK_WITH_VTABLE_P.
	(build_primary_vtable): Simplify.
	(add_virtual_function): Use BV_FN, rather than TREE_VALUE.
	(dfs_find_base): Remove.
	(update_vtable_entry_for_fn): Correct bug in finding the base
	where a virtual function was first declared.  Figure out whether
	or not to emit a vcall-thunk with the vtables in which it appears.
	Correct logic for deciding whether to use an ordinary thunk, or a
	vcall thunk.
	(finish_struct_1): Remove unnecssary code.
	(build_vtbl_initializer): Use ssize_int for the running counter of
	negative indices.
	(build_vtbl_initializer): Only use vcall thunks where necessary.
	Mark thunks as needing to be emitted with their vtables, or not.
	(build_vbase_offset_vtbl_entries): Adjust for use of ssize_int in
	indices.  Use size_binop.
	(dfs_build_vcall_offset_vtbl_entries): Don't rely on
	BINFO_PRIMARY_MARKED_P here.  Use BV_FN consistently.  Use
	size_binop.
	(build_rtti_vtbl_entries): Adjust call to build_vtable_entry.
	(build_vtable_entry): Mark thunks as needing to be emitted with
	their vtables, or not.
	* decl.c (lang_mark_tree): Mark the vcall_offset in a thunk.
	* decl2.c (mark_vtable_entries): Use use_thunk instead of
	emit_thunk.
	* dump.c (dequeue_and_dump): Remove dead code.  Dump new thunk
	information.
	* error.c (dump_expr): Use BV_FN.
	* mangle.c (mangle_thunk): Adjust now that vcall_offset is a tree,
	not an int.
	* method.c (make_thunk): Likewise.
	(emit_thunk): Rename to use_thunk.  Allow callers to decide
	whether or not to actually emit the thunk.  Adjust for changes in
	representation of vcall offsets.
	* search.c (dfs_get_pure_virtuals): Use BV_FN.
	* semantics.c (emit_associated_thunks): New function.
	(expand_body): Use it.
	* ir.texi: Adjust decriptions of thunks.
	
Index: testsuite/g++.old-deja/g++.other/virtual8.C
===================================================================
RCS file: virtual8.C
diff -N virtual8.C
*** /dev/null	Tue May  5 13:32:27 1998
--- virtual8.C	Thu Jun 22 18:01:57 2000
***************
*** 0 ****
--- 1,31 ----
+ extern "C" void printf (const char*, ...);
+ 
+ struct A
+ {
+   virtual void f () {
+     printf ("%x\n", this);
+   }
+ };
+ 
+ struct B : public A
+ {
+ };
+ 
+ struct C : public A
+ {
+ };
+ 
+ struct D : virtual public B, public C
+ {
+ };
+ 
+ int main ()
+ {
+   D d;
+ 
+   A* a1 = (A*) (B*) &d;
+   A* a2 = (A*) (C*) &d;
+ 
+   a1->f ();
+   a2->f ();
+ }
Index: class.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/class.c,v
retrieving revision 1.320
diff -c -p -r1.320 class.c
*** class.c	2000/06/14 16:10:14	1.320
--- class.c	2000/06/23 00:59:40
*************** varray_type local_classes;
*** 96,102 ****
  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 get_vtable_name PARAMS ((tree));
  static tree get_derived_offset PARAMS ((tree, tree));
  static tree get_basefndecls PARAMS ((tree, tree));
--- 96,102 ----
  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, 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 build_vcall_offset_vtbl_entr
*** 162,168 ****
  static void layout_vtable_decl PARAMS ((tree, int));
  static tree dfs_find_final_overrider PARAMS ((tree, void *));
  static tree find_final_overrider PARAMS ((tree, tree, tree));
- static tree dfs_find_base PARAMS ((tree, void *));
  static int make_new_vtable PARAMS ((tree, tree));
  static void dump_class_hierarchy_r PARAMS ((tree, tree, int));
  extern void dump_class_hierarchy PARAMS ((tree));
--- 162,167 ----
*************** get_derived_offset (binfo, type)
*** 685,700 ****
  {
    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);
!     }
  
    offset2 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
    return size_binop (MINUS_EXPR, offset1, offset2);
--- 684,692 ----
  {
    tree offset1 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
    tree offset2;
  
!   while (!same_type_p (BINFO_TYPE (binfo), type))
!     binfo = BINFO_PRIMARY_BINFO (binfo);
  
    offset2 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
    return size_binop (MINUS_EXPR, offset1, offset2);
*************** copy_virtuals (binfo)
*** 778,784 ****
  
    copies = copy_list (BINFO_VIRTUALS (binfo));
    for (t = copies; t; t = TREE_CHAIN (t))
!     BV_VCALL_INDEX (t) = NULL_TREE;
  
    return copies;
  }
--- 770,780 ----
  
    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;
  }
*************** static int
*** 793,799 ****
  build_primary_vtable (binfo, type)
       tree binfo, type;
  {
!   tree virtuals, decl;
  
    decl = get_vtable_decl (type, /*complete=*/0);
    
--- 789,796 ----
  build_primary_vtable (binfo, type)
       tree binfo, type;
  {
!   tree decl;
!   tree virtuals;
  
    decl = get_vtable_decl (type, /*complete=*/0);
    
*************** build_primary_vtable (binfo, type)
*** 825,833 ****
       on our first approximation.  */
    TYPE_BINFO_VTABLE (type) = decl;
    TYPE_BINFO_VIRTUALS (type) = virtuals;
! 
!   binfo = TYPE_BINFO (type);
!   SET_BINFO_NEW_VTABLE_MARKED (binfo, type);
    return 1;
  }
  
--- 822,828 ----
       on our first approximation.  */
    TYPE_BINFO_VTABLE (type) = decl;
    TYPE_BINFO_VIRTUALS (type) = virtuals;
!   SET_BINFO_NEW_VTABLE_MARKED (TYPE_BINFO (type), type);
    return 1;
  }
  
*************** add_virtual_function (new_virtuals_p, ov
*** 1126,1132 ****
      /* We've already dealt with this function.  */
      return;
  
!   new_virtual = build_tree_list (NULL_TREE, fndecl);
    BV_DELTA (new_virtual) = integer_zero_node;
  
    if (DECL_VINDEX (fndecl) == error_mark_node)
--- 1121,1128 ----
      /* We've already dealt with this function.  */
      return;
  
!   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)
*************** find_final_overrider (t, binfo, fn)
*** 2590,2607 ****
    return build_tree_list (ffod.overriding_fn, ffod.overriding_base);
  }
  
- /* Called via dfs_walk.  Returns BINFO if BINFO has the same type as
-    DATA (which is really an _TYPE node).  */
- 
- static tree
- dfs_find_base (binfo, data)
-      tree binfo;
-      void *data;
- {
-   return (same_type_p (BINFO_TYPE (binfo), (tree) data)
- 	  ? binfo : NULL_TREE);
- }
- 
  /* Update a entry in the vtable for BINFO, which is in the hierarchy
     dominated by T.  FN has been overridden in BINFO; VIRTUALS points
     to the corresponding position in the BINFO_VIRTUALS list.  */
--- 2586,2591 ----
*************** update_vtable_entry_for_fn (t, binfo, fn
*** 2615,2640 ****
  {
    tree b;
    tree overrider;
-   tree vindex;
    tree delta;
!   HOST_WIDE_INT vindex_val;
!   HOST_WIDE_INT i;
  
    /* Find the function which originally caused this vtable
       entry to be present.  */
!   vindex = DECL_VINDEX (fn);
!   b = dfs_walk (binfo, dfs_find_base, NULL, DECL_VIRTUAL_CONTEXT (fn));
!   fn = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (b)));
!   i = first_vfun_index (BINFO_TYPE (b));
!   vindex_val = tree_low_cst (vindex, 0);
!   while (i < vindex_val)
      {
!       fn = TREE_CHAIN (fn);
!       ++i;
      }
-   fn = BV_FN (fn);
  
!   /* Handle the case of a virtual function defined in BINFO itself.  */
    overrider = find_final_overrider (t, b, fn);
    if (overrider == error_mark_node)
      return;
--- 2599,2634 ----
  {
    tree b;
    tree overrider;
    tree delta;
!   tree virtual_base;
!   int generate_thunk_with_vtable_p;
  
    /* Find the function which originally caused this vtable
       entry to be present.  */
!   b = binfo;
!   while (1)
      {
!       tree primary_base;
!       tree f;
! 
!       primary_base = BINFO_PRIMARY_BINFO (b);
!       if (!primary_base)
! 	break;
! 
!       for (f = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (primary_base)));
! 	   f;
! 	   f = TREE_CHAIN (f))
! 	if (same_signature_p (BV_FN (f), fn))
! 	  break;
! 
!       if (!f)
! 	break;
! 
!       fn = BV_FN (f);
!       b = primary_base;
      }
  
!   /* Find the final overrider.  */
    overrider = find_final_overrider (t, b, fn);
    if (overrider == error_mark_node)
      return;
*************** update_vtable_entry_for_fn (t, binfo, fn
*** 2646,2672 ****
  		      get_derived_offset (binfo,
  					  DECL_VIRTUAL_CONTEXT (fn)),
  		      BINFO_OFFSET (binfo));
    if (flag_new_abi)
      {
!       /* Under the new ABI, we only need to adjust as far as the
! 	 nearest virtual base.  Then we use the vcall offset in the
! 	 virtual bases vtable.  */
!       for (b = binfo; b; b = BINFO_INHERITANCE_CHAIN (b))
  	{
! 	  if (TREE_VIA_VIRTUAL (b))
! 	    break;
  	  if (same_type_p (BINFO_TYPE (b), 
  			   BINFO_TYPE (TREE_VALUE (overrider))))
  	    break;
  	}
      }
    else
!     b = NULL_TREE;
  
!   if (b && TREE_VIA_VIRTUAL (b))
      /* The `this' pointer needs to be adjusted to the nearest virtual
         base.  */
!     delta = size_diffop (BINFO_OFFSET (b), delta);
    else
      /* The `this' pointer needs to be adjusted from pointing to
         BINFO to pointing at the base where the final overrider
--- 2640,2692 ----
  		      get_derived_offset (binfo,
  					  DECL_VIRTUAL_CONTEXT (fn)),
  		      BINFO_OFFSET (binfo));
+ 
+   /* Assume that we will produce a thunk that convert all the way to
+      the final overrider, and not to an intermediate virtual base.  */
+   virtual_base  = NULL_TREE;
+ 
+   /* Assume that we will always generate thunks with the vtables that
+      reference them.  */
+   generate_thunk_with_vtable_p = 1;
+ 
+   /* Under the new ABI, we will convert to an intermediate virtual
+      base first, and then use the vcall offset located there to finish
+      the conversion.  */
    if (flag_new_abi)
      {
!       while (b)
  	{
! 	  /* If we find BINFO, then the final overrider is in a class
! 	     derived from BINFO, so the thunks can be generated with
! 	     the final overrider.  */
! 	  if (same_type_p (BINFO_TYPE (b), BINFO_TYPE (binfo)))
! 	    generate_thunk_with_vtable_p = 0;
! 
! 	  /* If we find the final overrider, then we can stop
! 	     walking.  */
  	  if (same_type_p (BINFO_TYPE (b), 
  			   BINFO_TYPE (TREE_VALUE (overrider))))
  	    break;
+ 
+ 	  /* If we find a virtual base, and we haven't yet found the
+ 	     overrider, then there is a virtual base between the
+ 	     declaring base and the final overrider.  */
+ 	  if (!virtual_base && TREE_VIA_VIRTUAL (b))
+ 	    {
+ 	      generate_thunk_with_vtable_p = 1;
+ 	      virtual_base = b;
+ 	    }
+ 
+ 	  b = BINFO_INHERITANCE_CHAIN (b);
  	}
      }
    else
!     virtual_base = NULL_TREE;
  
!   if (virtual_base)
      /* The `this' pointer needs to be adjusted to the nearest virtual
         base.  */
!     delta = size_diffop (BINFO_OFFSET (virtual_base), delta);
    else
      /* The `this' pointer needs to be adjusted from pointing to
         BINFO to pointing at the base where the final overrider
*************** update_vtable_entry_for_fn (t, binfo, fn
*** 2678,2683 ****
--- 2698,2708 ----
  		       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.  */
*************** finish_struct_1 (t)
*** 5074,5090 ****
      {
        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 (TYPE_BINFO_VTABLE (t) != BINFO_VTABLE (binfo))
  	CLASSTYPE_NEEDS_VIRTUAL_REINIT (t) = 1;
      }
--- 5099,5107 ----
      {
        tree binfo = CLASSTYPE_PRIMARY_BINFO (t);
  
!       /* 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;
      }
*************** build_vtbl_initializer (binfo, orig_binf
*** 6992,6998 ****
    vod.last_init = &vod.inits;
    vod.primary_p = (binfo == TYPE_BINFO (t));
    /* The first vbase or vcall offset is at index -3 in the vtable.  */
!   vod.index = build_int_2 (-3, -1);
  
    /* Add entries to the vtable for RTTI.  */
    build_rtti_vtbl_entries (binfo, rtti_binfo, &vod);
--- 7009,7015 ----
    vod.last_init = &vod.inits;
    vod.primary_p = (binfo == TYPE_BINFO (t));
    /* The first vbase or vcall offset is at index -3 in the vtable.  */
!   vod.index = ssize_int (-3);
  
    /* Add entries to the vtable for RTTI.  */
    build_rtti_vtbl_entries (binfo, rtti_binfo, &vod);
*************** build_vtbl_initializer (binfo, orig_binf
*** 7023,7029 ****
        /* 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);
--- 7040,7054 ----
        /* 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);
*************** build_vtbl_initializer (binfo, orig_binf
*** 7039,7045 ****
        /* The address of a function can't change.  */
        TREE_CONSTANT (pfn) = 1;
        /* Enter it in the vtable.  */
!       init = build_vtable_entry (delta, vcall_index, pfn);
        /* And add it to the chain of initializers.  */
        vfun_inits = tree_cons (NULL_TREE, init, vfun_inits);
      }
--- 7064,7071 ----
        /* 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);
      }
*************** build_vbase_offset_vtbl_entries (binfo, 
*** 7125,7131 ****
  
        /* Figure out where we can find this vbase offset.  */
        delta = size_binop (MULT_EXPR, 
! 			  convert (ssizetype, vod->index),
  			  convert (ssizetype,
  				   TYPE_SIZE_UNIT (vtable_entry_type)));
        if (vod->primary_p)
--- 7151,7157 ----
  
        /* Figure out where we can find this vbase offset.  */
        delta = size_binop (MULT_EXPR, 
! 			  vod->index,
  			  convert (ssizetype,
  				   TYPE_SIZE_UNIT (vtable_entry_type)));
        if (vod->primary_p)
*************** build_vbase_offset_vtbl_entries (binfo, 
*** 7146,7153 ****
  	}
  
        /* The next vbase will come at a more negative offset.  */
!       vod->index = fold (build (MINUS_EXPR, integer_type_node,
! 				vod->index, integer_one_node));
  
        /* The initializer is the delta from BINFO to this virtual base.
  	 The vbase offsets go in reverse inheritance-graph order, and
--- 7172,7178 ----
  	}
  
        /* The next vbase will come at a more negative offset.  */
!       vod->index = size_binop (MINUS_EXPR, vod->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
*************** dfs_build_vcall_offset_vtbl_entries (bin
*** 7174,7181 ****
    tree derived_virtuals;
    tree base_virtuals;
    tree binfo_inits;
    tree non_primary_binfo;
!   tree b;
    int i;
  
    vod = (vcall_offset_data *) data;
--- 7199,7209 ----
    tree derived_virtuals;
    tree base_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;
!   /* The primary base of BINFO.  */
!   tree primary_binfo;
    int i;
  
    vod = (vcall_offset_data *) data;
*************** dfs_build_vcall_offset_vtbl_entries (bin
*** 7185,7200 ****
       hierarchy until we find the class of which we are a primary base:
       it is the BINFO_VIRTUALS there that we need to consider.  */
    non_primary_binfo = binfo;
!   while (BINFO_PRIMARY_MARKED_P (non_primary_binfo))
!     non_primary_binfo = BINFO_INHERITANCE_CHAIN (non_primary_binfo);
  
    /* Skip virtuals that we have already handled in a primary base
       class.  */
    base_virtuals = BINFO_VIRTUALS (binfo);
    derived_virtuals = BINFO_VIRTUALS (non_primary_binfo);
!   b = BINFO_PRIMARY_BINFO (binfo);
!   if (b)
!     for (i = 0; i < CLASSTYPE_VSIZE (BINFO_TYPE (b)); ++i)
        {
  	base_virtuals = TREE_CHAIN (base_virtuals);
  	derived_virtuals = TREE_CHAIN (derived_virtuals);
--- 7213,7233 ----
       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 = BINFO_INHERITANCE_CHAIN (non_primary_binfo);
!       if (BINFO_PRIMARY_BINFO (b) != non_primary_binfo)
! 	break;
!       non_primary_binfo = b;
!     }
  
    /* Skip virtuals that we have already handled in a primary base
       class.  */
    base_virtuals = BINFO_VIRTUALS (binfo);
    derived_virtuals = BINFO_VIRTUALS (non_primary_binfo);
!   primary_binfo = BINFO_PRIMARY_BINFO (binfo);
!   if (primary_binfo)
!     for (i = 0; i < CLASSTYPE_VSIZE (BINFO_TYPE (primary_binfo)); ++i)
        {
  	base_virtuals = TREE_CHAIN (base_virtuals);
  	derived_virtuals = TREE_CHAIN (derived_virtuals);
*************** dfs_build_vcall_offset_vtbl_entries (bin
*** 7206,7212 ****
  	 base_virtuals = TREE_CHAIN (base_virtuals))
      {
        /* Figure out what function we're looking at.  */
!       tree fn = TREE_VALUE (derived_virtuals);
        tree base;
        tree base_binfo;
        size_t i;
--- 7239,7245 ----
  	 base_virtuals = TREE_CHAIN (base_virtuals))
      {
        /* Figure out what function we're looking at.  */
!       tree fn = BV_FN (derived_virtuals);
        tree base;
        tree base_binfo;
        size_t i;
*************** dfs_build_vcall_offset_vtbl_entries (bin
*** 7220,7226 ****
  	  tree derived_entry;
  
  	  derived_entry = VARRAY_TREE (vod->fns, i);
! 	  if (same_signature_p (TREE_VALUE (derived_entry), fn))
  	    {
  	      BV_VCALL_INDEX (derived_virtuals) 
  		= BV_VCALL_INDEX (derived_entry);
--- 7253,7259 ----
  	  tree derived_entry;
  
  	  derived_entry = VARRAY_TREE (vod->fns, i);
! 	  if (same_signature_p (BV_FN (derived_entry), fn))
  	    {
  	      BV_VCALL_INDEX (derived_virtuals) 
  		= BV_VCALL_INDEX (derived_entry);
*************** dfs_build_vcall_offset_vtbl_entries (bin
*** 7259,7266 ****
  
        /* The next vcall offset will be found at a more negative
  	 offset.  */
!       vod->index = fold (build (MINUS_EXPR, integer_type_node,
! 				vod->index, integer_one_node));
  
        /* Keep track of this function.  */
        VARRAY_PUSH_TREE (vod->fns, derived_virtuals);
--- 7292,7298 ----
  
        /* The next vcall offset will be found at a more negative
  	 offset.  */
!       vod->index = size_binop (MINUS_EXPR, vod->index, ssize_int (1));
  
        /* Keep track of this function.  */
        VARRAY_PUSH_TREE (vod->fns, derived_virtuals);
*************** build_rtti_vtbl_entries (binfo, rtti_bin
*** 7383,7389 ****
  	 vtable.  */
        init = build1 (ADDR_EXPR, vfunc_ptr_type_node, decl);
        TREE_CONSTANT (init) = 1;
!       init = build_vtable_entry (offset, integer_zero_node, init);
      }
    *vod->last_init = build_tree_list (NULL_TREE, init);
    vod->last_init = &TREE_CHAIN (*vod->last_init);
--- 7415,7422 ----
  	 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);
      }
    *vod->last_init = build_tree_list (NULL_TREE, init);
    vod->last_init = &TREE_CHAIN (*vod->last_init);
*************** build_rtti_vtbl_entries (binfo, rtti_bin
*** 7410,7437 ****
     ABI.)  */
  
  static tree
! build_vtable_entry (delta, vcall_index, entry)
       tree delta;
       tree vcall_index;
       tree entry;
  {
-   if (!vcall_index)
-     vcall_index = integer_zero_node;
- 
    if (flag_vtable_thunks)
      {
-       HOST_WIDE_INT idelta;
-       HOST_WIDE_INT ivindex;
        tree fn;
  
-       idelta = tree_low_cst (delta, 0);
-       ivindex = tree_low_cst (vcall_index, 0);
        fn = TREE_OPERAND (entry, 0);
!       if ((idelta || ivindex) 
  	  && fn != abort_fndecl
  	  && !DECL_TINFO_FN_P (fn))
  	{
! 	  entry = make_thunk (entry, idelta, ivindex);
  	  entry = build1 (ADDR_EXPR, vtable_entry_type, entry);
  	  TREE_READONLY (entry) = 1;
  	  TREE_CONSTANT (entry) = 1;
--- 7443,7465 ----
     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;
*************** build_vtable_entry (delta, vcall_index, 
*** 7449,7455 ****
        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
--- 7477,7483 ----
        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
Index: cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.485
diff -c -p -r1.485 cp-tree.h
*** cp-tree.h	2000/06/17 02:37:23	1.485
--- cp-tree.h	2000/06/23 00:59:43
*************** Boston, MA 02111-1307, USA.  */
*** 45,50 ****
--- 45,51 ----
        SCOPE_BEGIN_P (in SCOPE_STMT)
        CTOR_BEGIN_P (in CTOR_STMT)
        DECL_PRETTY_FUNCTION_P (in VAR_DECL)
+       BV_USE_VCALL_INDEX_P (in the BINFO_VIRTUALS TREE_LIST)
     1: IDENTIFIER_VIRTUAL_P.
        TI_PENDING_TEMPLATE_FLAG.
        TEMPLATE_PARMS_FOR_INLINE.
*************** Boston, MA 02111-1307, USA.  */
*** 57,62 ****
--- 58,64 ----
        ICS_ELLIPSIS_FLAG (in _CONV)
        STMT_IS_FULL_EXPR_P (in _STMT)
        BINFO_ACCESS (in BINFO)
+       BV_GENERATE_THUNK_WITH_VTABLE_P (in TREE_LIST)
     2: IDENTIFIER_OPNAME_P.
        TYPE_POLYMORHPIC_P (in _TYPE)
        ICS_THIS_FLAG (in _CONV)
*************** Boston, MA 02111-1307, USA.  */
*** 128,134 ****
       the this pointer points to an object of the base class.
  
       The BV_VCALL_INDEX of each node, if non-NULL, gives the vtable
!      index of the vcall offset for this entry.
  
       The BV_FN is the declaration for the virtual function itself.
       When CLASSTYPE_COM_INTERFACE_P does not hold, the first entry
--- 130,138 ----
       the this pointer points to an object of the base class.
  
       The BV_VCALL_INDEX of each node, if non-NULL, gives the vtable
!      index of the vcall offset for this entry.  If
!      BV_USE_VCALL_INDEX_P then the corresponding vtable entry should
!      use a virtual thunk, as opposed to an ordinary thunk.
  
       The BV_FN is the declaration for the virtual function itself.
       When CLASSTYPE_COM_INTERFACE_P does not hold, the first entry
*************** struct lang_type
*** 1841,1846 ****
--- 1845,1859 ----
  /* The function to call.  */
  #define BV_FN(NODE) (TREE_VALUE (NODE))
  
+ /* Nonzero if we should use a virtual thunk for this entry.  */
+ #define BV_USE_VCALL_INDEX_P(NODE) \
+    (TREE_LANG_FLAG_0 (NODE))
+ 
+ /* Nonzero if we should generate this thunk when the vtable that
+    references it is emitted, rather than with the final overrider.  */
+ #define BV_GENERATE_THUNK_WITH_VTABLE_P(NODE) \
+   (TREE_LANG_FLAG_1 (NODE))
+ 
  /* The most derived class.  */
  
  
*************** struct lang_decl_flags
*** 1901,1907 ****
    unsigned tinfo_fn_p : 1;
    unsigned assignment_operator_p : 1;
    unsigned anticipated_p : 1;
!   unsigned dummy : 2;
  
    tree context;
  
--- 1914,1921 ----
    unsigned tinfo_fn_p : 1;
    unsigned assignment_operator_p : 1;
    unsigned anticipated_p : 1;
!   unsigned generate_with_vtable_p : 1;
!   unsigned dummy : 1;
  
    tree context;
  
*************** struct lang_decl_flags
*** 1924,1930 ****
  
      /* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is
         THUNK_VCALL_OFFSET.  */
!     HOST_WIDE_INT vcall_offset;
    } u2;
  };
  
--- 1938,1944 ----
  
      /* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is
         THUNK_VCALL_OFFSET.  */
!     tree vcall_offset;
    } u2;
  };
  
*************** extern int flag_new_for_scope;
*** 3141,3146 ****
--- 3155,3164 ----
  #define THUNK_VCALL_OFFSET(DECL) \
    (DECL_LANG_SPECIFIC (DECL)->decl_flags.u2.vcall_offset)
  
+ /* Nonzero if this thunk should be generated with the vtable that
+    references it.  */
+ #define THUNK_GENERATE_WITH_VTABLE_P(DECL) \
+   (DECL_LANG_SPECIFIC (DECL)->decl_flags.generate_with_vtable_p)
  
  /* These macros provide convenient access to the various _STMT nodes
     created when parsing template declarations.  */
*************** extern tree build_overload_with_type		PA
*** 4244,4251 ****
  extern tree build_destructor_name		PARAMS ((tree));
  extern tree build_opfncall			PARAMS ((enum tree_code, int, tree, tree, tree));
  extern tree hack_identifier			PARAMS ((tree, tree));
! extern tree make_thunk				PARAMS ((tree, int, int));
! extern void emit_thunk				PARAMS ((tree));
  extern void synthesize_method			PARAMS ((tree));
  extern tree get_id_2				PARAMS ((const char *, tree));
  extern tree implicitly_declare_fn               PARAMS ((special_function_kind, tree, int));
--- 4262,4269 ----
  extern tree build_destructor_name		PARAMS ((tree));
  extern tree build_opfncall			PARAMS ((enum tree_code, int, tree, tree, tree));
  extern tree hack_identifier			PARAMS ((tree, tree));
! extern tree make_thunk				PARAMS ((tree, tree, tree, int));
! extern void use_thunk				PARAMS ((tree, int));
  extern void synthesize_method			PARAMS ((tree));
  extern tree get_id_2				PARAMS ((const char *, tree));
  extern tree implicitly_declare_fn               PARAMS ((special_function_kind, tree, int));
*************** extern tree mangle_typeinfo_string_for_t
*** 4684,4690 ****
  extern tree mangle_vtbl_for_type                PARAMS ((tree));
  extern tree mangle_vtt_for_type                 PARAMS ((tree));
  extern tree mangle_ctor_vtbl_for_type           PARAMS ((tree, tree));
! extern tree mangle_thunk                        PARAMS ((tree, int, int)); 
  extern tree mangle_conv_op_name_for_type        PARAMS ((tree));
  extern tree mangle_guard_variable               PARAMS ((tree));
  
--- 4702,4708 ----
  extern tree mangle_vtbl_for_type                PARAMS ((tree));
  extern tree mangle_vtt_for_type                 PARAMS ((tree));
  extern tree mangle_ctor_vtbl_for_type           PARAMS ((tree, tree));
! extern tree mangle_thunk                        PARAMS ((tree, tree, tree)); 
  extern tree mangle_conv_op_name_for_type        PARAMS ((tree));
  extern tree mangle_guard_variable               PARAMS ((tree));
  
Index: decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl.c,v
retrieving revision 1.637
diff -c -p -r1.637 decl.c
*** decl.c	2000/06/16 07:34:41	1.637
--- decl.c	2000/06/23 00:59:52
*************** lang_mark_tree (t)
*** 15043,15048 ****
--- 15043,15050 ----
  	      && !DECL_GLOBAL_DTOR_P (t)
  	      && !DECL_THUNK_P (t))
  	    ggc_mark_tree (ld->decl_flags.u2.access);
+ 	  else if (DECL_THUNK_P (t))
+ 	    ggc_mark_tree (ld->decl_flags.u2.vcall_offset);
  	  ggc_mark_tree (ld->decl_flags.context);
  	  if (TREE_CODE (t) != NAMESPACE_DECL)
  	    ggc_mark_tree (ld->decl_flags.u.template_info);
Index: decl2.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl2.c,v
retrieving revision 1.368
diff -c -p -r1.368 decl2.c
*** decl2.c	2000/06/14 05:30:04	1.368
--- decl2.c	2000/06/23 00:59:56
*************** mark_vtable_entries (decl)
*** 2422,2432 ****
  
        fn = TREE_OPERAND (fnaddr, 0);
        TREE_ADDRESSABLE (fn) = 1;
!       if (DECL_THUNK_P (fn) && DECL_EXTERNAL (fn))
! 	{
! 	  DECL_EXTERNAL (fn) = 0;
! 	  emit_thunk (fn);
! 	}
        mark_used (fn);
      }
  }
--- 2422,2433 ----
  
        fn = TREE_OPERAND (fnaddr, 0);
        TREE_ADDRESSABLE (fn) = 1;
!       /* When we don't have vcall offsets, we output thunks whenever
! 	 we output the vtables that contain them.  With vcall offsets,
! 	 we know all the thunks we'll need when we emit a virtual
! 	 function, so we emit the thunks there instead.  */
!       if (DECL_THUNK_P (fn)) 
! 	use_thunk (fn, THUNK_GENERATE_WITH_VTABLE_P (fn));
        mark_used (fn);
      }
  }
Index: dump.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/dump.c,v
retrieving revision 1.46
diff -c -p -r1.46 dump.c
*** dump.c	2000/06/16 07:34:42	1.46
--- dump.c	2000/06/23 00:59:56
*************** dequeue_and_dump (di)
*** 566,572 ****
  	dump_string(di, "extern");
        else
  	dump_string (di, "static");
!       if (TREE_CODE (t) == FUNCTION_DECL)
  	{
  	  if (DECL_FUNCTION_MEMBER_P (t))
  	    dump_string (di, "member");
--- 566,572 ----
  	dump_string(di, "extern");
        else
  	dump_string (di, "static");
!       if (!DECL_THUNK_P (t))
  	{
  	  if (DECL_FUNCTION_MEMBER_P (t))
  	    dump_string (di, "member");
*************** dequeue_and_dump (di)
*** 578,590 ****
  	    dump_string (di, "operator");
  	  if (DECL_CONV_FN_P (t))
  	    dump_string (di, "conversion");
- 	  if (DECL_THUNK_P (t))
- 	    {
- 	      dump_string (di, "thunk");
- 	      dump_int (di, "dlta", THUNK_DELTA (t));
- 	      dump_int (di, "vcll", THUNK_VCALL_OFFSET (t));
- 	      dump_child ("fn", DECL_INITIAL (t));
- 	    }
  	  if (DECL_GLOBAL_CTOR_P (t) || DECL_GLOBAL_DTOR_P (t))
  	    {
  	      if (DECL_GLOBAL_CTOR_P (t))
--- 578,583 ----
*************** dequeue_and_dump (di)
*** 600,607 ****
  	}
        else
  	{
  	  dump_int (di, "dlta", THUNK_DELTA (t));
! 	  dump_child ("init", DECL_INITIAL (t));
  	}
        break;
  
--- 593,602 ----
  	}
        else
  	{
+ 	  dump_string (di, "thunk");
  	  dump_int (di, "dlta", THUNK_DELTA (t));
! 	  dump_child ("vcll", THUNK_VCALL_OFFSET (t));
! 	  dump_child ("fn", DECL_INITIAL (t));
  	}
        break;
  
Index: error.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/error.c,v
retrieving revision 1.116
diff -c -p -r1.116 error.c
*** error.c	2000/06/16 07:34:42	1.116
--- error.c	2000/06/23 00:59:57
*************** dump_expr (t, flags)
*** 1865,1871 ****
  		}
  	      if (virtuals)
  		{
! 		  dump_expr (TREE_VALUE (virtuals),
  	                     flags | TS_EXPR_PARENS);
  		  break;
  		}
--- 1865,1871 ----
  		}
  	      if (virtuals)
  		{
! 		  dump_expr (BV_FN (virtuals),
  	                     flags | TS_EXPR_PARENS);
  		  break;
  		}
Index: ir.texi
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/ir.texi,v
retrieving revision 1.31
diff -c -p -r1.31 ir.texi
*** ir.texi	2000/06/05 01:42:22	1.31
--- ir.texi	2000/06/23 00:59:59
*************** returning to the thunk.  The first param
*** 1040,1047 ****
  value.  (The @code{THUNK_DELTA} is an @code{int}, not an
  @code{INTEGER_CST}.)  
  
! Then, if @code{THUNK_VCALL_OFFSET} (also an @code{int}) is non-zero the
! adjusted @code{this} pointer must be adjusted again.  The complete
  calculation is given by the following pseudo-code:
  
  @example
--- 1040,1047 ----
  value.  (The @code{THUNK_DELTA} is an @code{int}, not an
  @code{INTEGER_CST}.)  
  
! Then, if @code{THUNK_VCALL_OFFSET} (an @code{INTEGER_CST}) is non-zero
! the adjusted @code{this} pointer must be adjusted again.  The complete
  calculation is given by the following pseudo-code:
  
  @example
Index: mangle.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/mangle.c,v
retrieving revision 1.8
diff -c -p -r1.8 mangle.c
*** mangle.c	2000/06/12 06:43:27	1.8
--- mangle.c	2000/06/23 01:00:00
*************** mangle_ctor_vtbl_for_type (type, binfo)
*** 2076,2082 ****
  
  /* Return an identifier for the mangled name of a thunk to FN_DECL.
     OFFSET is the initial adjustment to this used to find the vptr.  If
!    VCALL_OFFSET is non-zero, this is a virtual thunk, and it is the
     vtbl offset in bytes.  
  
      <special-name> ::= Th <offset number> _ <base encoding>
--- 2076,2082 ----
  
  /* Return an identifier for the mangled name of a thunk to FN_DECL.
     OFFSET is the initial adjustment to this used to find the vptr.  If
!    VCALL_OFFSET is non-NULL, this is a virtual thunk, and it is the
     vtbl offset in bytes.  
  
      <special-name> ::= Th <offset number> _ <base encoding>
*************** mangle_ctor_vtbl_for_type (type, binfo)
*** 2087,2094 ****
  tree
  mangle_thunk (fn_decl, offset, vcall_offset)
       tree fn_decl;
!      int offset;
!      int vcall_offset;
  {
    const char *result;
    
--- 2087,2094 ----
  tree
  mangle_thunk (fn_decl, offset, vcall_offset)
       tree fn_decl;
!      tree offset;
!      tree vcall_offset;
  {
    const char *result;
    
*************** mangle_thunk (fn_decl, offset, vcall_off
*** 2104,2117 ****
      write_char ('h');
  
    /* For either flavor, write the offset to this.  */
!   write_signed_number (offset);
    write_char ('_');
  
    /* For a virtual thunk, add the vcall offset.  */
!   if (vcall_offset != 0)
      {
        /* Virtual thunk.  Write the vcall offset and base type name.  */
!       write_signed_number (vcall_offset);
        write_char ('_');
      }
  
--- 2104,2117 ----
      write_char ('h');
  
    /* For either flavor, write the offset to this.  */
!   write_integer_cst (offset);
    write_char ('_');
  
    /* For a virtual thunk, add the vcall offset.  */
!   if (vcall_offset)
      {
        /* Virtual thunk.  Write the vcall offset and base type name.  */
!       write_integer_cst (vcall_offset);
        write_char ('_');
      }
  
Index: method.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/method.c,v
retrieving revision 1.168
diff -c -p -r1.168 method.c
*** method.c	2000/06/16 07:34:43	1.168
--- method.c	2000/06/23 01:00:01
*************** hack_identifier (value, name)
*** 2064,2079 ****
     DELTA is the offset to this and VCALL_INDEX is zero.  */
  
  tree
! make_thunk (function, delta, vcall_index)
       tree function;
!      int delta;
!      int vcall_index;
  {
    tree thunk_id;
    tree thunk;
    tree func_decl;
!   int vcall_offset = vcall_index * int_size_in_bytes (vtable_entry_type);
  
    if (TREE_CODE (function) != ADDR_EXPR)
      abort ();
    func_decl = TREE_OPERAND (function, 0);
--- 2064,2093 ----
     DELTA is the offset to this and VCALL_INDEX is zero.  */
  
  tree
! make_thunk (function, delta, vcall_index, generate_with_vtable_p)
       tree function;
!      tree delta;
!      tree vcall_index;
!      int generate_with_vtable_p;
  {
    tree thunk_id;
    tree thunk;
    tree func_decl;
!   tree vcall_offset;
!   HOST_WIDE_INT d;
  
+   /* Scale the VCALL_INDEX to be in terms of bytes.  */
+   if (vcall_index)
+     vcall_offset 
+       = size_binop (MULT_EXPR,
+ 		    vcall_index,
+ 		    convert (ssizetype,
+ 			     TYPE_SIZE_UNIT (vtable_entry_type)));
+   else
+     vcall_offset = NULL_TREE;
+ 
+   d = tree_low_cst (delta, 0);
+ 
    if (TREE_CODE (function) != ADDR_EXPR)
      abort ();
    func_decl = TREE_OPERAND (function, 0);
*************** make_thunk (function, delta, vcall_index
*** 2081,2102 ****
      abort ();
  
    if (flag_new_abi) 
!     thunk_id = mangle_thunk (TREE_OPERAND (function, 0),  delta, vcall_offset);
    else
      {
        OB_INIT ();
        OB_PUTS ("__thunk_");
!       if (delta > 0)
  	{
  	  OB_PUTC ('n');
! 	  icat (delta);
  	}
        else
! 	icat (-delta);
        OB_PUTC ('_');
        if (vcall_index)
  	{
! 	  icat (vcall_index);
  	  OB_PUTC ('_');
  	}
        OB_PUTID (DECL_ASSEMBLER_NAME (func_decl));
--- 2095,2117 ----
      abort ();
  
    if (flag_new_abi) 
!     thunk_id = mangle_thunk (TREE_OPERAND (function, 0), 
! 			     delta, vcall_offset);
    else
      {
        OB_INIT ();
        OB_PUTS ("__thunk_");
!       if (d > 0)
  	{
  	  OB_PUTC ('n');
! 	  icat (d);
  	}
        else
! 	icat (-d);
        OB_PUTC ('_');
        if (vcall_index)
  	{
! 	  icat (tree_low_cst (vcall_index, 0));
  	  OB_PUTC ('_');
  	}
        OB_PUTID (DECL_ASSEMBLER_NAME (func_decl));
*************** make_thunk (function, delta, vcall_index
*** 2122,2129 ****
        comdat_linkage (thunk);
        SET_DECL_THUNK_P (thunk);
        DECL_INITIAL (thunk) = function;
!       THUNK_DELTA (thunk) = delta;
        THUNK_VCALL_OFFSET (thunk) = vcall_offset;
        /* The thunk itself is not a constructor or destructor, even if
         the thing it is thunking to is.  */
        DECL_INTERFACE_KNOWN (thunk) = 1;
--- 2137,2145 ----
        comdat_linkage (thunk);
        SET_DECL_THUNK_P (thunk);
        DECL_INITIAL (thunk) = function;
!       THUNK_DELTA (thunk) = d;
        THUNK_VCALL_OFFSET (thunk) = vcall_offset;
+       THUNK_GENERATE_WITH_VTABLE_P (thunk) = generate_with_vtable_p;
        /* The thunk itself is not a constructor or destructor, even if
         the thing it is thunking to is.  */
        DECL_INTERFACE_KNOWN (thunk) = 1;
*************** make_thunk (function, delta, vcall_index
*** 2143,2148 ****
--- 2159,2166 ----
        DECL_DEFERRED_FN (thunk) = 0;
        /* So that finish_file can write out any thunks that need to be: */
        pushdecl_top_level (thunk);
+       /* Create RTL for this thunk so that its address can be taken.  */
+       make_function_rtl (thunk);
      }
    return thunk;
  }
*************** make_thunk (function, delta, vcall_index
*** 2150,2166 ****
  /* Emit the definition of a C++ multiple inheritance vtable thunk.  */
  
  void
! emit_thunk (thunk_fndecl)
       tree thunk_fndecl;
  {
    tree fnaddr;
    tree function;
!   int delta;
!   int vcall_offset;
  
    if (TREE_ASM_WRITTEN (thunk_fndecl))
      return;
! 
    if (TREE_CODE (DECL_INITIAL (thunk_fndecl)) != ADDR_EXPR)
      /* We already turned this thunk into an ordinary function.
         There's no need to process this thunk again.  (We can't just
--- 2168,2187 ----
  /* Emit the definition of a C++ multiple inheritance vtable thunk.  */
  
  void
! use_thunk (thunk_fndecl, emit_p)
       tree thunk_fndecl;
+      int emit_p;
+      
  {
    tree fnaddr;
    tree function;
!   tree vcall_offset;
!   HOST_WIDE_INT delta;
  
    if (TREE_ASM_WRITTEN (thunk_fndecl))
      return;
!   
!   fnaddr = DECL_INITIAL (thunk_fndecl);
    if (TREE_CODE (DECL_INITIAL (thunk_fndecl)) != ADDR_EXPR)
      /* We already turned this thunk into an ordinary function.
         There's no need to process this thunk again.  (We can't just
*************** emit_thunk (thunk_fndecl)
*** 2168,2183 ****
         FNADDR_FROM_VTABLE_ENTRY and friends.)  */
      return;
  
!   fnaddr = DECL_INITIAL (thunk_fndecl);
!   function = TREE_OPERAND (fnaddr, 0);
!   delta = THUNK_DELTA (thunk_fndecl);
!   vcall_offset = THUNK_VCALL_OFFSET (thunk_fndecl);
  
    TREE_ADDRESSABLE (function) = 1;
    mark_used (function);
  
!   if (current_function_decl)
!     abort ();
  
    if (flag_syntax_only)
      {
--- 2189,2213 ----
         FNADDR_FROM_VTABLE_ENTRY and friends.)  */
      return;
  
!   /* Thunks are always addressable; they only appear in vtables.  */
!   TREE_ADDRESSABLE (thunk_fndecl) = 1;
  
+   /* Figure out what function is being thunked to.  It's referenced in
+      this translation unit.  */
+   function = TREE_OPERAND (fnaddr, 0);
    TREE_ADDRESSABLE (function) = 1;
    mark_used (function);
+   TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (function)) = 1;
+   if (!emit_p)
+     return;
  
!   delta = THUNK_DELTA (thunk_fndecl);
!   vcall_offset = THUNK_VCALL_OFFSET (thunk_fndecl);
! 
!   /* And, if we need to emit the thunk, it's used.  */
!   mark_used (thunk_fndecl);
!   /* This thunk is actually defined.  */
!   DECL_EXTERNAL (thunk_fndecl) = 0;
  
    if (flag_syntax_only)
      {
*************** emit_thunk (thunk_fndecl)
*** 2185,2198 ****
        return;
      }
  
  #ifdef ASM_OUTPUT_MI_THUNK
!   if (vcall_offset == 0)
      {
        const char *fnname;
        current_function_decl = thunk_fndecl;
-       /* Make sure we build up its RTL before we go onto the
- 	 temporary obstack.  */
-       make_function_rtl (thunk_fndecl);
        DECL_RESULT (thunk_fndecl)
  	= build_decl (RESULT_DECL, 0, integer_type_node);
        fnname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0);
--- 2215,2227 ----
        return;
      }
  
+   push_to_top_level ();
+ 
  #ifdef ASM_OUTPUT_MI_THUNK
!   if (!vcall_offset)
      {
        const char *fnname;
        current_function_decl = thunk_fndecl;
        DECL_RESULT (thunk_fndecl)
  	= build_decl (RESULT_DECL, 0, integer_type_node);
        fnname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0);
*************** emit_thunk (thunk_fndecl)
*** 2231,2247 ****
      DECL_ARGUMENTS (thunk_fndecl) = a;
      DECL_RESULT (thunk_fndecl) = NULL_TREE;
  
-     push_to_top_level ();
      start_function (NULL_TREE, thunk_fndecl, NULL_TREE, SF_PRE_PARSED);
      store_parm_decls ();
  
      /* Adjust the this pointer by the constant.  */
      t = ssize_int (delta);
-     TREE_TYPE (t) = signed_type (sizetype);
      t = fold (build (PLUS_EXPR, TREE_TYPE (a), a, t));
      /* If there's a vcall offset, look up that value in the vtable and
         adjust the `this' pointer again.  */
!     if (vcall_offset != 0)
        {
  	tree orig_this;
  
--- 2260,2274 ----
      DECL_ARGUMENTS (thunk_fndecl) = a;
      DECL_RESULT (thunk_fndecl) = NULL_TREE;
  
      start_function (NULL_TREE, thunk_fndecl, NULL_TREE, SF_PRE_PARSED);
      store_parm_decls ();
  
      /* Adjust the this pointer by the constant.  */
      t = ssize_int (delta);
      t = fold (build (PLUS_EXPR, TREE_TYPE (a), a, t));
      /* If there's a vcall offset, look up that value in the vtable and
         adjust the `this' pointer again.  */
!     if (!integer_zerop (vcall_offset))
        {
  	tree orig_this;
  
*************** emit_thunk (thunk_fndecl)
*** 2255,2261 ****
  	/* Form the vtable address.  */
  	t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
  	/* Find the entry with the vcall offset.  */
! 	t = build (PLUS_EXPR, TREE_TYPE (t), t, ssize_int (vcall_offset));
  	/* Calculate the offset itself.  */
  	t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
  	/* Adjust the `this' pointer.  */
--- 2282,2288 ----
  	/* Form the vtable address.  */
  	t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
  	/* Find the entry with the vcall offset.  */
! 	t = build (PLUS_EXPR, TREE_TYPE (t), t, vcall_offset);
  	/* Calculate the offset itself.  */
  	t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
  	/* Adjust the `this' pointer.  */
*************** emit_thunk (thunk_fndecl)
*** 2282,2289 ****
      BLOCK_VARS (DECL_INITIAL (thunk_fndecl)) 
        = DECL_ARGUMENTS (thunk_fndecl);
      expand_body (finish_function (0));
-     pop_from_top_level ();
    }
  }
  
  /* Code for synthesizing methods which have default semantics defined.  */
--- 2309,2317 ----
      BLOCK_VARS (DECL_INITIAL (thunk_fndecl)) 
        = DECL_ARGUMENTS (thunk_fndecl);
      expand_body (finish_function (0));
    }
+ 
+   pop_from_top_level ();
  }
  
  /* Code for synthesizing methods which have default semantics defined.  */
Index: search.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/search.c,v
retrieving revision 1.182
diff -c -p -r1.182 search.c
*** search.c	2000/06/06 00:12:40	1.182
--- search.c	2000/06/23 01:00:03
*************** dfs_get_pure_virtuals (binfo, data)
*** 2295,2303 ****
        for (virtuals = BINFO_VIRTUALS (binfo);
  	   virtuals;
  	   virtuals = TREE_CHAIN (virtuals))
! 	if (DECL_PURE_VIRTUAL_P (TREE_VALUE (virtuals)))
  	  CLASSTYPE_PURE_VIRTUALS (type) 
! 	    = tree_cons (NULL_TREE, TREE_VALUE (virtuals),
  			 CLASSTYPE_PURE_VIRTUALS (type));
      }
    
--- 2295,2303 ----
        for (virtuals = BINFO_VIRTUALS (binfo);
  	   virtuals;
  	   virtuals = TREE_CHAIN (virtuals))
! 	if (DECL_PURE_VIRTUAL_P (BV_FN (virtuals)))
  	  CLASSTYPE_PURE_VIRTUALS (type) 
! 	    = tree_cons (NULL_TREE, BV_FN (virtuals),
  			 CLASSTYPE_PURE_VIRTUALS (type));
      }
    
*************** get_pure_virtuals (type)
*** 2341,2347 ****
  	   virtuals;
  	   virtuals = TREE_CHAIN (virtuals))
  	{
! 	  tree base_fndecl = TREE_VALUE (virtuals);
  	  if (DECL_NEEDS_FINAL_OVERRIDER_P (base_fndecl))
  	    cp_error ("`%#D' needs a final overrider", base_fndecl);
  	}
--- 2341,2347 ----
  	   virtuals;
  	   virtuals = TREE_CHAIN (virtuals))
  	{
! 	  tree base_fndecl = BV_FN (virtuals);
  	  if (DECL_NEEDS_FINAL_OVERRIDER_P (base_fndecl))
  	    cp_error ("`%#D' needs a final overrider", base_fndecl);
  	}
Index: semantics.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/semantics.c,v
retrieving revision 1.150
diff -c -p -r1.150 semantics.c
*** semantics.c	2000/06/16 15:35:10	1.150
--- semantics.c	2000/06/23 01:00:05
*************** static tree expand_cond PARAMS ((tree));
*** 50,55 ****
--- 50,56 ----
  static tree maybe_convert_cond PARAMS ((tree));
  static tree simplify_aggr_init_exprs_r PARAMS ((tree *, int *, void *));
  static void deferred_type_access_control PARAMS ((void));
+ static void emit_associated_thunks PARAMS ((tree));
  
  /* Record the fact that STMT was the last statement added to the
     statement tree.  */
*************** simplify_aggr_init_exprs_r (tp, walk_sub
*** 2774,2779 ****
--- 2775,2827 ----
    return NULL_TREE;
  }
  
+ /* Emit all thunks to FN that should be emitted when FN is emitted.  */
+ 
+ static void
+ emit_associated_thunks (fn)
+      tree fn;
+ {
+   /* When we use vcall offsets, we emit thunks with the virtual
+      functions to which they thunk. The whole point of vcall offsets
+      is so that you can know statically the entire set of thunks that
+      will ever be needed for a given virtual function, thereby
+      enabling you to output all the thunks with the function itself.  */
+   if (vcall_offsets_in_vtable_p () && DECL_VIRTUAL_P (fn))
+     {
+       tree binfo;
+       tree v;
+ 
+       for (binfo = TYPE_BINFO (DECL_CONTEXT (fn));
+ 	   binfo;
+ 	   binfo = TREE_CHAIN (binfo))
+ 	for (v = BINFO_VIRTUALS (binfo); v; v = TREE_CHAIN (v))
+ 	  if (BV_FN (v) == fn
+ 	      && (!integer_zerop (BV_DELTA (v))
+ 		  || BV_VCALL_INDEX (v)))
+ 	    {
+ 	      tree thunk;
+ 	      tree vcall_index;
+ 
+ 	      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;
+ 
+ 	      thunk = make_thunk (build1 (ADDR_EXPR,
+ 					  vfunc_ptr_type_node,
+ 					  fn),
+ 				  BV_DELTA (v),
+ 				  vcall_index,
+ 				  /*generate_with_vtable_p=*/0);
+ 	      use_thunk (thunk, /*emit_p=*/1);
+ 	    }
+     }
+ }
+ 
+ 
  /* Generate RTL for FN.  */
  
  void
*************** expand_body (fn)
*** 2848,2853 ****
--- 2896,2904 ----
        note_deferral_of_defined_inline_function (fn);
        return;
      }
+ 
+   /* Emit any thunks that should be emitted at the same time as FN.  */
+   emit_associated_thunks (fn);
  
    timevar_push (TV_INTEGRATION);
  


More information about the Gcc-patches mailing list