From 3cfabe60d4c8f85750afa5cf61a66a13a1140097 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Tue, 31 Dec 2002 19:43:16 +0000 Subject: [PATCH] class.c (modify_vtable_entry): Remove unused variable. cp: * class.c (modify_vtable_entry): Remove unused variable. (get_vcall_index): Always expect a non-thunk. (update_vtable_entry_for_fn): Combine covariant adjustments, when overriding a thunk. Pass get_vcall_index a non-thunk. * decl2.c (finish_file): Mark undefined inlines as extern. testsuite: * g++.dg/inherit/covariant8.C: New test. From-SVN: r60710 --- gcc/cp/ChangeLog | 9 ++ gcc/cp/class.c | 144 ++++++++++++---------- gcc/cp/cp-tree.h | 10 +- gcc/cp/decl2.c | 9 +- gcc/testsuite/ChangeLog | 4 + gcc/testsuite/g++.dg/inherit/covariant8.C | 34 +++++ 6 files changed, 142 insertions(+), 68 deletions(-) create mode 100644 gcc/testsuite/g++.dg/inherit/covariant8.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 921c0de4ec5..987e42bac40 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2002-12-31 Nathan Sidwell + + * class.c (modify_vtable_entry): Remove unused variable. + (get_vcall_index): Always expect a non-thunk. + (update_vtable_entry_for_fn): Combine covariant adjustments, when + overriding a thunk. Pass get_vcall_index a non-thunk. + + * decl2.c (finish_file): Mark undefined inlines as extern. + 2002-12-31 Mark Mitchell * cp-tree.def (RETURN_INIT): Remove. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 0ce3f113468..b54c1f658d3 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -716,8 +716,6 @@ modify_vtable_entry (t, binfo, fndecl, delta, virtuals) if (fndecl != BV_FN (v) || !tree_int_cst_equal (delta, BV_DELTA (v))) { - tree base_fndecl; - /* We need a new vtable for BINFO. */ if (make_new_vtable (t, binfo)) { @@ -730,7 +728,6 @@ modify_vtable_entry (t, binfo, fndecl, delta, virtuals) v = *virtuals; } - base_fndecl = BV_FN (v); BV_DELTA (v) = delta; BV_VCALL_INDEX (v) = NULL_TREE; BV_FN (v) = fndecl; @@ -2331,9 +2328,6 @@ get_vcall_index (tree fn, tree type) { tree v; - 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))) || same_signature_p (fn, TREE_PURPOSE (v))) @@ -2361,18 +2355,18 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals) tree delta; tree virtual_base; tree first_defn; + tree overrider_fn, overrider_target; + tree target_fn = DECL_THUNK_P (fn) ? THUNK_TARGET (fn) : fn; + tree over_return, base_return; 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)) + if (look_for_overrides_here (BINFO_TYPE (b), target_fn)) break; /* The nearest definition is from a lost primary. */ @@ -2382,58 +2376,85 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals) first_defn = b; /* Find the final overrider. */ - overrider = find_final_overrider (TYPE_BINFO (t), b, fn); + overrider = find_final_overrider (TYPE_BINFO (t), b, target_fn); if (overrider == error_mark_node) return; - { - /* Check for adjusting covariant return types. */ - tree over_return = TREE_TYPE (TREE_TYPE (TREE_PURPOSE (overrider))); - tree base_return = TREE_TYPE (TREE_TYPE (fn)); + overrider_target = overrider_fn = TREE_PURPOSE (overrider); + + /* Check for adjusting covariant return types. */ + over_return = TREE_TYPE (TREE_TYPE (overrider_target)); + base_return = TREE_TYPE (TREE_TYPE (target_fn)); + + if (POINTER_TYPE_P (over_return) + && TREE_CODE (over_return) == TREE_CODE (base_return) + && CLASS_TYPE_P (TREE_TYPE (over_return)) + && CLASS_TYPE_P (TREE_TYPE (base_return))) + { + /* If FN is a covariant thunk, we must figure out the adjustment + to the final base FN was converting to. As OVERRIDER_TARGET might + also be converting to the return type of FN, we have to + combine the two conversions here. */ + tree fixed_offset, virtual_offset; + + if (DECL_THUNK_P (fn)) + { + fixed_offset = ssize_int (THUNK_FIXED_OFFSET (fn)); + virtual_offset = THUNK_VIRTUAL_OFFSET (fn); + if (virtual_offset) + virtual_offset = binfo_for_vbase (BINFO_TYPE (virtual_offset), + TREE_TYPE (over_return)); + } + else + fixed_offset = virtual_offset = NULL_TREE; - if (POINTER_TYPE_P (over_return) - && TREE_CODE (over_return) == TREE_CODE (base_return) - && CLASS_TYPE_P (TREE_TYPE (over_return)) - && CLASS_TYPE_P (TREE_TYPE (base_return))) - { - tree binfo; - base_kind kind; + if (!virtual_offset) + { + /* There was no existing virtual thunk (which takes + precidence). */ + tree thunk_binfo; + base_kind kind; + + thunk_binfo = lookup_base (TREE_TYPE (over_return), + TREE_TYPE (base_return), + ba_check | ba_quiet, &kind); - binfo = lookup_base (TREE_TYPE (over_return), TREE_TYPE (base_return), - ba_check | ba_quiet, &kind); - - if (binfo && (kind == bk_via_virtual || !BINFO_OFFSET_ZEROP (binfo))) - { - tree fixed_offset = BINFO_OFFSET (binfo); - tree virtual_offset = NULL_TREE; - tree thunk; - - if (kind == bk_via_virtual) - { - while (!TREE_VIA_VIRTUAL (binfo)) - binfo = BINFO_INHERITANCE_CHAIN (binfo); - - /* 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. */ - 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. - We will emit the overriding function in its own slot - as well. */ - thunk = make_thunk (TREE_PURPOSE (overrider), /*this_adjusting=*/0, - fixed_offset, virtual_offset); - TREE_PURPOSE (overrider) = thunk; - if (!virtual_offset && !DECL_NAME (thunk)) - finish_thunk (thunk); - } - } - } + if (thunk_binfo && (kind == bk_via_virtual + || !BINFO_OFFSET_ZEROP (thunk_binfo))) + { + tree offset = BINFO_OFFSET (thunk_binfo); + if (kind == bk_via_virtual) + { + /* We convert via virtual base. Find the virtual + base and adjust the fixed offset to be from there. */ + while (!TREE_VIA_VIRTUAL (thunk_binfo)) + thunk_binfo = BINFO_INHERITANCE_CHAIN (thunk_binfo); + + virtual_offset = binfo_for_vbase (BINFO_TYPE (thunk_binfo), + TREE_TYPE (over_return)); + offset = size_diffop (offset, + BINFO_OFFSET (virtual_offset)); + } + if (fixed_offset) + /* There was an existing fixed offset, this must be + from the base just converted to, and the base the + FN was thunking to. */ + fixed_offset = size_binop (PLUS_EXPR, fixed_offset, offset); + else + fixed_offset = offset; + } + } + + if (fixed_offset || virtual_offset) + /* Replace the overriding function with a covariant thunk. We + will emit the overriding function in its own slot as + well. */ + overrider_fn = make_thunk (overrider_target, /*this_adjusting=*/0, + fixed_offset, virtual_offset); + } + else + my_friendly_assert (!DECL_THUNK_P (fn), 20021231); + /* Assume that we will produce a thunk that convert all the way to the final overrider, and not to an intermediate virtual base. */ virtual_base = NULL_TREE; @@ -2476,16 +2497,11 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals) delta = size_diffop (BINFO_OFFSET (TREE_VALUE (overrider)), BINFO_OFFSET (binfo)); - modify_vtable_entry (t, - binfo, - TREE_PURPOSE (overrider), - delta, - virtuals); + modify_vtable_entry (t, binfo, overrider_fn, delta, virtuals); if (virtual_base) BV_VCALL_INDEX (*virtuals) - = get_vcall_index (TREE_PURPOSE (overrider), - BINFO_TYPE (virtual_base)); + = get_vcall_index (overrider_target, BINFO_TYPE (virtual_base)); } /* Called from modify_all_vtables via dfs_walk. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 3346a1fe86d..e27c66832ea 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2977,9 +2977,13 @@ struct lang_decl GTY(()) /* 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. */ + binfo of the relevant virtual base. If NULL, then there is no + virtual adjust. (The vptr is always located at offset zero from + the this or result pointer.) (If the covariant type is within the + class hierarchy being layed out, the vbase index is not yet known + at the point we need to create the thunks, hence the need to use + binfos.) */ + #define THUNK_VIRTUAL_OFFSET(DECL) \ (LANG_DECL_U2_CHECK (VAR_OR_FUNCTION_DECL_CHECK (DECL), 0)->virtual_offset) diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 6efb9bdd46b..8e440e92e97 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -2802,7 +2802,14 @@ finish_file () if (TREE_USED (decl) && DECL_DECLARED_INLINE_P (decl) && !(TREE_ASM_WRITTEN (decl) || DECL_SAVED_TREE (decl))) - cp_warning_at ("inline function `%D' used but never defined", decl); + { + cp_warning_at ("inline function `%D' used but never defined", decl); + /* This symbol is effectively an "extern" declaration now. + This is not strictly necessary, but removes a duplicate + warning. */ + TREE_PUBLIC (decl) = 1; + } + } /* We give C linkage to static constructors and destructors. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f3378e4af02..b63e0088068 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2002-12-31 Nathan Sidwell + + * g++.dg/inherit/covariant8.C: New test. + 2002-12-31 Mark Mitchell * g++.dg/init/array9.C: New test. diff --git a/gcc/testsuite/g++.dg/inherit/covariant8.C b/gcc/testsuite/g++.dg/inherit/covariant8.C new file mode 100644 index 00000000000..33dc431065e --- /dev/null +++ b/gcc/testsuite/g++.dg/inherit/covariant8.C @@ -0,0 +1,34 @@ +// { dg-do compile } + +// Copyright (C) 2002 Free Software Foundation, Inc. +// Contributed by Nathan Sidwell 31 Dec 2002 + +// ICE with covariant thunks. + +struct c0 {}; + +struct c1 : virtual c0 +{ + virtual c0 &f2 (); +}; + +struct c2 +{ + int m; +}; + +struct c3 : virtual c0, virtual c1, c2 +{ + virtual c1 &f2 (); +}; + +c1 &c3::f2 () +{ + throw 0; +} + +struct c4 : virtual c3, virtual c0, virtual c1 {}; + +struct c8 : virtual c2, virtual c0 {}; + +struct c12 : virtual c4, virtual c3, virtual c8 {};