class.c (modify_vtable_entry): Remove unused variable.

cp:
	* class.c (modify_vtable_entry): Remove unused variable.
	(get_vcall_index): Always expect a non-thunk.
	(update_vtable_entry_for_fn): Combine covariant adjustments, when
	overriding a thunk. Pass get_vcall_index a non-thunk.

	* decl2.c (finish_file): Mark undefined inlines as extern.
testsuite:
	* g++.dg/inherit/covariant8.C: New test.

From-SVN: r60710
This commit is contained in:
Nathan Sidwell 2002-12-31 19:43:16 +00:00 committed by Nathan Sidwell
parent 3b41afd944
commit 3cfabe60d4
6 changed files with 142 additions and 68 deletions

View File

@ -1,3 +1,12 @@
2002-12-31 Nathan Sidwell <nathan@codesourcery.com>
* class.c (modify_vtable_entry): Remove unused variable.
(get_vcall_index): Always expect a non-thunk.
(update_vtable_entry_for_fn): Combine covariant adjustments, when
overriding a thunk. Pass get_vcall_index a non-thunk.
* decl2.c (finish_file): Mark undefined inlines as extern.
2002-12-31 Mark Mitchell <mark@codesourcery.com>
* cp-tree.def (RETURN_INIT): Remove.

View File

