From 85a9a0a28bd6f48e7e45386cbe6003ea3199f43b Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Fri, 8 Jun 2001 11:10:29 +0000 Subject: [PATCH] re PR c++/3061 (kde2/artsd miscompilation (part 2)) PR c++/3061 * class.c (build_secondary_vtable): Use assert, rather than an error message. (dfs_fixup_binfo_vtbls): BINFO_VTABLE might be NULL. (dfs_accumulate_vtbl_inits): A lost primary virtual base may be between ORIG_BINFO and RTTI_BINFO, but neither of them. Don't set BINFO_VTABLE for a primary virtual base. Co-Authored-By: Jason Merrill From-SVN: r43006 --- gcc/cp/ChangeLog | 11 ++ gcc/cp/class.c | 143 +++++++++++-------- gcc/cp/method.c | 2 +- gcc/testsuite/g++.old-deja/g++.abi/vtable4.C | 27 ++++ 4 files changed, 125 insertions(+), 58 deletions(-) create mode 100644 gcc/testsuite/g++.old-deja/g++.abi/vtable4.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index fb986e5be3c..1fa95c8aad5 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +2001-06-08 Nathan Sidwell + Jason Merrill + + PR c++/3061 + * class.c (build_secondary_vtable): Use assert, rather than an error + message. + (dfs_fixup_binfo_vtbls): BINFO_VTABLE might be NULL. + (dfs_accumulate_vtbl_inits): A lost primary virtual base may + be between ORIG_BINFO and RTTI_BINFO, but neither of them. + Don't set BINFO_VTABLE for a primary virtual base. + 2001-06-07 Mark Mitchell * decl.c (duplicate_decls): Update source position information diff --git a/gcc/cp/class.c b/gcc/cp/class.c index cdd92b5d4c2..499053c7db1 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -768,7 +768,7 @@ copy_virtuals (binfo) return copies; } - + /* Build the primary virtual function table for TYPE. If BINFO is non-NULL, build the vtable starting with the initial approximation that it is the same as the one which is the head of the association @@ -866,20 +866,8 @@ build_secondary_vtable (binfo, for_type) /* Make fresh virtual list, so we can smash it later. */ BINFO_VIRTUALS (binfo) = copy_virtuals (binfo); - if (TREE_VIA_VIRTUAL (binfo)) - { - tree binfo1 = binfo_for_vbase (BINFO_TYPE (binfo), for_type); - - /* XXX - This should never happen, if it does, the caller should - ensure that the binfo is from for_type's binfos, not from any - base type's. We can remove all this code after a while. */ - if (binfo1 != binfo) - warning ("internal inconsistency: binfo offset error for rtti"); - - offset = BINFO_OFFSET (binfo1); - } - else - offset = BINFO_OFFSET (binfo); + my_friendly_assert (binfo == CANONICAL_BINFO (binfo, for_type), 20010605); + offset = BINFO_OFFSET (binfo); /* In the new ABI, secondary vtables are laid out as part of the same structure as the primary vtable. */ @@ -6744,12 +6732,12 @@ dfs_get_primary_binfo (binfo, data) return NULL_TREE; } -/* Returns the binfo for the primary base of BINFO. Note that in a - complex hierarchy the resulting BINFO may not actually *be* - primary. In particular if the resulting BINFO is a virtual base, - and it occurs elsewhere in the hierarchy, then this occurrence may - not actually be a primary base in the complete object. Check - BINFO_PRIMARY_P to be sure. */ +/* Returns the unshared binfo for the primary base of BINFO. Note + that in a complex hierarchy the resulting BINFO may not actually + *be* primary. In particular if the resulting BINFO is a virtual + base, and it occurs elsewhere in the hierarchy, then this + occurrence may not actually be a primary base in the complete + object. Check BINFO_PRIMARY_P to be sure. */ tree get_primary_binfo (binfo) @@ -7397,7 +7385,8 @@ dfs_fixup_binfo_vtbls (binfo, data) /* If we scribbled the construction vtable vptr into BINFO, clear it out now. */ - if (TREE_CODE (BINFO_VTABLE (binfo)) == TREE_LIST + if (BINFO_VTABLE (binfo) + && TREE_CODE (BINFO_VTABLE (binfo)) == TREE_LIST && (TREE_PURPOSE (BINFO_VTABLE (binfo)) == TREE_VALUE ((tree) data))) BINFO_VTABLE (binfo) = TREE_CHAIN (BINFO_VTABLE (binfo)); @@ -7543,41 +7532,80 @@ dfs_accumulate_vtbl_inits (binfo, orig_binfo, rtti_binfo, t, l) virtual base. If it is not the same primary in the hierarchy of T, we'll need to generate a ctor vtable for it, to place at its location in T. If it is the same primary, we still need a VTT - entry for the vtable, but that must be the base it is a - primary for within the sub-hierarchy of RTTI_BINFO. */ - tree parent; - tree best_primary = NULL; - tree primary_for; - - my_friendly_assert (BINFO_PRIMARY_P (binfo), 20010131); + entry for the vtable, but it should point to the ctor vtable for the + base it is a primary for within the sub-hierarchy of RTTI_BINFO. - for (primary_for = BINFO_PRIMARY_BASE_OF (binfo); - primary_for; - primary_for = BINFO_PRIMARY_BASE_OF (primary_for)) - { - for (parent = primary_for; - parent; - parent = BINFO_INHERITANCE_CHAIN (parent)) - { - if (parent == rtti_binfo) - { - best_primary = primary_for; - break; - } - } - if (!parent) - break; - } - if (best_primary) - { - vtbl = BINFO_VTABLE (best_primary); - if (TREE_CODE (vtbl) == TREE_LIST) - { - my_friendly_assert (TREE_PURPOSE (vtbl) == rtti_binfo, - 20010126); - vtbl = TREE_VALUE (vtbl); - } + There are three possible cases: + + 1) We are in the same place. + 2) We are a primary base within a lost primary virtual base of + RTTI_BINFO. + 3) We are not primary to anything else in RTTI_BINFO. */ + + tree primary = NULL_TREE; + if (tree_int_cst_equal (BINFO_OFFSET (orig_binfo), + size_diffop (BINFO_OFFSET (binfo), + BINFO_OFFSET (rtti_binfo)))) + { + /* Case 1: We're in the same place relative to RTTI_BINFO as we + were in the complete type, so we are primary either to + RTTI_BINFO or one of its secondary bases. */ + + tree b = BINFO_PRIMARY_BASE_OF (binfo); + + /* Walk down our until we either find the last primary base or + rtti_binfo. */ + for (; b; b = BINFO_PRIMARY_BASE_OF (b)) + { + primary = b; + if (b == rtti_binfo) + break; + } } + else + { + /* Case 2 or 3: We're not in the same place. We might still be + primary to something within a lost primary virtual base of + RTTI_BINFO. */ + + tree b = BINFO_PRIMARY_BASE_OF (binfo); + tree last; + + /* First, look through the bases we are primary to for a virtual + base. */ + for (; b; b = BINFO_PRIMARY_BASE_OF (b)) + { + last = b; + if (TREE_VIA_VIRTUAL (b)) + break; + } + /* If we run out of primary links, keep looking down our + inheritance chain; we might be an indirect primary of a + virtual base. */ + if (b == NULL_TREE) + for (b = last; b; b = BINFO_INHERITANCE_CHAIN (b)) + if (TREE_VIA_VIRTUAL (b)) + break; + + /* If we found a virtual base B and it is a base of RTTI_BINFO, we + share our vtable with LAST, i.e. the derived-most base within + B of which we are a primary. Otherwise, we get our own. */ + if (b && binfo_for_vbase (BINFO_TYPE (b), + BINFO_TYPE (rtti_binfo))) + primary = last; + } + + if (primary) + { + vtbl = BINFO_VTABLE (primary); + /* If we haven't already been here for our primary derivation, + all bets are off. Especially for case 2 above, we need + the derived vtable to have been generated. */ + my_friendly_assert (TREE_CODE (vtbl) == TREE_LIST + && TREE_PURPOSE (vtbl) == rtti_binfo, + 20010126); + vtbl = TREE_VALUE (vtbl); + } } else if (!BINFO_NEW_VTABLE_MARKED (orig_binfo, BINFO_TYPE (rtti_binfo))) return inits; @@ -7610,9 +7638,10 @@ dfs_accumulate_vtbl_inits (binfo, orig_binfo, rtti_binfo, t, l) if (!ctor_vtbl_p) { /* For an ordinary vtable, set BINFO_VTABLE. */ - BINFO_VTABLE (binfo) = vtbl; if (BINFO_PRIMARY_P (binfo) && TREE_VIA_VIRTUAL (binfo)) - inits = NULL_TREE; + inits = NULL_TREE; + else + BINFO_VTABLE (binfo) = vtbl; } else /* For a construction vtable, we can't overwrite BINFO_VTABLE. diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 4acf6b670b0..ceb569c70d7 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -292,7 +292,7 @@ request for member `%D' is ambiguous in multiple inheritance lattice", /* Return a thunk to FUNCTION. For a virtual thunk, DELTA is the offset to this used to locate the vptr, and VCALL_INDEX is used to look up the eventual subobject location. For a non-virtual thunk, - DELTA is the offset to this and VCALL_INDEX is zero. */ + DELTA is the offset to this and VCALL_INDEX is NULL. */ tree make_thunk (function, delta, vcall_index) diff --git a/gcc/testsuite/g++.old-deja/g++.abi/vtable4.C b/gcc/testsuite/g++.old-deja/g++.abi/vtable4.C new file mode 100644 index 00000000000..8190c0e9bdc --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.abi/vtable4.C @@ -0,0 +1,27 @@ +// Test for proper handling of extreme virtual inheritance. +// Previously we failed to recognise that in the constructor vtable +// for B_skel in C_skel, A_base was still primary to B_base, even though +// not to B_skel. + +// From PR c++/3061. + +struct A_base { + virtual void foo() { } +}; +class A_skel : virtual public A_base { }; + +class B_base : virtual public A_base { }; +class B_skel : virtual public B_base, virtual public A_skel { }; + +class C_base : virtual public B_base { }; +class C_skel : virtual public C_base, virtual public B_skel { }; + +class D_base : virtual public C_base { }; +class D_skel : virtual public D_base, virtual public C_skel { }; + +class D_impl : virtual public D_skel { }; + +int main() +{ + D_impl i; +} -- 2.30.2