fix errors on passing input iterator to `std::views::take`
authorHui Xie <hui.xie1990@gmail.com>
Fri, 2 Sep 2022 18:24:22 +0000 (19:24 +0100)
committerHui Xie <hui.xie1990@gmail.com>
Sun, 25 Sep 2022 14:41:13 +0000 (15:41 +0100)
In the implementation of `std::views::take`, it uses `subrange<Iter>` as part of the return type. But in case of input iterator, `subrange<Iter>` can be ill-formed

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

libcxx/include/__ranges/take_view.h
libcxx/test/std/ranges/range.adaptors/range.take/adaptor.pass.cpp

index 4bc7bf5..3fb9499 100644 (file)
@@ -226,6 +226,7 @@ struct __passthrough_type<basic_string_view<_CharT, _Traits>> {
 };
 
 template <class _Iter, class _Sent, subrange_kind _Kind>
+  requires requires{typename subrange<_Iter>;}
 struct __passthrough_type<subrange<_Iter, _Sent, _Kind>> {
   using type = subrange<_Iter>;
 };
index 40b6a3d..9f4a563 100644 (file)
@@ -194,6 +194,19 @@ constexpr bool test() {
     [[maybe_unused]] auto partial = std::views::take(X{});
   }
 
+  // Test when `subrange<Iter>` is not well formed
+  {
+    int input[] = {1, 2, 3};
+    using Iter  = cpp20_input_iterator<int*>;
+    using Sent  = sentinel_wrapper<Iter>;
+    std::ranges::subrange r{Iter{input}, Sent{Iter{input + 3}}};
+    auto tv = std::views::take(std::move(r), 1);
+    auto it                  = tv.begin();
+    assert(*it == 1);
+    ++it;
+    assert(it == tv.end());
+  }
+
   return true;
 }