From a2ddc3977ab5a1ae4ed182155d403bc899d36f8e Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Mon, 27 Jan 2003 23:29:50 +0000 Subject: [PATCH] class.c (update_vtable_entry_for_fn): Add index parameter. cp: * class.c (update_vtable_entry_for_fn): Add index parameter. Generate vcall thunk for covariant overriding from a virtual primary base. (dfs_modify_vtables): Adjust. testsuite: * g++.dg/abi/covariant1.C: New test. From-SVN: r61906 --- gcc/cp/ChangeLog | 7 ++++ gcc/cp/class.c | 53 ++++++++++++++++++++++----- gcc/testsuite/ChangeLog | 4 ++ gcc/testsuite/g++.dg/abi/covariant1.C | 21 +++++++++++ 4 files changed, 75 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/g++.dg/abi/covariant1.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index fe8898f28d6..180fccb2fbf 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2003-01-27 Nathan Sidwell + + * class.c (update_vtable_entry_for_fn): Add index parameter. + Generate vcall thunk for covariant overriding from a virtual + primary base. + (dfs_modify_vtables): Adjust. + 2003-01-25 Nathan Sidwell PR c++/9403 diff --git a/gcc/cp/class.c b/gcc/cp/class.c index efc86e10708..6cdcb9a5b78 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -190,7 +190,7 @@ static void mark_primary_bases (tree); static tree mark_primary_virtual_base (tree, tree); static void clone_constructors_and_destructors (tree); static tree build_clone (tree, tree); -static void update_vtable_entry_for_fn (tree, tree, tree, tree *); +static void update_vtable_entry_for_fn (tree, tree, tree, tree *, unsigned); static tree copy_virtuals (tree); static void build_ctor_vtbl_group (tree, tree); static void build_vtt (tree); @@ -2395,7 +2395,8 @@ get_vcall_index (tree fn, tree type) corresponding position in the BINFO_VIRTUALS list. */ static void -update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals) +update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals, + unsigned ix) { tree b; tree overrider; @@ -2479,7 +2480,7 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals) virtual_offset = binfo_for_vbase (BINFO_TYPE (thunk_binfo), TREE_TYPE (over_return)); - offset = size_diffop (offset, + offset = size_binop (MINUS_EXPR, offset, BINFO_OFFSET (virtual_offset)); } if (fixed_offset) @@ -2523,6 +2524,38 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals) virtual_base = b; } + 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; + + for (probe = first_defn; (probe = get_primary_binfo (probe));) + { + if (TREE_VIA_VIRTUAL (probe)) + virtual_base = probe; + if ((unsigned) list_length (BINFO_VIRTUALS (probe)) <= ix) + break; + } + if (virtual_base) + /* Even if we find a virtual base, the correct delta is + between the overrider and the binfo we're building a vtable + for. */ + 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). */ @@ -2541,6 +2574,7 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals) /* The `this' pointer needs to be adjusted from pointing to BINFO to pointing at the base where the final overrider appears. */ + virtual_covariant: delta = size_diffop (BINFO_OFFSET (TREE_VALUE (overrider)), BINFO_OFFSET (binfo)); @@ -2564,26 +2598,25 @@ dfs_modify_vtables (tree binfo, void* data) /* Similarly, a base without a vtable needs no modification. */ && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))) { - tree t; + tree t = (tree) data; tree virtuals; tree old_virtuals; - - t = (tree) data; - + unsigned ix; + make_new_vtable (t, binfo); /* Now, go through each of the virtual functions in the virtual function table for BINFO. Find the final overrider, and update the BINFO_VIRTUALS list appropriately. */ - for (virtuals = BINFO_VIRTUALS (binfo), + for (ix = 0, virtuals = BINFO_VIRTUALS (binfo), old_virtuals = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (binfo))); virtuals; - virtuals = TREE_CHAIN (virtuals), + ix++, virtuals = TREE_CHAIN (virtuals), old_virtuals = TREE_CHAIN (old_virtuals)) update_vtable_entry_for_fn (t, binfo, BV_FN (old_virtuals), - &virtuals); + &virtuals, ix); } SET_BINFO_MARKED (binfo); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 0f62daf09a3..c778bcc6ee3 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2003-01-27 Nathan Sidwell + + * g++.dg/abi/covariant1.C: New test. + 2003-01-25 Ulrich Weigand * gcc.dg/20030123-1.c: New test. diff --git a/gcc/testsuite/g++.dg/abi/covariant1.C b/gcc/testsuite/g++.dg/abi/covariant1.C new file mode 100644 index 00000000000..203ec2c9fcb --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/covariant1.C @@ -0,0 +1,21 @@ +// { dg-do compile } +// { dg-options "-w" } + +// We don't want to use a covariant thunk to have a virtual +// primary base + +struct c4 {}; + +struct c6 : c4 { virtual c4* f17(); }; + +c4* c6::f17() { return 0; } + +struct c11 : virtual c6 { int i; }; + +struct c12 : c11 { }; + +struct c14 : + virtual c12, + virtual c11 { virtual c12* f17(); }; + +// { dg-final { scan-assembler-not "\n_ZTch0_v0_n16_N3c143f17Ev\[: \t\n\]" } }