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  <aol...@redhat.com>
            Paolo Carlini  <paolo.carl...@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  <aol...@redhat.com>
            Paolo Carlini  <paolo.carl...@oracle.com>

        PR c++/17805
        * g++.dg/overload/operator6.C: New.
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);

Reply via email to