diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 8d12568a675..fc5351815bb 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2012-11-14 Fabien ChĂȘne + + PR c++/11750 + * call.c (build_new_method_call_1): Check that the instance type + and the function context are the same before setting the flag + LOOKUP_NONVIRTUAL. + 2012-11-13 Sriraman Tallam * class.c (mark_versions_used): Remove. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index bbeea852629..77bd28882d6 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -7652,9 +7652,15 @@ build_new_method_call_1 (tree instance, tree fns, VEC(tree,gc) **args, } else { - /* Optimize away vtable lookup if we know that this function - can't be overridden. */ + /* Optimize away vtable lookup if we know that this + function can't be overridden. We need to check if + the context and the instance type are the same, + actually FN might be defined in a different class + type because of a using-declaration. In this case, we + do not want to perform a non-virtual call. */ if (DECL_VINDEX (fn) && ! (flags & LOOKUP_NONVIRTUAL) + && same_type_ignoring_top_level_qualifiers_p + (DECL_CONTEXT (fn), TREE_TYPE (instance)) && resolves_to_fixed_type_p (instance, 0)) flags |= LOOKUP_NONVIRTUAL; if (explicit_targs) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index fec239c5ecb..23424c50154 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2012-11-14 Fabien ChĂȘne + + PR c++/11750 + * call.c (build_new_method_call_1): Check that the instance type + and the function context are the same before setting the flag + LOOKUP_NONVIRTUAL. + 2012-11-13 Sriraman Tallam * testsuite/g++.dg/mv4.C: Add require ifunc. Change error message. diff --git a/gcc/testsuite/g++.dg/inherit/virtual9.C b/gcc/testsuite/g++.dg/inherit/virtual9.C new file mode 100644 index 00000000000..03342646ff5 --- /dev/null +++ b/gcc/testsuite/g++.dg/inherit/virtual9.C @@ -0,0 +1,44 @@ +// { dg-do run } +// PR c++/11750 + +struct A +{ + virtual void f() const { __builtin_abort(); } + virtual void g() {} +}; + +struct B : virtual A +{ + virtual void f() const {} + virtual void g() { __builtin_abort(); } +}; + +struct C : B, virtual A +{ + using A::f; + using A::g; +}; + +int main() +{ + C c; + c.f(); // call B::f + + C c2; + c2.C::g(); // call A::g + + C* c3 = &c; + c3->f(); // call B::f + + C& c4 = c; + c4.f(); // call B::f + + C const* c5 = &c; + c5->f(); // call B::f + + C** c6 = &c3; + (*c6)->f(); // call B::f + + C const& c7 = c; + c7.f(); // call B::f +}