[C++ Patch] PR 90909 ("[10 Regression] call devirtualized to pure virtual")
Paolo Carlini
paolo.carlini@oracle.com
Sun Jun 23 11:53:00 GMT 2019
... hi again ;)
The other day I was having a look at using declarations for this issue
and noticed that only a few lines below the de-virtualization check we
have to handle functions found by a using declaration, for various
reasons. In particular, we know whether we found a function fn where has
been declared or in a derived class. Thus the idea: for the purpose of
making some progress, in particular all the cases in c++/67184 & co,
would it make sense for the time being to simply add a check to the
de-virtualization condition restricting it to non-using declarations?
See the below (it also moves the conditional a few lines below only for
clarity and consistency with the code handling using declarations, no
functional impact) What do you think?
Thanks, Paolo.
///////////////////
-------------- next part --------------
Index: cp/call.c
===================================================================
--- cp/call.c (revision 272583)
+++ cp/call.c (working copy)
@@ -8241,12 +8241,6 @@ build_over_call (struct z_candidate *cand, int fla
return error_mark_node;
}
- /* 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 (TYPE_METHOD_BASETYPE (TREE_TYPE (fn))))
- flags |= LOOKUP_NONVIRTUAL;
-
/* [class.mfct.nonstatic]: If a nonstatic member function of a class
X is called for an object that is not of type X, or of a type
derived from X, the behavior is undefined.
@@ -8271,6 +8265,17 @@ build_over_call (struct z_candidate *cand, int fla
else
return error_mark_node;
}
+
+ /* 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))
+ /* Give up for now if fn was found by a using declaration,
+ the complex case, see c++/90909. */
+ && (TREE_TYPE (TREE_TYPE (converted_arg))
+ == TREE_TYPE (parmtype))))
+ flags |= LOOKUP_NONVIRTUAL;
+
/* If fn was found by a using declaration, the conversion path
will be to the derived class, not the base declaring fn. We
must convert from derived to base. */
Index: testsuite/g++.dg/other/final3.C
===================================================================
--- testsuite/g++.dg/other/final3.C (nonexistent)
+++ testsuite/g++.dg/other/final3.C (working copy)
@@ -0,0 +1,28 @@
+// PR c++/67184
+// { dg-do compile { target c++11 } }
+// { dg-options "-fdump-tree-original" }
+
+struct V {
+ virtual void foo();
+};
+
+struct wV final : V {
+};
+
+struct oV final : V {
+ void foo();
+};
+
+void call(wV& x)
+{
+ x.foo();
+ x.V::foo();
+}
+
+void call(oV& x)
+{
+ x.foo();
+ x.V::foo();
+}
+
+// { dg-final { scan-tree-dump-times "OBJ_TYPE_REF" 0 "original" } }
Index: testsuite/g++.dg/other/final4.C
===================================================================
--- testsuite/g++.dg/other/final4.C (nonexistent)
+++ testsuite/g++.dg/other/final4.C (working copy)
@@ -0,0 +1,16 @@
+// PR c++/67184
+// { dg-do compile { target c++11 } }
+// { dg-options "-fdump-tree-original" }
+
+struct B
+{
+ virtual void operator()();
+ virtual operator int();
+ virtual int operator++();
+};
+
+struct D final : B { };
+
+void foo(D& d) { d(); int t = d; ++d; }
+
+// { dg-final { scan-tree-dump-times "OBJ_TYPE_REF" 0 "original" } }
Index: testsuite/g++.dg/other/final5.C
===================================================================
--- testsuite/g++.dg/other/final5.C (nonexistent)
+++ testsuite/g++.dg/other/final5.C (working copy)
@@ -0,0 +1,19 @@
+// PR c++/69445
+// { dg-do compile { target c++11 } }
+// { dg-options "-fdump-tree-original" }
+
+struct Base {
+ virtual void foo() const = 0;
+ virtual void bar() const {}
+};
+
+struct C final : Base {
+ void foo() const { }
+};
+
+void func(const C & c) {
+ c.bar();
+ c.foo();
+}
+
+// { dg-final { scan-tree-dump-times "OBJ_TYPE_REF" 0 "original" } }
More information about the Gcc-patches
mailing list