[libcxx-commits] [libcxx] [libc++] Implement P2442R1 `std::views::chunk` (PR #171234)

via libcxx-commits libcxx-commits at lists.llvm.org
Sat Jul 25 22:42:09 PDT 2026


https://github.com/shyeyian updated https://github.com/llvm/llvm-project/pull/171234

>From f6554ea2a0e1d9571cf82fc7b2f3d1115c466474 Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at petalmail.com>
Date: Wed, 24 Dec 2025 22:05:29 +0800
Subject: [PATCH 01/43] Implement `views::chunk`.

This commit squashes previous commits.
---
 libcxx/docs/FeatureTestMacroTable.rst         |   2 +-
 libcxx/docs/ReleaseNotes/22.rst               |   1 +
 libcxx/docs/Status/Cxx23Papers.csv            |   2 +-
 libcxx/include/CMakeLists.txt                 |   1 +
 libcxx/include/__ranges/chunk_view.h          | 562 ++++++++++++++++++
 libcxx/include/module.modulemap.in            |   4 +
 libcxx/include/ranges                         |  12 +
 libcxx/include/version                        |   2 +-
 libcxx/modules/std/ranges.inc                 |  11 +-
 .../no_unique_address.compile.pass.cpp        |  53 ++
 .../range.chunk/nodiscard.verify.cpp          |  86 +++
 .../ranges.version.compile.pass.cpp           |  32 +-
 .../version.version.compile.pass.cpp          |  32 +-
 .../range.chunk/adaptor.pass.cpp              |  75 +++
 .../range.adaptors/range.chunk/base.pass.cpp  |  46 ++
 .../range.adaptors/range.chunk/begin.pass.cpp |  67 +++
 .../range.chunk/ctad.compile.pass.cpp         |  55 ++
 .../range.adaptors/range.chunk/end.pass.cpp   |  65 ++
 .../range.chunk/general.pass.cpp              |  48 ++
 .../range.chunk.iter/compare.pass.cpp         | 109 ++++
 .../range.chunk.iter/decrement.pass.cpp       |  60 ++
 .../range.chunk.iter/deref.pass.cpp           |  77 +++
 .../range.chunk.iter/increment.pass.cpp       |  95 +++
 .../ranges/range.adaptors/range.chunk/types.h |  50 ++
 .../generate_feature_test_macro_components.py |   1 -
 25 files changed, 1494 insertions(+), 54 deletions(-)
 create mode 100644 libcxx/include/__ranges/chunk_view.h
 create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.chunk/no_unique_address.compile.pass.cpp
 create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.chunk/nodiscard.verify.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/adaptor.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/base.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/begin.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/ctad.compile.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/end.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/general.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/compare.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/decrement.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/deref.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/increment.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/types.h

diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 32911d0f64449..8e57305f32ad1 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -370,7 +370,7 @@ Status
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_ranges_as_rvalue``                             ``202207L``
     ---------------------------------------------------------- -----------------
-    ``__cpp_lib_ranges_chunk``                                 *unimplemented*
+    ``__cpp_lib_ranges_chunk``                                 ``202202L``
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_ranges_chunk_by``                              ``202202L``
     ---------------------------------------------------------- -----------------
diff --git a/libcxx/docs/ReleaseNotes/22.rst b/libcxx/docs/ReleaseNotes/22.rst
index 0d1a1fbc00f2c..d2a2d1b712689 100644
--- a/libcxx/docs/ReleaseNotes/22.rst
+++ b/libcxx/docs/ReleaseNotes/22.rst
@@ -54,6 +54,7 @@ Implemented Papers
 - P3567R2: ``flat_meow`` Fixes (`Github <https://llvm.org/PR162022>`__)
 - P3836R2: Make ``optional<T&>`` trivially copyable (`Github <https://llvm.org/PR171275>`__)
 - P1789R3: Library Support for Expansion Statements (`Github <https://llvm.org/PR167184>`__)
+- P2442R1: P2442R1: Windowing range adaptors: ``views::chunk`` and ``views::slide`` (`Github <https://llvm.org/PR171234>`__) (Implemented ``views::slide`` only)
 
 Improvements and New Features
 -----------------------------
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index e4c6cb0f51065..8c8ab211e5bf4 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -48,7 +48,7 @@
 "`P2387R3 <https://wg21.link/P2387R3>`__","Pipe support for user-defined range adaptors","2022-02 (Virtual)","|Complete|","19","`#105183 <https://github.com/llvm/llvm-project/issues/105183>`__",""
 "`P2440R1 <https://wg21.link/P2440R1>`__","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","2022-02 (Virtual)","|Partial|","","`#105184 <https://github.com/llvm/llvm-project/issues/105184>`__","Only ``ranges::iota`` is implemented."
 "`P2441R2 <https://wg21.link/P2441R2>`__","``views::join_with``","2022-02 (Virtual)","|Complete|","21","`#105185 <https://github.com/llvm/llvm-project/issues/105185>`__",""
-"`P2442R1 <https://wg21.link/P2442R1>`__","Windowing range adaptors: ``views::chunk`` and ``views::slide``","2022-02 (Virtual)","","","`#105187 <https://github.com/llvm/llvm-project/issues/105187>`__",""
+"`P2442R1 <https://wg21.link/P2442R1>`__","Windowing range adaptors: ``views::chunk`` and ``views::slide``","2022-02 (Virtual)","|Partial|","22","`#105187 <https://github.com/llvm/llvm-project/issues/105187>`__","Only ``views::chunk`` is implemented."
 "`P2443R1 <https://wg21.link/P2443R1>`__","``views::chunk_by``","2022-02 (Virtual)","|Complete|","18","`#105188 <https://github.com/llvm/llvm-project/issues/105188>`__",""
 "","","","","","",""
 "`P0009R18 <https://wg21.link/P0009R18>`__","mdspan: A Non-Owning Multidimensional Array Reference","2022-07 (Virtual)","|Complete|","18","`#105189 <https://github.com/llvm/llvm-project/issues/105189>`__",""
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index eb423ae923b4f..2426da6848b51 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -707,6 +707,7 @@ set(files
   __ranges/all.h
   __ranges/as_rvalue_view.h
   __ranges/chunk_by_view.h
+  __ranges/chunk_view.h
   __ranges/common_view.h
   __ranges/concepts.h
   __ranges/container_compatible_range.h
diff --git a/libcxx/include/__ranges/chunk_view.h b/libcxx/include/__ranges/chunk_view.h
new file mode 100644
index 0000000000000..f19d2c9ede8a7
--- /dev/null
+++ b/libcxx/include/__ranges/chunk_view.h
@@ -0,0 +1,562 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___RANGES_CHUNK_VIEW_H
+#define _LIBCPP___RANGES_CHUNK_VIEW_H
+
+#include <__algorithm/ranges_min.h>
+#include <__assert>
+#include <__concepts/constructible.h>
+#include <__concepts/convertible_to.h>
+#include <__config>
+#include <__functional/bind_back.h>
+#include <__iterator/advance.h>
+#include <__iterator/concepts.h>
+#include <__iterator/default_sentinel.h>
+#include <__iterator/distance.h>
+#include <__iterator/iter_move.h>
+#include <__iterator/iter_swap.h>
+#include <__iterator/iterator_traits.h>
+#include <__memory/addressof.h>
+#include <__ranges/access.h>
+#include <__ranges/all.h>
+#include <__ranges/concepts.h>
+#include <__ranges/enable_borrowed_range.h>
+#include <__ranges/non_propagating_cache.h>
+#include <__ranges/range_adaptor.h>
+#include <__ranges/take_view.h>
+#include <__ranges/view_interface.h>
+#include <__type_traits/conditional.h>
+#include <__type_traits/decay.h>
+#include <__type_traits/is_nothrow_constructible.h>
+#include <__type_traits/make_unsigned.h>
+#include <__utility/forward.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 23
+
+namespace ranges {
+
+template <class _Integral>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto __div_ceil(_Integral __num, _Integral __denom) {
+  _Integral __r = __num / __denom;
+  if (__num % __denom)
+    ++__r;
+  return __r;
+}
+
+template <view _View>
+  requires input_range<_View>
+class chunk_view : public view_interface<chunk_view<_View>> {
+  _LIBCPP_NO_UNIQUE_ADDRESS _View __base_;
+  _LIBCPP_NO_UNIQUE_ADDRESS range_difference_t<_View> __n_;
+  _LIBCPP_NO_UNIQUE_ADDRESS range_difference_t<_View> __remainder_;
+  _LIBCPP_NO_UNIQUE_ADDRESS __non_propagating_cache<iterator_t<_View>> __current_;
+
+  class __outer_iterator;
+  class __inner_iterator;
+
+public:
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit chunk_view(_View __base, range_difference_t<_View> __n)
+      : __base_(std::move(__base)), __n_(__n), __remainder_(0) {
+    _LIBCPP_ASSERT_PEDANTIC(__n > 0, "Trying to construct a chunk_view with chunk size <= 0");
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() const&
+    requires std::copy_constructible<_View>
+  {
+    return __base_;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __outer_iterator begin() {
+    __current_.__emplace(ranges::begin(__base_));
+    __remainder_ = __n_;
+    return __outer_iterator(*this);
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr default_sentinel_t end() const noexcept {
+    return std::default_sentinel;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size()
+    requires sized_range<_View>
+  {
+    return std::__to_unsigned_like(ranges::__div_ceil(ranges::distance(__base_), __n_));
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
+    requires sized_range<const _View>
+  {
+    return std::__to_unsigned_like(ranges::__div_ceil(ranges::distance(__base_), __n_));
+  }
+};
+
+template <view _View>
+  requires input_range<_View>
+class chunk_view<_View>::__outer_iterator {
+  friend chunk_view;
+
+  chunk_view* __parent_;
+
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit __outer_iterator(chunk_view& __parent)
+      : __parent_(std::addressof(__parent)) {}
+
+public:
+  class value_type;
+  using iterator_concept = input_iterator_tag;
+  using difference_type  = range_difference_t<_View>;
+
+  _LIBCPP_HIDE_FROM_ABI __outer_iterator(__outer_iterator&&) = default;
+
+  _LIBCPP_HIDE_FROM_ABI __outer_iterator& operator=(__outer_iterator&&) = default;
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr value_type operator*() const {
+    _LIBCPP_ASSERT_PEDANTIC(*this != default_sentinel, "Trying to dereference past-the-end chunk_view iterator.");
+    return value_type(*__parent_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __outer_iterator& operator++() {
+    ranges::advance(*__parent_->__current_, __parent_->__remainder_, ranges::end(__parent_->__base_));
+    __parent_->__remainder_ = __parent_->__n_;
+    return *this;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) { ++*this; }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr bool
+  operator==(const __outer_iterator& __i, default_sentinel_t) {
+    return *__i.__parent_->__current_ == ranges::end(__i.__parent_->__base_) && __i.__parent_->__remainder_ != 0;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
+  operator-(default_sentinel_t, const __outer_iterator& __i)
+    requires sized_sentinel_for<sentinel_t<_View>, iterator_t<_View>>
+  {
+    const auto __dist = ranges::end(__i.__parent_->__base_) - *__i.__parent_->__current_;
+    if (__dist < __i.__parent_->__remainder_)
+      return __dist == 0 ? 0 : 1;
+    return ranges::__div_ceil(__dist - __i.__parent_->__remainder_, __i.__parent_->__n_) + 1;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
+  operator-(const __outer_iterator& __i, default_sentinel_t __s)
+    requires sized_sentinel_for<sentinel_t<_View>, iterator_t<_View>>
+  {
+    return -(__s - __i);
+  }
+};
+
+template <view _View>
+  requires input_range<_View>
+class chunk_view<_View>::__outer_iterator::value_type : public view_interface<value_type> {
+  friend __outer_iterator;
+
+  chunk_view* __parent_;
+
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit value_type(chunk_view& __parent) : __parent_(std::addressof(__parent)) {}
+
+public:
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __inner_iterator begin() const noexcept {
+    return __inner_iterator(*__parent_);
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr default_sentinel_t end() const noexcept { return default_sentinel; }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
+    requires sized_sentinel_for<sentinel_t<_View>, iterator_t<_View>>
+  {
+    return std::__to_unsigned_like(
+        ranges::min(__parent_->__remainder_, ranges::end(__parent_->__base_) - *__parent_->__current_));
+  }
+};
+
+template <view _View>
+  requires input_range<_View>
+class chunk_view<_View>::__inner_iterator {
+  friend chunk_view;
+
+  chunk_view* __parent_;
+
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit __inner_iterator(chunk_view& __parent) noexcept
+      : __parent_(std::addressof(__parent)) {}
+
+public:
+  using iterator_concept = input_iterator_tag;
+  using difference_type  = range_difference_t<_View>;
+  using value_type       = range_value_t<_View>;
+
+  _LIBCPP_HIDE_FROM_ABI __inner_iterator(__inner_iterator&&) = default;
+
+  _LIBCPP_HIDE_FROM_ABI __inner_iterator& operator=(__inner_iterator&&) = default;
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const iterator_t<_View> base() const& { return *__parent_->__current_; }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr range_reference_t<_View> operator*() const {
+    _LIBCPP_ASSERT_PEDANTIC(*this != default_sentinel, "Trying to dereference past-the-end chunk_view iterator");
+    return **__parent_->__current_;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __inner_iterator& operator++() {
+    ++*__parent_->__current_;
+    if (*__parent_->__current_ == ranges::end(__parent_->__base_))
+      __parent_->__remainder_ = 0;
+    else
+      --__parent_->__remainder_;
+    return *this;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) { ++*this; }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr bool
+  operator==(const __inner_iterator& __i, default_sentinel_t) {
+    return __i.__parent_->__remainder_ == 0;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
+  operator-(default_sentinel_t, const __inner_iterator& __i)
+    requires sized_sentinel_for<sentinel_t<_View>, iterator_t<_View>>
+  {
+    return ranges::min(__i.__parent_->__remainder_, ranges::end(__i.__parent_->__base_) - *__i.__parent_->__current_);
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
+  operator-(const __inner_iterator& __i, default_sentinel_t __s)
+    requires sized_sentinel_for<sentinel_t<_View>, iterator_t<_View>>
+  {
+    return -(__s - __i);
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto
+  iter_move(const __inner_iterator& __i) noexcept(noexcept(ranges::iter_move(*__i.__parent_->__current_))) {
+    return ranges::iter_move(*__i.__parent_->__current_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr void
+  iter_swap(const __inner_iterator& __x, const __inner_iterator& __y) noexcept(
+      noexcept((ranges::iter_swap(*__x.__parent_->__current_, *__y.__parent_->__current_))))
+    requires indirectly_swappable<iterator_t<_View>>
+  {
+    return ranges::iter_swap(*__x.__parent_->__current_, *__y.__parent_->__current_);
+  }
+};
+
+template <view _View>
+  requires forward_range<_View>
+class chunk_view<_View> : public view_interface<chunk_view<_View>> {
+  _LIBCPP_NO_UNIQUE_ADDRESS _View __base_;
+  _LIBCPP_NO_UNIQUE_ADDRESS range_difference_t<_View> __n_;
+
+  template <bool _Const>
+  class __iterator;
+
+public:
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit chunk_view(_View __base, range_difference_t<_View> __n)
+      : __base_(std::move(__base)), __n_(__n) {
+    _LIBCPP_ASSERT_PEDANTIC(__n > 0, "Trying to construct a chunk_view with chunk size <= 0");
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() const&
+    requires copy_constructible<_View>
+  {
+    return __base_;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin()
+    requires(!__simple_view<_View>)
+  {
+    return __iterator<false>(this, ranges::begin(__base_));
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
+    requires forward_range<const _View>
+  {
+    return __iterator<true>(this, ranges::begin(__base_));
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end()
+    requires(!__simple_view<_View>)
+  {
+    if constexpr (common_range<_View> && sized_range<_View>) {
+      auto __missing = (__n_ - ranges::distance(__base_) % __n_) % __n_;
+      return __iterator<false>(this, ranges::end(__base_), __missing);
+    } else if constexpr (common_range<_View> && !bidirectional_range<_View>)
+      return __iterator<false>(this, ranges::end(__base_));
+    else
+      return default_sentinel;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
+    requires forward_range<const _View>
+  {
+    if constexpr (common_range<const _View> && sized_range<const _View>) {
+      auto __missing = (__n_ - ranges::distance(__base_) % __n_) % __n_;
+      return __iterator<true>(this, ranges::end(__base_), __missing);
+    } else if constexpr (common_range<const _View> && !bidirectional_range<const _View>)
+      return __iterator<true>(this, ranges::end(__base_));
+    else
+      return default_sentinel;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size()
+    requires sized_range<_View>
+  {
+    return std::__to_unsigned_like(ranges::__div_ceil(ranges::distance(__base_), __n_));
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
+    requires sized_range<const _View>
+  {
+    return std::__to_unsigned_like(ranges::__div_ceil(ranges::distance(__base_), __n_));
+  }
+};
+
+template <view _View>
+  requires forward_range<_View>
+template <bool _Const>
+class chunk_view<_View>::__iterator {
+  friend chunk_view;
+
+  using _Parent _LIBCPP_NODEBUG = __maybe_const<_Const, chunk_view>;
+  using _Base _LIBCPP_NODEBUG   = __maybe_const<_Const, _View>;
+
+  iterator_t<_Base> __current_         = iterator_t<_Base>();
+  sentinel_t<_Base> __end_             = sentinel_t<_Base>();
+  range_difference_t<_Base> __n_       = 0;
+  range_difference_t<_Base> __missing_ = 0;
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator(
+      _Parent* __parent, iterator_t<_Base> __current, range_difference_t<_Base> __missing = 0)
+      : __current_(__current), __end_(ranges::end(__parent->__base_)), __n_(__parent->__n_), __missing_(__missing) {}
+
+  [[nodiscard]] static consteval auto __get_iterator_concept() {
+    if constexpr (random_access_range<_Base>)
+      return random_access_iterator_tag{};
+    else if constexpr (bidirectional_range<_Base>)
+      return bidirectional_iterator_tag{};
+    else
+      return forward_iterator_tag{};
+  }
+
+public:
+  using iterator_category = input_iterator_tag;
+  using iterator_concept  = decltype(__iterator::__get_iterator_concept());
+  using value_type        = decltype(views::take(subrange(__current_, __end_), __n_));
+  using difference_type   = range_difference_t<_Base>;
+
+  _LIBCPP_HIDE_FROM_ABI __iterator() = default;
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator(__iterator<!_Const> __i)
+    requires _Const && convertible_to<iterator_t<_View>, iterator_t<_Base>> &&
+                 convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
+      : __current_(std::move(__i.__current_)),
+        __end_(std::move(__i.__end_)),
+        __n_(__i.__n_),
+        __missing_(__i.__missing_) {}
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_Base> base() const { return __current_; }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr value_type operator*() const {
+    _LIBCPP_ASSERT_PEDANTIC(__current_ != __end_, "Trying to dereference past-the-end chunk_view iterator");
+    return views::take(subrange(__current_, __end_), __n_);
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr value_type operator[](difference_type __pos) const
+    requires random_access_range<_Base>
+  {
+    return *(*this + __pos);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() {
+    _LIBCPP_ASSERT_PEDANTIC(__current_ != __end_, "Trying to advance past-the-end chunk_view iterator");
+    __missing_ = ranges::advance(__current_, __n_, __end_);
+    return *this;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) {
+    auto __tmp = *this;
+    ++*this;
+    return __tmp;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator--()
+    requires bidirectional_range<_Base>
+  {
+    ranges::advance(__current_, __missing_ - __n_);
+    __missing_ = 0;
+    return *this;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator--(int) {
+    auto __tmp = *this;
+    --*this;
+    return __tmp;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator+=(difference_type __x)
+    requires random_access_range<_Base>
+  {
+    if (__x > 0) {
+      _LIBCPP_ASSERT_PEDANTIC(ranges::distance(__current_, __end_) > __n_ * (__x - 1),
+                              "Trying to advance chunk_view iterator out of range");
+      ranges::advance(__current_, __n_ * (__x - 1));
+      __missing_ = ranges::advance(__current_, __n_, __end_);
+    } else if (__x < 0) {
+      ranges::advance(__current_, __n_ * __x + __missing_);
+      __missing_ = 0;
+    }
+    return *this;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(difference_type __x)
+    requires random_access_range<_Base>
+  {
+    return *this += -__x;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __iterator& __y) {
+    return __x.__current_ == __y.__current_;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, default_sentinel_t) {
+    return __x.__current_ == __x.__end_;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<(const __iterator& __x, const __iterator& __y)
+    requires random_access_range<_Base>
+  {
+    return __x.__current_ < __y.__current_;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>(const __iterator& __x, const __iterator& __y)
+    requires random_access_range<_Base>
+  {
+    return __y < __x;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<=(const __iterator& __x, const __iterator& __y)
+    requires random_access_range<_Base>
+  {
+    return !(__y < __x);
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>=(const __iterator& __x, const __iterator& __y)
+    requires random_access_range<_Base>
+  {
+    return !(__x < __y);
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(const __iterator& __x, const __iterator& __y)
+    requires random_access_range<_Base> && three_way_comparable<iterator_t<_Base>>
+  {
+    return __x.__current_ <=> __y.__current_;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator
+  operator+(const __iterator& __i, difference_type __pos)
+    requires random_access_range<_Base>
+  {
+    auto __r = __i;
+    __r += __pos;
+    return __r;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator
+  operator+(difference_type __pos, const __iterator& __i)
+    requires random_access_range<_Base>
+  {
+    auto __r = __i;
+    __r += __pos;
+    return __r;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator
+  operator-(const __iterator& __i, difference_type __pos)
+    requires random_access_range<_Base>
+  {
+    auto __r = __i;
+    __r -= __pos;
+    return __r;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
+  operator-(const __iterator& __i, const __iterator& __j)
+    requires sized_sentinel_for<iterator_t<_Base>, iterator_t<_Base>>
+  {
+    return (__i.__current_ - __j.__current_ + __i.__missing_ - __j.__missing_) / __i.__n_;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
+  operator-(default_sentinel_t, const __iterator& __i)
+    requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>>
+  {
+    return ranges::__div_ceil(__i.__end_ - __i.__current_, __i.__n_);
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
+  operator-(const __iterator& __i, default_sentinel_t __s)
+    requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>>
+  {
+    return -(__s - __i);
+  }
+};
+
+template <class _Range>
+chunk_view(_Range&&, range_difference_t<_Range>) -> chunk_view<views::all_t<_Range>>;
+
+template <class _View>
+inline constexpr bool enable_borrowed_range<chunk_view<_View>> = forward_range<_View> && enable_borrowed_range<_View>;
+
+namespace views {
+namespace __chunk {
+struct __fn {
+  template <viewable_range _Range>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto
+  operator()(_Range&& __range, range_difference_t<_Range> __n) noexcept(
+      noexcept(/*-----*/ chunk_view(std::forward<_Range>(__range), std::forward<range_difference_t<_Range>>(__n))))
+      -> decltype(/*--*/ chunk_view(std::forward<_Range>(__range), std::forward<range_difference_t<_Range>>(__n))) {
+    return /*---------*/ chunk_view(std::forward<_Range>(__range), std::forward<range_difference_t<_Range>>(__n));
+  }
+
+  template <class _DifferenceType>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto
+  operator()(_DifferenceType __n) noexcept(is_nothrow_constructible_v<decay_t<_DifferenceType>, _DifferenceType>) {
+    return __pipeable(std::__bind_back(__fn{}, std::forward<_DifferenceType>(__n)));
+  }
+};
+
+} // namespace __chunk
+
+inline namespace __cpo {
+inline constexpr auto chunk = __chunk::__fn{};
+
+} // namespace __cpo
+} // namespace views
+
+} // namespace ranges
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___RANGES_CHUNK_VIEW_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 4434a5446e35b..cb03eb8d14067 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1863,6 +1863,10 @@ module std [system] {
       header "__ranges/chunk_by_view.h"
       export std.functional.bind_back
     }
+    module chunk_view {
+      header "__ranges/chunk_view.h"
+      export std.functional.bind_back
+    }
     module common_view                    { header "__ranges/common_view.h" }
     module concepts                       { header "__ranges/concepts.h" }
     module container_compatible_range     { header "__ranges/container_compatible_range.h" }
diff --git a/libcxx/include/ranges b/libcxx/include/ranges
index 9f725b12ac6c2..9ec6a4a819919 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -396,6 +396,17 @@ namespace std::ranges {
   class chunk_by_view;                                                      // C++23
 
   namespace views { inline constexpr unspecified chunk_by = unspecified; }  // C++23
+
+  // [range.chunk]
+  template <view V>
+    requires input_range<V>
+  class chunk_view;                                                     // C++23
+
+  template <view V>
+    requires forward_range<V>
+  class chunk_view<V>;                                                  // C++23
+
+  namespace views { inline constexpr unspecified chunk = unspecified; } // C++23
 }
 
 namespace std {
@@ -482,6 +493,7 @@ namespace std {
 #    include <__ranges/adjacent_view.h>
 #    include <__ranges/as_rvalue_view.h>
 #    include <__ranges/chunk_by_view.h>
+#    include <__ranges/chunk_view.h>
 #    include <__ranges/from_range.h>
 #    include <__ranges/join_with_view.h>
 #    include <__ranges/repeat_view.h>
diff --git a/libcxx/include/version b/libcxx/include/version
index ab781466f5ed5..f5fc33674f521 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -523,7 +523,7 @@ __cpp_lib_void_t                                        201411L <type_traits>
 # define __cpp_lib_ranges                               202406L
 // # define __cpp_lib_ranges_as_const                      202207L
 # define __cpp_lib_ranges_as_rvalue                     202207L
-// # define __cpp_lib_ranges_chunk                         202202L
+# define __cpp_lib_ranges_chunk                         202202L
 # define __cpp_lib_ranges_chunk_by                      202202L
 # define __cpp_lib_ranges_contains                      202207L
 # define __cpp_lib_ranges_find_last                     202207L
diff --git a/libcxx/modules/std/ranges.inc b/libcxx/modules/std/ranges.inc
index 5caa2c052c00f..631ae10c922ae 100644
--- a/libcxx/modules/std/ranges.inc
+++ b/libcxx/modules/std/ranges.inc
@@ -314,18 +314,17 @@ export namespace std {
       using std::ranges::views::adjacent_transform;
       using std::ranges::views::pairwise_transform;
     } // namespace views
+#endif
 
-#endif // _LIBCPP_STD_VER >= 23
-
-#if 0
+#if _LIBCPP_STD_VER >= 23
     using std::ranges::chunk_view;
 
-    using std::ranges::chunk_view<V>;
-
     namespace views {
       using std::ranges::views::chunk;
-    }
+    } // namespace views
+#endif
 
+#if 0
     using std::ranges::slide_view;
 
     namespace views {
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/no_unique_address.compile.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/no_unique_address.compile.pass.cpp
new file mode 100644
index 0000000000000..14c618c505e70
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/no_unique_address.compile.pass.cpp
@@ -0,0 +1,53 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+// This test ensures that we use `[[no_unique_address]]` in `chunk_view`.
+
+#include <cstddef>
+#include <ranges>
+#include <string>
+#include <type_traits>
+
+#include "test_iterators.h"
+#include "test_range.h"
+
+struct input_view {
+  cpp20_input_iterator<int*> begin() const;
+  sentinel_wrapper<cpp20_input_iterator<int*>> end() const;
+};
+template <>
+inline constexpr bool std::ranges::enable_view<input_view> = true;
+static_assert(std::ranges::input_range<input_view> && !std::ranges::forward_range<input_view>);
+
+struct forward_view {
+  int* begin() const;
+  int* end() const;
+};
+template <>
+inline constexpr bool std::ranges::enable_view<forward_view> = true;
+static_assert(std::ranges::forward_range<forward_view>);
+
+using CV1 = std::ranges::chunk_view<input_view>;
+// Expected CV1 (with View == input) layout:
+// [[no_unique_address]] _View __base_                                         // size: 0
+// [[no_unique_address]] range_difference_t<_View> __n_                        // size: sizeof(ptrdiff_t)
+// [[no_unique_address]] range_difference_t<_View> __remainder_                // size: sizeof(ptrdiff_t)
+// [[no_unique_address]] __non_propagating_cache<iterator_t<_View>> __current_ // size: sizeof(__non_propagating_cache<cpp20_input_iterator<int*>>), align: std::ptrdiff_t
+static_assert(alignof(std::ranges::__non_propagating_cache<cpp20_input_iterator<int*>>) == alignof(std::ptrdiff_t));
+static_assert(sizeof(CV1) == /*sizeof(__base_) == 0 + */ sizeof(std::ptrdiff_t) * 2 +
+                                 sizeof(std::ranges::__non_propagating_cache<cpp20_input_iterator<int*>>));
+
+using CV2 = std::ranges::chunk_view<forward_view>;
+// Expected CV2 (with View >= forward) layout:
+// [[no_unique_address]] _View __base_             // size: 0
+// [[no_unique_address]] range_difference_t<_View> // size: sizeof(ptrdiff_t)
+static_assert(sizeof(CV2) == /*sizeof(__base_) == 0 + */ sizeof(std::ptrdiff_t));
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/nodiscard.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/nodiscard.verify.cpp
new file mode 100644
index 0000000000000..5e557715f4b03
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/nodiscard.verify.cpp
@@ -0,0 +1,86 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+// Test the libc++ extension that std::ranges::chunk_view::iterator<Const>::operator* is marked as [[nodiscard]].
+
+#include <ranges>
+#include <utility>
+
+void test() {
+  char range[6] = {'x', 'x', 'y', 'y', 'z', 'z'};
+  auto view     = range | std::views::chunk(2);
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::views::chunk(3);
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::views::chunk(range, 3);
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  range | std::views::chunk(3);
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::views::reverse | std::views::chunk(3);
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  view.base();
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::as_const(view).base();
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(std::as_const(view)).base();
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(view).base();
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  view.begin();
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::as_const(view).begin();
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  view.end();
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::as_const(view).end();
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::views::chunk(3);
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::views::chunk(range, 3);
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  range | std::views::chunk(3);
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::views::reverse | std::views::chunk(3);
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  *view.begin();
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  *std::as_const(view).begin();
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  (view.begin() == view.end());
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  (std::as_const(view).begin() == view.end());
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  (view.begin() == std::as_const(view).end());
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  (std::as_const(view).begin() == std::as_const(view).end());
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  (view.begin() == view.end());
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  (std::as_const(view).begin() == view.end());
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  (view.begin() == std::as_const(view).end());
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  (std::as_const(view).begin() == std::as_const(view).end());
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::ranges::iter_move(view.begin());
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::ranges::iter_move(std::as_const(view).begin());
+}
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp
index 5116864879485..41e1603f62350 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp
@@ -270,17 +270,11 @@
 #    error "__cpp_lib_ranges_as_rvalue should have the value 202207L in c++23"
 #  endif
 
-#  if !defined(_LIBCPP_VERSION)
-#    ifndef __cpp_lib_ranges_chunk
-#      error "__cpp_lib_ranges_chunk should be defined in c++23"
-#    endif
-#    if __cpp_lib_ranges_chunk != 202202L
-#      error "__cpp_lib_ranges_chunk should have the value 202202L in c++23"
-#    endif
-#  else
-#    ifdef __cpp_lib_ranges_chunk
-#      error "__cpp_lib_ranges_chunk should not be defined because it is unimplemented in libc++!"
-#    endif
+#  ifndef __cpp_lib_ranges_chunk
+#    error "__cpp_lib_ranges_chunk should be defined in c++23"
+#  endif
+#  if __cpp_lib_ranges_chunk != 202202L
+#    error "__cpp_lib_ranges_chunk should have the value 202202L in c++23"
 #  endif
 
 #  ifndef __cpp_lib_ranges_chunk_by
@@ -387,17 +381,11 @@
 #    error "__cpp_lib_ranges_as_rvalue should have the value 202207L in c++26"
 #  endif
 
-#  if !defined(_LIBCPP_VERSION)
-#    ifndef __cpp_lib_ranges_chunk
-#      error "__cpp_lib_ranges_chunk should be defined in c++26"
-#    endif
-#    if __cpp_lib_ranges_chunk != 202202L
-#      error "__cpp_lib_ranges_chunk should have the value 202202L in c++26"
-#    endif
-#  else
-#    ifdef __cpp_lib_ranges_chunk
-#      error "__cpp_lib_ranges_chunk should not be defined because it is unimplemented in libc++!"
-#    endif
+#  ifndef __cpp_lib_ranges_chunk
+#    error "__cpp_lib_ranges_chunk should be defined in c++26"
+#  endif
+#  if __cpp_lib_ranges_chunk != 202202L
+#    error "__cpp_lib_ranges_chunk should have the value 202202L in c++26"
 #  endif
 
 #  ifndef __cpp_lib_ranges_chunk_by
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index b3b424a1d77ce..bd1b55ccc8dfa 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -5700,17 +5700,11 @@
 #    error "__cpp_lib_ranges_as_rvalue should have the value 202207L in c++23"
 #  endif
 
-#  if !defined(_LIBCPP_VERSION)
-#    ifndef __cpp_lib_ranges_chunk
-#      error "__cpp_lib_ranges_chunk should be defined in c++23"
-#    endif
-#    if __cpp_lib_ranges_chunk != 202202L
-#      error "__cpp_lib_ranges_chunk should have the value 202202L in c++23"
-#    endif
-#  else
-#    ifdef __cpp_lib_ranges_chunk
-#      error "__cpp_lib_ranges_chunk should not be defined because it is unimplemented in libc++!"
-#    endif
+#  ifndef __cpp_lib_ranges_chunk
+#    error "__cpp_lib_ranges_chunk should be defined in c++23"
+#  endif
+#  if __cpp_lib_ranges_chunk != 202202L
+#    error "__cpp_lib_ranges_chunk should have the value 202202L in c++23"
 #  endif
 
 #  ifndef __cpp_lib_ranges_chunk_by
@@ -7619,17 +7613,11 @@
 #    error "__cpp_lib_ranges_as_rvalue should have the value 202207L in c++26"
 #  endif
 
-#  if !defined(_LIBCPP_VERSION)
-#    ifndef __cpp_lib_ranges_chunk
-#      error "__cpp_lib_ranges_chunk should be defined in c++26"
-#    endif
-#    if __cpp_lib_ranges_chunk != 202202L
-#      error "__cpp_lib_ranges_chunk should have the value 202202L in c++26"
-#    endif
-#  else
-#    ifdef __cpp_lib_ranges_chunk
-#      error "__cpp_lib_ranges_chunk should not be defined because it is unimplemented in libc++!"
-#    endif
+#  ifndef __cpp_lib_ranges_chunk
+#    error "__cpp_lib_ranges_chunk should be defined in c++26"
+#  endif
+#  if __cpp_lib_ranges_chunk != 202202L
+#    error "__cpp_lib_ranges_chunk should have the value 202202L in c++26"
 #  endif
 
 #  ifndef __cpp_lib_ranges_chunk_by
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/adaptor.pass.cpp
new file mode 100644
index 0000000000000..657e16383256b
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/adaptor.pass.cpp
@@ -0,0 +1,75 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+//   std::views::chunk
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <concepts>
+#include <ranges>
+#include <utility>
+
+constexpr bool test() {
+  std::array<int, 8> array                       = {1, 2, 3, 4, 5, 6, 7, 8};
+  std::ranges::ref_view<std::array<int, 8>> view = array | std::views::all;
+
+  // Test `views::chunk(view, n)`
+  {
+    std::same_as<std::ranges::chunk_view<std::ranges::ref_view<std::array<int, 8>>>> decltype(auto) chunked =
+        std::views::chunk(view, 2);
+    assert(std::ranges::equal(*chunked.begin(), std::array{1, 2}));
+    std::same_as<std::ranges::chunk_view<std::ranges::ref_view<std::array<int, 8>>>> decltype(auto) const_chunked =
+        std::views::chunk(std::as_const(view), 2);
+    assert(std::ranges::equal(*const_chunked.begin(), std::array{1, 2}));
+  }
+
+  // Test `views::chunk(n)(range)`
+  {
+    static_assert(noexcept(std::views::chunk(2)));
+    /*__pipable*/ auto adaptor = std::views::chunk(3);
+    std::same_as<std::ranges::chunk_view<std::ranges::ref_view<std::array<int, 8>>>> decltype(auto) chunked =
+        adaptor(view);
+    assert(std::ranges::equal(*chunked.begin(), std::array{1, 2, 3}));
+    std::same_as<std::ranges::chunk_view<std::ranges::ref_view<std::array<int, 8>>>> decltype(auto) const_chunked =
+        adaptor(std::as_const(view));
+    assert(std::ranges::equal(*const_chunked.begin(), std::array{1, 2, 3}));
+  }
+
+  // Test `view | views::chunk`
+  {
+    std::same_as<std::ranges::chunk_view<std::ranges::ref_view<std::array<int, 8>>>> decltype(auto) chunked =
+        view | std::views::chunk(4);
+    assert(std::ranges::equal(*chunked.begin(), std::array{1, 2, 3, 4}));
+    std::same_as<std::ranges::chunk_view<std::ranges::ref_view<std::array<int, 8>>>> decltype(auto) const_chunked =
+        std::as_const(view) | std::views::chunk(4);
+    assert(std::ranges::equal(*const_chunked.begin(), std::array{1, 2, 3, 4}));
+  }
+
+  // Test `views::chunk | adaptor`
+  {
+    /*__pipable*/ auto adaptors            = std::views::chunk(5) | std::views::join;
+    std::ranges::input_range auto rejoined = view | adaptors;
+    assert(std::ranges::equal(rejoined, view));
+    std::ranges::input_range auto const_rejoined = std::as_const(view) | adaptors;
+    assert(std::ranges::equal(const_rejoined, view));
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/base.pass.cpp
new file mode 100644
index 0000000000000..ac17f97a0a292
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/base.pass.cpp
@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+//   constexpr V base() const& requires copyy_constructible<V>;
+//   constexpr V base() &&;
+
+#include <array>
+#include <cassert>
+#include <concepts>
+#include <memory>
+#include <ranges>
+#include <utility>
+
+constexpr bool test() {
+  std::array<int, 8> array                                                   = {1, 2, 3, 4, 5, 6, 7, 8};
+  std::ranges::chunk_view<std::ranges::ref_view<std::array<int, 8>>> chunked = array | std::views::chunk(3);
+  std::ranges::chunk_view<std::ranges::ref_view<const std::array<int, 8>>> const_chunked =
+      std::as_const(array) | std::views::chunk(4);
+
+  // Test `chunk_view.base()`
+  {
+    std::same_as<std::array<int, 8>&> decltype(auto) base = chunked.base().base();
+    assert(std::addressof(base) == std::addressof(array));
+
+    std::same_as<const std::array<int, 8>&> decltype(auto) const_base = const_chunked.base().base();
+    assert(std::addressof(const_base) == std::addressof(array));
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/begin.pass.cpp
new file mode 100644
index 0000000000000..3cccd7d1bebc6
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/begin.pass.cpp
@@ -0,0 +1,67 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+//   V models only input_range:
+//     constexpr __outer_iterator begin();
+
+//   V models forward_range:
+//     constexpr auto begin() requires (!__simple_view<V>);
+//     constexpr auto begin() const requires forward_range<const V>;
+
+#include <algorithm>
+#include <cassert>
+#include <iterator>
+#include <ranges>
+#include <vector>
+
+#include "test_range.h"
+#include "types.h"
+
+constexpr bool test() {
+  std::vector<int> vector                                                  = {1, 2, 3, 4, 5, 6, 7, 8};
+  std::ranges::chunk_view<std::ranges::ref_view<std::vector<int>>> chunked = vector | std::views::chunk(3);
+  std::ranges::chunk_view<std::ranges::ref_view<const std::vector<int>>> const_chunked =
+      std::as_const(vector) | std::views::chunk(3);
+  std::ranges::chunk_view<input_span<int>> input_chunked = input_span<int>(vector.data(), 8) | std::views::chunk(3);
+
+  // Test `chunk_view.begin()` when V models only input_range
+  {
+    /*chunk_view::__outer_iterator*/ std::input_iterator auto it = input_chunked.begin();
+    assert(std::ranges::equal(*it, std::vector{1, 2, 3}));
+    assert(std::ranges::equal(*++it, std::vector{4, 5, 6}));
+    assert(std::ranges::equal(*++it, std::vector{7, 8}));
+    assert(++it == input_chunked.end());
+  }
+
+  // Test `chunk_view.begin()` when V models forward_range
+  {
+    /*chunk_view::__iterator<false>*/ std::forward_iterator auto it = chunked.begin();
+    assert(std::ranges::equal(*it, std::vector{1, 2, 3}));
+    assert(std::ranges::equal(*++it, std::vector{4, 5, 6}));
+    assert(std::ranges::equal(*++it, std::vector{7, 8}));
+    assert(++it == chunked.end());
+    /*chunk_view::__iterator<true>*/ std::forward_iterator auto const_it = const_chunked.begin();
+    assert(std::ranges::equal(*const_it, std::vector{1, 2, 3}));
+    assert(std::ranges::equal(*++const_it, std::vector{4, 5, 6}));
+    assert(std::ranges::equal(*++const_it, std::vector{7, 8}));
+    assert(++const_it == const_chunked.end());
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/ctad.compile.pass.cpp
new file mode 100644
index 0000000000000..9bf2baba58c78
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/ctad.compile.pass.cpp
@@ -0,0 +1,55 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+//   template <class R>
+//   chunk_view(R&&, range_difference_t<R>) -> chunk_view<all_t<R>>;
+
+#include <ranges>
+
+struct view : std::ranges::view_base {
+  int* begin() const;
+  int* end() const;
+};
+
+struct range {
+  int* begin() const;
+  int* end() const;
+};
+
+struct borrowed_range {
+  int* begin() const;
+  int* end() const;
+};
+
+template <>
+inline constexpr bool std::ranges::enable_borrowed_range<borrowed_range> = true;
+
+void test_ctad() {
+  view v;
+  range r;
+  borrowed_range br;
+
+  // clang-format off
+  static_assert(std::same_as<decltype(std::ranges::chunk_view(v, 0)), 
+                                      std::ranges::chunk_view<view>>);
+  static_assert(std::same_as<decltype(std::ranges::chunk_view(std::move(v), 0)), 
+                                      std::ranges::chunk_view<view>>);
+  static_assert(std::same_as<decltype(std::ranges::chunk_view(r, 0)), 
+                                      std::ranges::chunk_view<std::ranges::ref_view<range>>>);
+  static_assert(std::same_as<decltype(std::ranges::chunk_view(std::move(r), 0)),
+                                      std::ranges::chunk_view<std::ranges::owning_view<range>>>);
+  static_assert(std::same_as<decltype(std::ranges::chunk_view(br, 0)),
+                                      std::ranges::chunk_view<std::ranges::ref_view<borrowed_range>>>);
+  static_assert(std::same_as<decltype(std::ranges::chunk_view(std::move(br), 0)),
+                                      std::ranges::chunk_view<std::ranges::owning_view<borrowed_range>>>);
+  // clang-format on
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/end.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/end.pass.cpp
new file mode 100644
index 0000000000000..73eb0d967f6a2
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/end.pass.cpp
@@ -0,0 +1,65 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+//   V models only input_range:
+//     constexpr default_sentinel_t end();
+
+//   V moduels forward_range:
+//     constexpr auto end() requires (!__simple_view<V>);
+//     constexpr auto end() const requires forward_range<const V>;
+
+#include <algorithm>
+#include <cassert>
+#include <concepts>
+#include <iterator>
+#include <ranges>
+#include <vector>
+
+#include "test_range.h"
+#include "types.h"
+
+constexpr bool test() {
+  std::vector<int> vector                                                  = {1, 2, 3, 4, 5, 6, 7, 8};
+  std::ranges::chunk_view<std::ranges::ref_view<std::vector<int>>> chunked = vector | std::views::chunk(3);
+  std::ranges::chunk_view<std::ranges::ref_view<const std::vector<int>>> const_chunked =
+      std::as_const(vector) | std::views::chunk(3);
+  std::ranges::chunk_view<input_span<int>> input_chunked = input_span<int>(vector.data(), 8) | std::views::chunk(3);
+
+  // Test `chunk_view.end()` when V models only input_range
+  {
+    static_assert(noexcept(input_chunked.end()));
+    [[maybe_unused]] std::same_as<std::default_sentinel_t> auto it = input_chunked.end();
+  }
+
+  // Test `chunk_view.end()` when V models forward_range
+  {
+    /*chunk_view::__iterator<false>*/ std::forward_iterator auto it = chunked.end();
+    assert(std::ranges::equal(*--it, std::vector{7, 8}));
+    assert(std::ranges::equal(*--it, std::vector{4, 5, 6}));
+    assert(std::ranges::equal(*--it, std::vector{1, 2, 3}));
+    assert(it == chunked.begin());
+    /*chunk_view::__iterator<true>*/ std::forward_iterator auto const_it = const_chunked.end();
+    assert(std::ranges::equal(*--const_it, std::vector{7, 8}));
+    assert(std::ranges::equal(*--const_it, std::vector{4, 5, 6}));
+    assert(std::ranges::equal(*--const_it, std::vector{1, 2, 3}));
+    assert(const_it == const_chunked.begin());
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/general.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/general.pass.cpp
new file mode 100644
index 0000000000000..89891bc093080
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/general.pass.cpp
@@ -0,0 +1,48 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+//   General tests for chunk_view. This file does not test anything specifically.
+
+#include <algorithm>
+#include <cassert>
+#include <ranges>
+#include <string_view>
+
+#include "test_range.h"
+
+constexpr bool test() {
+  std::string_view str = "Cheese with chicken chunk by chunk on truck with my trick";
+  // clang-format off
+  auto str2 = str 
+            | std::views::chunk(4)
+            | std::views::join
+            | std::views::chunk(314159)
+            | std::views::take(1)
+            | std::views::join
+            | std::views::lazy_split(' ')
+            | std::views::chunk(2)
+            | std::views::transform([] (auto&& subview)
+              {
+                return subview | std::views::join_with(' ');
+              })
+            | std::views::join_with(' ');
+  // clang-format on
+  assert(std::ranges::equal(str, str2));
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/compare.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/compare.pass.cpp
new file mode 100644
index 0000000000000..d86726d958e6e
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/compare.pass.cpp
@@ -0,0 +1,109 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+//   V models only input_range
+//     friend constexpr bool opreator==(const outer_iterator& x, default_sentinel_t);
+//     friend constexpr difference_type operator-(default_sentinel_t t, const outer_iterator& i)
+//       requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
+//     friend constexpr difference_type operator-(const outer_iterator& i, default_sentinel_t t)
+//       requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
+
+//   V models forward_range
+//     friend constexpr bool operator==(const iterator& x, const iterator& y)
+//     friend constexpr bool operator<(const iterator& x, const iterator& y)
+//       requires random_access_range<Base>;
+//     friend constexpr bool operator>(const iterator& x, const iterator& y)
+//       requires random_access_range<Base>;
+//     friend constexpr bool operator<=(const iterator& x, const iterator& y)
+//       requires random_access_range<Base>;
+//     friend constexpr bool operator>=(const iterator& x, const iterator& y)
+//       requires random_access_range<Base>;
+//     friend constexpr auto operator<=>(const iterator& x, const iterator& y)
+//       requires random_access_range<Base> &&
+//                three_way_comparable<iterator_t<Base>>;
+
+#include <algorithm>
+#include <cassert>
+#include <compare>
+#include <iterator>
+#include <ranges>
+#include <vector>
+
+#include "test_range.h"
+#include "../types.h"
+
+constexpr bool test() {
+  std::vector<int> vector                                                  = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
+  std::ranges::chunk_view<std::ranges::ref_view<std::vector<int>>> chunked = vector | std::views::chunk(3);
+  std::ranges::chunk_view<input_span<int>> input_chunked = input_span<int>(vector) | std::views::chunk(3);
+
+  // Test `friend constexpr bool opreator==(const outer_iterator& x, default_sentinel_t)`
+  {
+    /*chunk_view::__outer_iterator*/ std::input_iterator auto it = input_chunked.begin();
+    std::ranges::advance(it, 4);
+    assert(it == std::default_sentinel);
+  }
+
+  // Test `friend constexpr difference_type operator-(default_sentinel_t t, const outer_iterator& i)`
+  {
+    assert(input_chunked.end() - input_chunked.begin() == 4);
+  }
+
+  // Test `friend constexpr difference_type operator-(const outer_iterator& i, default_sentinel_t)`
+  {
+    assert(input_chunked.begin() - input_chunked.end() == -4);
+  }
+
+  // Test `friend constexpr bool operator==(const iterator& x, const iterator& y)`
+  {
+    assert(chunked.begin() == chunked.begin());
+    assert(chunked.end() == chunked.end());
+  }
+
+  // Test `friend constexpr bool operator<(const iterator& x, const iterator& y)`
+  {
+    assert(chunked.begin() < chunked.end());
+  }
+
+  // Test `friend constexpr bool operator>(const iterator& x, const iterator& y)`
+  {
+    assert(chunked.end() > chunked.begin());
+  }
+
+  // Test `friend constexpr bool operator>=(const iterator& x, const iterator& y)`
+  {
+    assert(chunked.begin() <= chunked.begin());
+    assert(chunked.begin() <= chunked.end());
+  }
+
+  // Test `friend constexpr bool operator>=(const iterator& x, const iterator& y)`
+  {
+    assert(chunked.end() >= chunked.end());
+    assert(chunked.end() >= chunked.begin());
+  }
+
+  // Test `friend constexpr auto operator<=>(const iterator& x, const iterator& y)`
+  {
+    assert((chunked.begin() <=> chunked.begin()) == std::strong_ordering::equal);
+    assert((chunked.begin() <=> chunked.end()) == std::strong_ordering::less);
+    assert((chunked.end() <=> chunked.begin()) == std::strong_ordering::greater);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/decrement.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/decrement.pass.cpp
new file mode 100644
index 0000000000000..397b32e73080a
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/decrement.pass.cpp
@@ -0,0 +1,60 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+//   constexpr iterator& operator--()
+//     requires bidirectional_range<Base>;
+//   constexpr iterator operator--(int)
+//     requires bidirectional_range<Base>;
+//   constexpr iterator& operator-=(difference_type)
+//     requires random_access_range<Base>;
+
+#include <algorithm>
+#include <cassert>
+#include <iterator>
+#include <ranges>
+#include <vector>
+
+#include "test_range.h"
+
+constexpr bool test() {
+  std::vector<int> vector                                                  = {1, 2, 3, 4, 5, 6, 7, 8};
+  std::ranges::chunk_view<std::ranges::ref_view<std::vector<int>>> chunked = vector | std::views::chunk(2);
+
+  // Test `constexpr iterator& operator--();`
+  {
+    /*chunk_view::__outer_iterator*/ std::bidirectional_iterator auto it = chunked.end();
+    assert(std::ranges::equal(*--it, std::vector{7, 8}));
+  }
+
+  // Test `constexpr iterator operator--(int)`
+  {
+    /*chunk_view::__outer_iterator*/ std::bidirectional_iterator auto it = chunked.end();
+    it--;
+    assert(std::ranges::equal(*it, std::vector{7, 8}));
+  }
+
+  // Test `constexpr iterator& operator-=(difference_type)`
+  {
+    /*chunk_view::__iterator*/ std::random_access_iterator auto it = chunked.end();
+    it -= 3;
+    assert(std::ranges::equal(*it, std::vector{3, 4}));
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/deref.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/deref.pass.cpp
new file mode 100644
index 0000000000000..b8772d0fac3d2
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/deref.pass.cpp
@@ -0,0 +1,77 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+//   V models only input_range:
+//     constexpr value_type outer_iterator::operator*() const;
+//     constexpr inner_iterator outer_iterator::value_type::begin() const noexcept;
+//     constexpr default_sentinel_t outer_iterator::value_type::end() const noexcept;
+//     constexpr range_reference_v<V> inner_iterator::operator*() const;
+
+//   V models forward_range:
+//     constexpr value_type iterator::operator*() const;
+
+#include <algorithm>
+#include <cassert>
+#include <compare>
+#include <iterator>
+#include <ranges>
+#include <vector>
+
+#include "test_range.h"
+#include "../types.h"
+
+constexpr bool test() {
+  std::vector<int> vector                                                  = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
+  std::ranges::chunk_view<std::ranges::ref_view<std::vector<int>>> chunked = vector | std::views::chunk(3);
+  std::ranges::chunk_view<input_span<int>> input_chunked = input_span<int>(vector) | std::views::chunk(3);
+
+  // Test `constexpr value_type outer_iterator::operator*() const`
+  {
+    static_assert(std::ranges::input_range<decltype(*input_chunked.begin())>);
+  }
+
+  // Test `constexpr inner_iterator outer_iterator::value_type::begin() const noexcept`
+  {
+    /*chunk_view::__outer_iterator::value_type*/ std::ranges::input_range auto inner = *input_chunked.begin();
+    assert(*inner.begin() == *vector.begin());
+    static_assert(noexcept(inner.begin()));
+  }
+
+  // Test `constexpr default_sentinel_t outer_iterator::value_type::end() const noexcept`
+  {
+    /*chunk_view::__outer_iterator::value_type*/ std::ranges::input_range auto inner = *input_chunked.begin();
+    [[maybe_unused]] std::same_as<std::default_sentinel_t> auto it                   = inner.end();
+    static_assert(noexcept((inner.end())));
+  }
+
+  // Test `constexpr value_type iterator::operator*() const`
+  {
+    /*chunk_view::__inner_iterator*/ std::input_iterator auto it = (*input_chunked.begin()).begin();
+    std::same_as<int> decltype(auto) v                           = *it;
+    assert(v == 1);
+  }
+
+  // Test `constexpr range_reference_v<V> inner_iterator::operator*() const`
+  {
+    std::same_as<int&> decltype(auto) v = *(*chunked.begin()).begin();
+    assert(v == 1);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/increment.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/increment.pass.cpp
new file mode 100644
index 0000000000000..6048aba027ce9
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/increment.pass.cpp
@@ -0,0 +1,95 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+//   V models only input_range
+//     constexpr outer_iterator& operator++();
+//     constexpr void operator++(int);
+//     constexpr inner_iterator& operator++();
+//     constexpr void operator++(int);
+
+//   V models forward_range
+//     constexpr iterator& operator++();
+//     constexpr iterator operator++(int);
+//     constexpr iterator& operator+=(difference_type)
+//       requires random_access_range<Base>;
+
+#include <algorithm>
+#include <cassert>
+#include <iterator>
+#include <ranges>
+#include <vector>
+
+#include "test_range.h"
+#include "../types.h"
+
+constexpr bool test() {
+  std::vector<int> vector                                                  = {1, 2, 3, 4, 5, 6, 7, 8};
+  std::ranges::chunk_view<std::ranges::ref_view<std::vector<int>>> chunked = vector | std::views::chunk(2);
+  std::ranges::chunk_view<input_span<int>> input_chunked = input_span<int>(vector) | std::views::chunk(2);
+
+  // Test `constexpr outer_iterator& operator++();`
+  {
+    /*chunk_view::__outer_iterator*/ std::input_iterator auto it = input_chunked.begin();
+    assert(std::ranges::equal(*++it, std::vector{3, 4}));
+  }
+
+  // Test `constexpr void operator++(int);`
+  {
+    /*chunk_view::__outer_iterator*/ std::input_iterator auto it = input_chunked.begin();
+    static_assert(std::same_as<decltype(it++), void>);
+    it++;
+    assert(std::ranges::equal(*it, std::vector{3, 4}));
+  }
+
+  // Test `constexpr inner_iterator& operator++();`
+  {
+    /*chunk_view::__inner_iterator*/ std::input_iterator auto it = (*input_chunked.begin()).begin();
+    assert(*++it == 2);
+  }
+
+  // Test `constexpr inner_iterator& operator++();`
+  {
+    /*chunk_view::__inner_iterator*/ std::input_iterator auto it = (*input_chunked.begin()).begin();
+    static_assert(std::same_as<decltype(it++), void>);
+    it++;
+    assert(*it == 2);
+  }
+
+  // Test `constexpr iterator& operator++();`
+  {
+    /*chunk_view::__iterator*/ std::forward_iterator auto it = chunked.begin();
+    assert(std::ranges::equal(*++it, std::vector{3, 4}));
+  }
+
+  // Test `constexpr iterator operator++(int)`
+  {
+    /*chunk_view::__iterator*/ std::forward_iterator auto it = chunked.begin();
+    it++;
+    assert(std::ranges::equal(*it, std::vector{3, 4}));
+  }
+
+  // Test `constexpr iterator& operator+=(difference_type)`
+  {
+    /*chunk_view::__iterator*/ std::random_access_iterator auto it = chunked.begin();
+    it += 3;
+    assert(std::ranges::equal(*it, std::vector{7, 8}));
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/types.h b/libcxx/test/std/ranges/range.adaptors/range.chunk/types.h
new file mode 100644
index 0000000000000..09d16c9a48af0
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/types.h
@@ -0,0 +1,50 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_CHUNK_TYPES_H
+#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_CHUNK_TYPES_H
+
+#include <iterator>
+#include <ranges>
+#include <span>
+#include <vector>
+
+// input_span
+
+template <class T>
+struct input_span : std::span<T> {
+  struct iterator : std::span<T>::iterator {
+    using iterator_concept = std::input_iterator_tag;
+    constexpr iterator()   = default;
+    constexpr iterator(std::span<T>::iterator i) : std::span<T>::iterator(i) {}
+    constexpr auto operator*() const { return std::span<T>::iterator::operator*(); }
+    friend constexpr auto operator+(iterator, std::span<T>::difference_type) = delete;
+    friend constexpr auto operator+(std::span<T>::difference_type, iterator) = delete;
+    friend constexpr auto operator-(iterator, std::span<T>::difference_type) = delete;
+    friend constexpr auto operator-(std::span<T>::difference_type, iterator) = delete;
+    friend constexpr iterator& operator++(iterator& self) {
+      ++static_cast<std::span<T>::iterator&>(self);
+      return self;
+    }
+    friend constexpr void operator++(iterator& self, int) { ++self; }
+    friend constexpr iterator& operator--(iterator&) = delete;
+    friend constexpr void operator--(iterator&, int) = delete;
+  };
+
+  using std::span<T>::span;
+  constexpr iterator begin() { return iterator(std::span<T>::begin()); }
+  constexpr iterator end() { return iterator(std::span<T>::end()); }
+};
+
+template <class T>
+inline constexpr bool std::ranges::enable_view<input_span<T>> = true;
+
+static_assert(std::ranges::input_range<input_span<int>> && !std::ranges::forward_range<input_span<int>> &&
+              std::ranges::view<input_span<int>>);
+
+#endif
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index f61d6f991cb15..49fb196903e77 100644
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -1106,7 +1106,6 @@ def add_version_header(tc):
             "name": "__cpp_lib_ranges_chunk",
             "values": {"c++23": 202202},
             "headers": ["ranges"],
-            "unimplemented": True,
         },
         {
             "name": "__cpp_lib_ranges_chunk_by",

>From af914e794ddb86103e6b7acf3bf17d40f5055a8a Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Fri, 26 Dec 2025 01:44:18 +0800
Subject: [PATCH 02/43] Code Review: adjust release notes

Note that we will merge this commit with the corresponding change in #172948 in the future.
---
 libcxx/docs/ReleaseNotes/22.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/docs/ReleaseNotes/22.rst b/libcxx/docs/ReleaseNotes/22.rst
index d2a2d1b712689..30fc22fc0d787 100644
--- a/libcxx/docs/ReleaseNotes/22.rst
+++ b/libcxx/docs/ReleaseNotes/22.rst
@@ -54,7 +54,7 @@ Implemented Papers
 - P3567R2: ``flat_meow`` Fixes (`Github <https://llvm.org/PR162022>`__)
 - P3836R2: Make ``optional<T&>`` trivially copyable (`Github <https://llvm.org/PR171275>`__)
 - P1789R3: Library Support for Expansion Statements (`Github <https://llvm.org/PR167184>`__)
-- P2442R1: P2442R1: Windowing range adaptors: ``views::chunk`` and ``views::slide`` (`Github <https://llvm.org/PR171234>`__) (Implemented ``views::slide`` only)
+- P2442R1: Windowing range adaptors: ``views::chunk`` and ``views::slide`` (`Github <https://llvm.org/PR171234>`__) (Implemented ``views::slide`` only)
 
 Improvements and New Features
 -----------------------------

>From dc62f798ba5615dcac60fffa2cc0afa8b79344c5 Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Fri, 26 Dec 2025 13:03:41 +0800
Subject: [PATCH 03/43] Add Tests: test if `_LIBCPP_ASSERT_XXX` works when
 `views::chunk` meets an undefined behaviour

---
 libcxx/include/__ranges/chunk_view.h          |  6 ++-
 .../range.chunk/assert.constructor.pass.cpp   | 39 ++++++++++++++
 .../range.chunk.iter/assert.advance.pass.cpp  | 32 ++++++++++++
 .../range.chunk.iter/assert.deref.pass.cpp    | 52 +++++++++++++++++++
 .../assert.increment.pass.cpp                 | 52 +++++++++++++++++++
 .../ranges/range.adaptors/range.chunk/types.h | 50 ++++++++++++++++++
 6 files changed, 229 insertions(+), 2 deletions(-)
 create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.chunk/assert.constructor.pass.cpp
 create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.advance.pass.cpp
 create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.deref.pass.cpp
 create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.increment.pass.cpp
 create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.chunk/types.h

diff --git a/libcxx/include/__ranges/chunk_view.h b/libcxx/include/__ranges/chunk_view.h
index f19d2c9ede8a7..683b6bbaa2ca5 100644
--- a/libcxx/include/__ranges/chunk_view.h
+++ b/libcxx/include/__ranges/chunk_view.h
@@ -128,11 +128,12 @@ class chunk_view<_View>::__outer_iterator {
   _LIBCPP_HIDE_FROM_ABI __outer_iterator& operator=(__outer_iterator&&) = default;
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr value_type operator*() const {
-    _LIBCPP_ASSERT_PEDANTIC(*this != default_sentinel, "Trying to dereference past-the-end chunk_view iterator.");
+    _LIBCPP_ASSERT_PEDANTIC(*this != default_sentinel, "Trying to dereference past-the-end chunk_view iterator");
     return value_type(*__parent_);
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr __outer_iterator& operator++() {
+    _LIBCPP_ASSERT_PEDANTIC(*this != default_sentinel, "Trying to increment past-the-end chunk_view iterator");
     ranges::advance(*__parent_->__current_, __parent_->__remainder_, ranges::end(__parent_->__base_));
     __parent_->__remainder_ = __parent_->__n_;
     return *this;
@@ -214,6 +215,7 @@ class chunk_view<_View>::__inner_iterator {
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr __inner_iterator& operator++() {
+    _LIBCPP_ASSERT_PEDANTIC(*this != default_sentinel, "Trying to increment past-the-end chunk_view iterator");
     ++*__parent_->__current_;
     if (*__parent_->__current_ == ranges::end(__parent_->__base_))
       __parent_->__remainder_ = 0;
@@ -386,7 +388,7 @@ class chunk_view<_View>::__iterator {
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() {
-    _LIBCPP_ASSERT_PEDANTIC(__current_ != __end_, "Trying to advance past-the-end chunk_view iterator");
+    _LIBCPP_ASSERT_PEDANTIC(__current_ != __end_, "Trying to increment past-the-end chunk_view iterator");
     __missing_ = ranges::advance(__current_, __n_, __end_);
     return *this;
   }
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/assert.constructor.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/assert.constructor.pass.cpp
new file mode 100644
index 0000000000000..03fc7dfb6a5de
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/assert.constructor.pass.cpp
@@ -0,0 +1,39 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: has-unix-headers
+// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
+
+// <ranges>
+
+// Construct a chunk_view with chunk size <= 0
+
+#include <ranges>
+#include <vector>
+
+#include "check_assertion.h"
+#include "types.h"
+
+int main() {
+  std::vector<int> vector = {1, 2, 3};
+
+  // Test constructor when V models only input_range.
+  {
+    TEST_LIBCPP_ASSERT_FAILURE(
+        input_span(vector.data(), 3) | std::views::chunk(0), "Trying to construct a chunk_view with chunk size <= 0");
+    TEST_LIBCPP_ASSERT_FAILURE(
+        input_span(vector.data(), 3) | std::views::chunk(-1), "Trying to construct a chunk_view with chunk size <= 0");
+  }
+
+  // Test constructor when V models forward_range.
+  {
+    TEST_LIBCPP_ASSERT_FAILURE(vector | std::views::chunk(0), "Trying to construct a chunk_view with chunk size <= 0");
+    TEST_LIBCPP_ASSERT_FAILURE(vector | std::views::chunk(-1), "Trying to construct a chunk_view with chunk size <= 0");
+  }
+}
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.advance.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.advance.pass.cpp
new file mode 100644
index 0000000000000..af2b826aa8eba
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.advance.pass.cpp
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: has-unix-headers
+// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
+
+// <ranges>
+
+// Trying to advance chunk_view iterator out of range
+
+#include <iterator>
+#include <ranges>
+#include <vector>
+
+#include "check_assertion.h"
+
+int main() {
+  std::vector<int> vector = {1, 2, 3, 4, 5, 6, 7, 8};
+  auto chunked            = vector | std::views::chunk(3);
+
+  // Test advance past-the-end iterator when V models forward_range
+  {
+    /*chunk_view::__iterator*/ std::random_access_iterator auto it = chunked.begin();
+    TEST_LIBCPP_ASSERT_FAILURE(it += 4, "Trying to advance chunk_view iterator out of range");
+  }
+}
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.deref.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.deref.pass.cpp
new file mode 100644
index 0000000000000..cb1d92885e684
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.deref.pass.cpp
@@ -0,0 +1,52 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: has-unix-headers
+// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
+
+// <ranges>
+
+// Trying to dereference past-the-end chunk_view iterator
+
+#include <iterator>
+#include <ranges>
+#include <vector>
+
+#include "check_assertion.h"
+#include "types.h"
+
+int main() {
+  std::vector<int> vector = {1, 2, 3, 4, 5, 6, 7, 8};
+  auto chunked            = vector | std::views::chunk(3);
+  auto input_chunked      = input_span(vector.data(), 8) | std::views::chunk(3);
+
+  // Test dereference iterator when V models only input_range
+  {
+    /*chunk_view::__outer_iterator*/ std::input_iterator auto outer_it = input_chunked.begin();
+    ++outer_it;
+    ++outer_it;
+    ++outer_it;
+    TEST_LIBCPP_ASSERT_FAILURE(*outer_it, "Trying to dereference past-the-end chunk_view iterator");
+
+    /*chunk_view::__inner_iterator*/ std::input_iterator auto inner_it = (*input_chunked.begin()).begin();
+    ++inner_it;
+    ++inner_it;
+    ++inner_it;
+    TEST_LIBCPP_ASSERT_FAILURE(*inner_it, "Trying to dereference past-the-end chunk_view iterator");
+  }
+
+  // Test dereference iterator when V models forward_range
+  {
+    /*chunk_view::__iterator*/ std::random_access_iterator auto it = chunked.begin();
+    ++it;
+    ++it;
+    ++it;
+    TEST_LIBCPP_ASSERT_FAILURE(*it, "Trying to dereference past-the-end chunk_view iterator");
+  }
+}
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.increment.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.increment.pass.cpp
new file mode 100644
index 0000000000000..8160ee1bb3e14
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.increment.pass.cpp
@@ -0,0 +1,52 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: has-unix-headers
+// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
+
+// <ranges>
+
+// Trying to increment past-the-end chunk_view iterator
+
+#include <iterator>
+#include <ranges>
+#include <vector>
+
+#include "check_assertion.h"
+#include "types.h"
+
+int main() {
+  std::vector<int> vector = {1, 2, 3, 4, 5, 6, 7, 8};
+  auto chunked            = vector | std::views::chunk(3);
+  auto input_chunked      = input_span(vector.data(), 8) | std::views::chunk(3);
+
+  // Test increment past-the-end iterator when V models only input_range
+  {
+    /*chunk_view::__outer_iterator*/ std::input_iterator auto outer_it = input_chunked.begin();
+    ++outer_it;
+    ++outer_it;
+    ++outer_it;
+    TEST_LIBCPP_ASSERT_FAILURE(++outer_it, "Trying to increment past-the-end chunk_view iterator");
+
+    /*chunk_view::__inner_iterator*/ std::input_iterator auto inner_it = (*input_chunked.begin()).begin();
+    ++inner_it;
+    ++inner_it;
+    ++inner_it;
+    TEST_LIBCPP_ASSERT_FAILURE(++inner_it, "Trying to increment past-the-end chunk_view iterator");
+  }
+
+  // Test increment past-the-end iterator when V models forward_range
+  {
+    /*chunk_view::__iterator*/ std::random_access_iterator auto it = chunked.begin();
+    ++it;
+    ++it;
+    ++it;
+    TEST_LIBCPP_ASSERT_FAILURE(++it, "Trying to increment past-the-end chunk_view iterator");
+  }
+}
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/types.h b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/types.h
new file mode 100644
index 0000000000000..a5d688abfa1b0
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/types.h
@@ -0,0 +1,50 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_LIBCXX_RANGES_RANGE_ADAPTORS_RANGE_CHUNK_TYPES_H
+#define TEST_LIBCXX_RANGES_RANGE_ADAPTORS_RANGE_CHUNK_TYPES_H
+
+#include <iterator>
+#include <ranges>
+#include <span>
+#include <vector>
+
+// input_span
+
+template <class T>
+struct input_span : std::span<T> {
+  struct iterator : std::span<T>::iterator {
+    using iterator_concept = std::input_iterator_tag;
+    constexpr iterator()   = default;
+    constexpr iterator(std::span<T>::iterator i) : std::span<T>::iterator(i) {}
+    constexpr auto operator*() const { return std::span<T>::iterator::operator*(); }
+    friend constexpr auto operator+(iterator, std::span<T>::difference_type) = delete;
+    friend constexpr auto operator+(std::span<T>::difference_type, iterator) = delete;
+    friend constexpr auto operator-(iterator, std::span<T>::difference_type) = delete;
+    friend constexpr auto operator-(std::span<T>::difference_type, iterator) = delete;
+    friend constexpr iterator& operator++(iterator& self) {
+      ++static_cast<std::span<T>::iterator&>(self);
+      return self;
+    }
+    friend constexpr void operator++(iterator& self, int) { ++self; }
+    friend constexpr iterator& operator--(iterator&) = delete;
+    friend constexpr void operator--(iterator&, int) = delete;
+  };
+
+  using std::span<T>::span;
+  constexpr iterator begin() { return iterator(std::span<T>::begin()); }
+  constexpr iterator end() { return iterator(std::span<T>::end()); }
+};
+
+template <class T>
+inline constexpr bool std::ranges::enable_view<input_span<T>> = true;
+
+static_assert(std::ranges::input_range<input_span<int>> && !std::ranges::forward_range<input_span<int>> &&
+              std::ranges::view<input_span<int>>);
+
+#endif

>From b664c0cb8f8ed9b46629fa49e4bdd846734615d4 Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Sun, 28 Dec 2025 12:42:26 +0800
Subject: [PATCH 04/43] Fix CI: adjust `#include` path in `test/libcxx` files

---
 .../range.chunk/range.chunk.iter/assert.deref.pass.cpp          | 2 +-
 .../range.chunk/range.chunk.iter/assert.increment.pass.cpp      | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.deref.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.deref.pass.cpp
index cb1d92885e684..0c96742147189 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.deref.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.deref.pass.cpp
@@ -19,7 +19,7 @@
 #include <vector>
 
 #include "check_assertion.h"
-#include "types.h"
+#include "../types.h"
 
 int main() {
   std::vector<int> vector = {1, 2, 3, 4, 5, 6, 7, 8};
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.increment.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.increment.pass.cpp
index 8160ee1bb3e14..451683bab71b0 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.increment.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.increment.pass.cpp
@@ -19,7 +19,7 @@
 #include <vector>
 
 #include "check_assertion.h"
-#include "types.h"
+#include "../types.h"
 
 int main() {
   std::vector<int> vector = {1, 2, 3, 4, 5, 6, 7, 8};

>From 4dc9b06c0dd515030226b9d27841352ef62549a3 Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Sun, 28 Dec 2025 12:42:58 +0800
Subject: [PATCH 05/43] Fix CI: add template deduction guide for
 `input_span<T>`

---
 libcxx/test/libcxx/ranges/range.adaptors/range.chunk/types.h | 3 +++
 libcxx/test/std/ranges/range.adaptors/range.chunk/types.h    | 3 +++
 2 files changed, 6 insertions(+)

diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/types.h b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/types.h
index a5d688abfa1b0..0978a23c37244 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/types.h
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/types.h
@@ -41,6 +41,9 @@ struct input_span : std::span<T> {
   constexpr iterator end() { return iterator(std::span<T>::end()); }
 };
 
+template <class T>
+input_span(T*, size_t) -> input_span<T>;
+
 template <class T>
 inline constexpr bool std::ranges::enable_view<input_span<T>> = true;
 
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/types.h b/libcxx/test/std/ranges/range.adaptors/range.chunk/types.h
index 09d16c9a48af0..4ff1af1d7cda3 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/types.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/types.h
@@ -41,6 +41,9 @@ struct input_span : std::span<T> {
   constexpr iterator end() { return iterator(std::span<T>::end()); }
 };
 
+template <class T>
+input_span(T*, size_t) -> input_span<T>;
+
 template <class T>
 inline constexpr bool std::ranges::enable_view<input_span<T>> = true;
 

>From 1e8906ad49a2406158161cc1b9d0e1570af2959d Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Sun, 28 Dec 2025 12:53:21 +0800
Subject: [PATCH 06/43] Code Review: add `REQUIRES: std-at-least-c++23` in all
 the tests related to `views::chunk`.

The previous commit, 4dc9b06c0dd515030226b9d27841352ef62549a3, which introduce manual/explicit template deduction guide in `input_span<T>`, is always implicitly-provided under -std=c++23. So this commit also reverts the changes about `types.h` in the previous commit.
---
 .../range.adaptors/range.chunk/assert.constructor.pass.cpp     | 1 +
 .../range.chunk/range.chunk.iter/assert.advance.pass.cpp       | 1 +
 .../range.chunk/range.chunk.iter/assert.deref.pass.cpp         | 1 +
 .../range.chunk/range.chunk.iter/assert.increment.pass.cpp     | 1 +
 libcxx/test/libcxx/ranges/range.adaptors/range.chunk/types.h   | 3 ---
 libcxx/test/std/ranges/range.adaptors/range.chunk/types.h      | 3 ---
 6 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/assert.constructor.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/assert.constructor.pass.cpp
index 03fc7dfb6a5de..477f89be5f070 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/assert.constructor.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/assert.constructor.pass.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+// REQUIRES: std-at-least-c++23
 // REQUIRES: has-unix-headers
 // REQUIRES: libcpp-hardening-mode={{extensive|debug}}
 // XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.advance.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.advance.pass.cpp
index af2b826aa8eba..9b91d94841b91 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.advance.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.advance.pass.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+// REQUIRES: std-at-least-c++23
 // REQUIRES: has-unix-headers
 // REQUIRES: libcpp-hardening-mode={{extensive|debug}}
 // XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.deref.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.deref.pass.cpp
index 0c96742147189..3640b04192bf4 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.deref.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.deref.pass.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+// REQUIRES: std-at-least-c++23
 // REQUIRES: has-unix-headers
 // REQUIRES: libcpp-hardening-mode={{extensive|debug}}
 // XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.increment.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.increment.pass.cpp
index 451683bab71b0..61c096f74158e 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.increment.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/range.chunk.iter/assert.increment.pass.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+// REQUIRES: std-at-least-c++23
 // REQUIRES: has-unix-headers
 // REQUIRES: libcpp-hardening-mode={{extensive|debug}}
 // XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/types.h b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/types.h
index 0978a23c37244..a5d688abfa1b0 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/types.h
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/types.h
@@ -41,9 +41,6 @@ struct input_span : std::span<T> {
   constexpr iterator end() { return iterator(std::span<T>::end()); }
 };
 
-template <class T>
-input_span(T*, size_t) -> input_span<T>;
-
 template <class T>
 inline constexpr bool std::ranges::enable_view<input_span<T>> = true;
 
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/types.h b/libcxx/test/std/ranges/range.adaptors/range.chunk/types.h
index 4ff1af1d7cda3..09d16c9a48af0 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/types.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/types.h
@@ -41,9 +41,6 @@ struct input_span : std::span<T> {
   constexpr iterator end() { return iterator(std::span<T>::end()); }
 };
 
-template <class T>
-input_span(T*, size_t) -> input_span<T>;
-
 template <class T>
 inline constexpr bool std::ranges::enable_view<input_span<T>> = true;
 

>From 7e21388c70b38c32125e4d3eda9b3a4c66e1d3db Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Sun, 28 Dec 2025 14:13:59 +0800
Subject: [PATCH 07/43] Fix CI: add template deduction guide for
 `input_span<T>` again.

Seems that even in C++23 the CI fails due to no implicit deduction guide, here we just add the explicit one and make the CI to basically run ok.
---
 libcxx/test/libcxx/ranges/range.adaptors/range.chunk/types.h | 4 ++++
 libcxx/test/std/ranges/range.adaptors/range.chunk/types.h    | 4 ++++
 2 files changed, 8 insertions(+)

diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/types.h b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/types.h
index a5d688abfa1b0..4852ec29204bb 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/types.h
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/types.h
@@ -9,6 +9,7 @@
 #ifndef TEST_LIBCXX_RANGES_RANGE_ADAPTORS_RANGE_CHUNK_TYPES_H
 #define TEST_LIBCXX_RANGES_RANGE_ADAPTORS_RANGE_CHUNK_TYPES_H
 
+#include <cstddef>
 #include <iterator>
 #include <ranges>
 #include <span>
@@ -41,6 +42,9 @@ struct input_span : std::span<T> {
   constexpr iterator end() { return iterator(std::span<T>::end()); }
 };
 
+template <class T>
+input_span(T*, std::ptrdiff_t) -> input_span<T>;
+
 template <class T>
 inline constexpr bool std::ranges::enable_view<input_span<T>> = true;
 
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/types.h b/libcxx/test/std/ranges/range.adaptors/range.chunk/types.h
index 09d16c9a48af0..7533e41713d72 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/types.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/types.h
@@ -9,6 +9,7 @@
 #ifndef TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_CHUNK_TYPES_H
 #define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_CHUNK_TYPES_H
 
+#include <cstddef>
 #include <iterator>
 #include <ranges>
 #include <span>
@@ -41,6 +42,9 @@ struct input_span : std::span<T> {
   constexpr iterator end() { return iterator(std::span<T>::end()); }
 };
 
+template <class T>
+input_span(T*, std::ptrdiff_t) -> input_span<T>;
+
 template <class T>
 inline constexpr bool std::ranges::enable_view<input_span<T>> = true;
 

>From f1ed40a1aed2a1f5ebd1e56efcd6ae2bbb25dc26 Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Thu, 15 Jan 2026 18:07:21 +0800
Subject: [PATCH 08/43] Code review: Update libcxx/test synopsis

Co-authored-by: Hristo Hristov <hghristov.rmm at gmail.com>
---
 .../ranges/range.adaptors/range.chunk/nodiscard.verify.cpp      | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/nodiscard.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/nodiscard.verify.cpp
index 5e557715f4b03..9264256fc6a52 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/nodiscard.verify.cpp
@@ -10,7 +10,7 @@
 
 // <ranges>
 
-// Test the libc++ extension that std::ranges::chunk_view::iterator<Const>::operator* is marked as [[nodiscard]].
+// Test that functions are marked [[nodiscard]].
 
 #include <ranges>
 #include <utility>

>From 12bec119ba49cd6016055f5887f5e83efa25ee30 Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Thu, 15 Jan 2026 18:21:29 +0800
Subject: [PATCH 09/43] Code review: Fix synopsis.

Co-authored-by: Hristo Hristov <hghristov.rmm at gmail.com>
---
 libcxx/test/std/ranges/range.adaptors/range.chunk/base.pass.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/base.pass.cpp
index ac17f97a0a292..b45e1f59f1394 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/base.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/base.pass.cpp
@@ -10,7 +10,7 @@
 
 // <ranges>
 
-//   constexpr V base() const& requires copyy_constructible<V>;
+//   constexpr V base() const& requires copy_constructible<V>;
 //   constexpr V base() &&;
 
 #include <array>

>From 1e05c5a038dd4cee5a0049b8c7e92e59c8aabd82 Mon Sep 17 00:00:00 2001
From: anonymous <shyeyian at icloud.com>
Date: Thu, 15 Jan 2026 21:13:46 +0800
Subject: [PATCH 10/43] Code review: sort and unique the tests

---
 .../no_unique_address.compile.pass.cpp        |  24 ++--
 .../range.chunk/nodiscard.verify.cpp          |  35 ++----
 .../range.chunk.iter/arithmetic.pass.cpp      | 108 ++++++++++++++++++
 .../range.chunk.iter/compare.pass.cpp         |  29 +++--
 .../range.chunk.iter/subscript.pass.cpp       |  42 +++++++
 5 files changed, 189 insertions(+), 49 deletions(-)
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/arithmetic.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/subscript.pass.cpp

diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/no_unique_address.compile.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/no_unique_address.compile.pass.cpp
index 14c618c505e70..5d32daf4c178a 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/no_unique_address.compile.pass.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/no_unique_address.compile.pass.cpp
@@ -20,6 +20,8 @@
 #include "test_iterators.h"
 #include "test_range.h"
 
+// When V models only input_range
+
 struct input_view {
   cpp20_input_iterator<int*> begin() const;
   sentinel_wrapper<cpp20_input_iterator<int*>> end() const;
@@ -28,16 +30,8 @@ template <>
 inline constexpr bool std::ranges::enable_view<input_view> = true;
 static_assert(std::ranges::input_range<input_view> && !std::ranges::forward_range<input_view>);
 
-struct forward_view {
-  int* begin() const;
-  int* end() const;
-};
-template <>
-inline constexpr bool std::ranges::enable_view<forward_view> = true;
-static_assert(std::ranges::forward_range<forward_view>);
-
 using CV1 = std::ranges::chunk_view<input_view>;
-// Expected CV1 (with View == input) layout:
+// Expected CV1 (when V models only input_range) layout:
 // [[no_unique_address]] _View __base_                                         // size: 0
 // [[no_unique_address]] range_difference_t<_View> __n_                        // size: sizeof(ptrdiff_t)
 // [[no_unique_address]] range_difference_t<_View> __remainder_                // size: sizeof(ptrdiff_t)
@@ -46,8 +40,18 @@ static_assert(alignof(std::ranges::__non_propagating_cache<cpp20_input_iterator<
 static_assert(sizeof(CV1) == /*sizeof(__base_) == 0 + */ sizeof(std::ptrdiff_t) * 2 +
                                  sizeof(std::ranges::__non_propagating_cache<cpp20_input_iterator<int*>>));
 
+// When V models forward_range
+
+struct forward_view {
+  int* begin() const;
+  int* end() const;
+};
+template <>
+inline constexpr bool std::ranges::enable_view<forward_view> = true;
+static_assert(std::ranges::forward_range<forward_view>);
+
 using CV2 = std::ranges::chunk_view<forward_view>;
-// Expected CV2 (with View >= forward) layout:
+// Expected CV2 (when V models forward_range) layout:
 // [[no_unique_address]] _View __base_             // size: 0
 // [[no_unique_address]] range_difference_t<_View> // size: sizeof(ptrdiff_t)
 static_assert(sizeof(CV2) == /*sizeof(__base_) == 0 + */ sizeof(std::ptrdiff_t));
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/nodiscard.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/nodiscard.verify.cpp
index 9264256fc6a52..4d0fb4f76857c 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/nodiscard.verify.cpp
@@ -19,15 +19,6 @@ void test() {
   char range[6] = {'x', 'x', 'y', 'y', 'z', 'z'};
   auto view     = range | std::views::chunk(2);
 
-  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
-  std::views::chunk(3);
-  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
-  std::views::chunk(range, 3);
-  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
-  range | std::views::chunk(3);
-  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
-  std::views::reverse | std::views::chunk(3);
-
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
   view.base();
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
@@ -43,18 +34,19 @@ void test() {
   std::as_const(view).begin();
 
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
-  view.end();
+  std::ranges::iter_move(view.begin());
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
-  std::as_const(view).end();
+  std::ranges::iter_move(std::as_const(view).begin());
 
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
-  std::views::chunk(3);
+  view.end();
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
-  std::views::chunk(range, 3);
+  std::as_const(view).end();
+
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
-  range | std::views::chunk(3);
+  std::ranges::iter_move(view.end());
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
-  std::views::reverse | std::views::chunk(3);
+  std::ranges::iter_move(std::as_const(view).end());
 
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
   *view.begin();
@@ -71,16 +63,11 @@ void test() {
   (std::as_const(view).begin() == std::as_const(view).end());
 
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
-  (view.begin() == view.end());
-  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
-  (std::as_const(view).begin() == view.end());
-  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
-  (view.begin() == std::as_const(view).end());
+  std::views::chunk(3);
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
-  (std::as_const(view).begin() == std::as_const(view).end());
-
+  std::views::chunk(range, 3);
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
-  std::ranges::iter_move(view.begin());
+  range | std::views::chunk(3);
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
-  std::ranges::iter_move(std::as_const(view).begin());
+  std::views::reverse | std::views::chunk(3);
 }
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/arithmetic.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/arithmetic.pass.cpp
new file mode 100644
index 0000000000000..6baa2fce13695
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/arithmetic.pass.cpp
@@ -0,0 +1,108 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+//   V models only input_range
+//     friend constexpr difference_type operator-(default_sentinel_t t, const outer_iterator& i)
+//       requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
+//     friend constexpr difference_type operator-(const outer_iterator& i, default_sentinel_t t)
+//       requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
+//     friend constexpr difference_type operator-(default_sentinel_t y, const inner_iterator& x)
+//       requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
+//     friend constexpr difference_type operator-(const inner_iterator& x, default_sentinel_t y)
+//       requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
+
+//   V models forward_range
+//     friend constexpr iterator operator+(const iterator& i, difference_type n)
+//       requires random_access_range<Base>;
+//     friend constexpr iterator operator+(difference_type n, const iterator& i)
+//       requires random_access_range<Base>;
+//     friend constexpr iterator operator-(const iterator& i, difference_type n)
+//       requires random_access_range<Base>;
+//     friend constexpr difference_type operator-(const iterator& x, const iterator& y)
+//       requires sized_sentinel_for<iterator_t<Base>, iterator_t<Base>>;
+//     friend constexpr difference_type operator-(default_sentinel_t y, const iterator& x)
+//       requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>;
+//     friend constexpr difference_type operator-(const iterator& x, default_sentinel_t y)
+//       requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>;
+
+#include <cassert>
+#include <iterator>
+#include <ranges>
+#include <vector>
+
+#include "test_range.h"
+#include "../types.h"
+
+constexpr bool test() {
+  std::vector<int> vector                                                  = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
+  std::ranges::chunk_view<std::ranges::ref_view<std::vector<int>>> chunked = vector | std::views::chunk(3);
+  std::ranges::chunk_view<input_span<int>> input_chunked = input_span<int>(vector) | std::views::chunk(3);
+
+  // Test `friend constexpr difference_type operator-(default_sentinel_t t, const outer_iterator& i)`
+  {
+    assert(std::default_sentinel - input_chunked.begin() == 4);
+  }
+
+  // Test `friend constexpr difference_type operator-(const outer_iterator& i, default_sentinel_t)`
+  {
+    assert(input_chunked.begin() - std::default_sentinel == -4);
+  }
+
+  // Test `friend constexpr difference_type operator-(default_sentinel_t, const inner_iterator& x)`
+  {
+    assert(std::default_sentinel - (*input_chunked.begin()).begin() == 3);
+  }
+
+  // Test `friend constexpr difference_type operator-(const inner_iterator& x, default_sentinel_t)`
+  {
+    assert((*input_chunked.begin()).begin() - std::default_sentinel == -3);
+  }
+
+  // Test `friend constexpr iterator operator+(const iterator& i, difference_type n)`
+  {
+    assert(chunked.begin() + 4 == chunked.end());
+  }
+
+  // Test `friend constexpr iterator operator+(difference_type n, const iterator& i)`
+  {
+    assert(4 + chunked.begin() == chunked.end());
+  }
+
+  // Test `friend constexpr iterator operator-(const iterator& i, difference_type n)`
+  {
+    assert(chunked.end() - 4 == chunked.begin());
+  }
+
+  // Test `friend constexpr difference_type operator-(const iterator& x, const iterator& y)`
+  {
+    assert(chunked.end() - chunked.begin() == 4);
+  }
+
+  // Test `friend constexpr difference_type operator-(default_sentinel_t y, const iterator& x)`
+  {
+    assert(std::default_sentinel - chunked.begin() == 4);
+  }
+
+  // Test `friend constexpr difference_type operator-(const iterator& x, default_sentinel_t y)`
+  {
+    assert(chunked.begin() - std::default_sentinel == -4);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/compare.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/compare.pass.cpp
index d86726d958e6e..ea6731cccce85 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/compare.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/compare.pass.cpp
@@ -11,14 +11,12 @@
 // <ranges>
 
 //   V models only input_range
-//     friend constexpr bool opreator==(const outer_iterator& x, default_sentinel_t);
-//     friend constexpr difference_type operator-(default_sentinel_t t, const outer_iterator& i)
-//       requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
-//     friend constexpr difference_type operator-(const outer_iterator& i, default_sentinel_t t)
-//       requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
+//     friend constexpr bool operator==(const outer_iterator& x, default_sentinel_t);
+//     friend constexpr bool operator==(const inner_iterator& x, default_sentinel_t);
 
 //   V models forward_range
-//     friend constexpr bool operator==(const iterator& x, const iterator& y)
+//     friend constexpr bool operator==(const iterator& x, const iterator& y);
+//     friend constexpr bool operator==(const iterator& x, default_sentinel_t);
 //     friend constexpr bool operator<(const iterator& x, const iterator& y)
 //       requires random_access_range<Base>;
 //     friend constexpr bool operator>(const iterator& x, const iterator& y)
@@ -31,7 +29,6 @@
 //       requires random_access_range<Base> &&
 //                three_way_comparable<iterator_t<Base>>;
 
-#include <algorithm>
 #include <cassert>
 #include <compare>
 #include <iterator>
@@ -53,14 +50,11 @@ constexpr bool test() {
     assert(it == std::default_sentinel);
   }
 
-  // Test `friend constexpr difference_type operator-(default_sentinel_t t, const outer_iterator& i)`
+  // Test `friend constexpr bool operator==(const inner_iterator& x, default_sentinel_t)`
   {
-    assert(input_chunked.end() - input_chunked.begin() == 4);
-  }
-
-  // Test `friend constexpr difference_type operator-(const outer_iterator& i, default_sentinel_t)`
-  {
-    assert(input_chunked.begin() - input_chunked.end() == -4);
+    /*chunk_view::__inner_iterator*/ std::input_iterator auto it = (*input_chunked.begin()).begin();
+    std::ranges::advance(it, 3);
+    assert(it == std::default_sentinel);
   }
 
   // Test `friend constexpr bool operator==(const iterator& x, const iterator& y)`
@@ -69,6 +63,11 @@ constexpr bool test() {
     assert(chunked.end() == chunked.end());
   }
 
+  // Test `friend constexpr bool operator==(const iterator& x, default_sentinel)`
+  {
+    assert(chunked.end() == std::default_sentinel);
+  }
+
   // Test `friend constexpr bool operator<(const iterator& x, const iterator& y)`
   {
     assert(chunked.begin() < chunked.end());
@@ -79,7 +78,7 @@ constexpr bool test() {
     assert(chunked.end() > chunked.begin());
   }
 
-  // Test `friend constexpr bool operator>=(const iterator& x, const iterator& y)`
+  // Test `friend constexpr bool operator<=(const iterator& x, const iterator& y)`
   {
     assert(chunked.begin() <= chunked.begin());
     assert(chunked.begin() <= chunked.end());
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/subscript.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/subscript.pass.cpp
new file mode 100644
index 0000000000000..9b45fc6d779bf
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/subscript.pass.cpp
@@ -0,0 +1,42 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+//   V models forward_range
+//     constexpr value_type iterator::operator[](difference_type n) const
+//       requires random_access_range<Base>;
+
+#include <algorithm>
+#include <cassert>
+#include <iterator>
+#include <ranges>
+#include <vector>
+
+#include "test_range.h"
+
+constexpr bool test() {
+  std::vector<int> vector                                                  = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
+  std::ranges::chunk_view<std::ranges::ref_view<std::vector<int>>> chunked = vector | std::views::chunk(3);
+
+  // Test `constexpr value_type iterator::operator[](difference_type n) const`
+  {
+    assert(std::ranges::equal(chunked.begin()[1], std::vector{4, 5, 6}));
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

>From 033a1c16289990a16b1f674f380f7a72f38f48ea Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Fri, 19 Jun 2026 14:30:08 -0400
Subject: [PATCH 11/43] Fix release notes

---
 libcxx/docs/ReleaseNotes/22.rst    | 1 -
 libcxx/docs/ReleaseNotes/23.rst    | 1 +
 libcxx/docs/Status/Cxx23Papers.csv | 2 +-
 3 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/docs/ReleaseNotes/22.rst b/libcxx/docs/ReleaseNotes/22.rst
index 0637ba98976a2..9f9927095a61f 100644
--- a/libcxx/docs/ReleaseNotes/22.rst
+++ b/libcxx/docs/ReleaseNotes/22.rst
@@ -55,7 +55,6 @@ Implemented Papers
 - P3567R2: ``flat_meow`` Fixes (`Github <https://llvm.org/PR162022>`__)
 - P3836R2: Make ``optional<T&>`` trivially copyable (`Github <https://llvm.org/PR171275>`__)
 - P1789R3: Library Support for Expansion Statements (`Github <https://llvm.org/PR167184>`__)
-- P2442R1: Windowing range adaptors: ``views::chunk`` and ``views::slide`` (`Github <https://llvm.org/PR171234>`__) (Implemented ``views::slide`` only)
 
 Improvements and New Features
 -----------------------------
diff --git a/libcxx/docs/ReleaseNotes/23.rst b/libcxx/docs/ReleaseNotes/23.rst
index e7eb42207db42..a98f42da70f00 100644
--- a/libcxx/docs/ReleaseNotes/23.rst
+++ b/libcxx/docs/ReleaseNotes/23.rst
@@ -52,6 +52,7 @@ Implemented Papers
 - P3383R3: ``mdspan.at()`` (`Github <https://llvm.org/PR175213>`__)
 - P3369R0: constexpr for ``uninitialized_default_construct`` (`Github <https://llvm.org/PR118380>`__)
 - P3508R0: Wording for "constexpr for specialized memory algorithms" (`Github <https://llvm.org/PR118379>`__)
+- P2442R1: Windowing range adaptors: ``views::chunk`` and ``views::slide`` (`Github <https://llvm.org/PR171234>`__) (Implemented ``views::chunk`` only)
 
 Improvements and New Features
 -----------------------------
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index 6abcac5e4ebca..8c92d89be999b 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -48,7 +48,7 @@
 "`P2387R3 <https://wg21.link/P2387R3>`__","Pipe support for user-defined range adaptors","2022-02 (Virtual)","|Complete|","19","`#105183 <https://github.com/llvm/llvm-project/issues/105183>`__",""
 "`P2440R1 <https://wg21.link/P2440R1>`__","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","2022-02 (Virtual)","|Complete|","23","`#105184 <https://github.com/llvm/llvm-project/issues/105184>`__",""
 "`P2441R2 <https://wg21.link/P2441R2>`__","``views::join_with``","2022-02 (Virtual)","|Complete|","21","`#105185 <https://github.com/llvm/llvm-project/issues/105185>`__",""
-"`P2442R1 <https://wg21.link/P2442R1>`__","Windowing range adaptors: ``views::chunk`` and ``views::slide``","2022-02 (Virtual)","|Partial|","22","`#105187 <https://github.com/llvm/llvm-project/issues/105187>`__","Only ``views::chunk`` is implemented."
+"`P2442R1 <https://wg21.link/P2442R1>`__","Windowing range adaptors: ``views::chunk`` and ``views::slide``","2022-02 (Virtual)","|Partial|","","`#105187 <https://github.com/llvm/llvm-project/issues/105187>`__","Only ``views::chunk`` is implemented."
 "`P2443R1 <https://wg21.link/P2443R1>`__","``views::chunk_by``","2022-02 (Virtual)","|Complete|","18","`#105188 <https://github.com/llvm/llvm-project/issues/105188>`__",""
 "","","","","","",""
 "`P0009R18 <https://wg21.link/P0009R18>`__","mdspan: A Non-Owning Multidimensional Array Reference","2022-07 (Virtual)","|Complete|","18","`#105189 <https://github.com/llvm/llvm-project/issues/105189>`__",""

>From 7fe126d5e7c88787f26228c64bcb5f89977c5b83 Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sun, 21 Jun 2026 15:02:10 +0800
Subject: [PATCH 12/43] Resolve overload conflicts on `__div_ceil` in
 `ranges::chunk_view` and `ranges::stride_view`.

Both `ranges::chunk_view` and `ranges::stride_view` need a helper function called `__div_ceil` that solves some simple maths. According to the style of other libcxx internal helper functions (e.g. `__priority_tag`, `__small_buffer`), it seems that we can put `__div_ceil` into a new file `__utility/div_ceil.h`. However, most files in `__utility/` refer to a corresponding symbol in `<utility>` header, so that if someone feels this is not proper, I'll be glad to revert it.
---
 libcxx/include/CMakeLists.txt         |  1 +
 libcxx/include/__ranges/chunk_view.h  | 21 ++++++-----------
 libcxx/include/__ranges/stride_view.h | 20 +++++-----------
 libcxx/include/__utility/div_ceil.h   | 33 +++++++++++++++++++++++++++
 libcxx/include/module.modulemap.in    |  1 +
 5 files changed, 48 insertions(+), 28 deletions(-)
 create mode 100644 libcxx/include/__utility/div_ceil.h

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 76b93c17c3312..0e9f19a81b1ab 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -935,6 +935,7 @@ set(files
   __utility/convert_to_integral.h
   __utility/declval.h
   __utility/default_three_way_comparator.h
+  __utility/div_ceil.h
   __utility/element_count.h
   __utility/empty.h
   __utility/exception_guard.h
diff --git a/libcxx/include/__ranges/chunk_view.h b/libcxx/include/__ranges/chunk_view.h
index 683b6bbaa2ca5..68d4408295e47 100644
--- a/libcxx/include/__ranges/chunk_view.h
+++ b/libcxx/include/__ranges/chunk_view.h
@@ -36,6 +36,7 @@
 #include <__type_traits/decay.h>
 #include <__type_traits/is_nothrow_constructible.h>
 #include <__type_traits/make_unsigned.h>
+#include <__utility/div_ceil.h>
 #include <__utility/forward.h>
 #include <__utility/move.h>
 
@@ -52,14 +53,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 namespace ranges {
 
-template <class _Integral>
-[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto __div_ceil(_Integral __num, _Integral __denom) {
-  _Integral __r = __num / __denom;
-  if (__num % __denom)
-    ++__r;
-  return __r;
-}
-
 template <view _View>
   requires input_range<_View>
 class chunk_view : public view_interface<chunk_view<_View>> {
@@ -98,13 +91,13 @@ class chunk_view : public view_interface<chunk_view<_View>> {
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size()
     requires sized_range<_View>
   {
-    return std::__to_unsigned_like(ranges::__div_ceil(ranges::distance(__base_), __n_));
+    return std::__to_unsigned_like(__div_ceil(ranges::distance(__base_), __n_));
   }
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
     requires sized_range<const _View>
   {
-    return std::__to_unsigned_like(ranges::__div_ceil(ranges::distance(__base_), __n_));
+    return std::__to_unsigned_like(__div_ceil(ranges::distance(__base_), __n_));
   }
 };
 
@@ -153,7 +146,7 @@ class chunk_view<_View>::__outer_iterator {
     const auto __dist = ranges::end(__i.__parent_->__base_) - *__i.__parent_->__current_;
     if (__dist < __i.__parent_->__remainder_)
       return __dist == 0 ? 0 : 1;
-    return ranges::__div_ceil(__dist - __i.__parent_->__remainder_, __i.__parent_->__n_) + 1;
+    return __div_ceil(__dist - __i.__parent_->__remainder_, __i.__parent_->__n_) + 1;
   }
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
@@ -321,13 +314,13 @@ class chunk_view<_View> : public view_interface<chunk_view<_View>> {
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size()
     requires sized_range<_View>
   {
-    return std::__to_unsigned_like(ranges::__div_ceil(ranges::distance(__base_), __n_));
+    return std::__to_unsigned_like(__div_ceil(ranges::distance(__base_), __n_));
   }
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
     requires sized_range<const _View>
   {
-    return std::__to_unsigned_like(ranges::__div_ceil(ranges::distance(__base_), __n_));
+    return std::__to_unsigned_like(__div_ceil(ranges::distance(__base_), __n_));
   }
 };
 
@@ -510,7 +503,7 @@ class chunk_view<_View>::__iterator {
   operator-(default_sentinel_t, const __iterator& __i)
     requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>>
   {
-    return ranges::__div_ceil(__i.__end_ - __i.__current_, __i.__n_);
+    return __div_ceil(__i.__end_ - __i.__current_, __i.__n_);
   }
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
diff --git a/libcxx/include/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h
index 780bb25743c15..7ea68b13330c3 100644
--- a/libcxx/include/__ranges/stride_view.h
+++ b/libcxx/include/__ranges/stride_view.h
@@ -32,6 +32,7 @@
 #include <__ranges/range_adaptor.h>
 #include <__ranges/view_interface.h>
 #include <__type_traits/make_unsigned.h>
+#include <__utility/div_ceil.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -46,15 +47,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 namespace ranges {
 
-template <class _Value>
-_LIBCPP_HIDE_FROM_ABI constexpr _Value __div_ceil(_Value __left, _Value __right) {
-  _Value __r = __left / __right;
-  if (__left % __right) {
-    ++__r;
-  }
-  return __r;
-}
-
 template <input_range _View>
   requires view<_View>
 class stride_view : public view_interface<stride_view<_View>> {
@@ -121,13 +113,13 @@ class stride_view : public view_interface<stride_view<_View>> {
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size()
     requires sized_range<_View>
   {
-    return std::__to_unsigned_like(ranges::__div_ceil(ranges::distance(__base_), __stride_));
+    return std::__to_unsigned_like(__div_ceil(ranges::distance(__base_), __stride_));
   }
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
     requires sized_range<const _View>
   {
-    return std::__to_unsigned_like(ranges::__div_ceil(ranges::distance(__base_), __stride_));
+    return std::__to_unsigned_like(__div_ceil(ranges::distance(__base_), __stride_));
   }
 }; // class stride_view
 
@@ -340,16 +332,16 @@ class stride_view<_View>::__iterator : public __stride_iterator_category<__maybe
     }
     auto __n = __x.__current_ - __y.__current_;
     if (__n < 0) {
-      return -ranges::__div_ceil(-__n, __x.__stride_);
+      return -__div_ceil(-__n, __x.__stride_);
     }
-    return ranges::__div_ceil(__n, __x.__stride_);
+    return __div_ceil(__n, __x.__stride_);
   }
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
   operator-(default_sentinel_t, __iterator const& __x)
     requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>>
   {
-    return ranges::__div_ceil(__x.__end_ - __x.__current_, __x.__stride_);
+    return __div_ceil(__x.__end_ - __x.__current_, __x.__stride_);
   }
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
   operator-(__iterator const& __x, default_sentinel_t __y)
diff --git a/libcxx/include/__utility/div_ceil.h b/libcxx/include/__utility/div_ceil.h
new file mode 100644
index 0000000000000..595c590b9e3f6
--- /dev/null
+++ b/libcxx/include/__utility/div_ceil.h
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___UTILITY_DIV_CEIL_H
+#define _LIBCPP___UTILITY_DIV_CEIL_H
+
+#include <__config>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+// __div_ceil computes the ceiling of the division of two integers. It is mainly used by
+// range adaptors like chunk_view and stride_view.
+
+template <class _Integral>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto __div_ceil(_Integral __num, _Integral __denom) {
+  _Integral __r = __num / __denom;
+  if (__num % __denom)
+    ++__r;
+  return __r;
+}
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___UTILITY_DIV_CEIL_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 64238440b9dd7..ef5d15d063f69 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -2200,6 +2200,7 @@ module std [system] {
     module constant_wrapper                { header "__utility/constant_wrapper.h" }
     module convert_to_integral             { header "__utility/convert_to_integral.h" }
     module default_three_way_comparator    { header "__utility/default_three_way_comparator.h" }
+    module div_ceil                        { header "__utility/div_ceil.h" }
     module element_count                   { header "__utility/element_count.h" }
     module exception_guard                 { header "__utility/exception_guard.h" }
     module exchange                        { header "__utility/exchange.h" }

>From d27b355e67e17b0ed15d44a247fdba1c3b13ed49 Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sun, 21 Jun 2026 15:22:38 +0800
Subject: [PATCH 13/43] Fix test error that `constexpr` is not supported in
 `-std=c++03`

---
 libcxx/include/__utility/div_ceil.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/libcxx/include/__utility/div_ceil.h b/libcxx/include/__utility/div_ceil.h
index 595c590b9e3f6..4d2868465c141 100644
--- a/libcxx/include/__utility/div_ceil.h
+++ b/libcxx/include/__utility/div_ceil.h
@@ -17,6 +17,8 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
+#if _LIBCPP_STD_VER >= 11
+
 // __div_ceil computes the ceiling of the division of two integers. It is mainly used by
 // range adaptors like chunk_view and stride_view.
 
@@ -28,6 +30,8 @@ template <class _Integral>
   return __r;
 }
 
+#endif
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP___UTILITY_DIV_CEIL_H

>From a1a5918bb79d29cbe7be2736da7a72b83ee0afbb Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sun, 21 Jun 2026 15:38:37 +0800
Subject: [PATCH 14/43] Fix test error again that `constexpr` is not supported
 in `-std=c++11`

---
 libcxx/include/__utility/div_ceil.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__utility/div_ceil.h b/libcxx/include/__utility/div_ceil.h
index 4d2868465c141..21e9bcb30d1a1 100644
--- a/libcxx/include/__utility/div_ceil.h
+++ b/libcxx/include/__utility/div_ceil.h
@@ -17,7 +17,7 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-#if _LIBCPP_STD_VER >= 11
+#if _LIBCPP_STD_VER >= 23
 
 // __div_ceil computes the ceiling of the division of two integers. It is mainly used by
 // range adaptors like chunk_view and stride_view.
@@ -30,7 +30,7 @@ template <class _Integral>
   return __r;
 }
 
-#endif
+#endif // _LIBCPP_STD_VER >= 23
 
 _LIBCPP_END_NAMESPACE_STD
 

>From c2e0e2e926c92ee6d001e060aa5660b681874dfd Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sun, 21 Jun 2026 15:45:41 +0800
Subject: [PATCH 15/43] Fix test error that `std::as_const` is included from
 `<utility>`.

---
 libcxx/test/std/ranges/range.adaptors/range.chunk/begin.pass.cpp | 1 +
 libcxx/test/std/ranges/range.adaptors/range.chunk/end.pass.cpp   | 1 +
 2 files changed, 2 insertions(+)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/begin.pass.cpp
index 3cccd7d1bebc6..29588a57fbcab 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/begin.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/begin.pass.cpp
@@ -22,6 +22,7 @@
 #include <iterator>
 #include <ranges>
 #include <vector>
+#include <utility>
 
 #include "test_range.h"
 #include "types.h"
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/end.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/end.pass.cpp
index 73eb0d967f6a2..2f37ac5f73524 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/end.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/end.pass.cpp
@@ -23,6 +23,7 @@
 #include <iterator>
 #include <ranges>
 #include <vector>
+#include <utility>
 
 #include "test_range.h"
 #include "types.h"

>From 7d3cdd73f5da77a7499969fb7954312a19e26630 Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Thu, 25 Jun 2026 14:19:19 +0800
Subject: [PATCH 16/43] Avoid ADL in `std::__div_ceil`.

---
 libcxx/include/__ranges/chunk_view.h  | 12 ++++++------
 libcxx/include/__ranges/stride_view.h | 10 +++++-----
 2 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/libcxx/include/__ranges/chunk_view.h b/libcxx/include/__ranges/chunk_view.h
index 68d4408295e47..1107a9238b2bc 100644
--- a/libcxx/include/__ranges/chunk_view.h
+++ b/libcxx/include/__ranges/chunk_view.h
@@ -91,13 +91,13 @@ class chunk_view : public view_interface<chunk_view<_View>> {
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size()
     requires sized_range<_View>
   {
-    return std::__to_unsigned_like(__div_ceil(ranges::distance(__base_), __n_));
+    return std::__to_unsigned_like(std::__div_ceil(ranges::distance(__base_), __n_));
   }
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
     requires sized_range<const _View>
   {
-    return std::__to_unsigned_like(__div_ceil(ranges::distance(__base_), __n_));
+    return std::__to_unsigned_like(std::__div_ceil(ranges::distance(__base_), __n_));
   }
 };
 
@@ -146,7 +146,7 @@ class chunk_view<_View>::__outer_iterator {
     const auto __dist = ranges::end(__i.__parent_->__base_) - *__i.__parent_->__current_;
     if (__dist < __i.__parent_->__remainder_)
       return __dist == 0 ? 0 : 1;
-    return __div_ceil(__dist - __i.__parent_->__remainder_, __i.__parent_->__n_) + 1;
+    return std::__div_ceil(__dist - __i.__parent_->__remainder_, __i.__parent_->__n_) + 1;
   }
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
@@ -314,13 +314,13 @@ class chunk_view<_View> : public view_interface<chunk_view<_View>> {
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size()
     requires sized_range<_View>
   {
-    return std::__to_unsigned_like(__div_ceil(ranges::distance(__base_), __n_));
+    return std::__to_unsigned_like(std::__div_ceil(ranges::distance(__base_), __n_));
   }
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
     requires sized_range<const _View>
   {
-    return std::__to_unsigned_like(__div_ceil(ranges::distance(__base_), __n_));
+    return std::__to_unsigned_like(std::__div_ceil(ranges::distance(__base_), __n_));
   }
 };
 
@@ -503,7 +503,7 @@ class chunk_view<_View>::__iterator {
   operator-(default_sentinel_t, const __iterator& __i)
     requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>>
   {
-    return __div_ceil(__i.__end_ - __i.__current_, __i.__n_);
+    return std::__div_ceil(__i.__end_ - __i.__current_, __i.__n_);
   }
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
diff --git a/libcxx/include/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h
index 7ea68b13330c3..a8b485cbe33e5 100644
--- a/libcxx/include/__ranges/stride_view.h
+++ b/libcxx/include/__ranges/stride_view.h
@@ -113,13 +113,13 @@ class stride_view : public view_interface<stride_view<_View>> {
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size()
     requires sized_range<_View>
   {
-    return std::__to_unsigned_like(__div_ceil(ranges::distance(__base_), __stride_));
+    return std::__to_unsigned_like(std::__div_ceil(ranges::distance(__base_), __stride_));
   }
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
     requires sized_range<const _View>
   {
-    return std::__to_unsigned_like(__div_ceil(ranges::distance(__base_), __stride_));
+    return std::__to_unsigned_like(std::__div_ceil(ranges::distance(__base_), __stride_));
   }
 }; // class stride_view
 
@@ -332,16 +332,16 @@ class stride_view<_View>::__iterator : public __stride_iterator_category<__maybe
     }
     auto __n = __x.__current_ - __y.__current_;
     if (__n < 0) {
-      return -__div_ceil(-__n, __x.__stride_);
+      return -std::__div_ceil(-__n, __x.__stride_);
     }
-    return __div_ceil(__n, __x.__stride_);
+    return std::__div_ceil(__n, __x.__stride_);
   }
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
   operator-(default_sentinel_t, __iterator const& __x)
     requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>>
   {
-    return __div_ceil(__x.__end_ - __x.__current_, __x.__stride_);
+    return std::__div_ceil(__x.__end_ - __x.__current_, __x.__stride_);
   }
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
   operator-(__iterator const& __x, default_sentinel_t __y)

>From 116c6d85d8a9ad177b1df1975eea92479cb03664 Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Thu, 25 Jun 2026 16:39:58 +0800
Subject: [PATCH 17/43] [Important] Add missing concepts requirements.

---
 libcxx/include/__ranges/chunk_view.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/libcxx/include/__ranges/chunk_view.h b/libcxx/include/__ranges/chunk_view.h
index 1107a9238b2bc..47e6bd56415b6 100644
--- a/libcxx/include/__ranges/chunk_view.h
+++ b/libcxx/include/__ranges/chunk_view.h
@@ -400,7 +400,8 @@ class chunk_view<_View>::__iterator {
     return *this;
   }
 
-  _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator--(int) {
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator--(int)
+    requires bidirectional_range<_Base> {
     auto __tmp = *this;
     --*this;
     return __tmp;

>From 545bbdf10d24c3790790bfe669b8c756da719838 Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Fri, 26 Jun 2026 22:35:12 +0800
Subject: [PATCH 18/43] Cover tests on `chunk_range`. (I'll continue to cover
 tests on `__iterator`, `__inner_iterator` and `__outer_iterator` at the
 weekend)

---
 libcxx/include/__ranges/chunk_view.h          |  3 +-
 .../range.adaptors/range.chunk/base.pass.cpp  | 12 +++-
 .../range.chunk/borrowing.compile.pass.cpp    | 27 +++++++
 .../range.adaptors/range.chunk/ctor.pass.cpp  | 54 ++++++++++++++
 .../range.adaptors/range.chunk/size.pass.cpp  | 72 +++++++++++++++++++
 5 files changed, 166 insertions(+), 2 deletions(-)
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/borrowing.compile.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/ctor.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/size.pass.cpp

diff --git a/libcxx/include/__ranges/chunk_view.h b/libcxx/include/__ranges/chunk_view.h
index 47e6bd56415b6..1798711eabd16 100644
--- a/libcxx/include/__ranges/chunk_view.h
+++ b/libcxx/include/__ranges/chunk_view.h
@@ -401,7 +401,8 @@ class chunk_view<_View>::__iterator {
   }
 
   _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator--(int)
-    requires bidirectional_range<_Base> {
+    requires bidirectional_range<_Base>
+  {
     auto __tmp = *this;
     --*this;
     return __tmp;
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/base.pass.cpp
index b45e1f59f1394..4dca324a23695 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/base.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/base.pass.cpp
@@ -26,7 +26,7 @@ constexpr bool test() {
   std::ranges::chunk_view<std::ranges::ref_view<const std::array<int, 8>>> const_chunked =
       std::as_const(array) | std::views::chunk(4);
 
-  // Test `chunk_view.base()`
+  // Test `chunk_view.base() const&`
   {
     std::same_as<std::array<int, 8>&> decltype(auto) base = chunked.base().base();
     assert(std::addressof(base) == std::addressof(array));
@@ -35,6 +35,16 @@ constexpr bool test() {
     assert(std::addressof(const_base) == std::addressof(array));
   }
 
+  // Test `chunk_view.base() &&`
+  {
+    std::same_as<std::ranges::ref_view<std::array<int, 8>>> decltype(auto) moved = std::move(chunked).base();
+    assert(std::addressof(moved.base()) == std::addressof(array));
+
+    std::same_as<std::ranges::ref_view<const std::array<int, 8>>> decltype(auto) const_moved =
+        std::move(const_chunked).base();
+    assert(std::addressof(const_moved.base()) == std::addressof(array));
+  }
+
   return true;
 }
 
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/borrowing.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/borrowing.compile.pass.cpp
new file mode 100644
index 0000000000000..1eb4a34f87217
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/borrowing.compile.pass.cpp
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+//   template <class V>
+//   inline constexpr bool enable_borrowed_range<chunk_view<V>> =
+//       forward_range<V> && enable_borrowed_range<V>;
+
+#include <ranges>
+
+#include "test_range.h"
+#include "types.h"
+
+// When V models only `input_range`.
+static_assert(!std::ranges::enable_borrowed_range<std::ranges::chunk_view<input_span<int>>>);
+
+// When V models at least `forward_range`.
+static_assert(std::ranges::enable_borrowed_range<std::ranges::chunk_view<BorrowedView>>);
+static_assert(!std::ranges::enable_borrowed_range<std::ranges::chunk_view<NonBorrowedView>>);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/ctor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/ctor.pass.cpp
new file mode 100644
index 0000000000000..b60e040b807eb
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/ctor.pass.cpp
@@ -0,0 +1,54 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+//   constexpr explicit chunk_view(_View __base, range_difference_t<_View> __n);
+
+#include <algorithm>
+#include <cassert>
+#include <ranges>
+#include <utility>
+#include <vector>
+
+#include "test_convertible.h"
+#include "test_range.h"
+#include "types.h"
+
+constexpr bool test() {
+  std::vector<int> vector = {1, 2, 3, 4, 5, 6, 7, 8};
+
+  // Test `chunk_view(_View, range_difference_t<_View>)` when V models only `input_range`
+  {
+    static_assert(!test_convertible<std::ranges::chunk_view<input_span<int>>, input_span<int>, std::ptrdiff_t>());
+
+    std::ranges::chunk_view<input_span<int>> chunked(input_span(vector.data(), 8), 3);
+    assert(std::ranges::equal(*chunked.begin(), std::vector{1, 2, 3}));
+  }
+
+  // Test `chunk_view(_View, range_difference_t<_View>)` when V models `forward_range`
+  {
+    static_assert(!test_convertible<std::ranges::chunk_view<input_span<int>>,
+                                    std::ranges::ref_view<std::vector<int>>,
+                                    std::ptrdiff_t>());
+
+    std::ranges::chunk_view<input_span<int>> chunked(std::ranges::ref_view(vector), 3);
+    assert(std::ranges::equal(*chunked.begin(), std::vector{1, 2, 3}));
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/size.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/size.pass.cpp
new file mode 100644
index 0000000000000..820774c3b750e
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/size.pass.cpp
@@ -0,0 +1,72 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+//   constexpr auto size() requires sized_range<_View>;
+//   constexpr auto size() const requires sized_range<const _View>;
+
+#include <cassert>
+#include <ranges>
+
+#include "test_range.h"
+#include "types.h"
+
+constexpr bool test() {
+  int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
+
+  // Test `chunk_view.size()` when V models only `input_range`
+  {
+    static_assert(std::ranges::sized_range<std::ranges::chunk_view<input_span<int>>>);
+    static_assert(!std::ranges::sized_range<const std::ranges::chunk_view<input_span<int>>>);
+
+    auto chunked = input_span<int>(arr, 12) | std::views::chunk(3);
+    assert(chunked.size() == 4);
+  }
+
+  // Test `chunk_view.size()` when V models `forward_range`
+  {
+    static_assert(std::ranges::sized_range<std::ranges::chunk_view<std::ranges::ref_view<int[12]>>>);
+    static_assert(std::ranges::sized_range<const std::ranges::chunk_view<std::ranges::ref_view<int[12]>>>);
+
+    auto chunked = std::ranges::ref_view(arr) | std::views::chunk(3);
+    assert(chunked.size() == 4);
+    const auto& const_chunked = chunked;
+    assert(const_chunked.size() == 4);
+  }
+
+  // Test `chunk_view.size()` when the range is not fully divisible
+  {
+    auto chunked = std::ranges::ref_view(arr) | std::views::chunk(5);
+    assert(chunked.size() == 3);
+  }
+
+  // Test `chunk_view.size()` when the range is empty
+  {
+    static_assert(std::ranges::sized_range<std::ranges::empty_view<int>>);
+    auto chunked = std::views::empty<int> | std::views::chunk(3);
+    assert(chunked.size() == 0);
+  }
+
+  // Test `chunk_view.size()` when chunk size is larger than the range
+  {
+    auto chunked = std::ranges::ref_view(arr) | std::views::chunk(100);
+    assert(chunked.size() == 1);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

>From e262f9e7497fb3ccf232a3c7265b8faa83f2fa20 Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sun, 19 Jul 2026 22:36:04 +0800
Subject: [PATCH 19/43] Fix chunk_view ctor test for forward ranges.

---
 .../test/std/ranges/range.adaptors/range.chunk/ctor.pass.cpp  | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/ctor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/ctor.pass.cpp
index b60e040b807eb..c0d210aa45dc3 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/ctor.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/ctor.pass.cpp
@@ -35,11 +35,11 @@ constexpr bool test() {
 
   // Test `chunk_view(_View, range_difference_t<_View>)` when V models `forward_range`
   {
-    static_assert(!test_convertible<std::ranges::chunk_view<input_span<int>>,
+    static_assert(!test_convertible<std::ranges::chunk_view<std::ranges::ref_view<std::vector<int>>>,
                                     std::ranges::ref_view<std::vector<int>>,
                                     std::ptrdiff_t>());
 
-    std::ranges::chunk_view<input_span<int>> chunked(std::ranges::ref_view(vector), 3);
+    std::ranges::chunk_view<std::ranges::ref_view<std::vector<int>>> chunked(std::ranges::ref_view(vector), 3);
     assert(std::ranges::equal(*chunked.begin(), std::vector{1, 2, 3}));
   }
 

>From bf13c55de976c562120249f2fc7208ea1091fc95 Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sun, 19 Jul 2026 22:39:36 +0800
Subject: [PATCH 20/43] Use consistent copy_constructible spelling in
 chunk_view

---
 libcxx/include/__ranges/chunk_view.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/include/__ranges/chunk_view.h b/libcxx/include/__ranges/chunk_view.h
index 1798711eabd16..f3edc617de07a 100644
--- a/libcxx/include/__ranges/chunk_view.h
+++ b/libcxx/include/__ranges/chunk_view.h
@@ -71,7 +71,7 @@ class chunk_view : public view_interface<chunk_view<_View>> {
   }
 
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() const&
-    requires std::copy_constructible<_View>
+    requires copy_constructible<_View>
   {
     return __base_;
   }

>From f457f267b72fe64a2f22c288da4b096ae0bcc83c Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sun, 19 Jul 2026 22:48:59 +0800
Subject: [PATCH 21/43] Remove unnecessary no_unique_address from chunk_view
 counts

---
 libcxx/include/__ranges/chunk_view.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/libcxx/include/__ranges/chunk_view.h b/libcxx/include/__ranges/chunk_view.h
index f3edc617de07a..4478af951dbca 100644
--- a/libcxx/include/__ranges/chunk_view.h
+++ b/libcxx/include/__ranges/chunk_view.h
@@ -57,8 +57,8 @@ template <view _View>
   requires input_range<_View>
 class chunk_view : public view_interface<chunk_view<_View>> {
   _LIBCPP_NO_UNIQUE_ADDRESS _View __base_;
-  _LIBCPP_NO_UNIQUE_ADDRESS range_difference_t<_View> __n_;
-  _LIBCPP_NO_UNIQUE_ADDRESS range_difference_t<_View> __remainder_;
+  range_difference_t<_View> __n_;
+  range_difference_t<_View> __remainder_;
   _LIBCPP_NO_UNIQUE_ADDRESS __non_propagating_cache<iterator_t<_View>> __current_;
 
   class __outer_iterator;
@@ -256,7 +256,7 @@ template <view _View>
   requires forward_range<_View>
 class chunk_view<_View> : public view_interface<chunk_view<_View>> {
   _LIBCPP_NO_UNIQUE_ADDRESS _View __base_;
-  _LIBCPP_NO_UNIQUE_ADDRESS range_difference_t<_View> __n_;
+  range_difference_t<_View> __n_;
 
   template <bool _Const>
   class __iterator;

>From 39c371e116736dd37006c3cf48ed9cf9412b1222 Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sun, 19 Jul 2026 23:25:01 +0800
Subject: [PATCH 22/43] Fix chunk_view inner iter_move return type (from T into
 T&&)

---
 libcxx/include/__ranges/chunk_view.h          |  2 +-
 .../range.chunk.inner.iter/iter_move.pass.cpp | 43 +++++++++++++++++++
 2 files changed, 44 insertions(+), 1 deletion(-)
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/iter_move.pass.cpp

diff --git a/libcxx/include/__ranges/chunk_view.h b/libcxx/include/__ranges/chunk_view.h
index 4478af951dbca..e9511f027160a 100644
--- a/libcxx/include/__ranges/chunk_view.h
+++ b/libcxx/include/__ranges/chunk_view.h
@@ -238,7 +238,7 @@ class chunk_view<_View>::__inner_iterator {
     return -(__s - __i);
   }
 
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr range_rvalue_reference_t<_View>
   iter_move(const __inner_iterator& __i) noexcept(noexcept(ranges::iter_move(*__i.__parent_->__current_))) {
     return ranges::iter_move(*__i.__parent_->__current_);
   }
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/iter_move.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/iter_move.pass.cpp
new file mode 100644
index 0000000000000..5c7b620924c2f
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/iter_move.pass.cpp
@@ -0,0 +1,43 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+// V models only input_range:
+//   friend constexpr range_rvalue_reference_t<V> iter_move(const inner_iterator& i)
+//     noexcept(noexcept(ranges::iter_move(i.parent_->current_.value())));
+
+#include <concepts>
+#include <ranges>
+#include <utility>
+
+#include "test_iterators.h"
+#include "test_range.h"
+
+constexpr bool test() {
+  using InnerIterator =
+      std::ranges::iterator_t<std::ranges::range_reference_t<std::ranges::chunk_view<test_view<cpp20_input_iterator>>>>;
+
+  static_assert(std::ranges::input_range<test_view<cpp20_input_iterator>>);
+  static_assert(!std::ranges::forward_range<test_view<cpp20_input_iterator>>);
+
+  static_assert(std::same_as<decltype(std::ranges::iter_move(std::declval<const InnerIterator&>())), int&&>);
+  static_assert(std::same_as<decltype(std::ranges::iter_move(std::declval<const InnerIterator&>())),
+                             std::ranges::range_rvalue_reference_t<test_view<cpp20_input_iterator>>>);
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
\ No newline at end of file

>From c1a0811d8824267ff40fa442b2c2ad10d95b7690 Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Mon, 20 Jul 2026 00:13:15 +0800
Subject: [PATCH 23/43] Add chunk_view constraint tests

---
 .../range.chunk/concept.compile.pass.cpp      | 64 +++++++++++++++++++
 1 file changed, 64 insertions(+)
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/concept.compile.pass.cpp

diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/concept.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/concept.compile.pass.cpp
new file mode 100644
index 0000000000000..61b89d4c09c32
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/concept.compile.pass.cpp
@@ -0,0 +1,64 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+//   template <view V>
+//     requires input_range<V>
+//   class chunk_view;
+//
+//   template <view V>
+//     requires forward_range<V>
+//   class chunk_view<_View>;
+
+#include <ranges>
+#include <utility>
+
+#include "almost_satisfies_types.h"
+#include "test_range.h"
+#include "types.h"
+
+template <>
+inline constexpr bool std::ranges::enable_view<InputRangeNotDerivedFrom> = true;
+
+// Test two separate properties:
+// 1. Whether `chunk_view<View>` can be formed.
+// 2. Whether a well-formed `chunk_view<View>` can be constructed.
+template <class View>
+concept CanFormChunkView = requires { typename std::ranges::chunk_view<View>; };
+
+template <class View>
+concept CanConstructChunkView = CanFormChunkView<View> && requires(View view, std::ranges::range_difference_t<View> n) {
+  std::ranges::chunk_view<View>(std::move(view), n);
+};
+
+// Test constraints when the template argument is not a view
+static_assert(!std::ranges::view<test_non_const_range<cpp17_input_iterator>>);
+static_assert(std::ranges::input_range<test_non_const_range<cpp17_input_iterator>>);
+static_assert(!CanFormChunkView<test_non_const_range<cpp17_input_iterator>>);
+
+// Test constraints when the template argument is not an input_range
+static_assert(!std::ranges::input_range<InputRangeNotDerivedFrom>);
+static_assert(std::ranges::view<InputRangeNotDerivedFrom>);
+static_assert(!CanFormChunkView<InputRangeNotDerivedFrom>);
+
+// Test constraints when the template argument is an input_range and a view
+static_assert(std::ranges::input_range<input_span<int>>);
+static_assert(std::ranges::view<input_span<int>>);
+static_assert(CanFormChunkView<input_span<int>> && CanConstructChunkView<input_span<int>>);
+
+// Test constraints when the template argument is a forward_range and a view
+static_assert(std::ranges::forward_range<BorrowedView>);
+static_assert(std::ranges::view<BorrowedView>);
+static_assert(CanFormChunkView<BorrowedView> && CanConstructChunkView<BorrowedView>);
+
+// chunk_view itself models view
+static_assert(std::ranges::view<std::ranges::chunk_view<input_span<int>>>);
+static_assert(std::ranges::view<std::ranges::chunk_view<BorrowedView>>);

>From 8085a1d3bf45b122557796308e767016f9f7e784 Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Mon, 20 Jul 2026 00:13:26 +0800
Subject: [PATCH 24/43] Add chunk_view iterator type tests

---
 .../types.compile.pass.cpp                    | 30 ++++++++++
 .../range.chunk.iter/types.compile.pass.cpp   | 57 +++++++++++++++++++
 .../types.compile.pass.cpp                    | 31 ++++++++++
 3 files changed, 118 insertions(+)
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/types.compile.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/types.compile.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/types.compile.pass.cpp

diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/types.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/types.compile.pass.cpp
new file mode 100644
index 0000000000000..1775a08f84a2f
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/types.compile.pass.cpp
@@ -0,0 +1,30 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+// V models only input_range:
+//   class inner_iterator;
+
+//   using inner_iterator::iterator_concept = input_iterator_tag;
+//   using inner_iterator::difference_type = range_difference_t<V>;
+//   using inner_iterator::value_type = range_value_t<V>;
+
+#include <concepts>
+#include <iterator>
+#include <ranges>
+
+#include "../types.h"
+
+using InnerIterator = std::ranges::iterator_t<std::ranges::range_reference_t<std::ranges::chunk_view<input_span<int>>>>;
+
+static_assert(std::same_as<typename InnerIterator::iterator_concept, std::input_iterator_tag>);
+static_assert(std::same_as<typename InnerIterator::difference_type, std::ranges::range_difference_t<input_span<int>>>);
+static_assert(std::same_as<typename InnerIterator::value_type, std::ranges::range_value_t<input_span<int>>>);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/types.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/types.compile.pass.cpp
new file mode 100644
index 0000000000000..96e3057edc04a
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/types.compile.pass.cpp
@@ -0,0 +1,57 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+// V models forward_range:
+//   class iterator;
+
+//   using iterator::iterator_category = input_iterator_tag;
+//   using iterator::iterator_concept = see below;
+//   using iterator::value_type = decltype(views::take(subrange(current_, end_), n_));
+//   using iterator::difference_type = range_difference_t<Base>;
+
+#include <concepts>
+#include <iterator>
+#include <ranges>
+
+#include "test_iterators.h"
+#include "test_range.h"
+
+template <template <class...> class Iter>
+using ChunkViewFor = std::ranges::chunk_view<test_view<Iter>>;
+
+template <template <class...> class Iter>
+using ChunkIteratorFor = std::ranges::iterator_t<ChunkViewFor<Iter>>;
+
+template <template <class...> class Iter>
+constexpr void test_iterator_types() {
+  using ChunkView     = ChunkViewFor<Iter>;
+  using ChunkIterator = ChunkIteratorFor<Iter>;
+
+  static_assert(std::same_as<typename ChunkIterator::iterator_category, std::input_iterator_tag>);
+  static_assert(std::same_as<typename ChunkIterator::value_type, std::ranges::range_value_t<ChunkView>>);
+  static_assert(std::same_as<typename ChunkIterator::difference_type, std::ranges::range_difference_t<test_view<Iter>>>);
+}
+
+constexpr void test() {
+  test_iterator_types<forward_iterator>();
+  test_iterator_types<bidirectional_iterator>();
+  test_iterator_types<random_access_iterator>();
+  test_iterator_types<contiguous_iterator>();
+
+  static_assert(std::same_as<ChunkIteratorFor<forward_iterator>::iterator_concept, std::forward_iterator_tag>);
+  static_assert(std::same_as<ChunkIteratorFor<bidirectional_iterator>::iterator_concept,
+                             std::bidirectional_iterator_tag>);
+  static_assert(std::same_as<ChunkIteratorFor<random_access_iterator>::iterator_concept,
+                             std::random_access_iterator_tag>);
+  static_assert(std::same_as<ChunkIteratorFor<contiguous_iterator>::iterator_concept,
+                             std::random_access_iterator_tag>);
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/types.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/types.compile.pass.cpp
new file mode 100644
index 0000000000000..9127e567305ce
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/types.compile.pass.cpp
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+// V models only input_range:
+//   class outer_iterator;
+
+//   using outer_iterator::iterator_concept = input_iterator_tag;
+//   using outer_iterator::difference_type = range_difference_t<V>;
+//   class outer_iterator::value_type;
+
+#include <concepts>
+#include <iterator>
+#include <ranges>
+
+#include "../types.h"
+
+using OuterIterator = std::ranges::iterator_t<std::ranges::chunk_view<input_span<int>>>;
+
+static_assert(std::same_as<typename OuterIterator::iterator_concept, std::input_iterator_tag>);
+static_assert(std::same_as<typename OuterIterator::difference_type, std::ranges::range_difference_t<input_span<int>>>);
+static_assert(std::same_as<typename OuterIterator::value_type, std::iter_value_t<OuterIterator>>);
+static_assert(std::ranges::input_range<typename OuterIterator::value_type>);

>From 48bf130465c89823e4c9817180cfa15434057466 Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sat, 25 Jul 2026 15:22:10 +0800
Subject: [PATCH 25/43] Add chunk_view inner iterator special member tests

---
 .../ctor.compile.pass.cpp                     | 28 +++++++++++++++++++
 1 file changed, 28 insertions(+)
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/ctor.compile.pass.cpp

diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/ctor.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/ctor.compile.pass.cpp
new file mode 100644
index 0000000000000..ec2e68cb0c8ca
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/ctor.compile.pass.cpp
@@ -0,0 +1,28 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+// V models only input_range:
+//   inner_iterator(inner_iterator&&) = default;
+//   inner_iterator& operator=(inner_iterator&&) = default;
+
+#include <concepts>
+#include <ranges>
+
+#include "../types.h"
+
+using InnerIterator = std::ranges::iterator_t<std::ranges::range_reference_t<std::ranges::chunk_view<input_span<int>>>>;
+
+static_assert(!std::default_initializable<InnerIterator>);
+static_assert(!std::copy_constructible<InnerIterator>);
+static_assert(!std::assignable_from<InnerIterator&, const InnerIterator&>);
+static_assert(std::move_constructible<InnerIterator>);
+static_assert(std::assignable_from<InnerIterator&, InnerIterator>);

>From 5d32ff5424b490676c9771699233a396532fea1b Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sat, 25 Jul 2026 15:37:21 +0800
Subject: [PATCH 26/43] Add chunk_view inner iterator base() test

---
 .../range.chunk.inner.iter/base.pass.cpp      | 44 +++++++++++++++++++
 1 file changed, 44 insertions(+)
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/base.pass.cpp

diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/base.pass.cpp
new file mode 100644
index 0000000000000..9546aecb01560
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/base.pass.cpp
@@ -0,0 +1,44 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+// V models only input_range:
+//   constexpr const iterator_t<V> base() const&;
+
+#include <cassert>
+#include <concepts>
+#include <iterator>
+#include <ranges>
+
+#include "../types.h"
+
+constexpr bool test() {
+  int buffer[] = {1, 2, 3, 4};
+
+  std::ranges::chunk_view<input_span<int>> chunked(input_span<int>(buffer, 4), 2);
+  auto outer = chunked.begin();
+  auto inner = (*outer).begin();
+
+  std::same_as<const std::ranges::iterator_t<input_span<int>>> decltype(auto) base = inner.base();
+  assert(*base == 1);
+
+  ++inner;
+  assert(*inner.base() == 2);
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

>From 2c8a8c62abfca361ca45933de0da5eeebd68b290 Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sat, 25 Jul 2026 15:48:43 +0800
Subject: [PATCH 27/43] Fix input_span operator* to return a reference

---
 .../range.chunk/range.chunk.iter/deref.pass.cpp               | 4 ++--
 libcxx/test/std/ranges/range.adaptors/range.chunk/types.h     | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/deref.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/deref.pass.cpp
index b8772d0fac3d2..32054584f4358 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/deref.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/deref.pass.cpp
@@ -53,10 +53,10 @@ constexpr bool test() {
     static_assert(noexcept((inner.end())));
   }
 
-  // Test `constexpr value_type iterator::operator*() const`
+  // Test `constexpr range_reference_v<V> inner_iterator::operator*() const`
   {
     /*chunk_view::__inner_iterator*/ std::input_iterator auto it = (*input_chunked.begin()).begin();
-    std::same_as<int> decltype(auto) v                           = *it;
+    std::same_as<int&> decltype(auto) v                          = *it;
     assert(v == 1);
   }
 
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/types.h b/libcxx/test/std/ranges/range.adaptors/range.chunk/types.h
index 7533e41713d72..83e383e98110e 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/types.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/types.h
@@ -23,7 +23,7 @@ struct input_span : std::span<T> {
     using iterator_concept = std::input_iterator_tag;
     constexpr iterator()   = default;
     constexpr iterator(std::span<T>::iterator i) : std::span<T>::iterator(i) {}
-    constexpr auto operator*() const { return std::span<T>::iterator::operator*(); }
+    constexpr decltype(auto) operator*() const { return std::span<T>::iterator::operator*(); }
     friend constexpr auto operator+(iterator, std::span<T>::difference_type) = delete;
     friend constexpr auto operator+(std::span<T>::difference_type, iterator) = delete;
     friend constexpr auto operator-(iterator, std::span<T>::difference_type) = delete;

>From 32f132912f08cfd18cbf8fffff80ee42d178b745 Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sat, 25 Jul 2026 15:48:48 +0800
Subject: [PATCH 28/43] Add chunk_view inner iterator iter_swap test

---
 .../range.chunk.inner.iter/iter_swap.pass.cpp | 50 +++++++++++++++++++
 1 file changed, 50 insertions(+)
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/iter_swap.pass.cpp

diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/iter_swap.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/iter_swap.pass.cpp
new file mode 100644
index 0000000000000..b5223d5091982
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/iter_swap.pass.cpp
@@ -0,0 +1,50 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+// V models only input_range:
+//   friend constexpr void iter_swap(const inner_iterator& x, const inner_iterator& y)
+//     noexcept(noexcept(ranges::iter_swap(x.parent_->current_.value(), y.parent_->current_.value())))
+//     requires indirectly_swappable<iterator_t<V>>;
+
+#include <cassert>
+#include <ranges>
+
+#include "../types.h"
+
+constexpr bool test() {
+  int a[] = {1, 2, 3, 4};
+  int b[] = {5, 6, 7, 8};
+
+  // Each chunk_view owns its own `current_` cache, so use two independent views to observe a real swap.
+  std::ranges::chunk_view<input_span<int>> chunked_a(input_span<int>(a, 4), 2);
+  std::ranges::chunk_view<input_span<int>> chunked_b(input_span<int>(b, 4), 2);
+
+  auto inner_a = (*chunked_a.begin()).begin();
+  auto inner_b = (*chunked_b.begin()).begin();
+
+  assert(a[0] == 1);
+  assert(b[0] == 5);
+
+  std::ranges::iter_swap(inner_a, inner_b);
+
+  assert(a[0] == 5);
+  assert(b[0] == 1);
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

>From 237fa79aa5d1cc327884fef2dd96529686912fa6 Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sat, 25 Jul 2026 15:51:42 +0800
Subject: [PATCH 29/43] Add chunk_view outer iterator value_type size test

---
 .../range.chunk.outer.iter/size.pass.cpp      | 55 +++++++++++++++++++
 1 file changed, 55 insertions(+)
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/size.pass.cpp

diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/size.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/size.pass.cpp
new file mode 100644
index 0000000000000..51c7cac8da280
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/size.pass.cpp
@@ -0,0 +1,55 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+// V models only input_range:
+//   constexpr auto outer_iterator::value_type::size() const
+//     requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
+
+#include <cassert>
+#include <ranges>
+
+#include "../types.h"
+
+constexpr bool test() {
+  int arr[] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+  // Test `size()` when the range is fully divisible by the chunk size.
+  {
+    std::ranges::chunk_view<input_span<int>> chunked(input_span<int>(arr, 8), 4);
+    auto outer = chunked.begin();
+
+    assert((*outer).size() == 4);
+    ++outer;
+    assert((*outer).size() == 4);
+  }
+
+  // Test `size()` when the last chunk is smaller than the chunk size.
+  {
+    std::ranges::chunk_view<input_span<int>> chunked(input_span<int>(arr, 8), 3);
+    auto outer = chunked.begin();
+
+    assert((*outer).size() == 3);
+    ++outer;
+    assert((*outer).size() == 3);
+    ++outer;
+    assert((*outer).size() == 2);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

>From b329da3717ddf952907bf38181edd116277bd6bd Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sat, 25 Jul 2026 16:02:22 +0800
Subject: [PATCH 30/43] Add chunk_view outer iterator special member tests

---
 .../ctor.compile.pass.cpp                     | 28 +++++++++++++++++++
 1 file changed, 28 insertions(+)
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/ctor.compile.pass.cpp

diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/ctor.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/ctor.compile.pass.cpp
new file mode 100644
index 0000000000000..51198c1ffea81
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/ctor.compile.pass.cpp
@@ -0,0 +1,28 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+// V models only input_range:
+//   outer_iterator(outer_iterator&&) = default;
+//   outer_iterator& operator=(outer_iterator&&) = default;
+
+#include <concepts>
+#include <ranges>
+
+#include "../types.h"
+
+using OuterIterator = std::ranges::iterator_t<std::ranges::chunk_view<input_span<int>>>;
+
+static_assert(!std::default_initializable<OuterIterator>);
+static_assert(!std::copy_constructible<OuterIterator>);
+static_assert(!std::assignable_from<OuterIterator&, const OuterIterator&>);
+static_assert(std::move_constructible<OuterIterator>);
+static_assert(std::assignable_from<OuterIterator&, OuterIterator>);

>From 9f7ee27f55bf878305de8382e6086eb166949c5a Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sat, 25 Jul 2026 16:12:39 +0800
Subject: [PATCH 31/43] Add chunk_view forward iterator base() test

---
 .../range.chunk.iter/base.pass.cpp            | 41 +++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/base.pass.cpp

diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/base.pass.cpp
new file mode 100644
index 0000000000000..516de09aff5e5
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/base.pass.cpp
@@ -0,0 +1,41 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+// V models forward_range:
+//   constexpr iterator_t<Base> base() const;
+
+#include <cassert>
+#include <concepts>
+#include <ranges>
+#include <vector>
+
+constexpr bool test() {
+  std::vector<int> vector = {1, 2, 3, 4, 5, 6};
+
+  std::ranges::chunk_view<std::ranges::ref_view<std::vector<int>>> chunked = vector | std::views::chunk(2);
+  auto it = chunked.begin();
+
+  std::same_as<std::vector<int>::iterator> decltype(auto) base = it.base();
+  assert(base == vector.begin());
+
+  ++it;
+  assert(it.base() == vector.begin() + 2);
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

>From fb564fe8948b86ec24b9fdffaa9261bfbb4ad219 Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sat, 25 Jul 2026 19:59:40 +0800
Subject: [PATCH 32/43] Add chunk_view forward iterator converting constructor
 test

---
 .../range.chunk.iter/ctor.compile.pass.cpp    | 32 +++++++++++++++++++
 1 file changed, 32 insertions(+)
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/ctor.compile.pass.cpp

diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/ctor.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/ctor.compile.pass.cpp
new file mode 100644
index 0000000000000..3bd5bf9b97bb2
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/ctor.compile.pass.cpp
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+// V models forward_range:
+//   constexpr iterator(iterator<!Const> i)
+//     requires Const && convertible_to<iterator_t<V>, iterator_t<Base>> &&
+//                  convertible_to<sentinel_t<V>, sentinel_t<Base>>;
+
+#include <concepts>
+#include <ranges>
+
+#include "test_iterators.h"
+#include "test_range.h"
+
+using ChunkView     = std::ranges::chunk_view<test_view<forward_iterator>>;
+using Iterator      = std::ranges::iterator_t<ChunkView>;
+using ConstIterator = std::ranges::iterator_t<const ChunkView>;
+
+// `test_view`'s const and non-const `begin()` return different iterator types, so the converting
+// constructor is actually exercised here (unlike a simple_view, where both would collapse into one type).
+static_assert(!std::same_as<Iterator, ConstIterator>);
+static_assert(std::convertible_to<Iterator, ConstIterator>);
+static_assert(!std::convertible_to<ConstIterator, Iterator>);

>From 987eebdf25a36da980ac7e9e0cc6672afbf3aa05 Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sat, 25 Jul 2026 20:02:49 +0800
Subject: [PATCH 33/43] Add negative comparison cases for chunk_view sentinel
 equality

---
 .../range.chunk/range.chunk.iter/compare.pass.cpp            | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/compare.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/compare.pass.cpp
index ea6731cccce85..2871c48e0c46a 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/compare.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/compare.pass.cpp
@@ -46,6 +46,7 @@ constexpr bool test() {
   // Test `friend constexpr bool opreator==(const outer_iterator& x, default_sentinel_t)`
   {
     /*chunk_view::__outer_iterator*/ std::input_iterator auto it = input_chunked.begin();
+    assert(it != std::default_sentinel);
     std::ranges::advance(it, 4);
     assert(it == std::default_sentinel);
   }
@@ -53,7 +54,9 @@ constexpr bool test() {
   // Test `friend constexpr bool operator==(const inner_iterator& x, default_sentinel_t)`
   {
     /*chunk_view::__inner_iterator*/ std::input_iterator auto it = (*input_chunked.begin()).begin();
-    std::ranges::advance(it, 3);
+    std::ranges::advance(it, 2);
+    assert(it != std::default_sentinel);
+    ++it;
     assert(it == std::default_sentinel);
   }
 

>From 3f254012f59df5d68bf0618ac43ec26c46945bdc Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sat, 25 Jul 2026 20:08:46 +0800
Subject: [PATCH 34/43] Add chunk_view forward iterator comparison constraints
 and negative cases

---
 .../range.chunk.iter/compare.pass.cpp         | 21 +++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/compare.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/compare.pass.cpp
index 2871c48e0c46a..a9b6e359a2be6 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/compare.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/compare.pass.cpp
@@ -38,6 +38,19 @@
 #include "test_range.h"
 #include "../types.h"
 
+// The relational operators (<, >, <=, >=, <=>) are only available when `Base` models `random_access_range`.
+template <class Base>
+concept HasChunkIteratorRelationalOperators = requires(std::ranges::iterator_t<std::ranges::chunk_view<Base>> it) {
+  it < it;
+  it > it;
+  it <= it;
+  it >= it;
+};
+
+static_assert(!HasChunkIteratorRelationalOperators<test_view<forward_iterator>>);
+static_assert(!HasChunkIteratorRelationalOperators<test_view<bidirectional_iterator>>);
+static_assert(HasChunkIteratorRelationalOperators<test_view<random_access_iterator>>);
+
 constexpr bool test() {
   std::vector<int> vector                                                  = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
   std::ranges::chunk_view<std::ranges::ref_view<std::vector<int>>> chunked = vector | std::views::chunk(3);
@@ -64,33 +77,41 @@ constexpr bool test() {
   {
     assert(chunked.begin() == chunked.begin());
     assert(chunked.end() == chunked.end());
+    assert(chunked.begin() != chunked.end());
   }
 
   // Test `friend constexpr bool operator==(const iterator& x, default_sentinel)`
   {
     assert(chunked.end() == std::default_sentinel);
+    assert(chunked.begin() != std::default_sentinel);
   }
 
   // Test `friend constexpr bool operator<(const iterator& x, const iterator& y)`
   {
     assert(chunked.begin() < chunked.end());
+    assert(!(chunked.end() < chunked.begin()));
+    assert(!(chunked.begin() < chunked.begin()));
   }
 
   // Test `friend constexpr bool operator>(const iterator& x, const iterator& y)`
   {
     assert(chunked.end() > chunked.begin());
+    assert(!(chunked.begin() > chunked.end()));
+    assert(!(chunked.begin() > chunked.begin()));
   }
 
   // Test `friend constexpr bool operator<=(const iterator& x, const iterator& y)`
   {
     assert(chunked.begin() <= chunked.begin());
     assert(chunked.begin() <= chunked.end());
+    assert(!(chunked.end() <= chunked.begin()));
   }
 
   // Test `friend constexpr bool operator>=(const iterator& x, const iterator& y)`
   {
     assert(chunked.end() >= chunked.end());
     assert(chunked.end() >= chunked.begin());
+    assert(!(chunked.begin() >= chunked.end()));
   }
 
   // Test `friend constexpr auto operator<=>(const iterator& x, const iterator& y)`

>From 0879289b515e7d4a1680346da8ae93aef7b60fbf Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sat, 25 Jul 2026 20:12:56 +0800
Subject: [PATCH 35/43] Add chunk_view iterator arithmetic test for partial
 final chunk

---
 .../range.chunk.iter/arithmetic.pass.cpp         | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/arithmetic.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/arithmetic.pass.cpp
index 6baa2fce13695..2702cc70f54f0 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/arithmetic.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/arithmetic.pass.cpp
@@ -34,6 +34,7 @@
 //     friend constexpr difference_type operator-(const iterator& x, default_sentinel_t y)
 //       requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>;
 
+#include <algorithm>
 #include <cassert>
 #include <iterator>
 #include <ranges>
@@ -97,6 +98,21 @@ constexpr bool test() {
     assert(chunked.begin() - std::default_sentinel == -4);
   }
 
+  // Test `operator+=`/`operator-=` moving back and forth across a partial final chunk, when the range is
+  // not evenly divisible by the chunk size.
+  {
+    std::ranges::chunk_view<std::ranges::ref_view<std::vector<int>>> uneven_chunked = vector | std::views::chunk(5);
+
+    auto it = uneven_chunked.begin();
+    assert(std::ranges::equal(*it, std::vector{1, 2, 3, 4, 5}));
+
+    it += 2;
+    assert(std::ranges::equal(*it, std::vector{11, 12}));
+
+    it -= 1;
+    assert(std::ranges::equal(*it, std::vector{6, 7, 8, 9, 10}));
+  }
+
   return true;
 }
 

>From 7450780dbdb64c98ec5a7b6e45389bf2cdb9d04f Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sat, 25 Jul 2026 20:21:02 +0800
Subject: [PATCH 36/43] Remove [[nodiscard]] from chunk_view comparison
 operators

---
 libcxx/include/__ranges/chunk_view.h | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/libcxx/include/__ranges/chunk_view.h b/libcxx/include/__ranges/chunk_view.h
index e9511f027160a..a6686cc1e90df 100644
--- a/libcxx/include/__ranges/chunk_view.h
+++ b/libcxx/include/__ranges/chunk_view.h
@@ -134,7 +134,7 @@ class chunk_view<_View>::__outer_iterator {
 
   _LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) { ++*this; }
 
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr bool
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool
   operator==(const __outer_iterator& __i, default_sentinel_t) {
     return *__i.__parent_->__current_ == ranges::end(__i.__parent_->__base_) && __i.__parent_->__remainder_ != 0;
   }
@@ -219,7 +219,7 @@ class chunk_view<_View>::__inner_iterator {
 
   _LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) { ++*this; }
 
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr bool
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool
   operator==(const __inner_iterator& __i, default_sentinel_t) {
     return __i.__parent_->__remainder_ == 0;
   }
@@ -342,7 +342,7 @@ class chunk_view<_View>::__iterator {
       _Parent* __parent, iterator_t<_Base> __current, range_difference_t<_Base> __missing = 0)
       : __current_(__current), __end_(ranges::end(__parent->__base_)), __n_(__parent->__n_), __missing_(__missing) {}
 
-  [[nodiscard]] static consteval auto __get_iterator_concept() {
+  static consteval auto __get_iterator_concept() {
     if constexpr (random_access_range<_Base>)
       return random_access_iterator_tag{};
     else if constexpr (bidirectional_range<_Base>)
@@ -429,39 +429,39 @@ class chunk_view<_View>::__iterator {
     return *this += -__x;
   }
 
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __iterator& __y) {
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __iterator& __y) {
     return __x.__current_ == __y.__current_;
   }
 
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, default_sentinel_t) {
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, default_sentinel_t) {
     return __x.__current_ == __x.__end_;
   }
 
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<(const __iterator& __x, const __iterator& __y)
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<(const __iterator& __x, const __iterator& __y)
     requires random_access_range<_Base>
   {
     return __x.__current_ < __y.__current_;
   }
 
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>(const __iterator& __x, const __iterator& __y)
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>(const __iterator& __x, const __iterator& __y)
     requires random_access_range<_Base>
   {
     return __y < __x;
   }
 
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<=(const __iterator& __x, const __iterator& __y)
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<=(const __iterator& __x, const __iterator& __y)
     requires random_access_range<_Base>
   {
     return !(__y < __x);
   }
 
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>=(const __iterator& __x, const __iterator& __y)
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>=(const __iterator& __x, const __iterator& __y)
     requires random_access_range<_Base>
   {
     return !(__x < __y);
   }
 
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(const __iterator& __x, const __iterator& __y)
+  _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(const __iterator& __x, const __iterator& __y)
     requires random_access_range<_Base> && three_way_comparable<iterator_t<_Base>>
   {
     return __x.__current_ <=> __y.__current_;

>From f3a3326533ddf8c0eb97e0a23051cd84c72bd7ee Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sat, 25 Jul 2026 20:35:08 +0800
Subject: [PATCH 37/43] Simplify chunk_view nodiscard.verify.cpp

---
 .../range.adaptors/range.chunk/nodiscard.verify.cpp      | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/nodiscard.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/nodiscard.verify.cpp
index 4d0fb4f76857c..30ab0e9dade01 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/nodiscard.verify.cpp
@@ -53,15 +53,6 @@ void test() {
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
   *std::as_const(view).begin();
 
-  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
-  (view.begin() == view.end());
-  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
-  (std::as_const(view).begin() == view.end());
-  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
-  (view.begin() == std::as_const(view).end());
-  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
-  (std::as_const(view).begin() == std::as_const(view).end());
-
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
   std::views::chunk(3);
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}

>From adfc2f5a66ac6c2f7afbb412f9491acd8abc13d3 Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sat, 25 Jul 2026 20:35:18 +0800
Subject: [PATCH 38/43] Split chunk_view compare.pass.cpp by iterator kind

---
 .../range.chunk.inner.iter/compare.pass.cpp   | 44 +++++++++++++++++++
 .../range.chunk.iter/compare.pass.cpp         | 23 ----------
 .../range.chunk.outer.iter/compare.pass.cpp   | 43 ++++++++++++++++++
 3 files changed, 87 insertions(+), 23 deletions(-)
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/compare.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/compare.pass.cpp

diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/compare.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/compare.pass.cpp
new file mode 100644
index 0000000000000..dfa4a537f0eab
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/compare.pass.cpp
@@ -0,0 +1,44 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+// V models only input_range:
+//   friend constexpr bool operator==(const inner_iterator& x, default_sentinel_t);
+
+#include <cassert>
+#include <iterator>
+#include <ranges>
+#include <vector>
+
+#include "../types.h"
+
+constexpr bool test() {
+  std::vector<int> vector = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
+  std::ranges::chunk_view<input_span<int>> input_chunked = input_span<int>(vector) | std::views::chunk(3);
+
+  // Test `friend constexpr bool operator==(const inner_iterator& x, default_sentinel_t)`
+  {
+    /*chunk_view::__inner_iterator*/ std::input_iterator auto it = (*input_chunked.begin()).begin();
+    std::ranges::advance(it, 2);
+    assert(it != std::default_sentinel);
+    ++it;
+    assert(it == std::default_sentinel);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/compare.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/compare.pass.cpp
index a9b6e359a2be6..9b9a42dd1034a 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/compare.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/compare.pass.cpp
@@ -10,10 +10,6 @@
 
 // <ranges>
 
-//   V models only input_range
-//     friend constexpr bool operator==(const outer_iterator& x, default_sentinel_t);
-//     friend constexpr bool operator==(const inner_iterator& x, default_sentinel_t);
-
 //   V models forward_range
 //     friend constexpr bool operator==(const iterator& x, const iterator& y);
 //     friend constexpr bool operator==(const iterator& x, default_sentinel_t);
@@ -36,7 +32,6 @@
 #include <vector>
 
 #include "test_range.h"
-#include "../types.h"
 
 // The relational operators (<, >, <=, >=, <=>) are only available when `Base` models `random_access_range`.
 template <class Base>
@@ -54,24 +49,6 @@ static_assert(HasChunkIteratorRelationalOperators<test_view<random_access_iterat
 constexpr bool test() {
   std::vector<int> vector                                                  = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
   std::ranges::chunk_view<std::ranges::ref_view<std::vector<int>>> chunked = vector | std::views::chunk(3);
-  std::ranges::chunk_view<input_span<int>> input_chunked = input_span<int>(vector) | std::views::chunk(3);
-
-  // Test `friend constexpr bool opreator==(const outer_iterator& x, default_sentinel_t)`
-  {
-    /*chunk_view::__outer_iterator*/ std::input_iterator auto it = input_chunked.begin();
-    assert(it != std::default_sentinel);
-    std::ranges::advance(it, 4);
-    assert(it == std::default_sentinel);
-  }
-
-  // Test `friend constexpr bool operator==(const inner_iterator& x, default_sentinel_t)`
-  {
-    /*chunk_view::__inner_iterator*/ std::input_iterator auto it = (*input_chunked.begin()).begin();
-    std::ranges::advance(it, 2);
-    assert(it != std::default_sentinel);
-    ++it;
-    assert(it == std::default_sentinel);
-  }
 
   // Test `friend constexpr bool operator==(const iterator& x, const iterator& y)`
   {
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/compare.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/compare.pass.cpp
new file mode 100644
index 0000000000000..d269ad67c8d41
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/compare.pass.cpp
@@ -0,0 +1,43 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+// V models only input_range:
+//   friend constexpr bool operator==(const outer_iterator& x, default_sentinel_t);
+
+#include <cassert>
+#include <iterator>
+#include <ranges>
+#include <vector>
+
+#include "../types.h"
+
+constexpr bool test() {
+  std::vector<int> vector = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
+  std::ranges::chunk_view<input_span<int>> input_chunked = input_span<int>(vector) | std::views::chunk(3);
+
+  // Test `friend constexpr bool operator==(const outer_iterator& x, default_sentinel_t)`
+  {
+    /*chunk_view::__outer_iterator*/ std::input_iterator auto it = input_chunked.begin();
+    assert(it != std::default_sentinel);
+    std::ranges::advance(it, 4);
+    assert(it == std::default_sentinel);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

>From 938406638236c4d23110612f12e31ab1e1170966 Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sat, 25 Jul 2026 20:42:59 +0800
Subject: [PATCH 39/43] Split chunk_view deref.pass.cpp by iterator kind

---
 .../range.chunk.inner.iter/deref.pass.cpp     | 42 ++++++++++++++
 .../range.chunk.iter/deref.pass.cpp           | 46 ++-------------
 .../range.chunk.outer.iter/deref.pass.cpp     | 57 +++++++++++++++++++
 3 files changed, 103 insertions(+), 42 deletions(-)
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/deref.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/deref.pass.cpp

diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/deref.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/deref.pass.cpp
new file mode 100644
index 0000000000000..0a649809b9cc1
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/deref.pass.cpp
@@ -0,0 +1,42 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+// V models only input_range:
+//   constexpr range_reference_v<V> inner_iterator::operator*() const;
+
+#include <cassert>
+#include <concepts>
+#include <ranges>
+#include <vector>
+
+#include "../types.h"
+
+constexpr bool test() {
+  std::vector<int> vector                                = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
+  std::ranges::chunk_view<input_span<int>> input_chunked = input_span<int>(vector) | std::views::chunk(3);
+
+  // Test `constexpr range_reference_v<V> inner_iterator::operator*() const`
+  {
+    /*chunk_view::__inner_iterator*/ std::input_iterator auto it = (*input_chunked.begin()).begin();
+    std::same_as<int&> decltype(auto) v                          = *it;
+    assert(v == 1);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/deref.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/deref.pass.cpp
index 32054584f4358..414d65fd55a50 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/deref.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/deref.pass.cpp
@@ -10,57 +10,19 @@
 
 // <ranges>
 
-//   V models only input_range:
-//     constexpr value_type outer_iterator::operator*() const;
-//     constexpr inner_iterator outer_iterator::value_type::begin() const noexcept;
-//     constexpr default_sentinel_t outer_iterator::value_type::end() const noexcept;
-//     constexpr range_reference_v<V> inner_iterator::operator*() const;
+// V models forward_range:
+//   constexpr value_type iterator::operator*() const;
 
-//   V models forward_range:
-//     constexpr value_type iterator::operator*() const;
-
-#include <algorithm>
 #include <cassert>
-#include <compare>
-#include <iterator>
+#include <concepts>
 #include <ranges>
 #include <vector>
 
-#include "test_range.h"
-#include "../types.h"
-
 constexpr bool test() {
   std::vector<int> vector                                                  = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
   std::ranges::chunk_view<std::ranges::ref_view<std::vector<int>>> chunked = vector | std::views::chunk(3);
-  std::ranges::chunk_view<input_span<int>> input_chunked = input_span<int>(vector) | std::views::chunk(3);
-
-  // Test `constexpr value_type outer_iterator::operator*() const`
-  {
-    static_assert(std::ranges::input_range<decltype(*input_chunked.begin())>);
-  }
-
-  // Test `constexpr inner_iterator outer_iterator::value_type::begin() const noexcept`
-  {
-    /*chunk_view::__outer_iterator::value_type*/ std::ranges::input_range auto inner = *input_chunked.begin();
-    assert(*inner.begin() == *vector.begin());
-    static_assert(noexcept(inner.begin()));
-  }
-
-  // Test `constexpr default_sentinel_t outer_iterator::value_type::end() const noexcept`
-  {
-    /*chunk_view::__outer_iterator::value_type*/ std::ranges::input_range auto inner = *input_chunked.begin();
-    [[maybe_unused]] std::same_as<std::default_sentinel_t> auto it                   = inner.end();
-    static_assert(noexcept((inner.end())));
-  }
-
-  // Test `constexpr range_reference_v<V> inner_iterator::operator*() const`
-  {
-    /*chunk_view::__inner_iterator*/ std::input_iterator auto it = (*input_chunked.begin()).begin();
-    std::same_as<int&> decltype(auto) v                          = *it;
-    assert(v == 1);
-  }
 
-  // Test `constexpr range_reference_v<V> inner_iterator::operator*() const`
+  // Test `constexpr value_type iterator::operator*() const`
   {
     std::same_as<int&> decltype(auto) v = *(*chunked.begin()).begin();
     assert(v == 1);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/deref.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/deref.pass.cpp
new file mode 100644
index 0000000000000..2a0eb9561ff98
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/deref.pass.cpp
@@ -0,0 +1,57 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+// V models only input_range:
+//   constexpr value_type outer_iterator::operator*() const;
+//   constexpr inner_iterator outer_iterator::value_type::begin() const noexcept;
+//   constexpr default_sentinel_t outer_iterator::value_type::end() const noexcept;
+
+#include <cassert>
+#include <compare>
+#include <iterator>
+#include <ranges>
+#include <vector>
+
+#include "../types.h"
+
+constexpr bool test() {
+  std::vector<int> vector                                = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
+  std::ranges::chunk_view<input_span<int>> input_chunked = input_span<int>(vector) | std::views::chunk(3);
+
+  // Test `constexpr value_type outer_iterator::operator*() const`
+  {
+    static_assert(std::ranges::input_range<decltype(*input_chunked.begin())>);
+  }
+
+  // Test `constexpr inner_iterator outer_iterator::value_type::begin() const noexcept`
+  {
+    /*chunk_view::__outer_iterator::value_type*/ std::ranges::input_range auto inner = *input_chunked.begin();
+    assert(*inner.begin() == *vector.begin());
+    static_assert(noexcept(inner.begin()));
+  }
+
+  // Test `constexpr default_sentinel_t outer_iterator::value_type::end() const noexcept`
+  {
+    /*chunk_view::__outer_iterator::value_type*/ std::ranges::input_range auto inner = *input_chunked.begin();
+    [[maybe_unused]] std::same_as<std::default_sentinel_t> auto it                   = inner.end();
+    static_assert(noexcept((inner.end())));
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

>From 3167ebdb22b2900134def6ac3d09cba156a1272b Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sat, 25 Jul 2026 20:48:22 +0800
Subject: [PATCH 40/43] Split chunk_view increment.pass.cpp by iterator kind

---
 .../range.chunk.inner.iter/increment.pass.cpp | 51 ++++++++++++++++++
 .../range.chunk.iter/increment.pass.cpp       | 48 ++---------------
 .../range.chunk.outer.iter/increment.pass.cpp | 52 +++++++++++++++++++
 3 files changed, 108 insertions(+), 43 deletions(-)
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/increment.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/increment.pass.cpp

diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/increment.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/increment.pass.cpp
new file mode 100644
index 0000000000000..ea722ffe943c7
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/increment.pass.cpp
@@ -0,0 +1,51 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+// V models only input_range:
+//   constexpr inner_iterator& operator++();
+//   constexpr void operator++(int);
+
+#include <cassert>
+#include <concepts>
+#include <iterator>
+#include <ranges>
+#include <vector>
+
+#include "../types.h"
+
+constexpr bool test() {
+  std::vector<int> vector                                = {1, 2, 3, 4, 5, 6, 7, 8};
+  std::ranges::chunk_view<input_span<int>> input_chunked = input_span<int>(vector) | std::views::chunk(2);
+
+  // Test `constexpr inner_iterator& operator++();`
+  {
+    /*chunk_view::__inner_iterator*/ std::input_iterator auto it = (*input_chunked.begin()).begin();
+    assert(*++it == 2);
+  }
+
+  // Test `constexpr inner_iterator& operator++();`
+  {
+    /*chunk_view::__inner_iterator*/ std::input_iterator auto it = (*input_chunked.begin()).begin();
+    static_assert(std::same_as<decltype(it++), void>);
+    it++;
+    assert(*it == 2);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/increment.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/increment.pass.cpp
index 6048aba027ce9..94d1dd71d603f 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/increment.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/increment.pass.cpp
@@ -10,17 +10,11 @@
 
 // <ranges>
 
-//   V models only input_range
-//     constexpr outer_iterator& operator++();
-//     constexpr void operator++(int);
-//     constexpr inner_iterator& operator++();
-//     constexpr void operator++(int);
-
-//   V models forward_range
-//     constexpr iterator& operator++();
-//     constexpr iterator operator++(int);
-//     constexpr iterator& operator+=(difference_type)
-//       requires random_access_range<Base>;
+// V models forward_range:
+//   constexpr iterator& operator++();
+//   constexpr iterator operator++(int);
+//   constexpr iterator& operator+=(difference_type)
+//     requires random_access_range<Base>;
 
 #include <algorithm>
 #include <cassert>
@@ -28,41 +22,9 @@
 #include <ranges>
 #include <vector>
 
-#include "test_range.h"
-#include "../types.h"
-
 constexpr bool test() {
   std::vector<int> vector                                                  = {1, 2, 3, 4, 5, 6, 7, 8};
   std::ranges::chunk_view<std::ranges::ref_view<std::vector<int>>> chunked = vector | std::views::chunk(2);
-  std::ranges::chunk_view<input_span<int>> input_chunked = input_span<int>(vector) | std::views::chunk(2);
-
-  // Test `constexpr outer_iterator& operator++();`
-  {
-    /*chunk_view::__outer_iterator*/ std::input_iterator auto it = input_chunked.begin();
-    assert(std::ranges::equal(*++it, std::vector{3, 4}));
-  }
-
-  // Test `constexpr void operator++(int);`
-  {
-    /*chunk_view::__outer_iterator*/ std::input_iterator auto it = input_chunked.begin();
-    static_assert(std::same_as<decltype(it++), void>);
-    it++;
-    assert(std::ranges::equal(*it, std::vector{3, 4}));
-  }
-
-  // Test `constexpr inner_iterator& operator++();`
-  {
-    /*chunk_view::__inner_iterator*/ std::input_iterator auto it = (*input_chunked.begin()).begin();
-    assert(*++it == 2);
-  }
-
-  // Test `constexpr inner_iterator& operator++();`
-  {
-    /*chunk_view::__inner_iterator*/ std::input_iterator auto it = (*input_chunked.begin()).begin();
-    static_assert(std::same_as<decltype(it++), void>);
-    it++;
-    assert(*it == 2);
-  }
 
   // Test `constexpr iterator& operator++();`
   {
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/increment.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/increment.pass.cpp
new file mode 100644
index 0000000000000..f77d20daab8a4
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/increment.pass.cpp
@@ -0,0 +1,52 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+// V models only input_range:
+//   constexpr outer_iterator& operator++();
+//   constexpr void operator++(int);
+
+#include <algorithm>
+#include <cassert>
+#include <concepts>
+#include <iterator>
+#include <ranges>
+#include <vector>
+
+#include "../types.h"
+
+constexpr bool test() {
+  std::vector<int> vector                                = {1, 2, 3, 4, 5, 6, 7, 8};
+  std::ranges::chunk_view<input_span<int>> input_chunked = input_span<int>(vector) | std::views::chunk(2);
+
+  // Test `constexpr outer_iterator& operator++();`
+  {
+    /*chunk_view::__outer_iterator*/ std::input_iterator auto it = input_chunked.begin();
+    assert(std::ranges::equal(*++it, std::vector{3, 4}));
+  }
+
+  // Test `constexpr void operator++(int);`
+  {
+    /*chunk_view::__outer_iterator*/ std::input_iterator auto it = input_chunked.begin();
+    static_assert(std::same_as<decltype(it++), void>);
+    it++;
+    assert(std::ranges::equal(*it, std::vector{3, 4}));
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

>From 6287f7f6b9edad7a64ba776675e3841278c92599 Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sat, 25 Jul 2026 20:52:56 +0800
Subject: [PATCH 41/43] Split chunk_view arithmetic.pass.cpp by iterator kind

---
 .../arithmetic.pass.cpp                       | 48 +++++++++++++++
 .../range.chunk.iter/arithmetic.pass.cpp      | 60 ++++---------------
 .../arithmetic.pass.cpp                       | 48 +++++++++++++++
 3 files changed, 109 insertions(+), 47 deletions(-)
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/arithmetic.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/arithmetic.pass.cpp

diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/arithmetic.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/arithmetic.pass.cpp
new file mode 100644
index 0000000000000..c89fc26026711
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/arithmetic.pass.cpp
@@ -0,0 +1,48 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+// V models only input_range:
+//   friend constexpr difference_type operator-(default_sentinel_t y, const inner_iterator& x)
+//     requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
+//   friend constexpr difference_type operator-(const inner_iterator& x, default_sentinel_t y)
+//     requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
+
+#include <cassert>
+#include <iterator>
+#include <ranges>
+#include <vector>
+
+#include "../types.h"
+
+constexpr bool test() {
+  std::vector<int> vector                                = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
+  std::ranges::chunk_view<input_span<int>> input_chunked = input_span<int>(vector) | std::views::chunk(3);
+
+  // Test `friend constexpr difference_type operator-(default_sentinel_t, const inner_iterator& x)`
+  {
+    assert(std::default_sentinel - (*input_chunked.begin()).begin() == 3);
+  }
+
+  // Test `friend constexpr difference_type operator-(const inner_iterator& x, default_sentinel_t)`
+  {
+    assert((*input_chunked.begin()).begin() - std::default_sentinel == -3);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/arithmetic.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/arithmetic.pass.cpp
index 2702cc70f54f0..2151a488664fb 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/arithmetic.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/arithmetic.pass.cpp
@@ -10,29 +10,19 @@
 
 // <ranges>
 
-//   V models only input_range
-//     friend constexpr difference_type operator-(default_sentinel_t t, const outer_iterator& i)
-//       requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
-//     friend constexpr difference_type operator-(const outer_iterator& i, default_sentinel_t t)
-//       requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
-//     friend constexpr difference_type operator-(default_sentinel_t y, const inner_iterator& x)
-//       requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
-//     friend constexpr difference_type operator-(const inner_iterator& x, default_sentinel_t y)
-//       requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
-
-//   V models forward_range
-//     friend constexpr iterator operator+(const iterator& i, difference_type n)
-//       requires random_access_range<Base>;
-//     friend constexpr iterator operator+(difference_type n, const iterator& i)
-//       requires random_access_range<Base>;
-//     friend constexpr iterator operator-(const iterator& i, difference_type n)
-//       requires random_access_range<Base>;
-//     friend constexpr difference_type operator-(const iterator& x, const iterator& y)
-//       requires sized_sentinel_for<iterator_t<Base>, iterator_t<Base>>;
-//     friend constexpr difference_type operator-(default_sentinel_t y, const iterator& x)
-//       requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>;
-//     friend constexpr difference_type operator-(const iterator& x, default_sentinel_t y)
-//       requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>;
+// V models forward_range:
+//   friend constexpr iterator operator+(const iterator& i, difference_type n)
+//     requires random_access_range<Base>;
+//   friend constexpr iterator operator+(difference_type n, const iterator& i)
+//     requires random_access_range<Base>;
+//   friend constexpr iterator operator-(const iterator& i, difference_type n)
+//     requires random_access_range<Base>;
+//   friend constexpr difference_type operator-(const iterator& x, const iterator& y)
+//     requires sized_sentinel_for<iterator_t<Base>, iterator_t<Base>>;
+//   friend constexpr difference_type operator-(default_sentinel_t y, const iterator& x)
+//     requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>;
+//   friend constexpr difference_type operator-(const iterator& x, default_sentinel_t y)
+//     requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>;
 
 #include <algorithm>
 #include <cassert>
@@ -40,33 +30,9 @@
 #include <ranges>
 #include <vector>
 
-#include "test_range.h"
-#include "../types.h"
-
 constexpr bool test() {
   std::vector<int> vector                                                  = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
   std::ranges::chunk_view<std::ranges::ref_view<std::vector<int>>> chunked = vector | std::views::chunk(3);
-  std::ranges::chunk_view<input_span<int>> input_chunked = input_span<int>(vector) | std::views::chunk(3);
-
-  // Test `friend constexpr difference_type operator-(default_sentinel_t t, const outer_iterator& i)`
-  {
-    assert(std::default_sentinel - input_chunked.begin() == 4);
-  }
-
-  // Test `friend constexpr difference_type operator-(const outer_iterator& i, default_sentinel_t)`
-  {
-    assert(input_chunked.begin() - std::default_sentinel == -4);
-  }
-
-  // Test `friend constexpr difference_type operator-(default_sentinel_t, const inner_iterator& x)`
-  {
-    assert(std::default_sentinel - (*input_chunked.begin()).begin() == 3);
-  }
-
-  // Test `friend constexpr difference_type operator-(const inner_iterator& x, default_sentinel_t)`
-  {
-    assert((*input_chunked.begin()).begin() - std::default_sentinel == -3);
-  }
 
   // Test `friend constexpr iterator operator+(const iterator& i, difference_type n)`
   {
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/arithmetic.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/arithmetic.pass.cpp
new file mode 100644
index 0000000000000..7048344a5ba97
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/arithmetic.pass.cpp
@@ -0,0 +1,48 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <ranges>
+
+// V models only input_range:
+//   friend constexpr difference_type operator-(default_sentinel_t t, const outer_iterator& i)
+//     requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
+//   friend constexpr difference_type operator-(const outer_iterator& i, default_sentinel_t t)
+//     requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
+
+#include <cassert>
+#include <iterator>
+#include <ranges>
+#include <vector>
+
+#include "../types.h"
+
+constexpr bool test() {
+  std::vector<int> vector                                = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
+  std::ranges::chunk_view<input_span<int>> input_chunked = input_span<int>(vector) | std::views::chunk(3);
+
+  // Test `friend constexpr difference_type operator-(default_sentinel_t t, const outer_iterator& i)`
+  {
+    assert(std::default_sentinel - input_chunked.begin() == 4);
+  }
+
+  // Test `friend constexpr difference_type operator-(const outer_iterator& i, default_sentinel_t)`
+  {
+    assert(input_chunked.begin() - std::default_sentinel == -4);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

>From 5e5bd8dc6411e5ad1c15a26504d92533a8b66635 Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sat, 25 Jul 2026 21:30:00 +0800
Subject: [PATCH 42/43] Adjust test 'title' style

---
 .../arithmetic.pass.cpp                       | 10 +++----
 .../range.chunk.inner.iter/base.pass.cpp      |  4 +--
 .../range.chunk.inner.iter/compare.pass.cpp   |  4 +--
 .../ctor.compile.pass.cpp                     |  6 ++---
 .../range.chunk.inner.iter/deref.pass.cpp     |  4 +--
 .../range.chunk.inner.iter/increment.pass.cpp |  6 ++---
 .../range.chunk.inner.iter/iter_move.pass.cpp |  6 ++---
 .../range.chunk.inner.iter/iter_swap.pass.cpp |  8 +++---
 .../types.compile.pass.cpp                    | 10 +++----
 .../range.chunk.iter/arithmetic.pass.cpp      | 26 +++++++++----------
 .../range.chunk.iter/base.pass.cpp            |  4 +--
 .../range.chunk.iter/ctor.compile.pass.cpp    |  8 +++---
 .../range.chunk.iter/deref.pass.cpp           |  4 +--
 .../range.chunk.iter/increment.pass.cpp       | 10 +++----
 .../range.chunk.iter/types.compile.pass.cpp   | 12 ++++-----
 .../arithmetic.pass.cpp                       | 10 +++----
 .../range.chunk.outer.iter/compare.pass.cpp   |  4 +--
 .../ctor.compile.pass.cpp                     |  6 ++---
 .../range.chunk.outer.iter/deref.pass.cpp     |  8 +++---
 .../range.chunk.outer.iter/increment.pass.cpp |  6 ++---
 .../range.chunk.outer.iter/size.pass.cpp      |  6 ++---
 .../types.compile.pass.cpp                    | 10 +++----
 22 files changed, 86 insertions(+), 86 deletions(-)

diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/arithmetic.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/arithmetic.pass.cpp
index c89fc26026711..c6fc5d026699e 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/arithmetic.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/arithmetic.pass.cpp
@@ -10,11 +10,11 @@
 
 // <ranges>
 
-// V models only input_range:
-//   friend constexpr difference_type operator-(default_sentinel_t y, const inner_iterator& x)
-//     requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
-//   friend constexpr difference_type operator-(const inner_iterator& x, default_sentinel_t y)
-//     requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
+//   V models only input_range:
+//     friend constexpr difference_type operator-(default_sentinel_t y, const inner_iterator& x)
+//       requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
+//     friend constexpr difference_type operator-(const inner_iterator& x, default_sentinel_t y)
+//       requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
 
 #include <cassert>
 #include <iterator>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/base.pass.cpp
index 9546aecb01560..76816ea99ab9c 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/base.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/base.pass.cpp
@@ -10,8 +10,8 @@
 
 // <ranges>
 
-// V models only input_range:
-//   constexpr const iterator_t<V> base() const&;
+//   V models only input_range:
+//     constexpr const iterator_t<V> base() const&;
 
 #include <cassert>
 #include <concepts>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/compare.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/compare.pass.cpp
index dfa4a537f0eab..81333cd787e6e 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/compare.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/compare.pass.cpp
@@ -10,8 +10,8 @@
 
 // <ranges>
 
-// V models only input_range:
-//   friend constexpr bool operator==(const inner_iterator& x, default_sentinel_t);
+//   V models only input_range:
+//     friend constexpr bool operator==(const inner_iterator& x, default_sentinel_t);
 
 #include <cassert>
 #include <iterator>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/ctor.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/ctor.compile.pass.cpp
index ec2e68cb0c8ca..072e0bd524481 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/ctor.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/ctor.compile.pass.cpp
@@ -10,9 +10,9 @@
 
 // <ranges>
 
-// V models only input_range:
-//   inner_iterator(inner_iterator&&) = default;
-//   inner_iterator& operator=(inner_iterator&&) = default;
+//   V models only input_range:
+//     inner_iterator(inner_iterator&&) = default;
+//     inner_iterator& operator=(inner_iterator&&) = default;
 
 #include <concepts>
 #include <ranges>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/deref.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/deref.pass.cpp
index 0a649809b9cc1..41c58c02cbd72 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/deref.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/deref.pass.cpp
@@ -10,8 +10,8 @@
 
 // <ranges>
 
-// V models only input_range:
-//   constexpr range_reference_v<V> inner_iterator::operator*() const;
+//   V models only input_range:
+//     constexpr range_reference_v<V> inner_iterator::operator*() const;
 
 #include <cassert>
 #include <concepts>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/increment.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/increment.pass.cpp
index ea722ffe943c7..082e9ad7c08ea 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/increment.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/increment.pass.cpp
@@ -10,9 +10,9 @@
 
 // <ranges>
 
-// V models only input_range:
-//   constexpr inner_iterator& operator++();
-//   constexpr void operator++(int);
+//   V models only input_range:
+//     constexpr inner_iterator& operator++();
+//     constexpr void operator++(int);
 
 #include <cassert>
 #include <concepts>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/iter_move.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/iter_move.pass.cpp
index 5c7b620924c2f..d7d6dd9cce2ae 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/iter_move.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/iter_move.pass.cpp
@@ -10,9 +10,9 @@
 
 // <ranges>
 
-// V models only input_range:
-//   friend constexpr range_rvalue_reference_t<V> iter_move(const inner_iterator& i)
-//     noexcept(noexcept(ranges::iter_move(i.parent_->current_.value())));
+//   V models only input_range:
+//     friend constexpr range_rvalue_reference_t<V> iter_move(const inner_iterator& i)
+//       noexcept(noexcept(ranges::iter_move(i.parent_->current_.value())));
 
 #include <concepts>
 #include <ranges>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/iter_swap.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/iter_swap.pass.cpp
index b5223d5091982..6efa479e56c2e 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/iter_swap.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/iter_swap.pass.cpp
@@ -10,10 +10,10 @@
 
 // <ranges>
 
-// V models only input_range:
-//   friend constexpr void iter_swap(const inner_iterator& x, const inner_iterator& y)
-//     noexcept(noexcept(ranges::iter_swap(x.parent_->current_.value(), y.parent_->current_.value())))
-//     requires indirectly_swappable<iterator_t<V>>;
+//   V models only input_range:
+//     friend constexpr void iter_swap(const inner_iterator& x, const inner_iterator& y)
+//       noexcept(noexcept(ranges::iter_swap(x.parent_->current_.value(), y.parent_->current_.value())))
+//       requires indirectly_swappable<iterator_t<V>>;
 
 #include <cassert>
 #include <ranges>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/types.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/types.compile.pass.cpp
index 1775a08f84a2f..288388843b919 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/types.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.inner.iter/types.compile.pass.cpp
@@ -10,12 +10,12 @@
 
 // <ranges>
 
-// V models only input_range:
-//   class inner_iterator;
+//   V models only input_range:
+//     class inner_iterator;
 
-//   using inner_iterator::iterator_concept = input_iterator_tag;
-//   using inner_iterator::difference_type = range_difference_t<V>;
-//   using inner_iterator::value_type = range_value_t<V>;
+//     using inner_iterator::iterator_concept = input_iterator_tag;
+//     using inner_iterator::difference_type = range_difference_t<V>;
+//     using inner_iterator::value_type = range_value_t<V>;
 
 #include <concepts>
 #include <iterator>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/arithmetic.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/arithmetic.pass.cpp
index 2151a488664fb..89fd953e4306a 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/arithmetic.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/arithmetic.pass.cpp
@@ -10,19 +10,19 @@
 
 // <ranges>
 
-// V models forward_range:
-//   friend constexpr iterator operator+(const iterator& i, difference_type n)
-//     requires random_access_range<Base>;
-//   friend constexpr iterator operator+(difference_type n, const iterator& i)
-//     requires random_access_range<Base>;
-//   friend constexpr iterator operator-(const iterator& i, difference_type n)
-//     requires random_access_range<Base>;
-//   friend constexpr difference_type operator-(const iterator& x, const iterator& y)
-//     requires sized_sentinel_for<iterator_t<Base>, iterator_t<Base>>;
-//   friend constexpr difference_type operator-(default_sentinel_t y, const iterator& x)
-//     requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>;
-//   friend constexpr difference_type operator-(const iterator& x, default_sentinel_t y)
-//     requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>;
+//   V models forward_range:
+//     friend constexpr iterator operator+(const iterator& i, difference_type n)
+//       requires random_access_range<Base>;
+//     friend constexpr iterator operator+(difference_type n, const iterator& i)
+//       requires random_access_range<Base>;
+//     friend constexpr iterator operator-(const iterator& i, difference_type n)
+//       requires random_access_range<Base>;
+//     friend constexpr difference_type operator-(const iterator& x, const iterator& y)
+//       requires sized_sentinel_for<iterator_t<Base>, iterator_t<Base>>;
+//     friend constexpr difference_type operator-(default_sentinel_t y, const iterator& x)
+//       requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>;
+//     friend constexpr difference_type operator-(const iterator& x, default_sentinel_t y)
+//       requires sized_sentinel_for<sentinel_t<Base>, iterator_t<Base>>;
 
 #include <algorithm>
 #include <cassert>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/base.pass.cpp
index 516de09aff5e5..7f150b218eb2a 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/base.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/base.pass.cpp
@@ -10,8 +10,8 @@
 
 // <ranges>
 
-// V models forward_range:
-//   constexpr iterator_t<Base> base() const;
+//   V models forward_range:
+//     constexpr iterator_t<Base> base() const;
 
 #include <cassert>
 #include <concepts>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/ctor.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/ctor.compile.pass.cpp
index 3bd5bf9b97bb2..bdf96841bda73 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/ctor.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/ctor.compile.pass.cpp
@@ -10,10 +10,10 @@
 
 // <ranges>
 
-// V models forward_range:
-//   constexpr iterator(iterator<!Const> i)
-//     requires Const && convertible_to<iterator_t<V>, iterator_t<Base>> &&
-//                  convertible_to<sentinel_t<V>, sentinel_t<Base>>;
+//   V models forward_range:
+//     constexpr iterator(iterator<!Const> i)
+//       requires Const && convertible_to<iterator_t<V>, iterator_t<Base>> &&
+//                    convertible_to<sentinel_t<V>, sentinel_t<Base>>;
 
 #include <concepts>
 #include <ranges>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/deref.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/deref.pass.cpp
index 414d65fd55a50..4404ac907e6c7 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/deref.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/deref.pass.cpp
@@ -10,8 +10,8 @@
 
 // <ranges>
 
-// V models forward_range:
-//   constexpr value_type iterator::operator*() const;
+//   V models forward_range:
+//     constexpr value_type iterator::operator*() const;
 
 #include <cassert>
 #include <concepts>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/increment.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/increment.pass.cpp
index 94d1dd71d603f..36bc19c5dee65 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/increment.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/increment.pass.cpp
@@ -10,11 +10,11 @@
 
 // <ranges>
 
-// V models forward_range:
-//   constexpr iterator& operator++();
-//   constexpr iterator operator++(int);
-//   constexpr iterator& operator+=(difference_type)
-//     requires random_access_range<Base>;
+//   V models forward_range:
+//     constexpr iterator& operator++();
+//     constexpr iterator operator++(int);
+//     constexpr iterator& operator+=(difference_type)
+//       requires random_access_range<Base>;
 
 #include <algorithm>
 #include <cassert>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/types.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/types.compile.pass.cpp
index 96e3057edc04a..06b41656abc8e 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/types.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.iter/types.compile.pass.cpp
@@ -10,13 +10,13 @@
 
 // <ranges>
 
-// V models forward_range:
-//   class iterator;
+//   V models forward_range:
+//     class iterator;
 
-//   using iterator::iterator_category = input_iterator_tag;
-//   using iterator::iterator_concept = see below;
-//   using iterator::value_type = decltype(views::take(subrange(current_, end_), n_));
-//   using iterator::difference_type = range_difference_t<Base>;
+//     using iterator::iterator_category = input_iterator_tag;
+//     using iterator::iterator_concept = see below;
+//     using iterator::value_type = decltype(views::take(subrange(current_, end_), n_));
+//     using iterator::difference_type = range_difference_t<Base>;
 
 #include <concepts>
 #include <iterator>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/arithmetic.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/arithmetic.pass.cpp
index 7048344a5ba97..f9c739424d16e 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/arithmetic.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/arithmetic.pass.cpp
@@ -10,11 +10,11 @@
 
 // <ranges>
 
-// V models only input_range:
-//   friend constexpr difference_type operator-(default_sentinel_t t, const outer_iterator& i)
-//     requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
-//   friend constexpr difference_type operator-(const outer_iterator& i, default_sentinel_t t)
-//     requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
+//   V models only input_range:
+//     friend constexpr difference_type operator-(default_sentinel_t t, const outer_iterator& i)
+//       requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
+//     friend constexpr difference_type operator-(const outer_iterator& i, default_sentinel_t t)
+//       requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
 
 #include <cassert>
 #include <iterator>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/compare.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/compare.pass.cpp
index d269ad67c8d41..47249230a6d12 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/compare.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/compare.pass.cpp
@@ -10,8 +10,8 @@
 
 // <ranges>
 
-// V models only input_range:
-//   friend constexpr bool operator==(const outer_iterator& x, default_sentinel_t);
+//   V models only input_range:
+//     friend constexpr bool operator==(const outer_iterator& x, default_sentinel_t);
 
 #include <cassert>
 #include <iterator>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/ctor.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/ctor.compile.pass.cpp
index 51198c1ffea81..811a55c77c277 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/ctor.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/ctor.compile.pass.cpp
@@ -10,9 +10,9 @@
 
 // <ranges>
 
-// V models only input_range:
-//   outer_iterator(outer_iterator&&) = default;
-//   outer_iterator& operator=(outer_iterator&&) = default;
+//   V models only input_range:
+//     outer_iterator(outer_iterator&&) = default;
+//     outer_iterator& operator=(outer_iterator&&) = default;
 
 #include <concepts>
 #include <ranges>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/deref.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/deref.pass.cpp
index 2a0eb9561ff98..9e6bc77ef12cd 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/deref.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/deref.pass.cpp
@@ -10,10 +10,10 @@
 
 // <ranges>
 
-// V models only input_range:
-//   constexpr value_type outer_iterator::operator*() const;
-//   constexpr inner_iterator outer_iterator::value_type::begin() const noexcept;
-//   constexpr default_sentinel_t outer_iterator::value_type::end() const noexcept;
+//   V models only input_range:
+//     constexpr value_type outer_iterator::operator*() const;
+//     constexpr inner_iterator outer_iterator::value_type::begin() const noexcept;
+//     constexpr default_sentinel_t outer_iterator::value_type::end() const noexcept;
 
 #include <cassert>
 #include <compare>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/increment.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/increment.pass.cpp
index f77d20daab8a4..506695e53edd9 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/increment.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/increment.pass.cpp
@@ -10,9 +10,9 @@
 
 // <ranges>
 
-// V models only input_range:
-//   constexpr outer_iterator& operator++();
-//   constexpr void operator++(int);
+//   V models only input_range:
+//     constexpr outer_iterator& operator++();
+//     constexpr void operator++(int);
 
 #include <algorithm>
 #include <cassert>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/size.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/size.pass.cpp
index 51c7cac8da280..2863f85b21f4f 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/size.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/size.pass.cpp
@@ -10,9 +10,9 @@
 
 // <ranges>
 
-// V models only input_range:
-//   constexpr auto outer_iterator::value_type::size() const
-//     requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
+//   V models only input_range:
+//     constexpr auto outer_iterator::value_type::size() const
+//       requires sized_sentinel_for<sentinel_t<V>, iterator_t<V>>;
 
 #include <cassert>
 #include <ranges>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/types.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/types.compile.pass.cpp
index 9127e567305ce..483784d730223 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/types.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk/range.chunk.outer.iter/types.compile.pass.cpp
@@ -10,12 +10,12 @@
 
 // <ranges>
 
-// V models only input_range:
-//   class outer_iterator;
+//   V models only input_range:
+//     class outer_iterator;
 
-//   using outer_iterator::iterator_concept = input_iterator_tag;
-//   using outer_iterator::difference_type = range_difference_t<V>;
-//   class outer_iterator::value_type;
+//     using outer_iterator::iterator_concept = input_iterator_tag;
+//     using outer_iterator::difference_type = range_difference_t<V>;
+//     class outer_iterator::value_type;
 
 #include <concepts>
 #include <iterator>

>From 187687d4cda3cde7f6dfdd08096331c3500f7511 Mon Sep 17 00:00:00 2001
From: shyeyian <shyeyian at mail.shyeyian.com>
Date: Sun, 26 Jul 2026 11:41:18 +0800
Subject: [PATCH 43/43] Add [[nodiscard]] tests for full coverage

---
 .../range.chunk/nodiscard.verify.cpp          | 64 ++++++++++++++++++-
 1 file changed, 62 insertions(+), 2 deletions(-)

diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/nodiscard.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/nodiscard.verify.cpp
index 30ab0e9dade01..94df3795a40e0 100644
--- a/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.chunk/nodiscard.verify.cpp
@@ -15,9 +15,17 @@
 #include <ranges>
 #include <utility>
 
+#include "types.h"
+
 void test() {
-  char range[6] = {'x', 'x', 'y', 'y', 'z', 'z'};
-  auto view     = range | std::views::chunk(2);
+  char range[6]      = {'x', 'x', 'y', 'y', 'z', 'z'};
+  auto view          = range | std::views::chunk(2);
+  auto it            = view.begin();
+  int input_range[]  = {1, 2, 3, 4, 5, 6};
+  auto input_view    = input_span(input_range, 6) | std::views::chunk(2);
+  auto outer         = input_view.begin();
+  auto value         = *outer;
+  auto inner         = value.begin();
 
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
   view.base();
@@ -48,11 +56,63 @@ void test() {
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
   std::ranges::iter_move(std::as_const(view).end());
 
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  view.size();
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::as_const(view).size();
+
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
   *view.begin();
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
   *std::as_const(view).begin();
 
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  it.base();
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  it[0];
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  it + 1;
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  1 + it;
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  it - 1;
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  view.end() - it;
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::default_sentinel - it;
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  it - std::default_sentinel;
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  input_view.size();
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  *outer;
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::default_sentinel - outer;
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  outer - std::default_sentinel;
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  value.begin();
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  value.end();
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  value.size();
+
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  inner.base();
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  *inner;
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::default_sentinel - inner;
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  inner - std::default_sentinel;
+  // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::ranges::iter_move(inner);
+
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
   std::views::chunk(3);
   // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}



More information about the libcxx-commits mailing list