mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-19 15:11:08 +08:00
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:
parent
3950dcdfcc
commit
e00853fd90
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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) \
|
||||
|
@ -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;
|
||||
|
@ -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))
|
||||
|
@ -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.
|
||||
|
85
gcc/testsuite/g++.dg/abi/covariant3.C
Normal file
85
gcc/testsuite/g++.dg/abi/covariant3.C
Normal 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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user