From c908cf849ef98f23d70f675e26e54be347bc9fe9 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 25 Jan 2013 17:55:09 +0000 Subject: PR c++/56104 * typeck.c (get_member_function_from_ptrfunc): Optimize if the dynamic type has no virtual functions. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@195470 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/cp/ChangeLog | 6 ++++++ gcc/cp/typeck.c | 27 ++++++++++++++++++--------- gcc/testsuite/g++.dg/warn/pmf2.C | 24 ++++++++++++++++++++++++ gcc/testsuite/g++.old-deja/g++.mike/pmf1.C | 2 +- 4 files changed, 49 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/g++.dg/warn/pmf2.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9a25935adff..3d304917b3c 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2013-01-25 Jason Merrill + + PR c++/56104 + * typeck.c (get_member_function_from_ptrfunc): Optimize if the + dynamic type has no virtual functions. + 2013-01-22 Paolo Carlini PR c++/55944 diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 093e7c148fa..bfac39494e2 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -3122,7 +3122,8 @@ build_array_ref (location_t loc, tree array, tree idx) With the final ISO C++ rules, such an optimization is incorrect: A pointer to a derived member can be static_cast to pointer-to-base-member, as long as the dynamic object - later has the right member. */ + later has the right member. So now we only do this optimization + when we know the dynamic type of the object. */ tree get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function, @@ -3133,8 +3134,10 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function, if (TYPE_PTRMEMFUNC_P (TREE_TYPE (function))) { - tree idx, delta, e1, e2, e3, vtbl, basetype; + tree idx, delta, e1, e2, e3, vtbl; + bool nonvirtual; tree fntype = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function)); + tree basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (fntype)); tree instance_ptr = *instance_ptrptr; tree instance_save_expr = 0; @@ -3157,6 +3160,12 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function, } } + /* True if we know that the dynamic type of the object doesn't have + virtual functions, so we can assume the PFN field is a pointer. */ + nonvirtual = (COMPLETE_TYPE_P (basetype) + && !TYPE_POLYMORPHIC_P (basetype) + && resolves_to_fixed_type_p (instance_ptr, 0)); + if (TREE_SIDE_EFFECTS (instance_ptr)) instance_ptr = instance_save_expr = save_expr (instance_ptr); @@ -3167,7 +3176,9 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function, e3 = pfn_from_ptrmemfunc (function); delta = delta_from_ptrmemfunc (function); idx = build1 (NOP_EXPR, vtable_index_type, e3); - switch (TARGET_PTRMEMFUNC_VBIT_LOCATION) + if (nonvirtual) + e1 = integer_zero_node; + else switch (TARGET_PTRMEMFUNC_VBIT_LOCATION) { case ptrmemfunc_vbit_in_pfn: e1 = cp_build_binary_op (input_location, @@ -3204,7 +3215,6 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function, a member of C, and no conversion is required. In fact, lookup_base will fail in that case, because incomplete classes do not have BINFOs. */ - basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (fntype)); if (!same_type_ignoring_top_level_qualifiers_p (basetype, TREE_TYPE (TREE_TYPE (instance_ptr)))) { @@ -3221,6 +3231,10 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function, /* Hand back the adjusted 'this' argument to our caller. */ *instance_ptrptr = instance_ptr; + if (nonvirtual) + /* Now just return the pointer. */ + return e3; + /* Next extract the vtable pointer from the object. */ vtbl = build1 (NOP_EXPR, build_pointer_type (vtbl_ptr_type_node), instance_ptr); @@ -3228,11 +3242,6 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function, if (vtbl == error_mark_node) return error_mark_node; - /* If the object is not dynamic the access invokes undefined - behavior. As it is not executed in this case silence the - spurious warnings it may provoke. */ - TREE_NO_WARNING (vtbl) = 1; - /* Finally, extract the function pointer from the vtable. */ e2 = fold_build_pointer_plus_loc (input_location, vtbl, idx); e2 = cp_build_indirect_ref (e2, RO_NULL, complain); diff --git a/gcc/testsuite/g++.dg/warn/pmf2.C b/gcc/testsuite/g++.dg/warn/pmf2.C new file mode 100644 index 00000000000..be138190b09 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/pmf2.C @@ -0,0 +1,24 @@ +// PR c++/56104 +// { dg-options "-Wall -O2" } + +struct Foo +{ + Foo(); + Foo(const Foo&); + void call() + {} +}; + +template +struct Wrap +{ + inline static void call( Foo cc ) + { + (cc.*MEMFUNC)(); // <- warning here + } +}; + +void bar() +{ + Wrap::call( Foo() ); +} diff --git a/gcc/testsuite/g++.old-deja/g++.mike/pmf1.C b/gcc/testsuite/g++.old-deja/g++.mike/pmf1.C index 15460ebaaa5..aa1ea3efaef 100644 --- a/gcc/testsuite/g++.old-deja/g++.mike/pmf1.C +++ b/gcc/testsuite/g++.old-deja/g++.mike/pmf1.C @@ -1,5 +1,5 @@ // { dg-do run } -// extern "C" printf(const char *, ...); +// extern "C" int printf(const char *, ...); class X { -- cgit v1.2.3