@ -716,8 +716,6 @@ modify_vtable_entry (t, binfo, fndecl, delta, virtuals)
if (fndecl != BV_FN (v)
|| !tree_int_cst_equal (delta, BV_DELTA (v)))
{
tree base_fndecl;
/* We need a new vtable for BINFO. */
if (make_new_vtable (t, binfo))
{
@ -730,7 +728,6 @@ modify_vtable_entry (t, binfo, fndecl, delta, virtuals)
v = *virtuals;
}
base_fndecl = BV_FN (v);
BV_DELTA (v) = delta;
BV_VCALL_INDEX (v) = NULL_TREE;
BV_FN (v) = fndecl;
@ -2331,9 +2328,6 @@ get_vcall_index (tree fn, tree type)
{
tree v;
if (DECL_THUNK_P (fn))
fn = THUNK_TARGET (fn);
for (v = CLASSTYPE_VCALL_INDICES (type); v; v = TREE_CHAIN (v))
if ((DECL_DESTRUCTOR_P (fn) && DECL_DESTRUCTOR_P (TREE_PURPOSE (v)))
|| same_signature_p (fn, TREE_PURPOSE (v)))
@ -2361,18 +2355,18 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals)
tree delta;
tree virtual_base;
tree first_defn;
tree overrider_fn, overrider_target;
tree target_fn = DECL_THUNK_P (fn) ? THUNK_TARGET (fn) : fn;
tree over_return, base_return;
bool lost = false;
if (DECL_THUNK_P (fn))
fn = THUNK_TARGET (fn);
/* Find the nearest primary base (possibly binfo itself) which defines
this function; this is the class the caller will convert to when
calling FN through BINFO. */
for (b = binfo; ; b = get_primary_binfo (b))
{
my_friendly_assert (b, 20021227);
if (look_for_overrides_here (BINFO_TYPE (b), fn))
if (look_for_overrides_here (BINFO_TYPE (b), target_fn))
break;
/* The nearest definition is from a lost primary. */
@ -2382,58 +2376,85 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals)
first_defn = b;
/* Find the final overrider. */
overrider = find_final_overrider (TYPE_BINFO (t), b, fn);
overrider = find_final_overrider (TYPE_BINFO (t), b, target_fn);
if (overrider == error_mark_node)
return;
{
/* Check for adjusting covariant return types. */
tree over_return = TREE_TYPE (TREE_TYPE (TREE_PURPOSE (overrider)));
tree base_return = TREE_TYPE (TREE_TYPE (fn));
overrider_target = overrider_fn = TREE_PURPOSE (overrider);
/* Check for adjusting covariant return types. */
over_return = TREE_TYPE (TREE_TYPE (overrider_target));
base_return = TREE_TYPE (TREE_TYPE (target_fn));
if (POINTER_TYPE_P (over_return)
&& TREE_CODE (over_return) == TREE_CODE (base_return)
&& CLASS_TYPE_P (TREE_TYPE (over_return))
&& CLASS_TYPE_P (TREE_TYPE (base_return)))
{
/* If FN is a covariant thunk, we must figure out the adjustment
to the final base FN was converting to. As OVERRIDER_TARGET might
also be converting to the return type of FN, we have to
combine the two conversions here. */
tree fixed_offset, virtual_offset;
if (DECL_THUNK_P (fn))
{
fixed_offset = ssize_int (THUNK_FIXED_OFFSET (fn));
virtual_offset = THUNK_VIRTUAL_OFFSET (fn);
if (virtual_offset)
virtual_offset = binfo_for_vbase (BINFO_TYPE (virtual_offset),
TREE_TYPE (over_return));
}
else
fixed_offset = virtual_offset = NULL_TREE;
if (POINTER_TYPE_P (over_return)
&& TREE_CODE (over_return) == TREE_CODE (base_return)
&& CLASS_TYPE_P (TREE_TYPE (over_return))
&& CLASS_TYPE_P (TREE_TYPE (base_return)))
{
tree binfo;
base_kind kind;
if (!virtual_offset)
{
/* There was no existing virtual thunk (which takes
precidence). */
tree thunk_binfo;
base_kind kind;
thunk_binfo = lookup_base (TREE_TYPE (over_return),
TREE_TYPE (base_return),
ba_check | ba_quiet, &kind);
binfo = lookup_base (TREE_TYPE (over_return), TREE_TYPE (base_return),
ba_check | ba_quiet, &kind);
if (binfo && (kind == bk_via_virtual || !BINFO_OFFSET_ZEROP (binfo)))
{
tree fixed_offset = BINFO_OFFSET (binfo);
tree virtual_offset = NULL_TREE;
tree thunk;
if (kind == bk_via_virtual)
{
while (!TREE_VIA_VIRTUAL (binfo))
binfo = BINFO_INHERITANCE_CHAIN (binfo);
/* If the covariant type is within the class hierarchy
we are currently laying out, the vbase index is not
yet known, so we have to remember the virtual base
binfo. */
virtual_offset = binfo_for_vbase (BINFO_TYPE (binfo),
TREE_TYPE (over_return));
fixed_offset = size_diffop (fixed_offset,
BINFO_OFFSET (virtual_offset));
}
/* Replace the overriding function with a covariant thunk.
We will emit the overriding function in its own slot
as well. */
thunk = make_thunk (TREE_PURPOSE (overrider), /*this_adjusting=*/0,
fixed_offset, virtual_offset);
TREE_PURPOSE (overrider) = thunk;
if (!virtual_offset && !DECL_NAME (thunk))
finish_thunk (thunk);
}
}
}
if (thunk_binfo && (kind == bk_via_virtual
|| !BINFO_OFFSET_ZEROP (thunk_binfo)))
{
tree offset = BINFO_OFFSET (thunk_binfo);
if (kind == bk_via_virtual)
{
/* We convert via virtual base. Find the virtual
base and adjust the fixed offset to be from there. */
while (!TREE_VIA_VIRTUAL (thunk_binfo))
thunk_binfo = BINFO_INHERITANCE_CHAIN (thunk_binfo);
virtual_offset = binfo_for_vbase (BINFO_TYPE (thunk_binfo),
TREE_TYPE (over_return));
offset = size_diffop (offset,
BINFO_OFFSET (virtual_offset));
}
if (fixed_offset)
/* There was an existing fixed offset, this must be
from the base just converted to, and the base the
FN was thunking to. */
fixed_offset = size_binop (PLUS_EXPR, fixed_offset, offset);
else
fixed_offset = offset;
}
}
if (fixed_offset || virtual_offset)
/* Replace the overriding function with a covariant thunk. We
will emit the overriding function in its own slot as
well. */
overrider_fn = make_thunk (overrider_target, /*this_adjusting=*/0,
fixed_offset, virtual_offset);
}
else
my_friendly_assert (!DECL_THUNK_P (fn), 20021231);
/* 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;
@ -2476,16 +2497,11 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals)
delta = size_diffop (BINFO_OFFSET (TREE_VALUE (overrider)),
BINFO_OFFSET (binfo));
modify_vtable_entry (t,
binfo,
TREE_PURPOSE (overrider),
delta,
virtuals);
modify_vtable_entry (t, binfo, overrider_fn, delta, virtuals);
if (virtual_base)
BV_VCALL_INDEX (*virtuals)
= get_vcall_index (TREE_PURPOSE (overrider),
BINFO_TYPE (virtual_base));
= get_vcall_index (overrider_target, BINFO_TYPE (virtual_base));
}
/* Called from modify_all_vtables via dfs_walk. */

View File

@ -2977,9 +2977,13 @@ struct lang_decl GTY(())
/* A tree indicating how to perform the virtual adjustment. For a this
adjusting thunk it is the number of bytes to be added to the vtable
to find the vcall offset. For a result adjusting thunk, it is the
binfo of the relevant virtual base. The vptr is always located at
offset zero from the this or result pointer. If NULL, then there
is no virtual adjust. */
binfo of the relevant virtual base. If NULL, then there is no
virtual adjust. (The vptr is always located at offset zero from
the this or result pointer.) (If the covariant type is within the
class hierarchy being layed out, the vbase index is not yet known
at the point we need to create the thunks, hence the need to use
binfos.) */
#define THUNK_VIRTUAL_OFFSET(DECL) \
(LANG_DECL_U2_CHECK (VAR_OR_FUNCTION_DECL_CHECK (DECL), 0)->virtual_offset)

View File

@ -2802,7 +2802,14 @@ finish_file ()
if (TREE_USED (decl) && DECL_DECLARED_INLINE_P (decl)
&& !(TREE_ASM_WRITTEN (decl) || DECL_SAVED_TREE (decl)))
cp_warning_at ("inline function `%D' used but never defined", decl);
{
cp_warning_at ("inline function `%D' used but never defined", decl);
/* This symbol is effectively an "extern" declaration now.
This is not strictly necessary, but removes a duplicate
warning. */
TREE_PUBLIC (decl) = 1;
}
}
/* We give C linkage to static constructors and destructors. */

View File

@ -1,3 +1,7 @@
2002-12-31 Nathan Sidwell <nathan@codesourcery.com>
* g++.dg/inherit/covariant8.C: New test.
2002-12-31 Mark Mitchell <mark@codesourcery.com>
* g++.dg/init/array9.C: New test.

View File

@ -0,0 +1,34 @@
// { dg-do compile }
// Copyright (C) 2002 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 31 Dec 2002 <nathan@codesourcery.com>
// ICE with covariant thunks.
struct c0 {};
struct c1 : virtual c0
{
virtual c0 &f2 ();
};
struct c2
{
int m;
};
struct c3 : virtual c0, virtual c1, c2
{
virtual c1 &f2 ();
};
c1 &c3::f2 ()
{
throw 0;
}
struct c4 : virtual c3, virtual c0, virtual c1 {};
struct c8 : virtual c2, virtual c0 {};
struct c12 : virtual c4, virtual c3, virtual c8 {};