[libcxx-commits] [libcxx] 6a56d5c - [libc++] Fix LWG3589 "The const lvalue reference overload of get for subrange..."

Arthur O'Dwyer via libcxx-commits libcxx-commits at lists.llvm.org
Tue Feb 1 12:14:53 PST 2022


Author: Arthur O'Dwyer
Date: 2022-02-01T15:14:44-05:00
New Revision: 6a56d5cc25cd4a5e401649e76a4c5fae2493f670

URL: https://github.com/llvm/llvm-project/commit/6a56d5cc25cd4a5e401649e76a4c5fae2493f670
DIFF: https://github.com/llvm/llvm-project/commit/6a56d5cc25cd4a5e401649e76a4c5fae2493f670.diff

LOG: [libc++] Fix LWG3589 "The const lvalue reference overload of get for subrange..."

https://cplusplus.github.io/LWG/issue3589

Differential Revision: https://reviews.llvm.org/D117961

Added: 
    

Modified: 
    libcxx/docs/Status/Cxx2bIssues.csv
    libcxx/include/__ranges/subrange.h
    libcxx/test/std/ranges/range.utility/range.subrange/get.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Status/Cxx2bIssues.csv b/libcxx/docs/Status/Cxx2bIssues.csv
index 1ca6844491627..bcbfe44022879 100644
--- a/libcxx/docs/Status/Cxx2bIssues.csv
+++ b/libcxx/docs/Status/Cxx2bIssues.csv
@@ -130,7 +130,7 @@
 `3580 <https://wg21.link/LWG3580>`__,"``iota_view``'s ``iterator``'s binary ``operator+`` should be improved","October 2021","|Complete|","14.0","|ranges|"
 `3581 <https://wg21.link/LWG3581>`__,"The range constructor makes ``basic_string_view`` not trivially move constructible","October 2021","|Complete|","14.0","|ranges|"
 `3585 <https://wg21.link/LWG3585>`__,"``variant`` converting assignment with immovable alternative","October 2021","",""
-`3589 <https://wg21.link/LWG3589>`__,"The ``const`` lvalue reference overload of ``get`` for ``subrange`` does not constrain ``I`` to be ``copyable`` when ``N == 0``","October 2021","","","|ranges|"
+`3589 <https://wg21.link/LWG3589>`__,"The ``const`` lvalue reference overload of ``get`` for ``subrange`` does not constrain ``I`` to be ``copyable`` when ``N == 0``","October 2021","|Complete|","14.0","|ranges|"
 `3590 <https://wg21.link/LWG3590>`__,"``split_view::base() const &`` is overconstrained","October 2021","","","|ranges|"
 `3591 <https://wg21.link/LWG3591>`__,"``lazy_split_view<input_view>::inner-iterator::base() &&`` invalidates outer iterators","October 2021","","","|ranges|"
 `3592 <https://wg21.link/LWG3592>`__,"``lazy_split_view`` needs to check the simpleness of Pattern","October 2021","","","|ranges|"

diff  --git a/libcxx/include/__ranges/subrange.h b/libcxx/include/__ranges/subrange.h
index 707ba2dd889f4..c6977cec36721 100644
--- a/libcxx/include/__ranges/subrange.h
+++ b/libcxx/include/__ranges/subrange.h
@@ -227,7 +227,7 @@ namespace ranges {
     -> subrange<iterator_t<_Range>, sentinel_t<_Range>, subrange_kind::sized>;
 
   template<size_t _Index, class _Iter, class _Sent, subrange_kind _Kind>
-    requires (_Index < 2)
+    requires ((_Index == 0 && copyable<_Iter>) || _Index == 1)
   _LIBCPP_HIDE_FROM_ABI
   constexpr auto get(const subrange<_Iter, _Sent, _Kind>& __subrange) {
     if constexpr (_Index == 0)

diff  --git a/libcxx/test/std/ranges/range.utility/range.subrange/get.pass.cpp b/libcxx/test/std/ranges/range.utility/range.subrange/get.pass.cpp
index c546d884b020d..f06c73357cf70 100644
--- a/libcxx/test/std/ranges/range.utility/range.subrange/get.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/range.subrange/get.pass.cpp
@@ -17,26 +17,75 @@
 #include <cassert>
 #include "test_macros.h"
 #include "test_iterators.h"
-#include "types.h"
 
 template<size_t I, class S>
-concept GetInvocable = requires {
+concept HasGet = requires {
   std::get<I>(std::declval<S>());
 };
 
-static_assert( GetInvocable<0, std::ranges::subrange<int*>>);
-static_assert( GetInvocable<1, std::ranges::subrange<int*>>);
-static_assert(!GetInvocable<2, std::ranges::subrange<int*>>);
-static_assert(!GetInvocable<3, std::ranges::subrange<int*>>);
+static_assert( HasGet<0, std::ranges::subrange<int*>>);
+static_assert( HasGet<1, std::ranges::subrange<int*>>);
+static_assert(!HasGet<2, std::ranges::subrange<int*>>);
+static_assert(!HasGet<3, std::ranges::subrange<int*>>);
 
 constexpr bool test() {
-  std::ranges::subrange<int*> a(globalBuff, globalBuff + 8, 8);
-  assert(std::get<0>(a) == a.begin());
-  assert(std::get<1>(a) == a.end());
-
-  assert(a.begin() == std::get<0>(std::move(a)));
-  std::ranges::subrange<int*> b(globalBuff, globalBuff + 8, 8);
-  assert(b.end() == std::get<1>(std::move(b)));
+  {
+    using It = int*;
+    using Sent = sentinel_wrapper<int*>;
+    int a[] = {1, 2, 3};
+    using R = std::ranges::subrange<It, Sent, std::ranges::subrange_kind::unsized>;
+    R r = R(It(a), Sent(It(a + 3)));
+    ASSERT_SAME_TYPE(decltype(std::get<0>(r)), It);
+    ASSERT_SAME_TYPE(decltype(std::get<1>(r)), Sent);
+    ASSERT_SAME_TYPE(decltype(std::get<0>(static_cast<R&&>(r))), It);
+    ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast<R&&>(r))), Sent);
+    ASSERT_SAME_TYPE(decltype(std::get<0>(static_cast<const R&>(r))), It);
+    ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast<const R&>(r))), Sent);
+    ASSERT_SAME_TYPE(decltype(std::get<0>(static_cast<const R&&>(r))), It);
+    ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast<const R&&>(r))), Sent);
+    assert(base(std::get<0>(r)) == a);                      // copy from It
+    assert(base(base(std::get<1>(r))) == a + 3);            // copy from Sent
+    assert(base(std::get<0>(std::move(r))) == a);           // copy from It
+    assert(base(base(std::get<1>(std::move(r)))) == a + 3); // copy from Sent
+  }
+  {
+    using It = int*;
+    using Sent = sentinel_wrapper<int*>;
+    int a[] = {1, 2, 3};
+    using R = std::ranges::subrange<It, Sent, std::ranges::subrange_kind::sized>;
+    R r = R(It(a), Sent(It(a + 3)), 3);
+    ASSERT_SAME_TYPE(decltype(std::get<0>(r)), It);
+    ASSERT_SAME_TYPE(decltype(std::get<1>(r)), Sent);
+    ASSERT_SAME_TYPE(decltype(std::get<0>(static_cast<R&&>(r))), It);
+    ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast<R&&>(r))), Sent);
+    ASSERT_SAME_TYPE(decltype(std::get<0>(static_cast<const R&>(r))), It);
+    ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast<const R&>(r))), Sent);
+    ASSERT_SAME_TYPE(decltype(std::get<0>(static_cast<const R&&>(r))), It);
+    ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast<const R&&>(r))), Sent);
+    assert(base(std::get<0>(r)) == a);                      // copy from It
+    assert(base(base(std::get<1>(r))) == a + 3);            // copy from Sent
+    assert(base(std::get<0>(std::move(r))) == a);           // copy from It
+    assert(base(base(std::get<1>(std::move(r)))) == a + 3); // copy from Sent
+  }
+  {
+    // Test the fix for LWG 3589.
+    using It = cpp20_input_iterator<int*>;
+    using Sent = sentinel_wrapper<It>;
+    int a[] = {1, 2, 3};
+    using R = std::ranges::subrange<It, Sent>;
+    R r = R(It(a), Sent(It(a + 3)));
+    static_assert(!HasGet<0, R&>);
+    ASSERT_SAME_TYPE(decltype(std::get<1>(r)), Sent);
+    ASSERT_SAME_TYPE(decltype(std::get<0>(static_cast<R&&>(r))), It);
+    ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast<R&&>(r))), Sent);
+    static_assert(!HasGet<0, const R&>);
+    ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast<const R&>(r))), Sent);
+    static_assert(!HasGet<0, const R&&>);
+    ASSERT_SAME_TYPE(decltype(std::get<1>(static_cast<const R&&>(r))), Sent);
+    assert(base(base(std::get<1>(r))) == a + 3);            // copy from Sent
+    assert(base(std::get<0>(std::move(r))) == a);           // move from It
+    assert(base(base(std::get<1>(std::move(r)))) == a + 3); // copy from Sent
+  }
 
   return true;
 }


        


More information about the libcxx-commits mailing list