Skip to content

Use the correct namespace for looking up matching operator!= #68922

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 23, 2023

Conversation

usx95
Copy link
Contributor

@usx95 usx95 commented Oct 12, 2023

S.getScopeForContext determins the active scope associated with the given declContext.
This fails to find the matching operator!= if candidate operator== was found via ADL since that scope is not active.

Instead, just directly lookup using the namespace decl of operator==

Fixes #68901

@usx95 usx95 marked this pull request as ready for review October 12, 2023 19:43
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Oct 12, 2023
@llvmbot
Copy link
Member

llvmbot commented Oct 12, 2023

@llvm/pr-subscribers-clang

Author: Utkarsh Saxena (usx95)

Changes

S.getScopeForContext determins the active scope associated with the given declContext.
This fails to find the matching operator!= if candidate operator== was found via ADL since that scope is not active.

Instead, just directly lookup using the namespace decl of operator==

Fixes #68901


Full diff: https://github.com/llvm/llvm-project/pull/68922.diff

2 Files Affected:

  • (modified) clang/lib/Sema/SemaOverload.cpp (+1-6)
  • (modified) clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp (+24)
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index ce78994e6553814..e1e0b4a888e49fa 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -960,12 +960,7 @@ 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) {
+  for (NamedDecl *Op : EqFD->getEnclosingNamespaceContext()->lookup(NotEqOp)) {
     auto *FD = Op->getAsFunction();
     if(auto* UD = dyn_cast<UsingShadowDecl>(Op))
       FD = UD->getUnderlyingDecl()->getAsFunction();
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 5c6804eb7726b5f..7142ed22ddb22ca 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
@@ -324,6 +324,30 @@ bool x = X() == X(); // expected-warning {{ambiguous}}
 }
 } // namespace P2468R2
 
+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 ADL_GH68901
+
+
 #else // NO_ERRORS
 
 namespace problem_cases {

@zygoloid
Copy link
Collaborator

Does this work for function-scope operator declarations?

Copy link
Contributor

@cor3ntin cor3ntin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks reasonable, but i found a typo

@usx95
Copy link
Contributor Author

usx95 commented Oct 13, 2023

Does this work for function-scope operator declarations?

@zygoloid I am not sure I follow. Could you please give an example. If this is about member operator, the search scope is class scope of the first operand.

@usx95 usx95 requested a review from cor3ntin October 13, 2023 10:55
@zygoloid
Copy link
Collaborator

Does this work for function-scope operator declarations?

@zygoloid I am not sure I follow. Could you please give an example.

Sure:

struct X { operator int(); };

bool f(X x) {
  bool operator==(X, int);
  return x == x;
}


bool g(X x) {
  bool operator==(X, int);
  bool operator!=(X, int);
  return x == x;
}

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;
}

Based on the standard's rules, it looks like f and g should be invalid due to ambiguity, but h and i should be valid. (Which I think is a pretty surprising outcome, but that's what the rules say.)

If there's not already something like that in our test suite, it'd be good to add it.

@usx95
Copy link
Contributor Author

usx95 commented Oct 16, 2023

Thanks @zygoloid.
This case was failing with my change. Corrected and added tests.

@usx95 usx95 requested a review from zygoloid October 16, 2023 10:19
@usx95 usx95 closed this Oct 22, 2023
@usx95 usx95 force-pushed the equals-operator-68901 branch from 8804fe6 to 3d40411 Compare October 22, 2023 08:24
@usx95 usx95 reopened this Oct 22, 2023
@ilya-biryukov
Copy link
Contributor

Oh, one last thing! @usx95 maybe add a test for the visibility check?
Various tests with modules (search for files with the .cppm extension in the tests) should give a good starting point.

@usx95 usx95 merged commit 9330261 into llvm:main Oct 23, 2023
usx95 added a commit to usx95/llvm-project that referenced this pull request Nov 15, 2023
)

`S.getScopeForContext` determins the **active** scope associated with
the given `declContext`.
This fails to find the matching `operator!=` if candidate `operator==`
was found via ADL since that scope is not active.

Instead, just directly lookup using the namespace decl of `operator==`

Fixes llvm#68901

(cherry picked from commit 9330261)
tru pushed a commit that referenced this pull request Nov 20, 2023
`S.getScopeForContext` determins the **active** scope associated with
the given `declContext`.
This fails to find the matching `operator!=` if candidate `operator==`
was found via ADL since that scope is not active.

Instead, just directly lookup using the namespace decl of `operator==`

Fixes #68901

(cherry picked from commit 9330261)
AlexisPerry pushed a commit to AlexisPerry/kitsune-1 that referenced this pull request Jul 23, 2024
)

`S.getScopeForContext` determins the **active** scope associated with
the given `declContext`.
This fails to find the matching `operator!=` if candidate `operator==`
was found via ADL since that scope is not active.

Instead, just directly lookup using the namespace decl of `operator==`

Fixes llvm#68901

(cherry picked from commit 9330261)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

C++20 reversed operator== not properly suppressed by operator!= in namespace
5 participants