diff mbox

C++ PATCH for c++/65880 (wrong error with pointer to member function)

Message ID 5584573A.7000607@redhat.com
State New
Headers show

Commit Message

Jason Merrill June 19, 2015, 5:54 p.m. UTC
In this case merge_types was applying type quals to a POINTER_TYPE and 
then build_ptrmemfunc_type stripped them.  build_ptrmemfunc_type 
shouldn't assume that DECL_LANG_SPECIFIC is different between 
cv-variants of a type.

Tested x86_64-pc-linux-gnu, applying to trunk.  Applying decl.c hunk to 5.
diff mbox

Patch

commit 0fe2e085ba7febb30a2ab48f8690e2868d0e243a
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Jun 19 13:08:56 2015 -0400

    	PR c++/65880
    	* decl.c (build_ptrmemfunc_type): Check TYPE_GET_PTRMEMFUNC_TYPE after
    	cv-qualifiers.
    	* typeck.c (merge_types): build_ptrmemfunc_type before applying
    	quals and attributes.

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index c102a4e..515c2d3 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -8224,13 +8224,6 @@  build_ptrmemfunc_type (tree type)
   if (type == error_mark_node)
     return type;
 
-  /* If a canonical type already exists for this type, use it.  We use
-     this method instead of type_hash_canon, because it only does a
-     simple equality check on the list of field members.  */
-
-  if ((t = TYPE_GET_PTRMEMFUNC_TYPE (type)))
-    return t;
-
   /* Make sure that we always have the unqualified pointer-to-member
      type first.  */
   if (cp_cv_quals quals = cp_type_quals (type))
@@ -8239,6 +8232,13 @@  build_ptrmemfunc_type (tree type)
       return cp_build_qualified_type (unqual, quals);
     }
 
+  /* If a canonical type already exists for this type, use it.  We use
+     this method instead of type_hash_canon, because it only does a
+     simple equality check on the list of field members.  */
+
+  if ((t = TYPE_GET_PTRMEMFUNC_TYPE (type)))
+    return t;
+
   t = make_node (RECORD_TYPE);
 
   /* Let the front end know this is a pointer to member function.  */
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index c33ffd5..22fbb6e 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -786,15 +786,16 @@  merge_types (tree t1, tree t2)
 	int quals = cp_type_quals (t1);
 
 	if (code1 == POINTER_TYPE)
-	  t1 = build_pointer_type (target);
+	  {
+	    t1 = build_pointer_type (target);
+	    if (TREE_CODE (target) == METHOD_TYPE)
+	      t1 = build_ptrmemfunc_type (t1);
+	  }
 	else
 	  t1 = cp_build_reference_type (target, TYPE_REF_IS_RVALUE (t1));
 	t1 = build_type_attribute_variant (t1, attributes);
 	t1 = cp_build_qualified_type (t1, quals);
 
-	if (TREE_CODE (target) == METHOD_TYPE)
-	  t1 = build_ptrmemfunc_type (t1);
-
 	return t1;
       }
 
diff --git a/gcc/testsuite/g++.dg/overload/pmf3.C b/gcc/testsuite/g++.dg/overload/pmf3.C
new file mode 100644
index 0000000..a71f5544
--- /dev/null
+++ b/gcc/testsuite/g++.dg/overload/pmf3.C
@@ -0,0 +1,70 @@ 
+// PR c++/65880
+
+class Test
+{
+  public:
+    Test();
+    ~Test();
+
+    bool barl(void);
+
+  private:
+    bool fool(bool (Test::* const *fms)(void));
+    bool foo(void);
+    bool bar(void);
+};
+
+Test::Test()
+{
+}
+
+Test::~Test()
+{
+}
+
+bool Test::fool(bool (Test::* const *fms)(void))
+{
+    bool retval = false;
+
+    int i = 0;
+    bool (Test::*f)(void) = fms[i++];
+
+    while (f) {
+        retval = (this->*f)();
+        if (retval) break;
+        f = fms[i++];
+    }
+
+    return retval;
+}
+
+
+bool Test::barl(void)
+{
+    static bool (Test::* const fms[])(void) = {
+        &Test::foo,
+        &Test::bar,
+        0
+    };
+
+
+
+    return fool(fms);
+}
+
+
+bool Test::foo(void)
+{
+    return false;
+}
+
+bool Test::bar(void)
+{
+    return true;
+}
+
+int main(int argc, const char *argv[])
+{
+    Test t;
+    return t.barl();
+}