commit 337b414b3475c8e3d9a504046da549b2b2f69a27
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Jan 25 10:37:26 2013 -0500

    	PR c++/56104
    	* typeck.c (get_member_function_from_ptrfunc): Optimize if the
    	dynamic type has no virtual functions.

diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 093e7c1..bfac394 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 0000000..be13819
--- /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 15460eb..aa1ea3e 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
 {
