The solution is to look at all paths to BINFO. If we find
different overriders along any two, then there is a problem. */
+ if (DECL_THUNK_P (fn))
+ fn = THUNK_TARGET (fn);
+
ffod.fn = fn;
ffod.declaring_base = binfo;
ffod.most_derived_type = BINFO_TYPE (derived);
{
tree v;
- if (DECL_RESULT_THUNK_P (fn))
- fn = TREE_OPERAND (DECL_INITIAL (fn), 0);
+ if (DECL_THUNK_P (fn))
+ fn = THUNK_TARGET (fn);
for (v = CLASSTYPE_VCALL_INDICES (type); v; v = TREE_CHAIN (v))
if ((DECL_DESTRUCTOR_P (fn) && DECL_DESTRUCTOR_P (TREE_PURPOSE (v)))
tree first_defn;
bool lost = false;
+ if (DECL_THUNK_P (fn))
+ fn = THUNK_TARGET (fn);
+
/* Find the nearest primary base (possibly binfo itself) which defines
this function; this is the class the caller will convert to when
calling FN through BINFO. */
for (b = binfo; ; b = get_primary_binfo (b))
{
+ my_friendly_assert (b, 20021227);
if (look_for_overrides_here (BINFO_TYPE (b), fn))
break;
/* 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);
+ binfo. */
+ virtual_offset = binfo_for_vbase (BINFO_TYPE (binfo),
+ TREE_TYPE (over_return));
+ fixed_offset = size_diffop (fixed_offset,
+ BINFO_OFFSET (virtual_offset));
}
/* Replace the overriding function with a covariant thunk.
fixed_offset, virtual_offset);
TREE_PURPOSE (overrider) = thunk;
if (!virtual_offset && !DECL_NAME (thunk))
- finish_thunk (thunk, fixed_offset, NULL_TREE);
+ finish_thunk (thunk);
}
}
}
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))
+ fn_original = fn;
+ if (DECL_THUNK_P (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 (!DECL_NAME (fn))
+ finish_thunk (fn);
+ fn_original = THUNK_TARGET (fn);
}
/* If the only definition of this function signature along our
{
fn = make_thunk (fn, /*this_adjusting=*/1, delta, vcall_index);
if (!DECL_NAME (fn))
- finish_thunk (fn, delta, THUNK_VIRTUAL_OFFSET (fn));
+ finish_thunk (fn);
}
/* Take the address of the function, considering it to be of an
appropriate generic type. */
{
struct full_lang_decl
{
+ /* For a non-thunk function decl, this is a tree list of
+ friendly classes. For a thunk function decl, it is the
+ thunked to function decl. */
tree befriending_classes;
/* For a non-virtual FUNCTION_DECL, this is
/* An integer indicating how many bytes should be subtracted from the
this or result pointer when this function is called. */
#define THUNK_FIXED_OFFSET(DECL) \
- (DECL_LANG_SPECIFIC (DECL)->u.f.fixed_offset)
-
-/* A tree indicating how many bytes should be added to the
- vtable for the this or result pointer to find the vcall or vbase
- offset. (The vptr is always located at offset zero from the
- this or result pointer.) If NULL, then there is no virtual adjust. */
+ (DECL_LANG_SPECIFIC (VAR_OR_FUNCTION_DECL_CHECK (DECL))->u.f.fixed_offset)
+
+/* A tree indicating how to perform the virtual adjustment. For a this
+ adjusting thunk it is the number of bytes to be added to the vtable
+ to find the vcall offset. For a result adjusting thunk, it is the
+ binfo of the relevant virtual base. The vptr is always located at
+ offset zero from the this or result pointer. If NULL, then there
+ is no virtual adjust. */
#define THUNK_VIRTUAL_OFFSET(DECL) \
- (LANG_DECL_U2_CHECK (DECL, 0)->virtual_offset)
+ (LANG_DECL_U2_CHECK (VAR_OR_FUNCTION_DECL_CHECK (DECL), 0)->virtual_offset)
+
+/* For thunk NODE, this is the FUNCTION_DECL thunked to. */
+#define THUNK_TARGET(NODE) \
+ (DECL_LANG_SPECIFIC (NODE)->u.f.befriending_classes)
/* These macros provide convenient access to the various _STMT nodes
created when parsing template declarations. */
extern tree build_opfncall (enum tree_code, int, tree, tree, tree);
extern tree hack_identifier (tree, tree);
extern tree make_thunk (tree, bool, tree, tree);
-extern void finish_thunk (tree, tree, tree);
+extern void finish_thunk (tree);
extern void use_thunk (tree, bool);
extern void synthesize_method (tree);
extern tree implicitly_declare_fn (special_function_kind, tree, bool);
}
else
{
+ tree virt = THUNK_VIRTUAL_OFFSET (t);
+
dump_string (di, "thunk");
if (DECL_THIS_THUNK_P (t))
dump_string (di, "this adjusting");
else
- dump_string (di, "result adjusting");
+ {
+ dump_string (di, "result adjusting");
+ if (virt)
+ virt = BINFO_VPTR_FIELD (virt);
+ }
dump_int (di, "fixd", THUNK_FIXED_OFFSET (t));
- dump_child ("virt", THUNK_VIRTUAL_OFFSET (t));
+ if (virt)
+ dump_int (di, "virt", tree_low_cst (virt, 0));
dump_child ("fn", DECL_INITIAL (t));
}
break;
tree fixed_offset;
tree virtual_offset;
{
- if (virtual_offset)
- write_char (virtual_offset ? 'v' : 'h');
- else
- write_char ('h');
+ write_char (virtual_offset ? 'v' : 'h');
/* For either flavor, write the fixed offset. */
write_integer_cst (fixed_offset);
write_string ("_Z");
write_char ('T');
- if (this_adjusting && !DECL_RESULT_THUNK_P (fn_decl))
- /* Plain this adjusting thunk. */
- mangle_call_offset (fixed_offset, virtual_offset);
- else if (!this_adjusting)
+ if (!this_adjusting)
{
/* Covariant thunk with no this adjustment */
write_char ('c');
mangle_call_offset (integer_zero_node, NULL_TREE);
mangle_call_offset (fixed_offset, virtual_offset);
}
+ else if (!DECL_THUNK_P (fn_decl))
+ /* Plain this adjusting thunk. */
+ mangle_call_offset (fixed_offset, virtual_offset);
else
{
/* This adjusting thunk to covariant thunk. */
write_char ('c');
mangle_call_offset (fixed_offset, virtual_offset);
- mangle_call_offset (ssize_int (THUNK_FIXED_OFFSET (fn_decl)),
- THUNK_VIRTUAL_OFFSET (fn_decl));
- fn_decl = TREE_OPERAND (DECL_INITIAL (fn_decl), 0);
+ fixed_offset = ssize_int (THUNK_FIXED_OFFSET (fn_decl));
+ virtual_offset = THUNK_VIRTUAL_OFFSET (fn_decl);
+ if (virtual_offset)
+ virtual_offset = BINFO_VPTR_FIELD (virtual_offset);
+ mangle_call_offset (fixed_offset, virtual_offset);
+ fn_decl = THUNK_TARGET (fn_decl);
}
/* Scoped name. */
/* See if we already have the thunk in question. For this_adjusting
thunks VIRTUAL_OFFSET will be an INTEGER_CST, for covariant thunks it
- will be a BINFO (because of the organization of the layout
- algorithm). */
+ will be a BINFO. */
for (thunk = DECL_THUNKS (function); thunk; thunk = TREE_CHAIN (thunk))
if (DECL_THIS_THUNK_P (thunk) == this_adjusting
&& THUNK_FIXED_OFFSET (thunk) == d
thunk = build_decl (FUNCTION_DECL, NULL_TREE, TREE_TYPE (function));
DECL_LANG_SPECIFIC (thunk) = DECL_LANG_SPECIFIC (function);
- cxx_dup_lang_specific_decl (function);
+ cxx_dup_lang_specific_decl (thunk);
DECL_CONTEXT (thunk) = DECL_CONTEXT (function);
TREE_READONLY (thunk) = TREE_READONLY (function);
TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (function);
if (flag_weak)
comdat_linkage (thunk);
SET_DECL_THUNK_P (thunk, this_adjusting);
- DECL_INITIAL (thunk) = build1 (ADDR_EXPR, vfunc_ptr_type_node, function);
- THUNK_FIXED_OFFSET (thunk) = tree_low_cst (fixed_offset, 0);
+ THUNK_TARGET (thunk) = function;
+ THUNK_FIXED_OFFSET (thunk) = d;
THUNK_VIRTUAL_OFFSET (thunk) = virtual_offset;
/* The thunk itself is not a constructor or destructor, even if
return thunk;
}
-/* Finish THUNK, a thunk decl. FIXED_OFFSET and VIRTUAL_OFFSET are the
- adjustments to apply. */
+/* Finish THUNK, a thunk decl. */
void
-finish_thunk (tree thunk, tree fixed_offset, tree virtual_offset)
+finish_thunk (tree thunk)
{
tree function, name;
-
+ tree fixed_offset = ssize_int (THUNK_FIXED_OFFSET (thunk));
+ tree virtual_offset = THUNK_VIRTUAL_OFFSET (thunk);
+
my_friendly_assert (!DECL_NAME (thunk) && DECL_THUNK_P (thunk), 20021127);
- function = TREE_OPERAND (DECL_INITIAL (thunk), 0);
+ if (virtual_offset && DECL_RESULT_THUNK_P (thunk))
+ virtual_offset = BINFO_VPTR_FIELD (virtual_offset);
+ function = THUNK_TARGET (thunk);
name = mangle_thunk (function, DECL_THIS_THUNK_P (thunk),
- fixed_offset, virtual_offset);
- THUNK_FIXED_OFFSET (thunk) = tree_low_cst (fixed_offset, 0);
- THUNK_VIRTUAL_OFFSET (thunk) = virtual_offset;
+ fixed_offset, virtual_offset);
DECL_NAME (thunk) = name;
SET_DECL_ASSEMBLER_NAME (thunk, name);
}
{
tree vtable;
- /* It shouldn't be a binfo any more. */
- my_friendly_assert (TREE_CODE (virtual_offset) == INTEGER_CST, 20021127);
-
ptr = save_expr (ptr);
/* The vptr is always at offset zero in the object. */
vtable = build1 (NOP_EXPR,
void
use_thunk (tree thunk_fndecl, bool emit_p)
{
- tree fnaddr;
tree function;
tree virtual_offset;
HOST_WIDE_INT fixed_offset, virtual_value;
+ bool this_adjusting = DECL_THIS_THUNK_P (thunk_fndecl);
/* We should have called finish_thunk to give it a name. */
my_friendly_assert (DECL_NAME (thunk_fndecl), 20021127);
if (TREE_ASM_WRITTEN (thunk_fndecl))
return;
- fnaddr = DECL_INITIAL (thunk_fndecl);
- if (TREE_CODE (DECL_INITIAL (thunk_fndecl)) != ADDR_EXPR)
+ function = THUNK_TARGET (thunk_fndecl);
+ if (DECL_RESULT (thunk_fndecl))
/* We already turned this thunk into an ordinary function.
There's no need to process this thunk again. */
return;
/* Figure out what function is being thunked to. It's referenced in
this translation unit. */
- function = TREE_OPERAND (fnaddr, 0);
TREE_ADDRESSABLE (function) = 1;
mark_used (function);
TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (function)) = 1;
fixed_offset = THUNK_FIXED_OFFSET (thunk_fndecl);
virtual_offset = THUNK_VIRTUAL_OFFSET (thunk_fndecl);
- virtual_value = (virtual_offset
- ? tree_low_cst (virtual_offset, /*pos=*/0) : 0);
- my_friendly_assert (!virtual_offset || virtual_value, 20021026);
+ if (virtual_offset)
+ {
+ if (!this_adjusting)
+ virtual_offset = BINFO_VPTR_FIELD (virtual_offset);
+ virtual_value = tree_low_cst (virtual_offset, /*pos=*/0);
+ my_friendly_assert (virtual_value, 20021026);
+ }
+ else
+ virtual_value = 0;
/* And, if we need to emit the thunk, it's used. */
mark_used (thunk_fndecl);
/* The back-end expects DECL_INITIAL to contain a BLOCK, so we
create one. */
DECL_INITIAL (thunk_fndecl) = make_node (BLOCK);
- BLOCK_VARS (DECL_INITIAL (thunk_fndecl))
- = DECL_ARGUMENTS (thunk_fndecl);
-
- if (DECL_THIS_THUNK_P (thunk_fndecl)
+ BLOCK_VARS (DECL_INITIAL (thunk_fndecl)) = DECL_ARGUMENTS (thunk_fndecl);
+
+ if (this_adjusting
&& targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset,
virtual_value, function))
{
t = a;
- if (DECL_THIS_THUNK_P (thunk_fndecl))
+ if (this_adjusting)
t = thunk_adjust (t, /*this_adjusting=*/1,
fixed_offset, virtual_offset);
t = tree_cons (NULL_TREE, a, t);
t = nreverse (t);
t = build_call (function, t);
- if (DECL_RESULT_THUNK_P (thunk_fndecl))
+ if (!this_adjusting)
t = thunk_adjust (t, /*this_adjusting=*/0,
fixed_offset, virtual_offset);
+2002-12-30 Nathan Sidwell <nathan@codesourcery.com>
+
+ * g++.dg/inherit/covariant5.C: New test.
+ * g++.dg/inherit/covariant6.C: New test.
+ * g++.dg/inherit/covariant7.C: New test.
+
2002-12-29 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
PR c++/2739
--- /dev/null
+// { dg-do compile }
+
+// Copyright (C) 2002 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 27 Dec 2002 <nathan@codesourcery.com>
+
+// We ICE'd
+
+struct c0 {};
+
+struct c1 : virtual c0
+{
+ virtual c0 &f2();
+};
+
+struct c3 : c1
+{
+ virtual c1 &f2();
+};
+
+c1 &c3::f2()
+{
+ throw 0;
+}
+
+struct c4 : virtual c3
+{
+};
--- /dev/null
+// { dg-do compile }
+
+// Copyright (C) 2002 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 27 Dec 2002 <nathan@codesourcery.com>
+
+// We ICE'd
+
+struct c0 {};
+
+struct c1 : virtual c0
+{
+ virtual c0 &f2();
+};
+
+struct c3 : virtual c1
+{
+ virtual c1 &f2();
+};
+
+c1 &c3::f2()
+{
+ throw 0;
+}
+
+struct c4 : virtual c3
+{
+};
--- /dev/null
+// { dg-do compile }
+
+// Copyright (C) 2002 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 27 Dec 2002 <nathan@codesourcery.com>
+
+// We ICE'd
+
+struct c0 {};
+
+struct c1 : virtual c0
+{
+ virtual c0 &f2() volatile;
+};
+
+struct c2
+{
+ int m;
+};
+
+struct c3 : virtual c0, virtual c1, c2
+{
+ virtual c1 &f2() volatile;
+};
+
+struct c4 : virtual c3, virtual c0, virtual c1
+{
+ int m;
+};
+
+struct c6 : c0, c3, c4
+{ // { dg-warning "direct base" "" }
+ virtual c1 &f2() volatile;
+};