aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2013-01-25 17:55:09 +0000
committerJason Merrill <jason@redhat.com>2013-01-25 17:55:09 +0000
commitc908cf849ef98f23d70f675e26e54be347bc9fe9 (patch)
tree5e2df0316d27809d43a8136fcd1dfb5585f1bac9
parent0cd4143524a316108d05138f4b3108d18b1c4fbf (diff)
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
-rw-r--r--gcc/cp/ChangeLog6
-rw-r--r--gcc/cp/typeck.c27
-rw-r--r--gcc/testsuite/g++.dg/warn/pmf2.C24
-rw-r--r--gcc/testsuite/g++.old-deja/g++.mike/pmf1.C2
4 files changed, 49 insertions, 10 deletions
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 <jason@redhat.com>
+
+ PR c++/56104
+ * typeck.c (get_member_function_from_ptrfunc): Optimize if the
+ dynamic type has no virtual functions.
+
2013-01-22 Paolo Carlini <paolo.carlini@oracle.com>
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<class MEMSIG, MEMSIG MEMFUNC>
+struct Wrap
+{
+ inline static void call( Foo cc )
+ {
+ (cc.*MEMFUNC)(); // <- warning here
+ }
+};
+
+void bar()
+{
+ Wrap<void (Foo::*)(), &Foo::call>::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
{