Bootstrapped and rgetested on x86_64-pc-linux-gnu, does this look OK for
trunk?

In order to properly handle all rewritten operator expressions, I
suppose we could teach build_min_non_dep_op_overload to carefully look
through 'non_dep' and note when arguments are reversed etc.  But rather
than that, I wonder if we should just remove build_min_non_dep_op_overload
and stick with the templated CALL_EXPR returned by build_new_op in
the first place?  Making build_min_non_dep_op_overload a no-op that just
returns 'non_dep' seems to work nicely in for my tests, e.g.
operator-8.C is now accepted completely.

In any case this I reckon this narrow fix would be good to get in
incrementally in order to fix the libstdc++/std module error.

-- >8 --

Here we're incorrectly rejecting the modules testcase (reduced from a
std module example):

$ cat 121179_a.C
export module foo;

enum class E { x };
bool operator==(E, int);

export
template<class T>
void f() {
  E::x != 0;
}

$ cat 121179_b.C
import foo;

template void f<int>();

$ g++ -fmodules 121179_*.C
In module foo, imported at 121179_b.C:1:
121179_a.C: In instantiation of ‘void f@foo() [with T = int]’:
121179_b.C:3:9:   required from here
121179_a.C:9:8: error: no match for ‘operator!=’ (operand types are ‘E@foo’ and 
‘int’)

This is ultimately because our non-dependent rewritten operator expression
handling throws away the result of unqualified lookup at template parse time,
and so we have to repeat the lookup at instantiation time which fails because
the operator== isn't exported.

This patch fixes this known deficiency in build_min_non_dep_op_overload
narrowly for simple != to == rewrites.

        PR c++/121179

gcc/cp/ChangeLog:

        * call.cc (build_new_op): Don't clear *overload for a simple
        != to == rewrite.
        * tree.cc (build_min_non_dep_op_overload): Handle TRUTH_NOT_EXPR
        appearing in a rewritten operator expression.

gcc/testsuite/ChangeLog:

        * g++.dg/lookup/operator-8.C: Strengthen test and remove one
        XFAIL.
---
 gcc/cp/call.cc                           | 4 +++-
 gcc/cp/tree.cc                           | 3 +++
 gcc/testsuite/g++.dg/lookup/operator-8.C | 9 ++++++++-
 3 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 26296255b1ec..a25b6a2b31c0 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -7535,7 +7535,9 @@ build_new_op (const op_location_t &loc, enum tree_code 
code, int flags,
          if (cand->rewritten ())
            {
              /* FIXME build_min_non_dep_op_overload can't handle rewrites.  */
-             if (overload)
+             if (code == NE_EXPR && !cand->reversed ())
+               /* It can handle != rewritten to == though.  */;
+             else if (overload)
                *overload = NULL_TREE;
              switch (code)
                {
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index a7b890884abd..a0db961a5f1f 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -3696,6 +3696,7 @@ build_min_non_dep_op_overload (enum tree_code op,
   int nargs, expected_nargs;
   tree fn, call, obj = NULL_TREE;
 
+  bool rewritten = (TREE_CODE (non_dep) == TRUTH_NOT_EXPR);
   non_dep = extract_call_expr (non_dep);
 
   nargs = call_expr_nargs (non_dep);
@@ -3753,6 +3754,8 @@ build_min_non_dep_op_overload (enum tree_code op,
   CALL_EXPR_ORDERED_ARGS (call_expr) = CALL_EXPR_ORDERED_ARGS (non_dep);
   CALL_EXPR_REVERSE_ARGS (call_expr) = CALL_EXPR_REVERSE_ARGS (non_dep);
 
+  if (rewritten)
+    call = build_min (TRUTH_NOT_EXPR, boolean_type_node, call);
   if (obj)
     return keep_unused_object_arg (call, obj, overload);
   return call;
diff --git a/gcc/testsuite/g++.dg/lookup/operator-8.C 
b/gcc/testsuite/g++.dg/lookup/operator-8.C
index 64d8a97cdd00..c5972d119d66 100644
--- a/gcc/testsuite/g++.dg/lookup/operator-8.C
+++ b/gcc/testsuite/g++.dg/lookup/operator-8.C
@@ -16,7 +16,8 @@ struct A {
 template<class T>
 void f() {
   A a;
-  (void)(a != 0, 0 != a); // { dg-bogus "deleted" "" { xfail *-*-* } }
+  (void)(a != 0);         // We only handle this special case after PR121179
+  (void)(0 != a);         // { dg-bogus "deleted" "" { xfail *-*-* } }
   (void)(a < 0, 0 < a);   // { dg-bogus "deleted" "" { xfail *-*-* } }
   (void)(a <= 0, 0 <= a); // { dg-bogus "deleted" "" { xfail *-*-* } }
   (void)(a > 0, 0 > a);   // { dg-bogus "deleted" "" { xfail *-*-* } }
@@ -31,4 +32,10 @@ bool operator<=(A, int) = delete;
 bool operator>(A, int) = delete;
 bool operator>=(A, int) = delete;
 
+bool operator!=(int, A) = delete;
+bool operator<(int, A) = delete;
+bool operator<=(int, A) = delete;
+bool operator>(int, A) = delete;
+bool operator>=(int, A) = delete;
+
 template void f<int>();
-- 
2.50.1.319.g90c0775e97

Reply via email to