aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/class.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/class.c')
-rw-r--r--gcc/cp/class.c213
1 files changed, 131 insertions, 82 deletions
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index a557292..8c1073e 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -115,7 +115,7 @@ static tree resolve_address_of_overloaded_function PROTO((tree, tree, int,
int, tree));
static void build_vtable_entry_ref PROTO((tree, tree, tree));
static tree build_vtable_entry_for_fn PROTO((tree, tree));
-static tree build_vtbl_initializer PROTO((tree));
+static tree build_vtbl_initializer PROTO((tree, tree));
static int count_fields PROTO((tree));
static int add_fields_to_vec PROTO((tree, tree, int));
static void check_bitfield_decl PROTO((tree));
@@ -145,7 +145,8 @@ static void remove_base_fields PROTO((tree));
static tree dfs_set_offset_for_shared_vbases PROTO((tree, void *));
static tree dfs_set_offset_for_unshared_vbases PROTO((tree, void *));
static tree dfs_build_vbase_offset_vtbl_entries PROTO((tree, void *));
-static tree build_vbase_offset_vtbl_entries PROTO((tree));
+static tree build_vbase_offset_vtbl_entries PROTO((tree, tree));
+static void start_vtable PROTO((tree, int *));
/* Variables shared between class.c and call.c. */
@@ -178,9 +179,12 @@ build_vbase_pointer_fields (rec, empty_p)
tree decl;
int i;
- /* Handle basetypes almost like fields, but record their
- offsets differently. */
+ /* Under the new ABI, there are no vbase pointers in the object.
+ Instead, the offsets are stored in the vtable. */
+ if (vbase_offsets_in_vtable_p ())
+ return NULL_TREE;
+ /* Loop over the baseclasses, adding vbase pointers as needed. */
for (i = 0; i < n_baseclasses; i++)
{
register tree base_binfo = TREE_VEC_ELT (binfos, i);
@@ -251,10 +255,27 @@ dfs_build_vbase_offset_vtbl_entries (binfo, data)
else if (TREE_VIA_VIRTUAL (binfo))
{
tree init;
+ tree vbase;
+
+ /* Remember the index to the vbase offset for this virtual
+ base. */
+ vbase = BINFO_FOR_VBASE (TREE_TYPE (binfo), TREE_PURPOSE (list));
+ if (!TREE_VALUE (list))
+ BINFO_VPTR_FIELD (vbase) = build_int_2 (-1, 0);
+ else
+ {
+ BINFO_VPTR_FIELD (vbase) = TREE_PURPOSE (TREE_VALUE (list));
+ BINFO_VPTR_FIELD (vbase) = ssize_binop (MINUS_EXPR,
+ BINFO_VPTR_FIELD (vbase),
+ integer_one_node);
+ }
+ /* And record the offset at which this virtual base lies in the
+ vtable. */
init = BINFO_OFFSET (binfo);
- init = build1 (NOP_EXPR, vtable_entry_type, init);
- TREE_VALUE (list) = tree_cons (NULL_TREE, init, TREE_VALUE (list));
+ TREE_VALUE (list) = tree_cons (BINFO_VPTR_FIELD (vbase),
+ init,
+ TREE_VALUE (list));
}
SET_BINFO_VTABLE_PATH_MARKED (binfo);
@@ -262,69 +283,46 @@ dfs_build_vbase_offset_vtbl_entries (binfo, data)
return NULL_TREE;
}
-/* Returns the initializers for the vbase offset entries in the
- vtable, in reverse order. */
+/* Returns the initializers for the vbase offset entries in the vtable
+ for BINFO (which is part of the class hierarchy dominated by T), in
+ reverse order. */
static tree
-build_vbase_offset_vtbl_entries (binfo)
+build_vbase_offset_vtbl_entries (binfo, t)
tree binfo;
+ tree t;
{
- tree type;
tree inits;
tree init;
+ tree list;
/* Under the old ABI, pointers to virtual bases are stored in each
object. */
- if (!flag_new_abi)
+ if (!vbase_offsets_in_vtable_p ())
return NULL_TREE;
/* If there are no virtual baseclasses, then there is nothing to
do. */
- type = BINFO_TYPE (binfo);
- if (!TYPE_USES_VIRTUAL_BASECLASSES (type))
+ if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo)))
return NULL_TREE;
inits = NULL_TREE;
- /* Under the new ABI, the vtable contains offsets to all virtual
- bases. The ABI specifies different layouts depending on whether
- or not *all* of the bases of this type are virtual. */
- if (CLASSTYPE_N_BASECLASSES (type)
- == list_length (CLASSTYPE_VBASECLASSES (type)))
- {
- /* In this case, the offsets are allocated from right to left of
- the declaration order in which the virtual bases appear. */
- int i;
-
- for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
- {
- tree vbase = BINFO_BASETYPE (binfo, i);
- init = BINFO_OFFSET (vbase);
- init = build1 (NOP_EXPR, vtable_entry_type, init);
- inits = tree_cons (NULL_TREE, init, inits);
- }
- }
- else
- {
- tree list;
-
- /* While in this case, the offsets are allocated in the reverse
- order of a depth-first left-to-right traversal of the
- hierarchy. We use BINFO_VTABLE_PATH_MARKED because we are
- ourselves during a dfs_walk, and so BINFO_MARKED is already
- in use. */
- list = build_tree_list (type, NULL_TREE);
- TREE_TYPE (list) = binfo;
- dfs_walk (binfo,
- dfs_build_vbase_offset_vtbl_entries,
- dfs_vtable_path_unmarked_real_bases_queue_p,
- list);
- dfs_walk (binfo,
- dfs_vtable_path_unmark,
- dfs_vtable_path_marked_real_bases_queue_p,
- list);
- inits = nreverse (TREE_VALUE (list));
- }
+ /* The offsets are allocated in the reverse order of a
+ depth-first left-to-right traversal of the hierarchy. We use
+ BINFO_VTABLE_PATH_MARKED because we are ourselves during a
+ dfs_walk, and so BINFO_MARKED is already in use. */
+ list = build_tree_list (t, NULL_TREE);
+ TREE_TYPE (list) = binfo;
+ dfs_walk (binfo,
+ dfs_build_vbase_offset_vtbl_entries,
+ dfs_vtable_path_unmarked_real_bases_queue_p,
+ list);
+ dfs_walk (binfo,
+ dfs_vtable_path_unmark,
+ dfs_vtable_path_marked_real_bases_queue_p,
+ list);
+ inits = nreverse (TREE_VALUE (list));
/* We've now got offsets in the right oder. However, the offsets
we've stored are offsets from the beginning of the complete
@@ -334,9 +332,13 @@ build_vbase_offset_vtbl_entries (binfo)
tree exp = TREE_VALUE (init);
exp = ssize_binop (MINUS_EXPR, exp, BINFO_OFFSET (binfo));
- exp = build1 (NOP_EXPR, vtable_entry_type, TREE_VALUE (init));
+ exp = build1 (NOP_EXPR, vtable_entry_type, exp);
exp = fold (exp);
TREE_CONSTANT (exp) = 1;
+ /* The dfs_build_vbase_offset_vtbl_entries routine uses the
+ TREE_PURPOSE to scribble in. But, we need to clear it now so
+ that the values are not perceived as labeled initializers. */
+ TREE_PURPOSE (init) = NULL_TREE;
TREE_VALUE (init) = exp;
}
@@ -344,16 +346,41 @@ build_vbase_offset_vtbl_entries (binfo)
}
/* Returns a pointer to the virtual base class of EXP that has the
- indicated TYPE. */
+ indicated TYPE. EXP is of class type, not a pointer type. */
static tree
build_vbase_pointer (exp, type)
tree exp, type;
{
- char *name;
- FORMAT_VBASE_NAME (name, type);
-
- return build_component_ref (exp, get_identifier (name), NULL_TREE, 0);
+ if (vbase_offsets_in_vtable_p ())
+ {
+ tree vbase;
+ tree vbase_ptr;
+
+ /* Find the shared copy of TYPE; that's where the vtable offset
+ is recorded. */
+ vbase = BINFO_FOR_VBASE (type, TREE_TYPE (exp));
+ /* Find the virtual function table pointer. */
+ vbase_ptr = build_vfield_ref (exp, TREE_TYPE (exp));
+ /* Compute the location where the offset will lie. */
+ vbase_ptr = build_binary_op (PLUS_EXPR,
+ vbase_ptr,
+ BINFO_VPTR_FIELD (vbase));
+ vbase_ptr = build1 (NOP_EXPR,
+ build_pointer_type (ptrdiff_type_node),
+ vbase_ptr);
+ /* Add the contents of this location to EXP. */
+ return build (PLUS_EXPR,
+ build_pointer_type (type),
+ build_unary_op (ADDR_EXPR, exp, /*noconvert=*/0),
+ build1 (INDIRECT_REF, ptrdiff_type_node, vbase_ptr));
+ }
+ else
+ {
+ char *name;
+ FORMAT_VBASE_NAME (name, type);
+ return build_component_ref (exp, get_identifier (name), NULL_TREE, 0);
+ }
}
/* Build multi-level access to EXPR using hierarchy path PATH.
@@ -1100,6 +1127,25 @@ get_vtable_entry_n (virtuals, n)
return virtuals;
}
+/* Call this function whenever its known that a vtable for T is going
+ to be needed. It's safe to call it more than once. *HAS_VIRTUAL_P
+ is initialized to the number of slots that are reserved at the
+ beginning of the vtable for RTTI information. */
+
+static void
+start_vtable (t, has_virtual_p)
+ tree t;
+ int *has_virtual_p;
+{
+ if (*has_virtual_p == 0 && ! CLASSTYPE_COM_INTERFACE (t))
+ {
+ if (flag_vtable_thunks)
+ *has_virtual_p = 2;
+ else
+ *has_virtual_p = 1;
+ }
+}
+
/* Add a virtual function to all the appropriate vtables for the class
T. DECL_VINDEX(X) should be error_mark_node, if we want to
allocate a new slot in our table. If it is error_mark_node, we
@@ -1139,13 +1185,7 @@ add_virtual_function (pv, phv, has_virtual, fndecl, t)
/* If we are using thunks, use two slots at the front, one
for the offset pointer, one for the tdesc pointer.
For ARM-style vtables, use the same slot for both. */
- if (*has_virtual == 0 && ! CLASSTYPE_COM_INTERFACE (t))
- {
- if (flag_vtable_thunks)
- *has_virtual = 2;
- else
- *has_virtual = 1;
- }
+ start_vtable (t, has_virtual);
/* Build a new INT_CST for this DECL_VINDEX. */
{
@@ -1767,7 +1807,7 @@ determine_primary_base (t, has_virtual_p)
tree base_binfo = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (t), i);
tree basetype = BINFO_TYPE (base_binfo);
- if (TYPE_POLYMORPHIC_P (basetype))
+ if (TYPE_CONTAINS_VPTR_P (basetype))
{
/* Even a virtual baseclass can contain our RTTI
information. But, we prefer a non-virtual polymorphic
@@ -2287,9 +2327,8 @@ num_extra_vtbl_entries (binfo)
tree type;
int entries;
-
/* Under the old ABI, there are no entries at negative offsets. */
- if (!flag_new_abi)
+ if (!vbase_offsets_in_vtable_p ())
return size_zero_node;
type = BINFO_TYPE (binfo);
@@ -2317,18 +2356,20 @@ size_extra_vtbl_entries (binfo)
return fold (offset);
}
-/* Construct the initializer for BINFOs virtual function table. */
+/* Construct the initializer for BINFOs virtual function table. BINFO
+ is part of the hierarchy dominated by T. */
static tree
-build_vtbl_initializer (binfo)
+build_vtbl_initializer (binfo, t)
tree binfo;
+ tree t;
{
tree v = BINFO_VIRTUALS (binfo);
tree inits = NULL_TREE;
tree type = BINFO_TYPE (binfo);
/* Add entries to the vtable for offsets to our virtual bases. */
- inits = build_vbase_offset_vtbl_entries (binfo);
+ inits = build_vbase_offset_vtbl_entries (binfo, t);
/* Process the RTTI stuff at the head of the list. If we're not
using vtable thunks, then the RTTI entry is just an ordinary
@@ -2397,7 +2438,7 @@ build_vtbl_initializer (binfo)
static tree
dfs_finish_vtbls (binfo, data)
tree binfo;
- void *data ATTRIBUTE_UNUSED;
+ void *data;
{
if (!BINFO_PRIMARY_MARKED_P (binfo)
&& CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))
@@ -2409,7 +2450,7 @@ dfs_finish_vtbls (binfo, data)
decl = BINFO_VTABLE (binfo);
context = DECL_CONTEXT (decl);
DECL_CONTEXT (decl) = 0;
- DECL_INITIAL (decl) = build_vtbl_initializer (binfo);
+ DECL_INITIAL (decl) = build_vtbl_initializer (binfo, (tree) data);
cp_finish_decl (decl, DECL_INITIAL (decl), NULL_TREE, 0);
DECL_CONTEXT (decl) = context;
}
@@ -4112,9 +4153,9 @@ check_bases_and_members (t, empty_p)
/* Check all the method declarations. */
check_methods (t);
- /* A nearly-empty class has to be polymorphic; a nearly empty class
- contains a vptr. */
- if (!TYPE_POLYMORPHIC_P (t))
+ /* A nearly-empty class has to be vptr-containing; a nearly empty
+ class contains just a vptr. */
+ if (!TYPE_CONTAINS_VPTR_P (t))
CLASSTYPE_NEARLY_EMPTY_P (t) = 0;
/* Do some bookkeeping that will guide the generation of implicitly
@@ -4177,6 +4218,12 @@ create_vtable_ptr (t, empty_p, has_virtual_p,
add_virtual_function (pending_virtuals_p, pending_hard_virtuals_p,
has_virtual_p, fn, t);
+ /* Even if there weren't any new virtual functions, we might need a
+ new virtual function table if we're supposed to include vptrs in
+ all classes that need them. */
+ if (TYPE_CONTAINS_VPTR_P (t) && vptrs_present_everywhere_p ())
+ start_vtable (t, has_virtual_p);
+
/* If we couldn't find an appropriate base class, create a new field
here. */
if (*has_virtual_p && !TYPE_VFIELD (t))
@@ -4771,7 +4818,7 @@ finish_struct_1 (t)
TYPE_VFIELD (t) = vfield;
}
- if (flag_rtti && TYPE_POLYMORPHIC_P (t) && !pending_hard_virtuals)
+ if (flag_rtti && TYPE_CONTAINS_VPTR_P (t) && !pending_hard_virtuals)
modify_all_vtables (t, NULL_TREE);
for (pending_hard_virtuals = nreverse (pending_hard_virtuals);
@@ -4802,9 +4849,9 @@ finish_struct_1 (t)
}
}
- /* Under our model of GC, every C++ class gets its own virtual
- function table, at least virtually. */
- if (pending_virtuals)
+ /* If necessary, create the vtable for this class. */
+ if (pending_virtuals
+ || (TYPE_CONTAINS_VPTR_P (t) && vptrs_present_everywhere_p ()))
{
pending_virtuals = nreverse (pending_virtuals);
/* We must enter these virtuals into the table. */
@@ -4836,6 +4883,8 @@ finish_struct_1 (t)
CLASSTYPE_NEEDS_VIRTUAL_REINIT (t) = 1;
}
+ /* If we didn't need a new vtable, see if we should copy one from
+ the base. */
else if (CLASSTYPE_HAS_PRIMARY_BASE_P (t))
{
tree binfo = CLASSTYPE_PRIMARY_BINFO (t);
@@ -4855,7 +4904,7 @@ finish_struct_1 (t)
CLASSTYPE_NEEDS_VIRTUAL_REINIT (t) = 1;
}
- if (TYPE_POLYMORPHIC_P (t))
+ if (TYPE_CONTAINS_VPTR_P (t))
{
CLASSTYPE_VSIZE (t) = has_virtual;
if (CLASSTYPE_HAS_PRIMARY_BASE_P (t))
@@ -6004,7 +6053,7 @@ get_vfield_name (type)
char *buf;
while (BINFO_BASETYPES (binfo)
- && TYPE_POLYMORPHIC_P (BINFO_TYPE (BINFO_BASETYPE (binfo, 0)))
+ && TYPE_CONTAINS_VPTR_P (BINFO_TYPE (BINFO_BASETYPE (binfo, 0)))
&& ! TREE_VIA_VIRTUAL (BINFO_BASETYPE (binfo, 0)))
binfo = BINFO_BASETYPE (binfo, 0);