re PR c++/13118 ([ABI] Missed covariant return thunk)

cp:
	PR c++/13118
	* cp-tree.h (lang_decl_u): Add thunk_alias member.
	(THUNK_VIRTUAL_OFFSET): Must be a FUNCTION_DECL.
	(THUNK_ALIAS_P): Remove.
	(THUNK_ALIAS): Adjust.
	* class.c (update_vtable_entry_for_fn): Get the vbase within the
	overriding function's return type.
	(dump_thunk): Adjust THUNK_ALIAS printing.
	(build_vtbl_initializer): Adjust THUNK_ALIAS use.
	* method.c (make_thunk): Revert 12881 test change. Clear
	THUNK_ALIAS.
	(finish_thunk): Adjust THUNK_ALIAS setting.
	(use_thunk): Adjust THUNK_ALIAS use.
	* semantics.c (emit_associated_thunks): Likewise.
testsuite:
	PR c++/13118
	* g++.dg/abi/covariant3.C: New.

From-SVN: r74576
This commit is contained in:
Nathan Sidwell 2003-12-12 18:22:23 +00:00 committed by Nathan Sidwell
parent 3950dcdfcc
commit e00853fd90
7 changed files with 152 additions and 69 deletions

View File

@ -1,5 +1,20 @@
2003-12-12 Nathan Sidwell <nathan@codesourcery.com>
PR c++/13118
* cp-tree.h (lang_decl_u): Add thunk_alias member.
(THUNK_VIRTUAL_OFFSET): Must be a FUNCTION_DECL.
(THUNK_ALIAS_P): Remove.
(THUNK_ALIAS): Adjust.
* class.c (update_vtable_entry_for_fn): Get the vbase within the
overriding function's return type.
(dump_thunk): Adjust THUNK_ALIAS printing.
(build_vtbl_initializer): Adjust THUNK_ALIAS use.
* method.c (make_thunk): Revert 12881 test change. Clear
THUNK_ALIAS.
(finish_thunk): Adjust THUNK_ALIAS setting.
(use_thunk): Adjust THUNK_ALIAS use.
* semantics.c (emit_associated_thunks): Likewise.
PR c++/13114, c++/13115
* class.c (layout_empty_base): Propagate the move of an empty base
to offset zero.

View File

