summaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>2010-07-09 19:36:19 +0000
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>2010-07-09 19:36:19 +0000
commit0ec820421213c3308258f9241363fda0b3133f40 (patch)
tree27b3670f92dc982f83cc34bdb5baecdb238472d7 /gcc/cp
parent4be7307ce1e74282de71f3806026c59177aacc25 (diff)
downloadgcc-0ec820421213c3308258f9241363fda0b3133f40.tar.gz
PR c++/43120
* cp-tree.h (BV_LOST_PRIMARY): New macro. * class.c (update_vtable_entry_for_fn): Fix covariant thunk logic. Set BV_LOST_PRIMARY. (build_vtbl_initializer): Check BV_LOST_PRIMARY. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@162008 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog8
-rw-r--r--gcc/cp/class.c88
-rw-r--r--gcc/cp/cp-tree.h5
3 files changed, 53 insertions, 48 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 0a3f54a7c1b..bdae8fc813c 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,11 @@
+2010-07-09 Jason Merrill <jason@redhat.com>
+
+ PR c++/43120
+ * cp-tree.h (BV_LOST_PRIMARY): New macro.
+ * class.c (update_vtable_entry_for_fn): Fix covariant thunk logic.
+ Set BV_LOST_PRIMARY.
+ (build_vtbl_initializer): Check BV_LOST_PRIMARY.
+
2010-07-08 Jason Merrill <jason@redhat.com>
PR c++/43120
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 20b8c1245c1..dfb2cd942d7 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -2205,6 +2205,40 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,
gcc_assert (DECL_INVALID_OVERRIDER_P (overrider_target) ||
!DECL_THUNK_P (fn));
+ /* If we need a covariant thunk, then we may need to adjust first_defn.
+ The ABI specifies that the thunks emitted with a function are
+ determined by which bases the function overrides, so we need to be
+ sure that we're using a thunk for some overridden base; even if we
+ know that the necessary this adjustment is zero, there may not be an
+ appropriate zero-this-adjusment thunk for us to use since thunks for
+ overriding virtual bases always use the vcall offset.
+
+ Furthermore, just choosing any base that overrides this function isn't
+ quite right, as this slot won't be used for calls through a type that
+ puts a covariant thunk here. Calling the function through such a type
+ will use a different slot, and that slot is the one that determines
+ the thunk emitted for that base.
+
+ So, keep looking until we find the base that we're really overriding
+ in this slot: the nearest primary base that doesn't use a covariant
+ thunk in this slot. */
+ if (overrider_target != overrider_fn)
+ {
+ if (BINFO_TYPE (b) == DECL_CONTEXT (overrider_target))
+ /* We already know that the overrider needs a covariant thunk. */
+ b = get_primary_binfo (b);
+ for (; ; b = get_primary_binfo (b))
+ {
+ tree main_binfo = TYPE_BINFO (BINFO_TYPE (b));
+ tree bv = chain_index (ix, BINFO_VIRTUALS (main_binfo));
+ if (BINFO_LOST_PRIMARY_P (b))
+ lost = true;
+ if (!DECL_THUNK_P (TREE_VALUE (bv)))
+ break;
+ }
+ first_defn = b;
+ }
+
/* Assume that we will produce a thunk that convert all the way to
the final overrider, and not to an intermediate virtual base. */
virtual_base = NULL_TREE;
@@ -2229,38 +2263,6 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,
}
}
- if (overrider_fn != overrider_target && !virtual_base)
- {
- /* The ABI specifies that a covariant thunk includes a mangling
- for a this pointer adjustment. This-adjusting thunks that
- override a function from a virtual base have a vcall
- adjustment. When the virtual base in question is a primary
- virtual base, we know the adjustments are zero, (and in the
- non-covariant case, we would not use the thunk).
- Unfortunately we didn't notice this could happen, when
- designing the ABI and so never mandated that such a covariant
- thunk should be emitted. Because we must use the ABI mandated
- name, we must continue searching from the binfo where we
- found the most recent definition of the function, towards the
- primary binfo which first introduced the function into the
- vtable. If that enters a virtual base, we must use a vcall
- this-adjusting thunk. Bleah! */
- tree probe = first_defn;
-
- while ((probe = get_primary_binfo (probe))
- && (unsigned) list_length (BINFO_VIRTUALS (probe)) > ix)
- if (BINFO_VIRTUAL_P (probe))
- virtual_base = probe;
-
- if (virtual_base)
- /* OK, first_defn got this function from a (possibly lost) primary
- virtual base, so we're going to use the vcall offset for that
- primary virtual base. But the caller is passing a first_defn*,
- not a virtual_base*, so the correct delta is the delta between
- first_defn* and itself, i.e. zero. */
- goto virtual_covariant;
- }
-
/* Compute the constant adjustment to the `this' pointer. The
`this' pointer, when this function is called, will point at BINFO
(or one of its primary bases, which are at the same offset). */
@@ -2275,7 +2277,6 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,
entry in our vtable. Except possibly in a constructor vtable,
if we happen to get our primary back. In that case, the offset
will be zero, as it will be a primary base. */
- virtual_covariant:
delta = size_zero_node;
else
/* The `this' pointer needs to be adjusted from pointing to
@@ -2293,6 +2294,9 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,
= get_vcall_index (overrider_target, BINFO_TYPE (virtual_base));
else
BV_VCALL_INDEX (*virtuals) = NULL_TREE;
+
+ if (lost)
+ BV_LOST_PRIMARY (*virtuals) = true;
}
/* Called from modify_all_vtables via dfs_walk. */
@@ -7648,7 +7652,7 @@ build_vtbl_initializer (tree binfo,
int* non_fn_entries_p,
VEC(constructor_elt,gc) **inits)
{
- tree v, b;
+ tree v;
vtbl_init_data vid;
unsigned ix, jx;
tree vbinfo;
@@ -7762,20 +7766,8 @@ build_vtbl_initializer (tree binfo,
zero out unused slots in ctor vtables, rather than filling them
with erroneous values (though harmless, apart from relocation
costs). */
- for (b = binfo; ; b = get_primary_binfo (b))
- {
- /* We found a defn before a lost primary; go ahead as normal. */
- if (look_for_overrides_here (BINFO_TYPE (b), fn_original))
- break;
-
- /* The nearest definition is from a lost primary; clear the
- slot. */
- if (BINFO_LOST_PRIMARY_P (b))
- {
- init = size_zero_node;
- break;
- }
- }
+ if (BV_LOST_PRIMARY (v))
+ init = size_zero_node;
if (! init)
{
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 56e86beaf51..08398aa19ff 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -168,6 +168,9 @@ c-common.h, not after.
The BV_FN is the declaration for the virtual function itself.
+ If BV_LOST_PRIMARY is set, it means that this entry is for a lost
+ primary virtual base and can be left null in the vtable.
+
BINFO_VTABLE
This is an expression with POINTER_TYPE that gives the value
to which the vptr should be initialized. Use get_vtbl_decl_for_binfo
@@ -1767,6 +1770,8 @@ struct GTY((variable_size)) lang_type {
/* The function to call. */
#define BV_FN(NODE) (TREE_VALUE (NODE))
+/* Whether or not this entry is for a lost primary virtual base. */
+#define BV_LOST_PRIMARY(NODE) (TREE_LANG_FLAG_0 (NODE))
/* For FUNCTION_TYPE or METHOD_TYPE, a list of the exceptions that
this type can raise. Each TREE_VALUE is a _TYPE. The TREE_VALUE