Hi,

this bug notices that the more aggressive de-virtualization check that we have now in place (fixed c++/67184) doesn't work correctly for the below reproducer, which involves a pure virtual: we de-virtualize and the build fails at link-time. To cure this I believe we simply want an additional DECL_PURE_VIRTUAL_P in the condition. I also checked that the other compilers I have at hand appear to do the same, that is, they compile the reproducer both as-is and without the final specifier to the same assembly.

Note, in principle we have the option of not doing the additional DECL_PURE_VIRTUAL_P check when the final overrider comes from the class itself, not from a base, that is in the cases that we were already de-virtualizing pre-67184. That is, for something like:

struct A final
{
  virtual void foo () = 0;
};

void fun(A* a, B* b)
{
  a->foo();
}

devirtualize anyway (which then doesn't link). We could add back an '|| CLASSTYPE_FINAL (TYPE_METHOD_BASETYPE (TREE_TYPE (fn)))' for that. ICC appears to behave this way.

Tested x86_64-linux.

Thanks, Paolo.

////////////////////////



/cp
2019-06-20  Paolo Carlini  <paolo.carl...@oracle.com>

        PR c++/90909
        * call.c (build_over_call): Do not try to devirtualize when
        then function is pure virtual.

/testsuite
2019-06-20  Paolo Carlini  <paolo.carl...@oracle.com>

        PR c++/90909
        * g++.dg/other/final6.C: New.
Index: testsuite/g++.dg/other/final6.C
===================================================================
--- testsuite/g++.dg/other/final6.C     (nonexistent)
+++ testsuite/g++.dg/other/final6.C     (working copy)
@@ -0,0 +1,9 @@
+// PR c++/90909
+// { dg-do link { target c++11 } }
+
+struct S1 { virtual void f() = 0; };
+struct S2: S1 { virtual void f() {} };
+struct S3: S2 { using S1::f; };
+struct S4 final: S3 { void g(); };
+void S4::g() { f(); }
+int main() { S4().g(); }
Index: cp/call.c
===================================================================
--- cp/call.c   (revision 272410)
+++ cp/call.c   (working copy)
@@ -8244,7 +8244,8 @@ build_over_call (struct z_candidate *cand, int fla
       /* See if the function member or the whole class type is declared
         final and the call can be devirtualized.  */
       if (DECL_FINAL_P (fn)
-         || CLASSTYPE_FINAL (TREE_TYPE (argtype)))
+         || (CLASSTYPE_FINAL (TREE_TYPE (argtype))
+             && !DECL_PURE_VIRTUAL_P (fn)))
        flags |= LOOKUP_NONVIRTUAL;
 
       /* [class.mfct.nonstatic]: If a nonstatic member function of a class

Reply via email to