From 9d4c0187c6805870fd437f4973bbf51d1ca064ea Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Tue, 11 Jan 2000 04:13:27 +0000 Subject: [PATCH] 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 --- gcc/cp/ChangeLog | 12 + gcc/cp/class.c | 216 ++++++++---------- gcc/cp/search.c | 3 +- gcc/testsuite/g++.old-deja/g++.other/ambig2.C | 4 +- 4 files changed, 108 insertions(+), 127 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index c291cb527a93..00078c6fc564 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,17 @@ 2000-01-10 Mark Mitchell + * 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 ... (build_base_fields): ... here. Use it. Allocate primary bases first, under the new ABI. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index f2fad7c341c9..ddcd17fbc916 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -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_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 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)); +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. */ @@ -335,16 +337,7 @@ build_vbase_path (code, type, expr, path, nonnull) } } 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)) { @@ -4142,7 +4135,26 @@ fixup_inline_methods (type) 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. @@ -4154,87 +4166,14 @@ propagate_binfo_offsets (binfo, offset) 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); - } - } - } + 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 @@ -4258,7 +4197,6 @@ remove_base_field (t, binfo, field) 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. */ @@ -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 -dfs_set_offset_for_vbases (binfo, data) +dfs_set_offset_for_shared_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)) + if (TREE_VIA_VIRTUAL (binfo) && BINFO_PRIMARY_MARKED_P (binfo)) { - tree vbase; + /* Update the shared copy. */ + tree shared_binfo; - vbase = BINFO_FOR_VBASE (BINFO_TYPE (binfo), (tree) data); - BINFO_OFFSET (vbase) = BINFO_OFFSET (binfo); - SET_BINFO_VBASE_MARKED (binfo); + shared_binfo = BINFO_FOR_VBASE (BINFO_TYPE (binfo), (tree) data); + BINFO_OFFSET (shared_binfo) = BINFO_OFFSET (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; } @@ -4357,10 +4315,12 @@ layout_virtual_bases (t) /* 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_PRIMARY_MARKED_P (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. */ @@ -4375,24 +4335,36 @@ layout_virtual_bases (t) 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)); + 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)); - - /* 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. @@ -4426,17 +4398,13 @@ layout_basetypes (rec) 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); - } - } + 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 diff --git a/gcc/cp/search.c b/gcc/cp/search.c index 335a183fc5b1..abd6867a0f4c 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -3046,7 +3046,8 @@ dfs_get_vbase_types (binfo, data) 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_VIRTUALS (binfo)); unshare_base_binfos (new_vbase); diff --git a/gcc/testsuite/g++.old-deja/g++.other/ambig2.C b/gcc/testsuite/g++.old-deja/g++.other/ambig2.C index 0966566ffcee..764bdd676661 100644 --- a/gcc/testsuite/g++.old-deja/g++.other/ambig2.C +++ b/gcc/testsuite/g++.old-deja/g++.other/ambig2.C @@ -1,5 +1,5 @@ // 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 // We should spot all ambiguities @@ -14,7 +14,7 @@ struct D3 : B, C { int m; }; 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 *a2 = d2; // ERROR - A is an ambiguous base A *a3 = d3; // ERROR - A is an ambiguous base -- 2.43.5