re PR c++/43120 (Virtual inheritance with covariant return type confuses GCC)
authorJason Merrill <jason@redhat.com>
Thu, 8 Jul 2010 14:00:26 +0000 (10:00 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Thu, 8 Jul 2010 14:00:26 +0000 (10:00 -0400)
PR c++/43120
* class.c (update_vtable_entry_for_fn): Fix handling of dummy
virtual bases for covariant thunks.

From-SVN: r161954

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/abi/covariant1.C
gcc/testsuite/g++.dg/inherit/covariant17.C [new file with mode: 0644]

index 983d751570f9b67e04703e119537d92f5281091b..0a3f54a7c1b9931e990b9ec975c1e788aa285266 100644 (file)
@@ -1,7 +1,13 @@
+2010-07-08  Jason Merrill  <jason@redhat.com>
+
+       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  <manu@gcc.gnu.org>
 
        * cp-tree.h: Do not include toplev.h.
-       
+
 2010-07-06  Jason Merrill  <jason@redhat.com>
 
        PR c++/44703
index 3c4830e857e2b9495957ead2f09c9fde9e1a8c8f..20b8c1245c17b9371d743e82631693596bc2f591 100644 (file)
@@ -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))),
index ba1123922de91076a52e5976ad216a040ff4c008..7bf8c0254ceb6724b85ec63ebe64ef867f56fc1e 100644 (file)
@@ -1,3 +1,9 @@
+2010-07-08  Jason Merrill  <jason@redhat.com>
+
+       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  <hongjiu.lu@intel.com>
 
        PR rtl-optimization/44838
index 203ec2c9fcb237105b0dff03b18bf1fb775d63bf..42522c1b92578e89afad3ed89ac564574d6d519a 100644 (file)
@@ -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 (file)
index 0000000..26031d5
--- /dev/null
@@ -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;
+}