splay_tree names_used;
}* class_stack_node_t;
-typedef struct vcall_offset_data_s
+typedef struct vtbl_init_data_s
{
+ /* The base for which we're building initializers. */
+ tree binfo;
/* The binfo for the most-derived type. */
tree derived;
+ /* The negative-index vtable initializers built up so far. These
+ are in order from least negative index to most negative index. */
+ tree inits;
+ /* The last (i.e., most negative entry in INITS. */
+ tree* last_init;
/* The binfo for the virtual base for which we're building
- initializers. */
+ vcall offset initializers. */
tree vbase;
- /* The vcall offset initializers built up so far. */
- tree inits;
+ /* The functions in vbase for which we have already provided vcall
+ offsets. */
+ varray_type fns;
/* The vtable index of the next vcall or vbase offset. */
tree index;
/* Nonzero if we are building the initializer for the primary
vtable. */
- int primary_p;
-} vcall_offset_data;
+ int primary_vtbl_p;
+ /* Nonzero if we are building the initializer for a construction
+ vtable. */
+ int ctor_vtbl_p;
+} vtbl_init_data;
+
+/* The type of a function passed to walk_subobject_offsets. */
+typedef int (*subobject_offset_fn) PARAMS ((tree, tree, splay_tree));
/* The stack itself. This is an dynamically resized array. The
number of elements allocated is CURRENT_CLASS_STACK_SIZE. */
static int current_class_stack_size;
static class_stack_node_t current_class_stack;
+/* An array of all local classes present in this translation unit, in
+ declaration order. */
+varray_type local_classes;
+
static tree get_vfield_name PARAMS ((tree));
static void finish_struct_anon PARAMS ((tree));
static tree build_vbase_pointer PARAMS ((tree, tree));
-static tree build_vtable_entry PARAMS ((tree, tree, tree));
+static tree build_vtable_entry PARAMS ((tree, tree, tree, int));
static tree get_vtable_name PARAMS ((tree));
static tree get_derived_offset PARAMS ((tree, tree));
static tree get_basefndecls PARAMS ((tree, tree));
static int build_primary_vtable PARAMS ((tree, tree));
static int build_secondary_vtable PARAMS ((tree, tree));
static tree dfs_finish_vtbls PARAMS ((tree, void *));
-static tree dfs_accumulate_vtbl_inits PARAMS ((tree, void *));
+static tree dfs_accumulate_vtbl_inits PARAMS ((tree, tree, tree, tree,
+ tree));
static void finish_vtbls PARAMS ((tree));
static void modify_vtable_entry PARAMS ((tree, tree, tree, tree, tree *));
static void add_virtual_function PARAMS ((tree *, tree *, int *, tree, tree));
static void finish_struct_bits PARAMS ((tree));
static int alter_access PARAMS ((tree, tree, tree));
static void handle_using_decl PARAMS ((tree, tree));
-static int overrides PARAMS ((tree, tree));
+static int same_signature_p PARAMS ((tree, tree));
static int strictly_overrides PARAMS ((tree, tree));
static void mark_overriders PARAMS ((tree, tree));
static void check_for_override PARAMS ((tree, tree));
static tree add_implicitly_declared_members PARAMS ((tree, int, int, int));
static tree fixed_type_or_null PARAMS ((tree, int *));
static tree resolve_address_of_overloaded_function PARAMS ((tree, tree, int,
- int, tree));
+ int, int, tree));
static void build_vtable_entry_ref PARAMS ((tree, tree, tree));
-static tree build_vtbl_initializer PARAMS ((tree, tree, int *));
+static tree build_vtbl_initializer PARAMS ((tree, tree, tree, tree, int *));
static int count_fields PARAMS ((tree));
static int add_fields_to_vec PARAMS ((tree, tree, int));
static void check_bitfield_decl PARAMS ((tree));
static void check_field_decls PARAMS ((tree, tree *, int *, int *, int *,
int *));
static void build_base_field PARAMS ((record_layout_info, tree, int *,
- unsigned int *, varray_type *));
-static varray_type build_base_fields PARAMS ((record_layout_info, int *));
+ unsigned int *, splay_tree));
+static void build_base_fields PARAMS ((record_layout_info, int *,
+ splay_tree));
static tree build_vbase_pointer_fields PARAMS ((record_layout_info, int *));
static tree build_vtbl_or_vbase_field PARAMS ((tree, tree, tree, tree, tree,
int *));
static void check_bases_and_members PARAMS ((tree, int *));
static tree create_vtable_ptr PARAMS ((tree, int *, int *, tree *, tree *));
static void layout_class_type PARAMS ((tree, int *, int *, tree *, tree *));
-static void fixup_pending_inline PARAMS ((struct pending_inline *));
+static void fixup_pending_inline PARAMS ((tree));
static void fixup_inline_methods PARAMS ((tree));
-static void set_primary_base PARAMS ((tree, int, int *));
-static tree dfs_propagate_binfo_offsets PARAMS ((tree, void *));
+static void set_primary_base PARAMS ((tree, tree, int *));
static void propagate_binfo_offsets PARAMS ((tree, tree));
-static void layout_virtual_bases PARAMS ((tree, varray_type *));
-static tree dfs_set_offset_for_shared_vbases PARAMS ((tree, void *));
+static void layout_virtual_bases PARAMS ((tree, splay_tree));
static tree dfs_set_offset_for_unshared_vbases PARAMS ((tree, void *));
-static void build_vbase_offset_vtbl_entries PARAMS ((tree, vcall_offset_data *));
-static tree dfs_vcall_offset_queue_p PARAMS ((tree, void *));
-static tree dfs_build_vcall_offset_vtbl_entries PARAMS ((tree, void *));
-static void build_vcall_offset_vtbl_entries PARAMS ((tree, vcall_offset_data *));
+static void build_vbase_offset_vtbl_entries PARAMS ((tree, vtbl_init_data *));
+static void add_vcall_offset_vtbl_entries_r PARAMS ((tree, vtbl_init_data *));
+static void add_vcall_offset_vtbl_entries_1 PARAMS ((tree, vtbl_init_data *));
+static void build_vcall_offset_vtbl_entries PARAMS ((tree, vtbl_init_data *));
static void layout_vtable_decl PARAMS ((tree, int));
static tree dfs_find_final_overrider PARAMS ((tree, void *));
static tree find_final_overrider PARAMS ((tree, tree, tree));
-static tree dfs_find_base PARAMS ((tree, void *));
static int make_new_vtable PARAMS ((tree, tree));
static void dump_class_hierarchy_r PARAMS ((tree, tree, int));
extern void dump_class_hierarchy PARAMS ((tree));
static tree build_vtable PARAMS ((tree, tree, tree));
static void initialize_vtable PARAMS ((tree, tree));
+static void initialize_array PARAMS ((tree, tree));
static void layout_nonempty_base_or_field PARAMS ((record_layout_info,
tree, tree,
- varray_type));
-static tree dfs_record_base_offsets PARAMS ((tree, void *));
-static void record_base_offsets PARAMS ((tree, varray_type *));
-static tree dfs_search_base_offsets PARAMS ((tree, void *));
-static int layout_conflict_p PARAMS ((tree, varray_type));
+ splay_tree));
static unsigned HOST_WIDE_INT end_of_class PARAMS ((tree, int));
-static void layout_empty_base PARAMS ((tree, tree, varray_type));
-static void accumulate_vtbl_inits PARAMS ((tree, tree));
+static void layout_empty_base PARAMS ((tree, tree, splay_tree));
+static void accumulate_vtbl_inits PARAMS ((tree, tree, tree, tree, tree));
static void set_vindex PARAMS ((tree, tree, int *));
-static tree build_rtti_vtbl_entries PARAMS ((tree, tree));
+static void build_rtti_vtbl_entries PARAMS ((tree, tree, vtbl_init_data *));
static void build_vcall_and_vbase_vtbl_entries PARAMS ((tree,
- vcall_offset_data *));
+ vtbl_init_data *));
static tree dfs_mark_primary_bases PARAMS ((tree, void *));
static void mark_primary_bases PARAMS ((tree));
+static void clone_constructors_and_destructors PARAMS ((tree));
+static tree build_clone PARAMS ((tree, tree));
+static void update_vtable_entry_for_fn PARAMS ((tree, tree, tree, tree *));
+static tree copy_virtuals PARAMS ((tree));
+static void build_ctor_vtbl_group PARAMS ((tree, tree));
+static void build_vtt PARAMS ((tree));
+static tree *build_vtt_inits PARAMS ((tree, tree, int, tree *, tree *));
+static tree dfs_build_secondary_vptr_vtt_inits PARAMS ((tree, void *));
+static tree dfs_fixup_binfo_vtbls PARAMS ((tree, void *));
+static tree get_matching_base PARAMS ((tree, tree));
+static tree dfs_get_primary_binfo PARAMS ((tree, void*));
+static int record_subobject_offset PARAMS ((tree, tree, splay_tree));
+static int check_subobject_offset PARAMS ((tree, tree, splay_tree));
+static int walk_subobject_offsets PARAMS ((tree, subobject_offset_fn,
+ tree, splay_tree, int));
+static void record_subobject_offsets PARAMS ((tree, tree, splay_tree, int));
+static int layout_conflict_p PARAMS ((tree, tree, splay_tree, int));
+static int splay_tree_compare_integer_csts PARAMS ((splay_tree_key k1,
+ splay_tree_key k2));
/* Variables shared between class.c and call.c. */
{
tree other_base_binfo = TREE_VEC_ELT (binfos, j);
if (! TREE_VIA_VIRTUAL (other_base_binfo)
- && BINFO_FOR_VBASE (basetype, BINFO_TYPE (other_base_binfo)))
+ && binfo_for_vbase (basetype, BINFO_TYPE (other_base_binfo)))
goto got_it;
}
FORMAT_VBASE_NAME (name, basetype);
/* Find the shared copy of TYPE; that's where the vtable offset
is recorded. */
- vbase = BINFO_FOR_VBASE (type, TREE_TYPE (exp));
+ 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. */
static char asm_stmt[] = ".vtable_entry %c0, %c1";
tree s, i, i2;
- s = build_unary_op (ADDR_EXPR, get_vtbl_decl_for_binfo (basetype), 0);
+ s = build_unary_op (ADDR_EXPR,
+ get_vtbl_decl_for_binfo (TYPE_BINFO (basetype)),
+ 0);
s = build_tree_list (build_string (1, "s"), s);
i = build_array_ref (vtbl, idx);
i = build_c_cast (ptrdiff_type_node, build_unary_op (ADDR_EXPR, i, 0));
i2 = build_array_ref (vtbl, build_int_2(0,0));
i2 = build_c_cast (ptrdiff_type_node, build_unary_op (ADDR_EXPR, i2, 0));
- i = build_binary_op (MINUS_EXPR, i, i2);
+ i = cp_build_binary_op (MINUS_EXPR, i, i2);
i = build_tree_list (build_string (1, "i"), i);
finish_asm_stmt (ridpointers[RID_VOLATILE],
get_vtable_name (type)
tree type;
{
- tree type_id = build_typename_overload (type);
- char *buf = (char *) alloca (strlen (VTABLE_NAME_PREFIX)
- + IDENTIFIER_LENGTH (type_id) + 2);
- const char *ptr = IDENTIFIER_POINTER (type_id);
- int i;
- for (i = 0; ptr[i] == OPERATOR_TYPENAME_FORMAT[i]; i++) ;
-#if 0
- /* We don't take off the numbers; build_secondary_vtable uses the
- DECL_ASSEMBLER_NAME for the type, which includes the number
- in `3foo'. If we were to pull them off here, we'd end up with
- something like `_vt.foo.3bar', instead of a uniform definition. */
- while (ptr[i] >= '0' && ptr[i] <= '9')
- i += 1;
-#endif
- sprintf (buf, "%s%s", VTABLE_NAME_PREFIX, ptr+i);
- return get_identifier (buf);
+ if (flag_new_abi)
+ return mangle_vtbl_for_type (type);
+ else
+ return build_overload_with_type (get_identifier (VTABLE_NAME_PREFIX),
+ type);
+}
+
+/* Return an IDENTIFIER_NODE for the name of the virtual table table
+ for TYPE. */
+
+tree
+get_vtt_name (type)
+ tree type;
+{
+ if (flag_new_abi)
+ return mangle_vtt_for_type (type);
+ else
+ return build_overload_with_type (get_identifier (VTT_NAME_PREFIX),
+ type);
}
/* Return the offset to the main vtable for a given base BINFO. */
on method calling is expected to point to a DECL_CONTEXT (fndecl)
object, and not a baseclass of it. */
-
static tree
get_derived_offset (binfo, type)
tree binfo, type;
{
tree offset1 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
tree offset2;
- int i;
- while (BINFO_BASETYPES (binfo)
- && (i = CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo))) != -1)
- {
- tree binfos = BINFO_BASETYPES (binfo);
- if (BINFO_TYPE (binfo) == type)
- break;
- binfo = TREE_VEC_ELT (binfos, i);
- }
+ while (!same_type_p (BINFO_TYPE (binfo), type))
+ binfo = get_primary_binfo (binfo);
offset2 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
return size_binop (MINUS_EXPR, offset1, offset2);
}
-/* Create a VAR_DECL for a primary or secondary vtable for
- CLASS_TYPE. Use NAME for the name of the vtable, and VTABLE_TYPE
- for its type. */
+/* Create a VAR_DECL for a primary or secondary vtable for CLASS_TYPE.
+ (For a secondary vtable for B-in-D, CLASS_TYPE should be D, not B.)
+ Use NAME for the name of the vtable, and VTABLE_TYPE for its type. */
static tree
build_vtable (class_type, name, vtable_type)
decl = build_vtable (type, name, void_type_node);
decl = pushdecl_top_level (decl);
- SET_IDENTIFIER_GLOBAL_VALUE (name, decl);
+ my_friendly_assert (IDENTIFIER_GLOBAL_VALUE (name) == decl,
+ 20000517);
/* At one time the vtable info was grabbed 2 words at a time. This
fails on sparc unless you have 8-byte alignment. (tiemann) */
return decl;
}
+/* Returns a copy of the BINFO_VIRTUALS list in BINFO. The
+ BV_VCALL_INDEX for each entry is cleared. */
+
+static tree
+copy_virtuals (binfo)
+ tree binfo;
+{
+ tree copies;
+ tree t;
+
+ copies = copy_list (BINFO_VIRTUALS (binfo));
+ for (t = copies; t; t = TREE_CHAIN (t))
+ {
+ BV_VCALL_INDEX (t) = NULL_TREE;
+ BV_USE_VCALL_INDEX_P (t) = 0;
+ BV_GENERATE_THUNK_WITH_VTABLE_P (t) = 0;
+ }
+
+ return copies;
+}
+
/* Build the primary virtual function table for TYPE. If BINFO is
non-NULL, build the vtable starting with the initial approximation
that it is the same as the one which is the head of the association
build_primary_vtable (binfo, type)
tree binfo, type;
{
- tree virtuals, decl;
+ tree decl;
+ tree virtuals;
decl = get_vtable_decl (type, /*complete=*/0);
no need to do it again. */
return 0;
- virtuals = copy_list (BINFO_VIRTUALS (binfo));
+ virtuals = copy_virtuals (binfo);
TREE_TYPE (decl) = TREE_TYPE (get_vtbl_decl_for_binfo (binfo));
DECL_SIZE (decl) = TYPE_SIZE (TREE_TYPE (decl));
DECL_SIZE_UNIT (decl) = TYPE_SIZE_UNIT (TREE_TYPE (decl));
on our first approximation. */
TYPE_BINFO_VTABLE (type) = decl;
TYPE_BINFO_VIRTUALS (type) = virtuals;
-
- binfo = TYPE_BINFO (type);
- SET_BINFO_NEW_VTABLE_MARKED (binfo, type);
+ SET_BINFO_NEW_VTABLE_MARKED (TYPE_BINFO (type), type);
return 1;
}
tree new_decl;
tree offset;
tree path = binfo;
- char *buf, *buf2;
+ char *buf;
+ const char *buf2;
char joiner = '_';
int i;
#endif
if (TREE_VIA_VIRTUAL (binfo))
- my_friendly_assert (binfo == BINFO_FOR_VBASE (BINFO_TYPE (binfo),
+ my_friendly_assert (binfo == binfo_for_vbase (BINFO_TYPE (binfo),
current_class_type),
170);
SET_BINFO_NEW_VTABLE_MARKED (binfo, current_class_type);
/* Make fresh virtual list, so we can smash it later. */
- BINFO_VIRTUALS (binfo) = copy_list (BINFO_VIRTUALS (binfo));
+ BINFO_VIRTUALS (binfo) = copy_virtuals (binfo);
if (TREE_VIA_VIRTUAL (binfo))
{
- tree binfo1 = BINFO_FOR_VBASE (BINFO_TYPE (binfo), for_type);
+ tree binfo1 = binfo_for_vbase (BINFO_TYPE (binfo), for_type);
/* XXX - This should never happen, if it does, the caller should
ensure that the binfo is from for_type's binfos, not from any
new_decl = build_vtable (for_type, name, TREE_TYPE (orig_decl));
DECL_ALIGN (new_decl) = DECL_ALIGN (orig_decl);
+ DECL_USER_ALIGN (new_decl) = DECL_USER_ALIGN (orig_decl);
BINFO_VTABLE (binfo) = pushdecl_top_level (new_decl);
#ifdef GATHER_STATISTICS
/* Make *VIRTUALS, an entry on the BINFO_VIRTUALS list for BINFO
(which is in the hierarchy dominated by T) list FNDECL as its
- BV_FN. DELTA is the required adjustment from the `this' pointer
- where the vtable entry appears to the `this' required when the
- function is actually called. */
+ BV_FN. DELTA is the required constant adjustment from the `this'
+ pointer where the vtable entry appears to the `this' required when
+ the function is actually called. */
static void
modify_vtable_entry (t, binfo, fndecl, delta, virtuals)
tree delta;
tree *virtuals;
{
- tree vcall_index;
tree v;
v = *virtuals;
- vcall_index = integer_zero_node;
if (fndecl != BV_FN (v)
- || !tree_int_cst_equal (delta, BV_DELTA (v))
- || !tree_int_cst_equal (vcall_index, BV_VCALL_INDEX (v)))
+ || !tree_int_cst_equal (delta, BV_DELTA (v)))
{
tree base_fndecl;
base_fndecl = BV_FN (v);
BV_DELTA (v) = delta;
- BV_VCALL_INDEX (v) = vcall_index;
+ BV_VCALL_INDEX (v) = NULL_TREE;
BV_FN (v) = fndecl;
/* Now assign virtual dispatch information, if unset. We can
/* We've already dealt with this function. */
return;
- new_virtual = build_tree_list (integer_zero_node, fndecl);
- BV_VCALL_INDEX (new_virtual) = integer_zero_node;
+ new_virtual = make_node (TREE_LIST);
+ BV_FN (new_virtual) = fndecl;
+ BV_DELTA (new_virtual) = integer_zero_node;
if (DECL_VINDEX (fndecl) == error_mark_node)
{
}
}
\f
-extern struct obstack *current_obstack;
-
-/* Add method METHOD to class TYPE.
-
- If non-NULL, FIELDS is the entry in the METHOD_VEC vector entry of
- the class type where the method should be added. */
+/* Add method METHOD to class TYPE. If ERROR_P is true, we are adding
+ the method after the class has already been defined because a
+ declaration for it was seen. (Even though that is erroneous, we
+ add the method for improved error recovery.) */
void
-add_method (type, fields, method)
- tree type, *fields, method;
+add_method (type, method, error_p)
+ tree type;
+ tree method;
+ int error_p;
{
int using = (DECL_CONTEXT (method) != type);
-
- if (fields && *fields)
- *fields = build_overload (method, *fields);
- else
+ int len;
+ int slot;
+ tree method_vec;
+
+ if (!CLASSTYPE_METHOD_VEC (type))
+ /* Make a new method vector. We start with 8 entries. We must
+ allocate at least two (for constructors and destructors), and
+ we're going to end up with an assignment operator at some point
+ as well.
+
+ We could use a TREE_LIST for now, and convert it to a TREE_VEC
+ in finish_struct, but we would probably waste more memory
+ making the links in the list than we would by over-allocating
+ the size of the vector here. Furthermore, we would complicate
+ all the code that expects this to be a vector. */
+ CLASSTYPE_METHOD_VEC (type) = make_tree_vec (8);
+
+ method_vec = CLASSTYPE_METHOD_VEC (type);
+ len = TREE_VEC_LENGTH (method_vec);
+
+ /* Constructors and destructors go in special slots. */
+ if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (method))
+ slot = CLASSTYPE_CONSTRUCTOR_SLOT;
+ else if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (method))
+ slot = CLASSTYPE_DESTRUCTOR_SLOT;
+ else
{
- int len;
- int slot;
- tree method_vec;
-
- if (!CLASSTYPE_METHOD_VEC (type))
- /* Make a new method vector. We start with 8 entries. We must
- allocate at least two (for constructors and destructors), and
- we're going to end up with an assignment operator at some
- point as well.
-
- We could use a TREE_LIST for now, and convert it to a
- TREE_VEC in finish_struct, but we would probably waste more
- memory making the links in the list than we would by
- over-allocating the size of the vector here. Furthermore,
- we would complicate all the code that expects this to be a
- vector. */
- CLASSTYPE_METHOD_VEC (type) = make_tree_vec (8);
-
- method_vec = CLASSTYPE_METHOD_VEC (type);
- len = TREE_VEC_LENGTH (method_vec);
-
- if (DECL_NAME (method) == constructor_name (type))
- /* A new constructor or destructor. Constructors go in
- slot 0; destructors go in slot 1. */
- slot = DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (method)) ? 1 : 0;
- else
- {
- /* See if we already have an entry with this name. */
- for (slot = 2; slot < len; ++slot)
- if (!TREE_VEC_ELT (method_vec, slot)
- || (DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (method_vec,
- slot)))
- == DECL_NAME (method)))
- break;
+ /* See if we already have an entry with this name. */
+ for (slot = CLASSTYPE_FIRST_CONVERSION_SLOT; slot < len; ++slot)
+ if (!TREE_VEC_ELT (method_vec, slot)
+ || (DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (method_vec,
+ slot)))
+ == DECL_NAME (method)))
+ break;
- if (slot == len)
- {
- /* We need a bigger method vector. */
- tree new_vec = make_tree_vec (2 * len);
- bcopy ((PTR) &TREE_VEC_ELT (method_vec, 0),
- (PTR) &TREE_VEC_ELT (new_vec, 0),
- len * sizeof (tree));
- len = 2 * len;
- method_vec = CLASSTYPE_METHOD_VEC (type) = new_vec;
- }
+ if (slot == len)
+ {
+ /* We need a bigger method vector. */
+ int new_len;
+ tree new_vec;
+
+ /* In the non-error case, we are processing a class
+ definition. Double the size of the vector to give room
+ for new methods. */
+ if (!error_p)
+ new_len = 2 * len;
+ /* In the error case, the vector is already complete. We
+ don't expect many errors, and the rest of the front-end
+ will get confused if there are empty slots in the vector. */
+ else
+ new_len = len + 1;
+
+ new_vec = make_tree_vec (new_len);
+ bcopy ((PTR) &TREE_VEC_ELT (method_vec, 0),
+ (PTR) &TREE_VEC_ELT (new_vec, 0),
+ len * sizeof (tree));
+ len = new_len;
+ method_vec = CLASSTYPE_METHOD_VEC (type) = new_vec;
+ }
- if (DECL_CONV_FN_P (method) && !TREE_VEC_ELT (method_vec, slot))
+ if (DECL_CONV_FN_P (method) && !TREE_VEC_ELT (method_vec, slot))
+ {
+ /* Type conversion operators have to come before ordinary
+ methods; add_conversions depends on this to speed up
+ looking for conversion operators. So, if necessary, we
+ slide some of the vector elements up. In theory, this
+ makes this algorithm O(N^2) but we don't expect many
+ conversion operators. */
+ for (slot = 2; slot < len; ++slot)
{
- /* Type conversion operators have to come before
- ordinary methods; add_conversions depends on this to
- speed up looking for conversion operators. So, if
- necessary, we slide some of the vector elements up.
- In theory, this makes this algorithm O(N^2) but we
- don't expect many conversion operators. */
- for (slot = 2; slot < len; ++slot)
- {
- tree fn = TREE_VEC_ELT (method_vec, slot);
+ tree fn = TREE_VEC_ELT (method_vec, slot);
- if (!fn)
- /* There are no more entries in the vector, so we
- can insert the new conversion operator here. */
- break;
+ if (!fn)
+ /* There are no more entries in the vector, so we
+ can insert the new conversion operator here. */
+ break;
- if (!DECL_CONV_FN_P (OVL_CURRENT (fn)))
- /* We can insert the new function right at the
- SLOTth position. */
- break;
- }
+ if (!DECL_CONV_FN_P (OVL_CURRENT (fn)))
+ /* We can insert the new function right at the
+ SLOTth position. */
+ break;
+ }
- if (!TREE_VEC_ELT (method_vec, slot))
- /* There is nothing in the Ith slot, so we can avoid
- moving anything. */
+ if (!TREE_VEC_ELT (method_vec, slot))
+ /* There is nothing in the Ith slot, so we can avoid
+ moving anything. */
;
- else
- {
- /* We know the last slot in the vector is empty
- because we know that at this point there's room
- for a new function. */
- bcopy ((PTR) &TREE_VEC_ELT (method_vec, slot),
- (PTR) &TREE_VEC_ELT (method_vec, slot + 1),
- (len - slot - 1) * sizeof (tree));
- TREE_VEC_ELT (method_vec, slot) = NULL_TREE;
- }
+ else
+ {
+ /* We know the last slot in the vector is empty
+ because we know that at this point there's room
+ for a new function. */
+ bcopy ((PTR) &TREE_VEC_ELT (method_vec, slot),
+ (PTR) &TREE_VEC_ELT (method_vec, slot + 1),
+ (len - slot - 1) * sizeof (tree));
+ TREE_VEC_ELT (method_vec, slot) = NULL_TREE;
}
}
+ }
- if (template_class_depth (type))
- /* TYPE is a template class. Don't issue any errors now; wait
- until instantiation time to complain. */
- ;
- else
- {
- tree fns;
+ if (template_class_depth (type))
+ /* TYPE is a template class. Don't issue any errors now; wait
+ until instantiation time to complain. */
+ ;
+ else
+ {
+ tree fns;
- /* Check to see if we've already got this method. */
- for (fns = TREE_VEC_ELT (method_vec, slot);
- fns;
- fns = OVL_NEXT (fns))
- {
- tree fn = OVL_CURRENT (fns);
+ /* Check to see if we've already got this method. */
+ for (fns = TREE_VEC_ELT (method_vec, slot);
+ fns;
+ fns = OVL_NEXT (fns))
+ {
+ tree fn = OVL_CURRENT (fns);
- if (TREE_CODE (fn) != TREE_CODE (method))
- continue;
+ if (TREE_CODE (fn) != TREE_CODE (method))
+ continue;
- if (TREE_CODE (method) != TEMPLATE_DECL)
+ if (TREE_CODE (method) != TEMPLATE_DECL)
+ {
+ /* [over.load] Member function declarations with the
+ same name and the same parameter types cannot be
+ overloaded if any of them is a static member
+ function declaration. */
+ if ((DECL_STATIC_FUNCTION_P (fn)
+ != DECL_STATIC_FUNCTION_P (method))
+ || using)
{
- /* [over.load] Member function declarations with the
- same name and the same parameter types cannot be
- overloaded if any of them is a static member
- function declaration. */
- if ((DECL_STATIC_FUNCTION_P (fn)
- != DECL_STATIC_FUNCTION_P (method))
- || using)
+ tree parms1 = TYPE_ARG_TYPES (TREE_TYPE (fn));
+ tree parms2 = TYPE_ARG_TYPES (TREE_TYPE (method));
+
+ if (! DECL_STATIC_FUNCTION_P (fn))
+ parms1 = TREE_CHAIN (parms1);
+ if (! DECL_STATIC_FUNCTION_P (method))
+ parms2 = TREE_CHAIN (parms2);
+
+ if (compparms (parms1, parms2))
{
- tree parms1 = TYPE_ARG_TYPES (TREE_TYPE (fn));
- tree parms2 = TYPE_ARG_TYPES (TREE_TYPE (method));
-
- if (! DECL_STATIC_FUNCTION_P (fn))
- parms1 = TREE_CHAIN (parms1);
- if (! DECL_STATIC_FUNCTION_P (method))
- parms2 = TREE_CHAIN (parms2);
-
- if (compparms (parms1, parms2))
- {
- if (using)
- /* Defer to the local function. */
- return;
- else
- cp_error ("`%#D' and `%#D' cannot be overloaded",
- fn, method);
- }
+ if (using)
+ /* Defer to the local function. */
+ return;
+ else
+ cp_error ("`%#D' and `%#D' cannot be overloaded",
+ fn, method);
}
-
- /* Since this is an ordinary function in a
- non-template class, it's mangled name can be used
- as a unique identifier. This technique is only
- an optimization; we would get the same results if
- we just used decls_match here. */
- if (DECL_ASSEMBLER_NAME (fn)
- != DECL_ASSEMBLER_NAME (method))
- continue;
}
- else if (!decls_match (fn, method))
+
+ /* Since this is an ordinary function in a
+ non-template class, it's mangled name can be used
+ as a unique identifier. This technique is only
+ an optimization; we would get the same results if
+ we just used decls_match here. */
+ if (DECL_ASSEMBLER_NAME (fn)
+ != DECL_ASSEMBLER_NAME (method))
continue;
+ }
+ else if (!decls_match (fn, method))
+ continue;
- /* There has already been a declaration of this method
- or member template. */
- cp_error_at ("`%D' has already been declared in `%T'",
- method, type);
+ /* There has already been a declaration of this method
+ or member template. */
+ cp_error_at ("`%D' has already been declared in `%T'",
+ method, type);
- /* We don't call duplicate_decls here to merge the
- declarations because that will confuse things if the
- methods have inline definitions. In particular, we
- will crash while processing the definitions. */
- return;
- }
+ /* We don't call duplicate_decls here to merge the
+ declarations because that will confuse things if the
+ methods have inline definitions. In particular, we
+ will crash while processing the definitions. */
+ return;
}
+ }
- /* Actually insert the new method. */
- TREE_VEC_ELT (method_vec, slot)
- = build_overload (method, TREE_VEC_ELT (method_vec, slot));
+ /* Actually insert the new method. */
+ TREE_VEC_ELT (method_vec, slot)
+ = build_overload (method, TREE_VEC_ELT (method_vec, slot));
/* Add the new binding. */
- if (!DECL_CONSTRUCTOR_P (method)
- && !DECL_DESTRUCTOR_P (method))
- push_class_level_binding (DECL_NAME (method),
- TREE_VEC_ELT (method_vec, slot));
- }
+ if (!DECL_CONSTRUCTOR_P (method)
+ && !DECL_DESTRUCTOR_P (method))
+ push_class_level_binding (DECL_NAME (method),
+ TREE_VEC_ELT (method_vec, slot));
}
/* Subroutines of finish_struct. */
tree fdecl;
tree access;
{
- tree elem = purpose_member (t, DECL_ACCESS (fdecl));
+ tree elem;
+
+ if (!DECL_LANG_SPECIFIC (fdecl))
+ retrofit_lang_decl (fdecl);
+
+ elem = purpose_member (t, DECL_ACCESS (fdecl));
if (elem)
{
if (TREE_VALUE (elem) != access)
if (is_overloaded_fn (fdecl))
flist = fdecl;
- else if (! DECL_LANG_SPECIFIC (fdecl))
- my_friendly_abort (20000221);
if (! old_value)
;
if (flist)
for (; flist; flist = OVL_NEXT (flist))
{
- add_method (t, 0, OVL_CURRENT (flist));
+ add_method (t, OVL_CURRENT (flist), /*error_p=*/0);
alter_access (t, OVL_CURRENT (flist), access);
}
else
tree binfo;
void *data;
{
- int i;
tree base_binfo;
if (!CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (binfo)))
return NULL_TREE;
- i = CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
- base_binfo = BINFO_BASETYPE (binfo, i);
+ base_binfo = get_primary_binfo (binfo);
- if (!TREE_VIA_VIRTUAL (base_binfo))
- /* Non-virtual base classes are easy. */
- BINFO_PRIMARY_MARKED_P (base_binfo) = 1;
- else
+ if (TREE_VIA_VIRTUAL (base_binfo))
{
tree shared_binfo;
+ tree type;
- shared_binfo
- = BINFO_FOR_VBASE (BINFO_TYPE (base_binfo), (tree) data);
+ type = (tree) data;
+ shared_binfo = binfo_for_vbase (BINFO_TYPE (base_binfo), type);
/* If this virtual base is not already primary somewhere else in
the hiearchy, then we'll be using this copy. */
- if (!BINFO_VBASE_PRIMARY_P (shared_binfo))
+ if (!BINFO_PRIMARY_MARKED_P (shared_binfo))
{
- BINFO_VBASE_PRIMARY_P (shared_binfo) = 1;
- BINFO_PRIMARY_MARKED_P (base_binfo) = 1;
+ /* Make sure the CLASSTYPE_VBASECLASSES list contains the
+ primary copy; it's the one that really exists. */
+ if (base_binfo != shared_binfo)
+ TREE_VALUE (purpose_member (BINFO_TYPE (base_binfo),
+ CLASSTYPE_VBASECLASSES (type)))
+ = base_binfo;
}
+ else
+ base_binfo = NULL_TREE;
}
+ if (base_binfo)
+ BINFO_PRIMARY_BASE_OF (base_binfo) = binfo;
+
return NULL_TREE;
}
if (!TREE_VIA_VIRTUAL (vbases))
continue;
- vbase = BINFO_FOR_VBASE (BINFO_TYPE (vbases), type);
- if (BINFO_VBASE_PRIMARY_P (vbase))
+ vbase = binfo_for_vbase (BINFO_TYPE (vbases), type);
+ if (BINFO_PRIMARY_MARKED_P (vbase))
/* This virtual base was already included in the hierarchy, so
there's nothing to do here. */
continue;
- /* Temporarily pretend that VBASE is primary so that its bases
- will be walked; this is the real copy of VBASE. */
- BINFO_PRIMARY_MARKED_P (vbase) = 1;
-
/* Now, walk its bases. */
dfs_walk_real (vbase, dfs_mark_primary_bases, NULL,
dfs_skip_nonprimary_vbases_unmarkedp, type);
-
- /* VBASE wasn't really primary. */
- BINFO_PRIMARY_MARKED_P (vbase) = 0;
}
}
-/* Make the Ith baseclass of T its primary base. */
+/* Make the BINFO the primary base of T. */
static void
-set_primary_base (t, i, vfuns_p)
+set_primary_base (t, binfo, vfuns_p)
tree t;
- int i;
+ tree binfo;
int *vfuns_p;
{
tree basetype;
- CLASSTYPE_VFIELD_PARENT (t) = i;
- basetype = BINFO_TYPE (CLASSTYPE_PRIMARY_BINFO (t));
+ CLASSTYPE_PRIMARY_BINFO (t) = binfo;
+ basetype = BINFO_TYPE (binfo);
TYPE_BINFO_VTABLE (t) = TYPE_BINFO_VTABLE (basetype);
TYPE_BINFO_VIRTUALS (t) = TYPE_BINFO_VIRTUALS (basetype);
TYPE_VFIELD (t) = TYPE_VFIELD (basetype);
int *vfuns_p;
{
int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (t);
+ tree vbases;
+ tree type_binfo;
/* If there are no baseclasses, there is certainly no primary base. */
if (n_baseclasses == 0)
return;
- *vfuns_p = 0;
+ type_binfo = TYPE_BINFO (t);
for (i = 0; i < n_baseclasses; i++)
{
- tree base_binfo = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (t), i);
+ tree base_binfo = BINFO_BASETYPE (type_binfo, i);
tree basetype = BINFO_TYPE (base_binfo);
if (TYPE_CONTAINS_VPTR_P (basetype))
if (!CLASSTYPE_HAS_PRIMARY_BASE_P (t))
{
- set_primary_base (t, i, vfuns_p);
+ set_primary_base (t, base_binfo, vfuns_p);
CLASSTYPE_VFIELDS (t) = copy_list (CLASSTYPE_VFIELDS (basetype));
}
else
CLASSTYPE_VFIELDS (t));
if (!flag_new_abi && *vfuns_p == 0)
- set_primary_base (t, i, vfuns_p);
+ set_primary_base (t, base_binfo, vfuns_p);
}
}
}
if (!TYPE_VFIELD (t))
- CLASSTYPE_VFIELD_PARENT (t) = -1;
+ CLASSTYPE_PRIMARY_BINFO (t) = NULL_TREE;
+
+ /* Mark the indirect primary bases. */
+ for (vbases = CLASSTYPE_VBASECLASSES (t);
+ vbases;
+ vbases = TREE_CHAIN (vbases))
+ {
+ tree binfo = TREE_VALUE (vbases);
+
+ /* See if this virtual base is an indirect primary base. If so,
+ it must be either a primary base or an indirect primary base
+ in one of the direct bases. */
+ for (i = 0; i < n_baseclasses; ++i)
+ {
+ tree basetype;
+ tree v;
+
+ basetype = TYPE_BINFO_BASETYPE (t, i);
+ for (v = CLASSTYPE_VBASECLASSES (basetype);
+ v;
+ v = TREE_CHAIN (v))
+ {
+ tree b = TREE_VALUE (v);
+ if ((BINFO_PRIMARY_MARKED_P (b)
+ || BINFO_INDIRECT_PRIMARY_P (b))
+ && same_type_p (BINFO_TYPE (b), BINFO_TYPE (binfo)))
+ {
+ BINFO_INDIRECT_PRIMARY_P (binfo) = 1;
+ break;
+ }
+ }
+
+ /* If we've discovered that this virtual base is an indirect
+ primary base, then we can move on to the next virtual
+ base. */
+ if (BINFO_INDIRECT_PRIMARY_P (binfo))
+ break;
+ }
+ }
/* The new ABI allows for the use of a "nearly-empty" virtual base
class as the primary base class if no non-virtual polymorphic
base can be found. */
if (flag_new_abi && !CLASSTYPE_HAS_PRIMARY_BASE_P (t))
- for (i = 0; i < n_baseclasses; ++i)
- {
- tree base_binfo = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (t), i);
- tree basetype = BINFO_TYPE (base_binfo);
+ {
+ /* If not NULL, this is the best primary base candidate we have
+ found so far. */
+ tree candidate = NULL_TREE;
+ tree base_binfo;
- if (TREE_VIA_VIRTUAL (base_binfo)
- && CLASSTYPE_NEARLY_EMPTY_P (basetype))
- {
- set_primary_base (t, i, vfuns_p);
- CLASSTYPE_VFIELDS (t) = copy_list (CLASSTYPE_VFIELDS (basetype));
- break;
- }
- }
+ /* Loop over the baseclasses. */
+ for (base_binfo = TYPE_BINFO (t);
+ base_binfo;
+ base_binfo = TREE_CHAIN (base_binfo))
+ {
+ tree basetype = BINFO_TYPE (base_binfo);
+
+ if (TREE_VIA_VIRTUAL (base_binfo)
+ && CLASSTYPE_NEARLY_EMPTY_P (basetype))
+ {
+ /* If this is not an indirect primary base, then it's
+ definitely our primary base. */
+ if (!BINFO_INDIRECT_PRIMARY_P (base_binfo))
+ {
+ candidate = base_binfo;
+ break;
+ }
+ /* If this was an indirect primary base, it's still our
+ primary base -- unless there's another nearly-empty
+ virtual base that isn't an indirect primary base. */
+ else if (!candidate)
+ candidate = base_binfo;
+ }
+ }
+
+ /* If we've got a primary base, use it. */
+ if (candidate)
+ {
+ set_primary_base (t, candidate, vfuns_p);
+ CLASSTYPE_VFIELDS (t)
+ = copy_list (CLASSTYPE_VFIELDS (BINFO_TYPE (candidate)));
+ }
+ }
/* Mark the primary base classes at this point. */
mark_primary_bases (t);
/* Clear out this flag. */
DECL_IN_AGGR_P (fn_fields) = 0;
- if (TYPE_HAS_DESTRUCTOR (t) && !TREE_VEC_ELT (method_vec, 1))
+ if (TYPE_HAS_DESTRUCTOR (t) && !CLASSTYPE_DESTRUCTORS (t))
/* We thought there was a destructor, but there wasn't. Some
parse errors cause this anomalous situation. */
TYPE_HAS_DESTRUCTOR (t) = 0;
tree template_info = CLASSTYPE_TEMPLATE_INFO (t);
int use_template = CLASSTYPE_USE_TEMPLATE (t);
- bzero ((char *) TYPE_LANG_SPECIFIC (t), sizeof (struct lang_type));
+ memset ((char *) TYPE_LANG_SPECIFIC (t), 0, sizeof (struct lang_type));
BINFO_BASETYPES(binfo) = NULL_TREE;
TYPE_BINFO (t) = binfo;
}
}
-/* True if we should override the given BASE_FNDECL with the given
- FNDECL. */
+/* True iff FNDECL and BASE_FNDECL (both non-static member functions)
+ have the same signature. */
static int
-overrides (fndecl, base_fndecl)
+same_signature_p (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)))
+ /* One destructor overrides another if they are the same kind of
+ destructor. */
+ if (DECL_DESTRUCTOR_P (base_fndecl) && DECL_DESTRUCTOR_P (fndecl)
+ && special_function_p (base_fndecl) == special_function_p (fndecl))
return 1;
- if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (base_fndecl))
- || DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
+ /* But a non-destructor never overrides a destructor, nor vice
+ versa, nor do different kinds of destructors override
+ one-another. For example, a complete object destructor does not
+ override a deleting destructor. */
+ if (DECL_DESTRUCTOR_P (base_fndecl) || DECL_DESTRUCTOR_P (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)))
tree path;
tree method;
+ /* We haven't found an overrider yet. */
+ method = NULL_TREE;
/* We've found a path to the declaring base. Walk down the path
looking for an overrider for FN. */
- for (path = reverse_path (binfo);
+ 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))
+ if (DECL_VIRTUAL_P (method)
+ && same_signature_p (method, ffod->fn))
break;
if (method)
the base from which it came. */
if (path)
{
+ tree base;
+
+ /* Assume the path is non-virtual. See if there are any
+ virtual bases from (but not including) the overrider up
+ to and including the base where the function is
+ defined. */
+ for (base = TREE_CHAIN (path); base; base = TREE_CHAIN (base))
+ if (TREE_VIA_VIRTUAL (TREE_VALUE (base)))
+ {
+ base = ffod->declaring_base;
+ while (BINFO_PRIMARY_MARKED_P (base))
+ {
+ BINFO_OVERRIDE_ALONG_VIRTUAL_PATH_P (base) = 1;
+ base = BINFO_INHERITANCE_CHAIN (base);
+ }
+ BINFO_OVERRIDE_ALONG_VIRTUAL_PATH_P (base) = 1;
+ break;
+ }
+
if (ffod->overriding_fn && ffod->overriding_fn != method)
{
/* We've found a different overrider along a different
return build_tree_list (ffod.overriding_fn, ffod.overriding_base);
}
-/* Called via dfs_walk. Returns BINFO if BINFO has the same type as
- DATA (which is really an _TYPE node). */
+/* Update a entry in the vtable for BINFO, which is in the hierarchy
+ dominated by T. FN has been overridden in BINFO; VIRTUALS points
+ to the corresponding position in the BINFO_VIRTUALS list. */
-static tree
-dfs_find_base (binfo, data)
+static void
+update_vtable_entry_for_fn (t, binfo, fn, virtuals)
+ tree t;
tree binfo;
- void *data;
+ tree fn;
+ tree *virtuals;
{
- return (same_type_p (BINFO_TYPE (binfo), (tree) data)
- ? binfo : NULL_TREE);
+ tree b;
+ tree overrider;
+ tree delta;
+ tree virtual_base;
+ int generate_thunk_with_vtable_p;
+
+ /* Find the function which originally caused this vtable
+ entry to be present. */
+ b = binfo;
+ while (1)
+ {
+ tree primary_base;
+ tree f;
+
+ primary_base = get_primary_binfo (b);
+ if (!primary_base)
+ break;
+
+ for (f = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (primary_base)));
+ f;
+ f = TREE_CHAIN (f))
+ if (same_signature_p (BV_FN (f), fn))
+ break;
+
+ if (!f)
+ break;
+
+ fn = BV_FN (f);
+ b = primary_base;
+ }
+
+ /* Find the final overrider. */
+ overrider = find_final_overrider (t, b, fn);
+ if (overrider == error_mark_node)
+ return;
+
+ /* Compute the constant adjustment to the `this' pointer. The
+ `this' pointer, when this function is called, will point at the
+ class whose vtable this is. */
+ delta = size_binop (PLUS_EXPR,
+ get_derived_offset (binfo,
+ DECL_VIRTUAL_CONTEXT (fn)),
+ BINFO_OFFSET (binfo));
+
+ /* Assume that we will produce a thunk that convert all the way to
+ the final overrider, and not to an intermediate virtual base. */
+ virtual_base = NULL_TREE;
+
+ /* Assume that we will always generate thunks with the vtables that
+ reference them. */
+ generate_thunk_with_vtable_p = 1;
+
+ /* Under the new ABI, we will convert to an intermediate virtual
+ base first, and then use the vcall offset located there to finish
+ the conversion. */
+ if (flag_new_abi)
+ {
+ while (b)
+ {
+ /* If we find BINFO, then the final overrider is in a class
+ derived from BINFO, so the thunks can be generated with
+ the final overrider. */
+ if (!virtual_base
+ && same_type_p (BINFO_TYPE (b), BINFO_TYPE (binfo)))
+ generate_thunk_with_vtable_p = 0;
+
+ /* If we find the final overrider, then we can stop
+ walking. */
+ if (same_type_p (BINFO_TYPE (b),
+ BINFO_TYPE (TREE_VALUE (overrider))))
+ break;
+
+ /* If we find a virtual base, and we haven't yet found the
+ overrider, then there is a virtual base between the
+ declaring base and the final overrider. */
+ if (!virtual_base && TREE_VIA_VIRTUAL (b))
+ {
+ generate_thunk_with_vtable_p = 1;
+ virtual_base = b;
+ }
+
+ b = BINFO_INHERITANCE_CHAIN (b);
+ }
+ }
+ else
+ virtual_base = NULL_TREE;
+
+ if (virtual_base)
+ /* The `this' pointer needs to be adjusted to the nearest virtual
+ base. */
+ delta = size_diffop (BINFO_OFFSET (virtual_base), delta);
+ else
+ /* The `this' pointer needs to be adjusted from pointing to
+ BINFO to pointing at the base where the final overrider
+ appears. */
+ delta = size_diffop (BINFO_OFFSET (TREE_VALUE (overrider)), delta);
+
+ modify_vtable_entry (t,
+ binfo,
+ TREE_PURPOSE (overrider),
+ delta,
+ virtuals);
+
+ if (virtual_base)
+ BV_USE_VCALL_INDEX_P (*virtuals) = 1;
+ if (generate_thunk_with_vtable_p)
+ BV_GENERATE_THUNK_WITH_VTABLE_P (*virtuals) = 1;
}
/* Called from modify_all_vtables via dfs_walk. */
virtuals;
virtuals = TREE_CHAIN (virtuals),
old_virtuals = TREE_CHAIN (old_virtuals))
- {
- tree b;
- tree fn;
- tree overrider;
- tree vindex;
- tree delta;
- HOST_WIDE_INT vindex_val;
- HOST_WIDE_INT i;
-
- /* Find the function which originally caused this vtable
- entry to be present. */
- fn = BV_FN (old_virtuals);
- vindex = DECL_VINDEX (fn);
- b = dfs_walk (binfo, dfs_find_base, NULL, DECL_VIRTUAL_CONTEXT (fn));
- fn = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (b)));
- i = first_vfun_index (BINFO_TYPE (b));
- vindex_val = tree_low_cst (vindex, 0);
- while (i < vindex_val)
- {
- fn = TREE_CHAIN (fn);
- ++i;
- }
- fn = BV_FN (fn);
-
- /* Handle the case of a virtual function defined in BINFO
- itself. */
- overrider = find_final_overrider (t, b, fn);
- if (overrider == error_mark_node)
- continue;
-
- /* The `this' pointer needs to be adjusted from pointing to
- BINFO to pointing at the base where the final overrider
- appears. */
- delta = size_binop (PLUS_EXPR,
- get_derived_offset (binfo,
- DECL_VIRTUAL_CONTEXT (fn)),
- BINFO_OFFSET (binfo));
- delta = size_diffop (BINFO_OFFSET (TREE_VALUE (overrider)), delta);
-
- modify_vtable_entry (t,
- binfo,
- TREE_PURPOSE (overrider),
- delta,
- &virtuals);
- }
+ update_vtable_entry_for_fn (t,
+ binfo,
+ BV_FN (old_virtuals),
+ &virtuals);
}
SET_BINFO_MARKED (binfo);
{
tree fn = TREE_VALUE (*fnsp);
- if (BINFO_VIRTUALS (binfo)
- && !value_member (fn, BINFO_VIRTUALS (binfo)))
+ if (!BINFO_VIRTUALS (binfo)
+ || !value_member (fn, BINFO_VIRTUALS (binfo)))
{
/* Set the vtable index. */
set_vindex (t, fn, vfuns_p);
/* We don't need to adjust the `this' pointer when
calling this function. */
BV_DELTA (*fnsp) = integer_zero_node;
- BV_VCALL_INDEX (*fnsp) = integer_zero_node;
+ BV_VCALL_INDEX (*fnsp) = NULL_TREE;
/* This is an overridden function not already in our
vtable. Keep it. */
tree fndecl, base_fndecls;
{
for (; base_fndecls; base_fndecls = TREE_CHAIN (base_fndecls))
- {
- if (overrides (fndecl, TREE_VALUE (base_fndecls)))
- TREE_PURPOSE (base_fndecls) = fndecl;
- }
+ if (same_signature_p (fndecl, TREE_VALUE (base_fndecls)))
+ TREE_PURPOSE (base_fndecls) = fndecl;
}
/* If this declaration supersedes the declaration of
check_for_override (decl, ctype)
tree decl, ctype;
{
- tree binfos = BINFO_BASETYPES (TYPE_BINFO (ctype));
- int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
- int virtualp = DECL_VIRTUAL_P (decl);
- int found_overriden_fn = 0;
+ if (TREE_CODE (decl) == TEMPLATE_DECL)
+ /* In [temp.mem] we have:
- for (i = 0; i < n_baselinks; i++)
+ A specialization of a member function template does not
+ override a virtual function from a base class. */
+ return;
+ if ((DECL_DESTRUCTOR_P (decl)
+ || IDENTIFIER_VIRTUAL_P (DECL_NAME (decl)))
+ && look_for_overrides (ctype, decl)
+ && !DECL_STATIC_FUNCTION_P (decl))
{
- tree base_binfo = TREE_VEC_ELT (binfos, i);
- if (TYPE_POLYMORPHIC_P (BINFO_TYPE (base_binfo)))
- {
- tree tmp = get_matching_virtual
- (base_binfo, decl,
- DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl)));
-
- if (tmp && !found_overriden_fn)
- {
- /* If this function overrides some virtual in some base
- class, then the function itself is also necessarily
- virtual, even if the user didn't explicitly say so. */
- DECL_VIRTUAL_P (decl) = 1;
-
- /* The TMP we really want is the one from the deepest
- baseclass on this path, taking care not to
- duplicate if we have already found it (via another
- path to its virtual baseclass. */
- if (TREE_CODE (TREE_TYPE (decl)) == FUNCTION_TYPE)
- {
- cp_error_at ("`static %#D' cannot be declared", decl);
- cp_error_at (" since `virtual %#D' declared in base class",
- tmp);
- break;
- }
- virtualp = 1;
-
- /* Set DECL_VINDEX to a value that is neither an
- INTEGER_CST nor the error_mark_node so that
- add_virtual_function will realize this is an
- overridden function. */
- DECL_VINDEX (decl)
- = tree_cons (tmp, NULL_TREE, DECL_VINDEX (decl));
-
- /* We now know that DECL overrides something,
- which is all that is important. But, we must
- continue to iterate through all the base-classes
- in order to allow get_matching_virtual to check for
- various illegal overrides. */
- found_overriden_fn = 1;
- }
- }
+ /* Set DECL_VINDEX to a value that is neither an
+ INTEGER_CST nor the error_mark_node so that
+ add_virtual_function will realize this is an
+ overriding function. */
+ DECL_VINDEX (decl) = decl;
}
- if (virtualp)
+ if (DECL_VIRTUAL_P (decl))
{
if (DECL_VINDEX (decl) == NULL_TREE)
DECL_VINDEX (decl) = error_mark_node;
/* Now give a warning for all base functions without overriders,
as they are hidden. */
for (; base_fndecls; base_fndecls = TREE_CHAIN (base_fndecls))
- {
- if (! overrides (TREE_PURPOSE (base_fndecls),
- TREE_VALUE (base_fndecls)))
- {
- /* Here we know it is a hider, and no overrider exists. */
- cp_warning_at ("`%D' was hidden", TREE_VALUE (base_fndecls));
- cp_warning_at (" by `%D'", TREE_PURPOSE (base_fndecls));
- }
- }
+ if (!same_signature_p (TREE_PURPOSE (base_fndecls),
+ TREE_VALUE (base_fndecls)))
+ {
+ /* Here we know it is a hider, and no overrider exists. */
+ cp_warning_at ("`%D' was hidden", TREE_VALUE (base_fndecls));
+ cp_warning_at (" by `%D'", TREE_PURPOSE (base_fndecls));
+ }
}
}
/* Now, hook all of the new functions on to TYPE_METHODS,
and add them to the CLASSTYPE_METHOD_VEC. */
for (f = &implicit_fns; *f; f = &TREE_CHAIN (*f))
- add_method (t, 0, *f);
+ add_method (t, *f, /*error_p=*/0);
*f = TYPE_METHODS (t);
TYPE_METHODS (t) = implicit_fns;
/* detect invalid field size. */
if (TREE_CODE (w) == CONST_DECL)
w = DECL_INITIAL (w);
- else if (TREE_READONLY_DECL_P (w))
+ else
w = decl_constant_value (w);
if (TREE_CODE (w) != INTEGER_CST)
#endif
#ifdef PCC_BITFIELD_TYPE_MATTERS
if (PCC_BITFIELD_TYPE_MATTERS)
- DECL_ALIGN (field) = MAX (DECL_ALIGN (field),
- TYPE_ALIGN (type));
+ {
+ DECL_ALIGN (field) = MAX (DECL_ALIGN (field),
+ TYPE_ALIGN (type));
+ DECL_USER_ALIGN (field) |= TYPE_USER_ALIGN (type);
+ }
#endif
}
}
DECL_BIT_FIELD (field) = 0;
CLEAR_DECL_C_BIT_FIELD (field);
DECL_ALIGN (field) = MAX (DECL_ALIGN (field), TYPE_ALIGN (type));
+ DECL_USER_ALIGN (field) |= TYPE_USER_ALIGN (type);
}
}
(DECL_PACKED (field)
? BITS_PER_UNIT
: TYPE_ALIGN (TREE_TYPE (field))));
+ if (! DECL_PACKED (field))
+ DECL_USER_ALIGN (field) |= TYPE_USER_ALIGN (TREE_TYPE (field));
}
/* Check the data members (both static and non-static), class-scoped
TYPE_HAS_COMPLEX_ASSIGN_REF (t) = 1;
if (! TYPE_HAS_CONSTRUCTOR (t) && extra_warnings)
- {
- if (DECL_NAME (x))
- cp_warning_at ("non-static reference `%#D' in class without a constructor", x);
- else
- cp_warning_at ("non-static reference in class without a constructor", x);
- }
+ cp_warning_at ("non-static reference `%#D' in class without a constructor", x);
}
type = strip_array_types (type);
TYPE_HAS_COMPLEX_ASSIGN_REF (t) = 1;
if (! TYPE_HAS_CONSTRUCTOR (t) && extra_warnings)
- {
- if (DECL_NAME (x))
- cp_warning_at ("non-static const member `%#D' in class without a constructor", x);
- else
- cp_warning_at ("non-static const member in class without a constructor", x);
- }
+ cp_warning_at ("non-static const member `%#D' in class without a constructor", x);
}
/* A field that is pseudo-const makes the structure likewise. */
else if (IS_AGGR_TYPE (type))
|= CLASSTYPE_READONLY_FIELDS_NEED_INIT (type);
}
+ /* Core issue 80: A nonstatic data member is required to have a
+ different name from the class iff the class has a
+ user-defined constructor. */
+ if (DECL_NAME (x) == constructor_name (t)
+ && TYPE_HAS_CONSTRUCTOR (t))
+ cp_pedwarn_at ("field `%#D' with same name as class", x);
+
/* We set DECL_C_BIT_FIELD in grokbitfield.
If the type and width are valid, we'll also set DECL_BIT_FIELD. */
if (DECL_C_BIT_FIELD (x))
*empty_p = 0;
/* Build the FIELD_DECL. */
- field = build_lang_decl (FIELD_DECL, name, type);
+ field = build_decl (FIELD_DECL, name, type);
DECL_ASSEMBLER_NAME (field) = assembler_name;
DECL_VIRTUAL_P (field) = 1;
DECL_ARTIFICIAL (field) = 1;
DECL_FIELD_CONTEXT (field) = class_type;
DECL_FCONTEXT (field) = fcontext;
DECL_ALIGN (field) = TYPE_ALIGN (type);
+ DECL_USER_ALIGN (field) = TYPE_USER_ALIGN (type);
/* Return it. */
return field;
}
-/* Record the type of BINFO in the slot in DATA (which is really a
- `varray_type *') corresponding to the BINFO_OFFSET. */
+/* If TYPE is an empty class type, records its OFFSET in the table of
+ OFFSETS. */
-static tree
-dfs_record_base_offsets (binfo, data)
- tree binfo;
- void *data;
+static int
+record_subobject_offset (type, offset, offsets)
+ tree type;
+ tree offset;
+ splay_tree offsets;
{
- varray_type *v;
- unsigned HOST_WIDE_INT offset = tree_low_cst (BINFO_OFFSET (binfo), 1);
+ splay_tree_node n;
+
+ if (!is_empty_class (type))
+ return 0;
- v = (varray_type *) data;
- while (VARRAY_SIZE (*v) <= offset)
- VARRAY_GROW (*v, 2 * VARRAY_SIZE (*v));
- VARRAY_TREE (*v, offset) = tree_cons (NULL_TREE,
- BINFO_TYPE (binfo),
- VARRAY_TREE (*v, offset));
+ /* Record the location of this empty object in OFFSETS. */
+ n = splay_tree_lookup (offsets, (splay_tree_key) offset);
+ if (!n)
+ n = splay_tree_insert (offsets,
+ (splay_tree_key) offset,
+ (splay_tree_value) NULL_TREE);
+ n->value = ((splay_tree_value)
+ tree_cons (NULL_TREE,
+ type,
+ (tree) n->value));
- return NULL_TREE;
+ return 0;
}
-/* Add the offset of BINFO and its bases to BASE_OFFSETS. */
+/* Returns non-zero if TYPE is an empty class type and there is
+ already an entry in OFFSETS for the same TYPE as the same OFFSET. */
-static void
-record_base_offsets (binfo, base_offsets)
- tree binfo;
- varray_type *base_offsets;
+static int
+check_subobject_offset (type, offset, offsets)
+ tree type;
+ tree offset;
+ splay_tree offsets;
{
- dfs_walk (binfo,
- dfs_record_base_offsets,
- dfs_skip_vbases,
- base_offsets);
-}
+ splay_tree_node n;
+ tree t;
-/* Returns non-NULL if there is already an entry in DATA (which is
- really a `varray_type') indicating that an object with the same
- type of BINFO is already at the BINFO_OFFSET for BINFO. */
+ if (!is_empty_class (type))
+ return 0;
-static tree
-dfs_search_base_offsets (binfo, data)
- tree binfo;
- void *data;
-{
- if (is_empty_class (BINFO_TYPE (binfo)))
- {
- varray_type v = (varray_type) data;
- /* Find the offset for this BINFO. */
- unsigned HOST_WIDE_INT offset = tree_low_cst (BINFO_OFFSET (binfo), 1);
- tree t;
+ /* Record the location of this empty object in OFFSETS. */
+ n = splay_tree_lookup (offsets, (splay_tree_key) offset);
+ if (!n)
+ return 0;
- /* If we haven't yet encountered any objects at offsets that
- big, then there's no conflict. */
- if (VARRAY_SIZE (v) <= offset)
- return NULL_TREE;
- /* Otherwise, go through the objects already allocated at this
- offset. */
- for (t = VARRAY_TREE (v, offset); t; t = TREE_CHAIN (t))
- if (same_type_p (TREE_VALUE (t), BINFO_TYPE (binfo)))
- return binfo;
- }
+ for (t = (tree) n->value; t; t = TREE_CHAIN (t))
+ if (same_type_p (TREE_VALUE (t), type))
+ return 1;
- return NULL_TREE;
+ return 0;
}
-/* Returns non-zero if there's a conflict between BINFO and a base
- already mentioned in BASE_OFFSETS if BINFO is placed at its current
- BINFO_OFFSET. */
+/* Walk through all the subobjects of TYPE (located at OFFSET). Call
+ F for every subobject, passing it the type, offset, and table of
+ OFFSETS. If VBASES_P is non-zero, then even non-virtual primary
+ bases should be traversed; otherwise, they are ignored. If F
+ returns a non-zero value, the traversal ceases, and that value is
+ returned. Otherwise, returns zero. */
static int
-layout_conflict_p (binfo, base_offsets)
- tree binfo;
- varray_type base_offsets;
+walk_subobject_offsets (type, f, offset, offsets, vbases_p)
+ tree type;
+ subobject_offset_fn f;
+ tree offset;
+ splay_tree offsets;
+ int vbases_p;
+{
+ int r = 0;
+
+ if (CLASS_TYPE_P (type))
+ {
+ tree field;
+ int i;
+
+ /* Record the location of TYPE. */
+ r = (*f) (type, offset, offsets);
+ if (r)
+ return r;
+
+ /* Iterate through the direct base classes of TYPE. */
+ for (i = 0; i < CLASSTYPE_N_BASECLASSES (type); ++i)
+ {
+ tree binfo = BINFO_BASETYPE (TYPE_BINFO (type), i);
+
+ if (!vbases_p
+ && TREE_VIA_VIRTUAL (binfo)
+ && !BINFO_PRIMARY_MARKED_P (binfo))
+ continue;
+
+ r = walk_subobject_offsets (BINFO_TYPE (binfo),
+ f,
+ size_binop (PLUS_EXPR,
+ offset,
+ BINFO_OFFSET (binfo)),
+ offsets,
+ vbases_p);
+ if (r)
+ return r;
+ }
+
+ /* Iterate through the fields of TYPE. */
+ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ if (TREE_CODE (field) == FIELD_DECL)
+ {
+ r = walk_subobject_offsets (TREE_TYPE (field),
+ f,
+ size_binop (PLUS_EXPR,
+ offset,
+ DECL_FIELD_OFFSET (field)),
+ offsets,
+ /*vbases_p=*/1);
+ if (r)
+ return r;
+ }
+ }
+ else if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ tree domain = TYPE_DOMAIN (type);
+ tree index;
+
+ /* Step through each of the elements in the array. */
+ for (index = size_zero_node;
+ INT_CST_LT (index, TYPE_MAX_VALUE (domain));
+ index = size_binop (PLUS_EXPR, index, size_one_node))
+ {
+ r = walk_subobject_offsets (TREE_TYPE (type),
+ f,
+ offset,
+ offsets,
+ /*vbases_p=*/1);
+ if (r)
+ return r;
+ offset = size_binop (PLUS_EXPR, offset,
+ TYPE_SIZE_UNIT (TREE_TYPE (type)));
+ }
+ }
+
+ return 0;
+}
+
+/* Record all of the empty subobjects of TYPE (located at OFFSET) in
+ OFFSETS. If VBASES_P is non-zero, virtual bases of TYPE are
+ examined. */
+
+static void
+record_subobject_offsets (type, offset, offsets, vbases_p)
+ tree type;
+ tree offset;
+ splay_tree offsets;
+ int vbases_p;
+{
+ walk_subobject_offsets (type, record_subobject_offset, offset,
+ offsets, vbases_p);
+}
+
+/* Returns non-zero if any of the empty subobjects of TYPE (located at
+ OFFSET) conflict with entries in OFFSETS. If VBASES_P is non-zero,
+ virtual bases of TYPE are examined. */
+
+static int
+layout_conflict_p (type, offset, offsets, vbases_p)
+ tree type;
+ tree offset;
+ splay_tree offsets;
+ int vbases_p;
{
- return dfs_walk (binfo, dfs_search_base_offsets, dfs_skip_vbases,
- base_offsets) != NULL_TREE;
+ return walk_subobject_offsets (type, check_subobject_offset, offset,
+ offsets, vbases_p);
}
/* DECL is a FIELD_DECL corresponding either to a base subobject of a
non-static data member of the type indicated by RLI. BINFO is the
- binfo corresponding to the base subobject, or, if this is a
- non-static data-member, a dummy BINFO for the type of the data
- member. BINFO may be NULL if checks to see if the field overlaps
- an existing field with the same type are not required. V maps
- offsets to types already located at those offsets. This function
- determines the position of the DECL. */
+ binfo corresponding to the base subobject, OFFSETS maps offsets to
+ types already located at those offsets. This function determines
+ the position of the DECL. */
static void
-layout_nonempty_base_or_field (rli, decl, binfo, v)
+layout_nonempty_base_or_field (rli, decl, binfo, offsets)
record_layout_info rli;
tree decl;
tree binfo;
- varray_type v;
+ splay_tree offsets;
{
+ tree offset = NULL_TREE;
+ tree type = TREE_TYPE (decl);
+ /* If we are laying out a base class, rather than a field, then
+ DECL_ARTIFICIAL will be set on the FIELD_DECL. */
+ int field_p = !DECL_ARTIFICIAL (decl);
+
/* Try to place the field. It may take more than one try if we have
a hard time placing the field without putting two objects of the
same type at the same address. */
while (1)
{
- tree offset;
- struct record_layout_info old_rli = *rli;
+ struct record_layout_info_s old_rli = *rli;
/* Place this field. */
place_field (rli, decl);
-
- /* Now that we know where it wil be placed, update its
- BINFO_OFFSET. */
offset = byte_position (decl);
- if (binfo)
- propagate_binfo_offsets (binfo,
- convert (ssizetype, offset));
/* We have to check to see whether or not there is already
something of the same type at the offset we're about to use.
empty class, have non-zero size, any overlap can happen only
with a direct or indirect base-class -- it can't happen with
a data member. */
- if (binfo && flag_new_abi && layout_conflict_p (binfo, v))
+ if (flag_new_abi && layout_conflict_p (TREE_TYPE (decl),
+ offset,
+ offsets,
+ field_p))
{
- /* Undo the propogate_binfo_offsets call. */
- offset = size_diffop (size_zero_node, offset);
- propagate_binfo_offsets (binfo, convert (ssizetype, offset));
-
/* Strip off the size allocated to this field. That puts us
at the first place we could have put the field with
proper alignment. */
*rli = old_rli;
- /* Bump up by the alignment required for the type, without
- virtual base classes. */
+ /* Bump up by the alignment required for the type. */
rli->bitpos
- = size_binop (PLUS_EXPR, rli->bitpos,
- bitsize_int (CLASSTYPE_ALIGN (BINFO_TYPE (binfo))));
+ = size_binop (PLUS_EXPR, rli->bitpos,
+ bitsize_int (binfo
+ ? CLASSTYPE_ALIGN (type)
+ : TYPE_ALIGN (type)));
normalize_rli (rli);
}
else
/* There was no conflict. We're done laying out this field. */
break;
}
+
+ /* Now that we know where it wil be placed, update its
+ BINFO_OFFSET. */
+ if (binfo && CLASS_TYPE_P (BINFO_TYPE (binfo)))
+ propagate_binfo_offsets (binfo,
+ convert (ssizetype, offset));
}
/* Layout the empty base BINFO. EOC indicates the byte currently just
past the end of the class, and should be correctly aligned for a
- class of the type indicated by BINFO; BINFO_OFFSETS gives the
- offsets of the other bases allocated so far. */
+ class of the type indicated by BINFO; OFFSETS gives the offsets of
+ the empty bases allocated so far. */
static void
-layout_empty_base (binfo, eoc, binfo_offsets)
+layout_empty_base (binfo, eoc, offsets)
tree binfo;
tree eoc;
- varray_type binfo_offsets;
+ splay_tree offsets;
{
tree alignment;
tree basetype = BINFO_TYPE (binfo);
/* This routine should only be used for empty classes. */
my_friendly_assert (is_empty_class (basetype), 20000321);
- alignment = ssize_int (CLASSTYPE_ALIGN (basetype));
+ alignment = ssize_int (CLASSTYPE_ALIGN_UNIT (basetype));
/* This is an empty base class. We first try to put it at offset
zero. */
- if (layout_conflict_p (binfo, binfo_offsets))
+ if (layout_conflict_p (BINFO_TYPE (binfo),
+ BINFO_OFFSET (binfo),
+ offsets,
+ /*vbases_p=*/0))
{
/* That didn't work. Now, we move forward from the next
available spot in the class. */
propagate_binfo_offsets (binfo, convert (ssizetype, eoc));
while (1)
{
- if (!layout_conflict_p (binfo, binfo_offsets))
+ if (!layout_conflict_p (BINFO_TYPE (binfo),
+ BINFO_OFFSET (binfo),
+ offsets,
+ /*vbases_p=*/0))
/* We finally found a spot where there's no overlap. */
break;
}
/* Build a FIELD_DECL for the base given by BINFO in the class
- *indicated by RLI. If the new object is non-empty, clear *EMPTY_P.
+ indicated by RLI. If the new object is non-empty, clear *EMPTY_P.
*BASE_ALIGN is a running maximum of the alignments of any base
- *class. */
+ class. OFFSETS gives the location of empty base subobjects. */
static void
-build_base_field (rli, binfo, empty_p, base_align, v)
+build_base_field (rli, binfo, empty_p, base_align, offsets)
record_layout_info rli;
tree binfo;
int *empty_p;
unsigned int *base_align;
- varray_type *v;
+ splay_tree offsets;
{
tree basetype = BINFO_TYPE (binfo);
tree decl;
location information. */
return;
- decl = build_lang_decl (FIELD_DECL, NULL_TREE, basetype);
+ decl = build_decl (FIELD_DECL, NULL_TREE, basetype);
DECL_ARTIFICIAL (decl) = 1;
DECL_FIELD_CONTEXT (decl) = rli->t;
DECL_SIZE (decl) = CLASSTYPE_SIZE (basetype);
DECL_SIZE_UNIT (decl) = CLASSTYPE_SIZE_UNIT (basetype);
DECL_ALIGN (decl) = CLASSTYPE_ALIGN (basetype);
+ DECL_USER_ALIGN (decl) = CLASSTYPE_USER_ALIGN (basetype);
if (! flag_new_abi)
{
/* Try to place the field. It may take more than one try if we
have a hard time placing the field without putting two
objects of the same type at the same address. */
- layout_nonempty_base_or_field (rli, decl, binfo, *v);
+ layout_nonempty_base_or_field (rli, decl, binfo, offsets);
}
else
{
/* On some platforms (ARM), even empty classes will not be
byte-aligned. */
eoc = tree_low_cst (rli_size_unit_so_far (rli), 0);
- eoc = CEIL (eoc, DECL_ALIGN (decl)) * DECL_ALIGN (decl);
- layout_empty_base (binfo, size_int (eoc), *v);
+ eoc = CEIL (eoc, DECL_ALIGN_UNIT (decl)) * DECL_ALIGN_UNIT (decl);
+ layout_empty_base (binfo, size_int (eoc), offsets);
}
/* Check for inaccessible base classes. If the same base class
basetype, rli->t);
/* Record the offsets of BINFO and its base subobjects. */
- record_base_offsets (binfo, v);
+ record_subobject_offsets (BINFO_TYPE (binfo),
+ BINFO_OFFSET (binfo),
+ offsets,
+ /*vbases_p=*/0);
}
-/* Layout all of the non-virtual base classes. Returns a map from
- offsets to types present at those offsets. */
+/* Layout all of the non-virtual base classes. Record empty
+ subobjects in OFFSETS. */
-static varray_type
-build_base_fields (rli, empty_p)
+static void
+build_base_fields (rli, empty_p, offsets)
record_layout_info rli;
int *empty_p;
+ splay_tree offsets;
{
/* Chain to hold all the new FIELD_DECLs which stand in for base class
subobjects. */
tree rec = rli->t;
int n_baseclasses = CLASSTYPE_N_BASECLASSES (rec);
int i;
- varray_type v;
unsigned int base_align = 0;
- /* Create the table mapping offsets to empty base classes. */
- VARRAY_TREE_INIT (v, 32, "v");
-
/* Under the new ABI, the primary base class is always allocated
first. */
if (flag_new_abi && CLASSTYPE_HAS_PRIMARY_BASE_P (rec))
build_base_field (rli, CLASSTYPE_PRIMARY_BINFO (rec),
- empty_p, &base_align, &v);
+ empty_p, &base_align, offsets);
/* Now allocate the rest of the bases. */
for (i = 0; i < n_baseclasses; ++i)
{
tree base_binfo;
+ base_binfo = BINFO_BASETYPE (TYPE_BINFO (rec), i);
+
/* Under the new ABI, the primary base was already allocated
above, so we don't need to allocate it again here. */
- if (flag_new_abi && i == CLASSTYPE_VFIELD_PARENT (rec))
+ if (flag_new_abi && base_binfo == CLASSTYPE_PRIMARY_BINFO (rec))
continue;
- base_binfo = BINFO_BASETYPE (TYPE_BINFO (rec), i);
-
/* A primary virtual base class is allocated just like any other
base class, but a non-primary virtual base is allocated
later, in layout_virtual_bases. */
&& !BINFO_PRIMARY_MARKED_P (base_binfo))
continue;
- build_base_field (rli, base_binfo, empty_p, &base_align, &v);
+ build_base_field (rli, base_binfo, empty_p, &base_align, offsets);
}
-
- return v;
}
/* Go through the TYPE_METHODS of T issuing any appropriate
}
}
+/* FN is a constructor or destructor. Clone the declaration to create
+ a specialized in-charge or not-in-charge version, as indicated by
+ NAME. */
+
+static tree
+build_clone (fn, name)
+ tree fn;
+ tree name;
+{
+ tree parms;
+ tree clone;
+
+ /* Copy the function. */
+ clone = copy_decl (fn);
+ /* Remember where this function came from. */
+ DECL_CLONED_FUNCTION (clone) = fn;
+ /* Reset the function name. */
+ DECL_NAME (clone) = name;
+ DECL_ASSEMBLER_NAME (clone) = DECL_NAME (clone);
+ /* There's no pending inline data for this function. */
+ DECL_PENDING_INLINE_INFO (clone) = NULL;
+ DECL_PENDING_INLINE_P (clone) = 0;
+ /* And it hasn't yet been deferred. */
+ DECL_DEFERRED_FN (clone) = 0;
+ /* There's no magic VTT parameter in the clone. */
+ DECL_VTT_PARM (clone) = NULL_TREE;
+
+ /* The base-class destructor is not virtual. */
+ if (name == base_dtor_identifier)
+ {
+ DECL_VIRTUAL_P (clone) = 0;
+ if (TREE_CODE (clone) != TEMPLATE_DECL)
+ DECL_VINDEX (clone) = NULL_TREE;
+ }
+
+ /* If there was an in-charge parameter, drop it from the function
+ type. */
+ if (DECL_HAS_IN_CHARGE_PARM_P (clone))
+ {
+ tree basetype;
+ tree parmtypes;
+ tree exceptions;
+
+ exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (clone));
+ basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (clone));
+ parmtypes = TYPE_ARG_TYPES (TREE_TYPE (clone));
+ /* Skip the `this' parameter. */
+ parmtypes = TREE_CHAIN (parmtypes);
+ /* Skip the in-charge parameter. */
+ parmtypes = TREE_CHAIN (parmtypes);
+ /* If this is subobject constructor or destructor, add the vtt
+ parameter. */
+ if (DECL_NEEDS_VTT_PARM_P (clone))
+ parmtypes = hash_tree_chain (vtt_parm_type, parmtypes);
+ TREE_TYPE (clone)
+ = build_cplus_method_type (basetype,
+ TREE_TYPE (TREE_TYPE (clone)),
+ parmtypes);
+ if (exceptions)
+ TREE_TYPE (clone) = build_exception_variant (TREE_TYPE (clone),
+ exceptions);
+ }
+
+ /* Copy the function parameters. But, DECL_ARGUMENTS aren't
+ function parameters; instead, those are the template parameters. */
+ if (TREE_CODE (clone) != TEMPLATE_DECL)
+ {
+ DECL_ARGUMENTS (clone) = copy_list (DECL_ARGUMENTS (clone));
+ /* Remove the in-charge parameter. */
+ if (DECL_HAS_IN_CHARGE_PARM_P (clone))
+ {
+ TREE_CHAIN (DECL_ARGUMENTS (clone))
+ = TREE_CHAIN (TREE_CHAIN (DECL_ARGUMENTS (clone)));
+ DECL_HAS_IN_CHARGE_PARM_P (clone) = 0;
+ }
+
+ /* Add the VTT parameter. */
+ if (DECL_NEEDS_VTT_PARM_P (clone))
+ {
+ tree parm;
+
+ parm = build_artificial_parm (vtt_parm_identifier,
+ vtt_parm_type);
+ TREE_CHAIN (parm) = TREE_CHAIN (DECL_ARGUMENTS (clone));
+ TREE_CHAIN (DECL_ARGUMENTS (clone)) = parm;
+ }
+
+ for (parms = DECL_ARGUMENTS (clone); parms; parms = TREE_CHAIN (parms))
+ {
+ DECL_CONTEXT (parms) = clone;
+ copy_lang_decl (parms);
+ }
+ }
+
+ /* Mangle the function name. */
+ set_mangled_name_for_decl (clone);
+
+ /* Create the RTL for this function. */
+ DECL_RTL (clone) = NULL_RTX;
+ rest_of_decl_compilation (clone, NULL, /*top_level=*/1, at_eof);
+
+ /* Make it easy to find the CLONE given the FN. */
+ TREE_CHAIN (clone) = TREE_CHAIN (fn);
+ TREE_CHAIN (fn) = clone;
+
+ /* If this is a template, handle the DECL_TEMPLATE_RESULT as well. */
+ if (TREE_CODE (clone) == TEMPLATE_DECL)
+ {
+ tree result;
+
+ DECL_TEMPLATE_RESULT (clone)
+ = build_clone (DECL_TEMPLATE_RESULT (clone), name);
+ result = DECL_TEMPLATE_RESULT (clone);
+ DECL_TEMPLATE_INFO (result) = copy_node (DECL_TEMPLATE_INFO (result));
+ DECL_TI_TEMPLATE (result) = clone;
+ }
+ else if (DECL_DEFERRED_FN (fn))
+ defer_fn (clone);
+
+ return clone;
+}
+
+/* Produce declarations for all appropriate clones of FN. If
+ UPDATE_METHOD_VEC_P is non-zero, the clones are added to the
+ CLASTYPE_METHOD_VEC as well. */
+
+void
+clone_function_decl (fn, update_method_vec_p)
+ tree fn;
+ int update_method_vec_p;
+{
+ tree clone;
+
+ /* Avoid inappropriate cloning. */
+ if (! flag_new_abi
+ || (TREE_CHAIN (fn)
+ && DECL_CLONED_FUNCTION (TREE_CHAIN (fn))))
+ return;
+
+ if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn))
+ {
+ /* For each constructor, we need two variants: an in-charge version
+ and a not-in-charge version. */
+ clone = build_clone (fn, complete_ctor_identifier);
+ if (update_method_vec_p)
+ add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
+ clone = build_clone (fn, base_ctor_identifier);
+ if (update_method_vec_p)
+ add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
+ }
+ else
+ {
+ my_friendly_assert (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn), 20000411);
+
+ /* For each destructor, we need three variants: an in-charge
+ version, a not-in-charge version, and an in-charge deleting
+ version. We clone the deleting version first because that
+ means it will go second on the TYPE_METHODS list -- and that
+ corresponds to the correct layout order in the virtual
+ function table. */
+ clone = build_clone (fn, deleting_dtor_identifier);
+ if (update_method_vec_p)
+ add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
+ clone = build_clone (fn, complete_dtor_identifier);
+ if (update_method_vec_p)
+ add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
+ clone = build_clone (fn, base_dtor_identifier);
+ if (update_method_vec_p)
+ add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
+ }
+}
+
+/* For each of the constructors and destructors in T, create an
+ in-charge and not-in-charge variant. */
+
+static void
+clone_constructors_and_destructors (t)
+ tree t;
+{
+ tree fns;
+
+ /* We only clone constructors and destructors under the new ABI. */
+ if (!flag_new_abi)
+ return;
+
+ /* If for some reason we don't have a CLASSTYPE_METHOD_VEC, we bail
+ out now. */
+ if (!CLASSTYPE_METHOD_VEC (t))
+ return;
+
+ for (fns = CLASSTYPE_CONSTRUCTORS (t); fns; fns = OVL_NEXT (fns))
+ clone_function_decl (OVL_CURRENT (fns), /*update_method_vec_p=*/1);
+ for (fns = CLASSTYPE_DESTRUCTORS (t); fns; fns = OVL_NEXT (fns))
+ clone_function_decl (OVL_CURRENT (fns), /*update_method_vec_p=*/1);
+}
+
/* Remove all zero-width bit-fields from T. */
static void
cant_have_const_ctor,
no_const_asn_ref);
+ /* Create the in-charge and not-in-charge variants of constructors
+ and destructors. */
+ clone_constructors_and_destructors (t);
+
/* Process the using-declarations. */
for (; access_decls; access_decls = TREE_CHAIN (access_decls))
handle_using_decl (TREE_VALUE (access_decls), t);
/* Loop over the virtual functions, adding them to our various
vtables. */
for (fn = TYPE_METHODS (t); fn; fn = TREE_CHAIN (fn))
- if (DECL_VINDEX (fn))
+ if (DECL_VINDEX (fn)
+ && !(flag_new_abi && DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn)))
add_virtual_function (new_virtuals_p, overridden_virtuals_p,
vfuns_p, fn, t);
complete. */
static void
-fixup_pending_inline (info)
- struct pending_inline *info;
+fixup_pending_inline (fn)
+ tree fn;
{
- if (info)
+ if (DECL_PENDING_INLINE_INFO (fn))
{
- tree args;
- tree fn = info->fndecl;
-
- args = DECL_ARGUMENTS (fn);
+ tree args = DECL_ARGUMENTS (fn);
while (args)
{
DECL_CONTEXT (args) = fn;
/* Do inline member functions. */
for (; method; method = TREE_CHAIN (method))
- fixup_pending_inline (DECL_PENDING_INLINE_INFO (method));
+ fixup_pending_inline (method);
/* Do friends. */
for (method = CLASSTYPE_INLINE_FRIENDS (type);
method;
method = TREE_CHAIN (method))
- fixup_pending_inline (DECL_PENDING_INLINE_INFO (TREE_VALUE (method)));
+ fixup_pending_inline (TREE_VALUE (method));
CLASSTYPE_INLINE_FRIENDS (type) = NULL_TREE;
}
-/* Called from propagate_binfo_offsets via dfs_walk. */
-
-static tree
-dfs_propagate_binfo_offsets (binfo, data)
- tree binfo;
- void *data;
-{
- tree offset = (tree) data;
-
- /* Update the BINFO_OFFSET for this base. Allow for the case where it
- might be negative. */
- BINFO_OFFSET (binfo)
- = convert (sizetype, size_binop (PLUS_EXPR,
- convert (ssizetype, BINFO_OFFSET (binfo)),
- offset));
- SET_BINFO_MARKED (binfo);
-
- return NULL_TREE;
-}
-
/* Add OFFSET to all base types of BINFO which is a base in the
hierarchy dominated by T.
- OFFSET, which is a type offset, is number of bytes.
-
- Note that we don't have to worry about having two paths to the
- same base type, since this type owns its association list. */
+ OFFSET, which is a type offset, is number of bytes. */
static void
propagate_binfo_offsets (binfo, offset)
tree binfo;
tree offset;
{
- dfs_walk (binfo,
- dfs_propagate_binfo_offsets,
- dfs_skip_nonprimary_vbases_unmarkedp,
- offset);
- dfs_walk (binfo,
- dfs_unmark,
- dfs_skip_nonprimary_vbases_markedp,
- NULL);
-}
+ int i;
+ tree primary_binfo;
-/* Called via dfs_walk from layout_virtual bases. */
+ /* Update BINFO's offset. */
+ BINFO_OFFSET (binfo)
+ = convert (sizetype,
+ size_binop (PLUS_EXPR,
+ convert (ssizetype, BINFO_OFFSET (binfo)),
+ offset));
-static tree
-dfs_set_offset_for_shared_vbases (binfo, data)
- tree binfo;
- void *data;
-{
- if (TREE_VIA_VIRTUAL (binfo) && BINFO_PRIMARY_MARKED_P (binfo))
+ /* Find the primary base class. */
+ primary_binfo = get_primary_binfo (binfo);
+
+ /* Scan all of the bases, pushing the BINFO_OFFSET adjust
+ downwards. */
+ for (i = -1; i < BINFO_N_BASETYPES (binfo); ++i)
{
- /* Update the shared copy. */
- tree shared_binfo;
+ tree base_binfo;
- shared_binfo = BINFO_FOR_VBASE (BINFO_TYPE (binfo), (tree) data);
- BINFO_OFFSET (shared_binfo) = BINFO_OFFSET (binfo);
- }
+ /* On the first through the loop, do the primary base. Because
+ the primary base need not be an immediate base, we must
+ handle the primary base specially. */
+ if (i == -1)
+ {
+ if (!primary_binfo)
+ continue;
- return NULL_TREE;
+ base_binfo = primary_binfo;
+ }
+ else
+ {
+ base_binfo = BINFO_BASETYPE (binfo, i);
+ /* Don't do the primary base twice. */
+ if (base_binfo == primary_binfo)
+ continue;
+ }
+
+ /* Skip virtual bases that aren't our primary base. */
+ if (TREE_VIA_VIRTUAL (base_binfo)
+ && BINFO_PRIMARY_BASE_OF (base_binfo) != binfo)
+ continue;
+
+ propagate_binfo_offsets (base_binfo, offset);
+ }
}
/* Called via dfs_walk from layout_virtual bases. */
tree vbase;
tree offset;
- vbase = BINFO_FOR_VBASE (BINFO_TYPE (binfo), t);
+ vbase = binfo_for_vbase (BINFO_TYPE (binfo), t);
offset = size_diffop (BINFO_OFFSET (vbase), BINFO_OFFSET (binfo));
propagate_binfo_offsets (binfo, offset);
}
}
/* Set BINFO_OFFSET for all of the virtual bases for T. Update
- TYPE_ALIGN and TYPE_SIZE for T. BASE_OFFSETS is a varray mapping
- offsets to the types at those offsets. */
+ TYPE_ALIGN and TYPE_SIZE for T. OFFSETS gives the location of
+ empty subobjects of T. */
static void
-layout_virtual_bases (t, base_offsets)
+layout_virtual_bases (t, offsets)
tree t;
- varray_type *base_offsets;
+ splay_tree offsets;
{
tree vbases;
unsigned HOST_WIDE_INT dsize;
{
tree vbase;
- if (!TREE_VIA_VIRTUAL (vbases))
- continue;
-
if (flag_new_abi)
- vbase = BINFO_FOR_VBASE (BINFO_TYPE (vbases), t);
+ {
+ if (!TREE_VIA_VIRTUAL (vbases))
+ continue;
+ vbase = binfo_for_vbase (BINFO_TYPE (vbases), t);
+ }
else
- vbase = vbases;
+ vbase = TREE_VALUE (vbases);
- if (!BINFO_VBASE_PRIMARY_P (vbase))
+ if (!BINFO_PRIMARY_MARKED_P (vbase))
{
/* This virtual base is not a primary base of any class in the
hierarchy, so we have to add space for it. */
if (flag_new_abi && is_empty_class (basetype))
layout_empty_base (vbase,
size_int (CEIL (dsize, BITS_PER_UNIT)),
- *base_offsets);
+ offsets);
else
{
+ tree offset;
+
+ offset = ssize_int (CEIL (dsize, BITS_PER_UNIT));
+ offset = size_diffop (offset,
+ convert (ssizetype,
+ BINFO_OFFSET (vbase)));
+
/* And compute the offset of the virtual base. */
- propagate_binfo_offsets (vbase,
- ssize_int (CEIL (dsize, BITS_PER_UNIT)));
+ propagate_binfo_offsets (vbase, offset);
/* Every virtual baseclass takes a least a UNIT, so that
we can take it's address and get something different
for each base. */
}
/* Keep track of the offsets assigned to this virtual base. */
- record_base_offsets (vbase, base_offsets);
+ record_subobject_offsets (BINFO_TYPE (vbase),
+ BINFO_OFFSET (vbase),
+ offsets,
+ /*vbases_p=*/0);
}
}
- /* Make sure that all of the CLASSTYPE_VBASECLASSES have their
- BINFO_OFFSET set correctly. Those we just allocated certainly
- will. The others are primary baseclasses; we walk the hierarchy
- to find the primary copies and update the shared copy. */
- dfs_walk (TYPE_BINFO (t),
- dfs_set_offset_for_shared_vbases,
- dfs_unmarked_real_bases_queue_p,
- t);
-
- /* Now, go through the TYPE_BINFO hierarchy again, setting the
+ /* Now, go through the TYPE_BINFO hierarchy, setting the
BINFO_OFFSETs correctly for all non-primary copies of the virtual
bases and their direct and indirect bases. The ambiguity checks
in get_base_distance depend on the BINFO_OFFSETs being set
correctly. */
dfs_walk (TYPE_BINFO (t), dfs_set_offset_for_unshared_vbases, NULL, t);
- for (vbases = CLASSTYPE_VBASECLASSES (t);
- vbases;
- vbases = TREE_CHAIN (vbases))
- dfs_walk (vbases, dfs_set_offset_for_unshared_vbases, NULL, t);
/* If we had empty base classes that protruded beyond the end of the
class, we didn't update DSIZE above; we were hoping to overlay
vbases;
vbases = TREE_CHAIN (vbases))
{
- tree basetype = BINFO_TYPE (vbases);
+ tree basetype = BINFO_TYPE (TREE_VALUE (vbases));
if (get_base_distance (basetype, t, 0, (tree*)0) == -2)
cp_warning ("virtual base `%T' inaccessible in `%T' due to ambiguity",
basetype, t);
return result;
}
+/* Compare two INTEGER_CSTs K1 and K2. */
+
+static int
+splay_tree_compare_integer_csts (k1, k2)
+ splay_tree_key k1;
+ splay_tree_key k2;
+{
+ return tree_int_cst_compare ((tree) k1, (tree) k2);
+}
+
/* Calculate the TYPE_SIZE, TYPE_ALIGN, etc for T. Calculate
BINFO_OFFSETs for all of the base-classes. Position the vtable
pointer. */
tree field;
tree vptr;
record_layout_info rli;
- varray_type v;
unsigned HOST_WIDE_INT eoc;
+ /* Maps offsets (represented as INTEGER_CSTs) to a TREE_LIST of
+ types that appear at that offset. */
+ splay_tree empty_base_offsets;
/* Keep track of the first non-static data member. */
non_static_data_members = TYPE_FIELDS (t);
place_field (rli, vptr);
}
+ /* Build FIELD_DECLs for all of the non-virtual base-types. */
+ empty_base_offsets = splay_tree_new (splay_tree_compare_integer_csts,
+ NULL, NULL);
+ build_base_fields (rli, empty_p, empty_base_offsets);
/* Add pointers to all of our virtual base-classes. */
TYPE_FIELDS (t) = chainon (build_vbase_pointer_fields (rli, empty_p),
TYPE_FIELDS (t));
- /* Build FIELD_DECLs for all of the non-virtual base-types. */
- v = build_base_fields (rli, empty_p);
/* CLASSTYPE_INLINE_FRIENDS is really TYPE_NONCOPIED_PARTS. Thus,
we have to save this before we start modifying
/* Layout the non-static data members. */
for (field = non_static_data_members; field; field = TREE_CHAIN (field))
{
- tree binfo;
tree type;
tree padding;
TYPE_SIZE (integer_type));
DECL_SIZE (field) = TYPE_SIZE (integer_type);
DECL_ALIGN (field) = TYPE_ALIGN (integer_type);
+ DECL_USER_ALIGN (field) = TYPE_USER_ALIGN (integer_type);
}
else
padding = NULL_TREE;
- /* Create a dummy BINFO corresponding to this field. */
- binfo = make_binfo (size_zero_node, type, NULL_TREE, NULL_TREE);
- unshare_base_binfos (binfo);
- layout_nonempty_base_or_field (rli, field, binfo, v);
+ layout_nonempty_base_or_field (rli, field, NULL_TREE,
+ empty_base_offsets);
/* If we needed additional padding after this field, add it
now. */
DECL_BIT_FIELD (padding_field) = 1;
DECL_SIZE (padding_field) = padding;
DECL_ALIGN (padding_field) = 1;
- layout_nonempty_base_or_field (rli, padding_field, NULL_TREE, v);
+ DECL_USER_ALIGN (padding_field) = 0;
+ layout_nonempty_base_or_field (rli, padding_field,
+ NULL_TREE,
+ empty_base_offsets);
}
}
{
tree padding;
- padding = build_lang_decl (FIELD_DECL, NULL_TREE, char_type_node);
+ padding = build_decl (FIELD_DECL, NULL_TREE, char_type_node);
place_field (rli, padding);
TYPE_NONCOPIED_PARTS (t)
= tree_cons (NULL_TREE, padding, TYPE_NONCOPIED_PARTS (t));
CLASSTYPE_SIZE (t) = bitsize_zero_node;
CLASSTYPE_SIZE_UNIT (t) = size_zero_node;
}
- else if (flag_new_abi && TYPE_HAS_COMPLEX_INIT_REF (t)
- && TYPE_HAS_COMPLEX_ASSIGN_REF (t))
+ else if (flag_new_abi)
{
CLASSTYPE_SIZE (t) = TYPE_BINFO_SIZE (t);
CLASSTYPE_SIZE_UNIT (t) = TYPE_BINFO_SIZE_UNIT (t);
}
CLASSTYPE_ALIGN (t) = TYPE_ALIGN (t);
+ CLASSTYPE_USER_ALIGN (t) = TYPE_USER_ALIGN (t);
/* Set the TYPE_DECL for this type to contain the right
value for DECL_OFFSET, so that we can use it as part
around. We must get these done before we try to lay out the
virtual function table. As a side-effect, this will remove the
base subobject fields. */
- layout_virtual_bases (t, &v);
+ layout_virtual_bases (t, empty_base_offsets);
/* Clean up. */
- VARRAY_FREE (v);
+ splay_tree_delete (empty_base_offsets);
}
/* Create a RECORD_TYPE or UNION_TYPE node for a C struct or union declaration
make sure we lay it out again. */
TYPE_SIZE (t) = NULL_TREE;
CLASSTYPE_GOT_SEMICOLON (t) = 0;
- CLASSTYPE_VFIELD_PARENT (t) = -1;
+ CLASSTYPE_PRIMARY_BINFO (t) = NULL_TREE;
vfuns = 0;
CLASSTYPE_RTTI (t) = NULL_TREE;
overridden_virtuals
= modify_all_vtables (t, &vfuns, nreverse (overridden_virtuals));
+ /* If we created a new vtbl pointer for this class, add it to the
+ list. */
+ if (TYPE_VFIELD (t) && !CLASSTYPE_HAS_PRIMARY_BASE_P (t))
+ CLASSTYPE_VFIELDS (t)
+ = chainon (CLASSTYPE_VFIELDS (t), build_tree_list (NULL_TREE, t));
+
/* If necessary, create the primary vtable for this class. */
if (new_virtuals
|| overridden_virtuals
{
tree binfo = CLASSTYPE_PRIMARY_BINFO (t);
- /* This class contributes nothing new to the virtual function
- table. However, it may have declared functions which
- went into the virtual function table "inherited" from the
- base class. If so, we grab a copy of those updated functions,
- and pretend they are ours. */
-
- /* See if we should steal the virtual info from base class. */
- if (TYPE_BINFO_VTABLE (t) == NULL_TREE)
- TYPE_BINFO_VTABLE (t) = BINFO_VTABLE (binfo);
- if (TYPE_BINFO_VIRTUALS (t) == NULL_TREE)
- TYPE_BINFO_VIRTUALS (t) = BINFO_VIRTUALS (binfo);
+ /* If this class uses a different vtable than its primary base
+ then when we will need to initialize our vptr after the base
+ class constructor runs. */
if (TYPE_BINFO_VTABLE (t) != BINFO_VTABLE (binfo))
CLASSTYPE_NEEDS_VIRTUAL_REINIT (t) = 1;
}
= chainon (TYPE_BINFO_VIRTUALS (t), overridden_virtuals);
}
- /* If we created a new vtbl pointer for this class, add it to the
- list. */
- if (TYPE_VFIELD (t) && !CLASSTYPE_HAS_PRIMARY_BASE_P (t))
- CLASSTYPE_VFIELDS (t)
- = chainon (CLASSTYPE_VFIELDS (t), build_tree_list (NULL_TREE, t));
-
finish_struct_bits (t);
/* Complete the rtl for any static member objects of the type we're
/* Make the rtl for any new vtables we have created, and unmark
the base types we marked. */
finish_vtbls (t);
+ /* Build the VTT for T. */
+ build_vtt (t);
if (TYPE_VFIELD (t))
{
maybe_suppress_debug_info (t);
/* Finish debugging output for this type. */
- rest_of_type_compilation (t, toplevel_bindings_p ());
+ rest_of_type_compilation (t, ! LOCAL_CLASS_P (t));
}
/* When T was built up, the member declarations were added in reverse
{
tree scope = current_scope ();
if (scope && TREE_CODE (scope) == FUNCTION_DECL)
- add_tree (build_min (TAG_DEFN, t));
+ add_stmt (build_min (TAG_DEFN, t));
}
return t;
return 0;
if (POINTER_TYPE_P (t))
t = TREE_TYPE (t);
- return same_type_p (TYPE_MAIN_VARIANT (t), TYPE_MAIN_VARIANT (fixed));
+ return same_type_ignoring_top_level_qualifiers_p (t, fixed);
}
\f
current_class_stack
= (class_stack_node_t) xmalloc (current_class_stack_size
* sizeof (struct class_stack_node));
+ VARRAY_TREE_INIT (local_classes, 8, "local_classes");
+ ggc_add_tree_varray_root (&local_classes, 1);
access_default_node = build_int_2 (0, 0);
access_public_node = build_int_2 (ak_public, 0);
access_public_virtual_node = build_int_2 (4 | ak_public, 0);
access_protected_virtual_node = build_int_2 (4 | ak_protected, 0);
access_private_virtual_node = build_int_2 (4 | ak_private, 0);
+
+ ridpointers[(int) RID_PUBLIC] = access_public_node;
+ ridpointers[(int) RID_PRIVATE] = access_private_node;
+ ridpointers[(int) RID_PROTECTED] = access_protected_node;
}
/* Set current scope to NAME. CODE tells us if this is a
pushlevel_class ();
-#if 0
- if (CLASSTYPE_TEMPLATE_INFO (type))
- overload_template_name (type);
-#endif
-
if (modify)
{
if (type != previous_class_type || current_class_depth > 1)
|| TREE_CODE (type) == NAMESPACE_DECL
|| ! IS_AGGR_TYPE (type)
|| TREE_CODE (type) == TEMPLATE_TYPE_PARM
- || TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM)
+ || TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM)
return;
context = DECL_CONTEXT (TYPE_MAIN_DECL (type));
if (name == lang_name_cplusplus)
{
- strict_prototype = strict_prototypes_lang_cplusplus;
current_lang_name = name;
}
else if (name == lang_name_java)
{
- strict_prototype = strict_prototypes_lang_cplusplus;
current_lang_name = name;
/* DECL_IGNORED_P is initially set for these types, to avoid clutter.
(See record_builtin_java_type in decl.c.) However, that causes
incorrect debug entries if these types are actually used.
So we re-enable debug output after extern "Java". */
- DECL_IGNORED_P (java_byte_type_node) = 0;
- DECL_IGNORED_P (java_short_type_node) = 0;
- DECL_IGNORED_P (java_int_type_node) = 0;
- DECL_IGNORED_P (java_long_type_node) = 0;
- DECL_IGNORED_P (java_float_type_node) = 0;
- DECL_IGNORED_P (java_double_type_node) = 0;
- DECL_IGNORED_P (java_char_type_node) = 0;
- DECL_IGNORED_P (java_boolean_type_node) = 0;
+ DECL_IGNORED_P (TYPE_NAME (java_byte_type_node)) = 0;
+ DECL_IGNORED_P (TYPE_NAME (java_short_type_node)) = 0;
+ DECL_IGNORED_P (TYPE_NAME (java_int_type_node)) = 0;
+ DECL_IGNORED_P (TYPE_NAME (java_long_type_node)) = 0;
+ DECL_IGNORED_P (TYPE_NAME (java_float_type_node)) = 0;
+ DECL_IGNORED_P (TYPE_NAME (java_double_type_node)) = 0;
+ DECL_IGNORED_P (TYPE_NAME (java_char_type_node)) = 0;
+ DECL_IGNORED_P (TYPE_NAME (java_boolean_type_node)) = 0;
}
else if (name == lang_name_c)
{
- strict_prototype = strict_prototypes_lang_c;
current_lang_name = name;
}
else
to it. */
*current_lang_stack = NULL_TREE;
current_lang_name = *--current_lang_stack;
- if (current_lang_name == lang_name_cplusplus
- || current_lang_name == lang_name_java)
- strict_prototype = strict_prototypes_lang_cplusplus;
- else if (current_lang_name == lang_name_c)
- strict_prototype = strict_prototypes_lang_c;
}
\f
/* Type instantiation routines. */
/* Given an OVERLOAD and a TARGET_TYPE, return the function that
matches the TARGET_TYPE. If there is no satisfactory match, return
error_mark_node, and issue an error message if COMPLAIN is
- non-zero. If TEMPLATE_ONLY, the name of the overloaded function
+ non-zero. Permit pointers to member function if PTRMEM is non-zero.
+ If TEMPLATE_ONLY, the name of the overloaded function
was a template-id, and EXPLICIT_TARGS are the explicitly provided
template arguments. */
static tree
resolve_address_of_overloaded_function (target_type,
overload,
- complain,
+ complain,
+ ptrmem,
template_only,
explicit_targs)
tree target_type;
tree overload;
int complain;
+ int ptrmem;
int template_only;
tree explicit_targs;
{
target_fn_type = TREE_TYPE (target_type);
target_arg_types = TYPE_ARG_TYPES (target_fn_type);
target_ret_type = TREE_TYPE (target_fn_type);
+
+ /* Never do unification on the 'this' parameter. */
+ if (TREE_CODE (target_fn_type) == METHOD_TYPE)
+ target_arg_types = TREE_CHAIN (target_arg_types);
for (fns = overload; fns; fns = OVL_CHAIN (fns))
{
targs = make_tree_vec (DECL_NTPARMS (fn));
if (fn_type_unification (fn, explicit_targs, targs,
target_arg_types, target_ret_type,
- DEDUCE_EXACT) != 0)
+ DEDUCE_EXACT, -1) != 0)
/* Argument deduction failed. */
continue;
/* Now, remove all but the most specialized of the matches. */
if (matches)
{
- tree match = most_specialized_instantiation (matches,
- explicit_targs);
+ tree match = most_specialized_instantiation (matches);
if (match != error_mark_node)
matches = tree_cons (match, NULL_TREE, NULL_TREE);
/* Good, exactly one match. Now, convert it to the correct type. */
fn = TREE_PURPOSE (matches);
+ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)
+ && !ptrmem && !flag_ms_extensions)
+ {
+ static int explained;
+
+ if (!complain)
+ return error_mark_node;
+
+ cp_pedwarn ("assuming pointer to member `%D'", fn);
+ if (!explained)
+ {
+ cp_pedwarn ("(a pointer to member can only be formed with `&%E')", fn);
+ explained = 1;
+ }
+ }
mark_used (fn);
if (TYPE_PTRFN_P (target_type) || TYPE_PTRMEMFUNC_P (target_type))
/* This function will instantiate the type of the expression given in
RHS to match the type of LHSTYPE. If errors exist, then return
- error_mark_node. We only complain is COMPLAIN is set. If we are
- not complaining, never modify rhs, as overload resolution wants to
- try many possible instantiations, in hopes that at least one will
- work.
-
- FLAGS is a bitmask, as we see at the top of the function.
-
+ error_mark_node. FLAGS is a bit mask. If ITF_COMPLAIN is set, then
+ we complain on errors. If we are not complaining, never modify rhs,
+ as overload resolution wants to try many possible instantiations, in
+ the hope that at least one will work.
+
For non-recursive calls, LHSTYPE should be a function, pointer to
function, or a pointer to member function. */
tree
instantiate_type (lhstype, rhs, flags)
tree lhstype, rhs;
- int flags;
+ enum instantiate_type_flags flags;
{
- int complain = (flags & 1);
- int strict = (flags & 2) ? COMPARE_NO_ATTRIBUTES : COMPARE_STRICT;
- tree r;
-
+ int complain = (flags & itf_complain);
+ int strict = (flags & itf_no_attributes)
+ ? COMPARE_NO_ATTRIBUTES : COMPARE_STRICT;
+ int allow_ptrmem = flags & itf_ptrmem_ok;
+
+ flags &= ~itf_ptrmem_ok;
+
if (TREE_CODE (lhstype) == UNKNOWN_TYPE)
{
if (complain)
return instantiate_type (lhstype, rhs, flags);
case COMPONENT_REF:
- {
- r = instantiate_type (lhstype, TREE_OPERAND (rhs, 1), flags);
-
- comp:
- if (r != error_mark_node && TYPE_PTRMEMFUNC_P (lhstype)
- && complain && !flag_ms_extensions)
- {
- /* Note: we check this after the recursive call to avoid
- complaining about cases where overload resolution fails. */
-
- tree t = TREE_TYPE (TREE_OPERAND (rhs, 0));
- tree fn = PTRMEM_CST_MEMBER (r);
-
- my_friendly_assert (TREE_CODE (r) == PTRMEM_CST, 990811);
-
- cp_pedwarn
- ("object-dependent reference to `%E' can only be used in a call",
- DECL_NAME (fn));
- cp_pedwarn
- (" to form a pointer to member function, say `&%T::%E'",
- t, DECL_NAME (fn));
- }
-
- return r;
- }
+ return instantiate_type (lhstype, TREE_OPERAND (rhs, 1), flags);
case OFFSET_REF:
rhs = TREE_OPERAND (rhs, 1);
if (BASELINK_P (rhs))
- return instantiate_type (lhstype, TREE_VALUE (rhs), flags);
+ return instantiate_type (lhstype, TREE_VALUE (rhs),
+ flags | allow_ptrmem);
/* This can happen if we are forming a pointer-to-member for a
member template. */
tree fns = TREE_OPERAND (rhs, 0);
tree args = TREE_OPERAND (rhs, 1);
- r =
+ return
resolve_address_of_overloaded_function (lhstype,
fns,
complain,
+ allow_ptrmem,
/*template_only=*/1,
args);
- if (TREE_CODE (fns) == COMPONENT_REF)
- {
- rhs = fns;
- goto comp;
- }
- return r;
}
case OVERLOAD:
resolve_address_of_overloaded_function (lhstype,
rhs,
complain,
+ allow_ptrmem,
/*template_only=*/0,
/*explicit_targs=*/NULL_TREE);
return rhs;
case ADDR_EXPR:
+ {
+ if (PTRMEM_OK_P (rhs))
+ flags |= itf_ptrmem_ok;
+
return instantiate_type (lhstype, TREE_OPERAND (rhs, 0), flags);
-
+ }
case ENTRY_VALUE_EXPR:
my_friendly_abort (184);
return error_mark_node;
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))),
+ cp_error_at ("changes meaning of `%D' from `%+#D'",
+ DECL_NAME (OVL_CURRENT (decl)),
(tree) n->value);
}
}
return decl;
}
+/* Called from get_primary_binfo via dfs_walk. */
+
+static tree
+dfs_get_primary_binfo (binfo, data)
+ tree binfo;
+ void *data;
+{
+ tree primary_base = (tree) data;
+
+ if (TREE_VIA_VIRTUAL (binfo)
+ && same_type_p (TREE_TYPE (binfo), TREE_TYPE (primary_base)))
+ return binfo;
+
+ return NULL_TREE;
+}
+
+/* Returns the binfo for the primary base of BINFO. Note that in a
+ complex hierarchy the resulting BINFO may not actually *be*
+ primary. In particular if the resulting BINFO is a virtual base,
+ and it occurs elsewhere in the hierarchy, then this occurrence may
+ not actually be a primary base in the complete object. Check
+ BINFO_PRIMARY_MARKED_P to be sure. */
+
+tree
+get_primary_binfo (binfo)
+ tree binfo;
+{
+ tree primary_base;
+ tree result;
+
+ primary_base = CLASSTYPE_PRIMARY_BINFO (BINFO_TYPE (binfo));
+ if (!primary_base)
+ return NULL_TREE;
+
+ /* A non-virtual primary base is always a direct base, and easy to
+ find. */
+ if (!TREE_VIA_VIRTUAL (primary_base))
+ {
+ int i;
+
+ /* Scan the direct basetypes until we find a base with the same
+ type as the primary base. */
+ for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
+ {
+ tree base_binfo = BINFO_BASETYPE (binfo, i);
+
+ if (same_type_p (BINFO_TYPE (base_binfo),
+ BINFO_TYPE (primary_base)))
+ return base_binfo;
+ }
+
+ /* We should always find the primary base. */
+ my_friendly_abort (20000729);
+ }
+
+ /* For a primary virtual base, we have to scan the entire hierarchy
+ rooted at BINFO; the virtual base could be an indirect virtual
+ base. */
+ result = dfs_walk (binfo, dfs_get_primary_binfo, NULL, primary_base);
+ my_friendly_assert (result != NULL_TREE, 20000730);
+ return result;
+}
+
/* Dump the offsets of all the bases rooted at BINFO (in the hierarchy
dominated by T) to stderr. INDENT should be zero when called from
the top level; it is incremented recursively. */
fprintf (stderr, "%*s0x%lx (%s) ", indent, "",
(unsigned long) binfo,
- type_as_string (binfo, TS_PLAIN));
+ type_as_string (binfo, TFF_PLAIN_IDENTIFIER));
fprintf (stderr, HOST_WIDE_INT_PRINT_DEC,
tree_low_cst (BINFO_OFFSET (binfo), 0));
if (TREE_VIA_VIRTUAL (binfo))
fprintf (stderr, " virtual");
if (BINFO_PRIMARY_MARKED_P (binfo)
|| (TREE_VIA_VIRTUAL (binfo)
- && BINFO_VBASE_PRIMARY_P (BINFO_FOR_VBASE (BINFO_TYPE (binfo),
- t))))
+ && BINFO_PRIMARY_MARKED_P (binfo_for_vbase (BINFO_TYPE (binfo),
+ t))))
fprintf (stderr, " primary");
fprintf (stderr, "\n");
dump_class_hierarchy (t)
tree t;
{
- tree vbase;
-
dump_class_hierarchy_r (t, TYPE_BINFO (t), 0);
- fprintf (stderr, "virtual bases\n");
- for (vbase = CLASSTYPE_VBASECLASSES (t); vbase; vbase = TREE_CHAIN (vbase))
- dump_class_hierarchy_r (t, vbase, 0);
}
/* Virtual function table initialization. */
first, followed by the non-virtual secondary vtables in
inheritance graph order. */
list = build_tree_list (TYPE_BINFO_VTABLE (t), NULL_TREE);
- TREE_TYPE (list) = t;
- accumulate_vtbl_inits (TYPE_BINFO (t), list);
+ accumulate_vtbl_inits (TYPE_BINFO (t), TYPE_BINFO (t),
+ TYPE_BINFO (t), t, list);
/* Then come the virtual bases, also in inheritance graph
order. */
for (vbase = TYPE_BINFO (t); vbase; vbase = TREE_CHAIN (vbase))
{
if (!TREE_VIA_VIRTUAL (vbase))
continue;
- accumulate_vtbl_inits (BINFO_FOR_VBASE (BINFO_TYPE (vbase), t),
- list);
+
+ accumulate_vtbl_inits (vbase, vbase, TYPE_BINFO (t), t, list);
}
if (TYPE_BINFO_VTABLE (t))
{
tree t = (tree) data;
- if (!BINFO_PRIMARY_MARKED_P (binfo)
- && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))
- && BINFO_NEW_VTABLE_MARKED (binfo, t))
+ if (BINFO_NEW_VTABLE_MARKED (binfo, t))
initialize_vtable (binfo,
- build_vtbl_initializer (binfo, t, NULL));
+ build_vtbl_initializer (binfo, binfo, t,
+ TYPE_BINFO (t), NULL));
- CLEAR_BINFO_NEW_VTABLE_MARKED (binfo, t);
SET_BINFO_MARKED (binfo);
return NULL_TREE;
tree binfo;
tree inits;
{
- tree context;
tree decl;
layout_vtable_decl (binfo, list_length (inits));
decl = get_vtbl_decl_for_binfo (binfo);
+ initialize_array (decl, inits);
+}
+
+/* Initialize DECL (a declaration for a namespace-scope array) with
+ the INITS. */
+
+static void
+initialize_array (decl, inits)
+ tree decl;
+ tree inits;
+{
+ tree context;
+
context = DECL_CONTEXT (decl);
- DECL_CONTEXT (decl) = 0;
+ DECL_CONTEXT (decl) = NULL_TREE;
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. */
+/* Build the VTT (virtual table table) for T. */
static void
-accumulate_vtbl_inits (binfo, inits)
- tree binfo;
- tree inits;
+build_vtt (t)
+ tree t;
{
- /* Walk the BINFO and its bases. We walk in preorder so that as we
- initialize each vtable we can figure out at what offset the
- secondary vtable lies from the primary vtable. */
+ tree inits;
+ tree type;
+ tree vtt;
+ tree index;
+
+ /* Under the old ABI, we don't use VTTs. */
+ if (!flag_new_abi)
+ return;
+
+ /* Build up the initializers for the VTT. */
+ inits = NULL_TREE;
+ index = size_zero_node;
+ build_vtt_inits (TYPE_BINFO (t), t, /*virtual_vtts_p=*/1,
+ &inits, &index);
+
+ /* If we didn't need a VTT, we're done. */
+ if (!inits)
+ return;
+
+ /* Figure out the type of the VTT. */
+ type = build_index_type (size_int (list_length (inits)));
+ type = build_cplus_array_type (const_ptr_type_node, type);
+
+ /* Now, build the VTT object itself. */
+ vtt = build_vtable (t, get_vtt_name (t), type);
+ pushdecl_top_level (vtt);
+ initialize_array (vtt, inits);
+}
+
+/* The type corresponding to BINFO is a base class of T, but BINFO is
+ in the base class hierarchy of a class derived from T. Return the
+ base, in T's hierarchy, that corresponds to BINFO. */
+
+static tree
+get_matching_base (binfo, t)
+ tree binfo;
+ tree t;
+{
+ tree derived;
+ int i;
+
+ if (same_type_p (BINFO_TYPE (binfo), t))
+ return binfo;
+
+ if (TREE_VIA_VIRTUAL (binfo))
+ return binfo_for_vbase (BINFO_TYPE (binfo), t);
+
+ derived = get_matching_base (BINFO_INHERITANCE_CHAIN (binfo), t);
+ for (i = 0; i < BINFO_N_BASETYPES (derived); ++i)
+ if (same_type_p (BINFO_TYPE (BINFO_BASETYPE (derived, i)),
+ BINFO_TYPE (binfo)))
+ return BINFO_BASETYPE (derived, i);
+
+ my_friendly_abort (20000628);
+ return NULL_TREE;
+}
+
+/* Recursively build the VTT-initializer for BINFO (which is in the
+ hierarchy dominated by T). If VIRTUAL_VTTS_P is non-zero, then
+ sub-VTTs for virtual bases are included. INITS points to the end
+ of the initializer list to date. INDEX is the VTT index where the
+ next element will be placed. */
+
+static tree *
+build_vtt_inits (binfo, t, virtual_vtts_p, inits, index)
+ tree binfo;
+ tree t;
+ int virtual_vtts_p;
+ tree *inits;
+ tree *index;
+{
+ int i;
+ tree b;
+ tree init;
+ tree secondary_vptrs;
+ int ctor_vtbl_p;
+
+ /* We only need VTTs for subobjects with virtual bases. */
+ if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo)))
+ return inits;
+
+ /* We need to use a construction vtable if this is not the primary
+ VTT. */
+ ctor_vtbl_p = !same_type_p (TREE_TYPE (binfo), t);
+ if (ctor_vtbl_p)
+ {
+ build_ctor_vtbl_group (binfo, t);
+
+ /* Record the offset in the VTT where this sub-VTT can be found. */
+ BINFO_SUBVTT_INDEX (binfo) = *index;
+ }
+
+ /* Add the address of the primary vtable for the complete object. */
+ init = BINFO_VTABLE (binfo);
+ if (TREE_CODE (init) == TREE_LIST)
+ init = TREE_VALUE (init);
+ *inits = build_tree_list (NULL_TREE, init);
+ inits = &TREE_CHAIN (*inits);
+ BINFO_VPTR_INDEX (binfo) = *index;
+ *index = size_binop (PLUS_EXPR, *index, TYPE_SIZE_UNIT (ptr_type_node));
+
+ /* Recursively add the secondary VTTs for non-virtual bases. */
+ for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
+ {
+ b = BINFO_BASETYPE (binfo, i);
+ if (!TREE_VIA_VIRTUAL (b))
+ inits = build_vtt_inits (BINFO_BASETYPE (binfo, i), t,
+ /*virtuals_vtts_p=*/0,
+ inits, index);
+ }
+
+ /* Add secondary virtual pointers for all subobjects of BINFO with
+ either virtual bases or virtual functions overridden along a
+ virtual path between the declaration and D, except subobjects
+ that are non-virtual primary bases. */
+ secondary_vptrs = tree_cons (t, NULL_TREE, BINFO_TYPE (binfo));
+ TREE_TYPE (secondary_vptrs) = *index;
dfs_walk_real (binfo,
- dfs_accumulate_vtbl_inits,
+ dfs_build_secondary_vptr_vtt_inits,
NULL,
- dfs_skip_vbases,
- inits);
+ dfs_unmarked_real_bases_queue_p,
+ secondary_vptrs);
+ dfs_walk (binfo, dfs_unmark, dfs_marked_real_bases_queue_p, t);
+ *index = TREE_TYPE (secondary_vptrs);
+
+ /* The secondary vptrs come back in reverse order. After we reverse
+ them, and add the INITS, the last init will be the first element
+ of the chain. */
+ secondary_vptrs = TREE_VALUE (secondary_vptrs);
+ if (secondary_vptrs)
+ {
+ *inits = nreverse (secondary_vptrs);
+ inits = &TREE_CHAIN (secondary_vptrs);
+ my_friendly_assert (*inits == NULL_TREE, 20000517);
+ }
+
+ /* Add the secondary VTTs for virtual bases. */
+ if (virtual_vtts_p)
+ for (b = TYPE_BINFO (BINFO_TYPE (binfo)); b; b = TREE_CHAIN (b))
+ {
+ tree vbase;
+
+ if (!TREE_VIA_VIRTUAL (b))
+ continue;
+
+ vbase = binfo_for_vbase (BINFO_TYPE (b), t);
+ inits = build_vtt_inits (vbase, t, /*virtual_vtts_p=*/0,
+ inits, index);
+ }
+
+ dfs_walk (binfo, dfs_fixup_binfo_vtbls,
+ dfs_unmarked_real_bases_queue_p,
+ build_tree_list (t, binfo));
+
+ return 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). */
+/* Called from build_vtt_inits via dfs_walk. */
static tree
-dfs_accumulate_vtbl_inits (binfo, data)
+dfs_build_secondary_vptr_vtt_inits (binfo, data)
tree binfo;
void *data;
{
- tree l;
+ tree l;
tree t;
+ tree init;
+ tree index;
l = (tree) data;
- t = TREE_TYPE (l);
+ t = TREE_CHAIN (l);
+
+ SET_BINFO_MARKED (binfo);
+
+ /* We don't care about bases that don't have vtables. */
+ if (!TYPE_VFIELD (BINFO_TYPE (binfo)))
+ return NULL_TREE;
+
+ /* We're only interested in proper subobjects of T. */
+ if (same_type_p (BINFO_TYPE (binfo), t))
+ return NULL_TREE;
+
+ /* We're not interested in non-virtual primary bases. */
+ if (!TREE_VIA_VIRTUAL (binfo) && BINFO_PRIMARY_MARKED_P (binfo))
+ return NULL_TREE;
+
+ /* If BINFO doesn't have virtual bases, then we have to look to see
+ whether or not any virtual functions were overidden along a
+ virtual path. The point is that given:
+
+ struct V { virtual void f(); int i; };
+ struct C : public virtual V { void f (); };
+
+ when we constrct C we need a secondary vptr for V-in-C because we
+ don't know what the vcall offset for `f' should be. If `V' ends
+ up in a different place in the complete object, then we'll need a
+ different vcall offset than that present in the normal V-in-C
+ vtable. */
+ if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo))
+ && !BINFO_OVERRIDE_ALONG_VIRTUAL_PATH_P (get_matching_base (binfo, t)))
+ return NULL_TREE;
+
+ /* Record the index where this secondary vptr can be found. */
+ index = TREE_TYPE (l);
+ BINFO_VPTR_INDEX (binfo) = index;
+ TREE_TYPE (l) = size_binop (PLUS_EXPR, index,
+ TYPE_SIZE_UNIT (ptr_type_node));
+
+ /* Add the initializer for the secondary vptr itself. */
+ init = BINFO_VTABLE (binfo);
+ if (TREE_CODE (init) == TREE_LIST)
+ init = TREE_VALUE (init);
+ TREE_VALUE (l) = tree_cons (NULL_TREE, init, TREE_VALUE (l));
+
+ return NULL_TREE;
+}
+
+/* Called from build_vtt_inits via dfs_walk. */
+
+static tree
+dfs_fixup_binfo_vtbls (binfo, data)
+ tree binfo;
+ void *data;
+{
+ CLEAR_BINFO_MARKED (binfo);
+
+ /* We don't care about bases that don't have vtables. */
+ if (!TYPE_VFIELD (BINFO_TYPE (binfo)))
+ return NULL_TREE;
+
+ /* If we scribbled the construction vtable vptr into BINFO, clear it
+ out now. */
+ if (TREE_CODE (BINFO_VTABLE (binfo)) == TREE_LIST
+ && (TREE_PURPOSE (BINFO_VTABLE (binfo))
+ == TREE_VALUE ((tree) data)))
+ BINFO_VTABLE (binfo) = TREE_CHAIN (BINFO_VTABLE (binfo));
+
+ return NULL_TREE;
+}
+
+/* Build the construction vtable group for BINFO which is in the
+ hierarchy dominated by T. */
+
+static void
+build_ctor_vtbl_group (binfo, t)
+ tree binfo;
+ tree t;
+{
+ tree list;
+ tree type;
+ tree vtbl;
+ tree inits;
+ tree id;
+ tree vbase;
+
+ /* See if we've already create this construction vtable group. */
+ if (flag_new_abi)
+ id = mangle_ctor_vtbl_for_type (t, binfo);
+ else
+ id = get_ctor_vtbl_name (t, binfo);
+ if (IDENTIFIER_GLOBAL_VALUE (id))
+ return;
+
+ /* Build a version of VTBL (with the wrong type) for use in
+ constructing the addresses of secondary vtables in the
+ construction vtable group. */
+ vtbl = build_vtable (t, id, ptr_type_node);
+ list = build_tree_list (vtbl, NULL_TREE);
+ accumulate_vtbl_inits (binfo, TYPE_BINFO (TREE_TYPE (binfo)),
+ binfo, t, list);
+ for (vbase = TYPE_BINFO (TREE_TYPE (binfo));
+ vbase;
+ vbase = TREE_CHAIN (vbase))
+ {
+ tree b;
+
+ if (!TREE_VIA_VIRTUAL (vbase))
+ continue;
+
+ b = binfo_for_vbase (BINFO_TYPE (vbase), t);
+ accumulate_vtbl_inits (b, vbase, binfo, t, list);
+ }
+
+ inits = TREE_VALUE (list);
+
+ /* Figure out the type of the construction vtable. */
+ type = build_index_type (size_int (list_length (inits)));
+ type = build_cplus_array_type (vtable_entry_type, type);
+ TREE_TYPE (vtbl) = type;
+
+ /* Initialize the construction vtable. */
+ pushdecl_top_level (vtbl);
+ initialize_array (vtbl, inits);
+}
+
+/* Add the vtbl initializers for BINFO (and its non-primary,
+ non-virtual bases) to the list of INITS. BINFO is in the hierarchy
+ dominated by T. ORIG_BINFO must have the same type as BINFO, but
+ may be different from BINFO if we are building a construction
+ vtable. RTTI_BINFO gives the object that should be used as the
+ complete object for BINFO. */
+
+static void
+accumulate_vtbl_inits (binfo, orig_binfo, rtti_binfo, t, inits)
+ tree binfo;
+ tree orig_binfo;
+ tree rtti_binfo;
+ tree t;
+ tree inits;
+{
+ int i;
+ int ctor_vtbl_p;
+
+ my_friendly_assert (same_type_p (BINFO_TYPE (binfo),
+ BINFO_TYPE (orig_binfo)),
+ 20000517);
+
+ /* This is a construction vtable if the RTTI type is not the most
+ derived type in the hierarchy. */
+ ctor_vtbl_p = !same_type_p (BINFO_TYPE (rtti_binfo), t);
+
+ /* If we're building a construction vtable, we're not interested in
+ subobjects that don't require construction vtables. */
+ if (ctor_vtbl_p
+ && !TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo))
+ && !(BINFO_OVERRIDE_ALONG_VIRTUAL_PATH_P
+ (get_matching_base (binfo, BINFO_TYPE (rtti_binfo)))))
+ return;
+
+ /* Build the initializers for the BINFO-in-T vtable. */
+ TREE_VALUE (inits)
+ = chainon (TREE_VALUE (inits),
+ dfs_accumulate_vtbl_inits (binfo, orig_binfo,
+ rtti_binfo, t, inits));
+
+ /* Walk the BINFO and its bases. We walk in preorder so that as we
+ initialize each vtable we can figure out at what offset the
+ secondary vtable lies from the primary vtable. We can't use
+ dfs_walk here because we need to iterate through bases of BINFO
+ and RTTI_BINFO simultaneously. */
+ for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
+ {
+ tree base_binfo;
+
+ base_binfo = BINFO_BASETYPE (binfo, i);
+ /* Skip virtual bases. */
+ if (TREE_VIA_VIRTUAL (base_binfo))
+ continue;
+ accumulate_vtbl_inits (base_binfo,
+ BINFO_BASETYPE (orig_binfo, i),
+ rtti_binfo,
+ t,
+ 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). Returns the initializers for the BINFO vtable. */
+
+static tree
+dfs_accumulate_vtbl_inits (binfo, orig_binfo, rtti_binfo, t, l)
+ tree binfo;
+ tree orig_binfo;
+ tree rtti_binfo;
+ tree t;
+ tree l;
+{
+ tree inits = NULL_TREE;
- if (!BINFO_PRIMARY_MARKED_P (binfo)
- && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))
- && BINFO_NEW_VTABLE_MARKED (binfo, t))
+ if (BINFO_NEW_VTABLE_MARKED (orig_binfo, t))
{
- tree inits;
tree vtbl;
tree index;
int non_fn_entries;
/* Compute the initializer for this vtable. */
- inits = build_vtbl_initializer (binfo, t, &non_fn_entries);
+ inits = build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo,
+ &non_fn_entries);
- /* Set BINFO_VTABLE to the address where the VPTR should point. */
+ /* Figure out the position to which the VPTR should point. */
vtbl = TREE_PURPOSE (l);
vtbl = build1 (ADDR_EXPR,
- build_pointer_type (TREE_TYPE (vtbl)),
+ vtbl_ptr_type_node,
vtbl);
index = size_binop (PLUS_EXPR,
size_int (non_fn_entries),
size_int (list_length (TREE_VALUE (l))));
- BINFO_VTABLE (binfo)
- = build (PLUS_EXPR, TREE_TYPE (vtbl), vtbl,
- size_binop (MULT_EXPR,
- TYPE_SIZE_UNIT (TREE_TYPE (vtbl)),
- index));
-
- /* Add the initializers for this vtable to the initializers for
- the other vtables we've already got. */
- TREE_VALUE (l) = chainon (TREE_VALUE (l), inits);
+ index = size_binop (MULT_EXPR,
+ TYPE_SIZE_UNIT (vtable_entry_type),
+ index);
+ vtbl = build (PLUS_EXPR, TREE_TYPE (vtbl), vtbl, index);
+ TREE_CONSTANT (vtbl) = 1;
+
+ /* For an ordinary vtable, set BINFO_VTABLE. */
+ if (same_type_p (BINFO_TYPE (rtti_binfo), t))
+ BINFO_VTABLE (binfo) = vtbl;
+ /* For a construction vtable, we can't overwrite BINFO_VTABLE.
+ So, we make a TREE_LIST. Later, dfs_fixup_binfo_vtbls will
+ straighten this out. */
+ else
+ BINFO_VTABLE (binfo) =
+ tree_cons (rtti_binfo, vtbl, BINFO_VTABLE (binfo));
}
- CLEAR_BINFO_NEW_VTABLE_MARKED (binfo, t);
-
- return NULL_TREE;
+ return inits;
}
/* 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. If NON_FN_ENTRIES_P is not NULL,
- *NON_FN_ENTRIES_P is set to the number of non-function entries in
- the vtable. */
+ is part of the hierarchy dominated by T. If we're building a
+ construction vtable, the ORIG_BINFO is the binfo we should use to
+ find the actual function pointers to put in the vtable. Otherwise,
+ ORIG_BINFO should be the same as BINFO. The RTTI_BINFO is the
+ BINFO that should be indicated by the RTTI information in the
+ vtable; it will be a base class of T, rather than T itself, if we
+ are building a construction vtable.
+
+ The value returned is a TREE_LIST suitable for wrapping in a
+ CONSTRUCTOR to use as the DECL_INITIAL for a vtable. If
+ NON_FN_ENTRIES_P is not NULL, *NON_FN_ENTRIES_P is set to the
+ number of non-function entries in the vtable.
+
+ It might seem that this function should never be called with a
+ BINFO for which BINFO_PRIMARY_MARKED_P holds, the vtable for such a
+ base is always subsumed by a derived class vtable. However, when
+ we are building construction vtables we do build vtables for
+ primary bases; we need these while the primary base is being
+ constructed. */
static tree
-build_vtbl_initializer (binfo, t, non_fn_entries_p)
+build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)
tree binfo;
+ tree orig_binfo;
tree t;
+ tree rtti_binfo;
int *non_fn_entries_p;
{
- tree v = BINFO_VIRTUALS (binfo);
- tree inits = NULL_TREE;
+ tree v;
tree vfun_inits;
tree vbase;
- vcall_offset_data vod;
-
- /* Initialize those parts of VOD that matter. */
- vod.derived = t;
- vod.inits = NULL_TREE;
- vod.primary_p = (binfo == TYPE_BINFO (t));
+ vtbl_init_data vid;
+
+ /* Initialize VID. */
+ memset (&vid, 0, sizeof (vid));
+ vid.binfo = binfo;
+ vid.derived = t;
+ vid.last_init = &vid.inits;
+ vid.primary_vtbl_p = (binfo == TYPE_BINFO (t));
+ vid.ctor_vtbl_p = !same_type_p (BINFO_TYPE (rtti_binfo), t);
/* The first vbase or vcall offset is at index -3 in the vtable. */
- vod.index = build_int_2 (-3, -1);
+ vid.index = ssize_int (-3);
+ /* Add entries to the vtable for RTTI. */
+ build_rtti_vtbl_entries (binfo, rtti_binfo, &vid);
+
+ /* Create an array for keeping track of the functions we've
+ processed. When we see multiple functions with the same
+ signature, we share the vcall offsets. */
+ VARRAY_TREE_INIT (vid.fns, 32, "fns");
/* Add the vcall and vbase offset entries. */
- build_vcall_and_vbase_vtbl_entries (binfo, &vod);
- inits = vod.inits;
- /* Clear BINFO_VTABLE_PAATH_MARKED; it's set by
+ build_vcall_and_vbase_vtbl_entries (binfo, &vid);
+ /* Clean up. */
+ VARRAY_FREE (vid.fns);
+ /* Clear BINFO_VTABLE_PATH_MARKED; it's set by
build_vbase_offset_vtbl_entries. */
for (vbase = CLASSTYPE_VBASECLASSES (t);
vbase;
vbase = TREE_CHAIN (vbase))
- CLEAR_BINFO_VTABLE_PATH_MARKED (vbase);
-
- /* Add entries to the vtable for RTTI. */
- inits = chainon (inits, build_rtti_vtbl_entries (binfo, t));
+ CLEAR_BINFO_VTABLE_PATH_MARKED (TREE_VALUE (vbase));
if (non_fn_entries_p)
- *non_fn_entries_p = list_length (inits);
+ *non_fn_entries_p = list_length (vid.inits);
/* Go through all the ordinary virtual functions, building up
initializers. */
vfun_inits = NULL_TREE;
- while (v)
+ for (v = BINFO_VIRTUALS (orig_binfo); v; v = TREE_CHAIN (v))
{
tree delta;
tree vcall_index;
/* Pull the offset for `this', and the function to call, out of
the list. */
delta = BV_DELTA (v);
- vcall_index = BV_VCALL_INDEX (v);
+
+ if (BV_USE_VCALL_INDEX_P (v))
+ {
+ vcall_index = BV_VCALL_INDEX (v);
+ my_friendly_assert (vcall_index != NULL_TREE, 20000621);
+ }
+ else
+ vcall_index = NULL_TREE;
+
fn = BV_FN (v);
my_friendly_assert (TREE_CODE (delta) == INTEGER_CST, 19990727);
my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727);
/* The address of a function can't change. */
TREE_CONSTANT (pfn) = 1;
/* Enter it in the vtable. */
- init = build_vtable_entry (delta, vcall_index, pfn);
+ init = build_vtable_entry (delta, vcall_index, pfn,
+ BV_GENERATE_THUNK_WITH_VTABLE_P (v));
/* And add it to the chain of initializers. */
vfun_inits = tree_cons (NULL_TREE, init, vfun_inits);
-
- /* Keep going. */
- v = TREE_CHAIN (v);
}
/* The initializers for virtual functions were built up in reverse
order; straighten them out now. */
vfun_inits = nreverse (vfun_inits);
- /* The complete initializer is the INITS, followed by the
- VFUN_INITS. */
- return chainon (inits, vfun_inits);
+ /* The negative offset initializers are also in reverse order. */
+ vid.inits = nreverse (vid.inits);
+
+ /* Chain the two together. */
+ return chainon (vid.inits, vfun_inits);
}
-/* Sets vod->inits to be the initializers for the vbase and vcall
+/* Sets vid->inits to be the initializers for the vbase and vcall
offsets in BINFO, which is in the hierarchy dominated by T. */
static void
-build_vcall_and_vbase_vtbl_entries (binfo, vod)
+build_vcall_and_vbase_vtbl_entries (binfo, vid)
tree binfo;
- vcall_offset_data *vod;
+ vtbl_init_data *vid;
{
tree b;
- tree inits;
/* If this is a derived class, we must first create entries
- corresponding to the base class. These entries must go closer to
- the vptr, so we save them up and add them to the end of the list
- later. */
- inits = vod->inits;
- vod->inits = NULL_TREE;
- b = BINFO_PRIMARY_BINFO (binfo);
+ corresponding to the primary base class. */
+ b = get_primary_binfo (binfo);
if (b)
- build_vcall_and_vbase_vtbl_entries (b, vod);
+ build_vcall_and_vbase_vtbl_entries (b, vid);
/* Add the vbase entries for this base. */
- build_vbase_offset_vtbl_entries (binfo, vod);
+ build_vbase_offset_vtbl_entries (binfo, vid);
/* Add the vcall entries for this base. */
- build_vcall_offset_vtbl_entries (binfo, vod);
-
- vod->inits = chainon (vod->inits, inits);
+ build_vcall_offset_vtbl_entries (binfo, vid);
}
/* Returns the initializers for the vbase offset entries in the vtable
where the next vbase offset will go. */
static void
-build_vbase_offset_vtbl_entries (binfo, vod)
+build_vbase_offset_vtbl_entries (binfo, vid)
tree binfo;
- vcall_offset_data *vod;
+ vtbl_init_data *vid;
{
tree vbase;
tree t;
if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo)))
return;
- t = vod->derived;
+ t = vid->derived;
/* Go through the virtual bases, adding the offsets. */
for (vbase = TYPE_BINFO (BINFO_TYPE (binfo));
/* Find the instance of this virtual base in the complete
object. */
- b = BINFO_FOR_VBASE (BINFO_TYPE (vbase), t);
+ b = binfo_for_vbase (BINFO_TYPE (vbase), t);
/* If we've already got an offset for this virtual base, we
don't need another one. */
/* Figure out where we can find this vbase offset. */
delta = size_binop (MULT_EXPR,
- convert (ssizetype, vod->index),
+ vid->index,
convert (ssizetype,
TYPE_SIZE_UNIT (vtable_entry_type)));
- if (vod->primary_p)
+ if (vid->primary_vtbl_p)
BINFO_VPTR_FIELD (b) = delta;
if (binfo != TYPE_BINFO (t))
tree orig_vbase;
/* Find the instance of this virtual base in the type of BINFO. */
- orig_vbase = BINFO_FOR_VBASE (BINFO_TYPE (vbase),
+ orig_vbase = binfo_for_vbase (BINFO_TYPE (vbase),
BINFO_TYPE (binfo));
/* The vbase offset had better be the same. */
}
/* The next vbase will come at a more negative offset. */
- vod->index = fold (build (MINUS_EXPR, integer_type_node,
- vod->index, integer_one_node));
+ vid->index = size_binop (MINUS_EXPR, vid->index, ssize_int (1));
/* The initializer is the delta from BINFO to this virtual base.
- The vbase offsets go in reverse inheritance-graph order, and
- we are walking in inheritance graph order so these end up in
- the right order. */
+ The vbase offsets go in reverse inheritance-graph order, and
+ we are walking in inheritance graph order so these end up in
+ the right order. */
delta = size_diffop (BINFO_OFFSET (b), BINFO_OFFSET (binfo));
- vod->inits = tree_cons (NULL_TREE,
- fold (build1 (NOP_EXPR,
- vtable_entry_type,
- delta)),
- vod->inits);
- }
-}
-
-/* Called from build_vcall_offset_vtbl_entries via dfs_walk. */
-
-static tree
-dfs_vcall_offset_queue_p (binfo, data)
- tree binfo;
- void *data;
-{
- vcall_offset_data* vod = (vcall_offset_data *) data;
-
- return (binfo == vod->vbase) ? binfo : dfs_skip_vbases (binfo, NULL);
-}
-
-/* Called from build_vcall_offset_vtbl_entries via dfs_walk. */
-
-static tree
-dfs_build_vcall_offset_vtbl_entries (binfo, data)
- tree binfo;
- void *data;
-{
- vcall_offset_data* vod;
- tree virtuals;
- tree binfo_inits;
- tree b;
- int i;
-
- vod = (vcall_offset_data *) data;
- binfo_inits = NULL_TREE;
-
- /* Skip virtuals that we have already handled in a primary base
- class. */
- virtuals = BINFO_VIRTUALS (binfo);
- b = BINFO_PRIMARY_BINFO (binfo);
- if (b)
- for (i = 0; i < CLASSTYPE_VSIZE (BINFO_TYPE (b)); ++i)
- virtuals = TREE_CHAIN (virtuals);
-
- /* Make entries for the rest of the virtuals. */
- while (virtuals)
- {
- /* 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);
- vod->index = fold (build (MINUS_EXPR, integer_type_node,
- vod->index, integer_one_node));
- virtuals = TREE_CHAIN (virtuals);
- }
-
- /* The offests are built up in reverse order, so we straighten them
- here. We simultaneously add them to VOD->INITS; we're walking
- the bases in inheritance graph order, and the initializers are
- supposed to appear in reverse inheritance order, so that's
- correct. */
- while (binfo_inits)
- {
- tree next;
-
- next = TREE_CHAIN (binfo_inits);
- TREE_CHAIN (binfo_inits) = vod->inits;
- vod->inits = binfo_inits;
- binfo_inits = next;
+ *vid->last_init
+ = build_tree_list (NULL_TREE,
+ fold (build1 (NOP_EXPR,
+ vtable_entry_type,
+ delta)));
+ vid->last_init = &TREE_CHAIN (*vid->last_init);
}
-
- return NULL_TREE;
}
/* Adds the initializers for the vcall offset entries in the vtable
for BINFO (which is part of the class hierarchy dominated by T) to
- VOD->INITS. */
+ VID->INITS. */
static void
-build_vcall_offset_vtbl_entries (binfo, vod)
+build_vcall_offset_vtbl_entries (binfo, vid)
tree binfo;
- vcall_offset_data *vod;
+ vtbl_init_data *vid;
{
- tree inits;
-
/* Under the old ABI, the adjustments to the `this' pointer were made
elsewhere. */
if (!vcall_offsets_in_vtable_p ())
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->vbase = binfo;
- inits = vod->inits;
- vod->inits = NULL_TREE;
- dfs_walk_real (binfo,
- dfs_build_vcall_offset_vtbl_entries,
- NULL,
- dfs_vcall_offset_queue_p,
- vod);
- vod->inits = chainon (vod->inits, inits);
+ in our non-virtual bases vtables. */
+ vid->vbase = binfo;
+ /* Now, walk through the non-virtual bases, adding vcall offsets. */
+ add_vcall_offset_vtbl_entries_r (binfo, vid);
+}
+
+/* Build vcall offsets, starting with those for BINFO. */
+
+static void
+add_vcall_offset_vtbl_entries_r (binfo, vid)
+ tree binfo;
+ vtbl_init_data *vid;
+{
+ int i;
+ tree primary_binfo;
+
+ /* Don't walk into virtual bases -- except, of course, for the
+ virtual base for which we are building vcall offsets. */
+ if (TREE_VIA_VIRTUAL (binfo) && vid->vbase != binfo)
+ return;
+
+ /* If BINFO has a primary base, process it first. */
+ primary_binfo = get_primary_binfo (binfo);
+ if (primary_binfo)
+ add_vcall_offset_vtbl_entries_r (primary_binfo, vid);
+
+ /* Add BINFO itself to the list. */
+ add_vcall_offset_vtbl_entries_1 (binfo, vid);
+
+ /* Scan the non-primary bases of BINFO. */
+ for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
+ {
+ tree base_binfo;
+
+ base_binfo = BINFO_BASETYPE (binfo, i);
+ if (base_binfo != primary_binfo)
+ add_vcall_offset_vtbl_entries_r (base_binfo, vid);
+ }
+}
+
+/* Called from build_vcall_offset_vtbl_entries via dfs_walk. */
+
+static void
+add_vcall_offset_vtbl_entries_1 (binfo, vid)
+ tree binfo;
+ vtbl_init_data* vid;
+{
+ tree derived_virtuals;
+ tree base_virtuals;
+ tree orig_virtuals;
+ tree binfo_inits;
+ /* If BINFO is a primary base, this is the least derived class of
+ BINFO that is not a primary base. */
+ tree non_primary_binfo;
+
+ binfo_inits = NULL_TREE;
+
+ /* We might be a primary base class. Go up the inheritance
+ hierarchy until we find the class of which we are a primary base:
+ it is the BINFO_VIRTUALS there that we need to consider. */
+ non_primary_binfo = binfo;
+ while (BINFO_INHERITANCE_CHAIN (non_primary_binfo))
+ {
+ tree b;
+
+ /* If we have reached a virtual base, then it must be the
+ virtual base for which we are building vcall offsets. In
+ turn, the virtual base must be a (possibly indirect) primary
+ base of the class that we are initializing, or we wouldn't
+ care about its vtable offsets. */
+ if (TREE_VIA_VIRTUAL (non_primary_binfo))
+ {
+ non_primary_binfo = vid->binfo;
+ break;
+ }
+
+ b = BINFO_INHERITANCE_CHAIN (non_primary_binfo);
+ if (get_primary_binfo (b) != non_primary_binfo)
+ break;
+ non_primary_binfo = b;
+ }
+
+ /* Make entries for the rest of the virtuals. */
+ for (base_virtuals = BINFO_VIRTUALS (binfo),
+ derived_virtuals = BINFO_VIRTUALS (non_primary_binfo),
+ orig_virtuals = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (binfo)));
+ base_virtuals;
+ base_virtuals = TREE_CHAIN (base_virtuals),
+ derived_virtuals = TREE_CHAIN (derived_virtuals),
+ orig_virtuals = TREE_CHAIN (orig_virtuals))
+ {
+ tree orig_fn;
+ tree fn;
+ tree base;
+ tree base_binfo;
+ size_t i;
+
+ /* Find the declaration that originally caused this function to
+ be present. */
+ orig_fn = BV_FN (orig_virtuals);
+
+ /* We do not need an entry if this function is declared in a
+ virtual base (or one of its virtual bases), and not
+ overridden in the section of the hierarchy dominated by the
+ virtual base for which we are building vcall offsets. */
+ if (!same_type_p (DECL_CONTEXT (orig_fn), BINFO_TYPE (binfo)))
+ continue;
+
+ /* Find the overriding function. */
+ fn = BV_FN (derived_virtuals);
+
+ /* If there is already an entry for a function with the same
+ signature as FN, then we do not need a second vcall offset.
+ Check the list of functions already present in the derived
+ class vtable. */
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (vid->fns); ++i)
+ {
+ tree derived_entry;
+
+ derived_entry = VARRAY_TREE (vid->fns, i);
+ if (same_signature_p (BV_FN (derived_entry), fn))
+ {
+ BV_VCALL_INDEX (derived_virtuals)
+ = BV_VCALL_INDEX (derived_entry);
+ break;
+ }
+ }
+ if (i != VARRAY_ACTIVE_SIZE (vid->fns))
+ continue;
+
+ /* The FN comes from BASE. So, we must caculate the adjustment
+ from the virtual base that derived from BINFO to BASE. */
+ base = DECL_CONTEXT (fn);
+ base_binfo = get_binfo (base, vid->derived, /*protect=*/0);
+
+ /* Compute the vcall offset. */
+ *vid->last_init
+ = (build_tree_list
+ (NULL_TREE,
+ fold (build1 (NOP_EXPR, vtable_entry_type,
+ size_diffop (BINFO_OFFSET (base_binfo),
+ BINFO_OFFSET (vid->vbase))))));
+ vid->last_init = &TREE_CHAIN (*vid->last_init);
+
+ /* Keep track of the vtable index where this vcall offset can be
+ found. For a construction vtable, we already made this
+ annotation when we build the original vtable. */
+ if (!vid->ctor_vtbl_p)
+ BV_VCALL_INDEX (derived_virtuals) = vid->index;
+
+ /* The next vcall offset will be found at a more negative
+ offset. */
+ vid->index = size_binop (MINUS_EXPR, vid->index, ssize_int (1));
+
+ /* Keep track of this function. */
+ VARRAY_PUSH_TREE (vid->fns, derived_virtuals);
+ }
}
/* Return vtbl initializers for the RTTI entries coresponding to the
- BINFO's vtable. BINFO is a part of the hierarchy dominated by
- T. */
+ BINFO's vtable. The RTTI entries should indicate the object given
+ by RTTI_BINFO. */
-static tree
-build_rtti_vtbl_entries (binfo, t)
+static void
+build_rtti_vtbl_entries (binfo, rtti_binfo, vid)
tree binfo;
- tree t;
+ tree rtti_binfo;
+ vtbl_init_data *vid;
{
tree b;
+ tree t;
tree basetype;
tree offset;
tree decl;
tree init;
- tree inits;
basetype = BINFO_TYPE (binfo);
- inits = NULL_TREE;
+ t = BINFO_TYPE (rtti_binfo);
/* For a COM object there is no RTTI entry. */
if (CLASSTYPE_COM_INTERFACE (basetype))
- return inits;
+ return;
/* 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. */
{
tree primary_base;
- primary_base = BINFO_PRIMARY_BINFO (b);
+ primary_base = get_primary_binfo (b);
if (!BINFO_PRIMARY_MARKED_P (primary_base))
break;
b = primary_base;
}
- offset = size_diffop (size_zero_node, BINFO_OFFSET (b));
+ offset = size_diffop (BINFO_OFFSET (rtti_binfo), BINFO_OFFSET (b));
/* 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
vtable. */
init = build1 (ADDR_EXPR, vfunc_ptr_type_node, decl);
TREE_CONSTANT (init) = 1;
- init = build_vtable_entry (offset, integer_zero_node, init);
+ init = build_vtable_entry (offset, NULL_TREE, init,
+ /*generate_with_vtable_p=*/0);
}
- inits = tree_cons (NULL_TREE, init, inits);
+ *vid->last_init = build_tree_list (NULL_TREE, init);
+ vid->last_init = &TREE_CHAIN (*vid->last_init);
/* Add the offset-to-top entry. It comes earlier in the vtable that
the the typeinfo entry. */
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);
+ *vid->last_init = build_tree_list (NULL_TREE, init);
+ vid->last_init = &TREE_CHAIN (*vid->last_init);
}
-
- return inits;
}
/* Build an entry in the virtual function table. DELTA is the offset
ABI.) */
static tree
-build_vtable_entry (delta, vcall_index, entry)
+build_vtable_entry (delta, vcall_index, entry, generate_with_vtable_p)
tree delta;
tree vcall_index;
tree entry;
+ int generate_with_vtable_p;
{
if (flag_vtable_thunks)
{
- HOST_WIDE_INT idelta;
- HOST_WIDE_INT ivindex;
+ tree fn;
- idelta = tree_low_cst (delta, 0);
- ivindex = tree_low_cst (vcall_index, 0);
- if ((idelta || ivindex)
- && ! DECL_PURE_VIRTUAL_P (TREE_OPERAND (entry, 0)))
+ fn = TREE_OPERAND (entry, 0);
+ if ((!integer_zerop (delta) || vcall_index != NULL_TREE)
+ && fn != abort_fndecl
+ && !DECL_TINFO_FN_P (fn))
{
- entry = make_thunk (entry, idelta, ivindex);
+ entry = make_thunk (entry, delta, vcall_index,
+ generate_with_vtable_p);
entry = build1 (ADDR_EXPR, vtable_entry_type, entry);
TREE_READONLY (entry) = 1;
TREE_CONSTANT (entry) = 1;
}
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);
+ my_friendly_assert (vcall_index == NULL_TREE, 20000125);
/* DELTA used to be constructed by `size_int' and/or size_binop,
which caused overflow problems when it was negative. That should