aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>2000-06-23 01:14:40 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>2000-06-23 01:14:40 +0000
commit31f8e4f306e9ef25c534afb1601fb9547801ae90 (patch)
treed353106ea48473adbbbe826b110e6044aa4595b7
parent11fc1858a0850253a8487eae391b9ea3fd24ea5d (diff)
downloadgcc-31f8e4f306e9ef25c534afb1601fb9547801ae90.zip
gcc-31f8e4f306e9ef25c534afb1601fb9547801ae90.tar.gz
gcc-31f8e4f306e9ef25c534afb1601fb9547801ae90.tar.bz2
cp-tree.h (BV_USE_VCALL_INDEX_P): New macro.
* cp-tree.h (BV_USE_VCALL_INDEX_P): New macro. (BV_GENERATE_THUNK_WITH_VTABLE_P): Likewise. (lang_decl_flags): Add generate_with_vtable_p. Make vcall_offset a tree, not an int. (THUNK_GENERATE_WITH_VTABLE_P): New macro. (make_thunk): Change prototype. (emit_thunk): Rename to use_thunk. (mangle_thunk): Change prototype. * class.c (get_derived_offset): Simplify. (copy_virtuals): Clear BV_USE_VCALL_INDEX_P and BV_GENERATE_THUNK_WITH_VTABLE_P. (build_primary_vtable): Simplify. (add_virtual_function): Use BV_FN, rather than TREE_VALUE. (dfs_find_base): Remove. (update_vtable_entry_for_fn): Correct bug in finding the base where a virtual function was first declared. Figure out whether or not to emit a vcall-thunk with the vtables in which it appears. Correct logic for deciding whether to use an ordinary thunk, or a vcall thunk. (finish_struct_1): Remove unnecssary code. (build_vtbl_initializer): Use ssize_int for the running counter of negative indices. (build_vtbl_initializer): Only use vcall thunks where necessary. Mark thunks as needing to be emitted with their vtables, or not. (build_vbase_offset_vtbl_entries): Adjust for use of ssize_int in indices. Use size_binop. (dfs_build_vcall_offset_vtbl_entries): Don't rely on BINFO_PRIMARY_MARKED_P here. Use BV_FN consistently. Use size_binop. (build_rtti_vtbl_entries): Adjust call to build_vtable_entry. (build_vtable_entry): Mark thunks as needing to be emitted with their vtables, or not. * decl.c (lang_mark_tree): Mark the vcall_offset in a thunk. * decl2.c (mark_vtable_entries): Use use_thunk instead of emit_thunk. * dump.c (dequeue_and_dump): Remove dead code. Dump new thunk information. * error.c (dump_expr): Use BV_FN. * mangle.c (mangle_thunk): Adjust now that vcall_offset is a tree, not an int. * method.c (make_thunk): Likewise. (emit_thunk): Rename to use_thunk. Allow callers to decide whether or not to actually emit the thunk. Adjust for changes in representation of vcall offsets. * search.c (dfs_get_pure_virtuals): Use BV_FN. * semantics.c (emit_associated_thunks): New function. (expand_body): Use it. * ir.texi: Adjust decriptions of thunks. From-SVN: r34656
-rw-r--r--gcc/cp/ChangeLog51
-rw-r--r--gcc/cp/class.c208
-rw-r--r--gcc/cp/cp-tree.h30
-rw-r--r--gcc/cp/decl.c2
-rw-r--r--gcc/cp/decl2.c11
-rw-r--r--gcc/cp/dump.c13
-rw-r--r--gcc/cp/error.c2
-rw-r--r--gcc/cp/ir.texi4
-rw-r--r--gcc/cp/mangle.c12
-rw-r--r--gcc/cp/method.c86
-rw-r--r--gcc/cp/search.c6
-rw-r--r--gcc/cp/semantics.c51
-rw-r--r--gcc/testsuite/g++.old-deja/g++.other/virtual8.C31
13 files changed, 356 insertions, 151 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 1f655b3..0cebeac 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,54 @@
+2000-06-22 Mark Mitchell <mark@codesourcery.com>
+
+ * cp-tree.h (BV_USE_VCALL_INDEX_P): New macro.
+ (BV_GENERATE_THUNK_WITH_VTABLE_P): Likewise.
+ (lang_decl_flags): Add generate_with_vtable_p. Make vcall_offset
+ a tree, not an int.
+ (THUNK_GENERATE_WITH_VTABLE_P): New macro.
+ (make_thunk): Change prototype.
+ (emit_thunk): Rename to use_thunk.
+ (mangle_thunk): Change prototype.
+ * class.c (get_derived_offset): Simplify.
+ (copy_virtuals): Clear BV_USE_VCALL_INDEX_P and
+ BV_GENERATE_THUNK_WITH_VTABLE_P.
+ (build_primary_vtable): Simplify.
+ (add_virtual_function): Use BV_FN, rather than TREE_VALUE.
+ (dfs_find_base): Remove.
+ (update_vtable_entry_for_fn): Correct bug in finding the base
+ where a virtual function was first declared. Figure out whether
+ or not to emit a vcall-thunk with the vtables in which it appears.
+ Correct logic for deciding whether to use an ordinary thunk, or a
+ vcall thunk.
+ (finish_struct_1): Remove unnecssary code.
+ (build_vtbl_initializer): Use ssize_int for the running counter of
+ negative indices.
+ (build_vtbl_initializer): Only use vcall thunks where necessary.
+ Mark thunks as needing to be emitted with their vtables, or not.
+ (build_vbase_offset_vtbl_entries): Adjust for use of ssize_int in
+ indices. Use size_binop.
+ (dfs_build_vcall_offset_vtbl_entries): Don't rely on
+ BINFO_PRIMARY_MARKED_P here. Use BV_FN consistently. Use
+ size_binop.
+ (build_rtti_vtbl_entries): Adjust call to build_vtable_entry.
+ (build_vtable_entry): Mark thunks as needing to be emitted with
+ their vtables, or not.
+ * decl.c (lang_mark_tree): Mark the vcall_offset in a thunk.
+ * decl2.c (mark_vtable_entries): Use use_thunk instead of
+ emit_thunk.
+ * dump.c (dequeue_and_dump): Remove dead code. Dump new thunk
+ information.
+ * error.c (dump_expr): Use BV_FN.
+ * mangle.c (mangle_thunk): Adjust now that vcall_offset is a tree,
+ not an int.
+ * method.c (make_thunk): Likewise.
+ (emit_thunk): Rename to use_thunk. Allow callers to decide
+ whether or not to actually emit the thunk. Adjust for changes in
+ representation of vcall offsets.
+ * search.c (dfs_get_pure_virtuals): Use BV_FN.
+ * semantics.c (emit_associated_thunks): New function.
+ (expand_body): Use it.
+ * ir.texi: Adjust decriptions of thunks.
+
2000-06-22 Jason Merrill <jason@redhat.com>
* pt.c (tsubst_decl, case FUNCTION_DECL): Clear DECL_SAVED_TREE.
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 387451c..71a5aef 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -96,7 +96,7 @@ varray_type local_classes;
static tree get_vfield_name PARAMS ((tree));
static void finish_struct_anon PARAMS ((tree));
static tree build_vbase_pointer PARAMS ((tree, tree));
-static tree build_vtable_entry PARAMS ((tree, tree, tree));
+static tree build_vtable_entry PARAMS ((tree, tree, tree, int));
static tree get_vtable_name PARAMS ((tree));
static tree get_derived_offset PARAMS ((tree, tree));
static tree get_basefndecls PARAMS ((tree, tree));
@@ -162,7 +162,6 @@ static void build_vcall_offset_vtbl_entries PARAMS ((tree, vcall_offset_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));
-static tree dfs_find_base PARAMS ((tree, void *));
static int make_new_vtable PARAMS ((tree, tree));
static void dump_class_hierarchy_r PARAMS ((tree, tree, int));
extern void dump_class_hierarchy PARAMS ((tree));
@@ -685,16 +684,9 @@ get_derived_offset (binfo, type)
{
tree offset1 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
tree offset2;
- int i;
- while (BINFO_BASETYPES (binfo)
- && (i = CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo))) != -1)
- {
- tree binfos = BINFO_BASETYPES (binfo);
- if (BINFO_TYPE (binfo) == type)
- break;
- binfo = TREE_VEC_ELT (binfos, i);
- }
+ while (!same_type_p (BINFO_TYPE (binfo), type))
+ binfo = BINFO_PRIMARY_BINFO (binfo);
offset2 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
return size_binop (MINUS_EXPR, offset1, offset2);
@@ -778,7 +770,11 @@ copy_virtuals (binfo)
copies = copy_list (BINFO_VIRTUALS (binfo));
for (t = copies; t; t = TREE_CHAIN (t))
- BV_VCALL_INDEX (t) = NULL_TREE;
+ {
+ BV_VCALL_INDEX (t) = NULL_TREE;
+ BV_USE_VCALL_INDEX_P (t) = 0;
+ BV_GENERATE_THUNK_WITH_VTABLE_P (t) = 0;
+ }
return copies;
}
@@ -793,7 +789,8 @@ static int
build_primary_vtable (binfo, type)
tree binfo, type;
{
- tree virtuals, decl;
+ tree decl;
+ tree virtuals;
decl = get_vtable_decl (type, /*complete=*/0);
@@ -825,9 +822,7 @@ build_primary_vtable (binfo, type)
on our first approximation. */
TYPE_BINFO_VTABLE (type) = decl;
TYPE_BINFO_VIRTUALS (type) = virtuals;
-
- binfo = TYPE_BINFO (type);
- SET_BINFO_NEW_VTABLE_MARKED (binfo, type);
+ SET_BINFO_NEW_VTABLE_MARKED (TYPE_BINFO (type), type);
return 1;
}
@@ -1126,7 +1121,8 @@ add_virtual_function (new_virtuals_p, overridden_virtuals_p,
/* We've already dealt with this function. */
return;
- new_virtual = build_tree_list (NULL_TREE, fndecl);
+ new_virtual = make_node (TREE_LIST);
+ BV_FN (new_virtual) = fndecl;
BV_DELTA (new_virtual) = integer_zero_node;
if (DECL_VINDEX (fndecl) == error_mark_node)
@@ -2590,18 +2586,6 @@ find_final_overrider (t, binfo, fn)
return build_tree_list (ffod.overriding_fn, ffod.overriding_base);
}
-/* Called via dfs_walk. Returns BINFO if BINFO has the same type as
- DATA (which is really an _TYPE node). */
-
-static tree
-dfs_find_base (binfo, data)
- tree binfo;
- void *data;
-{
- return (same_type_p (BINFO_TYPE (binfo), (tree) data)
- ? binfo : NULL_TREE);
-}
-
/* Update a entry in the vtable for BINFO, which is in the hierarchy
dominated by T. FN has been overridden in BINFO; VIRTUALS points
to the corresponding position in the BINFO_VIRTUALS list. */
@@ -2615,26 +2599,36 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals)
{
tree b;
tree overrider;
- tree vindex;
tree delta;
- HOST_WIDE_INT vindex_val;
- HOST_WIDE_INT i;
+ tree virtual_base;
+ int generate_thunk_with_vtable_p;
/* Find the function which originally caused this vtable
entry to be present. */
- vindex = DECL_VINDEX (fn);
- b = dfs_walk (binfo, dfs_find_base, NULL, DECL_VIRTUAL_CONTEXT (fn));
- fn = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (b)));
- i = first_vfun_index (BINFO_TYPE (b));
- vindex_val = tree_low_cst (vindex, 0);
- while (i < vindex_val)
+ b = binfo;
+ while (1)
{
- fn = TREE_CHAIN (fn);
- ++i;
+ tree primary_base;
+ tree f;
+
+ primary_base = BINFO_PRIMARY_BINFO (b);
+ if (!primary_base)
+ break;
+
+ for (f = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (primary_base)));
+ f;
+ f = TREE_CHAIN (f))
+ if (same_signature_p (BV_FN (f), fn))
+ break;
+
+ if (!f)
+ break;
+
+ fn = BV_FN (f);
+ b = primary_base;
}
- fn = BV_FN (fn);
- /* Handle the case of a virtual function defined in BINFO itself. */
+ /* Find the final overrider. */
overrider = find_final_overrider (t, b, fn);
if (overrider == error_mark_node)
return;
@@ -2646,27 +2640,53 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals)
get_derived_offset (binfo,
DECL_VIRTUAL_CONTEXT (fn)),
BINFO_OFFSET (binfo));
+
+ /* 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;
+
+ /* Assume that we will always generate thunks with the vtables that
+ reference them. */
+ generate_thunk_with_vtable_p = 1;
+
+ /* Under the new ABI, we will convert to an intermediate virtual
+ base first, and then use the vcall offset located there to finish
+ the conversion. */
if (flag_new_abi)
{
- /* Under the new ABI, we only need to adjust as far as the
- nearest virtual base. Then we use the vcall offset in the
- virtual bases vtable. */
- for (b = binfo; b; b = BINFO_INHERITANCE_CHAIN (b))
+ while (b)
{
- if (TREE_VIA_VIRTUAL (b))
- break;
+ /* If we find BINFO, then the final overrider is in a class
+ derived from BINFO, so the thunks can be generated with
+ the final overrider. */
+ if (same_type_p (BINFO_TYPE (b), BINFO_TYPE (binfo)))
+ generate_thunk_with_vtable_p = 0;
+
+ /* If we find the final overrider, then we can stop
+ walking. */
if (same_type_p (BINFO_TYPE (b),
BINFO_TYPE (TREE_VALUE (overrider))))
break;
+
+ /* If we find a virtual base, and we haven't yet found the
+ overrider, then there is a virtual base between the
+ declaring base and the final overrider. */
+ if (!virtual_base && TREE_VIA_VIRTUAL (b))
+ {
+ generate_thunk_with_vtable_p = 1;
+ virtual_base = b;
+ }
+
+ b = BINFO_INHERITANCE_CHAIN (b);
}
}
else
- b = NULL_TREE;
+ virtual_base = NULL_TREE;
- if (b && TREE_VIA_VIRTUAL (b))
+ if (virtual_base)
/* The `this' pointer needs to be adjusted to the nearest virtual
base. */
- delta = size_diffop (BINFO_OFFSET (b), delta);
+ delta = size_diffop (BINFO_OFFSET (virtual_base), delta);
else
/* The `this' pointer needs to be adjusted from pointing to
BINFO to pointing at the base where the final overrider
@@ -2678,6 +2698,11 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals)
TREE_PURPOSE (overrider),
delta,
virtuals);
+
+ if (virtual_base)
+ BV_USE_VCALL_INDEX_P (*virtuals) = 1;
+ if (generate_thunk_with_vtable_p)
+ BV_GENERATE_THUNK_WITH_VTABLE_P (*virtuals) = 1;
}
/* Called from modify_all_vtables via dfs_walk. */
@@ -5074,17 +5099,9 @@ finish_struct_1 (t)
{
tree binfo = CLASSTYPE_PRIMARY_BINFO (t);
- /* This class contributes nothing new to the virtual function
- table. However, it may have declared functions which
- went into the virtual function table "inherited" from the
- base class. If so, we grab a copy of those updated functions,
- and pretend they are ours. */
-
- /* See if we should steal the virtual info from base class. */
- if (TYPE_BINFO_VTABLE (t) == NULL_TREE)
- TYPE_BINFO_VTABLE (t) = BINFO_VTABLE (binfo);
- if (TYPE_BINFO_VIRTUALS (t) == NULL_TREE)
- TYPE_BINFO_VIRTUALS (t) = BINFO_VIRTUALS (binfo);
+ /* If this class uses a different vtable than its primary base
+ then when we will need to initialize our vptr after the base
+ class constructor runs. */
if (TYPE_BINFO_VTABLE (t) != BINFO_VTABLE (binfo))
CLASSTYPE_NEEDS_VIRTUAL_REINIT (t) = 1;
}
@@ -6992,7 +7009,7 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)
vod.last_init = &vod.inits;
vod.primary_p = (binfo == TYPE_BINFO (t));
/* The first vbase or vcall offset is at index -3 in the vtable. */
- vod.index = build_int_2 (-3, -1);
+ vod.index = ssize_int (-3);
/* Add entries to the vtable for RTTI. */
build_rtti_vtbl_entries (binfo, rtti_binfo, &vod);
@@ -7023,7 +7040,15 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)
/* Pull the offset for `this', and the function to call, out of
the list. */
delta = BV_DELTA (v);
- vcall_index = BV_VCALL_INDEX (v);
+
+ if (BV_USE_VCALL_INDEX_P (v))
+ {
+ vcall_index = BV_VCALL_INDEX (v);
+ my_friendly_assert (vcall_index != NULL_TREE, 20000621);
+ }
+ else
+ vcall_index = NULL_TREE;
+
fn = BV_FN (v);
my_friendly_assert (TREE_CODE (delta) == INTEGER_CST, 19990727);
my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727);
@@ -7039,7 +7064,8 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)
/* The address of a function can't change. */
TREE_CONSTANT (pfn) = 1;
/* Enter it in the vtable. */
- init = build_vtable_entry (delta, vcall_index, pfn);
+ init = build_vtable_entry (delta, vcall_index, pfn,
+ BV_GENERATE_THUNK_WITH_VTABLE_P (v));
/* And add it to the chain of initializers. */
vfun_inits = tree_cons (NULL_TREE, init, vfun_inits);
}
@@ -7125,7 +7151,7 @@ build_vbase_offset_vtbl_entries (binfo, vod)
/* Figure out where we can find this vbase offset. */
delta = size_binop (MULT_EXPR,
- convert (ssizetype, vod->index),
+ vod->index,
convert (ssizetype,
TYPE_SIZE_UNIT (vtable_entry_type)));
if (vod->primary_p)
@@ -7146,8 +7172,7 @@ build_vbase_offset_vtbl_entries (binfo, vod)
}
/* The next vbase will come at a more negative offset. */
- vod->index = fold (build (MINUS_EXPR, integer_type_node,
- vod->index, integer_one_node));
+ vod->index = size_binop (MINUS_EXPR, vod->index, ssize_int (1));
/* The initializer is the delta from BINFO to this virtual base.
The vbase offsets go in reverse inheritance-graph order, and
@@ -7174,8 +7199,11 @@ dfs_build_vcall_offset_vtbl_entries (binfo, data)
tree derived_virtuals;
tree base_virtuals;
tree binfo_inits;
+ /* If BINFO is a primary base, this is the least derived class of
+ BINFO that is not a primary base. */
tree non_primary_binfo;
- tree b;
+ /* The primary base of BINFO. */
+ tree primary_binfo;
int i;
vod = (vcall_offset_data *) data;
@@ -7185,16 +7213,21 @@ dfs_build_vcall_offset_vtbl_entries (binfo, data)
hierarchy until we find the 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_PRIMARY_MARKED_P (non_primary_binfo))
- non_primary_binfo = BINFO_INHERITANCE_CHAIN (non_primary_binfo);
+ while (BINFO_INHERITANCE_CHAIN (non_primary_binfo))
+ {
+ tree b = BINFO_INHERITANCE_CHAIN (non_primary_binfo);
+ if (BINFO_PRIMARY_BINFO (b) != non_primary_binfo)
+ break;
+ non_primary_binfo = b;
+ }
/* Skip virtuals that we have already handled in a primary base
class. */
base_virtuals = BINFO_VIRTUALS (binfo);
derived_virtuals = BINFO_VIRTUALS (non_primary_binfo);
- b = BINFO_PRIMARY_BINFO (binfo);
- if (b)
- for (i = 0; i < CLASSTYPE_VSIZE (BINFO_TYPE (b)); ++i)
+ primary_binfo = BINFO_PRIMARY_BINFO (binfo);
+ if (primary_binfo)
+ for (i = 0; i < CLASSTYPE_VSIZE (BINFO_TYPE (primary_binfo)); ++i)
{
base_virtuals = TREE_CHAIN (base_virtuals);
derived_virtuals = TREE_CHAIN (derived_virtuals);
@@ -7206,7 +7239,7 @@ dfs_build_vcall_offset_vtbl_entries (binfo, data)
base_virtuals = TREE_CHAIN (base_virtuals))
{
/* Figure out what function we're looking at. */
- tree fn = TREE_VALUE (derived_virtuals);
+ tree fn = BV_FN (derived_virtuals);
tree base;
tree base_binfo;
size_t i;
@@ -7220,7 +7253,7 @@ dfs_build_vcall_offset_vtbl_entries (binfo, data)
tree derived_entry;
derived_entry = VARRAY_TREE (vod->fns, i);
- if (same_signature_p (TREE_VALUE (derived_entry), fn))
+ if (same_signature_p (BV_FN (derived_entry), fn))
{
BV_VCALL_INDEX (derived_virtuals)
= BV_VCALL_INDEX (derived_entry);
@@ -7259,8 +7292,7 @@ dfs_build_vcall_offset_vtbl_entries (binfo, data)
/* The next vcall offset will be found at a more negative
offset. */
- vod->index = fold (build (MINUS_EXPR, integer_type_node,
- vod->index, integer_one_node));
+ vod->index = size_binop (MINUS_EXPR, vod->index, ssize_int (1));
/* Keep track of this function. */
VARRAY_PUSH_TREE (vod->fns, derived_virtuals);
@@ -7383,7 +7415,8 @@ build_rtti_vtbl_entries (binfo, rtti_binfo, vod)
vtable. */
init = build1 (ADDR_EXPR, vfunc_ptr_type_node, decl);
TREE_CONSTANT (init) = 1;
- init = build_vtable_entry (offset, integer_zero_node, init);
+ init = build_vtable_entry (offset, NULL_TREE, init,
+ /*generate_with_vtable_p=*/0);
}
*vod->last_init = build_tree_list (NULL_TREE, init);
vod->last_init = &TREE_CHAIN (*vod->last_init);
@@ -7410,28 +7443,23 @@ build_rtti_vtbl_entries (binfo, rtti_binfo, vod)
ABI.) */
static tree
-build_vtable_entry (delta, vcall_index, entry)
+build_vtable_entry (delta, vcall_index, entry, generate_with_vtable_p)
tree delta;
tree vcall_index;
tree entry;
+ int generate_with_vtable_p;
{
- if (!vcall_index)
- vcall_index = integer_zero_node;
-
if (flag_vtable_thunks)
{
- HOST_WIDE_INT idelta;
- HOST_WIDE_INT ivindex;
tree fn;
- idelta = tree_low_cst (delta, 0);
- ivindex = tree_low_cst (vcall_index, 0);
fn = TREE_OPERAND (entry, 0);
- if ((idelta || ivindex)
+ if ((!integer_zerop (delta) || vcall_index != NULL_TREE)
&& fn != abort_fndecl
&& !DECL_TINFO_FN_P (fn))
{
- entry = make_thunk (entry, idelta, ivindex);
+ entry = make_thunk (entry, delta, vcall_index,
+ generate_with_vtable_p);
entry = build1 (ADDR_EXPR, vtable_entry_type, entry);
TREE_READONLY (entry) = 1;
TREE_CONSTANT (entry) = 1;
@@ -7449,7 +7477,7 @@ build_vtable_entry (delta, vcall_index, entry)
tree entry = build (CONSTRUCTOR, vtable_entry_type, NULL_TREE, elems);
/* We don't use vcall offsets when not using vtable thunks. */
- my_friendly_assert (integer_zerop (vcall_index), 20000125);
+ my_friendly_assert (vcall_index == NULL_TREE, 20000125);
/* DELTA used to be constructed by `size_int' and/or size_binop,
which caused overflow problems when it was negative. That should
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b93a29e..89e637e 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -45,6 +45,7 @@ Boston, MA 02111-1307, USA. */
SCOPE_BEGIN_P (in SCOPE_STMT)
CTOR_BEGIN_P (in CTOR_STMT)
DECL_PRETTY_FUNCTION_P (in VAR_DECL)
+ BV_USE_VCALL_INDEX_P (in the BINFO_VIRTUALS TREE_LIST)
1: IDENTIFIER_VIRTUAL_P.
TI_PENDING_TEMPLATE_FLAG.
TEMPLATE_PARMS_FOR_INLINE.
@@ -57,6 +58,7 @@ Boston, MA 02111-1307, USA. */
ICS_ELLIPSIS_FLAG (in _CONV)
STMT_IS_FULL_EXPR_P (in _STMT)
BINFO_ACCESS (in BINFO)
+ BV_GENERATE_THUNK_WITH_VTABLE_P (in TREE_LIST)
2: IDENTIFIER_OPNAME_P.
TYPE_POLYMORHPIC_P (in _TYPE)
ICS_THIS_FLAG (in _CONV)
@@ -128,7 +130,9 @@ Boston, MA 02111-1307, USA. */
the this pointer points to an object of the base class.
The BV_VCALL_INDEX of each node, if non-NULL, gives the vtable
- index of the vcall offset for this entry.
+ index of the vcall offset for this entry. If
+ BV_USE_VCALL_INDEX_P then the corresponding vtable entry should
+ use a virtual thunk, as opposed to an ordinary thunk.
The BV_FN is the declaration for the virtual function itself.
When CLASSTYPE_COM_INTERFACE_P does not hold, the first entry
@@ -1841,6 +1845,15 @@ struct lang_type
/* The function to call. */
#define BV_FN(NODE) (TREE_VALUE (NODE))
+/* Nonzero if we should use a virtual thunk for this entry. */
+#define BV_USE_VCALL_INDEX_P(NODE) \
+ (TREE_LANG_FLAG_0 (NODE))
+
+/* Nonzero if we should generate this thunk when the vtable that
+ references it is emitted, rather than with the final overrider. */
+#define BV_GENERATE_THUNK_WITH_VTABLE_P(NODE) \
+ (TREE_LANG_FLAG_1 (NODE))
+
/* The most derived class. */
@@ -1901,7 +1914,8 @@ struct lang_decl_flags
unsigned tinfo_fn_p : 1;
unsigned assignment_operator_p : 1;
unsigned anticipated_p : 1;
- unsigned dummy : 2;
+ unsigned generate_with_vtable_p : 1;
+ unsigned dummy : 1;
tree context;
@@ -1924,7 +1938,7 @@ struct lang_decl_flags
/* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is
THUNK_VCALL_OFFSET. */
- HOST_WIDE_INT vcall_offset;
+ tree vcall_offset;
} u2;
};
@@ -3141,6 +3155,10 @@ extern int flag_new_for_scope;
#define THUNK_VCALL_OFFSET(DECL) \
(DECL_LANG_SPECIFIC (DECL)->decl_flags.u2.vcall_offset)
+/* Nonzero if this thunk should be generated with the vtable that
+ references it. */
+#define THUNK_GENERATE_WITH_VTABLE_P(DECL) \
+ (DECL_LANG_SPECIFIC (DECL)->decl_flags.generate_with_vtable_p)
/* These macros provide convenient access to the various _STMT nodes
created when parsing template declarations. */
@@ -4244,8 +4262,8 @@ extern tree build_overload_with_type PARAMS ((tree, tree));
extern tree build_destructor_name PARAMS ((tree));
extern tree build_opfncall PARAMS ((enum tree_code, int, tree, tree, tree));
extern tree hack_identifier PARAMS ((tree, tree));
-extern tree make_thunk PARAMS ((tree, int, int));
-extern void emit_thunk PARAMS ((tree));
+extern tree make_thunk PARAMS ((tree, tree, tree, int));
+extern void use_thunk PARAMS ((tree, int));
extern void synthesize_method PARAMS ((tree));
extern tree get_id_2 PARAMS ((const char *, tree));
extern tree implicitly_declare_fn PARAMS ((special_function_kind, tree, int));
@@ -4718,7 +4736,7 @@ extern tree mangle_typeinfo_string_for_type PARAMS ((tree));
extern tree mangle_vtbl_for_type PARAMS ((tree));
extern tree mangle_vtt_for_type PARAMS ((tree));
extern tree mangle_ctor_vtbl_for_type PARAMS ((tree, tree));
-extern tree mangle_thunk PARAMS ((tree, int, int));
+extern tree mangle_thunk PARAMS ((tree, tree, tree));
extern tree mangle_conv_op_name_for_type PARAMS ((tree));
extern tree mangle_guard_variable PARAMS ((tree));
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 5451306..10d9d08 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -15063,6 +15063,8 @@ lang_mark_tree (t)
&& !DECL_GLOBAL_DTOR_P (t)
&& !DECL_THUNK_P (t))
ggc_mark_tree (ld->decl_flags.u2.access);
+ else if (DECL_THUNK_P (t))
+ ggc_mark_tree (ld->decl_flags.u2.vcall_offset);
ggc_mark_tree (ld->decl_flags.context);
if (TREE_CODE (t) != NAMESPACE_DECL)
ggc_mark_tree (ld->decl_flags.u.template_info);
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index b034d78..8fe160e 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -2425,11 +2425,12 @@ mark_vtable_entries (decl)
fn = TREE_OPERAND (fnaddr, 0);
TREE_ADDRESSABLE (fn) = 1;
- if (DECL_THUNK_P (fn) && DECL_EXTERNAL (fn))
- {
- DECL_EXTERNAL (fn) = 0;
- emit_thunk (fn);
- }
+ /* When we don't have vcall offsets, we output thunks whenever
+ we output the vtables that contain them. With vcall offsets,
+ we know all the thunks we'll need when we emit a virtual
+ function, so we emit the thunks there instead. */
+ if (DECL_THUNK_P (fn))
+ use_thunk (fn, THUNK_GENERATE_WITH_VTABLE_P (fn));
mark_used (fn);
}
}
diff --git a/gcc/cp/dump.c b/gcc/cp/dump.c
index ca3baa0..9b71106 100644
--- a/gcc/cp/dump.c
+++ b/gcc/cp/dump.c
@@ -566,7 +566,7 @@ dequeue_and_dump (di)
dump_string(di, "extern");
else
dump_string (di, "static");
- if (TREE_CODE (t) == FUNCTION_DECL)
+ if (!DECL_THUNK_P (t))
{
if (DECL_FUNCTION_MEMBER_P (t))
dump_string (di, "member");
@@ -578,13 +578,6 @@ dequeue_and_dump (di)
dump_string (di, "operator");
if (DECL_CONV_FN_P (t))
dump_string (di, "conversion");
- if (DECL_THUNK_P (t))
- {
- dump_string (di, "thunk");
- dump_int (di, "dlta", THUNK_DELTA (t));
- dump_int (di, "vcll", THUNK_VCALL_OFFSET (t));
- dump_child ("fn", DECL_INITIAL (t));
- }
if (DECL_GLOBAL_CTOR_P (t) || DECL_GLOBAL_DTOR_P (t))
{
if (DECL_GLOBAL_CTOR_P (t))
@@ -600,8 +593,10 @@ dequeue_and_dump (di)
}
else
{
+ dump_string (di, "thunk");
dump_int (di, "dlta", THUNK_DELTA (t));
- dump_child ("init", DECL_INITIAL (t));
+ dump_child ("vcll", THUNK_VCALL_OFFSET (t));
+ dump_child ("fn", DECL_INITIAL (t));
}
break;
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 8d2ad61..37c8dd6 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -1867,7 +1867,7 @@ dump_expr (t, flags)
}
if (virtuals)
{
- dump_expr (TREE_VALUE (virtuals),
+ dump_expr (BV_FN (virtuals),
flags | TS_EXPR_PARENS);
break;
}
diff --git a/gcc/cp/ir.texi b/gcc/cp/ir.texi
index 429c155..343dfc8 100644
--- a/gcc/cp/ir.texi
+++ b/gcc/cp/ir.texi
@@ -1040,8 +1040,8 @@ returning to the thunk. The first parameter to the thunk is always the
value. (The @code{THUNK_DELTA} is an @code{int}, not an
@code{INTEGER_CST}.)
-Then, if @code{THUNK_VCALL_OFFSET} (also an @code{int}) is non-zero the
-adjusted @code{this} pointer must be adjusted again. The complete
+Then, if @code{THUNK_VCALL_OFFSET} (an @code{INTEGER_CST}) is non-zero
+the adjusted @code{this} pointer must be adjusted again. The complete
calculation is given by the following pseudo-code:
@example
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index d6c7181..a1d1d55 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -2076,7 +2076,7 @@ mangle_ctor_vtbl_for_type (type, binfo)
/* Return an identifier for the mangled name of a thunk to FN_DECL.
OFFSET is the initial adjustment to this used to find the vptr. If
- VCALL_OFFSET is non-zero, this is a virtual thunk, and it is the
+ VCALL_OFFSET is non-NULL, this is a virtual thunk, and it is the
vtbl offset in bytes.
<special-name> ::= Th <offset number> _ <base encoding>
@@ -2087,8 +2087,8 @@ mangle_ctor_vtbl_for_type (type, binfo)
tree
mangle_thunk (fn_decl, offset, vcall_offset)
tree fn_decl;
- int offset;
- int vcall_offset;
+ tree offset;
+ tree vcall_offset;
{
const char *result;
@@ -2104,14 +2104,14 @@ mangle_thunk (fn_decl, offset, vcall_offset)
write_char ('h');
/* For either flavor, write the offset to this. */
- write_signed_number (offset);
+ write_integer_cst (offset);
write_char ('_');
/* For a virtual thunk, add the vcall offset. */
- if (vcall_offset != 0)
+ if (vcall_offset)
{
/* Virtual thunk. Write the vcall offset and base type name. */
- write_signed_number (vcall_offset);
+ write_integer_cst (vcall_offset);
write_char ('_');
}
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 04685d4..33ad29a 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -2063,15 +2063,29 @@ hack_identifier (value, name)
DELTA is the offset to this and VCALL_INDEX is zero. */
tree
-make_thunk (function, delta, vcall_index)
+make_thunk (function, delta, vcall_index, generate_with_vtable_p)
tree function;
- int delta;
- int vcall_index;
+ tree delta;
+ tree vcall_index;
+ int generate_with_vtable_p;
{
tree thunk_id;
tree thunk;
tree func_decl;
- int vcall_offset = vcall_index * int_size_in_bytes (vtable_entry_type);
+ tree vcall_offset;
+ HOST_WIDE_INT d;
+
+ /* Scale the VCALL_INDEX to be in terms of bytes. */
+ if (vcall_index)
+ vcall_offset
+ = size_binop (MULT_EXPR,
+ vcall_index,
+ convert (ssizetype,
+ TYPE_SIZE_UNIT (vtable_entry_type)));
+ else
+ vcall_offset = NULL_TREE;
+
+ d = tree_low_cst (delta, 0);
if (TREE_CODE (function) != ADDR_EXPR)
abort ();
@@ -2080,22 +2094,23 @@ make_thunk (function, delta, vcall_index)
abort ();
if (flag_new_abi)
- thunk_id = mangle_thunk (TREE_OPERAND (function, 0), delta, vcall_offset);
+ thunk_id = mangle_thunk (TREE_OPERAND (function, 0),
+ delta, vcall_offset);
else
{
OB_INIT ();
OB_PUTS ("__thunk_");
- if (delta > 0)
+ if (d > 0)
{
OB_PUTC ('n');
- icat (delta);
+ icat (d);
}
else
- icat (-delta);
+ icat (-d);
OB_PUTC ('_');
if (vcall_index)
{
- icat (vcall_index);
+ icat (tree_low_cst (vcall_index, 0));
OB_PUTC ('_');
}
OB_PUTID (DECL_ASSEMBLER_NAME (func_decl));
@@ -2121,8 +2136,9 @@ make_thunk (function, delta, vcall_index)
comdat_linkage (thunk);
SET_DECL_THUNK_P (thunk);
DECL_INITIAL (thunk) = function;
- THUNK_DELTA (thunk) = delta;
+ THUNK_DELTA (thunk) = d;
THUNK_VCALL_OFFSET (thunk) = vcall_offset;
+ THUNK_GENERATE_WITH_VTABLE_P (thunk) = generate_with_vtable_p;
/* The thunk itself is not a constructor or destructor, even if
the thing it is thunking to is. */
DECL_INTERFACE_KNOWN (thunk) = 1;
@@ -2142,6 +2158,8 @@ make_thunk (function, delta, vcall_index)
DECL_DEFERRED_FN (thunk) = 0;
/* So that finish_file can write out any thunks that need to be: */
pushdecl_top_level (thunk);
+ /* Create RTL for this thunk so that its address can be taken. */
+ make_function_rtl (thunk);
}
return thunk;
}
@@ -2149,17 +2167,20 @@ make_thunk (function, delta, vcall_index)
/* Emit the definition of a C++ multiple inheritance vtable thunk. */
void
-emit_thunk (thunk_fndecl)
+use_thunk (thunk_fndecl, emit_p)
tree thunk_fndecl;
+ int emit_p;
+
{
tree fnaddr;
tree function;
- int delta;
- int vcall_offset;
+ tree vcall_offset;
+ HOST_WIDE_INT delta;
if (TREE_ASM_WRITTEN (thunk_fndecl))
return;
-
+
+ fnaddr = DECL_INITIAL (thunk_fndecl);
if (TREE_CODE (DECL_INITIAL (thunk_fndecl)) != ADDR_EXPR)
/* We already turned this thunk into an ordinary function.
There's no need to process this thunk again. (We can't just
@@ -2167,16 +2188,25 @@ emit_thunk (thunk_fndecl)
FNADDR_FROM_VTABLE_ENTRY and friends.) */
return;
- fnaddr = DECL_INITIAL (thunk_fndecl);
- function = TREE_OPERAND (fnaddr, 0);
- delta = THUNK_DELTA (thunk_fndecl);
- vcall_offset = THUNK_VCALL_OFFSET (thunk_fndecl);
+ /* Thunks are always addressable; they only appear in vtables. */
+ TREE_ADDRESSABLE (thunk_fndecl) = 1;
+ /* 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;
+ if (!emit_p)
+ return;
- if (current_function_decl)
- abort ();
+ delta = THUNK_DELTA (thunk_fndecl);
+ vcall_offset = THUNK_VCALL_OFFSET (thunk_fndecl);
+
+ /* And, if we need to emit the thunk, it's used. */
+ mark_used (thunk_fndecl);
+ /* This thunk is actually defined. */
+ DECL_EXTERNAL (thunk_fndecl) = 0;
if (flag_syntax_only)
{
@@ -2184,14 +2214,13 @@ emit_thunk (thunk_fndecl)
return;
}
+ push_to_top_level ();
+
#ifdef ASM_OUTPUT_MI_THUNK
- if (vcall_offset == 0)
+ if (!vcall_offset)
{
const char *fnname;
current_function_decl = thunk_fndecl;
- /* Make sure we build up its RTL before we go onto the
- temporary obstack. */
- make_function_rtl (thunk_fndecl);
DECL_RESULT (thunk_fndecl)
= build_decl (RESULT_DECL, 0, integer_type_node);
fnname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0);
@@ -2230,17 +2259,15 @@ emit_thunk (thunk_fndecl)
DECL_ARGUMENTS (thunk_fndecl) = a;
DECL_RESULT (thunk_fndecl) = NULL_TREE;
- push_to_top_level ();
start_function (NULL_TREE, thunk_fndecl, NULL_TREE, SF_PRE_PARSED);
store_parm_decls ();
/* Adjust the this pointer by the constant. */
t = ssize_int (delta);
- TREE_TYPE (t) = signed_type (sizetype);
t = fold (build (PLUS_EXPR, TREE_TYPE (a), a, t));
/* If there's a vcall offset, look up that value in the vtable and
adjust the `this' pointer again. */
- if (vcall_offset != 0)
+ if (!integer_zerop (vcall_offset))
{
tree orig_this;
@@ -2254,7 +2281,7 @@ emit_thunk (thunk_fndecl)
/* Form the vtable address. */
t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
/* Find the entry with the vcall offset. */
- t = build (PLUS_EXPR, TREE_TYPE (t), t, ssize_int (vcall_offset));
+ t = build (PLUS_EXPR, TREE_TYPE (t), t, vcall_offset);
/* Calculate the offset itself. */
t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
/* Adjust the `this' pointer. */
@@ -2281,8 +2308,9 @@ emit_thunk (thunk_fndecl)
BLOCK_VARS (DECL_INITIAL (thunk_fndecl))
= DECL_ARGUMENTS (thunk_fndecl);
expand_body (finish_function (0));
- pop_from_top_level ();
}
+
+ pop_from_top_level ();
}
/* Code for synthesizing methods which have default semantics defined. */
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index efb8e6a..78fb5a4 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -2295,9 +2295,9 @@ dfs_get_pure_virtuals (binfo, data)
for (virtuals = BINFO_VIRTUALS (binfo);
virtuals;
virtuals = TREE_CHAIN (virtuals))
- if (DECL_PURE_VIRTUAL_P (TREE_VALUE (virtuals)))
+ if (DECL_PURE_VIRTUAL_P (BV_FN (virtuals)))
CLASSTYPE_PURE_VIRTUALS (type)
- = tree_cons (NULL_TREE, TREE_VALUE (virtuals),
+ = tree_cons (NULL_TREE, BV_FN (virtuals),
CLASSTYPE_PURE_VIRTUALS (type));
}
@@ -2341,7 +2341,7 @@ get_pure_virtuals (type)
virtuals;
virtuals = TREE_CHAIN (virtuals))
{
- tree base_fndecl = TREE_VALUE (virtuals);
+ tree base_fndecl = BV_FN (virtuals);
if (DECL_NEEDS_FINAL_OVERRIDER_P (base_fndecl))
cp_error ("`%#D' needs a final overrider", base_fndecl);
}
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 5cebea6..68dac42 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -50,6 +50,7 @@ static tree expand_cond PARAMS ((tree));
static tree maybe_convert_cond PARAMS ((tree));
static tree simplify_aggr_init_exprs_r PARAMS ((tree *, int *, void *));
static void deferred_type_access_control PARAMS ((void));
+static void emit_associated_thunks PARAMS ((tree));
/* Record the fact that STMT was the last statement added to the
statement tree. */
@@ -2962,6 +2963,53 @@ simplify_aggr_init_exprs_r (tp, walk_subtrees, data)
return NULL_TREE;
}
+/* Emit all thunks to FN that should be emitted when FN is emitted. */
+
+static void
+emit_associated_thunks (fn)
+ tree fn;
+{
+ /* When we use vcall offsets, we emit thunks with the virtual
+ functions to which they thunk. The whole point of vcall offsets
+ is so that you can know statically the entire set of thunks that
+ will ever be needed for a given virtual function, thereby
+ enabling you to output all the thunks with the function itself. */
+ if (vcall_offsets_in_vtable_p () && DECL_VIRTUAL_P (fn))
+ {
+ tree binfo;
+ tree v;
+
+ for (binfo = TYPE_BINFO (DECL_CONTEXT (fn));
+ binfo;
+ binfo = TREE_CHAIN (binfo))
+ for (v = BINFO_VIRTUALS (binfo); v; v = TREE_CHAIN (v))
+ if (BV_FN (v) == fn
+ && (!integer_zerop (BV_DELTA (v))
+ || BV_VCALL_INDEX (v)))
+ {
+ tree thunk;
+ tree vcall_index;
+
+ if (BV_USE_VCALL_INDEX_P (v))
+ {
+ vcall_index = BV_VCALL_INDEX (v);
+ my_friendly_assert (vcall_index != NULL_TREE, 20000621);
+ }
+ else
+ vcall_index = NULL_TREE;
+
+ thunk = make_thunk (build1 (ADDR_EXPR,
+ vfunc_ptr_type_node,
+ fn),
+ BV_DELTA (v),
+ vcall_index,
+ /*generate_with_vtable_p=*/0);
+ use_thunk (thunk, /*emit_p=*/1);
+ }
+ }
+}
+
+
/* Generate RTL for FN. */
void
@@ -3037,6 +3085,9 @@ expand_body (fn)
return;
}
+ /* Emit any thunks that should be emitted at the same time as FN. */
+ emit_associated_thunks (fn);
+
timevar_push (TV_INTEGRATION);
/* Optimize the body of the function before expanding it. */
diff --git a/gcc/testsuite/g++.old-deja/g++.other/virtual8.C b/gcc/testsuite/g++.old-deja/g++.other/virtual8.C
new file mode 100644
index 0000000..9f32ca0
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.other/virtual8.C
@@ -0,0 +1,31 @@
+extern "C" void printf (const char*, ...);
+
+struct A
+{
+ virtual void f () {
+ printf ("%x\n", this);
+ }
+};
+
+struct B : public A
+{
+};
+
+struct C : public A
+{
+};
+
+struct D : virtual public B, public C
+{
+};
+
+int main ()
+{
+ D d;
+
+ A* a1 = (A*) (B*) &d;
+ A* a2 = (A*) (C*) &d;
+
+ a1->f ();
+ a2->f ();
+}