summaryrefslogtreecommitdiffstats
path: root/gcc/cp/class.c
diff options
context:
space:
mode:
authorzack <zack@138bc75d-0d04-0410-961f-82ee72b054a4>2002-12-16 18:23:00 +0000
committerzack <zack@138bc75d-0d04-0410-961f-82ee72b054a4>2002-12-16 18:23:00 +0000
commit805e22b2051e9c6a75377ea6599654d7415da483 (patch)
treec259697c448b0c6f548f153c48c46a8d7a75970f /gcc/cp/class.c
parent2c27ce73ee2229b0871c4ccad2342d8a4be85eff (diff)
downloadppe42-gcc-805e22b2051e9c6a75377ea6599654d7415da483.tar.gz
ppe42-gcc-805e22b2051e9c6a75377ea6599654d7415da483.zip
Merge basic-improvements-branch to trunk
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@60174 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/cp/class.c')
-rw-r--r--gcc/cp/class.c94
1 files changed, 84 insertions, 10 deletions
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 06d09681e6f..9f95c994703 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -25,6 +25,8 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "tree.h"
#include "cp-tree.h"
#include "flags.h"
@@ -2326,6 +2328,9 @@ get_vcall_index (tree fn, tree type)
{
tree v;
+ if (DECL_RESULT_THUNK_P (fn))
+ fn = TREE_OPERAND (DECL_INITIAL (fn), 0);
+
for (v = CLASSTYPE_VCALL_INDICES (type); v; v = TREE_CHAIN (v))
if ((DECL_DESTRUCTOR_P (fn) && DECL_DESTRUCTOR_P (TREE_PURPOSE (v)))
|| same_signature_p (fn, TREE_PURPOSE (v)))
@@ -2373,10 +2378,53 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals)
overrider = find_final_overrider (TYPE_BINFO (t), b, fn);
if (overrider == error_mark_node)
return;
+ {
+ /* Check for adjusting covariant return types. */
+ tree over_return = TREE_TYPE (TREE_TYPE (TREE_PURPOSE (overrider)));
+ tree base_return = TREE_TYPE (TREE_TYPE (fn));
+
+ if (POINTER_TYPE_P (over_return)
+ && TREE_CODE (over_return) == TREE_CODE (base_return)
+ && CLASS_TYPE_P (TREE_TYPE (over_return))
+ && CLASS_TYPE_P (TREE_TYPE (base_return)))
+ {
+ tree binfo;
+ base_kind kind;
+
+ binfo = lookup_base (TREE_TYPE (over_return), TREE_TYPE (base_return),
+ ba_check | ba_quiet, &kind);
- /* Check for unsupported covariant returns again now that we've
- calculated the base offsets. */
- check_final_overrider (TREE_PURPOSE (overrider), fn);
+ if (binfo && (kind == bk_via_virtual || !BINFO_OFFSET_ZEROP (binfo)))
+ {
+ tree fixed_offset = BINFO_OFFSET (binfo);
+ tree virtual_offset = NULL_TREE;
+ tree thunk;
+
+ if (kind == bk_via_virtual)
+ {
+ while (!TREE_VIA_VIRTUAL (binfo))
+ binfo = BINFO_INHERITANCE_CHAIN (binfo);
+
+ /* If the covariant type is within the class hierarchy
+ we are currently laying out, the vbase index is not
+ yet known, so we have to remember the virtual base
+ binfo for the moment. The thunk will be finished
+ in build_vtbl_initializer, where we'll know the
+ vtable index of the virtual base. */
+ virtual_offset = binfo_for_vbase (BINFO_TYPE (binfo), t);
+ }
+
+ /* Replace the overriding function with a covariant thunk.
+ We will emit the overriding function in its own slot
+ as well. */
+ thunk = make_thunk (TREE_PURPOSE (overrider), /*this_adjusting=*/0,
+ fixed_offset, virtual_offset);
+ TREE_PURPOSE (overrider) = thunk;
+ if (!virtual_offset && !DECL_NAME (thunk))
+ finish_thunk (thunk, fixed_offset, NULL_TREE);
+ }
+ }
+ }
/* Assume that we will produce a thunk that convert all the way to
the final overrider, and not to an intermediate virtual base. */
@@ -5261,8 +5309,17 @@ finish_struct_1 (t)
fn = TREE_CHAIN (fn),
vindex += (TARGET_VTABLE_USES_DESCRIPTORS
? TARGET_VTABLE_USES_DESCRIPTORS : 1))
- if (TREE_CODE (DECL_VINDEX (BV_FN (fn))) != INTEGER_CST)
- DECL_VINDEX (BV_FN (fn)) = build_shared_int_cst (vindex);
+ {
+ tree fndecl = BV_FN (fn);
+
+ if (DECL_THUNK_P (fndecl))
+ /* A thunk. We should never be calling this entry directly
+ from this vtable -- we'd use the entry for the non
+ thunk base function. */
+ DECL_VINDEX (fndecl) = NULL_TREE;
+ else if (TREE_CODE (DECL_VINDEX (fndecl)) != INTEGER_CST)
+ DECL_VINDEX (fndecl) = build_shared_int_cst (vindex);
+ }
/* Add this class to the list of dynamic classes. */
dynamic_classes = tree_cons (NULL_TREE, t, dynamic_classes);
@@ -7684,11 +7741,24 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)
{
tree delta;
tree vcall_index;
- tree fn;
+ tree fn, fn_original;
tree init = NULL_TREE;
fn = BV_FN (v);
-
+ fn_original = (DECL_RESULT_THUNK_P (fn)
+ ? TREE_OPERAND (DECL_INITIAL (fn), 0)
+ : fn);
+ /* Finish an unfinished covariant thunk. */
+ if (DECL_RESULT_THUNK_P (fn) && !DECL_NAME (fn))
+ {
+ tree binfo = THUNK_VIRTUAL_OFFSET (fn);
+ tree fixed_offset = size_int (THUNK_FIXED_OFFSET (fn));
+ tree virtual_offset = BINFO_VPTR_FIELD (binfo);
+
+ fixed_offset = size_diffop (fixed_offset, BINFO_OFFSET (binfo));
+ finish_thunk (fn, fixed_offset, virtual_offset);
+ }
+
/* If the only definition of this function signature along our
primary base chain is from a lost primary, this vtable slot will
never be used, so just zero it out. This is important to avoid
@@ -7702,7 +7772,7 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)
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))
+ if (look_for_overrides_here (BINFO_TYPE (b), fn_original))
break;
/* The nearest definition is from a lost primary; clear the
@@ -7726,10 +7796,14 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)
/* You can't call an abstract virtual function; it's abstract.
So, we replace these functions with __pure_virtual. */
- if (DECL_PURE_VIRTUAL_P (fn))
+ if (DECL_PURE_VIRTUAL_P (fn_original))
fn = abort_fndecl;
else if (!integer_zerop (delta) || vcall_index)
- fn = make_thunk (fn, delta, vcall_index);
+ {
+ fn = make_thunk (fn, /*this_adjusting=*/1, delta, vcall_index);
+ if (!DECL_NAME (fn))
+ finish_thunk (fn, delta, THUNK_VIRTUAL_OFFSET (fn));
+ }
/* Take the address of the function, considering it to be of an
appropriate generic type. */
init = build1 (ADDR_EXPR, vfunc_ptr_type_node, fn);
OpenPOWER on IntegriCloud