This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[C++ PATCH]:Fix 13118
- From: Nathan Sidwell <nathan at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: Mark Mitchell <mitchell at codesourcery dot com>
- Date: Fri, 12 Dec 2003 18:23:06 +0000
- Subject: [C++ PATCH]:Fix 13118
- Organization: Codesourcery LLC
Hi,
I've installed this patch to fix 13118, a missing covariant thunk. When
overriding a virtual covaraint thunk, we need to find the equivalent virtual
base within the return type of the overriding function. Unfortunately
I was overloading the VIRTUAL_OFFSET slot with the THUNK_ALIAS slot, but
this patch requires both to be present. Luckily I found another spare slot.
This also simplifies the complexity I just added when fixing 12881. Ho hum.
booted & tested on i686-pc-linux-gnu.
nathan
--
Nathan Sidwell :: http://www.codesourcery.com :: CodeSourcery LLC
The voices in my head said this was stupid too
nathan@codesourcery.com :: http://www.planetfall.pwp.blueyonder.co.uk
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.
Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/class.c,v
retrieving revision 1.585
diff -c -3 -p -r1.585 class.c
*** cp/class.c 12 Dec 2003 14:48:30 -0000 1.585
--- cp/class.c 12 Dec 2003 16:50:14 -0000
*************** update_vtable_entry_for_fn (tree t, tree
*** 2168,2180 ****
if (DECL_THUNK_P (fn))
{
fixed_offset = ssize_int (THUNK_FIXED_OFFSET (fn));
virtual_offset = THUNK_VIRTUAL_OFFSET (fn);
}
else
fixed_offset = virtual_offset = NULL_TREE;
! if (!virtual_offset)
{
/* There was no existing virtual thunk (which takes
precedence). */
--- 2168,2189 ----
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)
! /* 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). */
*************** dump_thunk (FILE *stream, int indent, tr
*** 6715,6725 ****
!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
{
HOST_WIDE_INT fixed_adjust = THUNK_FIXED_OFFSET (thunk);
tree virtual_adjust = THUNK_VIRTUAL_OFFSET (thunk);
--- 6724,6730 ----
!DECL_THUNK_P (thunk) ? "function"
: DECL_THIS_THUNK_P (thunk) ? "this-thunk" : "covariant-thunk",
name ? IDENTIFIER_POINTER (name) : "<unset>");
! if (DECL_THUNK_P (thunk))
{
HOST_WIDE_INT fixed_adjust = THUNK_FIXED_OFFSET (thunk);
tree virtual_adjust = THUNK_VIRTUAL_OFFSET (thunk);
*************** dump_thunk (FILE *stream, int indent, tr
*** 6734,6739 ****
--- 6739,6746 ----
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))
*************** build_vtbl_initializer (tree binfo,
*** 7406,7412 ****
{
if (!DECL_NAME (fn))
finish_thunk (fn);
! if (THUNK_ALIAS_P (fn))
{
fn = THUNK_ALIAS (fn);
BV_FN (v) = fn;
--- 7413,7419 ----
{
if (!DECL_NAME (fn))
finish_thunk (fn);
! if (THUNK_ALIAS (fn))
{
fn = THUNK_ALIAS (fn);
BV_FN (v) = fn;
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.938
diff -c -3 -p -r1.938 cp-tree.h
*** cp/cp-tree.h 10 Dec 2003 14:06:21 -0000 1.938
--- cp/cp-tree.h 12 Dec 2003 16:50:27 -0000
*************** struct lang_decl_flags GTY(())
*** 1634,1645 ****
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. */
tree GTY ((tag ("0"))) template_info;
/* In a NAMESPACE_DECL, this is NAMESPACE_LEVEL. */
struct cp_binding_level * GTY ((tag ("1"))) level;
} GTY ((desc ("%1.u1sel"))) u;
union lang_decl_u2 {
--- 1634,1650 ----
unsigned this_thunk_p : 1;
union lang_decl_u {
! /* 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 {
*************** struct lang_decl GTY(())
*** 2859,2870 ****
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.
!
! 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. */
/* An integer indicating how many bytes should be subtracted from the
this or result pointer when this function is called. */
--- 2864,2880 ----
for the result pointer adjustment.
The constant adjustment is given by THUNK_FIXED_OFFSET. If the
! 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.
!
! 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. */
*************** struct lang_decl GTY(())
*** 2882,2896 ****
binfos.) */
#define THUNK_VIRTUAL_OFFSET(DECL) \
! (LANG_DECL_U2_CHECK (VAR_OR_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)
/* For thunk NODE, this is the FUNCTION_DECL thunked to. */
#define THUNK_TARGET(NODE) \
--- 2892,2902 ----
binfos.) */
#define THUNK_VIRTUAL_OFFSET(DECL) \
! (LANG_DECL_U2_CHECK (FUNCTION_DECL_CHECK (DECL), 0)->virtual_offset)
/* A thunk which is equivalent to another thunk. */
! #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) \
Index: cp/method.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/method.c,v
retrieving revision 1.272
diff -c -3 -p -r1.272 method.c
*** cp/method.c 12 Dec 2003 14:06:51 -0000 1.272
--- cp/method.c 12 Dec 2003 16:50:32 -0000
*************** make_thunk (tree function, bool this_adj
*** 124,174 ****
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;
! }
! }
/* All thunks must be created before FUNCTION is actually emitted;
the ABI requires that all thunks be emitted together with the
--- 124,138 ----
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
! && !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
*************** make_thunk (tree function, bool this_adj
*** 195,200 ****
--- 159,165 ----
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. */
*************** finish_thunk (tree thunk)
*** 254,260 ****
if (DECL_NAME (cov_probe) == name)
{
my_friendly_assert (!DECL_THUNKS (thunk), 20031023);
! THUNK_ALIAS (thunk) = (THUNK_ALIAS_P (cov_probe)
? THUNK_ALIAS (cov_probe) : cov_probe);
break;
}
--- 219,225 ----
if (DECL_NAME (cov_probe) == name)
{
my_friendly_assert (!DECL_THUNKS (thunk), 20031023);
! THUNK_ALIAS (thunk) = (THUNK_ALIAS (cov_probe)
? THUNK_ALIAS (cov_probe) : cov_probe);
break;
}
*************** use_thunk (tree thunk_fndecl, bool emit_
*** 376,382 ****
/* We should never be using an alias, always refer to the
aliased thunk. */
! my_friendly_assert (!THUNK_ALIAS_P (thunk_fndecl), 20031023);
if (TREE_ASM_WRITTEN (thunk_fndecl))
return;
--- 341,347 ----
/* We should never be using an alias, always refer to the
aliased thunk. */
! my_friendly_assert (!THUNK_ALIAS (thunk_fndecl), 20031023);
if (TREE_ASM_WRITTEN (thunk_fndecl))
return;
Index: cp/semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.374
diff -c -3 -p -r1.374 semantics.c
*** cp/semantics.c 4 Dec 2003 05:02:18 -0000 1.374
--- cp/semantics.c 12 Dec 2003 16:50:40 -0000
*************** emit_associated_thunks (tree fn)
*** 2836,2842 ****
for (thunk = DECL_THUNKS (fn); thunk; thunk = TREE_CHAIN (thunk))
{
! if (!THUNK_ALIAS_P (thunk))
{
use_thunk (thunk, /*emit_p=*/1);
if (DECL_RESULT_THUNK_P (thunk))
--- 2836,2842 ----
for (thunk = DECL_THUNKS (fn); thunk; thunk = TREE_CHAIN (thunk))
{
! if (!THUNK_ALIAS (thunk))
{
use_thunk (thunk, /*emit_p=*/1);
if (DECL_RESULT_THUNK_P (thunk))
// { 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;
}