-
Notifications
You must be signed in to change notification settings - Fork 14.3k
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
Conversation
@llvm/pr-subscribers-clang Author: Utkarsh Saxena (usx95) ChangesWe associated conversion seq for args (when reversed) to the wrong index. Fixes #53954 Full diff: https://github.com/llvm/llvm-project/pull/68999.diff 3 Files Affected:
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 {
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
Friendly ping. |
There was a problem hiding this 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 :)
+1 I agree that this is confusing and error prone. |
This breaks new code (expected) but does not respect |
… param order (#68999)" This reverts commit e6d0b12. See PR for reason #68999 (comment)
Ah. I see, this is because this is not a warning but hard errors in C++20. |
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) |
…d param order (llvm#68999)" This reverts commit a3a0f59.
#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
…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
…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
We associated conversion seq for args (when reversed) to the wrong index.
This lead to clang believing reversed
operator==
a worse overload candidate than theoperator==
without reversed args when both these candidate were ambiguous.Fixes #53954