This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
PATCH Re: c++/4122: undefined reference to `non-virtual thunk to...'
- From: Jason Merrill <jason at redhat dot com>
- To: Robert Boehne <rboehne at ricardo-us dot com>
- Cc: gcc-gnats at gcc dot gnu dot org, juergen at monocerus dot demon dot co dot uk, boehme at informatik dot hu-berlin dot de, loewis at informatik dot hu-berlin dot de, gcc-bugs at gcc dot gnu dot org, michael at ritzert dot de, gcc-patches at gcc dot gnu dot org
- Date: Fri, 21 Dec 2001 18:42:09 +0000
- Subject: PATCH Re: c++/4122: undefined reference to `non-virtual thunk to...'
- References: <3C21517D.23651617@ricardo-us.com><wvllmfyd1uo.fsf@prospero.cambridge.redhat.com><3C220D58.921A8A80@ricardo-us.com>
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)