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
This commit is contained in:
parent
11fc1858a0
commit
31f8e4f306
@ -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.
|
||||
|
210
gcc/cp/class.c
210
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;
|
||||
}
|
||||
fn = BV_FN (fn);
|
||||
tree primary_base;
|
||||
tree f;
|
||||
|
||||
/* Handle the case of a virtual function defined in BINFO itself. */
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 ('_');
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
/* 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;
|
||||
|
||||
delta = THUNK_DELTA (thunk_fndecl);
|
||||
vcall_offset = THUNK_VCALL_OFFSET (thunk_fndecl);
|
||||
|
||||
TREE_ADDRESSABLE (function) = 1;
|
||||
mark_used (function);
|
||||
|
||||
if (current_function_decl)
|
||||
abort ();
|
||||
/* 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. */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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. */
|
||||
|
31
gcc/testsuite/g++.old-deja/g++.other/virtual8.C
Normal file
31
gcc/testsuite/g++.old-deja/g++.other/virtual8.C
Normal file
@ -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 ();
|
||||
}
|
Loading…
Reference in New Issue
Block a user