Commit bb5e8a7f by Mark Mitchell Committed by Mark Mitchell

class.c (build_vtbl_initializer): Don't use build_vtable_entry.

	* class.c (build_vtbl_initializer): Don't use build_vtable_entry.
	(build_vtable_entry): Remove.
	* cp-tree.h (BINFO_VIRTUALS): Expand documentation.
	(lang_decl): Add thunks.
	(DECL_THUNKS): New macro.
	* decl.c (duplicate_decls): Copy it.
	* method.c (make_thunk): Simplify, and add thunks to DECL_THUNKS.
	* semantics.c (emit_associated_thunks): Simplify.

	* g++.dg/abi/vthunk2.C: New test.

From-SVN: r58536
parent f3763a44
2002-10-25 Mark Mitchell <mark@codesourcery.com>
* class.c (build_vtbl_initializer): Don't use build_vtable_entry.
(build_vtable_entry): Remove.
* cp-tree.h (BINFO_VIRTUALS): Expand documentation.
(lang_decl): Add thunks.
(DECL_THUNKS): New macro.
* decl.c (duplicate_decls): Copy it.
* method.c (make_thunk): Simplify, and add thunks to DECL_THUNKS.
* semantics.c (emit_associated_thunks): Simplify.
2002-10-24 David Edelsohn <edelsohn@gnu.org> 2002-10-24 David Edelsohn <edelsohn@gnu.org>
PR c++/7228 PR c++/7228
......
...@@ -103,7 +103,6 @@ varray_type local_classes; ...@@ -103,7 +103,6 @@ varray_type local_classes;
static tree get_vfield_name PARAMS ((tree)); static tree get_vfield_name PARAMS ((tree));
static void finish_struct_anon PARAMS ((tree)); static void finish_struct_anon PARAMS ((tree));
static tree build_vtable_entry PARAMS ((tree, tree, tree));
static tree get_vtable_name PARAMS ((tree)); static tree get_vtable_name PARAMS ((tree));
static tree get_basefndecls PARAMS ((tree, tree)); static tree get_basefndecls PARAMS ((tree, tree));
static int build_primary_vtable PARAMS ((tree, tree)); static int build_primary_vtable PARAMS ((tree, tree));
...@@ -7673,7 +7672,6 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p) ...@@ -7673,7 +7672,6 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)
tree delta; tree delta;
tree vcall_index; tree vcall_index;
tree fn; tree fn;
tree pfn;
tree init = NULL_TREE; tree init = NULL_TREE;
fn = BV_FN (v); fn = BV_FN (v);
...@@ -7724,15 +7722,13 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p) ...@@ -7724,15 +7722,13 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)
So, we replace these functions with __pure_virtual. */ So, we replace these functions with __pure_virtual. */
if (DECL_PURE_VIRTUAL_P (fn)) if (DECL_PURE_VIRTUAL_P (fn))
fn = abort_fndecl; fn = abort_fndecl;
else if (!integer_zerop (delta) || vcall_index)
fn = make_thunk (fn, delta, vcall_index);
/* Take the address of the function, considering it to be of an /* Take the address of the function, considering it to be of an
appropriate generic type. */ appropriate generic type. */
pfn = build1 (ADDR_EXPR, vfunc_ptr_type_node, fn); init = build1 (ADDR_EXPR, vfunc_ptr_type_node, fn);
/* The address of a function can't change. */ /* The address of a function can't change. */
TREE_CONSTANT (pfn) = 1; TREE_CONSTANT (init) = 1;
/* Enter it in the vtable. */
init = build_vtable_entry (delta, vcall_index, pfn);
} }
/* And add it to the chain of initializers. */ /* And add it to the chain of initializers. */
...@@ -8164,33 +8160,3 @@ build_rtti_vtbl_entries (binfo, vid) ...@@ -8164,33 +8160,3 @@ build_rtti_vtbl_entries (binfo, vid)
*vid->last_init = build_tree_list (NULL_TREE, init); *vid->last_init = build_tree_list (NULL_TREE, init);
vid->last_init = &TREE_CHAIN (*vid->last_init); vid->last_init = &TREE_CHAIN (*vid->last_init);
} }
/* Build an entry in the virtual function table. DELTA is the offset
for the `this' pointer. VCALL_INDEX is the vtable index containing
the vcall offset; NULL_TREE if none. ENTRY is the virtual function
table entry itself. It's TREE_TYPE must be VFUNC_PTR_TYPE_NODE,
but it may not actually be a virtual function table pointer. (For
example, it might be the address of the RTTI object, under the new
ABI.) */
static tree
build_vtable_entry (delta, vcall_index, entry)
tree delta;
tree vcall_index;
tree entry;
{
tree fn = TREE_OPERAND (entry, 0);
if ((!integer_zerop (delta) || vcall_index != NULL_TREE)
&& fn != abort_fndecl)
{
entry = make_thunk (entry, delta, vcall_index);
entry = build1 (ADDR_EXPR, vtable_entry_type, entry);
TREE_READONLY (entry) = 1;
TREE_CONSTANT (entry) = 1;
}
#ifdef GATHER_STATISTICS
n_vtable_entries += 1;
#endif
return entry;
}
...@@ -121,11 +121,15 @@ struct diagnostic_context; ...@@ -121,11 +121,15 @@ struct diagnostic_context;
For a FUNCTION_TYPE or METHOD_TYPE, this is TYPE_RAISES_EXCEPTIONS For a FUNCTION_TYPE or METHOD_TYPE, this is TYPE_RAISES_EXCEPTIONS
BINFO_VIRTUALS BINFO_VIRTUALS
For a binfo, this is a TREE_LIST. The BV_DELTA of each node For a binfo, this is a TREE_LIST. There is an entry for each
gives the amount by which to adjust the `this' pointer when virtual function declared either in BINFO or its direct and
calling the function. If the method is an overriden version of a indirect primary bases.
base class method, then it is assumed that, prior to adjustment,
the this pointer points to an object of the base class. The BV_DELTA of each node gives the amount by which to adjust the
`this' pointer when calling the function. If the method is an
overriden version of a base class method, then it is assumed
that, prior to adjustment, the this pointer points to an object
of the base class.
The BV_VCALL_INDEX of each node, if non-NULL, gives the vtable The BV_VCALL_INDEX of each node, if non-NULL, gives the vtable
index of the vcall offset for this entry. If index of the vcall offset for this entry. If
...@@ -1766,6 +1770,10 @@ struct lang_decl GTY(()) ...@@ -1766,6 +1770,10 @@ struct lang_decl GTY(())
non-virtual FUNCTION_DECL, this is DECL_FRIEND_CONTEXT. */ non-virtual FUNCTION_DECL, this is DECL_FRIEND_CONTEXT. */
tree context; tree context;
/* In a FUNCTION_DECL for which DECL_THUNK_P does not hold, this
is DECL_THUNKS. */
tree thunks;
/* In a FUNCTION_DECL, this is DECL_CLONED_FUNCTION. */ /* In a FUNCTION_DECL, this is DECL_CLONED_FUNCTION. */
tree cloned_function; tree cloned_function;
...@@ -2049,6 +2057,11 @@ struct lang_decl GTY(()) ...@@ -2049,6 +2057,11 @@ struct lang_decl GTY(())
#define DECL_NEEDS_FINAL_OVERRIDER_P(NODE) \ #define DECL_NEEDS_FINAL_OVERRIDER_P(NODE) \
(DECL_LANG_SPECIFIC (NODE)->decl_flags.needs_final_overrider) (DECL_LANG_SPECIFIC (NODE)->decl_flags.needs_final_overrider)
/* The thunks associated with NODE, a FUNCTION_DECL that is not itself
a thunk. */
#define DECL_THUNKS(NODE) \
(DECL_LANG_SPECIFIC (NODE)->u.f.thunks)
/* Nonzero if NODE is a thunk, rather than an ordinary function. */ /* Nonzero if NODE is a thunk, rather than an ordinary function. */
#define DECL_THUNK_P(NODE) \ #define DECL_THUNK_P(NODE) \
(TREE_CODE (NODE) == FUNCTION_DECL \ (TREE_CODE (NODE) == FUNCTION_DECL \
......
...@@ -3594,9 +3594,12 @@ duplicate_decls (newdecl, olddecl) ...@@ -3594,9 +3594,12 @@ duplicate_decls (newdecl, olddecl)
/* Only functions have DECL_BEFRIENDING_CLASSES. */ /* Only functions have DECL_BEFRIENDING_CLASSES. */
if (TREE_CODE (newdecl) == FUNCTION_DECL if (TREE_CODE (newdecl) == FUNCTION_DECL
|| DECL_FUNCTION_TEMPLATE_P (newdecl)) || DECL_FUNCTION_TEMPLATE_P (newdecl))
DECL_BEFRIENDING_CLASSES (newdecl) {
= chainon (DECL_BEFRIENDING_CLASSES (newdecl), DECL_BEFRIENDING_CLASSES (newdecl)
DECL_BEFRIENDING_CLASSES (olddecl)); = chainon (DECL_BEFRIENDING_CLASSES (newdecl),
DECL_BEFRIENDING_CLASSES (olddecl));
DECL_THUNKS (newdecl) = DECL_THUNKS (olddecl);
}
} }
if (TREE_CODE (newdecl) == FUNCTION_DECL) if (TREE_CODE (newdecl) == FUNCTION_DECL)
......
...@@ -278,10 +278,11 @@ make_thunk (function, delta, vcall_index) ...@@ -278,10 +278,11 @@ make_thunk (function, delta, vcall_index)
{ {
tree thunk_id; tree thunk_id;
tree thunk; tree thunk;
tree func_decl;
tree vcall_offset; tree vcall_offset;
HOST_WIDE_INT d; HOST_WIDE_INT d;
my_friendly_assert (TREE_CODE (function) == FUNCTION_DECL, 20021025);
/* Scale the VCALL_INDEX to be in terms of bytes. */ /* Scale the VCALL_INDEX to be in terms of bytes. */
if (vcall_index) if (vcall_index)
vcall_offset vcall_offset
...@@ -294,59 +295,59 @@ make_thunk (function, delta, vcall_index) ...@@ -294,59 +295,59 @@ make_thunk (function, delta, vcall_index)
d = tree_low_cst (delta, 0); d = tree_low_cst (delta, 0);
if (TREE_CODE (function) != ADDR_EXPR) /* See if we already have the thunk in question. */
abort (); for (thunk = DECL_THUNKS (function); thunk; thunk = TREE_CHAIN (thunk))
func_decl = TREE_OPERAND (function, 0); if (THUNK_DELTA (thunk) == d
if (TREE_CODE (func_decl) != FUNCTION_DECL) && ((THUNK_VCALL_OFFSET (thunk) != NULL_TREE)
abort (); == (vcall_offset != NULL_TREE))
&& (THUNK_VCALL_OFFSET (thunk)
? tree_int_cst_equal (THUNK_VCALL_OFFSET (thunk),
vcall_offset)
: true))
return thunk;
/* All thunks must be created before FUNCTION is actually emitted;
the ABI requires that all thunks be emitted together with the
function to which they transfer control. */
my_friendly_assert (!TREE_ASM_WRITTEN (function), 20021025);
thunk_id = mangle_thunk (function, delta, vcall_offset);
thunk = build_decl (FUNCTION_DECL, thunk_id, TREE_TYPE (function));
DECL_LANG_SPECIFIC (thunk) = DECL_LANG_SPECIFIC (function);
cxx_dup_lang_specific_decl (function);
SET_DECL_ASSEMBLER_NAME (thunk, thunk_id);
DECL_CONTEXT (thunk) = DECL_CONTEXT (function);
TREE_READONLY (thunk) = TREE_READONLY (function);
TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (function);
TREE_PUBLIC (thunk) = TREE_PUBLIC (function);
if (flag_weak)
comdat_linkage (thunk);
SET_DECL_THUNK_P (thunk);
DECL_INITIAL (thunk) = build1 (ADDR_EXPR, vfunc_ptr_type_node, function);
THUNK_DELTA (thunk) = d;
THUNK_VCALL_OFFSET (thunk) = vcall_offset;
/* The thunk itself is not a constructor or destructor, even if
the thing it is thunking to is. */
DECL_INTERFACE_KNOWN (thunk) = 1;
DECL_NOT_REALLY_EXTERN (thunk) = 1;
DECL_SAVED_FUNCTION_DATA (thunk) = NULL;
DECL_DESTRUCTOR_P (thunk) = 0;
DECL_CONSTRUCTOR_P (thunk) = 0;
/* And neither is it a clone. */
DECL_CLONED_FUNCTION (thunk) = NULL_TREE;
DECL_EXTERNAL (thunk) = 1;
DECL_ARTIFICIAL (thunk) = 1;
/* Even if this thunk is a member of a local class, we don't
need a static chain. */
DECL_NO_STATIC_CHAIN (thunk) = 1;
/* The THUNK is not a pending inline, even if the FUNCTION is. */
DECL_PENDING_INLINE_P (thunk) = 0;
/* Nor has it been deferred. */
DECL_DEFERRED_FN (thunk) = 0;
/* Add it to the list of thunks associated with FUNCTION. */
TREE_CHAIN (thunk) = DECL_THUNKS (function);
DECL_THUNKS (function) = thunk;
thunk_id = mangle_thunk (TREE_OPERAND (function, 0),
delta, vcall_offset);
thunk = IDENTIFIER_GLOBAL_VALUE (thunk_id);
if (thunk && !DECL_THUNK_P (thunk))
{
error ("implementation-reserved name `%D' used", thunk_id);
thunk = NULL_TREE;
SET_IDENTIFIER_GLOBAL_VALUE (thunk_id, thunk);
}
if (thunk == NULL_TREE)
{
thunk = build_decl (FUNCTION_DECL, thunk_id, TREE_TYPE (func_decl));
DECL_LANG_SPECIFIC (thunk) = DECL_LANG_SPECIFIC (func_decl);
cxx_dup_lang_specific_decl (func_decl);
SET_DECL_ASSEMBLER_NAME (thunk, thunk_id);
DECL_CONTEXT (thunk) = DECL_CONTEXT (func_decl);
TREE_READONLY (thunk) = TREE_READONLY (func_decl);
TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (func_decl);
TREE_PUBLIC (thunk) = TREE_PUBLIC (func_decl);
if (flag_weak)
comdat_linkage (thunk);
SET_DECL_THUNK_P (thunk);
DECL_INITIAL (thunk) = function;
THUNK_DELTA (thunk) = d;
THUNK_VCALL_OFFSET (thunk) = vcall_offset;
/* The thunk itself is not a constructor or destructor, even if
the thing it is thunking to is. */
DECL_INTERFACE_KNOWN (thunk) = 1;
DECL_NOT_REALLY_EXTERN (thunk) = 1;
DECL_SAVED_FUNCTION_DATA (thunk) = NULL;
DECL_DESTRUCTOR_P (thunk) = 0;
DECL_CONSTRUCTOR_P (thunk) = 0;
/* And neither is it a clone. */
DECL_CLONED_FUNCTION (thunk) = NULL_TREE;
DECL_EXTERNAL (thunk) = 1;
DECL_ARTIFICIAL (thunk) = 1;
/* Even if this thunk is a member of a local class, we don't
need a static chain. */
DECL_NO_STATIC_CHAIN (thunk) = 1;
/* The THUNK is not a pending inline, even if the FUNC_DECL is. */
DECL_PENDING_INLINE_P (thunk) = 0;
/* Nor has it been deferred. */
DECL_DEFERRED_FN (thunk) = 0;
/* So that finish_file can write out any thunks that need to be: */
pushdecl_top_level (thunk);
SET_IDENTIFIER_GLOBAL_VALUE (thunk_id, thunk);
}
return thunk; return thunk;
} }
......
...@@ -2271,35 +2271,9 @@ emit_associated_thunks (fn) ...@@ -2271,35 +2271,9 @@ emit_associated_thunks (fn)
enabling you to output all the thunks with the function itself. */ enabling you to output all the thunks with the function itself. */
if (DECL_VIRTUAL_P (fn)) if (DECL_VIRTUAL_P (fn))
{ {
tree binfo; tree thunk;
tree v; for (thunk = DECL_THUNKS (fn); thunk; thunk = TREE_CHAIN (thunk))
use_thunk (thunk, /*emit_p=*/1);
for (binfo = TYPE_BINFO (DECL_CONTEXT (fn));
binfo;
binfo = TREE_CHAIN (binfo))
for (v = BINFO_VIRTUALS (binfo); v; v = TREE_CHAIN (v))
if (BV_FN (v) == fn
&& (!integer_zerop (BV_DELTA (v))
|| BV_USE_VCALL_INDEX_P (v)))
{
tree thunk;
tree vcall_index;
if (BV_USE_VCALL_INDEX_P (v))
{
vcall_index = BV_VCALL_INDEX (v);
my_friendly_assert (vcall_index != NULL_TREE, 20000621);
}
else
vcall_index = NULL_TREE;
thunk = make_thunk (build1 (ADDR_EXPR,
vfunc_ptr_type_node,
fn),
BV_DELTA (v),
vcall_index);
use_thunk (thunk, /*emit_p=*/1);
}
} }
} }
......
2002-10-25 Mark Mitchell <mark@codesourcery.com>
* g++.dg/abi/vthunk2.C: New test.
2002-10-25 Zack Weinberg <zack@codesourcery.com> 2002-10-25 Zack Weinberg <zack@codesourcery.com>
* g++.dg/ext/vla1.C, gcc.dg/vla-2.c: New tests. * g++.dg/ext/vla1.C, gcc.dg/vla-2.c: New tests.
......
// { dg-do compile { target i?86-*-* } }
struct c0 {
virtual void f ();
};
struct c1 : virtual public c0 {
};
struct c2 : virtual public c0, public c1 {
virtual void f ();
};
void c2::f () {}
// { dg-final { scan-assembler _ZTv0_n12_N2c21fEv } }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment