diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 983d751570f..0a3f54a7c1b 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,7 +1,13 @@ +2010-07-08 Jason Merrill + + PR c++/43120 + * class.c (update_vtable_entry_for_fn): Fix handling of dummy + virtual bases for covariant thunks. + 2010-07-08 Manuel López-Ibáñez * cp-tree.h: Do not include toplev.h. - + 2010-07-06 Jason Merrill PR c++/44703 diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 3c4830e857e..20b8c1245c1 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -2058,8 +2058,9 @@ get_vcall_index (tree fn, tree type) } /* Update an entry in the vtable for BINFO, which is in the hierarchy - dominated by T. FN has been overridden in BINFO; VIRTUALS points to the - corresponding position in the BINFO_VIRTUALS list. */ + dominated by T. FN is the old function; VIRTUALS points to the + corresponding position in the new BINFO_VIRTUALS list. IX is the index + of that entry in the list. */ static void update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals, @@ -2252,9 +2253,11 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals, virtual_base = probe; 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. */ + /* OK, first_defn got this function from a (possibly lost) primary + virtual base, so we're going to use the vcall offset for that + primary virtual base. But the caller is passing a first_defn*, + not a virtual_base*, so the correct delta is the delta between + first_defn* and itself, i.e. zero. */ goto virtual_covariant; } @@ -2272,12 +2275,12 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals, entry in our vtable. Except possibly in a constructor vtable, if we happen to get our primary back. In that case, the offset will be zero, as it will be a primary base. */ + virtual_covariant: delta = size_zero_node; else /* 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_loc (input_location, convert (ssizetype, BINFO_OFFSET (TREE_VALUE (overrider))), diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ba1123922de..7bf8c0254ce 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2010-07-08 Jason Merrill + + PR c++/43120 + * g++.dg/inherit/covariant17.C: New. + * g++.dg/abi/covariant1.C: Actually test for the bug. + 2010-07-08 H.J. Lu PR rtl-optimization/44838 diff --git a/gcc/testsuite/g++.dg/abi/covariant1.C b/gcc/testsuite/g++.dg/abi/covariant1.C index 203ec2c9fcb..42522c1b925 100644 --- a/gcc/testsuite/g++.dg/abi/covariant1.C +++ b/gcc/testsuite/g++.dg/abi/covariant1.C @@ -16,6 +16,11 @@ struct c12 : c11 { }; struct c14 : virtual c12, - virtual c11 { virtual c12* f17(); }; + virtual c11 { virtual void f(); c12* f17(); }; -// { dg-final { scan-assembler-not "\n_ZTch0_v0_n16_N3c143f17Ev\[: \t\n\]" } } +void c14::f() { } + +// { dg-final { scan-assembler "_ZTcv0_n12_v0_n16_N3c143f17Ev" { target ilp32 } } } +// { dg-final { scan-assembler-not "_ZTch0_v0_n16_N3c143f17Ev" } } +// { dg-final { scan-assembler "_ZTcv0_n24_v0_n32_N3c143f17Ev" { target lp64 } } } +// { dg-final { scan-assembler-not "_ZTch0_v0_n32_N3c143f17Ev" } } diff --git a/gcc/testsuite/g++.dg/inherit/covariant17.C b/gcc/testsuite/g++.dg/inherit/covariant17.C new file mode 100644 index 00000000000..26031d52ca9 --- /dev/null +++ b/gcc/testsuite/g++.dg/inherit/covariant17.C @@ -0,0 +1,40 @@ +// PR c++/43120 +// { dg-do run } + +extern "C" void abort (); + +struct A { + int a; + + A(int a_) : a(a_) {} + + A(const A &other) { } + + virtual void dummy() {} +}; + +struct B { + virtual B *clone() const = 0; +}; + +struct C : public virtual B { + virtual B *clone() const = 0; +}; + +struct E* ep; +struct E : public A, public C { + E(int a_) : A(a_) { ep = this; } + + virtual E *clone() const { + if (this != ep) + abort(); + return new E(*this); + } +}; + +int main() { + E *a = new E(123); + B *c = a; + B *d = c->clone(); + return 0; +}