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
This commit is contained in:
Nathan Sidwell 2005-02-14 09:36:35 +00:00 committed by Nathan Sidwell
parent 90bb1c1f15
commit 12a669d1e1
6 changed files with 138 additions and 22 deletions

View File

@ -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> 2005-02-12 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
PR c++/14479 PR c++/14479

View File

@ -408,7 +408,18 @@ build_simple_base_path (tree expr, tree binfo)
if (d_binfo == NULL_TREE) if (d_binfo == NULL_TREE)
{ {
tree temp;
gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (expr)) == type); 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; return expr;
} }
@ -421,8 +432,27 @@ build_simple_base_path (tree expr, tree binfo)
if (TREE_CODE (field) == FIELD_DECL if (TREE_CODE (field) == FIELD_DECL
&& DECL_FIELD_IS_BASE (field) && DECL_FIELD_IS_BASE (field)
&& TREE_TYPE (field) == type) && 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?!? */ /* Didn't find the base field?!? */
gcc_unreachable (); gcc_unreachable ();
@ -1997,6 +2027,9 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,
combine the two conversions here. */ combine the two conversions here. */
tree fixed_offset, virtual_offset; tree fixed_offset, virtual_offset;
over_return = TREE_TYPE (over_return);
base_return = TREE_TYPE (base_return);
if (DECL_THUNK_P (fn)) if (DECL_THUNK_P (fn))
{ {
gcc_assert (DECL_RESULT_THUNK_P (fn)); gcc_assert (DECL_RESULT_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 overriding function. We will want the vbase offset from
there. */ there. */
virtual_offset = binfo_for_vbase (BINFO_TYPE (virtual_offset), virtual_offset = binfo_for_vbase (BINFO_TYPE (virtual_offset),
TREE_TYPE (over_return)); over_return);
else if (!same_type_p (TREE_TYPE (over_return), else if (!same_type_ignoring_top_level_qualifiers_p
TREE_TYPE (base_return))) (over_return, base_return))
{ {
/* There was no existing virtual thunk (which takes /* There was no existing virtual thunk (which takes
precedence). */ precedence). So find the binfo of the base function's
tree thunk_binfo; return type within the overriding function's return type.
base_kind kind; 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;
thunk_binfo = lookup_base (TREE_TYPE (over_return), /* Find the base binfo within the overriding function's
TREE_TYPE (base_return), return type. */
ba_check | ba_quiet, &kind); 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 /* See if virtual inheritance is involved. */
|| !BINFO_OFFSET_ZEROP (thunk_binfo))) 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)); tree offset = convert (ssizetype, BINFO_OFFSET (thunk_binfo));
if (kind == bk_via_virtual) if (virtual_offset)
{ {
/* We convert via virtual base. Find the virtual /* We convert via virtual base. Adjust the fixed
base and adjust the fixed offset to be from there. */ offset to be from there. */
while (!BINFO_VIRTUAL_P (thunk_binfo))
thunk_binfo = BINFO_INHERITANCE_CHAIN (thunk_binfo);
virtual_offset = thunk_binfo;
offset = size_diffop offset = size_diffop
(offset, convert (offset, convert
(ssizetype, BINFO_OFFSET (virtual_offset))); (ssizetype, BINFO_OFFSET (virtual_offset)));

View File

@ -1639,9 +1639,12 @@ tree
dfs_walk_once (tree binfo, tree (*pre_fn) (tree, void *), dfs_walk_once (tree binfo, tree (*pre_fn) (tree, void *),
tree (*post_fn) (tree, void *), void *data) tree (*post_fn) (tree, void *), void *data)
{ {
static int active = 0; /* We must not be called recursively. */
tree rval; tree rval;
gcc_assert (pre_fn || post_fn); gcc_assert (pre_fn || post_fn);
gcc_assert (!active);
active++;
if (!CLASSTYPE_DIAMOND_SHAPED_P (BINFO_TYPE (binfo))) if (!CLASSTYPE_DIAMOND_SHAPED_P (BINFO_TYPE (binfo)))
/* We are not diamond shaped, and therefore cannot encounter the /* 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 else
dfs_unmark_r (binfo); dfs_unmark_r (binfo);
} }
active--;
return rval; return rval;
} }

View File

@ -1750,7 +1750,7 @@ build_class_member_access_expr (tree object, tree member,
expression itself. */ expression itself. */
if (type_quals & TYPE_QUAL_CONST) if (type_quals & TYPE_QUAL_CONST)
TREE_READONLY (result) = 1; TREE_READONLY (result) = 1;
else if (type_quals & TYPE_QUAL_VOLATILE) if (type_quals & TYPE_QUAL_VOLATILE)
TREE_THIS_VOLATILE (result) = 1; TREE_THIS_VOLATILE (result) = 1;
} }
else if (BASELINK_P (member)) else if (BASELINK_P (member))

View File

@ -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> 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. * gcc.dg/pr15784-1.c, gcc.dg/pr15784-2.c, gcc.dg/pr15784-3.c: New tests.

View File

@ -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;
}