Commit 9d4c0187 by Mark Mitchell Committed by Mark Mitchell

class.c (build_vbase_path): Simplify.

	* class.c (build_vbase_path): Simplify.
	(dfs_propagate_binfo_offsets): New function.
	(propagate_binfo_offsets): Use it.
	(remove_base_field): Simplify.
	(dfs_set_offset_for_vbases): Remove.
	(dfs_set_offset_for_shared_vbases): New function.
	(dfs_set_offset_for_unshared_vbases): Likewise.
	(layout_virtual_bases): Use them.
	(layout_basetypes): Don't call propagate_binfo_offsets.
	* search.c (dfs_get_vbase_types): Clone completely fresh binfos
	for the vbases.

From-SVN: r31316
parent d77249e7
2000-01-10 Mark Mitchell <mitchell@dumbledore.codesourcery.com> 2000-01-10 Mark Mitchell <mitchell@dumbledore.codesourcery.com>
* class.c (build_vbase_path): Simplify.
(dfs_propagate_binfo_offsets): New function.
(propagate_binfo_offsets): Use it.
(remove_base_field): Simplify.
(dfs_set_offset_for_vbases): Remove.
(dfs_set_offset_for_shared_vbases): New function.
(dfs_set_offset_for_unshared_vbases): Likewise.
(layout_virtual_bases): Use them.
(layout_basetypes): Don't call propagate_binfo_offsets.
* search.c (dfs_get_vbase_types): Clone completely fresh binfos
for the vbases.
* class.c (build_base_field): New function, split out from ... * class.c (build_base_field): New function, split out from ...
(build_base_fields): ... here. Use it. Allocate primary bases (build_base_fields): ... here. Use it. Allocate primary bases
first, under the new ABI. first, under the new ABI.
......
...@@ -138,12 +138,14 @@ static void layout_class_type PROTO((tree, int *, int *, tree *, tree *)); ...@@ -138,12 +138,14 @@ static void layout_class_type PROTO((tree, int *, int *, tree *, tree *));
static void fixup_pending_inline PROTO((struct pending_inline *)); static void fixup_pending_inline PROTO((struct pending_inline *));
static void fixup_inline_methods PROTO((tree)); static void fixup_inline_methods PROTO((tree));
static void set_primary_base PROTO((tree, int, int *)); static void set_primary_base PROTO((tree, int, int *));
static void dfs_propagate_binfo_offsets PROTO((tree, tree));
static void propagate_binfo_offsets PROTO((tree, tree)); static void propagate_binfo_offsets PROTO((tree, tree));
static void layout_basetypes PROTO((tree)); static void layout_basetypes PROTO((tree));
static tree dfs_set_offset_for_vbases PROTO((tree, void *));
static void layout_virtual_bases PROTO((tree)); static void layout_virtual_bases PROTO((tree));
static void remove_base_field PROTO((tree, tree, tree *)); static void remove_base_field PROTO((tree, tree, tree *));
static void remove_base_fields PROTO((tree)); static void remove_base_fields PROTO((tree));
static void dfs_set_offset_for_shared_vbases PROTO((tree, void *));
static void dfs_set_offset_for_unshared_vbases PROTO((tree, void *));
/* Variables shared between class.c and call.c. */ /* Variables shared between class.c and call.c. */
...@@ -335,16 +337,7 @@ build_vbase_path (code, type, expr, path, nonnull) ...@@ -335,16 +337,7 @@ build_vbase_path (code, type, expr, path, nonnull)
} }
} }
else else
{
if (last_virtual)
{
offset = BINFO_OFFSET (BINFO_FOR_VBASE (last_virtual,
basetype));
offset = size_binop (PLUS_EXPR, offset, BINFO_OFFSET (last));
}
else
offset = BINFO_OFFSET (last); offset = BINFO_OFFSET (last);
}
if (TREE_INT_CST_LOW (offset)) if (TREE_INT_CST_LOW (offset))
{ {
...@@ -4142,7 +4135,26 @@ fixup_inline_methods (type) ...@@ -4142,7 +4135,26 @@ fixup_inline_methods (type)
CLASSTYPE_INLINE_FRIENDS (type) = NULL_TREE; CLASSTYPE_INLINE_FRIENDS (type) = NULL_TREE;
} }
/* Add OFFSET to all base types of T. /* 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. */
BINFO_OFFSET (binfo)
= size_binop (PLUS_EXPR, 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. OFFSET, which is a type offset, is number of bytes.
...@@ -4154,87 +4166,14 @@ propagate_binfo_offsets (binfo, offset) ...@@ -4154,87 +4166,14 @@ propagate_binfo_offsets (binfo, offset)
tree binfo; tree binfo;
tree offset; tree offset;
{ {
tree binfos = BINFO_BASETYPES (binfo); dfs_walk (binfo,
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0; dfs_propagate_binfo_offsets,
dfs_skip_nonprimary_vbases_unmarkedp,
if (flag_new_abi) offset);
{ dfs_walk (binfo,
for (i = 0; i < n_baselinks; ++i) dfs_unmark,
{ dfs_skip_nonprimary_vbases_markedp,
tree base_binfo; NULL);
/* Figure out which base we're looking at. */
base_binfo = TREE_VEC_ELT (binfos, i);
/* Skip non-primary virtual bases. Their BINFO_OFFSET
doesn't matter since they are always reached by using
offsets looked up at run-time. */
if (TREE_VIA_VIRTUAL (base_binfo)
&& i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo)))
continue;
/* Whatever offset this class used to have in its immediate
derived class, it is now at OFFSET more bytes in its
final derived class, since the immediate derived class is
already at the indicated OFFSET. */
BINFO_OFFSET (base_binfo)
= size_binop (PLUS_EXPR, BINFO_OFFSET (base_binfo), offset);
propagate_binfo_offsets (base_binfo, offset);
}
}
else
{
/* This algorithm, used for the old ABI, is neither simple, nor
general. For example, it mishandles the case of:
struct A;
struct B : public A;
struct C : public B;
if B is at offset zero in C, but A is not in offset zero in
B. In that case, it sets the BINFO_OFFSET for A to zero.
(This sitution arises in the new ABI if B has virtual
functions, but A does not.) Rather than change this
algorithm, and risking breaking the old ABI, it is preserved
here. */
for (i = 0; i < n_baselinks; /* note increment is done in the
loop. */)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
if (TREE_VIA_VIRTUAL (base_binfo))
i += 1;
else
{
int j;
tree delta = NULL_TREE;
for (j = i+1; j < n_baselinks; j++)
if (! TREE_VIA_VIRTUAL (TREE_VEC_ELT (binfos, j)))
{
/* The next basetype offset must take into account
the space between the classes, not just the
size of each class. */
delta = size_binop (MINUS_EXPR,
BINFO_OFFSET (TREE_VEC_ELT (binfos,
j)),
BINFO_OFFSET (base_binfo));
break;
}
BINFO_OFFSET (base_binfo) = offset;
propagate_binfo_offsets (base_binfo, offset);
/* Go to our next class that counts for offset
propagation. */
i = j;
if (i < n_baselinks)
offset = size_binop (PLUS_EXPR, offset, delta);
}
}
}
} }
/* Remove *FIELD (which corresponds to the base given by BINFO) from /* Remove *FIELD (which corresponds to the base given by BINFO) from
...@@ -4258,7 +4197,6 @@ remove_base_field (t, binfo, field) ...@@ -4258,7 +4197,6 @@ remove_base_field (t, binfo, field)
offset offset
= size_int (CEIL (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (*field)), = size_int (CEIL (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (*field)),
BITS_PER_UNIT)); BITS_PER_UNIT));
BINFO_OFFSET (binfo) = offset;
propagate_binfo_offsets (binfo, offset); propagate_binfo_offsets (binfo, offset);
/* Remove this field. */ /* Remove this field. */
...@@ -4317,27 +4255,47 @@ remove_base_fields (t) ...@@ -4317,27 +4255,47 @@ remove_base_fields (t)
} }
} }
/* Called via dfs_walk from layout_virtual_bases. */ /* Called via dfs_walk from layout_virtual bases. */
static tree static tree
dfs_set_offset_for_vbases (binfo, data) dfs_set_offset_for_shared_vbases (binfo, data)
tree binfo; tree binfo;
void *data; void *data;
{ {
/* If this is a primary virtual base that we have not encountered if (TREE_VIA_VIRTUAL (binfo) && BINFO_PRIMARY_MARKED_P (binfo))
before, give it an offset. */
if (TREE_VIA_VIRTUAL (binfo)
&& BINFO_PRIMARY_MARKED_P (binfo)
&& !BINFO_MARKED (binfo))
{ {
tree vbase; /* Update the shared copy. */
tree shared_binfo;
vbase = BINFO_FOR_VBASE (BINFO_TYPE (binfo), (tree) data); shared_binfo = BINFO_FOR_VBASE (BINFO_TYPE (binfo), (tree) data);
BINFO_OFFSET (vbase) = BINFO_OFFSET (binfo); BINFO_OFFSET (shared_binfo) = BINFO_OFFSET (binfo);
SET_BINFO_VBASE_MARKED (binfo);
} }
SET_BINFO_MARKED (binfo); return NULL_TREE;
}
/* Called via dfs_walk from layout_virtual bases. */
static tree
dfs_set_offset_for_unshared_vbases (binfo, data)
tree binfo;
void *data;
{
/* If this is a virtual base, make sure it has the same offset as
the shared copy. If it's a primary base, then we know it's
correct. */
if (TREE_VIA_VIRTUAL (binfo) && !BINFO_PRIMARY_MARKED_P (binfo))
{
tree t = (tree) data;
tree vbase;
tree offset;
vbase = BINFO_FOR_VBASE (BINFO_TYPE (binfo), t);
offset = ssize_binop (MINUS_EXPR,
BINFO_OFFSET (vbase),
BINFO_OFFSET (binfo));
propagate_binfo_offsets (binfo, offset);
}
return NULL_TREE; return NULL_TREE;
} }
...@@ -4357,10 +4315,12 @@ layout_virtual_bases (t) ...@@ -4357,10 +4315,12 @@ layout_virtual_bases (t)
/* Make every class have alignment of at least one. */ /* Make every class have alignment of at least one. */
TYPE_ALIGN (t) = MAX (TYPE_ALIGN (t), BITS_PER_UNIT); TYPE_ALIGN (t) = MAX (TYPE_ALIGN (t), BITS_PER_UNIT);
/* Go through the virtual bases, allocating space for each virtual
base that is not already a primary base class. */
for (vbase = CLASSTYPE_VBASECLASSES (t); for (vbase = CLASSTYPE_VBASECLASSES (t);
vbase; vbase;
vbase = TREE_CHAIN (vbase)) vbase = TREE_CHAIN (vbase))
if (!BINFO_PRIMARY_MARKED_P (vbase)) if (!BINFO_VBASE_PRIMARY_P (vbase))
{ {
/* This virtual base is not a primary base of any class in the /* This virtual base is not a primary base of any class in the
hierarchy, so we have to add space for it. */ hierarchy, so we have to add space for it. */
...@@ -4375,24 +4335,36 @@ layout_virtual_bases (t) ...@@ -4375,24 +4335,36 @@ layout_virtual_bases (t)
appropriately aligned offset. */ appropriately aligned offset. */
dsize = CEIL (dsize, desired_align) * desired_align; dsize = CEIL (dsize, desired_align) * desired_align;
/* And compute the offset of the virtual base. */ /* And compute the offset of the virtual base. */
BINFO_OFFSET (vbase) = size_int (CEIL (dsize, BITS_PER_UNIT)); propagate_binfo_offsets (vbase,
size_int (CEIL (dsize, BITS_PER_UNIT)));
/* Every virtual baseclass takes a least a UNIT, so that we can /* Every virtual baseclass takes a least a UNIT, so that we can
take it's address and get something different for each base. */ take it's address and get something different for each base. */
dsize += MAX (BITS_PER_UNIT, dsize += MAX (BITS_PER_UNIT,
TREE_INT_CST_LOW (CLASSTYPE_SIZE (basetype))); TREE_INT_CST_LOW (CLASSTYPE_SIZE (basetype)));
} }
/* 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
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);
/* Now, make sure that the total size of the type is a multiple of /* Now, make sure that the total size of the type is a multiple of
its alignment. */ its alignment. */
dsize = CEIL (dsize, TYPE_ALIGN (t)) * TYPE_ALIGN (t); dsize = CEIL (dsize, TYPE_ALIGN (t)) * TYPE_ALIGN (t);
TYPE_SIZE (t) = size_int (dsize); TYPE_SIZE (t) = size_int (dsize);
TYPE_SIZE_UNIT (t) = size_binop (FLOOR_DIV_EXPR, TYPE_SIZE (t), TYPE_SIZE_UNIT (t) = size_binop (FLOOR_DIV_EXPR, TYPE_SIZE (t),
size_int (BITS_PER_UNIT)); 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. /* Finish the work of layout_record, now taking virtual bases into account.
...@@ -4426,9 +4398,6 @@ layout_basetypes (rec) ...@@ -4426,9 +4398,6 @@ layout_basetypes (rec)
the vbase_types are unshared. */ the vbase_types are unshared. */
for (vbase_types = CLASSTYPE_VBASECLASSES (rec); vbase_types; for (vbase_types = CLASSTYPE_VBASECLASSES (rec); vbase_types;
vbase_types = TREE_CHAIN (vbase_types)) vbase_types = TREE_CHAIN (vbase_types))
{
propagate_binfo_offsets (vbase_types, BINFO_OFFSET (vbase_types));
if (extra_warnings) if (extra_warnings)
{ {
tree basetype = BINFO_TYPE (vbase_types); tree basetype = BINFO_TYPE (vbase_types);
...@@ -4436,7 +4405,6 @@ layout_basetypes (rec) ...@@ -4436,7 +4405,6 @@ layout_basetypes (rec)
cp_warning ("virtual base `%T' inaccessible in `%T' due to ambiguity", cp_warning ("virtual base `%T' inaccessible in `%T' due to ambiguity",
basetype, rec); basetype, rec);
} }
}
} }
/* Calculate the TYPE_SIZE, TYPE_ALIGN, etc for T. Calculate /* Calculate the TYPE_SIZE, TYPE_ALIGN, etc for T. Calculate
......
...@@ -3046,7 +3046,8 @@ dfs_get_vbase_types (binfo, data) ...@@ -3046,7 +3046,8 @@ dfs_get_vbase_types (binfo, data)
if (TREE_VIA_VIRTUAL (binfo) && ! BINFO_VBASE_MARKED (binfo)) if (TREE_VIA_VIRTUAL (binfo) && ! BINFO_VBASE_MARKED (binfo))
{ {
tree new_vbase = make_binfo (integer_zero_node, binfo, tree new_vbase = make_binfo (integer_zero_node,
BINFO_TYPE (binfo),
BINFO_VTABLE (binfo), BINFO_VTABLE (binfo),
BINFO_VIRTUALS (binfo)); BINFO_VIRTUALS (binfo));
unshare_base_binfos (new_vbase); unshare_base_binfos (new_vbase);
......
// Build don't link: // Build don't link:
// Copyright (C) 1999 Free Software Foundation, Inc. // Copyright (C) 1999, 2000 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 29 Aug 1999 <nathan@acm.org> // Contributed by Nathan Sidwell 29 Aug 1999 <nathan@acm.org>
// We should spot all ambiguities // We should spot all ambiguities
...@@ -14,7 +14,7 @@ struct D3 : B, C { int m; }; ...@@ -14,7 +14,7 @@ struct D3 : B, C { int m; };
void fn(D0 *d0, D1 *d1, D2 *d2, D3 *d3) void fn(D0 *d0, D1 *d1, D2 *d2, D3 *d3)
{ {
A *a0 = d0; // ERROR - A is an ambiguous base XFAIL A *a0 = d0; // ERROR - A is an ambiguous base
A *a1 = d1; // ERROR - A is an ambiguous base A *a1 = d1; // ERROR - A is an ambiguous base
A *a2 = d2; // ERROR - A is an ambiguous base A *a2 = d2; // ERROR - A is an ambiguous base
A *a3 = d3; // ERROR - A is an ambiguous base A *a3 = d3; // ERROR - A is an ambiguous base
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment