[libcxx] fixes common_reference requirement for swappable_with

LWG3175 identifies that the `common_reference` requirement for
`swappable_with` is over-constraining and doesn't need to concern itself
with cv- or reference qualifiers.

Differential Revision: https://reviews.llvm.org/D99817
This commit is contained in:
Christopher Di Bella 2021-04-02 21:33:39 +00:00
parent a547b4e26b
commit cedd07df51
3 changed files with 44 additions and 5 deletions

View File

@ -194,7 +194,7 @@
"`3050 <https://wg21.link/LWG3050>`__","Conversion specification problem in ``chrono::duration``\ constructor","Prague","",""
"`3141 <https://wg21.link/LWG3141>`__","``CopyConstructible``\ doesn't preserve source values","Prague","",""
"`3150 <https://wg21.link/LWG3150>`__","``UniformRandomBitGenerator``\ should validate ``min``\ and ``max``\ ","Prague","",""
"`3175 <https://wg21.link/LWG3175>`__","The ``CommonReference``\ requirement of concept ``SwappableWith``\ is not satisfied in the example","Prague","",""
"`3175 <https://wg21.link/LWG3175>`__","The ``CommonReference``\ requirement of concept ``SwappableWith``\ is not satisfied in the example","Prague","|Complete|","13.0"
"`3194 <https://wg21.link/LWG3194>`__","``ConvertibleTo``\ prose does not match code","Prague","",""
"`3200 <https://wg21.link/LWG3200>`__","``midpoint``\ should not constrain ``T``\ is complete","Prague","|Nothing To Do|",""
"`3201 <https://wg21.link/LWG3201>`__","``lerp``\ should be marked as ``noexcept``\ ","Prague","|Complete|",""

1 Issue # Issue Name Meeting Status First released version
194 `3050 <https://wg21.link/LWG3050>`__ Conversion specification problem in ``chrono::duration``\ constructor Prague
195 `3141 <https://wg21.link/LWG3141>`__ ``CopyConstructible``\ doesn't preserve source values Prague
196 `3150 <https://wg21.link/LWG3150>`__ ``UniformRandomBitGenerator``\ should validate ``min``\ and ``max``\ Prague
197 `3175 <https://wg21.link/LWG3175>`__ The ``CommonReference``\ requirement of concept ``SwappableWith``\ is not satisfied in the example Prague |Complete| 13.0
198 `3194 <https://wg21.link/LWG3194>`__ ``ConvertibleTo``\ prose does not match code Prague
199 `3200 <https://wg21.link/LWG3200>`__ ``midpoint``\ should not constrain ``T``\ is complete Prague |Nothing To Do|
200 `3201 <https://wg21.link/LWG3201>`__ ``lerp``\ should be marked as ``noexcept``\ Prague |Complete|

View File

@ -326,7 +326,7 @@ concept swappable = requires(_Tp& __a, _Tp& __b) { ranges::swap(__a, __b); };
template<class _Tp, class _Up>
concept swappable_with =
common_reference_with<_Tp&, _Up&> &&
common_reference_with<_Tp, _Up> &&
requires(_Tp&& __t, _Up&& __u) {
ranges::swap(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Tp>(__t));
ranges::swap(_VSTD::forward<_Up>(__u), _VSTD::forward<_Up>(__u));

View File

@ -15,6 +15,7 @@
#include <concepts>
#include <array>
#include <cassert>
#include <deque>
#include <forward_list>
#include <list>
@ -555,7 +556,7 @@ struct swappable_with_rvalue_ref_to_volatile_s3 {
friend void swap(swappable_with_rvalue_ref_to_volatile_s3 volatile&&,
s3 volatile&&);
operator s3 volatile &() volatile;
operator s3 volatile &&() volatile;
};
static_assert(
std::swappable_with<swappable_with_rvalue_ref_to_volatile_s3 volatile&&,
@ -578,7 +579,7 @@ struct swappable_with_rvalue_ref_to_cv_s3 {
friend void swap(swappable_with_rvalue_ref_to_cv_s3 const volatile&&,
s3 const volatile&&);
operator s3 const volatile &() const volatile;
operator s3 const volatile &&() const volatile;
};
static_assert(
std::swappable_with<swappable_with_rvalue_ref_to_cv_s3 const volatile&&,
@ -644,4 +645,42 @@ static_assert(
static_assert(!check_swappable_with<HasANonMovable, HasANonMovable>());
} // namespace types_with_purpose
int main(int, char**) { return 0; }
namespace LWG3175 {
// Example taken directly from [concept.swappable]
template <class T, std::swappable_with<T> U>
constexpr void value_swap(T&& t, U&& u) {
std::ranges::swap(std::forward<T>(t), std::forward<U>(u));
}
template <std::swappable T>
constexpr void lv_swap(T& t1, T& t2) {
std::ranges::swap(t1, t2);
}
namespace N {
struct A {
int m;
};
struct Proxy {
A* a;
constexpr Proxy(A& a_) : a{&a_} {}
friend constexpr void swap(Proxy x, Proxy y) {
std::ranges::swap(*x.a, *y.a);
}
};
constexpr Proxy proxy(A& a) { return Proxy{a}; }
} // namespace N
[[nodiscard]] constexpr bool CheckRegression() {
int i = 1, j = 2;
lv_swap(i, j);
assert(i == 2 && j == 1);
N::A a1 = {5}, a2 = {-5};
value_swap(a1, proxy(a2));
assert(a1.m == -5 && a2.m == 5);
return true;
}
static_assert(CheckRegression());
} // namespace LWG3175