Commit ca36f057 by Mark Mitchell Committed by Mark Mitchell

class.c: Reorganize to put virtual function table initialization machinery at the end of...

	* class.c: Reorganize to put virtual function table initialization
	machinery at the end of the file.

From-SVN: r32798
parent d6121128
2000-03-28 Mark Mitchell <mark@codesourcery.com>
* class.c: Reorganize to put virtual function table initialization
machinery at the end of the file.
2000-03-28 Jason Merrill <jason@casey.cygnus.com>
* class.c (finish_struct): Use bitsize_zero_node.
......
......@@ -256,438 +256,134 @@ build_vbase_pointer_fields (rli, empty_p)
return vbase_decls;
}
/* Called from build_vbase_offset_vtbl_entries via dfs_walk. */
/* Returns a pointer to the virtual base class of EXP that has the
indicated TYPE. EXP is of class type, not a pointer type. */
static tree
dfs_build_vbase_offset_vtbl_entries (binfo, data)
tree binfo;
void *data;
build_vbase_pointer (exp, type)
tree exp, type;
{
tree list = (tree) data;
if (TREE_TYPE (list) == binfo)
/* The TREE_TYPE of LIST is the base class from which we started
walking. If that BINFO is virtual it's not a virtual baseclass
of itself. */
;
else if (TREE_VIA_VIRTUAL (binfo))
if (vbase_offsets_in_vtable_p ())
{
tree init;
tree vbase;
tree vbase_ptr;
/* Remember the index to the vbase offset for this virtual
base. */
vbase = BINFO_FOR_VBASE (BINFO_TYPE (binfo), TREE_PURPOSE (list));
if (!TREE_VALUE (list))
BINFO_VPTR_FIELD (vbase) = build_int_2 (-3, 0);
else
{
BINFO_VPTR_FIELD (vbase) = TREE_PURPOSE (TREE_VALUE (list));
BINFO_VPTR_FIELD (vbase)
= fold (build (MINUS_EXPR, integer_type_node,
BINFO_VPTR_FIELD (vbase), integer_one_node));
}
/* And record the offset at which this virtual base lies in the
vtable. */
init = BINFO_OFFSET (binfo);
TREE_VALUE (list) = tree_cons (BINFO_VPTR_FIELD (vbase),
init, TREE_VALUE (list));
/* Find the shared copy of TYPE; that's where the vtable offset
is recorded. */
vbase = BINFO_FOR_VBASE (type, TREE_TYPE (exp));
/* Find the virtual function table pointer. */
vbase_ptr = build_vfield_ref (exp, TREE_TYPE (exp));
/* Compute the location where the offset will lie. */
vbase_ptr = build_binary_op (PLUS_EXPR,
vbase_ptr,
BINFO_VPTR_FIELD (vbase));
vbase_ptr = build1 (NOP_EXPR,
build_pointer_type (ptrdiff_type_node),
vbase_ptr);
/* Add the contents of this location to EXP. */
return build (PLUS_EXPR,
build_pointer_type (type),
build_unary_op (ADDR_EXPR, exp, /*noconvert=*/0),
build1 (INDIRECT_REF, ptrdiff_type_node, vbase_ptr));
}
SET_BINFO_VTABLE_PATH_MARKED (binfo);
return NULL_TREE;
}
/* Returns the initializers for the vbase offset entries in the vtable
for BINFO (which is part of the class hierarchy dominated by T), in
reverse order. */
static tree
build_vbase_offset_vtbl_entries (binfo, t)
tree binfo;
tree t;
{
tree inits;
tree init;
tree list;
/* Under the old ABI, pointers to virtual bases are stored in each
object. */
if (!vbase_offsets_in_vtable_p ())
return NULL_TREE;
/* If there are no virtual baseclasses, then there is nothing to
do. */
if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo)))
return NULL_TREE;
inits = NULL_TREE;
/* The offsets are allocated in the reverse order of a
depth-first left-to-right traversal of the hierarchy. We use
BINFO_VTABLE_PATH_MARKED because we are ourselves during a
dfs_walk, and so BINFO_MARKED is already in use. */
list = build_tree_list (t, NULL_TREE);
TREE_TYPE (list) = binfo;
dfs_walk (binfo,
dfs_build_vbase_offset_vtbl_entries,
unmarked_vtable_pathp,
list);
dfs_walk (binfo,
dfs_vtable_path_unmark,
marked_vtable_pathp,
list);
inits = nreverse (TREE_VALUE (list));
/* We've now got offsets in the right order. However, the offsets
we've stored are offsets from the beginning of the complete
object, and we need offsets from this BINFO. */
for (init = inits; init; init = TREE_CHAIN (init))
else
{
/* The dfs_build_vbase_offset_vtbl_entries routine uses the
TREE_PURPOSE to scribble in. But, we need to clear it now so
that the values are not perceived as labeled initializers. */
TREE_PURPOSE (init) = NULL_TREE;
TREE_VALUE (init)
= fold (build1 (NOP_EXPR, vtable_entry_type,
size_diffop (TREE_VALUE (init),
BINFO_OFFSET (binfo))));
char *name;
FORMAT_VBASE_NAME (name, type);
return build_component_ref (exp, get_identifier (name), NULL_TREE, 0);
}
return inits;
}
typedef struct vcall_offset_data_s
{
/* The binfo for the most-derived type. */
tree derived;
/* The binfo for the virtual base for which we're building
initializers. */
tree vbase;
/* The vcall offset initializers built up so far. */
tree inits;
/* The number of vcall offsets accumulated. */
int offsets;
} vcall_offset_data;
/* Build multi-level access to EXPR using hierarchy path PATH.
CODE is PLUS_EXPR if we are going with the grain,
and MINUS_EXPR if we are not (in which case, we cannot traverse
virtual baseclass links).
/* Called from build_vcall_offset_vtbl_entries via dfs_walk. */
TYPE is the type we want this path to have on exit.
static tree
dfs_vcall_offset_queue_p (binfo, data)
tree binfo;
void *data;
NONNULL is non-zero if we know (for any reason) that EXPR is
not, in fact, zero. */
tree
build_vbase_path (code, type, expr, path, nonnull)
enum tree_code code;
tree type, expr, path;
int nonnull;
{
vcall_offset_data* vod = (vcall_offset_data *) data;
register int changed = 0;
tree last = NULL_TREE, last_virtual = NULL_TREE;
int fixed_type_p;
tree null_expr = 0, nonnull_expr;
tree basetype;
tree offset = integer_zero_node;
return (binfo == vod->vbase) ? binfo : dfs_skip_vbases (binfo, NULL);
}
if (BINFO_INHERITANCE_CHAIN (path) == NULL_TREE)
return build1 (NOP_EXPR, type, expr);
/* Called from build_vcall_offset_vtbl_entries via dfs_walk. */
/* We could do better if we had additional logic to convert back to the
unconverted type (the static type of the complete object), and then
convert back to the type we want. Until that is done, we only optimize
if the complete type is the same type as expr has. */
fixed_type_p = resolves_to_fixed_type_p (expr, &nonnull);
static tree
dfs_build_vcall_offset_vtbl_entries (binfo, data)
tree binfo;
void *data;
{
vcall_offset_data* vod;
tree virtuals;
tree binfo_inits;
if (!fixed_type_p && TREE_SIDE_EFFECTS (expr))
expr = save_expr (expr);
nonnull_expr = expr;
/* Primary bases are not interesting; all of the virtual
function table entries have been overridden. */
if (BINFO_PRIMARY_MARKED_P (binfo))
return NULL_TREE;
path = reverse_path (path);
vod = (vcall_offset_data *) data;
binfo_inits = NULL_TREE;
basetype = BINFO_TYPE (path);
/* We chain the offsets on in reverse order. That's correct --
build_vtbl_initializer will straighten them out. */
for (virtuals = BINFO_VIRTUALS (binfo);
virtuals;
virtuals = TREE_CHAIN (virtuals))
while (path)
{
/* Figure out what function we're looking at. */
tree fn = TREE_VALUE (virtuals);
tree base = DECL_CONTEXT (fn);
/* The FN comes from BASE. So, we must caculate the adjustment
from the virtual base that derived from BINFO to BASE. */
tree base_binfo = get_binfo (base, vod->derived, /*protect=*/0);
if (TREE_VIA_VIRTUAL (TREE_VALUE (path)))
{
last_virtual = BINFO_TYPE (TREE_VALUE (path));
if (code == PLUS_EXPR)
{
changed = ! fixed_type_p;
binfo_inits
= tree_cons (NULL_TREE,
fold (build1 (NOP_EXPR, vtable_entry_type,
size_diffop (BINFO_OFFSET (base_binfo),
BINFO_OFFSET (vod->vbase)))),
binfo_inits);
}
if (changed)
{
tree ind;
/* Now add the initializers we've just created to the list that will
be returned to our caller. */
vod->inits = chainon (vod->inits, binfo_inits);
/* We already check for ambiguous things in the caller, just
find a path. */
if (last)
{
tree binfo = get_binfo (last, TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (nonnull_expr))), 0);
nonnull_expr = convert_pointer_to_real (binfo, nonnull_expr);
}
ind = build_indirect_ref (nonnull_expr, NULL_PTR);
nonnull_expr = build_vbase_pointer (ind, last_virtual);
if (nonnull == 0
&& TREE_CODE (type) == POINTER_TYPE
&& null_expr == NULL_TREE)
{
null_expr = build1 (NOP_EXPR, build_pointer_type (last_virtual), integer_zero_node);
expr = build (COND_EXPR, build_pointer_type (last_virtual),
build (EQ_EXPR, boolean_type_node, expr,
integer_zero_node),
null_expr, nonnull_expr);
}
}
/* else we'll figure out the offset below. */
return NULL_TREE;
}
/* Returns the initializers for the vcall offset entries in the vtable
for BINFO (which is part of the class hierarchy dominated by T), in
reverse order. */
static tree
build_vcall_offset_vtbl_entries (binfo, t)
tree binfo;
tree t;
{
vcall_offset_data vod;
/* Under the old ABI, the adjustments to the `this' pointer were made
elsewhere. */
if (!vcall_offsets_in_vtable_p ())
return NULL_TREE;
/* We only need these entries if this base is a virtual base. */
if (!TREE_VIA_VIRTUAL (binfo))
return NULL_TREE;
/* We need a vcall offset for each of the virtual functions in this
vtable. For example:
class A { virtual void f (); };
class B : virtual public A { };
class C: virtual public A, public B {};
Now imagine:
B* b = new C;
b->f();
The location of `A' is not at a fixed offset relative to `B'; the
offset depends on the complete object derived from `B'. So,
`B' vtable contains an entry for `f' that indicates by what
amount the `this' pointer for `B' needs to be adjusted to arrive
at `A'.
We need entries for all the functions in our primary vtable and
in our non-virtual bases vtables. For each base, the entries
appear in the same order as in the base; but the bases themselves
appear in reverse depth-first, left-to-right order. */
vod.derived = t;
vod.vbase = binfo;
vod.inits = NULL_TREE;
dfs_walk (binfo,
dfs_build_vcall_offset_vtbl_entries,
dfs_vcall_offset_queue_p,
&vod);
return vod.inits;
}
/* Return vtbl initializers for the RTTI entries coresponding to the
BINFO's vtable. BINFO is a part of the hierarchy dominated by
T. */
static tree
build_rtti_vtbl_entries (binfo, t)
tree binfo;
tree t;
{
tree b;
tree basetype;
tree inits;
tree offset;
tree decl;
tree init;
basetype = BINFO_TYPE (binfo);
inits = NULL_TREE;
/* For a COM object there is no RTTI entry. */
if (CLASSTYPE_COM_INTERFACE (basetype))
return inits;
/* To find the complete object, we will first convert to our most
primary base, and then add the offset in the vtbl to that value. */
b = binfo;
while (CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (b)))
b = BINFO_BASETYPE (b,
CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (b)));
offset = size_diffop (size_zero_node, BINFO_OFFSET (b));
/* Add the offset-to-top entry. */
if (flag_vtable_thunks)
{
/* Convert the offset to look like a function pointer, so that
we can put it in the vtable. */
init = build1 (NOP_EXPR, vfunc_ptr_type_node, offset);
TREE_CONSTANT (init) = 1;
inits = tree_cons (NULL_TREE, init, inits);
}
/* The second entry is, in the case of the new ABI, the address of
the typeinfo object, or, in the case of the old ABI, a function
which returns a typeinfo object. */
if (new_abi_rtti_p ())
{
if (flag_rtti)
decl = build_unary_op (ADDR_EXPR, get_tinfo_decl (t), 0);
else
decl = integer_zero_node;
/* Convert the declaration to a type that can be stored in the
vtable. */
init = build1 (NOP_EXPR, vfunc_ptr_type_node, decl);
TREE_CONSTANT (init) = 1;
}
else
{
if (flag_rtti)
decl = get_tinfo_decl (t);
else
decl = abort_fndecl;
/* Convert the declaration to a type that can be stored in the
vtable. */
init = build1 (ADDR_EXPR, vfunc_ptr_type_node, decl);
TREE_CONSTANT (init) = 1;
init = build_vtable_entry (offset, integer_zero_node, init);
}
/* Hook the RTTI declaration onto the list. */
inits = tree_cons (NULL_TREE, init, inits);
return inits;
}
/* Returns a pointer to the virtual base class of EXP that has the
indicated TYPE. EXP is of class type, not a pointer type. */
static tree
build_vbase_pointer (exp, type)
tree exp, type;
{
if (vbase_offsets_in_vtable_p ())
{
tree vbase;
tree vbase_ptr;
/* Find the shared copy of TYPE; that's where the vtable offset
is recorded. */
vbase = BINFO_FOR_VBASE (type, TREE_TYPE (exp));
/* Find the virtual function table pointer. */
vbase_ptr = build_vfield_ref (exp, TREE_TYPE (exp));
/* Compute the location where the offset will lie. */
vbase_ptr = build_binary_op (PLUS_EXPR,
vbase_ptr,
BINFO_VPTR_FIELD (vbase));
vbase_ptr = build1 (NOP_EXPR,
build_pointer_type (ptrdiff_type_node),
vbase_ptr);
/* Add the contents of this location to EXP. */
return build (PLUS_EXPR,
build_pointer_type (type),
build_unary_op (ADDR_EXPR, exp, /*noconvert=*/0),
build1 (INDIRECT_REF, ptrdiff_type_node, vbase_ptr));
}
else
{
char *name;
FORMAT_VBASE_NAME (name, type);
return build_component_ref (exp, get_identifier (name), NULL_TREE, 0);
}
}
/* Build multi-level access to EXPR using hierarchy path PATH.
CODE is PLUS_EXPR if we are going with the grain,
and MINUS_EXPR if we are not (in which case, we cannot traverse
virtual baseclass links).
TYPE is the type we want this path to have on exit.
NONNULL is non-zero if we know (for any reason) that EXPR is
not, in fact, zero. */
tree
build_vbase_path (code, type, expr, path, nonnull)
enum tree_code code;
tree type, expr, path;
int nonnull;
{
register int changed = 0;
tree last = NULL_TREE, last_virtual = NULL_TREE;
int fixed_type_p;
tree null_expr = 0, nonnull_expr;
tree basetype;
tree offset = integer_zero_node;
if (BINFO_INHERITANCE_CHAIN (path) == NULL_TREE)
return build1 (NOP_EXPR, type, expr);
/* We could do better if we had additional logic to convert back to the
unconverted type (the static type of the complete object), and then
convert back to the type we want. Until that is done, we only optimize
if the complete type is the same type as expr has. */
fixed_type_p = resolves_to_fixed_type_p (expr, &nonnull);
if (!fixed_type_p && TREE_SIDE_EFFECTS (expr))
expr = save_expr (expr);
nonnull_expr = expr;
path = reverse_path (path);
basetype = BINFO_TYPE (path);
while (path)
{
if (TREE_VIA_VIRTUAL (TREE_VALUE (path)))
{
last_virtual = BINFO_TYPE (TREE_VALUE (path));
if (code == PLUS_EXPR)
{
changed = ! fixed_type_p;
if (changed)
{
tree ind;
/* We already check for ambiguous things in the caller, just
find a path. */
if (last)
{
tree binfo = get_binfo (last, TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (nonnull_expr))), 0);
nonnull_expr = convert_pointer_to_real (binfo, nonnull_expr);
}
ind = build_indirect_ref (nonnull_expr, NULL_PTR);
nonnull_expr = build_vbase_pointer (ind, last_virtual);
if (nonnull == 0
&& TREE_CODE (type) == POINTER_TYPE
&& null_expr == NULL_TREE)
{
null_expr = build1 (NOP_EXPR, build_pointer_type (last_virtual), integer_zero_node);
expr = build (COND_EXPR, build_pointer_type (last_virtual),
build (EQ_EXPR, boolean_type_node, expr,
integer_zero_node),
null_expr, nonnull_expr);
}
}
/* else we'll figure out the offset below. */
/* Happens in the case of parse errors. */
if (nonnull_expr == error_mark_node)
return error_mark_node;
}
else
{
cp_error ("cannot cast up from virtual baseclass `%T'",
last_virtual);
return error_mark_node;
}
}
last = TREE_VALUE (path);
path = TREE_CHAIN (path);
}
/* LAST is now the last basetype assoc on the path. */
/* Happens in the case of parse errors. */
if (nonnull_expr == error_mark_node)
return error_mark_node;
}
else
{
cp_error ("cannot cast up from virtual baseclass `%T'",
last_virtual);
return error_mark_node;
}
}
last = TREE_VALUE (path);
path = TREE_CHAIN (path);
}
/* LAST is now the last basetype assoc on the path. */
/* A pointer to a virtual base member of a non-null object
is non-null. Therefore, we only need to test for zeroness once.
......@@ -752,75 +448,6 @@ build_vbase_path (code, type, expr, path, nonnull)
/* Virtual function things. */
/* Build an entry in the virtual function table. DELTA is the offset
for the `this' pointer. VCALL_INDEX is the vtable index containing
the vcall offset; zero if none. ENTRY is the virtual function
table entry itself. It's TREE_TYPE must be VFUNC_PTR_TYPE_NODE,
but it may not actually be a virtual function table pointer. (For
example, it might be the address of the RTTI object, under the new
ABI.) */
static tree
build_vtable_entry (delta, vcall_index, entry)
tree delta;
tree vcall_index;
tree entry;
{
if (flag_vtable_thunks)
{
HOST_WIDE_INT idelta;
HOST_WIDE_INT ivindex;
idelta = tree_low_cst (delta, 0);
ivindex = tree_low_cst (vcall_index, 0);
if ((idelta || ivindex)
&& ! DECL_PURE_VIRTUAL_P (TREE_OPERAND (entry, 0)))
{
entry = make_thunk (entry, idelta, ivindex);
entry = build1 (ADDR_EXPR, vtable_entry_type, entry);
TREE_READONLY (entry) = 1;
TREE_CONSTANT (entry) = 1;
}
#ifdef GATHER_STATISTICS
n_vtable_entries += 1;
#endif
return entry;
}
else
{
extern int flag_huge_objects;
tree elems = tree_cons (NULL_TREE, delta,
tree_cons (NULL_TREE, integer_zero_node,
build_tree_list (NULL_TREE, 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);
/* DELTA used to be constructed by `size_int' and/or size_binop,
which caused overflow problems when it was negative. That should
be fixed now. */
if (! int_fits_type_p (delta, delta_type_node))
{
if (flag_huge_objects)
sorry ("object size exceeds built-in limit for virtual function table implementation");
else
sorry ("object size exceeds normal limit for virtual function table implementation, recompile all source and use -fhuge-objects");
}
TREE_CONSTANT (entry) = 1;
TREE_STATIC (entry) = 1;
TREE_READONLY (entry) = 1;
#ifdef GATHER_STATISTICS
n_vtable_entries += 1;
#endif
return entry;
}
}
/* We want to give the assembler the vtable identifier as well as
the offset to the function pointer. So we generate
......@@ -2590,6 +2217,19 @@ num_vfun_entries (binfo)
return list_length (BINFO_VIRTUALS (binfo));
}
typedef struct vcall_offset_data_s
{
/* The binfo for the most-derived type. */
tree derived;
/* The binfo for the virtual base for which we're building
initializers. */
tree vbase;
/* The vcall offset initializers built up so far. */
tree inits;
/* The number of vcall offsets accumulated. */
int offsets;
} vcall_offset_data;
/* Called from num_extra_vtbl_entries via dfs_walk. */
static tree
......@@ -2664,284 +2304,79 @@ size_extra_vtbl_entries (binfo)
return fold (offset);
}
/* Construct the initializer for BINFOs virtual function table. BINFO
is part of the hierarchy dominated by T. The value returned is a
TREE_LIST suitable for wrapping in a CONSTRUCTOR to use as the
DECL_INITIAL for a vtable. */
/* True if we should override the given BASE_FNDECL with the given
FNDECL. */
static tree
build_vtbl_initializer (binfo, t)
tree binfo;
tree t;
static int
overrides (fndecl, base_fndecl)
tree fndecl, base_fndecl;
{
tree v = BINFO_VIRTUALS (binfo);
tree inits = NULL_TREE;
/* Add entries to the vtable that indicate how to adjust the this
pointer when calling a virtual function in this class. */
inits = build_vcall_offset_vtbl_entries (binfo, t);
/* Add entries to the vtable for offsets to our virtual bases. */
inits = chainon (build_vbase_offset_vtbl_entries (binfo, t),
inits);
/* Add entries to the vtable for RTTI. */
inits = chainon (build_rtti_vtbl_entries (binfo, t), inits);
/* Go through all the ordinary virtual functions, building up
initializers. */
while (v)
/* Destructors have special names. */
if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (base_fndecl))
&& DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
return 1;
if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (base_fndecl))
|| DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
return 0;
if (DECL_NAME (fndecl) == DECL_NAME (base_fndecl))
{
tree delta;
tree vcall_index;
tree fn;
tree pfn;
tree init;
/* Pull the offset for `this', and the function to call, out of
the list. */
delta = BV_DELTA (v);
vcall_index = BV_VCALL_INDEX (v);
fn = BV_FN (v);
my_friendly_assert (TREE_CODE (delta) == INTEGER_CST, 19990727);
my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727);
/* You can't call an abstract virtual function; it's abstract.
So, we replace these functions with __pure_virtual. */
if (DECL_PURE_VIRTUAL_P (fn))
fn = abort_fndecl;
/* Take the address of the function, considering it to be of an
appropriate generic type. */
pfn = build1 (ADDR_EXPR, vfunc_ptr_type_node, fn);
/* 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);
/* And add it to the chain of initializers. */
inits = tree_cons (NULL_TREE, init, inits);
/* Keep going. */
v = TREE_CHAIN (v);
tree types, base_types;
#if 0
retypes = TREE_TYPE (TREE_TYPE (fndecl));
base_retypes = TREE_TYPE (TREE_TYPE (base_fndecl));
#endif
types = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
base_types = TYPE_ARG_TYPES (TREE_TYPE (base_fndecl));
if ((TYPE_QUALS (TREE_TYPE (TREE_VALUE (base_types)))
== TYPE_QUALS (TREE_TYPE (TREE_VALUE (types))))
&& compparms (TREE_CHAIN (base_types), TREE_CHAIN (types)))
return 1;
}
/* The initializers were built up in reverse order; straighten them
out now. */
return nreverse (inits);
}
/* Initialize the vtable for BINFO with the INITS. */
static void
initialize_vtable (binfo, inits)
tree binfo;
tree inits;
{
tree context;
tree decl;
layout_vtable_decl (binfo, list_length (inits));
decl = BINFO_VTABLE (binfo);
context = DECL_CONTEXT (decl);
DECL_CONTEXT (decl) = 0;
DECL_INITIAL (decl) = build_nt (CONSTRUCTOR, NULL_TREE, inits);
cp_finish_decl (decl, DECL_INITIAL (decl), NULL_TREE, 0);
DECL_CONTEXT (decl) = context;
return 0;
}
/* Called from finish_vtbls via dfs_walk. */
static tree
dfs_finish_vtbls (binfo, data)
tree binfo;
void *data;
{
tree t = (tree) data;
if (!BINFO_PRIMARY_MARKED_P (binfo)
&& CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))
&& BINFO_NEW_VTABLE_MARKED (binfo, t))
initialize_vtable (binfo,
build_vtbl_initializer (binfo, t));
CLEAR_BINFO_NEW_VTABLE_MARKED (binfo, t);
SET_BINFO_MARKED (binfo);
return NULL_TREE;
}
typedef struct find_final_overrider_data_s {
/* The function for which we are trying to find a final overrider. */
tree fn;
/* The base class in which the function was declared. */
tree declaring_base;
/* The most derived class in the hierarchy. */
tree most_derived_type;
/* The final overriding function. */
tree overriding_fn;
/* The BINFO for the class in which the final overriding function
appears. */
tree overriding_base;
} find_final_overrider_data;
/* Called from finish_vtbls via dfs_walk when using the new ABI.
Accumulates the vtable initializers for all of the vtables into
TREE_VALUE (DATA). */
/* Called from find_final_overrider via dfs_walk. */
static tree
dfs_accumulate_vtbl_inits (binfo, data)
dfs_find_final_overrider (binfo, data)
tree binfo;
void *data;
{
tree l;
tree t;
l = (tree) data;
t = TREE_PURPOSE (l);
find_final_overrider_data *ffod = (find_final_overrider_data *) data;
if (!BINFO_PRIMARY_MARKED_P (binfo)
&& CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))
&& BINFO_NEW_VTABLE_MARKED (binfo, t))
if (same_type_p (BINFO_TYPE (binfo),
BINFO_TYPE (ffod->declaring_base))
&& tree_int_cst_equal (BINFO_OFFSET (binfo),
BINFO_OFFSET (ffod->declaring_base)))
{
/* If this is a secondary vtable, record its location. */
if (binfo != TYPE_BINFO (t))
tree path;
tree method;
/* We've found a path to the declaring base. Walk down the path
looking for an overrider for FN. */
for (path = reverse_path (binfo);
path;
path = TREE_CHAIN (path))
{
tree vtbl;
vtbl = TYPE_BINFO_VTABLE (t);
vtbl = build1 (ADDR_EXPR,
build_pointer_type (TREE_TYPE (vtbl)),
vtbl);
BINFO_VTABLE (binfo)
= build (PLUS_EXPR, TREE_TYPE (vtbl), vtbl,
size_binop (MULT_EXPR,
TYPE_SIZE_UNIT (TREE_TYPE (vtbl)),
size_int (list_length (TREE_VALUE (l)))));
}
/* Add the initializers for this vtable to the initializers for
the other vtables we've already got. */
TREE_VALUE (l)
= chainon (TREE_VALUE (l),
build_vtbl_initializer (binfo, t));
}
CLEAR_BINFO_NEW_VTABLE_MARKED (binfo, t);
return NULL_TREE;
}
/* Add the vtbl initializers for BINFO (and its non-primary,
non-virtual bases) to the list of INITS. */
static void
accumulate_vtbl_inits (binfo, inits)
tree binfo;
tree inits;
{
/* Walk the BINFO and its bases. */
dfs_walk_real (binfo,
dfs_accumulate_vtbl_inits,
NULL,
dfs_skip_vbases,
inits);
}
/* Create all the necessary vtables for T and its base classes. */
static void
finish_vtbls (t)
tree t;
{
if (merge_primary_and_secondary_vtables_p ())
{
tree list;
tree vbase;
/* Under the new ABI, we lay out the primary and secondary
vtables in one contiguous vtable. The primary vtable is
first, followed by the non-virtual secondary vtables in
inheritance graph order. */
list = build_tree_list (t, NULL_TREE);
accumulate_vtbl_inits (TYPE_BINFO (t), list);
/* Then come the virtual bases, also in inheritance graph
order. */
for (vbase = CLASSTYPE_VBASECLASSES (t);
vbase;
vbase = TREE_CHAIN (vbase))
accumulate_vtbl_inits (vbase, list);
if (TYPE_BINFO_VTABLE (t))
initialize_vtable (TYPE_BINFO (t), TREE_VALUE (list));
}
else
{
dfs_walk (TYPE_BINFO (t), dfs_finish_vtbls,
dfs_unmarked_real_bases_queue_p, t);
dfs_walk (TYPE_BINFO (t), dfs_unmark,
dfs_marked_real_bases_queue_p, t);
}
}
/* True if we should override the given BASE_FNDECL with the given
FNDECL. */
static int
overrides (fndecl, base_fndecl)
tree fndecl, base_fndecl;
{
/* Destructors have special names. */
if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (base_fndecl))
&& DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
return 1;
if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (base_fndecl))
|| DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
return 0;
if (DECL_NAME (fndecl) == DECL_NAME (base_fndecl))
{
tree types, base_types;
#if 0
retypes = TREE_TYPE (TREE_TYPE (fndecl));
base_retypes = TREE_TYPE (TREE_TYPE (base_fndecl));
#endif
types = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
base_types = TYPE_ARG_TYPES (TREE_TYPE (base_fndecl));
if ((TYPE_QUALS (TREE_TYPE (TREE_VALUE (base_types)))
== TYPE_QUALS (TREE_TYPE (TREE_VALUE (types))))
&& compparms (TREE_CHAIN (base_types), TREE_CHAIN (types)))
return 1;
}
return 0;
}
typedef struct find_final_overrider_data_s {
/* The function for which we are trying to find a final overrider. */
tree fn;
/* The base class in which the function was declared. */
tree declaring_base;
/* The most derived class in the hierarchy. */
tree most_derived_type;
/* The final overriding function. */
tree overriding_fn;
/* The BINFO for the class in which the final overriding function
appears. */
tree overriding_base;
} find_final_overrider_data;
/* Called from find_final_overrider via dfs_walk. */
static tree
dfs_find_final_overrider (binfo, data)
tree binfo;
void *data;
{
find_final_overrider_data *ffod = (find_final_overrider_data *) data;
if (same_type_p (BINFO_TYPE (binfo),
BINFO_TYPE (ffod->declaring_base))
&& tree_int_cst_equal (BINFO_OFFSET (binfo),
BINFO_OFFSET (ffod->declaring_base)))
{
tree path;
tree method;
/* We've found a path to the declaring base. Walk down the path
looking for an overrider for FN. */
for (path = reverse_path (binfo);
path;
path = TREE_CHAIN (path))
{
for (method = TYPE_METHODS (BINFO_TYPE (TREE_VALUE (path)));
method;
method = TREE_CHAIN (method))
if (DECL_VIRTUAL_P (method) && overrides (method, ffod->fn))
break;
for (method = TYPE_METHODS (BINFO_TYPE (TREE_VALUE (path)));
method;
method = TREE_CHAIN (method))
if (DECL_VIRTUAL_P (method) && overrides (method, ffod->fn))
break;
if (method)
break;
......@@ -5299,7 +4734,7 @@ finish_struct_1 (t)
/* If we created a new vtbl pointer for this class, add it to the
list. */
if (TYPE_VFIELD (t) && CLASSTYPE_VFIELD_PARENT (t) == -1)
if (TYPE_VFIELD (t) && !CLASSTYPE_HAS_PRIMARY_BASE_P (t))
CLASSTYPE_VFIELDS (t)
= chainon (CLASSTYPE_VFIELDS (t), build_tree_list (NULL_TREE, t));
......@@ -6367,270 +5802,837 @@ instantiate_type (lhstype, rhs, flags)
error ("not enough type information");
return error_mark_node;
case COND_EXPR:
if (type_unknown_p (TREE_OPERAND (rhs, 0)))
case COND_EXPR:
if (type_unknown_p (TREE_OPERAND (rhs, 0)))
{
if (complain)
error ("not enough type information");
return error_mark_node;
}
TREE_OPERAND (rhs, 1)
= instantiate_type (lhstype, TREE_OPERAND (rhs, 1), flags);
if (TREE_OPERAND (rhs, 1) == error_mark_node)
return error_mark_node;
TREE_OPERAND (rhs, 2)
= instantiate_type (lhstype, TREE_OPERAND (rhs, 2), flags);
if (TREE_OPERAND (rhs, 2) == error_mark_node)
return error_mark_node;
TREE_TYPE (rhs) = lhstype;
return rhs;
case MODIFY_EXPR:
TREE_OPERAND (rhs, 1)
= instantiate_type (lhstype, TREE_OPERAND (rhs, 1), flags);
if (TREE_OPERAND (rhs, 1) == error_mark_node)
return error_mark_node;
TREE_TYPE (rhs) = lhstype;
return rhs;
case ADDR_EXPR:
return instantiate_type (lhstype, TREE_OPERAND (rhs, 0), flags);
case ENTRY_VALUE_EXPR:
my_friendly_abort (184);
return error_mark_node;
case ERROR_MARK:
return error_mark_node;
default:
my_friendly_abort (185);
return error_mark_node;
}
}
/* Return the name of the virtual function pointer field
(as an IDENTIFIER_NODE) for the given TYPE. Note that
this may have to look back through base types to find the
ultimate field name. (For single inheritance, these could
all be the same name. Who knows for multiple inheritance). */
static tree
get_vfield_name (type)
tree type;
{
tree binfo = TYPE_BINFO (type);
char *buf;
while (BINFO_BASETYPES (binfo)
&& TYPE_CONTAINS_VPTR_P (BINFO_TYPE (BINFO_BASETYPE (binfo, 0)))
&& ! TREE_VIA_VIRTUAL (BINFO_BASETYPE (binfo, 0)))
binfo = BINFO_BASETYPE (binfo, 0);
type = BINFO_TYPE (binfo);
buf = (char *) alloca (sizeof (VFIELD_NAME_FORMAT)
+ TYPE_NAME_LENGTH (type) + 2);
sprintf (buf, VFIELD_NAME_FORMAT, TYPE_NAME_STRING (type));
return get_identifier (buf);
}
void
print_class_statistics ()
{
#ifdef GATHER_STATISTICS
fprintf (stderr, "convert_harshness = %d\n", n_convert_harshness);
fprintf (stderr, "compute_conversion_costs = %d\n", n_compute_conversion_costs);
fprintf (stderr, "build_method_call = %d (inner = %d)\n",
n_build_method_call, n_inner_fields_searched);
if (n_vtables)
{
fprintf (stderr, "vtables = %d; vtable searches = %d\n",
n_vtables, n_vtable_searches);
fprintf (stderr, "vtable entries = %d; vtable elems = %d\n",
n_vtable_entries, n_vtable_elems);
}
#endif
}
/* Build a dummy reference to ourselves so Derived::Base (and A::A) works,
according to [class]:
The class-name is also inserted
into the scope of the class itself. For purposes of access checking,
the inserted class name is treated as if it were a public member name. */
void
build_self_reference ()
{
tree name = constructor_name (current_class_type);
tree value = build_lang_decl (TYPE_DECL, name, current_class_type);
tree saved_cas;
DECL_NONLOCAL (value) = 1;
DECL_CONTEXT (value) = current_class_type;
DECL_ARTIFICIAL (value) = 1;
if (processing_template_decl)
value = push_template_decl (value);
saved_cas = current_access_specifier;
current_access_specifier = access_public_node;
finish_member_declaration (value);
current_access_specifier = saved_cas;
}
/* Returns 1 if TYPE contains only padding bytes. */
int
is_empty_class (type)
tree type;
{
tree t;
if (type == error_mark_node)
return 0;
if (! IS_AGGR_TYPE (type))
return 0;
if (flag_new_abi)
return integer_zerop (CLASSTYPE_SIZE (type));
if (TYPE_BINFO_BASETYPES (type))
return 0;
t = TYPE_FIELDS (type);
while (t && TREE_CODE (t) != FIELD_DECL)
t = TREE_CHAIN (t);
return (t == NULL_TREE);
}
/* Find the enclosing class of the given NODE. NODE can be a *_DECL or
a *_TYPE node. NODE can also be a local class. */
tree
get_enclosing_class (type)
tree type;
{
tree node = type;
while (node && TREE_CODE (node) != NAMESPACE_DECL)
{
switch (TREE_CODE_CLASS (TREE_CODE (node)))
{
case 'd':
node = DECL_CONTEXT (node);
break;
case 't':
if (node != type)
return node;
node = TYPE_CONTEXT (node);
break;
default:
my_friendly_abort (0);
}
}
return NULL_TREE;
}
/* Return 1 if TYPE or one of its enclosing classes is derived from BASE. */
int
is_base_of_enclosing_class (base, type)
tree base, type;
{
while (type)
{
if (get_binfo (base, type, 0))
return 1;
type = get_enclosing_class (type);
}
return 0;
}
/* Note that NAME was looked up while the current class was being
defined and that the result of that lookup was DECL. */
void
maybe_note_name_used_in_class (name, decl)
tree name;
tree decl;
{
splay_tree names_used;
/* If we're not defining a class, there's nothing to do. */
if (!current_class_type || !TYPE_BEING_DEFINED (current_class_type))
return;
/* If there's already a binding for this NAME, then we don't have
anything to worry about. */
if (IDENTIFIER_CLASS_VALUE (name))
return;
if (!current_class_stack[current_class_depth - 1].names_used)
current_class_stack[current_class_depth - 1].names_used
= splay_tree_new (splay_tree_compare_pointers, 0, 0);
names_used = current_class_stack[current_class_depth - 1].names_used;
splay_tree_insert (names_used,
(splay_tree_key) name,
(splay_tree_value) decl);
}
/* Note that NAME was declared (as DECL) in the current class. Check
to see that the declaration is legal. */
void
note_name_declared_in_class (name, decl)
tree name;
tree decl;
{
splay_tree names_used;
splay_tree_node n;
/* Look to see if we ever used this name. */
names_used
= current_class_stack[current_class_depth - 1].names_used;
if (!names_used)
return;
n = splay_tree_lookup (names_used, (splay_tree_key) name);
if (n)
{
/* [basic.scope.class]
A name N used in a class S shall refer to the same declaration
in its context and when re-evaluated in the completed scope of
S. */
cp_error ("declaration of `%#D'", decl);
cp_error_at ("changes meaning of `%s' from `%+#D'",
IDENTIFIER_POINTER (DECL_NAME (OVL_CURRENT (decl))),
(tree) n->value);
}
}
/* Dump the offsets of all the bases rooted at BINFO to stderr.
INDENT should be zero when called from the top level; it is
incremented recursively. */
void
dump_class_hierarchy (binfo, indent)
tree binfo;
int indent;
{
int i;
fprintf (stderr, "%*s0x%lx (%s) ", indent, "",
(unsigned long) binfo,
type_as_string (binfo, TS_PLAIN));
fprintf (stderr, HOST_WIDE_INT_PRINT_DEC,
tree_low_cst (BINFO_OFFSET (binfo), 0));
fprintf (stderr, " %s\n",
BINFO_PRIMARY_MARKED_P (binfo) ? "primary" : "");
for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
dump_class_hierarchy (BINFO_BASETYPE (binfo, i), indent + 2);
}
/* Virtual function table initialization. */
/* Create all the necessary vtables for T and its base classes. */
static void
finish_vtbls (t)
tree t;
{
if (merge_primary_and_secondary_vtables_p ())
{
tree list;
tree vbase;
/* Under the new ABI, we lay out the primary and secondary
vtables in one contiguous vtable. The primary vtable is
first, followed by the non-virtual secondary vtables in
inheritance graph order. */
list = build_tree_list (t, NULL_TREE);
accumulate_vtbl_inits (TYPE_BINFO (t), list);
/* Then come the virtual bases, also in inheritance graph
order. */
for (vbase = CLASSTYPE_VBASECLASSES (t);
vbase;
vbase = TREE_CHAIN (vbase))
accumulate_vtbl_inits (vbase, list);
if (TYPE_BINFO_VTABLE (t))
initialize_vtable (TYPE_BINFO (t), TREE_VALUE (list));
}
else
{
dfs_walk (TYPE_BINFO (t), dfs_finish_vtbls,
dfs_unmarked_real_bases_queue_p, t);
dfs_walk (TYPE_BINFO (t), dfs_unmark,
dfs_marked_real_bases_queue_p, t);
}
}
/* Called from finish_vtbls via dfs_walk. */
static tree
dfs_finish_vtbls (binfo, data)
tree binfo;
void *data;
{
tree t = (tree) data;
if (!BINFO_PRIMARY_MARKED_P (binfo)
&& CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))
&& BINFO_NEW_VTABLE_MARKED (binfo, t))
initialize_vtable (binfo,
build_vtbl_initializer (binfo, t));
CLEAR_BINFO_NEW_VTABLE_MARKED (binfo, t);
SET_BINFO_MARKED (binfo);
return NULL_TREE;
}
/* Initialize the vtable for BINFO with the INITS. */
static void
initialize_vtable (binfo, inits)
tree binfo;
tree inits;
{
tree context;
tree decl;
layout_vtable_decl (binfo, list_length (inits));
decl = BINFO_VTABLE (binfo);
context = DECL_CONTEXT (decl);
DECL_CONTEXT (decl) = 0;
DECL_INITIAL (decl) = build_nt (CONSTRUCTOR, NULL_TREE, inits);
cp_finish_decl (decl, DECL_INITIAL (decl), NULL_TREE, 0);
DECL_CONTEXT (decl) = context;
}
/* Add the vtbl initializers for BINFO (and its non-primary,
non-virtual bases) to the list of INITS. */
static void
accumulate_vtbl_inits (binfo, inits)
tree binfo;
tree inits;
{
/* Walk the BINFO and its bases. */
dfs_walk_real (binfo,
dfs_accumulate_vtbl_inits,
NULL,
dfs_skip_vbases,
inits);
}
/* Called from finish_vtbls via dfs_walk when using the new ABI.
Accumulates the vtable initializers for all of the vtables into
TREE_VALUE (DATA). */
static tree
dfs_accumulate_vtbl_inits (binfo, data)
tree binfo;
void *data;
{
tree l;
tree t;
l = (tree) data;
t = TREE_PURPOSE (l);
if (!BINFO_PRIMARY_MARKED_P (binfo)
&& CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))
&& BINFO_NEW_VTABLE_MARKED (binfo, t))
{
/* If this is a secondary vtable, record its location. */
if (binfo != TYPE_BINFO (t))
{
tree vtbl;
vtbl = TYPE_BINFO_VTABLE (t);
vtbl = build1 (ADDR_EXPR,
build_pointer_type (TREE_TYPE (vtbl)),
vtbl);
BINFO_VTABLE (binfo)
= build (PLUS_EXPR, TREE_TYPE (vtbl), vtbl,
size_binop (MULT_EXPR,
TYPE_SIZE_UNIT (TREE_TYPE (vtbl)),
size_int (list_length (TREE_VALUE (l)))));
}
/* Add the initializers for this vtable to the initializers for
the other vtables we've already got. */
TREE_VALUE (l)
= chainon (TREE_VALUE (l),
build_vtbl_initializer (binfo, t));
}
CLEAR_BINFO_NEW_VTABLE_MARKED (binfo, t);
return NULL_TREE;
}
/* Construct the initializer for BINFOs virtual function table. BINFO
is part of the hierarchy dominated by T. The value returned is a
TREE_LIST suitable for wrapping in a CONSTRUCTOR to use as the
DECL_INITIAL for a vtable. */
static tree
build_vtbl_initializer (binfo, t)
tree binfo;
tree t;
{
tree v = BINFO_VIRTUALS (binfo);
tree inits = NULL_TREE;
/* Add entries to the vtable that indicate how to adjust the this
pointer when calling a virtual function in this class. */
inits = build_vcall_offset_vtbl_entries (binfo, t);
/* Add entries to the vtable for offsets to our virtual bases. */
inits = chainon (build_vbase_offset_vtbl_entries (binfo, t),
inits);
/* Add entries to the vtable for RTTI. */
inits = chainon (build_rtti_vtbl_entries (binfo, t), inits);
/* Go through all the ordinary virtual functions, building up
initializers. */
while (v)
{
tree delta;
tree vcall_index;
tree fn;
tree pfn;
tree init;
/* Pull the offset for `this', and the function to call, out of
the list. */
delta = BV_DELTA (v);
vcall_index = BV_VCALL_INDEX (v);
fn = BV_FN (v);
my_friendly_assert (TREE_CODE (delta) == INTEGER_CST, 19990727);
my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727);
/* You can't call an abstract virtual function; it's abstract.
So, we replace these functions with __pure_virtual. */
if (DECL_PURE_VIRTUAL_P (fn))
fn = abort_fndecl;
/* Take the address of the function, considering it to be of an
appropriate generic type. */
pfn = build1 (ADDR_EXPR, vfunc_ptr_type_node, fn);
/* 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);
/* And add it to the chain of initializers. */
inits = tree_cons (NULL_TREE, init, inits);
/* Keep going. */
v = TREE_CHAIN (v);
}
/* The initializers were built up in reverse order; straighten them
out now. */
return nreverse (inits);
}
/* Called from build_vbase_offset_vtbl_entries via dfs_walk. */
static tree
dfs_build_vbase_offset_vtbl_entries (binfo, data)
tree binfo;
void *data;
{
tree list = (tree) data;
if (TREE_TYPE (list) == binfo)
/* The TREE_TYPE of LIST is the base class from which we started
walking. If that BINFO is virtual it's not a virtual baseclass
of itself. */
;
else if (TREE_VIA_VIRTUAL (binfo))
{
tree init;
tree vbase;
/* Remember the index to the vbase offset for this virtual
base. */
vbase = BINFO_FOR_VBASE (BINFO_TYPE (binfo), TREE_PURPOSE (list));
if (!TREE_VALUE (list))
BINFO_VPTR_FIELD (vbase) = build_int_2 (-3, 0);
else
{
if (complain)
error ("not enough type information");
return error_mark_node;
BINFO_VPTR_FIELD (vbase) = TREE_PURPOSE (TREE_VALUE (list));
BINFO_VPTR_FIELD (vbase)
= fold (build (MINUS_EXPR, integer_type_node,
BINFO_VPTR_FIELD (vbase), integer_one_node));
}
TREE_OPERAND (rhs, 1)
= instantiate_type (lhstype, TREE_OPERAND (rhs, 1), flags);
if (TREE_OPERAND (rhs, 1) == error_mark_node)
return error_mark_node;
TREE_OPERAND (rhs, 2)
= instantiate_type (lhstype, TREE_OPERAND (rhs, 2), flags);
if (TREE_OPERAND (rhs, 2) == error_mark_node)
return error_mark_node;
TREE_TYPE (rhs) = lhstype;
return rhs;
/* And record the offset at which this virtual base lies in the
vtable. */
init = BINFO_OFFSET (binfo);
TREE_VALUE (list) = tree_cons (BINFO_VPTR_FIELD (vbase),
init, TREE_VALUE (list));
}
case MODIFY_EXPR:
TREE_OPERAND (rhs, 1)
= instantiate_type (lhstype, TREE_OPERAND (rhs, 1), flags);
if (TREE_OPERAND (rhs, 1) == error_mark_node)
return error_mark_node;
SET_BINFO_VTABLE_PATH_MARKED (binfo);
return NULL_TREE;
}
TREE_TYPE (rhs) = lhstype;
return rhs;
case ADDR_EXPR:
return instantiate_type (lhstype, TREE_OPERAND (rhs, 0), flags);
/* Returns the initializers for the vbase offset entries in the vtable
for BINFO (which is part of the class hierarchy dominated by T), in
reverse order. */
case ENTRY_VALUE_EXPR:
my_friendly_abort (184);
return error_mark_node;
static tree
build_vbase_offset_vtbl_entries (binfo, t)
tree binfo;
tree t;
{
tree inits;
tree init;
tree list;
case ERROR_MARK:
return error_mark_node;
/* Under the old ABI, pointers to virtual bases are stored in each
object. */
if (!vbase_offsets_in_vtable_p ())
return NULL_TREE;
default:
my_friendly_abort (185);
return error_mark_node;
/* If there are no virtual baseclasses, then there is nothing to
do. */
if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo)))
return NULL_TREE;
inits = NULL_TREE;
/* The offsets are allocated in the reverse order of a
depth-first left-to-right traversal of the hierarchy. We use
BINFO_VTABLE_PATH_MARKED because we are ourselves during a
dfs_walk, and so BINFO_MARKED is already in use. */
list = build_tree_list (t, NULL_TREE);
TREE_TYPE (list) = binfo;
dfs_walk (binfo,
dfs_build_vbase_offset_vtbl_entries,
unmarked_vtable_pathp,
list);
dfs_walk (binfo,
dfs_vtable_path_unmark,
marked_vtable_pathp,
list);
inits = nreverse (TREE_VALUE (list));
/* We've now got offsets in the right order. However, the offsets
we've stored are offsets from the beginning of the complete
object, and we need offsets from this BINFO. */
for (init = inits; init; init = TREE_CHAIN (init))
{
/* The dfs_build_vbase_offset_vtbl_entries routine uses the
TREE_PURPOSE to scribble in. But, we need to clear it now so
that the values are not perceived as labeled initializers. */
TREE_PURPOSE (init) = NULL_TREE;
TREE_VALUE (init)
= fold (build1 (NOP_EXPR, vtable_entry_type,
size_diffop (TREE_VALUE (init),
BINFO_OFFSET (binfo))));
}
return inits;
}
/* Return the name of the virtual function pointer field
(as an IDENTIFIER_NODE) for the given TYPE. Note that
this may have to look back through base types to find the
ultimate field name. (For single inheritance, these could
all be the same name. Who knows for multiple inheritance). */
/* Called from build_vcall_offset_vtbl_entries via dfs_walk. */
static tree
get_vfield_name (type)
tree type;
dfs_vcall_offset_queue_p (binfo, data)
tree binfo;
void *data;
{
tree binfo = TYPE_BINFO (type);
char *buf;
while (BINFO_BASETYPES (binfo)
&& TYPE_CONTAINS_VPTR_P (BINFO_TYPE (BINFO_BASETYPE (binfo, 0)))
&& ! TREE_VIA_VIRTUAL (BINFO_BASETYPE (binfo, 0)))
binfo = BINFO_BASETYPE (binfo, 0);
vcall_offset_data* vod = (vcall_offset_data *) data;
type = BINFO_TYPE (binfo);
buf = (char *) alloca (sizeof (VFIELD_NAME_FORMAT)
+ TYPE_NAME_LENGTH (type) + 2);
sprintf (buf, VFIELD_NAME_FORMAT, TYPE_NAME_STRING (type));
return get_identifier (buf);
return (binfo == vod->vbase) ? binfo : dfs_skip_vbases (binfo, NULL);
}
void
print_class_statistics ()
/* Called from build_vcall_offset_vtbl_entries via dfs_walk. */
static tree
dfs_build_vcall_offset_vtbl_entries (binfo, data)
tree binfo;
void *data;
{
#ifdef GATHER_STATISTICS
fprintf (stderr, "convert_harshness = %d\n", n_convert_harshness);
fprintf (stderr, "compute_conversion_costs = %d\n", n_compute_conversion_costs);
fprintf (stderr, "build_method_call = %d (inner = %d)\n",
n_build_method_call, n_inner_fields_searched);
if (n_vtables)
vcall_offset_data* vod;
tree virtuals;
tree binfo_inits;
/* Primary bases are not interesting; all of the virtual
function table entries have been overridden. */
if (BINFO_PRIMARY_MARKED_P (binfo))
return NULL_TREE;
vod = (vcall_offset_data *) data;
binfo_inits = NULL_TREE;
/* We chain the offsets on in reverse order. That's correct --
build_vtbl_initializer will straighten them out. */
for (virtuals = BINFO_VIRTUALS (binfo);
virtuals;
virtuals = TREE_CHAIN (virtuals))
{
fprintf (stderr, "vtables = %d; vtable searches = %d\n",
n_vtables, n_vtable_searches);
fprintf (stderr, "vtable entries = %d; vtable elems = %d\n",
n_vtable_entries, n_vtable_elems);
/* Figure out what function we're looking at. */
tree fn = TREE_VALUE (virtuals);
tree base = DECL_CONTEXT (fn);
/* The FN comes from BASE. So, we must caculate the adjustment
from the virtual base that derived from BINFO to BASE. */
tree base_binfo = get_binfo (base, vod->derived, /*protect=*/0);
binfo_inits
= tree_cons (NULL_TREE,
fold (build1 (NOP_EXPR, vtable_entry_type,
size_diffop (BINFO_OFFSET (base_binfo),
BINFO_OFFSET (vod->vbase)))),
binfo_inits);
}
#endif
/* Now add the initializers we've just created to the list that will
be returned to our caller. */
vod->inits = chainon (vod->inits, binfo_inits);
return NULL_TREE;
}
/* Build a dummy reference to ourselves so Derived::Base (and A::A) works,
according to [class]:
The class-name is also inserted
into the scope of the class itself. For purposes of access checking,
the inserted class name is treated as if it were a public member name. */
/* Returns the initializers for the vcall offset entries in the vtable
for BINFO (which is part of the class hierarchy dominated by T), in
reverse order. */
void
build_self_reference ()
static tree
build_vcall_offset_vtbl_entries (binfo, t)
tree binfo;
tree t;
{
tree name = constructor_name (current_class_type);
tree value = build_lang_decl (TYPE_DECL, name, current_class_type);
tree saved_cas;
DECL_NONLOCAL (value) = 1;
DECL_CONTEXT (value) = current_class_type;
DECL_ARTIFICIAL (value) = 1;
vcall_offset_data vod;
if (processing_template_decl)
value = push_template_decl (value);
/* Under the old ABI, the adjustments to the `this' pointer were made
elsewhere. */
if (!vcall_offsets_in_vtable_p ())
return NULL_TREE;
saved_cas = current_access_specifier;
current_access_specifier = access_public_node;
finish_member_declaration (value);
current_access_specifier = saved_cas;
}
/* We only need these entries if this base is a virtual base. */
if (!TREE_VIA_VIRTUAL (binfo))
return NULL_TREE;
/* Returns 1 if TYPE contains only padding bytes. */
/* We need a vcall offset for each of the virtual functions in this
vtable. For example:
int
is_empty_class (type)
tree type;
{
tree t;
class A { virtual void f (); };
class B : virtual public A { };
class C: virtual public A, public B {};
Now imagine:
if (type == error_mark_node)
return 0;
B* b = new C;
b->f();
if (! IS_AGGR_TYPE (type))
return 0;
The location of `A' is not at a fixed offset relative to `B'; the
offset depends on the complete object derived from `B'. So,
`B' vtable contains an entry for `f' that indicates by what
amount the `this' pointer for `B' needs to be adjusted to arrive
at `A'.
if (flag_new_abi)
return integer_zerop (CLASSTYPE_SIZE (type));
We need entries for all the functions in our primary vtable and
in our non-virtual bases vtables. For each base, the entries
appear in the same order as in the base; but the bases themselves
appear in reverse depth-first, left-to-right order. */
vod.derived = t;
vod.vbase = binfo;
vod.inits = NULL_TREE;
dfs_walk (binfo,
dfs_build_vcall_offset_vtbl_entries,
dfs_vcall_offset_queue_p,
&vod);
if (TYPE_BINFO_BASETYPES (type))
return 0;
t = TYPE_FIELDS (type);
while (t && TREE_CODE (t) != FIELD_DECL)
t = TREE_CHAIN (t);
return (t == NULL_TREE);
return vod.inits;
}
/* Find the enclosing class of the given NODE. NODE can be a *_DECL or
a *_TYPE node. NODE can also be a local class. */
/* Return vtbl initializers for the RTTI entries coresponding to the
BINFO's vtable. BINFO is a part of the hierarchy dominated by
T. */
tree
get_enclosing_class (type)
tree type;
static tree
build_rtti_vtbl_entries (binfo, t)
tree binfo;
tree t;
{
tree node = type;
while (node && TREE_CODE (node) != NAMESPACE_DECL)
{
switch (TREE_CODE_CLASS (TREE_CODE (node)))
{
case 'd':
node = DECL_CONTEXT (node);
break;
tree b;
tree basetype;
tree inits;
tree offset;
tree decl;
tree init;
case 't':
if (node != type)
return node;
node = TYPE_CONTEXT (node);
break;
basetype = BINFO_TYPE (binfo);
inits = NULL_TREE;
default:
my_friendly_abort (0);
}
}
return NULL_TREE;
}
/* For a COM object there is no RTTI entry. */
if (CLASSTYPE_COM_INTERFACE (basetype))
return inits;
/* Return 1 if TYPE or one of its enclosing classes is derived from BASE. */
/* To find the complete object, we will first convert to our most
primary base, and then add the offset in the vtbl to that value. */
b = binfo;
while (CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (b)))
b = BINFO_BASETYPE (b,
CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (b)));
offset = size_diffop (size_zero_node, BINFO_OFFSET (b));
int
is_base_of_enclosing_class (base, type)
tree base, type;
{
while (type)
/* Add the offset-to-top entry. */
if (flag_vtable_thunks)
{
if (get_binfo (base, type, 0))
return 1;
type = get_enclosing_class (type);
/* Convert the offset to look like a function pointer, so that
we can put it in the vtable. */
init = build1 (NOP_EXPR, vfunc_ptr_type_node, offset);
TREE_CONSTANT (init) = 1;
inits = tree_cons (NULL_TREE, init, inits);
}
return 0;
}
/* Note that NAME was looked up while the current class was being
defined and that the result of that lookup was DECL. */
/* The second entry is, in the case of the new ABI, the address of
the typeinfo object, or, in the case of the old ABI, a function
which returns a typeinfo object. */
if (new_abi_rtti_p ())
{
if (flag_rtti)
decl = build_unary_op (ADDR_EXPR, get_tinfo_decl (t), 0);
else
decl = integer_zero_node;
void
maybe_note_name_used_in_class (name, decl)
tree name;
tree decl;
{
splay_tree names_used;
/* Convert the declaration to a type that can be stored in the
vtable. */
init = build1 (NOP_EXPR, vfunc_ptr_type_node, decl);
TREE_CONSTANT (init) = 1;
}
else
{
if (flag_rtti)
decl = get_tinfo_decl (t);
else
decl = abort_fndecl;
/* If we're not defining a class, there's nothing to do. */
if (!current_class_type || !TYPE_BEING_DEFINED (current_class_type))
return;
/* If there's already a binding for this NAME, then we don't have
anything to worry about. */
if (IDENTIFIER_CLASS_VALUE (name))
return;
/* Convert the declaration to a type that can be stored in the
vtable. */
init = build1 (ADDR_EXPR, vfunc_ptr_type_node, decl);
TREE_CONSTANT (init) = 1;
init = build_vtable_entry (offset, integer_zero_node, init);
}
if (!current_class_stack[current_class_depth - 1].names_used)
current_class_stack[current_class_depth - 1].names_used
= splay_tree_new (splay_tree_compare_pointers, 0, 0);
names_used = current_class_stack[current_class_depth - 1].names_used;
/* Hook the RTTI declaration onto the list. */
inits = tree_cons (NULL_TREE, init, inits);
splay_tree_insert (names_used,
(splay_tree_key) name,
(splay_tree_value) decl);
return inits;
}
/* Note that NAME was declared (as DECL) in the current class. Check
to see that the declaration is legal. */
/* Build an entry in the virtual function table. DELTA is the offset
for the `this' pointer. VCALL_INDEX is the vtable index containing
the vcall offset; zero if none. ENTRY is the virtual function
table entry itself. It's TREE_TYPE must be VFUNC_PTR_TYPE_NODE,
but it may not actually be a virtual function table pointer. (For
example, it might be the address of the RTTI object, under the new
ABI.) */
void
note_name_declared_in_class (name, decl)
tree name;
tree decl;
static tree
build_vtable_entry (delta, vcall_index, entry)
tree delta;
tree vcall_index;
tree entry;
{
splay_tree names_used;
splay_tree_node n;
/* Look to see if we ever used this name. */
names_used
= current_class_stack[current_class_depth - 1].names_used;
if (!names_used)
return;
n = splay_tree_lookup (names_used, (splay_tree_key) name);
if (n)
if (flag_vtable_thunks)
{
/* [basic.scope.class]
A name N used in a class S shall refer to the same declaration
in its context and when re-evaluated in the completed scope of
S. */
cp_error ("declaration of `%#D'", decl);
cp_error_at ("changes meaning of `%s' from `%+#D'",
IDENTIFIER_POINTER (DECL_NAME (OVL_CURRENT (decl))),
(tree) n->value);
HOST_WIDE_INT idelta;
HOST_WIDE_INT ivindex;
idelta = tree_low_cst (delta, 0);
ivindex = tree_low_cst (vcall_index, 0);
if ((idelta || ivindex)
&& ! DECL_PURE_VIRTUAL_P (TREE_OPERAND (entry, 0)))
{
entry = make_thunk (entry, idelta, ivindex);
entry = build1 (ADDR_EXPR, vtable_entry_type, entry);
TREE_READONLY (entry) = 1;
TREE_CONSTANT (entry) = 1;
}
#ifdef GATHER_STATISTICS
n_vtable_entries += 1;
#endif
return entry;
}
}
else
{
extern int flag_huge_objects;
tree elems = tree_cons (NULL_TREE, delta,
tree_cons (NULL_TREE, integer_zero_node,
build_tree_list (NULL_TREE, entry)));
tree entry = build (CONSTRUCTOR, vtable_entry_type, NULL_TREE, elems);
/* Dump the offsets of all the bases rooted at BINFO to stderr.
INDENT should be zero when called from the top level; it is
incremented recursively. */
/* We don't use vcall offsets when not using vtable thunks. */
my_friendly_assert (integer_zerop (vcall_index), 20000125);
void
dump_class_hierarchy (binfo, indent)
tree binfo;
int indent;
{
int i;
/* DELTA used to be constructed by `size_int' and/or size_binop,
which caused overflow problems when it was negative. That should
be fixed now. */
fprintf (stderr, "%*s0x%lx (%s) ", indent, "",
(unsigned long) binfo,
type_as_string (binfo, TS_PLAIN));
fprintf (stderr, HOST_WIDE_INT_PRINT_DEC,
tree_low_cst (BINFO_OFFSET (binfo), 0));
fprintf (stderr, " %s\n",
BINFO_PRIMARY_MARKED_P (binfo) ? "primary" : "");
if (! int_fits_type_p (delta, delta_type_node))
{
if (flag_huge_objects)
sorry ("object size exceeds built-in limit for virtual function table implementation");
else
sorry ("object size exceeds normal limit for virtual function table implementation, recompile all source and use -fhuge-objects");
}
TREE_CONSTANT (entry) = 1;
TREE_STATIC (entry) = 1;
TREE_READONLY (entry) = 1;
for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
dump_class_hierarchy (BINFO_BASETYPE (binfo, i), indent + 2);
#ifdef GATHER_STATISTICS
n_vtable_entries += 1;
#endif
return entry;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment