Skip to content

Correctly compute conversion seq for args to fn with reversed param order #68999

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 17, 2023

Conversation

usx95
Copy link
Contributor

@usx95 usx95 commented Oct 13, 2023

We associated conversion seq for args (when reversed) to the wrong index.
This lead to clang believing reversed operator== a worse overload candidate than the operator== without reversed args when both these candidate were ambiguous.

Fixes #53954

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Oct 13, 2023
@usx95 usx95 added the c++20 label Oct 13, 2023
@llvmbot
Copy link
Member

llvmbot commented Oct 13, 2023

@llvm/pr-subscribers-clang

Author: Utkarsh Saxena (usx95)

Changes

We associated conversion seq for args (when reversed) to the wrong index.
This lead to clang believing reversed operator== a worse overload candidate than the operator== without reversed args when both these candidate were ambiguous.

Fixes #53954


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

3 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+2)
  • (modified) clang/lib/Sema/SemaOverload.cpp (+2-2)
  • (modified) clang/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3-2a.cpp (+35)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 2d918967e7f0b02..07cedeabcdbd9b7 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -113,6 +113,8 @@ C++ Language Changes
 
 C++20 Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
+- Fix a bug in conversion sequence of arguments to a function with reversed parameter order.
+  Fixes `GH <https://github.com/llvm/llvm-project/issues/53954>`_.
 
 C++23 Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index ce78994e6553814..b00adb00eab01aa 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -7688,7 +7688,7 @@ bool Sema::CheckNonDependentConversions(
     QualType ParamType = ParamTypes[I + Offset];
     if (!ParamType->isDependentType()) {
       unsigned ConvIdx = PO == OverloadCandidateParamOrder::Reversed
-                             ? 0
+                             ? Args.size() - 1 - (ThisConversions + I)
                              : (ThisConversions + I);
       Conversions[ConvIdx]
         = TryCopyInitialization(*this, Args[I], ParamType,
@@ -10631,7 +10631,7 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
   // Find the best viable function.
   Best = end();
   for (auto *Cand : Candidates) {
-    Cand->Best = false;
+        Cand->Best = false;
     if (Cand->Viable) {
       if (Best == end() ||
           isBetterOverloadCandidate(S, *Cand, *Best, Loc, Kind))
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..8975706e721cff1 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,41 @@ bool x = X() == X(); // expected-warning {{ambiguous}}
 }
 } // namespace P2468R2
 
+namespace GH53954{
+namespace test1 {
+struct P {
+    template <class S>
+    friend bool operator==(const P &, const S &); // expected-note {{candidate}} \
+                                                  // expected-note {{reversed parameter order}}
+};
+struct A : public P {};
+struct B : public P {};
+bool check(A a, B b) { return a == b; } // expected-error {{ '==' is ambiguous}}
+}
+
+namespace test2 {
+struct P {
+    template <class S>
+    friend bool operator==(const S &, const P &); // expected-note {{candidate}} \
+                                                  // expected-note {{reversed parameter order}}
+};
+struct A : public P {};
+struct B : public P {};
+bool check(A a, B b) { return a == b; } // expected-error {{ '==' is ambiguous}}
+}
+
+namespace test3 {
+struct P {
+  template<class S>
+  bool operator==(const S &) const; // expected-note {{candidate}} \
+                                    // expected-note {{reversed parameter order}}
+};
+struct A : public P {};
+struct B : public P {};
+bool check(A a, B b) { return a == b; } // expected-error {{ '==' is ambiguous}}
+}
+}
+
 #else // NO_ERRORS
 
 namespace problem_cases {

@github-actions
Copy link

github-actions bot commented Oct 13, 2023

✅ With the latest revision this PR passed the C/C++ code formatter.

@usx95
Copy link
Contributor Author

usx95 commented Oct 17, 2023

Friendly ping.

Copy link
Collaborator

@zygoloid zygoloid left a comment

Choose a reason for hiding this comment

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

Thanks, looks good.

Our overall approach here seems error-prone, and I wonder if there's a better way to model the reversal of the conversion sequence. For example, perhaps we could change ConversionSequenceList into a class that tracks its OverloadCandidateParamOrder, and provides both accessors in candidate order (optionally the object parameter, then the remaining declared parameters in order) and in comparison order (potentially reversed). But let's land this as-is before thinking about that :)

@usx95
Copy link
Contributor Author

usx95 commented Oct 17, 2023

+1 I agree that this is confusing and error prone.

@usx95 usx95 merged commit e6d0b12 into llvm:main Oct 17, 2023
@usx95
Copy link
Contributor Author

usx95 commented Oct 18, 2023

This breaks new code (expected) but does not respect -Wno-ambiguous-reversed-operator. https://godbolt.org/z/oMsGeK1nc
@zygoloid IIUC this should be silenced by this warning but somehow does not. Will investigate further.
Reverting to put out large unsuppresable breakages

steelannelida pushed a commit that referenced this pull request Oct 18, 2023
@usx95
Copy link
Contributor Author

usx95 commented Oct 18, 2023

Ah. I see, this is because this is not a warning but hard errors in C++20.

@usx95
Copy link
Contributor Author

usx95 commented Oct 19, 2023

I think this is important that clang chooses not to error but only warn here as a clang extension (it already chooses to do so in cases when it the can match the function params(1 and 2)
Now that we correctly handle templated operator== in this PR, should we relax the error here as well to a warning ? WDYT @zygoloid ?

GCC does the same.

usx95 added a commit to usx95/llvm-project that referenced this pull request Oct 19, 2023
usx95 added a commit that referenced this pull request Oct 20, 2023
#68999 correctly computed
conversion sequence for reversed args to a template operators. This was
a breaking change as code, previously accepted in C++17, starts to break
in C++20.

Example:
```cpp
struct P {};
template<class S> bool operator==(const P&, const S &);

struct A : public P {};
struct B : public P {};
bool check(A a, B b) { return a == b; }  // This is now ambiguous in C++20.
```

In order to minimise widespread breakages, as a clang extension, we had
previously accepted such ambiguities with a warning
(`-Wambiguous-reversed-operator`) for non-template operators. Due to the
same reasons, we extend this relaxation for template operators.

Fixes #53954
usx95 added a commit that referenced this pull request Jan 12, 2024
…72213)

Re-applies #69595 with extra
[diff](79181ef)
### New changes

Further relax ambiguities with a warning for member operators of a
template class (primary templates of such ops do not match). Eg:
```cpp
template <class T>
struct S {
    template <typename OtherT>
    bool operator==(const OtherT &rhs); 
};
struct A : S<int> {};
struct B : S<bool> {};
bool x = A{} == B{}; // accepted with a warning.
```

This is important for making llvm build using previous clang versions in
C++20 mode (eg: this makes the commit
e558be5 keep working with a warning
instead of an error).

### Description from #69595

#68999 correctly computed
conversion sequence for reversed args to a template operator. This was a
breaking change as code, previously accepted in C++17, starts to break
in C++20.

Example:
```cpp
struct P {};
template<class S> bool operator==(const P&, const S &);

struct A : public P {};
struct B : public P {};
bool check(A a, B b) { return a == b; }  // This is now ambiguous in C++20.
```

In order to minimise widespread breakages, as a clang extension, we had
previously accepted such ambiguities with a warning
(`-Wambiguous-reversed-operator`) for non-template operators. Due to the
same reasons, we extend this relaxation for template operators.

Fixes #53954
justinfargnoli pushed a commit to justinfargnoli/llvm-project that referenced this pull request Jan 28, 2024
…lvm#72213)

Re-applies llvm#69595 with extra
[diff](llvm@79181ef)
### New changes

Further relax ambiguities with a warning for member operators of a
template class (primary templates of such ops do not match). Eg:
```cpp
template <class T>
struct S {
    template <typename OtherT>
    bool operator==(const OtherT &rhs); 
};
struct A : S<int> {};
struct B : S<bool> {};
bool x = A{} == B{}; // accepted with a warning.
```

This is important for making llvm build using previous clang versions in
C++20 mode (eg: this makes the commit
e558be5 keep working with a warning
instead of an error).

### Description from llvm#69595

llvm#68999 correctly computed
conversion sequence for reversed args to a template operator. This was a
breaking change as code, previously accepted in C++17, starts to break
in C++20.

Example:
```cpp
struct P {};
template<class S> bool operator==(const P&, const S &);

struct A : public P {};
struct B : public P {};
bool check(A a, B b) { return a == b; }  // This is now ambiguous in C++20.
```

In order to minimise widespread breakages, as a clang extension, we had
previously accepted such ambiguities with a warning
(`-Wambiguous-reversed-operator`) for non-template operators. Due to the
same reasons, we extend this relaxation for template operators.

Fixes llvm#53954
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++20 clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

C++20 operator== ambiguous with derived-to-base conversion
3 participants