This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH: correct BINFO_OFFSETs
- To: gcc-patches at gcc dot gnu dot org
- Subject: C++ PATCH: correct BINFO_OFFSETs
- From: Mark Mitchell <mark at codesourcery dot com>
- Date: Mon, 10 Jan 2000 20:18:39 -0800
- Reply-to: mark at codesourcery dot com
BINFO_OFFSET was not being set correctly for all bases. That's what
was causing us to miss an error in `ambig2.C'. This patch fixes that,
and makes it easier to calculate relative positions of bases, etc.
--
Mark Mitchell mark@codesourcery.com
CodeSourcery, LLC http://www.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.
Index: testsuite/g++.old-deja/g++.other/ambig2.C
===================================================================
RCS file: /cvs/gcc/egcs/gcc/testsuite/g++.old-deja/g++.other/ambig2.C,v
retrieving revision 1.3
diff -c -p -r1.3 ambig2.C
*** ambig2.C 1999/09/08 08:50:57 1.3
--- ambig2.C 2000/01/11 04:12:19
***************
*** 1,5 ****
// Build don't link:
! // Copyright (C) 1999 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 29 Aug 1999 <nathan@acm.org>
// We should spot all ambiguities
--- 1,5 ----
// Build don't link:
! // Copyright (C) 1999, 2000 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 29 Aug 1999 <nathan@acm.org>
// We should spot all ambiguities
*************** struct D3 : B, C { int m; };
*** 14,20 ****
void fn(D0 *d0, D1 *d1, D2 *d2, D3 *d3)
{
! A *a0 = d0; // ERROR - A is an ambiguous base XFAIL
A *a1 = d1; // ERROR - A is an ambiguous base
A *a2 = d2; // ERROR - A is an ambiguous base
A *a3 = d3; // ERROR - A is an ambiguous base
--- 14,20 ----
void fn(D0 *d0, D1 *d1, D2 *d2, D3 *d3)
{
! A *a0 = d0; // 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 *a3 = d3; // ERROR - A is an ambiguous base
Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/class.c,v
retrieving revision 1.226
diff -c -p -r1.226 class.c
*** class.c 2000/01/11 03:15:32 1.226
--- class.c 2000/01/11 04:12:36
*************** static void layout_class_type PROTO((tre
*** 138,149 ****
static void fixup_pending_inline PROTO((struct pending_inline *));
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_set_offset_for_vbases PROTO((tree, void *));
static void layout_virtual_bases PROTO((tree));
static void remove_base_field PROTO((tree, tree, tree *));
static void remove_base_fields PROTO((tree));
/* Variables shared between class.c and call.c. */
--- 138,151 ----
static void fixup_pending_inline PROTO((struct pending_inline *));
static void fixup_inline_methods PROTO((tree));
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 layout_basetypes PROTO((tree));
static void layout_virtual_bases PROTO((tree));
static void remove_base_field PROTO((tree, tree, 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. */
*************** build_vbase_path (code, type, expr, path
*** 335,350 ****
}
}
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);
! }
if (TREE_INT_CST_LOW (offset))
{
--- 337,343 ----
}
}
else
! offset = BINFO_OFFSET (last);
if (TREE_INT_CST_LOW (offset))
{
*************** fixup_inline_methods (type)
*** 4141,4148 ****
fixup_pending_inline (DECL_PENDING_INLINE_INFO (TREE_VALUE (method)));
CLASSTYPE_INLINE_FRIENDS (type) = NULL_TREE;
}
! /* Add OFFSET to all base types of T.
OFFSET, which is a type offset, is number of bytes.
--- 4134,4160 ----
fixup_pending_inline (DECL_PENDING_INLINE_INFO (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. */
+ 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.
*************** propagate_binfo_offsets (binfo, offset)
*** 4154,4240 ****
tree binfo;
tree offset;
{
! tree binfos = BINFO_BASETYPES (binfo);
! int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
!
! if (flag_new_abi)
! {
! for (i = 0; i < n_baselinks; ++i)
! {
! tree base_binfo;
!
! /* 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
--- 4166,4179 ----
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);
}
/* Remove *FIELD (which corresponds to the base given by BINFO) from
*************** remove_base_field (t, binfo, field)
*** 4258,4264 ****
offset
= size_int (CEIL (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (*field)),
BITS_PER_UNIT));
- BINFO_OFFSET (binfo) = offset;
propagate_binfo_offsets (binfo, offset);
/* Remove this field. */
--- 4197,4202 ----
*************** remove_base_fields (t)
*** 4317,4343 ****
}
}
! /* Called via dfs_walk from layout_virtual_bases. */
static tree
! dfs_set_offset_for_vbases (binfo, data)
tree binfo;
void *data;
{
! /* 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))
{
! tree vbase;
! vbase = BINFO_FOR_VBASE (BINFO_TYPE (binfo), (tree) data);
! BINFO_OFFSET (vbase) = BINFO_OFFSET (binfo);
! SET_BINFO_VBASE_MARKED (binfo);
}
! SET_BINFO_MARKED (binfo);
return NULL_TREE;
}
--- 4255,4301 ----
}
}
! /* Called via dfs_walk from layout_virtual bases. */
static tree
! dfs_set_offset_for_shared_vbases (binfo, data)
tree binfo;
void *data;
{
! if (TREE_VIA_VIRTUAL (binfo) && BINFO_PRIMARY_MARKED_P (binfo))
{
! /* Update the shared copy. */
! tree shared_binfo;
! shared_binfo = BINFO_FOR_VBASE (BINFO_TYPE (binfo), (tree) data);
! BINFO_OFFSET (shared_binfo) = BINFO_OFFSET (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;
}
*************** layout_virtual_bases (t)
*** 4357,4366 ****
/* Make every class have alignment of at least one. */
TYPE_ALIGN (t) = MAX (TYPE_ALIGN (t), BITS_PER_UNIT);
for (vbase = CLASSTYPE_VBASECLASSES (t);
vbase;
vbase = TREE_CHAIN (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. */
--- 4315,4326 ----
/* Make every class have alignment of at least one. */
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);
vbase;
vbase = TREE_CHAIN (vbase))
! if (!BINFO_VBASE_PRIMARY_P (vbase))
{
/* This virtual base is not a primary base of any class in the
hierarchy, so we have to add space for it. */
*************** layout_virtual_bases (t)
*** 4375,4398 ****
appropriately aligned offset. */
dsize = CEIL (dsize, desired_align) * desired_align;
/* And compute the offset of the virtual base. */
! BINFO_OFFSET (vbase) = size_int (CEIL (dsize, BITS_PER_UNIT));
/* Every virtual baseclass takes a least a UNIT, so that we can
take it's address and get something different for each base. */
dsize += MAX (BITS_PER_UNIT,
TREE_INT_CST_LOW (CLASSTYPE_SIZE (basetype)));
}
/* 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.
--- 4335,4370 ----
appropriately aligned offset. */
dsize = CEIL (dsize, desired_align) * desired_align;
/* And compute the offset of the virtual base. */
! propagate_binfo_offsets (vbase,
! size_int (CEIL (dsize, BITS_PER_UNIT)));
/* Every virtual baseclass takes a least a UNIT, so that we can
take it's address and get something different for each base. */
dsize += MAX (BITS_PER_UNIT,
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
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));
}
/* Finish the work of layout_record, now taking virtual bases into account.
*************** layout_basetypes (rec)
*** 4426,4442 ****
the vbase_types are unshared. */
for (vbase_types = CLASSTYPE_VBASECLASSES (rec); vbase_types;
vbase_types = TREE_CHAIN (vbase_types))
! {
! propagate_binfo_offsets (vbase_types, BINFO_OFFSET (vbase_types));
!
! if (extra_warnings)
! {
! tree basetype = BINFO_TYPE (vbase_types);
! if (get_base_distance (basetype, rec, 0, (tree*)0) == -2)
! cp_warning ("virtual base `%T' inaccessible in `%T' due to ambiguity",
! basetype, rec);
! }
! }
}
/* Calculate the TYPE_SIZE, TYPE_ALIGN, etc for T. Calculate
--- 4398,4410 ----
the vbase_types are unshared. */
for (vbase_types = CLASSTYPE_VBASECLASSES (rec); vbase_types;
vbase_types = TREE_CHAIN (vbase_types))
! if (extra_warnings)
! {
! tree basetype = BINFO_TYPE (vbase_types);
! if (get_base_distance (basetype, rec, 0, (tree*)0) == -2)
! cp_warning ("virtual base `%T' inaccessible in `%T' due to ambiguity",
! basetype, rec);
! }
}
/* Calculate the TYPE_SIZE, TYPE_ALIGN, etc for T. Calculate
Index: cp/search.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/search.c,v
retrieving revision 1.144
diff -c -p -r1.144 search.c
*** search.c 2000/01/11 02:43:00 1.144
--- search.c 2000/01/11 04:12:37
*************** dfs_get_vbase_types (binfo, data)
*** 3046,3052 ****
if (TREE_VIA_VIRTUAL (binfo) && ! BINFO_VBASE_MARKED (binfo))
{
! tree new_vbase = make_binfo (integer_zero_node, binfo,
BINFO_VTABLE (binfo),
BINFO_VIRTUALS (binfo));
unshare_base_binfos (new_vbase);
--- 3046,3053 ----
if (TREE_VIA_VIRTUAL (binfo) && ! BINFO_VBASE_MARKED (binfo))
{
! tree new_vbase = make_binfo (integer_zero_node,
! BINFO_TYPE (binfo),
BINFO_VTABLE (binfo),
BINFO_VIRTUALS (binfo));
unshare_base_binfos (new_vbase);