[clang] Use the correct namespace for looking up matching operator!= (PR #68922)
Utkarsh Saxena via cfe-commits
cfe-commits at lists.llvm.org
Sun Oct 22 02:12:21 PDT 2023
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/68922
>From 8aa439a97a56ef80bfc9ccc90a9f093680e455f5 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Sun, 22 Oct 2023 11:11:53 +0200
Subject: [PATCH] rebase...
---
clang/docs/ReleaseNotes.rst | 4 +
clang/lib/Sema/SemaOverload.cpp | 19 ++---
.../over.match.oper/p3-2a.cpp | 78 +++++++++++++++++++
3 files changed, 89 insertions(+), 12 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 3a9a67f7451c092..cef857244387e8b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -85,6 +85,10 @@ C/C++ Language Potentially Breaking Changes
``__has_c_attribute(warn_unused_result)``, 202003, 0
``__has_c_attribute(gnu::warn_unused_result)``, 202003, 1
+- Fixed a bug in finding matching `operator!=` while adding reversed `operator==` as
+ outlined in "The Equality Operator You Are Looking For" (`P2468 <http://wg21.link/p2468r2>`_).
+ Fixes (`#68901: <https://github.com/llvm/llvm-project/issues/68901>`_).
+
C++ Specific Potentially Breaking Changes
-----------------------------------------
- The name mangling rules for function templates has been changed to take into
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index d57a7ad8f46859a..75e4184c8aa6cb8 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -960,18 +960,13 @@ static bool shouldAddReversedEqEq(Sema &S, SourceLocation OpLoc,
return true;
}
// Otherwise the search scope is the namespace scope of which F is a member.
- LookupResult NonMembers(S, NotEqOp, OpLoc,
- Sema::LookupNameKind::LookupOperatorName);
- S.LookupName(NonMembers,
- S.getScopeForContext(EqFD->getEnclosingNamespaceContext()));
- NonMembers.suppressAccessDiagnostics();
- for (NamedDecl *Op : NonMembers) {
- auto *FD = Op->getAsFunction();
- if(auto* UD = dyn_cast<UsingShadowDecl>(Op))
- FD = UD->getUnderlyingDecl()->getAsFunction();
- if (FunctionsCorrespond(S.Context, EqFD, FD) &&
- declaresSameEntity(cast<Decl>(EqFD->getDeclContext()),
- cast<Decl>(Op->getDeclContext())))
+ for (NamedDecl *Op : EqFD->getEnclosingNamespaceContext()->lookup(NotEqOp)) {
+ auto *NotEqFD = Op->getAsFunction();
+ if (auto *UD = dyn_cast<UsingShadowDecl>(Op))
+ NotEqFD = UD->getUnderlyingDecl()->getAsFunction();
+ if (FunctionsCorrespond(S.Context, EqFD, NotEqFD) &&
+ declaresSameEntity(cast<Decl>(EqFD->getEnclosingNamespaceContext()),
+ cast<Decl>(Op->getLexicalDeclContext())))
return false;
}
return true;
diff --git a/clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp b/clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp
index 5727d506fe5e61d..9dc5ee8db565341 100644
--- a/clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp
+++ b/clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp
@@ -374,6 +374,84 @@ bool fine(A a, B b) { return a == b; } // Ok. Found a matching operator!=.
}
}
+
+namespace ADL_GH68901{
+namespace A {
+struct S {};
+bool operator==(S, int); // expected-note {{no known conversion from 'int' to 'S' for 1st argument}}
+bool operator!=(S, int);
+} // namespace A
+bool a = 0 == A::S(); // expected-error {{invalid operands to binary expression ('int' and 'A::S')}}
+
+namespace B {
+struct Derived {};
+struct Base : Derived {};
+
+bool operator==(Derived& a, Base& b);
+bool operator!=(Derived& a, Base& b);
+} // namespace B
+
+void foo() {
+ // B::Base{} == B::Base{};
+ B::Base a,b;
+ bool v = a == b;
+}
+
+namespace ns {
+template <class T>
+struct A {
+};
+
+template <class T>
+struct B : A<T> {
+};
+
+template <class T> bool operator == (B<T>, A<T>); // expected-note {{candidate template ignored: could not match 'B' against 'A'}}
+template <class T> bool operator != (B<T>, A<T>);
+}
+
+void test() {
+ ns::A<int> a;
+ ns::B<int> b;
+ a == b; // expected-error {{invalid operands to binary expression}}
+}
+
+
+} //namespace ADL_GH68901
+
+namespace function_scope_operator_eqeq {
+// For non-members, we always lookup for matching operator!= in the namespace scope of
+// operator== (and not in the scope of operator==).
+struct X { operator int(); };
+namespace test1{
+bool h(X x) {
+ bool operator==(X, int); // expected-note {{reversed}}
+ return x == x; // expected-warning {{ambiguous}}
+}
+
+bool g(X x) {
+ bool operator==(X, int); // expected-note {{reversed}}
+ bool operator!=(X, int);
+ return x == x; // expected-warning {{ambiguous}}
+}
+} // namespace test1
+
+namespace test2 {
+bool operator!=(X, int);
+
+bool h(X x) {
+ bool operator==(X, int);
+ return x == x;
+}
+
+bool i(X x) {
+ bool operator==(X, int);
+ bool operator!=(X, int);
+ return x == x;
+}
+} // namespace test2
+} // namespace function_scope_operator_eqeq
+
namespace non_member_template_2 {
struct P {};
template<class S>
More information about the cfe-commits
mailing list