This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] Fix PR c++/8171: Allow comparison of ptr-to-mem-fct of base and derived class


The C++ frontend rejects comparisons (== or !=) between
pointer-to-member-functions where the involved classes are not
identical, but derived from each other like in this code snippet:

  struct A
  {
      void foo() {}
  };

  struct B : A {};

  int bar()
  {
      void (A::*pa)() = &A::foo;
      void (B::*pb)() = &B::foo;

      return pa == pb;
  }

The following patch fixes that by changing the case METHOD_TYPE in
in comptypes (from cp/typeck.c) to honor the flag STRICT when comparing
the first arguments of the functions. That's where the pointer to the
classes are stored. Actually the patch strips away the pointers (by
calling TREE_TYPE) in order to compare the underlying classes directly.

The function build_binary_op (also from cp/typeck.c) makes use of
this modified comparison for METHOD_TYPE by calling comptypes with
the parameter STRICT = COMPARE_BASE | COMPARE_DERIVED and not with
parameter STRICT = 0 (like the macro same_type_p does).
Instead of calling comptypes with the pointer-to-member-functions,
the pointers are stripped away before the call, so that the
member-functions are compared directly.

The patch also adds to testcases: The first not only checks that
these comparisons are now accepted, but also checks that their
outcome is correct. The second testcase checks that comparisons
where the underlying classes are not derived from each other
are rejected.

Bootstrapped and regtested on x86_64-unknown-linux-gnu.
Ok for mainline?

Regards,
Volker

:ADDPATCH C++:


2006-04-21  Volker Reichelt  <reichelt@igpm.rwth-aachen.de>

	PR c++/8171
	* typeck.c (comptypes) <METHOD_TYPE>: Do not fall-through to
	FUNCTION_TYPE, but use a slightly modified version: Compare the
	class-pointers according to the parameter STRICT.
	(build_binary_op) <EQ_EXPR, NE_EXPR>: Allow derived classes when
	comparing ptr-to-member-functions.  Strip pointer before calling
	comptypes.

===================================================================
--- gcc/gcc/cp/typeck.c	2006-03-14 18:36:29 +0100
+++ gcc/gcc/cp/typeck.c	2006-04-21 01:45:33 +0200
@@ -1042,6 +1042,16 @@ comptypes (tree t1, tree t2, int strict)
       break;
 
     case METHOD_TYPE:
+      if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+	return false;
+      if (!comptypes (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t1))),
+		      TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t2))), strict))
+	return false;
+      if (!compparms (TREE_CHAIN (TYPE_ARG_TYPES (t1)),
+		      TREE_CHAIN (TYPE_ARG_TYPES (t2))))
+	return false;
+      break;
+
     case FUNCTION_TYPE:
       if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
 	return false;
@@ -3189,7 +3199,9 @@ build_binary_op (enum tree_code code,
       else if (TYPE_PTRMEMFUNC_P (type1) && null_ptr_cst_p (op0))
 	return cp_build_binary_op (code, op1, op0);
       else if (TYPE_PTRMEMFUNC_P (type0) && TYPE_PTRMEMFUNC_P (type1)
-	       && same_type_p (type0, type1))
+	       && comptypes (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (type0)),
+			     TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (type1)),
+			     COMPARE_BASE | COMPARE_DERIVED))
 	{
 	  /* E will be the final comparison.  */
 	  tree e;
===================================================================

2006-04-21  Volker Reichelt  <reichelt@igpm.rwth-aachen.de>

	PR c++/8171
	* g++.dg/conversion/ptrmemfun1.C: New test.
	* g++.dg/conversion/ptrmemfun2.C: New test.

===================================================================
--- gcc/gcc/testsuite/g++.dg/conversion/ptrmemfun1.C	2005-08-29 00:25:44 +0200
+++ gcc/gcc/testsuite/g++.dg/conversion/ptrmemfun1.C	2006-04-21 17:17:12 +0200
@@ -0,0 +1,29 @@
+// PR c++/8171
+// Origin: <zyzstar@ibl.sk>
+// { dg-do run }
+
+extern "C" void abort();
+
+struct A
+{
+  void foo() {}
+  void bar() {}
+};
+
+struct B : A {};
+
+int main()
+{
+  void (A::*pa)() = &A::foo;
+  void (B::*pb)() = &B::foo;
+  void (B::*pc)() = &B::bar;
+
+  if (pa != pb)
+    abort();
+  if (pa == pc)
+    abort();
+  if (pb == pc)
+    abort();
+
+  return 0;
+}
===================================================================
--- gcc/gcc/testsuite/g++.dg/conversion/ptrmemfun2.C	2005-08-29 00:25:44 +0200
+++ gcc/gcc/testsuite/g++.dg/conversion/ptrmemfun2.C	2006-04-21 18:22:20 +0200
@@ -0,0 +1,19 @@
+// PR c++/8171
+// { dg-do compile }
+
+struct A
+{
+  void foo() {}
+};
+
+struct B : A {};
+
+struct C : A {};
+
+int main()
+{
+  void (B::*pb)() = &B::foo;
+  void (C::*pc)() = &C::foo;
+
+  return pb == pc;  // { dg-error "invalid operands" }
+}
===================================================================



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]