This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PATCH Re: c++/4122: undefined reference to `non-virtual thunk to...'


Thanks for the testcase; please give this a try.  The problem was that we
had calculated the -4 offset for a lost primary, the primary base was
regained in the constructor vtable, and so the calculated offset was
wrong.

2001-12-21  Jason Merrill  <jason@redhat.com>

	* class.c (update_vtable_entry_for_fn): Set delta to zero for a
	lost primary.

	* class.c (build_vtbl_initializer): Check for a lost primary
	before calculating the vtable entry to throw away.

*** class.c.~1~	Tue Dec 18 15:17:39 2001
--- class.c	Fri Dec 21 17:55:14 2001
*************** update_vtable_entry_for_fn (t, binfo, fn
*** 2494,2499 ****
--- 2494,2500 ----
    tree delta;
    tree virtual_base;
    tree first_defn;
+   bool lost = false;
  
    /* Find the nearest primary base (possibly binfo itself) which defines
       this function; this is the class the caller will convert to when
*************** update_vtable_entry_for_fn (t, binfo, fn
*** 2502,2507 ****
--- 2503,2512 ----
      {
        if (look_for_overrides_here (BINFO_TYPE (b), fn))
  	break;
+ 
+       /* The nearest definition is from a lost primary.  */
+       if (BINFO_LOST_PRIMARY_P (b))
+ 	lost = true;
      }
    first_defn = b;
  
*************** update_vtable_entry_for_fn (t, binfo, fn
*** 2514,2522 ****
       the final overrider, and not to an intermediate virtual base.  */
    virtual_base = NULL_TREE;
  
!   /* We will convert to an intermediate virtual base first, and then
       use the vcall offset located there to finish the conversion.  */
!   while (b)
      {
        /* If we find the final overrider, then we can stop
  	 walking.  */
--- 2519,2527 ----
       the final overrider, and not to an intermediate virtual base.  */
    virtual_base = NULL_TREE;
  
!   /* See if we can convert to an intermediate virtual base first, and then
       use the vcall offset located there to finish the conversion.  */
!   for (; b; b = BINFO_INHERITANCE_CHAIN (b))
      {
        /* If we find the final overrider, then we can stop
  	 walking.  */
*************** update_vtable_entry_for_fn (t, binfo, fn
*** 2529,2536 ****
  	 declaring base (first_defn) and the final overrider.  */
        if (!virtual_base && TREE_VIA_VIRTUAL (b))
  	virtual_base = b;
- 
-       b = BINFO_INHERITANCE_CHAIN (b);
      }
  
    /* Compute the constant adjustment to the `this' pointer.  The
--- 2534,2539 ----
*************** update_vtable_entry_for_fn (t, binfo, fn
*** 2542,2547 ****
--- 2545,2556 ----
         the nearest virtual base.  */
      delta = size_diffop (BINFO_OFFSET (virtual_base),
  			 BINFO_OFFSET (first_defn));
+   else if (lost)
+     /* If the nearest definition is in a lost primary, we don't need an
+        entry in our vtable.  Except possibly in a constructor vtable,
+        if we happen to get our primary back.  In that case, the offset
+        will be zero, as it will be a primary base.  */
+     delta = size_zero_node;
    else
      {
        /* The `this' pointer needs to be adjusted from pointing to
*************** build_vtbl_initializer (binfo, orig_binf
*** 7502,7563 ****
        tree vcall_index;
        tree fn;
        tree pfn;
!       tree init;
        
-       /* Pull the offset for `this', and the function to call, out of
- 	 the list.  */
-       delta = BV_DELTA (v);
- 
-       if (BV_USE_VCALL_INDEX_P (v))
- 	{
- 	  vcall_index = BV_VCALL_INDEX (v);
- 	  my_friendly_assert (vcall_index != NULL_TREE, 20000621);
- 	}
-       else
-         vcall_index = NULL_TREE;
- 
        fn = BV_FN (v);
-       my_friendly_assert (TREE_CODE (delta) == INTEGER_CST, 19990727);
-       my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727);
- 
-       /* You can't call an abstract virtual function; it's abstract.
- 	 So, we replace these functions with __pure_virtual.  */
-       if (DECL_PURE_VIRTUAL_P (fn))
- 	fn = abort_fndecl;
- 
-       /* Take the address of the function, considering it to be of an
- 	 appropriate generic type.  */
-       pfn = build1 (ADDR_EXPR, vfunc_ptr_type_node, fn);
-       /* The address of a function can't change.  */
-       TREE_CONSTANT (pfn) = 1;
- 
-       /* Enter it in the vtable.  */
-       init = build_vtable_entry (delta, vcall_index, pfn);
  
        /* If the only definition of this function signature along our
  	 primary base chain is from a lost primary, this vtable slot will
  	 never be used, so just zero it out.  This is important to avoid
  	 requiring extra thunks which cannot be generated with the function.
  
! 	 We could also handle this in update_vtable_entry_for_fn; doing it
! 	 here means we zero out unused slots in ctor vtables as well,
! 	 rather than filling them with erroneous values (though harmless,
! 	 apart from relocation costs).  */
!       if (fn != abort_fndecl)
! 	for (b = binfo; ; b = get_primary_binfo (b))
! 	  {
! 	    /* We found a defn before a lost primary; go ahead as normal.  */
! 	    if (look_for_overrides_here (BINFO_TYPE (b), fn))
  	      break;
  
! 	    /* The nearest definition is from a lost primary; clear the
! 	       slot.  */
! 	    if (BINFO_LOST_PRIMARY_P (b))
! 	      {
! 		init = size_zero_node;
! 		break;
! 	      }
! 	  }
  
        /* And add it to the chain of initializers.  */
        if (TARGET_VTABLE_USES_DESCRIPTORS)
--- 7511,7576 ----
        tree vcall_index;
        tree fn;
        tree pfn;
!       tree init = NULL_TREE;
        
        fn = BV_FN (v);
  
        /* If the only definition of this function signature along our
  	 primary base chain is from a lost primary, this vtable slot will
  	 never be used, so just zero it out.  This is important to avoid
  	 requiring extra thunks which cannot be generated with the function.
  
! 	 We first check this in update_vtable_entry_for_fn, so we handle
! 	 restored primary bases properly; we also need to do it here so we
! 	 zero out unused slots in ctor vtables, rather than filling themff
! 	 with erroneous values (though harmless, apart from relocation
! 	 costs).  */
!       for (b = binfo; ; b = get_primary_binfo (b))
! 	{
! 	  /* We found a defn before a lost primary; go ahead as normal.  */
! 	  if (look_for_overrides_here (BINFO_TYPE (b), fn))
! 	    break;
! 
! 	  /* The nearest definition is from a lost primary; clear the
! 	     slot.  */
! 	  if (BINFO_LOST_PRIMARY_P (b))
! 	    {
! 	      init = size_zero_node;
  	      break;
+ 	    }
+ 	}
  
!       if (! init)
! 	{
! 	  /* Pull the offset for `this', and the function to call, out of
! 	     the list.  */
! 	  delta = BV_DELTA (v);
! 
! 	  if (BV_USE_VCALL_INDEX_P (v))
! 	    {
! 	      vcall_index = BV_VCALL_INDEX (v);
! 	      my_friendly_assert (vcall_index != NULL_TREE, 20000621);
! 	    }
! 	  else
! 	    vcall_index = NULL_TREE;
! 
! 	  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.  */
        if (TARGET_VTABLE_USES_DESCRIPTORS)

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]