[libcxx-commits] [libcxx] [libc++][ranges] Implement LWG 3599 (PR #221573)

via libcxx-commits libcxx-commits at lists.llvm.org
Sun Sep 6 07:17:21 PDT 2026


https://github.com/jiang1997 created https://github.com/llvm/llvm-project/pull/221573

Implement [LWG 3599](https://wg21.link/LWG3599) by requiring `forward_range<const Pattern>` for the `const` overloads of `lazy_split_view::begin` and `end`.

This adds tests for disabled `begin()` and fallback `end()` on non-const-forward patterns, as well as a regression test for `view_interface::front()`.

Closes #189808

>From 8d6a1adbf894a5b03cfaf580440e384b223373b8 Mon Sep 17 00:00:00 2001
From: jiang1997 <jieke at live.cn>
Date: Sun, 6 Sep 2026 20:43:47 +0800
Subject: [PATCH] [libc++][ranges] Implement LWG 3599

---
 libcxx/docs/Status/Cxx26Issues.csv             |  2 +-
 libcxx/include/__ranges/lazy_split_view.h      |  5 +++--
 .../range.lazy.split/begin.pass.cpp            | 18 ++++++++----------
 .../range.lazy.split/end.pass.cpp              | 13 +++++++++++++
 .../range.lazy.split/view_interface.pass.cpp   |  5 +++++
 5 files changed, 30 insertions(+), 13 deletions(-)

diff --git a/libcxx/docs/Status/Cxx26Issues.csv b/libcxx/docs/Status/Cxx26Issues.csv
index cf30ba8a45ca5..e46a043477527 100644
--- a/libcxx/docs/Status/Cxx26Issues.csv
+++ b/libcxx/docs/Status/Cxx26Issues.csv
@@ -263,7 +263,7 @@
 "`LWG2414 <https://wg21.link/LWG2414>`__","Member function reentrancy should be implementation-defined","2026-03 (Croydon)","","","`#189805 <https://github.com/llvm/llvm-project/issues/189805>`__",""
 "`LWG2746 <https://wg21.link/LWG2746>`__","Inconsistency between requirements for ``emplace`` between ``optional`` and ``variant``","2026-03 (Croydon)","","","`#189806 <https://github.com/llvm/llvm-project/issues/189806>`__",""
 "`LWG3504 <https://wg21.link/LWG3504>`__","``condition_variable::wait_for`` is overspecified","2026-03 (Croydon)","","","`#189807 <https://github.com/llvm/llvm-project/issues/189807>`__",""
-"`LWG3599 <https://wg21.link/LWG3599>`__","The ``const`` overload of ``lazy_split_view::begin`` should be constrained by ``const Pattern``","2026-03 (Croydon)","","","`#189808 <https://github.com/llvm/llvm-project/issues/189808>`__",""
+"`LWG3599 <https://wg21.link/LWG3599>`__","The ``const`` overload of ``lazy_split_view::begin`` should be constrained by ``const Pattern``","2026-03 (Croydon)","|Complete|","24","`#189808 <https://github.com/llvm/llvm-project/issues/189808>`__",""
 "`LWG3662 <https://wg21.link/LWG3662>`__","``basic_string::append/assign(NTBS, pos, n)`` suboptimal","2026-03 (Croydon)","|Complete|","23","`#189809 <https://github.com/llvm/llvm-project/issues/189809>`__",""
 "`LWG3777 <https://wg21.link/LWG3777>`__","Common ``cartesian_product_view`` produces an invalid range if the first range is input and one of the ranges is empty","2026-03 (Croydon)","","","`#189810 <https://github.com/llvm/llvm-project/issues/189810>`__",""
 "`LWG3797 <https://wg21.link/LWG3797>`__","``elements_view`` insufficiently constrained","2026-03 (Croydon)","","","`#189811 <https://github.com/llvm/llvm-project/issues/189811>`__",""
diff --git a/libcxx/include/__ranges/lazy_split_view.h b/libcxx/include/__ranges/lazy_split_view.h
index 9c44d26faf1e7..de7105944aa59 100644
--- a/libcxx/include/__ranges/lazy_split_view.h
+++ b/libcxx/include/__ranges/lazy_split_view.h
@@ -112,7 +112,7 @@ class lazy_split_view : public view_interface<lazy_split_view<_View, _Pattern>>
   }
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
-    requires forward_range<_View> && forward_range<const _View>
+    requires forward_range<_View> && forward_range<const _View> && forward_range<const _Pattern>
   {
     return __outer_iterator<true>{*this, ranges::begin(__base_)};
   }
@@ -124,7 +124,8 @@ class lazy_split_view : public view_interface<lazy_split_view<_View, _Pattern>>
   }
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() const {
-    if constexpr (forward_range<_View> && forward_range<const _View> && common_range<const _View>) {
+    if constexpr (forward_range<_View> && forward_range<const _View> && common_range<const _View> &&
+                  forward_range<const _Pattern>) {
       return __outer_iterator<true>{*this, ranges::end(__base_)};
     } else {
       return default_sentinel;
diff --git a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/begin.pass.cpp
index 113272703d59f..5d166697a7124 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/begin.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/begin.pass.cpp
@@ -9,7 +9,8 @@
 // UNSUPPORTED: c++03, c++11, c++14, c++17
 
 // constexpr auto begin();
-// constexpr auto begin() const requires forward_range<View> && forward_range<const View>;
+// constexpr auto begin() const
+//   requires forward_range<View> && forward_range<const View> && forward_range<const Pattern>;
 
 #include <ranges>
 
@@ -26,7 +27,8 @@ concept ConstBeginDisabled = !requires (const View v) {
 
 constexpr bool test() {
   // non-const: forward_range<View> && simple-view<View> -> outer-iterator<Const = true>
-  // const: forward_range<View> && forward_range<const View> -> outer-iterator<Const = true>
+  // const: forward_range<View> && forward_range<const View> && forward_range<const Pattern>
+  //     -> outer-iterator<Const = true>
   {
     using V = ForwardView;
     using P = V;
@@ -52,7 +54,8 @@ constexpr bool test() {
   }
 
   // non-const: forward_range<View> && !simple-view<View> -> outer-iterator<Const = false>
-  // const: forward_range<View> && forward_range<const View> -> outer-iterator<Const = true>
+  // const: forward_range<View> && forward_range<const View> && forward_range<const Pattern>
+  //     -> outer-iterator<Const = true>
   {
     using V = ForwardDiffView;
     using P = V;
@@ -96,7 +99,7 @@ constexpr bool test() {
   }
 
   // non-const: forward_range<View> && simple-view<View> && !simple-view<Pattern> -> outer-iterator<Const = false>
-  // const: forward_range<View> && forward_range<const View> -> outer-iterator<Const = true>
+  // const: forward_range<View> && forward_range<const View> && !forward_range<const Pattern> -> disabled
   {
     using V = ForwardView;
     using P = ForwardOnlyIfNonConstView;
@@ -113,12 +116,7 @@ constexpr bool test() {
       static_assert(std::is_same_v<decltype(*(*it).begin()), const char&>);
     }
 
-    {
-      const std::ranges::lazy_split_view<V, P> cv;
-      auto it = cv.begin();
-      static_assert(std::is_same_v<decltype(it)::iterator_concept, std::forward_iterator_tag>);
-      static_assert(std::is_same_v<decltype(*(*it).begin()), const char&>);
-    }
+    static_assert(ConstBeginDisabled<std::ranges::lazy_split_view<V, P>>);
   }
 
   // non-const: !forward_range<View> && tiny-range<Pattern> -> outer-iterator<Const = false>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/end.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/end.pass.cpp
index 3e3facc1cbe3d..5ce2bce9f00f2 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/end.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/end.pass.cpp
@@ -156,6 +156,19 @@ constexpr bool test() {
     }
   }
 
+  // const: !forward_range<const P> -> default_sentinel
+  {
+    using V = ForwardView;
+    using P = ForwardOnlyIfNonConstView;
+
+    static_assert(std::ranges::forward_range<const V>);
+    static_assert(std::ranges::common_range<const V>);
+    static_assert(!std::ranges::forward_range<const P>);
+
+    const std::ranges::lazy_split_view<V, P> cv;
+    static_assert(std::same_as<decltype(cv.end()), std::default_sentinel_t>);
+  }
+
   return true;
 }
 
diff --git a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/view_interface.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/view_interface.pass.cpp
index 8d5982d59759d..4d6c21c062233 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/view_interface.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/view_interface.pass.cpp
@@ -60,6 +60,11 @@ constexpr bool test() {
     SplitViewForward v("abc", "");
     assert(*(v.front()).begin() == 'a');
   }
+  {
+    auto pattern = std::views::iota(0) | std::views::take(1) | std::views::reverse;
+    auto v       = std::views::single(42) | std::views::lazy_split(pattern);
+    assert(*v.front().begin() == 42);
+  }
 
   return true;
 }



More information about the libcxx-commits mailing list