diff options
author | Mark Mitchell <mark@codesourcery.com> | 2002-11-08 02:16:48 +0000 |
---|---|---|
committer | Mark Mitchell <mmitchel@gcc.gnu.org> | 2002-11-08 02:16:48 +0000 |
commit | e6a6656780e22cd77495bd8faf3b179455346e15 (patch) | |
tree | 8a244591acba56e22812980ef1a56c3b92b02e7a /gcc | |
parent | 4f2c9d7ec6409e570be8df243c57e4e3298b26e6 (diff) | |
download | gcc-e6a6656780e22cd77495bd8faf3b179455346e15.zip gcc-e6a6656780e22cd77495bd8faf3b179455346e15.tar.gz gcc-e6a6656780e22cd77495bd8faf3b179455346e15.tar.bz2 |
class.c (add_vcall_offset_vtbl_entries_1): Correct ordering of vcall offfsets.
* class.c (add_vcall_offset_vtbl_entries_1): Correct ordering of
vcall offfsets. Split out ...
(add_vcall_offset): ... new function.
* g++.dg/abi/vthunk3.C: New test.
From-SVN: r58912
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/cp/class.c | 229 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/abi/vthunk3.C | 26 |
4 files changed, 166 insertions, 95 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 08f6b25..224c590 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,9 @@ 2002-11-07 Mark Mitchell <mark@codesourcery.com> + * class.c (add_vcall_offset_vtbl_entries_1): Correct ordering of + vcall offfsets. Split out ... + (add_vcall_offset): ... new function. + PR c++/8338 * pt.c (for_each_template_parm): Add htab parameter. (process_partial_specialization): Adjust call. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 82f7c8f..2ca45a6 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -156,6 +156,7 @@ static void build_vbase_offset_vtbl_entries PARAMS ((tree, vtbl_init_data *)); static void add_vcall_offset_vtbl_entries_r PARAMS ((tree, vtbl_init_data *)); static void add_vcall_offset_vtbl_entries_1 PARAMS ((tree, vtbl_init_data *)); static void build_vcall_offset_vtbl_entries PARAMS ((tree, vtbl_init_data *)); +static void add_vcall_offset (tree, tree, vtbl_init_data *); static void layout_vtable_decl PARAMS ((tree, int)); static tree dfs_find_final_overrider PARAMS ((tree, void *)); static tree find_final_overrider PARAMS ((tree, tree, tree)); @@ -7908,116 +7909,154 @@ add_vcall_offset_vtbl_entries_1 (binfo, vid) tree binfo; vtbl_init_data* vid; { - tree derived_virtuals; - tree base_virtuals; - tree orig_virtuals; - tree binfo_inits; - /* If BINFO is a primary base, the most derived class which has BINFO as - a primary base; otherwise, just BINFO. */ - tree non_primary_binfo; + tree binfo_in_rtti; - binfo_inits = NULL_TREE; + if (vid->ctor_vtbl_p) + binfo_in_rtti = (get_original_base + (binfo, TYPE_BINFO (BINFO_TYPE (vid->rtti_binfo)))); + else + binfo_in_rtti = binfo; - /* We might be a primary base class. Go up the inheritance hierarchy - until we find the most derived class of which we are a primary base: - it is the BINFO_VIRTUALS there that we need to consider. */ - non_primary_binfo = binfo; - while (BINFO_INHERITANCE_CHAIN (non_primary_binfo)) + /* Make entries for the rest of the virtuals. */ + if (abi_version_at_least (2)) { - tree b; + tree orig_fn; - /* If we have reached a virtual base, then it must be vid->vbase, - because we ignore other virtual bases in - add_vcall_offset_vtbl_entries_r. In turn, it must be a primary - base (possibly multi-level) of vid->binfo, or we wouldn't - have called build_vcall_and_vbase_vtbl_entries for it. But it - might be a lost primary, so just skip down to vid->binfo. */ - if (TREE_VIA_VIRTUAL (non_primary_binfo)) + /* The ABI requires that the methods be processed in declaration + order. G++ 3.2 used the order in the vtable. */ + for (orig_fn = TYPE_METHODS (BINFO_TYPE (binfo)); + orig_fn; + orig_fn = TREE_CHAIN (orig_fn)) + if (DECL_VINDEX (orig_fn)) + add_vcall_offset (orig_fn, binfo_in_rtti, vid); + } + else + { + tree derived_virtuals; + tree base_virtuals; + tree orig_virtuals; + /* If BINFO is a primary base, the most derived class which has + BINFO as a primary base; otherwise, just BINFO. */ + tree non_primary_binfo; + + /* We might be a primary base class. Go up the inheritance hierarchy + until we find the most derived class of which we are a primary base: + it is the BINFO_VIRTUALS there that we need to consider. */ + non_primary_binfo = binfo; + while (BINFO_INHERITANCE_CHAIN (non_primary_binfo)) { - if (non_primary_binfo != vid->vbase) - abort (); - non_primary_binfo = vid->binfo; - break; - } + tree b; + + /* If we have reached a virtual base, then it must be vid->vbase, + because we ignore other virtual bases in + add_vcall_offset_vtbl_entries_r. In turn, it must be a primary + base (possibly multi-level) of vid->binfo, or we wouldn't + have called build_vcall_and_vbase_vtbl_entries for it. But it + might be a lost primary, so just skip down to vid->binfo. */ + if (TREE_VIA_VIRTUAL (non_primary_binfo)) + { + if (non_primary_binfo != vid->vbase) + abort (); + non_primary_binfo = vid->binfo; + break; + } - b = BINFO_INHERITANCE_CHAIN (non_primary_binfo); - if (get_primary_binfo (b) != non_primary_binfo) - break; - non_primary_binfo = b; - } + b = BINFO_INHERITANCE_CHAIN (non_primary_binfo); + if (get_primary_binfo (b) != non_primary_binfo) + break; + non_primary_binfo = b; + } - if (vid->ctor_vtbl_p) - /* For a ctor vtable we need the equivalent binfo within the hierarchy - where rtti_binfo is the most derived type. */ - non_primary_binfo = get_original_base + if (vid->ctor_vtbl_p) + /* For a ctor vtable we need the equivalent binfo within the hierarchy + where rtti_binfo is the most derived type. */ + non_primary_binfo = get_original_base (non_primary_binfo, TYPE_BINFO (BINFO_TYPE (vid->rtti_binfo))); + + for (base_virtuals = BINFO_VIRTUALS (binfo), + derived_virtuals = BINFO_VIRTUALS (non_primary_binfo), + orig_virtuals = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (binfo))); + base_virtuals; + base_virtuals = TREE_CHAIN (base_virtuals), + derived_virtuals = TREE_CHAIN (derived_virtuals), + orig_virtuals = TREE_CHAIN (orig_virtuals)) + { + tree orig_fn; - /* Make entries for the rest of the virtuals. */ - for (base_virtuals = BINFO_VIRTUALS (binfo), - derived_virtuals = BINFO_VIRTUALS (non_primary_binfo), - orig_virtuals = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (binfo))); - base_virtuals; - base_virtuals = TREE_CHAIN (base_virtuals), - derived_virtuals = TREE_CHAIN (derived_virtuals), - orig_virtuals = TREE_CHAIN (orig_virtuals)) - { - tree orig_fn; - tree fn; - size_t i; - tree vcall_offset; + /* Find the declaration that originally caused this function to + be present in BINFO_TYPE (binfo). */ + orig_fn = BV_FN (orig_virtuals); - /* Find the declaration that originally caused this function to - be present in BINFO_TYPE (binfo). */ - orig_fn = BV_FN (orig_virtuals); + /* When processing BINFO, we only want to generate vcall slots for + function slots introduced in BINFO. So don't try to generate + one if the function isn't even defined in BINFO. */ + if (!same_type_p (DECL_CONTEXT (orig_fn), BINFO_TYPE (binfo))) + continue; - /* When processing BINFO, we only want to generate vcall slots for - function slots introduced in BINFO. So don't try to generate - one if the function isn't even defined in BINFO. */ - if (!same_type_p (DECL_CONTEXT (orig_fn), BINFO_TYPE (binfo))) - continue; + add_vcall_offset (orig_fn, binfo_in_rtti, vid); + } + } +} - /* Find the overriding function. */ - fn = BV_FN (derived_virtuals); +/* Add a vcall offset entry for ORIG_FN to the vtable. In a + construction vtable, BINFO_IN_RTTI is the base corresponding to the + vtable base in VID->RTTI_BINFO. */ - /* If there is already an entry for a function with the same - signature as FN, then we do not need a second vcall offset. - Check the list of functions already present in the derived - class vtable. */ - for (i = 0; i < VARRAY_ACTIVE_SIZE (vid->fns); ++i) - { - tree derived_entry; - - derived_entry = VARRAY_TREE (vid->fns, i); - if (same_signature_p (BV_FN (derived_entry), fn) - /* We only use one vcall offset for virtual destructors, - even though there are two virtual table entries. */ - || (DECL_DESTRUCTOR_P (BV_FN (derived_entry)) - && DECL_DESTRUCTOR_P (fn))) - break; - } - if (i != VARRAY_ACTIVE_SIZE (vid->fns)) - continue; +static void +add_vcall_offset (tree orig_fn, tree binfo_in_rtti, + vtbl_init_data *vid) +{ + size_t i; + tree vcall_offset; - /* If we are building these vcall offsets as part of building - the vtable for the most derived class, remember the vcall - offset. */ - if (vid->binfo == TYPE_BINFO (vid->derived)) - CLASSTYPE_VCALL_INDICES (vid->derived) - = tree_cons (fn, vid->index, CLASSTYPE_VCALL_INDICES (vid->derived)); + /* If there is already an entry for a function with the same + signature as FN, then we do not need a second vcall offset. + Check the list of functions already present in the derived + class vtable. */ + for (i = 0; i < VARRAY_ACTIVE_SIZE (vid->fns); ++i) + { + tree derived_entry; - /* The next vcall offset will be found at a more negative - offset. */ - vid->index = size_binop (MINUS_EXPR, vid->index, - ssize_int (TARGET_VTABLE_DATA_ENTRY_DISTANCE)); + derived_entry = VARRAY_TREE (vid->fns, i); + if (same_signature_p (derived_entry, orig_fn) + /* We only use one vcall offset for virtual destructors, + even though there are two virtual table entries. */ + || (DECL_DESTRUCTOR_P (derived_entry) + && DECL_DESTRUCTOR_P (orig_fn))) + return; + } - /* Keep track of this function. */ - VARRAY_PUSH_TREE (vid->fns, derived_virtuals); + /* If we are building these vcall offsets as part of building + the vtable for the most derived class, remember the vcall + offset. */ + if (vid->binfo == TYPE_BINFO (vid->derived)) + CLASSTYPE_VCALL_INDICES (vid->derived) + = tree_cons (orig_fn, vid->index, + CLASSTYPE_VCALL_INDICES (vid->derived)); - if (vid->generate_vcall_entries) - { - tree base; - tree base_binfo; + /* The next vcall offset will be found at a more negative + offset. */ + vid->index = size_binop (MINUS_EXPR, vid->index, + ssize_int (TARGET_VTABLE_DATA_ENTRY_DISTANCE)); + + /* Keep track of this function. */ + VARRAY_PUSH_TREE (vid->fns, orig_fn); + + if (vid->generate_vcall_entries) + { + tree base; + tree base_binfo; + tree fn; + /* Find the overriding function. */ + fn = find_final_overrider (BINFO_TYPE (vid->rtti_binfo), + binfo_in_rtti, orig_fn); + if (fn == error_mark_node) + vcall_offset = build1 (NOP_EXPR, vtable_entry_type, + integer_zero_node); + else + { + fn = TREE_PURPOSE (fn); /* The FN comes from BASE. So, we must calculate the adjustment from vid->vbase to BASE. We can just look for BASE in the complete object because we are converting @@ -8037,10 +8076,10 @@ add_vcall_offset_vtbl_entries_1 (binfo, vid) vcall_offset); vcall_offset = fold (build1 (NOP_EXPR, vtable_entry_type, vcall_offset)); - - *vid->last_init = build_tree_list (NULL_TREE, vcall_offset); - vid->last_init = &TREE_CHAIN (*vid->last_init); } + /* Add the intiailizer to the vtable. */ + *vid->last_init = build_tree_list (NULL_TREE, vcall_offset); + vid->last_init = &TREE_CHAIN (*vid->last_init); } } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c817452..679029e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,7 @@ 2002-11-07 Mark Mitchell <mark@codesourcery.com> + * g++.dg/abi/vthunk3.C: New test. + PR c++/8338 * g++.dg/template/crash2.C: New test. diff --git a/gcc/testsuite/g++.dg/abi/vthunk3.C b/gcc/testsuite/g++.dg/abi/vthunk3.C new file mode 100644 index 0000000..59e6067 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/vthunk3.C @@ -0,0 +1,26 @@ +// { dg-do compile } +// { dg-options "-fabi-version=0" } + +struct A { + virtual void a (); +}; + +struct B : virtual public A { + virtual void b (); + virtual void a (); +}; + +struct C { + virtual void c (); +}; + +struct D : public C, public B { +}; + +struct E : virtual public D { + void b (); +}; + +void E::b () {} + +// { dg-final { scan-assembler _ZTvn4_n20_N1E1bEv } } |