aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@codesourcery.com>2005-02-14 09:36:35 +0000
committerNathan Sidwell <nathan@codesourcery.com>2005-02-14 09:36:35 +0000
commit894ba01fbaa56c931eb45b529ae6e9600d8b5fb6 (patch)
tree489402919c97378f6127944f463d865fdc1383ad
parenta92e878cbb848cb69dd2f3fdd77802ef029a0c9c (diff)
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. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@95005 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/cp/ChangeLog11
-rw-r--r--gcc/cp/class.c90
-rw-r--r--gcc/cp/search.c6
-rw-r--r--gcc/cp/typeck.c2
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/abi/covariant4.C46
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;
+}