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.c199
1 files changed, 89 insertions, 110 deletions
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index edb0e3d..0a8fbf7 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -102,9 +102,9 @@ static void check_for_override PROTO((tree, tree));
static tree get_class_offset_1 PROTO((tree, tree, tree, tree, tree));
static tree get_class_offset PROTO((tree, tree, tree, tree));
static void modify_one_vtable PROTO((tree, tree, tree));
+static tree dfs_modify_vtables_queue_p PROTO((tree, void *));
+static tree dfs_modify_vtables PROTO((tree, void *));
static void modify_all_vtables PROTO((tree, tree));
-static void modify_all_direct_vtables PROTO((tree, int, tree, tree));
-static void modify_all_indirect_vtables PROTO((tree, int, int, tree, tree));
static void determine_primary_base PROTO((tree, int *));
static void finish_struct_methods PROTO((tree));
static void maybe_warn_about_overly_private_class PROTO ((tree));
@@ -138,7 +138,7 @@ static void fixup_inline_methods PROTO((tree));
static void set_primary_base PROTO((tree, int, int *));
static void propagate_binfo_offsets PROTO((tree, tree));
static void layout_basetypes PROTO((tree));
-static tree dfs_mark_primary_bases_and_set_vbase_offsets PROTO((tree, void *));
+static tree dfs_set_offset_for_vbases PROTO((tree, void *));
static void layout_virtual_bases PROTO((tree));
static void remove_base_fields PROTO((tree));
@@ -1651,6 +1651,10 @@ determine_primary_base (t, has_virtual_p)
{
int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (t);
+ /* If there are no baseclasses, there is certainly no primary base. */
+ if (n_baseclasses == 0)
+ return;
+
*has_virtual_p = 0;
for (i = 0; i < n_baseclasses; i++)
@@ -1666,7 +1670,9 @@ determine_primary_base (t, has_virtual_p)
if (!CLASSTYPE_HAS_PRIMARY_BASE_P (t))
CLASSTYPE_RTTI (t) = CLASSTYPE_RTTI (basetype);
- /* A virtual baseclass can't be the primary base. */
+ /* A virtual baseclass can't be the primary base under the
+ old ABI. And under the new ABI we still prefer a
+ non-virtual base. */
if (TREE_VIA_VIRTUAL (base_binfo))
continue;
@@ -1698,6 +1704,11 @@ determine_primary_base (t, has_virtual_p)
if (!TYPE_VFIELD (t))
CLASSTYPE_VFIELD_PARENT (t) = -1;
+
+ /* Now that we know what the primary base class is, we can run
+ through the entire hierarchy marking the primary bases for future
+ reference. */
+ mark_primary_bases (t);
}
/* Set memoizing fields and bits of T (and its variants) for later
@@ -2479,29 +2490,63 @@ modify_one_vtable (binfo, t, fndecl)
}
}
-/* These are the ones that are not through virtual base classes. */
+/* Called from modify_all_vtables via dfs_walk. */
-static void
-modify_all_direct_vtables (binfo, do_self, t, fndecl)
+static tree
+dfs_modify_vtables_queue_p (binfo, data)
tree binfo;
- int do_self;
- tree t, fndecl;
+ void *data;
{
- tree binfos = BINFO_BASETYPES (binfo);
- int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+ tree list = (tree) data;
- /* Should we use something besides CLASSTYPE_VFIELDS? */
- if (do_self && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
- modify_one_vtable (binfo, t, fndecl);
+ if (TREE_VIA_VIRTUAL (binfo))
+ binfo = BINFO_FOR_VBASE (BINFO_TYPE (binfo), TREE_PURPOSE (list));
- for (i = 0; i < n_baselinks; i++)
+ return (TREE_ADDRESSABLE (list)
+ ? markedp (binfo, NULL)
+ : unmarkedp (binfo, NULL));
+}
+
+/* Called from modify_all_vtables via dfs_walk. */
+
+static tree
+dfs_modify_vtables (binfo, data)
+ tree binfo;
+ void *data;
+{
+ if (/* There's no need to modify the vtable for a primary base;
+ we're not going to use that vtable anyhow. */
+ !BINFO_PRIMARY_MARKED_P (binfo)
+ /* Similarly, a base without a vtable needs no modification. */
+ && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
{
- tree base_binfo = TREE_VEC_ELT (binfos, i);
- int is_not_base_vtable
- = i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
- if (! TREE_VIA_VIRTUAL (base_binfo))
- modify_all_direct_vtables (base_binfo, is_not_base_vtable, t, fndecl);
+ tree list = (tree) data;
+
+ if (TREE_VIA_VIRTUAL (binfo))
+ binfo = BINFO_FOR_VBASE (BINFO_TYPE (binfo), TREE_PURPOSE (list));
+ modify_one_vtable (binfo, TREE_PURPOSE (list), TREE_VALUE (list));
}
+
+ SET_BINFO_MARKED (binfo);
+
+ return NULL_TREE;
+}
+
+static void
+modify_all_vtables (t, fndecl)
+ tree t;
+ tree fndecl;
+{
+ tree list;
+
+ list = build_tree_list (t, fndecl);
+ dfs_walk (TYPE_BINFO (t), dfs_modify_vtables, dfs_modify_vtables_queue_p,
+ list);
+ /* Let dfs_modify_vtables_queue_p know to check that the mark is
+ present before queueing a base, rather than checking to see that
+ it is *not* present. */
+ TREE_ADDRESSABLE (list) = 1;
+ dfs_walk (TYPE_BINFO (t), dfs_unmark, dfs_modify_vtables_queue_p, list);
}
/* Fixup all the delta entries in this one vtable that need updating. */
@@ -2595,47 +2640,6 @@ fixup_vtable_deltas (binfo, init_self, t)
fixup_vtable_deltas1 (binfo, t);
}
-/* These are the ones that are through virtual base classes. */
-
-static void
-modify_all_indirect_vtables (binfo, do_self, via_virtual, t, fndecl)
- tree binfo;
- int do_self, via_virtual;
- tree t, fndecl;
-{
- tree binfos = BINFO_BASETYPES (binfo);
- int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-
- /* Should we use something besides CLASSTYPE_VFIELDS? */
- if (do_self && via_virtual && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
- modify_one_vtable (binfo, t, fndecl);
-
- for (i = 0; i < n_baselinks; i++)
- {
- tree base_binfo = TREE_VEC_ELT (binfos, i);
- int is_not_base_vtable
- = i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
- if (TREE_VIA_VIRTUAL (base_binfo))
- {
- via_virtual = 1;
- base_binfo = BINFO_FOR_VBASE (BINFO_TYPE (base_binfo), t);
- }
- modify_all_indirect_vtables (base_binfo, is_not_base_vtable, via_virtual, t, fndecl);
- }
-}
-
-static void
-modify_all_vtables (t, fndecl)
- tree t;
- tree fndecl;
-{
- /* Do these first, so that we will make use of any non-virtual class's
- vtable, over a virtual classes vtable. */
- modify_all_direct_vtables (TYPE_BINFO (t), 1, t, fndecl);
- if (TYPE_USES_VIRTUAL_BASECLASSES (t))
- modify_all_indirect_vtables (TYPE_BINFO (t), 1, 0, t, fndecl);
-}
-
/* Here, we already know that they match in every respect.
All we have to check is where they had their declarations. */
@@ -3765,7 +3769,11 @@ build_base_fields (rec, empty_p)
location information. */
continue;
- if (TREE_VIA_VIRTUAL (base_binfo))
+ /* A primary virtual base class is allocated just like any other
+ base class, but a non-primary virtual base is allocated
+ later, in layout_basetypes. */
+ if (TREE_VIA_VIRTUAL (base_binfo)
+ && i != CLASSTYPE_VFIELD_PARENT (rec))
continue;
decl = build_lang_decl (FIELD_DECL, NULL_TREE, basetype);
@@ -3998,12 +4006,6 @@ create_vtable_ptr (t, empty_p, has_virtual_p,
{
tree fn;
- /* If possible, we reuse the virtual function table pointer from one
- of our base classes. */
- if (CLASSTYPE_N_BASECLASSES (t))
- /* Remember where we got our vfield from. */
- determine_primary_base (t, has_virtual_p);
-
/* Loop over the virtual functions, adding them to our various
vtables. */
for (fn = TYPE_METHODS (t); fn; fn = TREE_CHAIN (fn))
@@ -4270,31 +4272,21 @@ remove_base_fields (t)
/* Called via dfs_walk from layout_virtual_bases. */
static tree
-dfs_mark_primary_bases_and_set_vbase_offsets (binfo, data)
+dfs_set_offset_for_vbases (binfo, data)
tree binfo;
void *data;
{
- if (CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (binfo)))
+ /* If this is a primary virtual base that we have not encountered
+ before, give it an offset. */
+ if (TREE_VIA_VIRTUAL (binfo)
+ && BINFO_PRIMARY_MARKED_P (binfo)
+ && !BINFO_MARKED (binfo))
{
- int i;
- tree base_binfo;
-
- i = CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
- base_binfo = BINFO_BASETYPE (binfo, i);
-
- /* If this is a virtual base class, and we've just now
- discovered it to be a primary base, then reuse this copy as
- the virtual base class for the complete object. */
- if (TREE_VIA_VIRTUAL (base_binfo)
- && !BINFO_PRIMARY_MARKED_P (base_binfo))
- {
- tree vbase;
-
- vbase = BINFO_FOR_VBASE (BINFO_TYPE (base_binfo), (tree) data);
- BINFO_OFFSET (vbase) = BINFO_OFFSET (base_binfo);
- }
+ tree vbase;
- SET_BINFO_PRIMARY_MARKED_P (BINFO_BASETYPE (binfo, i));
+ vbase = BINFO_FOR_VBASE (BINFO_TYPE (binfo), (tree) data);
+ BINFO_OFFSET (vbase) = BINFO_OFFSET (binfo);
+ SET_BINFO_VBASE_MARKED (binfo);
}
SET_BINFO_MARKED (binfo);
@@ -4312,15 +4304,6 @@ layout_virtual_bases (t)
tree vbase;
int dsize;
- /* Mark the primary base classes. Only virtual bases that are not
- also primary base classes need to be laid out (since otherwise we
- can just reuse one of the places in the hierarchy where the
- virtual base already occurs.) */
- dfs_walk (TYPE_BINFO (t),
- dfs_mark_primary_bases_and_set_vbase_offsets,
- dfs_mark_primary_bases_queue_p,
- t);
-
/* DSIZE is the size of the class without the virtual bases. */
dsize = TREE_INT_CST_LOW (TYPE_SIZE (t));
/* Make every class have alignment of at least one. */
@@ -4349,27 +4332,19 @@ layout_virtual_bases (t)
take it's address and get something different for each base. */
dsize += MAX (BITS_PER_UNIT,
TREE_INT_CST_LOW (CLASSTYPE_SIZE (basetype)));
-
- /* Now that we've laid out this virtual base class, some of
- the remaining virtual bases might have been implicitly laid
- out as well -- they could be primary base classes of
- classes in BASETYPE. */
- dfs_walk (vbase,
- dfs_mark_primary_bases_and_set_vbase_offsets,
- dfs_mark_primary_bases_queue_p,
- t);
}
- /* We're done with the various marks, now, so clear them. */
- unmark_primary_bases (t);
- dfs_walk (TYPE_BINFO (t), dfs_unmark, markedp, 0);
-
/* Now, make sure that the total size of the type is a multiple of
its alignment. */
dsize = CEIL (dsize, TYPE_ALIGN (t)) * TYPE_ALIGN (t);
TYPE_SIZE (t) = size_int (dsize);
TYPE_SIZE_UNIT (t) = size_binop (FLOOR_DIV_EXPR, TYPE_SIZE (t),
size_int (BITS_PER_UNIT));
+
+ /* Run through the hierarchy now, setting up all the BINFO_OFFSETs
+ for those virtual base classes that we did not allocate above. */
+ dfs_walk (TYPE_BINFO (t), dfs_set_offset_for_vbases, unmarkedp, t);
+ dfs_walk (TYPE_BINFO (t), dfs_vbase_unmark, markedp, NULL);
}
/* Finish the work of layout_record, now taking virtual bases into account.
@@ -4431,6 +4406,10 @@ layout_class_type (t, empty_p, has_virtual_p,
tree *pending_virtuals_p;
tree *pending_hard_virtuals_p;
{
+ /* If possible, we reuse the virtual function table pointer from one
+ of our base classes. */
+ determine_primary_base (t, has_virtual_p);
+
/* Add pointers to all of our virtual base-classes. */
TYPE_FIELDS (t) = chainon (build_vbase_pointer_fields (t, empty_p),
TYPE_FIELDS (t));