diff options
author | Nathan Sidwell <nathan@codesourcery.com> | 2005-02-14 09:36:35 +0000 |
---|---|---|
committer | Nathan Sidwell <nathan@gcc.gnu.org> | 2005-02-14 09:36:35 +0000 |
commit | 12a669d1e1b3b14f15bf512479c664130f52c89d (patch) | |
tree | 489402919c97378f6127944f463d865fdc1383ad /gcc | |
parent | 90bb1c1f1511ccb29fc3c23fe2ab871c24c6b040 (diff) | |
download | gcc-12a669d1e1b3b14f15bf512479c664130f52c89d.tar.gz |
re PR c++/19891 (Covariant returns are broken)
cp:
PR c++/19891
* class.c (build_simple_base_path): Build the component_ref
directly.
(update_vtable_entry_for_fn): Walk the covariant's binfo chain
rather than using lookup_base.
* search.c (dfs_walk_once): Add non-recursive assert check.
* typeck.c (build_class_member_access_expr): It is possible for
the member type to be both const and volatile.
testsuite:
PR c++/19891
* g++.dg/abi/covariant4.C: New.
From-SVN: r95005
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 11 | ||||
-rw-r--r-- | gcc/cp/class.c | 90 | ||||
-rw-r--r-- | gcc/cp/search.c | 6 | ||||
-rw-r--r-- | gcc/cp/typeck.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/abi/covariant4.C | 46 |
6 files changed, 138 insertions, 22 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index b60b6deaf37..7e39ce13ba3 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +2005-02-11 Nathan Sidwell <nathan@codesourcery.com> + + PR c++/19891 + * class.c (build_simple_base_path): Build the component_ref + directly. + (update_vtable_entry_for_fn): Walk the covariant's binfo chain + rather than using lookup_base. + * search.c (dfs_walk_once): Add non-recursive assert check. + * typeck.c (build_class_member_access_expr): It is possible for + the member type to be both const and volatile. + 2005-02-12 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net> PR c++/14479 diff --git a/gcc/cp/class.c b/gcc/cp/class.c index bfb9ee12237..5207e924c2a 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -408,7 +408,18 @@ build_simple_base_path (tree expr, tree binfo) if (d_binfo == NULL_TREE) { + tree temp; + gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (expr)) == type); + + /* Transform `(a, b).x' into `(*(a, &b)).x', `(a ? b : c).x' + into `(*(a ? &b : &c)).x', and so on. A COND_EXPR is only + an lvalue in the frontend; only _DECLs and _REFs are lvalues + in the backend. */ + temp = unary_complex_lvalue (ADDR_EXPR, expr); + if (temp) + expr = build_indirect_ref (temp, NULL); + return expr; } @@ -421,8 +432,27 @@ build_simple_base_path (tree expr, tree binfo) if (TREE_CODE (field) == FIELD_DECL && DECL_FIELD_IS_BASE (field) && TREE_TYPE (field) == type) - return build_class_member_access_expr (expr, field, - NULL_TREE, false); + { + /* We don't use build_class_member_access_expr here, as that + has unnecessary checks, and more importantly results in + recursive calls to dfs_walk_once. */ + int type_quals = cp_type_quals (TREE_TYPE (expr)); + + expr = build3 (COMPONENT_REF, + cp_build_qualified_type (type, type_quals), + expr, field, NULL_TREE); + expr = fold_if_not_in_template (expr); + + /* Mark the expression const or volatile, as appropriate. + Even though we've dealt with the type above, we still have + to mark the expression itself. */ + if (type_quals & TYPE_QUAL_CONST) + TREE_READONLY (expr) = 1; + if (type_quals & TYPE_QUAL_VOLATILE) + TREE_THIS_VOLATILE (expr) = 1; + + return expr; + } /* Didn't find the base field?!? */ gcc_unreachable (); @@ -1996,6 +2026,9 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals, also be converting to the return type of FN, we have to combine the two conversions here. */ tree fixed_offset, virtual_offset; + + over_return = TREE_TYPE (over_return); + base_return = TREE_TYPE (base_return); if (DECL_THUNK_P (fn)) { @@ -2011,32 +2044,47 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals, overriding function. We will want the vbase offset from there. */ virtual_offset = binfo_for_vbase (BINFO_TYPE (virtual_offset), - TREE_TYPE (over_return)); - else if (!same_type_p (TREE_TYPE (over_return), - TREE_TYPE (base_return))) + over_return); + else if (!same_type_ignoring_top_level_qualifiers_p + (over_return, base_return)) { /* There was no existing virtual thunk (which takes - precedence). */ - tree thunk_binfo; - base_kind kind; - - thunk_binfo = lookup_base (TREE_TYPE (over_return), - TREE_TYPE (base_return), - ba_check | ba_quiet, &kind); + precedence). So find the binfo of the base function's + return type within the overriding function's return type. + We cannot call lookup base here, because we're inside a + dfs_walk, and will therefore clobber the BINFO_MARKED + flags. Fortunately we know the covariancy is valid (it + has already been checked), so we can just iterate along + the binfos, which have been chained in inheritance graph + order. Of course it is lame that we have to repeat the + search here anyway -- we should really be caching pieces + of the vtable and avoiding this repeated work. */ + tree thunk_binfo, base_binfo; + + /* Find the base binfo within the overriding function's + return type. */ + for (base_binfo = TYPE_BINFO (base_return), + thunk_binfo = TYPE_BINFO (over_return); + !SAME_BINFO_TYPE_P (BINFO_TYPE (thunk_binfo), + BINFO_TYPE (base_binfo)); + thunk_binfo = TREE_CHAIN (thunk_binfo)) + continue; - if (thunk_binfo && (kind == bk_via_virtual - || !BINFO_OFFSET_ZEROP (thunk_binfo))) + /* See if virtual inheritance is involved. */ + for (virtual_offset = thunk_binfo; + virtual_offset; + virtual_offset = BINFO_INHERITANCE_CHAIN (virtual_offset)) + if (BINFO_VIRTUAL_P (virtual_offset)) + break; + + if (virtual_offset || !BINFO_OFFSET_ZEROP (thunk_binfo)) { tree offset = convert (ssizetype, BINFO_OFFSET (thunk_binfo)); - if (kind == bk_via_virtual) + if (virtual_offset) { - /* We convert via virtual base. Find the virtual - base and adjust the fixed offset to be from there. */ - while (!BINFO_VIRTUAL_P (thunk_binfo)) - thunk_binfo = BINFO_INHERITANCE_CHAIN (thunk_binfo); - - virtual_offset = thunk_binfo; + /* We convert via virtual base. Adjust the fixed + offset to be from there. */ offset = size_diffop (offset, convert (ssizetype, BINFO_OFFSET (virtual_offset))); diff --git a/gcc/cp/search.c b/gcc/cp/search.c index a0cb0ff0bc1..f6a9b577dfc 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -1639,9 +1639,12 @@ tree dfs_walk_once (tree binfo, tree (*pre_fn) (tree, void *), tree (*post_fn) (tree, void *), void *data) { + static int active = 0; /* We must not be called recursively. */ tree rval; gcc_assert (pre_fn || post_fn); + gcc_assert (!active); + active++; if (!CLASSTYPE_DIAMOND_SHAPED_P (BINFO_TYPE (binfo))) /* We are not diamond shaped, and therefore cannot encounter the @@ -1666,6 +1669,9 @@ dfs_walk_once (tree binfo, tree (*pre_fn) (tree, void *), else dfs_unmark_r (binfo); } + + active--; + return rval; } diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 2badcc27494..e0dc1ebdb49 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1750,7 +1750,7 @@ build_class_member_access_expr (tree object, tree member, expression itself. */ if (type_quals & TYPE_QUAL_CONST) TREE_READONLY (result) = 1; - else if (type_quals & TYPE_QUAL_VOLATILE) + if (type_quals & TYPE_QUAL_VOLATILE) TREE_THIS_VOLATILE (result) = 1; } else if (BASELINK_P (member)) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 0295cc8eba5..78c096320fe 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2005-02-14 Nathan Sidwell <nathan@codesourcery.com> + + PR c++/19891 + * g++.dg/abi/covariant4.C: New. + 2005-02-13 James A. Morrison <phython@gcc.gnu.org> * gcc.dg/pr15784-1.c, gcc.dg/pr15784-2.c, gcc.dg/pr15784-3.c: New tests. diff --git a/gcc/testsuite/g++.dg/abi/covariant4.C b/gcc/testsuite/g++.dg/abi/covariant4.C new file mode 100644 index 00000000000..942b1686e8a --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/covariant4.C @@ -0,0 +1,46 @@ +// { dg-do run } + +// Copyright (C) 2005 Free Software Foundation, Inc. +// Contributed by Nathan Sidwell 11 Feb 2005 <nathan@codesourcery.com> + +// Origin: bredelin@ucla.edu +// Bug 19891: Incorrect covariant vtables + +struct Model { + bool full_tree; + virtual Model* clone() const =0; + virtual const char *name() const =0; + virtual ~Model() {} +}; + +struct R: virtual public Model { + virtual R* clone() const =0; +}; +struct A: virtual public Model { + virtual A* clone() const=0; +}; +struct RA: public R, public A { + virtual RA* clone() const=0; +}; + +static const char *string = "EQU"; + +struct EQU: public RA { + virtual EQU* clone() const {return new EQU(*this);} + const char *name() const {return string;} +}; + +int main() { + Model* M1 = new EQU(); + Model* M2 = M1->clone(); + Model* M3 = M2->clone(); + + if (M1->name () != string) + return 1; + if (M2->name () != string) + return 2; + if (M3->name () != string) + return 3; + + return 0; +} |