aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@codesourcery.com>2003-12-12 18:22:23 +0000
committerNathan Sidwell <nathan@gcc.gnu.org>2003-12-12 18:22:23 +0000
commite00853fd9010af463931114e469875303b7bf876 (patch)
treee4c56658ea817e7905726e5e9476381df44a1c17 /gcc
parent3950dcdfccd66e077b1be064826aac76122f4bb4 (diff)
downloadgcc-e00853fd9010af463931114e469875303b7bf876.zip
gcc-e00853fd9010af463931114e469875303b7bf876.tar.gz
gcc-e00853fd9010af463931114e469875303b7bf876.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog15
-rw-r--r--gcc/cp/class.c21
-rw-r--r--gcc/cp/cp-tree.h36
-rw-r--r--gcc/cp/method.c59
-rw-r--r--gcc/cp/semantics.c2
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/abi/covariant3.C85
7 files changed, 153 insertions, 70 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 6b57a91..427a36b 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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.
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index bc44452..ff615fe 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -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;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 968d0b3..250318e 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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.
-
- 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. */
+ 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. */
@@ -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) \
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index a08ae6b..bd1e2ad 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -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;
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index a5e93a2..8039ca78 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -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))
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 62c363e..cabc671 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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.
diff --git a/gcc/testsuite/g++.dg/abi/covariant3.C b/gcc/testsuite/g++.dg/abi/covariant3.C
new file mode 100644
index 0000000..178157c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/covariant3.C
@@ -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;
+}