diff options
author | Nathan Sidwell <nathan@codesourcery.com> | 2003-12-12 18:22:23 +0000 |
---|---|---|
committer | Nathan Sidwell <nathan@gcc.gnu.org> | 2003-12-12 18:22:23 +0000 |
commit | e00853fd9010af463931114e469875303b7bf876 (patch) | |
tree | e4c56658ea817e7905726e5e9476381df44a1c17 /gcc | |
parent | 3950dcdfccd66e077b1be064826aac76122f4bb4 (diff) | |
download | gcc-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/ChangeLog | 15 | ||||
-rw-r--r-- | gcc/cp/class.c | 21 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 36 | ||||
-rw-r--r-- | gcc/cp/method.c | 59 | ||||
-rw-r--r-- | gcc/cp/semantics.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/abi/covariant3.C | 85 |
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; +} |