Patchwork [C++] PR 17805

login
register
mail settings
Submitter Paolo Carlini
Date Oct. 14, 2012, 12:11 a.m.
Message ID <507A0333.8020504@oracle.com>
Download mbox | patch
Permalink /patch/191330/
State New
Headers show

Comments

Paolo Carlini - Oct. 14, 2012, 12:11 a.m.
Hi,

back in 2005 Alexandre worked on this issue up to the point that Mark 
approved a patch conditional to a couple of straightforward changes (see 
audit trail). Then nothing happened ;)

Today I resurrected the patch, implemented the requests and in the 
process noticed that it wasn't really handling the single argument case, 
thus I also extended a bit the testcase.

Tested x86_64-linux. (Finally) Ok?

Thanks,
Paolo.

///////////////////////////////
/cp
2012-10-14  Alexandre Oliva  <aoliva@redhat.com>
	    Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/17805
	* call.c (build_new_op): Filter out operator functions that don't
	satisfy enum-conversion match requirements.

/testsuite
2012-10-14  Alexandre Oliva  <aoliva@redhat.com>
	    Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/17805
	* g++.dg/overload/operator6.C: New.
Jason Merrill - Oct. 15, 2012, 5:57 p.m.
OK.

Jason

Patch

Index: cp/call.c
===================================================================
--- cp/call.c	(revision 192425)
+++ cp/call.c	(working copy)
@@ -5043,6 +5043,11 @@  build_new_op_1 (location_t loc, enum tree_code cod
 		  NULL_TREE, arglist, NULL_TREE,
 		  NULL_TREE, false, NULL_TREE, NULL_TREE,
 		  flags, &candidates, complain);
+
+  args[0] = arg1;
+  args[1] = arg2;
+  args[2] = NULL_TREE;
+
   /* Add class-member operators to the candidate set.  */
   if (CLASS_TYPE_P (TREE_TYPE (arg1)))
     {
@@ -5062,11 +5067,50 @@  build_new_op_1 (location_t loc, enum tree_code cod
 			BASELINK_ACCESS_BINFO (fns),
 			flags, &candidates, complain);
     }
+  /* Per 13.3.1.2/3, 2nd bullet, if no operand has a class type, then
+     only non-member functions that have type T1 or reference to
+     cv-qualified-opt T1 for the first argument, if the first argument
+     has an enumeration type, or T2 or reference to cv-qualified-opt
+     T2 for the second argument, if the the second argument has an
+     enumeration type.  Filter out those that don't match.  */
+  else if (! arg2 || ! CLASS_TYPE_P (TREE_TYPE (arg2)))
+    {
+      struct z_candidate **candp, **next;
 
-  args[0] = arg1;
-  args[1] = arg2;
-  args[2] = NULL_TREE;
+      for (candp = &candidates; *candp; candp = next)
+	{
+	  tree parmlist, parmtype;
+	  int i, nargs = (arg2 ? 2 : 1);
 
+	  cand = *candp;
+	  next = &cand->next;
+
+	  parmlist = TYPE_ARG_TYPES (TREE_TYPE (cand->fn));
+
+	  for (i = 0; i < nargs; ++i)
+	    {
+	      parmtype = TREE_VALUE (parmlist);
+
+	      if (TREE_CODE (parmtype) == REFERENCE_TYPE)
+		parmtype = TREE_TYPE (parmtype);
+	      if (TREE_CODE (TREE_TYPE (args[i])) == ENUMERAL_TYPE
+		  && (same_type_ignoring_top_level_qualifiers_p
+		      (TREE_TYPE (args[i]), parmtype)))
+		break;
+
+	      parmlist = TREE_CHAIN (parmlist);
+	    }
+
+	  /* No argument has an appropriate type, so remove this
+	     candidate function from the list.  */
+	  if (i == nargs)
+	    {
+	      *candp = cand->next;
+	      next = candp;
+	    }
+	}
+    }
+
   add_builtin_candidates (&candidates, code, code2, fnname, args,
 			  flags, complain);
 
Index: testsuite/g++.dg/overload/operator6.C
===================================================================
--- testsuite/g++.dg/overload/operator6.C	(revision 0)
+++ testsuite/g++.dg/overload/operator6.C	(working copy)
@@ -0,0 +1,27 @@ 
+// PR c++/17805
+
+// Per 13.3.1.2/3 bullet 2, an operator function is not a candidate
+// for overload resolution if neither argument is of class type and
+// neither enumerator-typed argument gets an exact match, with or
+// without reference binding, for the corresponding parameter.
+
+struct A
+{
+  A(int);
+  A(const char*);
+};
+
+bool operator==(const A&, const A&);
+const A& operator*(const A&);
+
+enum E { e };
+
+bool b1 = (e == "");     // { dg-error "no match" }
+
+bool b2 = (A(1) == "");
+
+bool b3 = (e == A(1));
+
+const A& a1 = *e;        // { dg-error "no match" }
+
+const A& a2 = *A(1);