[C++ Patch] PR 90909 ("[10 Regression] call devirtualized to pure virtual")

Paolo Carlini paolo.carlini@oracle.com
Thu Jun 20 04:24:00 GMT 2019


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.

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



-------------- next part --------------
/cp
2019-06-20  Paolo Carlini  <paolo.carlini@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.carlini@oracle.com>

	PR c++/90909
	* g++.dg/other/final6.C: New.
-------------- next part --------------
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


More information about the Gcc-patches mailing list