From 07fa4878595a4d496d066941d948186fe701afdf Mon Sep 17 00:00:00 2001 From: Nathan Sidwell <nathan@codesourcery.com> Date: Mon, 30 Dec 2002 13:39:48 +0000 Subject: [PATCH] cp-tree.h (THUNK_TARGET): New macro. cp: * cp-tree.h (THUNK_TARGET): New macro. (THUNK_VIRTUAL_OFFSET): For result thunks it is always a binfo. (finish_thunk): Remove offset parms. * class.c (find_final_overrider): Look through thunks. (get_vcall_index): Use THUNK_TARGET. (update_vtable_entry_for_fn): Look through thunks. Set covariant fixed offset here. Adjust finish_thunk call. (build_vtbl_initializer): Adjust finish_thunk calls. * mangle.c (mangle_call_offset): Remove superfluous if. (mangle_thunk): Adjust. * method.c (make_thunk): Adjust. (finish_thunk): Adjust. (thunk_adjust): Remove assert. (use_thunk): Use THUNK_TARGET * dump1.c (cp_dump_tree): Adjust thunk dumping. testsuite: * g++.dg/inherit/covariant5.C: New test. * g++.dg/inherit/covariant6.C: New test. * g++.dg/inherit/covariant7.C: New test. From-SVN: r60628 --- gcc/cp/class.c | 40 +++++++-------- gcc/cp/cp-tree.h | 25 +++++++--- gcc/cp/dump.c | 11 ++++- gcc/cp/mangle.c | 22 ++++----- gcc/cp/method.c | 59 ++++++++++++----------- gcc/testsuite/ChangeLog | 6 +++ gcc/testsuite/g++.dg/inherit/covariant5.C | 27 +++++++++++ gcc/testsuite/g++.dg/inherit/covariant6.C | 27 +++++++++++ gcc/testsuite/g++.dg/inherit/covariant7.C | 33 +++++++++++++ 9 files changed, 181 insertions(+), 69 deletions(-) create mode 100644 gcc/testsuite/g++.dg/inherit/covariant5.C create mode 100644 gcc/testsuite/g++.dg/inherit/covariant6.C create mode 100644 gcc/testsuite/g++.dg/inherit/covariant7.C diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 85d6d2addd75..0ce3f1134680 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -2299,6 +2299,9 @@ find_final_overrider (derived, binfo, fn) The solution is to look at all paths to BINFO. If we find different overriders along any two, then there is a problem. */ + if (DECL_THUNK_P (fn)) + fn = THUNK_TARGET (fn); + ffod.fn = fn; ffod.declaring_base = binfo; ffod.most_derived_type = BINFO_TYPE (derived); @@ -2328,8 +2331,8 @@ get_vcall_index (tree fn, tree type) { tree v; - if (DECL_RESULT_THUNK_P (fn)) - fn = TREE_OPERAND (DECL_INITIAL (fn), 0); + if (DECL_THUNK_P (fn)) + fn = THUNK_TARGET (fn); for (v = CLASSTYPE_VCALL_INDICES (type); v; v = TREE_CHAIN (v)) if ((DECL_DESTRUCTOR_P (fn) && DECL_DESTRUCTOR_P (TREE_PURPOSE (v))) @@ -2360,11 +2363,15 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals) tree first_defn; bool lost = false; + if (DECL_THUNK_P (fn)) + fn = THUNK_TARGET (fn); + /* Find the nearest primary base (possibly binfo itself) which defines this function; this is the class the caller will convert to when calling FN through BINFO. */ for (b = binfo; ; b = get_primary_binfo (b)) { + my_friendly_assert (b, 20021227); if (look_for_overrides_here (BINFO_TYPE (b), fn)) break; @@ -2408,10 +2415,11 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals) /* If the covariant type is within the class hierarchy we are currently laying out, the vbase index is not yet known, so we have to remember the virtual base - binfo for the moment. The thunk will be finished - in build_vtbl_initializer, where we'll know the - vtable index of the virtual base. */ - virtual_offset = binfo_for_vbase (BINFO_TYPE (binfo), t); + binfo. */ + virtual_offset = binfo_for_vbase (BINFO_TYPE (binfo), + TREE_TYPE (over_return)); + fixed_offset = size_diffop (fixed_offset, + BINFO_OFFSET (virtual_offset)); } /* Replace the overriding function with a covariant thunk. @@ -2421,7 +2429,7 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals) fixed_offset, virtual_offset); TREE_PURPOSE (overrider) = thunk; if (!virtual_offset && !DECL_NAME (thunk)) - finish_thunk (thunk, fixed_offset, NULL_TREE); + finish_thunk (thunk); } } } @@ -7739,18 +7747,12 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p) tree init = NULL_TREE; fn = BV_FN (v); - fn_original = (DECL_RESULT_THUNK_P (fn) - ? TREE_OPERAND (DECL_INITIAL (fn), 0) - : fn); - /* Finish an unfinished covariant thunk. */ - if (DECL_RESULT_THUNK_P (fn) && !DECL_NAME (fn)) + fn_original = fn; + if (DECL_THUNK_P (fn)) { - tree binfo = THUNK_VIRTUAL_OFFSET (fn); - tree fixed_offset = size_int (THUNK_FIXED_OFFSET (fn)); - tree virtual_offset = BINFO_VPTR_FIELD (binfo); - - fixed_offset = size_diffop (fixed_offset, BINFO_OFFSET (binfo)); - finish_thunk (fn, fixed_offset, virtual_offset); + if (!DECL_NAME (fn)) + finish_thunk (fn); + fn_original = THUNK_TARGET (fn); } /* If the only definition of this function signature along our @@ -7796,7 +7798,7 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p) { fn = make_thunk (fn, /*this_adjusting=*/1, delta, vcall_index); if (!DECL_NAME (fn)) - finish_thunk (fn, delta, THUNK_VIRTUAL_OFFSET (fn)); + finish_thunk (fn); } /* Take the address of the function, considering it to be of an appropriate generic type. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index c224e2a4f77b..6296731a080b 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1791,6 +1791,9 @@ struct lang_decl GTY(()) { struct full_lang_decl { + /* For a non-thunk function decl, this is a tree list of + friendly classes. For a thunk function decl, it is the + thunked to function decl. */ tree befriending_classes; /* For a non-virtual FUNCTION_DECL, this is @@ -2977,14 +2980,20 @@ struct lang_decl GTY(()) /* An integer indicating how many bytes should be subtracted from the this or result pointer when this function is called. */ #define THUNK_FIXED_OFFSET(DECL) \ - (DECL_LANG_SPECIFIC (DECL)->u.f.fixed_offset) - -/* A tree indicating how many bytes should be added to the - vtable for the this or result pointer to find the vcall or vbase - offset. (The vptr is always located at offset zero from the - this or result pointer.) If NULL, then there is no virtual adjust. */ + (DECL_LANG_SPECIFIC (VAR_OR_FUNCTION_DECL_CHECK (DECL))->u.f.fixed_offset) + +/* A tree indicating how to perform the virtual adjustment. For a this + adjusting thunk it is the number of bytes to be added to the vtable + to find the vcall offset. For a result adjusting thunk, it is the + binfo of the relevant virtual base. The vptr is always located at + offset zero from the this or result pointer. If NULL, then there + is no virtual adjust. */ #define THUNK_VIRTUAL_OFFSET(DECL) \ - (LANG_DECL_U2_CHECK (DECL, 0)->virtual_offset) + (LANG_DECL_U2_CHECK (VAR_OR_FUNCTION_DECL_CHECK (DECL), 0)->virtual_offset) + +/* For thunk NODE, this is the FUNCTION_DECL thunked to. */ +#define THUNK_TARGET(NODE) \ + (DECL_LANG_SPECIFIC (NODE)->u.f.befriending_classes) /* These macros provide convenient access to the various _STMT nodes created when parsing template declarations. */ @@ -3990,7 +3999,7 @@ extern void set_mangled_name_for_decl (tree); extern tree build_opfncall (enum tree_code, int, tree, tree, tree); extern tree hack_identifier (tree, tree); extern tree make_thunk (tree, bool, tree, tree); -extern void finish_thunk (tree, tree, tree); +extern void finish_thunk (tree); extern void use_thunk (tree, bool); extern void synthesize_method (tree); extern tree implicitly_declare_fn (special_function_kind, tree, bool); diff --git a/gcc/cp/dump.c b/gcc/cp/dump.c index da207d32917f..bb842bdcae23 100644 --- a/gcc/cp/dump.c +++ b/gcc/cp/dump.c @@ -336,13 +336,20 @@ cp_dump_tree (dump_info, t) } else { + tree virt = THUNK_VIRTUAL_OFFSET (t); + dump_string (di, "thunk"); if (DECL_THIS_THUNK_P (t)) dump_string (di, "this adjusting"); else - dump_string (di, "result adjusting"); + { + dump_string (di, "result adjusting"); + if (virt) + virt = BINFO_VPTR_FIELD (virt); + } dump_int (di, "fixd", THUNK_FIXED_OFFSET (t)); - dump_child ("virt", THUNK_VIRTUAL_OFFSET (t)); + if (virt) + dump_int (di, "virt", tree_low_cst (virt, 0)); dump_child ("fn", DECL_INITIAL (t)); } break; diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index cf106d518cd8..70443aab2583 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -2545,10 +2545,7 @@ mangle_call_offset (fixed_offset, virtual_offset) tree fixed_offset; tree virtual_offset; { - if (virtual_offset) - write_char (virtual_offset ? 'v' : 'h'); - else - write_char ('h'); + write_char (virtual_offset ? 'v' : 'h'); /* For either flavor, write the fixed offset. */ write_integer_cst (fixed_offset); @@ -2590,24 +2587,27 @@ mangle_thunk (fn_decl, this_adjusting, fixed_offset, virtual_offset) write_string ("_Z"); write_char ('T'); - if (this_adjusting && !DECL_RESULT_THUNK_P (fn_decl)) - /* Plain this adjusting thunk. */ - mangle_call_offset (fixed_offset, virtual_offset); - else if (!this_adjusting) + if (!this_adjusting) { /* Covariant thunk with no this adjustment */ write_char ('c'); mangle_call_offset (integer_zero_node, NULL_TREE); mangle_call_offset (fixed_offset, virtual_offset); } + else if (!DECL_THUNK_P (fn_decl)) + /* Plain this adjusting thunk. */ + mangle_call_offset (fixed_offset, virtual_offset); else { /* This adjusting thunk to covariant thunk. */ write_char ('c'); mangle_call_offset (fixed_offset, virtual_offset); - mangle_call_offset (ssize_int (THUNK_FIXED_OFFSET (fn_decl)), - THUNK_VIRTUAL_OFFSET (fn_decl)); - fn_decl = TREE_OPERAND (DECL_INITIAL (fn_decl), 0); + fixed_offset = ssize_int (THUNK_FIXED_OFFSET (fn_decl)); + virtual_offset = THUNK_VIRTUAL_OFFSET (fn_decl); + if (virtual_offset) + virtual_offset = BINFO_VPTR_FIELD (virtual_offset); + mangle_call_offset (fixed_offset, virtual_offset); + fn_decl = THUNK_TARGET (fn_decl); } /* Scoped name. */ diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 707a4987e91a..f4cfe0d67f19 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -261,8 +261,7 @@ make_thunk (tree function, bool this_adjusting, /* See if we already have the thunk in question. For this_adjusting thunks VIRTUAL_OFFSET will be an INTEGER_CST, for covariant thunks it - will be a BINFO (because of the organization of the layout - algorithm). */ + 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 @@ -281,7 +280,7 @@ make_thunk (tree function, bool this_adjusting, thunk = build_decl (FUNCTION_DECL, NULL_TREE, TREE_TYPE (function)); DECL_LANG_SPECIFIC (thunk) = DECL_LANG_SPECIFIC (function); - cxx_dup_lang_specific_decl (function); + cxx_dup_lang_specific_decl (thunk); DECL_CONTEXT (thunk) = DECL_CONTEXT (function); TREE_READONLY (thunk) = TREE_READONLY (function); TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (function); @@ -289,8 +288,8 @@ make_thunk (tree function, bool this_adjusting, if (flag_weak) comdat_linkage (thunk); SET_DECL_THUNK_P (thunk, this_adjusting); - DECL_INITIAL (thunk) = build1 (ADDR_EXPR, vfunc_ptr_type_node, function); - THUNK_FIXED_OFFSET (thunk) = tree_low_cst (fixed_offset, 0); + THUNK_TARGET (thunk) = function; + THUNK_FIXED_OFFSET (thunk) = d; THUNK_VIRTUAL_OFFSET (thunk) = virtual_offset; /* The thunk itself is not a constructor or destructor, even if @@ -320,20 +319,21 @@ make_thunk (tree function, bool this_adjusting, return thunk; } -/* Finish THUNK, a thunk decl. FIXED_OFFSET and VIRTUAL_OFFSET are the - adjustments to apply. */ +/* Finish THUNK, a thunk decl. */ void -finish_thunk (tree thunk, tree fixed_offset, tree virtual_offset) +finish_thunk (tree thunk) { tree function, name; - + tree fixed_offset = ssize_int (THUNK_FIXED_OFFSET (thunk)); + tree virtual_offset = THUNK_VIRTUAL_OFFSET (thunk); + my_friendly_assert (!DECL_NAME (thunk) && DECL_THUNK_P (thunk), 20021127); - function = TREE_OPERAND (DECL_INITIAL (thunk), 0); + if (virtual_offset && DECL_RESULT_THUNK_P (thunk)) + virtual_offset = BINFO_VPTR_FIELD (virtual_offset); + function = THUNK_TARGET (thunk); name = mangle_thunk (function, DECL_THIS_THUNK_P (thunk), - fixed_offset, virtual_offset); - THUNK_FIXED_OFFSET (thunk) = tree_low_cst (fixed_offset, 0); - THUNK_VIRTUAL_OFFSET (thunk) = virtual_offset; + fixed_offset, virtual_offset); DECL_NAME (thunk) = name; SET_DECL_ASSEMBLER_NAME (thunk, name); } @@ -358,9 +358,6 @@ thunk_adjust (tree ptr, bool this_adjusting, { tree vtable; - /* It shouldn't be a binfo any more. */ - my_friendly_assert (TREE_CODE (virtual_offset) == INTEGER_CST, 20021127); - ptr = save_expr (ptr); /* The vptr is always at offset zero in the object. */ vtable = build1 (NOP_EXPR, @@ -392,10 +389,10 @@ thunk_adjust (tree ptr, bool this_adjusting, void use_thunk (tree thunk_fndecl, bool emit_p) { - tree fnaddr; tree function; tree virtual_offset; HOST_WIDE_INT fixed_offset, virtual_value; + bool this_adjusting = DECL_THIS_THUNK_P (thunk_fndecl); /* We should have called finish_thunk to give it a name. */ my_friendly_assert (DECL_NAME (thunk_fndecl), 20021127); @@ -403,8 +400,8 @@ use_thunk (tree thunk_fndecl, bool emit_p) if (TREE_ASM_WRITTEN (thunk_fndecl)) return; - fnaddr = DECL_INITIAL (thunk_fndecl); - if (TREE_CODE (DECL_INITIAL (thunk_fndecl)) != ADDR_EXPR) + function = THUNK_TARGET (thunk_fndecl); + if (DECL_RESULT (thunk_fndecl)) /* We already turned this thunk into an ordinary function. There's no need to process this thunk again. */ return; @@ -414,7 +411,6 @@ use_thunk (tree thunk_fndecl, bool emit_p) /* Figure out what function is being thunked to. It's referenced in this translation unit. */ - function = TREE_OPERAND (fnaddr, 0); TREE_ADDRESSABLE (function) = 1; mark_used (function); TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (function)) = 1; @@ -424,9 +420,15 @@ use_thunk (tree thunk_fndecl, bool emit_p) fixed_offset = THUNK_FIXED_OFFSET (thunk_fndecl); virtual_offset = THUNK_VIRTUAL_OFFSET (thunk_fndecl); - virtual_value = (virtual_offset - ? tree_low_cst (virtual_offset, /*pos=*/0) : 0); - my_friendly_assert (!virtual_offset || virtual_value, 20021026); + if (virtual_offset) + { + if (!this_adjusting) + virtual_offset = BINFO_VPTR_FIELD (virtual_offset); + virtual_value = tree_low_cst (virtual_offset, /*pos=*/0); + my_friendly_assert (virtual_value, 20021026); + } + else + virtual_value = 0; /* And, if we need to emit the thunk, it's used. */ mark_used (thunk_fndecl); @@ -447,10 +449,9 @@ use_thunk (tree thunk_fndecl, bool emit_p) /* The back-end expects DECL_INITIAL to contain a BLOCK, so we create one. */ DECL_INITIAL (thunk_fndecl) = make_node (BLOCK); - BLOCK_VARS (DECL_INITIAL (thunk_fndecl)) - = DECL_ARGUMENTS (thunk_fndecl); - - if (DECL_THIS_THUNK_P (thunk_fndecl) + BLOCK_VARS (DECL_INITIAL (thunk_fndecl)) = DECL_ARGUMENTS (thunk_fndecl); + + if (this_adjusting && targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset, virtual_value, function)) { @@ -502,7 +503,7 @@ use_thunk (tree thunk_fndecl, bool emit_p) t = a; - if (DECL_THIS_THUNK_P (thunk_fndecl)) + if (this_adjusting) t = thunk_adjust (t, /*this_adjusting=*/1, fixed_offset, virtual_offset); @@ -512,7 +513,7 @@ use_thunk (tree thunk_fndecl, bool emit_p) t = tree_cons (NULL_TREE, a, t); t = nreverse (t); t = build_call (function, t); - if (DECL_RESULT_THUNK_P (thunk_fndecl)) + if (!this_adjusting) t = thunk_adjust (t, /*this_adjusting=*/0, fixed_offset, virtual_offset); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 3373f6d0caf5..cae2b90e786e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2002-12-30 Nathan Sidwell <nathan@codesourcery.com> + + * g++.dg/inherit/covariant5.C: New test. + * g++.dg/inherit/covariant6.C: New test. + * g++.dg/inherit/covariant7.C: New test. + 2002-12-29 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net> PR c++/2739 diff --git a/gcc/testsuite/g++.dg/inherit/covariant5.C b/gcc/testsuite/g++.dg/inherit/covariant5.C new file mode 100644 index 000000000000..a46b1bf20d8c --- /dev/null +++ b/gcc/testsuite/g++.dg/inherit/covariant5.C @@ -0,0 +1,27 @@ +// { dg-do compile } + +// Copyright (C) 2002 Free Software Foundation, Inc. +// Contributed by Nathan Sidwell 27 Dec 2002 <nathan@codesourcery.com> + +// We ICE'd + +struct c0 {}; + +struct c1 : virtual c0 +{ + virtual c0 &f2(); +}; + +struct c3 : c1 +{ + virtual c1 &f2(); +}; + +c1 &c3::f2() +{ + throw 0; +} + +struct c4 : virtual c3 +{ +}; diff --git a/gcc/testsuite/g++.dg/inherit/covariant6.C b/gcc/testsuite/g++.dg/inherit/covariant6.C new file mode 100644 index 000000000000..dc55971533ec --- /dev/null +++ b/gcc/testsuite/g++.dg/inherit/covariant6.C @@ -0,0 +1,27 @@ +// { dg-do compile } + +// Copyright (C) 2002 Free Software Foundation, Inc. +// Contributed by Nathan Sidwell 27 Dec 2002 <nathan@codesourcery.com> + +// We ICE'd + +struct c0 {}; + +struct c1 : virtual c0 +{ + virtual c0 &f2(); +}; + +struct c3 : virtual c1 +{ + virtual c1 &f2(); +}; + +c1 &c3::f2() +{ + throw 0; +} + +struct c4 : virtual c3 +{ +}; diff --git a/gcc/testsuite/g++.dg/inherit/covariant7.C b/gcc/testsuite/g++.dg/inherit/covariant7.C new file mode 100644 index 000000000000..596c679f2484 --- /dev/null +++ b/gcc/testsuite/g++.dg/inherit/covariant7.C @@ -0,0 +1,33 @@ +// { dg-do compile } + +// Copyright (C) 2002 Free Software Foundation, Inc. +// Contributed by Nathan Sidwell 27 Dec 2002 <nathan@codesourcery.com> + +// We ICE'd + +struct c0 {}; + +struct c1 : virtual c0 +{ + virtual c0 &f2() volatile; +}; + +struct c2 +{ + int m; +}; + +struct c3 : virtual c0, virtual c1, c2 +{ + virtual c1 &f2() volatile; +}; + +struct c4 : virtual c3, virtual c0, virtual c1 +{ + int m; +}; + +struct c6 : c0, c3, c4 +{ // { dg-warning "direct base" "" } + virtual c1 &f2() volatile; +}; -- GitLab