@ -2168,13 +2168,22 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,
if (DECL_THUNK_P (fn))
{
my_friendly_assert (DECL_RESULT_THUNK_P (fn), 20031211);
fixed_offset = ssize_int (THUNK_FIXED_OFFSET (fn));
virtual_offset = THUNK_VIRTUAL_OFFSET (fn);
}
else
fixed_offset = virtual_offset = NULL_TREE;
if (!virtual_offset)
if (virtual_offset)
/* Find the equivalent binfo within the return type of the
overriding function. We will want the vbase offset from
there. */
virtual_offset =
TREE_VALUE (purpose_member
(BINFO_TYPE (virtual_offset),
CLASSTYPE_VBASECLASSES (TREE_TYPE (over_return))));
else
{
/* There was no existing virtual thunk (which takes
precedence). */
@ -6715,11 +6724,7 @@ dump_thunk (FILE *stream, int indent, tree thunk)
!DECL_THUNK_P (thunk) ? "function"
: DECL_THIS_THUNK_P (thunk) ? "this-thunk" : "covariant-thunk",
name ? IDENTIFIER_POINTER (name) : "<unset>");
if (!DECL_THUNK_P (thunk))
/*NOP*/;
else if (THUNK_ALIAS_P (thunk))
fprintf (stream, " alias to %p", (void *)THUNK_ALIAS (thunk));
else
if (DECL_THUNK_P (thunk))
{
HOST_WIDE_INT fixed_adjust = THUNK_FIXED_OFFSET (thunk);
tree virtual_adjust = THUNK_VIRTUAL_OFFSET (thunk);
@ -6734,6 +6739,8 @@ dump_thunk (FILE *stream, int indent, tree thunk)
fprintf (stream, " vbase=" HOST_WIDE_INT_PRINT_DEC "(%s)",
tree_low_cst (BINFO_VPTR_FIELD (virtual_adjust), 0),
type_as_string (BINFO_TYPE (virtual_adjust), TFF_SCOPE));
if (THUNK_ALIAS (thunk))
fprintf (stream, " alias to %p", (void *)THUNK_ALIAS (thunk));
}
fprintf (stream, "\n");
for (thunks = DECL_THUNKS (thunk); thunks; thunks = TREE_CHAIN (thunks))
@ -7406,7 +7413,7 @@ build_vtbl_initializer (tree binfo,
{
if (!DECL_NAME (fn))
finish_thunk (fn);
if (THUNK_ALIAS_P (fn))
if (THUNK_ALIAS (fn))
{
fn = THUNK_ALIAS (fn);
BV_FN (v) = fn;

View File

@ -1634,12 +1634,17 @@ struct lang_decl_flags GTY(())
unsigned this_thunk_p : 1;
union lang_decl_u {
/* In a FUNCTION_DECL, VAR_DECL, TYPE_DECL, or TEMPLATE_DECL, this
is DECL_TEMPLATE_INFO. */
/* In a FUNCTION_DECL for which DECL_THUNK_P does not hold,
VAR_DECL, TYPE_DECL, or TEMPLATE_DECL, this is
DECL_TEMPLATE_INFO. */
tree GTY ((tag ("0"))) template_info;
/* In a NAMESPACE_DECL, this is NAMESPACE_LEVEL. */
struct cp_binding_level * GTY ((tag ("1"))) level;
/* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is
THUNK_ALIAS. */
tree GTY ((tag ("2"))) thunk_alias;
} GTY ((desc ("%1.u1sel"))) u;
union lang_decl_u2 {
@ -2859,12 +2864,17 @@ struct lang_decl GTY(())
for the result pointer adjustment.
The constant adjustment is given by THUNK_FIXED_OFFSET. If the
vcall or vbase offset is required, the index into the vtable is given by
THUNK_VIRTUAL_OFFSET.
vcall or vbase offset is required, THUNK_VIRTUAL_OFFSET is
used. For this pointer adjusting thunks, it is the vcall offset
into the vtable. For result pointer adjusting thunks it is the
binfo of the virtual base to convert to. Use that binfo's vbase
offset.
Due to ordering constraints in class layout, it is possible to have
equivalent covariant thunks. THUNK_ALIAS_P and THUNK_ALIAS are used
in those cases. */
It is possible to have equivalent covariant thunks. These are
distinct virtual covariant thunks whose vbase offsets happen to
have the same value. THUNK_ALIAS is used to pick one as the
canonical thunk, which will get all the this pointer adjusting
thunks attached to it. */
/* An integer indicating how many bytes should be subtracted from the
this or result pointer when this function is called. */
@ -2882,15 +2892,11 @@ struct lang_decl GTY(())
binfos.) */
#define THUNK_VIRTUAL_OFFSET(DECL) \
(LANG_DECL_U2_CHECK (VAR_OR_FUNCTION_DECL_CHECK (DECL), 0)->virtual_offset)
(LANG_DECL_U2_CHECK (FUNCTION_DECL_CHECK (DECL), 0)->virtual_offset)
/* A thunk which is equivalent to another thunk. */
#define THUNK_ALIAS_P(DECL) \
(THUNK_VIRTUAL_OFFSET (DECL) && DECL_P (THUNK_VIRTUAL_OFFSET (DECL)))
/* When THUNK_ALIAS_P is true, this indicates the thunk which is
aliased. */
#define THUNK_ALIAS(DECL) THUNK_VIRTUAL_OFFSET (DECL)
#define THUNK_ALIAS(DECL) \
(DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (DECL))->decl_flags.u.thunk_alias)
/* For thunk NODE, this is the FUNCTION_DECL thunked to. */
#define THUNK_TARGET(NODE) \

View File

@ -124,51 +124,15 @@ make_thunk (tree function, bool this_adjusting,
thunks VIRTUAL_OFFSET will be an INTEGER_CST, for covariant thunks it
will be a BINFO. */
for (thunk = DECL_THUNKS (function); thunk; thunk = TREE_CHAIN (thunk))
{
if (DECL_THIS_THUNK_P (thunk) != this_adjusting
|| THUNK_FIXED_OFFSET (thunk) != d)
/*not me*/;
else if (this_adjusting)
{
if (!virtual_offset)
{
/* We want a non-virtual covariant thunk. */
if (!THUNK_VIRTUAL_OFFSET (thunk))
return thunk;
}
else if (THUNK_VIRTUAL_OFFSET (thunk))
{
if (tree_int_cst_equal (THUNK_VIRTUAL_OFFSET (thunk),
virtual_offset))
return thunk;
}
}
else
{
if (!virtual_offset)
{
/* We want a non-virtual covariant thunk. */
if (!THUNK_VIRTUAL_OFFSET (thunk))
return thunk;
}
else if (!THUNK_VIRTUAL_OFFSET (thunk))
/*not me*/;
else if (THUNK_ALIAS_P (thunk))
{
/* We have already determined the thunks for FUNCTION,
and there is a virtual covariant thunk alias. We
must compare the vbase offsets of the binfo we have
been given, and the binfo of the thunk. */
tree binfo = THUNK_VIRTUAL_OFFSET (THUNK_ALIAS (thunk));
if (tree_int_cst_equal (BINFO_VPTR_FIELD (virtual_offset),
BINFO_VPTR_FIELD (binfo)))
return THUNK_ALIAS (thunk);
}
else if (THUNK_VIRTUAL_OFFSET (thunk) == virtual_offset)
return thunk;
}
}
if (DECL_THIS_THUNK_P (thunk) == this_adjusting
&& THUNK_FIXED_OFFSET (thunk) == d
&& !virtual_offset == !THUNK_VIRTUAL_OFFSET (thunk)
&& (!virtual_offset
|| (this_adjusting
? tree_int_cst_equal (THUNK_VIRTUAL_OFFSET (thunk),
virtual_offset)
: THUNK_VIRTUAL_OFFSET (thunk) == virtual_offset)))
return thunk;
/* All thunks must be created before FUNCTION is actually emitted;
the ABI requires that all thunks be emitted together with the
@ -195,6 +159,7 @@ make_thunk (tree function, bool this_adjusting,
THUNK_TARGET (thunk) = function;
THUNK_FIXED_OFFSET (thunk) = d;
THUNK_VIRTUAL_OFFSET (thunk) = virtual_offset;
THUNK_ALIAS (thunk) = NULL_TREE;
/* The thunk itself is not a constructor or destructor, even if
the thing it is thunking to is. */
@ -254,7 +219,7 @@ finish_thunk (tree thunk)
if (DECL_NAME (cov_probe) == name)
{
my_friendly_assert (!DECL_THUNKS (thunk), 20031023);
THUNK_ALIAS (thunk) = (THUNK_ALIAS_P (cov_probe)
THUNK_ALIAS (thunk) = (THUNK_ALIAS (cov_probe)
? THUNK_ALIAS (cov_probe) : cov_probe);
break;
}
@ -376,7 +341,7 @@ use_thunk (tree thunk_fndecl, bool emit_p)
/* We should never be using an alias, always refer to the
aliased thunk. */
my_friendly_assert (!THUNK_ALIAS_P (thunk_fndecl), 20031023);
my_friendly_assert (!THUNK_ALIAS (thunk_fndecl), 20031023);
if (TREE_ASM_WRITTEN (thunk_fndecl))
return;

View File

@ -2836,7 +2836,7 @@ emit_associated_thunks (tree fn)
for (thunk = DECL_THUNKS (fn); thunk; thunk = TREE_CHAIN (thunk))
{
if (!THUNK_ALIAS_P (thunk))
if (!THUNK_ALIAS (thunk))
{
use_thunk (thunk, /*emit_p=*/1);
if (DECL_RESULT_THUNK_P (thunk))

View File

@ -1,3 +1,8 @@
2003-12-12 Nathan Sidwell <nathan@codesourcery.com>
PR c++/13118
* g++.dg/abi/covariant3.C: New.
2003-12-12 Jakub Jelinek <jakub@redhat.com>
* g++.dg/eh/ia64-1.C: New test.

View File

@ -0,0 +1,85 @@
// { dg-do run }
// Copyright (C) 2003 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 12 Dec 2003 <nathan@codesourcery.com>
// Origin: grigory@stl.sarov.ru
// PR c++/13118. Missing covariant thunk.
struct c0 {};
struct c1 : virtual c0 {
virtual c0* f6();
};
struct c5 {
virtual void foo();
};
struct c10 : virtual c1 {
virtual void foo();
};
struct c1a : c1 {}; // disambiguation
struct c11 : virtual c10, c1a {
int i;
virtual c1* f6 () = 0;
};
struct c18 : c5, virtual c1 {
virtual void bar();
};
struct c28 : virtual c0, virtual c11 {
virtual c18* f6();
};
c0 *c1::f6 () {}
void c5::foo () {}
void c10::foo () {}
void c18::bar () {}
c18 ret;
c18 *c28::f6 ()
{
return &ret;
}
bool check_c1 (c1 *ptr)
{
c0 *r = ptr->f6 ();
return r != &ret;
}
bool check_c10 (c10 *ptr)
{
c0 *r = ptr->f6 ();
return r != &ret;
}
bool check_c11 (c11 *ptr)
{
c1 *r = ptr->f6 ();
return r != &ret;
}
bool check_c28 (c28 *ptr)
{
c18 *r = ptr->f6 ();
return r != &ret;
}
int main ()
{
c28 obj;
if (check_c1 (static_cast<c1a *> (&obj)))
return 1;
if (check_c1 (static_cast<c10 *> (&obj)))
return 2;
if (check_c10 (&obj))
return 3;
if (check_c11 (&obj))
return 4;
if (check_c28 (&obj))
return 5;
return 0;
}