diff --git a/libcxx/docs/Cxx2aStatusIssuesStatus.csv b/libcxx/docs/Cxx2aStatusIssuesStatus.csv --- a/libcxx/docs/Cxx2aStatusIssuesStatus.csv +++ b/libcxx/docs/Cxx2aStatusIssuesStatus.csv @@ -194,7 +194,7 @@ "`3050 `__","Conversion specification problem in ``chrono::duration``\ constructor","Prague","","" "`3141 `__","``CopyConstructible``\ doesn't preserve source values","Prague","","" "`3150 `__","``UniformRandomBitGenerator``\ should validate ``min``\ and ``max``\ ","Prague","","" -"`3175 `__","The ``CommonReference``\ requirement of concept ``SwappableWith``\ is not satisfied in the example","Prague","","" +"`3175 `__","The ``CommonReference``\ requirement of concept ``SwappableWith``\ is not satisfied in the example","Prague","|Complete|","13.0" "`3194 `__","``ConvertibleTo``\ prose does not match code","Prague","","" "`3200 `__","``midpoint``\ should not constrain ``T``\ is complete","Prague","|Nothing To Do|","" "`3201 `__","``lerp``\ should be marked as ``noexcept``\ ","Prague","|Complete|","" diff --git a/libcxx/include/concepts b/libcxx/include/concepts --- a/libcxx/include/concepts +++ b/libcxx/include/concepts @@ -326,7 +326,7 @@ template 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)); diff --git a/libcxx/test/std/concepts/concepts.lang/concept.swappable/swappable_with.compile.pass.cpp b/libcxx/test/std/concepts/concepts.lang/concept.swappable/swappable_with.compile.pass.cpp --- a/libcxx/test/std/concepts/concepts.lang/concept.swappable/swappable_with.compile.pass.cpp +++ b/libcxx/test/std/concepts/concepts.lang/concept.swappable/swappable_with.compile.pass.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -644,4 +645,43 @@ static_assert(!check_swappable_with()); } // namespace types_with_purpose +namespace LWG3175 { +// Example taken directly from [concept.swappable] +template U> +constexpr void value_swap(T&& t, U&& u) { + std::ranges::swap(std::forward(t), std::forward(u)); +} + +template +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)); + return a1.m == -5 && a2.m == 5; +} + +static_assert(CheckRegression()); +} // namespace LWG3175 + int main(int, char**) { return 0; }