+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>
PR c++/7228
static tree get_vfield_name 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_basefndecls PARAMS ((tree, tree));
static int build_primary_vtable PARAMS ((tree, tree));
tree delta;
tree vcall_index;
tree fn;
- tree pfn;
tree init = NULL_TREE;
fn = BV_FN (v);
So, we replace these functions with __pure_virtual. */
if (DECL_PURE_VIRTUAL_P (fn))
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
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. */
- TREE_CONSTANT (pfn) = 1;
-
- /* Enter it in the vtable. */
- init = build_vtable_entry (delta, vcall_index, pfn);
+ TREE_CONSTANT (init) = 1;
}
/* And add it to the chain of initializers. */
*vid->last_init = build_tree_list (NULL_TREE, 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;
-}
For a FUNCTION_TYPE or METHOD_TYPE, this is TYPE_RAISES_EXCEPTIONS
BINFO_VIRTUALS
- For a binfo, this is a TREE_LIST. 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.
+ For a binfo, this is a TREE_LIST. There is an entry for each
+ virtual function declared either in BINFO or its direct and
+ indirect primary bases.
+
+ 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
index of the vcall offset for this entry. If
non-virtual FUNCTION_DECL, this is DECL_FRIEND_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. */
tree cloned_function;
#define DECL_NEEDS_FINAL_OVERRIDER_P(NODE) \
(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. */
#define DECL_THUNK_P(NODE) \
(TREE_CODE (NODE) == FUNCTION_DECL \
/* Only functions have DECL_BEFRIENDING_CLASSES. */
if (TREE_CODE (newdecl) == FUNCTION_DECL
|| DECL_FUNCTION_TEMPLATE_P (newdecl))
- DECL_BEFRIENDING_CLASSES (newdecl)
- = chainon (DECL_BEFRIENDING_CLASSES (newdecl),
- DECL_BEFRIENDING_CLASSES (olddecl));
+ {
+ DECL_BEFRIENDING_CLASSES (newdecl)
+ = chainon (DECL_BEFRIENDING_CLASSES (newdecl),
+ DECL_BEFRIENDING_CLASSES (olddecl));
+ DECL_THUNKS (newdecl) = DECL_THUNKS (olddecl);
+ }
}
if (TREE_CODE (newdecl) == FUNCTION_DECL)
{
tree thunk_id;
tree thunk;
- tree func_decl;
tree vcall_offset;
HOST_WIDE_INT d;
+ my_friendly_assert (TREE_CODE (function) == FUNCTION_DECL, 20021025);
+
/* Scale the VCALL_INDEX to be in terms of bytes. */
if (vcall_index)
vcall_offset
d = tree_low_cst (delta, 0);
- if (TREE_CODE (function) != ADDR_EXPR)
- abort ();
- func_decl = TREE_OPERAND (function, 0);
- if (TREE_CODE (func_decl) != FUNCTION_DECL)
- abort ();
+ /* See if we already have the thunk in question. */
+ for (thunk = DECL_THUNKS (function); thunk; thunk = TREE_CHAIN (thunk))
+ if (THUNK_DELTA (thunk) == d
+ && ((THUNK_VCALL_OFFSET (thunk) != NULL_TREE)
+ == (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;
}
enabling you to output all the thunks with the function itself. */
if (DECL_VIRTUAL_P (fn))
{
- tree binfo;
- tree v;
-
- 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);
- }
+ tree thunk;
+ for (thunk = DECL_THUNKS (fn); thunk; thunk = TREE_CHAIN (thunk))
+ 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>
* g++.dg/ext/vla1.C, gcc.dg/vla-2.c: New tests.
--- /dev/null
+// { 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 } }