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.
\f
/* 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
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
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;
/* 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));
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;
+ }
+}
+\f
+/* 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;
}
-\f
-/* 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;
+ }
}