bool check_list_ctor = false;
bool check_converting = false;
unification_kind_t strict;
+ tree ne_context = NULL_TREE;
tree ne_fns = NULL_TREE;
if (!fns)
tree ne_name = ovl_op_identifier (false, NE_EXPR);
if (DECL_CLASS_SCOPE_P (fn))
{
+ ne_context = DECL_CONTEXT (fn);
ne_fns = lookup_fnfields (TREE_TYPE ((*args)[0]), ne_name,
1, tf_none);
if (ne_fns == error_mark_node || ne_fns == NULL_TREE)
}
else
{
- tree context = decl_namespace_context (fn);
- ne_fns = lookup_qualified_name (context, ne_name, LOOK_want::NORMAL,
+ ne_context = decl_namespace_context (fn);
+ ne_fns = lookup_qualified_name (ne_context, ne_name,
+ LOOK_want::NORMAL,
/*complain*/false);
if (ne_fns == error_mark_node
|| !is_overloaded_fn (ne_fns))
/* When considering reversed operator==, if there's a corresponding
operator!= in the same scope, it's not a rewrite target. */
- if (ne_fns)
+ if (ne_context)
{
+ if (TREE_CODE (ne_context) == NAMESPACE_DECL)
+ {
+ /* With argument-dependent lookup, fns can span multiple
+ namespaces; make sure we look in the fn's namespace for a
+ corresponding operator!=. */
+ tree fn_ns = decl_namespace_context (fn);
+ if (fn_ns != ne_context)
+ {
+ ne_context = fn_ns;
+ tree ne_name = ovl_op_identifier (false, NE_EXPR);
+ ne_fns = lookup_qualified_name (ne_context, ne_name,
+ LOOK_want::NORMAL,
+ /*complain*/false);
+ if (ne_fns == error_mark_node
+ || !is_overloaded_fn (ne_fns))
+ ne_fns = NULL_TREE;
+ }
+ }
bool found = false;
for (lkp_iterator ne (ne_fns); !found && ne; ++ne)
if (0 && !ne.using_p ()
--- /dev/null
+// { dg-do compile { target c++20 } }
+
+// We wrongly considered D to be ne_comparable because we were looking for a
+// corresponding op!= for N::op== in ::, because ::op== happened to be the
+// first thing in the lookup set.
+
+template<bool, typename _Tp = void>
+struct enable_if;
+
+template<typename _Tp>
+struct enable_if<true, _Tp>
+{ typedef _Tp type; };
+
+template <class T, class U> struct A { };
+
+namespace N {
+ struct X { };
+ template <class T> auto operator== (const A<T,X>&, const A<T,X>&)
+ -> typename enable_if<sizeof(T() == T()), bool>::type;
+ template <class T> auto operator!= (const A<T,X>&, const A<T,X>&)
+ -> typename enable_if<sizeof(T() != T()), bool>::type;
+}
+
+template<typename T, typename U = T>
+concept ne_comparable
+= requires (const A<T,N::X>& t, const A<U,N::X>& u) {
+ t != u;
+};
+
+struct D { };
+int operator==(D, D);
+bool operator!=(D, D) = delete;
+static_assert( ! ne_comparable<D> );