[libcxx-commits] [libcxx] [libc++][ranges] Implement P1899 `ranges::stride_view`. (PR #65200)

Will Hawkins via libcxx-commits libcxx-commits at lists.llvm.org
Sat Dec 20 00:54:35 PST 2025


https://github.com/hawkinsw updated https://github.com/llvm/llvm-project/pull/65200

>From c1be45e1d48e4e7ddb773bffc94206c3a589daa8 Mon Sep 17 00:00:00 2001
From: Will Hawkins <hawkinsw at obs.cr>
Date: Tue, 8 Aug 2023 01:04:17 -0400
Subject: [PATCH] WIP: [libc++][ranges] Implement `ranges::stride_view`.

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

Signed-off-by: Will Hawkins <hawkinsw at obs.cr>
---
 libcxx/docs/FeatureTestMacroTable.rst         |   2 +
 libcxx/docs/ReleaseNotes/20.rst               |   1 +
 libcxx/include/CMakeLists.txt                 |   1 +
 libcxx/include/__cxx03/module.modulemap       |   1 +
 libcxx/include/__ranges/stride_view.h         | 414 +++++++++++++++++
 libcxx/include/module.modulemap.in            |   4 +
 libcxx/include/ranges                         |  12 +
 libcxx/include/version                        |   2 +
 libcxx/modules/std/ranges.inc                 |   7 +-
 .../range.stride.view/ctor.assert.pass.cpp    |  27 ++
 .../iterator/base.nodiscard.verify.cpp        |  25 +
 .../iterator/dereference.nodiscard.verify.cpp |  24 +
 .../iterator/dereference.pass.cpp             |  34 ++
 .../iterator/increment.pass.cpp               |  45 ++
 .../iterator/iter_move.nodiscard.verify.cpp   |  37 ++
 .../iterator/operator.nodiscard.verify.cpp    |  64 +++
 .../iterator/operator_plus_equal.pass.cpp     |  26 ++
 .../iterator/subscript.nodiscard.verify.cpp   |  22 +
 .../range.stride.view/nodiscard.verify.cpp    |  70 +++
 .../ranges.version.compile.pass.cpp           |  30 ++
 .../version.version.compile.pass.cpp          | 204 +++++----
 .../range.stride.view/adaptor.pass.cpp        | 149 ++++++
 .../range.stride.view/base.pass.cpp           | 105 +++++
 .../range.stride.view/begin.pass.cpp          |  64 +++
 .../borrowing.compile.pass.cpp                |  19 +
 .../range.stride.view/concept.verify.cpp      |  42 ++
 .../range.stride.view/ctad.pass.cpp           |  96 ++++
 .../range.stride.view/ctor.pass.cpp           |  49 ++
 .../range.stride.view/end.pass.cpp            | 111 +++++
 .../range.stride.view/iterator/base.pass.cpp  | 132 ++++++
 .../iterator/ctor.copy.pass.cpp               | 374 +++++++++++++++
 .../iterator/ctor.default.verify.cpp          |  38 ++
 .../iterator/decrement.pass.cpp               |  93 ++++
 .../range.stride.view/iterator/equal.pass.cpp |  97 ++++
 .../iterator/greater_than.pass.cpp            | 426 ++++++++++++++++++
 .../iterator/increment.pass.cpp               | 205 +++++++++
 .../iterator/iter_move.pass.cpp               |  97 ++++
 .../iterator/iter_swap.pass.cpp               |  88 ++++
 .../iterator/less_than.pass.cpp               | 426 ++++++++++++++++++
 .../iterator/operator.pass.cpp                | 426 ++++++++++++++++++
 .../range.stride.view/iterator/plus.pass.cpp  | 103 +++++
 .../iterator/plus_equal.pass.cpp              | 109 +++++
 .../range.stride.view/size.verify.cpp         |  55 +++
 .../range.stride.view/stride.pass.cpp         |  40 ++
 .../range.adaptors/range.stride.view/types.h  | 296 ++++++++++++
 .../generate_feature_test_macro_components.py |   5 +
 46 files changed, 4598 insertions(+), 99 deletions(-)
 create mode 100644 libcxx/include/__ranges/stride_view.h
 create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/ctor.assert.pass.cpp
 create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/base.nodiscard.verify.cpp
 create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/dereference.nodiscard.verify.cpp
 create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/dereference.pass.cpp
 create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/increment.pass.cpp
 create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/iter_move.nodiscard.verify.cpp
 create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/operator.nodiscard.verify.cpp
 create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/operator_plus_equal.pass.cpp
 create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/subscript.nodiscard.verify.cpp
 create mode 100644 libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/nodiscard.verify.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/base.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/begin.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/borrowing.compile.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/concept.verify.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/end.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/base.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.copy.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.verify.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/decrement.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/equal.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/greater_than.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/increment.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/iter_move.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/iter_swap.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/less_than.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/plus.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/plus_equal.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/size.verify.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/types.h

diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 5f1e521bd79c2..299099994dc82 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -388,6 +388,8 @@ Status
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_ranges_starts_ends_with``                      ``202106L``
     ---------------------------------------------------------- -----------------
+    ``__cpp_lib_ranges_stride``                                ``202207L``
+    ---------------------------------------------------------- -----------------
     ``__cpp_lib_ranges_to_container``                          ``202202L``
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_ranges_zip``                                   *unimplemented*
diff --git a/libcxx/docs/ReleaseNotes/20.rst b/libcxx/docs/ReleaseNotes/20.rst
index 572d4321dc46f..ab6e25cf0854e 100644
--- a/libcxx/docs/ReleaseNotes/20.rst
+++ b/libcxx/docs/ReleaseNotes/20.rst
@@ -47,6 +47,7 @@ Implemented Papers
 - ``std::jthread`` and ``<stop_token>`` are not guarded behind ``-fexperimental-library`` anymore
 - P2674R1: A trait for implicit lifetime types (`Github <https://github.com/llvm/llvm-project/issues/105259>`__)
 - P0429R9: A Standard ``flat_map`` (`Github <https://github.com/llvm/llvm-project/issues/105190>`__)
+- P1899: ``stride_view`` (`Github <https://github.com/llvm/llvm-project/issues/105198>` __)
 
 Improvements and New Features
 -----------------------------
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 9df40eab678a2..7222a42350507 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -739,6 +739,7 @@ set(files
   __ranges/single_view.h
   __ranges/size.h
   __ranges/split_view.h
+  __ranges/stride_view.h
   __ranges/subrange.h
   __ranges/take_view.h
   __ranges/take_while_view.h
diff --git a/libcxx/include/__cxx03/module.modulemap b/libcxx/include/__cxx03/module.modulemap
index 34a2d0f25fc45..45e90c9b23830 100644
--- a/libcxx/include/__cxx03/module.modulemap
+++ b/libcxx/include/__cxx03/module.modulemap
@@ -1753,6 +1753,7 @@ module cxx03_std_private_ranges_size                       [system] {
   export std_private_type_traits_make_unsigned
 }
 module cxx03_std_private_ranges_split_view                 [system] { header "__ranges/split_view.h" }
+module cxx03_std_private_ranges_stride_view                [system] { header "__ranges/stride_view.h" }
 module cxx03_std_private_ranges_subrange                   [system] {
   header "__ranges/subrange.h"
   export std_private_ranges_subrange_fwd
diff --git a/libcxx/include/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h
new file mode 100644
index 0000000000000..5ca398382948b
--- /dev/null
+++ b/libcxx/include/__ranges/stride_view.h
@@ -0,0 +1,414 @@
+// -*- 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_STRIDE_VIEW_H
+#define _LIBCPP___RANGES_STRIDE_VIEW_H
+
+#include <__assert>
+#include <__compare/three_way_comparable.h>
+#include <__concepts/constructible.h>
+#include <__concepts/convertible_to.h>
+#include <__concepts/derived_from.h>
+#include <__concepts/equality_comparable.h>
+#include <__concepts/relation.h>
+#include <__config>
+#include <__functional/bind_back.h>
+#include <__functional/operations.h>
+#include <__functional/ranges_operations.h>
+#include <__iterator/advance.h>
+#include <__iterator/concepts.h>
+#include <__iterator/default_sentinel.h>
+#include <__iterator/distance.h>
+#include <__iterator/indirectly_comparable.h>
+#include <__iterator/iter_move.h>
+#include <__iterator/iter_swap.h>
+#include <__iterator/iterator_traits.h>
+#include <__ranges/access.h>
+#include <__ranges/all.h>
+#include <__ranges/concepts.h>
+#include <__ranges/enable_borrowed_range.h>
+#include <__ranges/range_adaptor.h>
+#include <__ranges/view_interface.h>
+#include <__type_traits/make_unsigned.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 _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>> {
+  _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
+  range_difference_t<_View> __stride_     = 0;
+
+  template <bool _Const>
+  class __iterator;
+
+public:
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit stride_view(_View __base, range_difference_t<_View> __stride)
+      : __base_(std::move(__base)), __stride_(__stride) {
+    _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__stride > 0, "The value of stride must be greater than 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 range_difference_t<_View> stride() const noexcept { return __stride_; }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin()
+    requires(!__simple_view<_View>)
+  {
+    return __iterator</*_Const=*/false>(this, ranges::begin(__base_), 0);
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
+    requires range<const _View>
+  {
+    return __iterator</*_Const=*/true>(this, ranges::begin(__base_), 0);
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end()
+    requires(!__simple_view<_View>)
+  {
+    if constexpr (common_range<_View> && sized_range<_View> && forward_range<_View>) {
+      auto __missing = (__stride_ - ranges::distance(__base_) % __stride_) % __stride_;
+      return __iterator</*_Const=*/false>(this, ranges::end(__base_), __missing);
+    } else if constexpr (common_range<_View> && !bidirectional_range<_View>) {
+      return __iterator</*_Const=*/false>(this, ranges::end(__base_), 0);
+    } else {
+      return default_sentinel;
+    }
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
+    requires(range<const _View>)
+  {
+    if constexpr (common_range<const _View> && sized_range<const _View> && forward_range<const _View>) {
+      auto __missing = (__stride_ - ranges::distance(__base_) % __stride_) % __stride_;
+      return __iterator</*_Const=*/true>(this, ranges::end(__base_), __missing);
+    } else if constexpr (common_range<_View> && !bidirectional_range<_View>) {
+      return __iterator</*_Const=*/true>(this, ranges::end(__base_), 0);
+    } 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_), __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_));
+  }
+}; // class stride_view
+
+template <class _Range>
+stride_view(_Range&&, range_difference_t<_Range>) -> stride_view<views::all_t<_Range>>;
+
+template <class _View>
+struct __stride_iterator_category {};
+
+template <forward_range _View>
+struct __stride_iterator_category<_View> {
+  using _Cat _LIBCPP_NODEBUG = typename iterator_traits<iterator_t<_View>>::iterator_category;
+  using iterator_category =
+      _If<derived_from<_Cat, random_access_iterator_tag>,
+          /* then */ random_access_iterator_tag,
+          /* else */ _Cat >;
+};
+
+template <input_range _View>
+  requires view<_View>
+template <bool _Const>
+class stride_view<_View>::__iterator : public __stride_iterator_category<_View> {
+  using _Parent _LIBCPP_NODEBUG = __maybe_const<_Const, stride_view<_View>>;
+  using _Base _LIBCPP_NODEBUG   = __maybe_const<_Const, _View>;
+
+  _LIBCPP_NO_UNIQUE_ADDRESS iterator_t<_Base> __current_     = iterator_t<_Base>();
+  _LIBCPP_NO_UNIQUE_ADDRESS ranges::sentinel_t<_Base> __end_ = ranges::sentinel_t<_Base>();
+  range_difference_t<_Base> __stride_                        = 0;
+  range_difference_t<_Base> __missing_                       = 0;
+
+  friend stride_view;
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator(
+      _Parent* __parent, ranges::iterator_t<_Base> __current, range_difference_t<_Base> __missing)
+      : __current_(std::move(__current)),
+        __end_(ranges::end(__parent->__base_)),
+        __stride_(__parent->__stride_),
+        __missing_(__missing) {}
+
+  static consteval auto __get_stride_view_iterator_concept() {
+    if constexpr (random_access_range<_Base>) {
+      return random_access_iterator_tag{};
+    } else if constexpr (bidirectional_range<_Base>) {
+      return bidirectional_iterator_tag{};
+    } else if constexpr (forward_range<_Base>) {
+      return forward_iterator_tag{};
+    } else {
+      return input_iterator_tag{};
+    }
+  }
+
+public:
+  using difference_type  = range_difference_t<_Base>;
+  using value_type       = range_value_t<_Base>;
+  using iterator_concept = decltype(__get_stride_view_iterator_concept());
+  // using iterator_category = inherited;
+
+  _LIBCPP_HIDE_FROM_ABI __iterator()
+    requires default_initializable<iterator_t<_Base>>
+  = default;
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator(__iterator<!_Const> __i)
+    requires _Const && convertible_to<ranges::iterator_t<_View>, iterator_t<_Base>> &&
+                 convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
+      : __current_(std::move(__i.__current_)),
+        __end_(std::move(__i.__end_)),
+        __stride_(__i.__stride_),
+        __missing_(__i.__missing_) {}
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_Base> const& base() const& noexcept { return __current_; }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_Base> base() && { return std::move(__current_); }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const {
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__current_ != __end_, "Cannot dereference an iterator at the end.");
+    return *__current_;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() {
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__current_ != __end_, "Cannot increment an iterator already at the end.");
+    __missing_ = ranges::advance(__current_, __stride_, __end_);
+    return *this;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) {
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__current_ != __end_, "Cannot increment an iterator already at the end.");
+    ++*this;
+  }
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int)
+    requires forward_range<_Base>
+  {
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__current_ != __end_, "Cannot increment an iterator already at the end.");
+    auto __tmp = *this;
+    ++*this;
+    return __tmp;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator--()
+    requires bidirectional_range<_Base>
+  {
+    ranges::advance(__current_, __missing_ - __stride_);
+    __missing_ = 0;
+    return *this;
+  }
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator--(int)
+    requires bidirectional_range<_Base>
+  {
+    auto __tmp = *this;
+    --*this;
+    return __tmp;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator+=(difference_type __n)
+    requires random_access_range<_Base>
+  {
+    if (__n > 0) {
+      _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(ranges::distance(__current_, __end_) > __stride_ * (__n - 1),
+                                          "Advancing the iterator beyond the end is not allowed.");
+      ranges::advance(__current_, __stride_ * (__n - 1));
+      __missing_ = ranges::advance(__current_, __stride_, __end_);
+
+    } else if (__n < 0) {
+      ranges::advance(__current_, __stride_ * __n + __missing_);
+      __missing_ = 0;
+    }
+    return *this;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(difference_type __n)
+    requires random_access_range<_Base>
+  {
+    return *this += -__n;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](difference_type __n) const
+    requires random_access_range<_Base>
+  {
+    return *(*this + __n);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(__iterator const& __x, default_sentinel_t) {
+    return __x.__current_ == __x.__end_;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(__iterator const& __x, __iterator const& __y)
+    requires equality_comparable<iterator_t<_Base>>
+  {
+    return __x.__current_ == __y.__current_;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<(__iterator const& __x, __iterator const& __y)
+    requires random_access_range<_Base>
+  {
+    return __x.__current_ < __y.__current_;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>(__iterator const& __x, __iterator const& __y)
+    requires random_access_range<_Base>
+  {
+    return __y < __x;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<=(__iterator const& __x, __iterator const& __y)
+    requires random_access_range<_Base>
+  {
+    return !(__y < __x);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>=(__iterator const& __x, __iterator const& __y)
+    requires random_access_range<_Base>
+  {
+    return !(__x < __y);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(__iterator const& __x, __iterator const& __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+(__iterator const& __i, difference_type __s)
+    requires random_access_range<_Base>
+  {
+    auto __r = __i;
+    __r += __s;
+    return __r;
+  }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(difference_type __s, __iterator const& __i)
+    requires random_access_range<_Base>
+  {
+    auto __r = __i;
+    __r += __s;
+    return __r;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(__iterator const& __i, difference_type __s)
+    requires random_access_range<_Base>
+  {
+    auto __r = __i;
+    __r -= __s;
+    return __r;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
+  operator-(__iterator const& __x, __iterator const& __y)
+    requires sized_sentinel_for<iterator_t<_Base>, iterator_t<_Base>>
+  {
+    if constexpr (forward_range<_Base>) {
+      auto __n = __x.__current_ - __y.__current_;
+      return (__n + __x.__missing_ - __y.__missing_) / __x.__stride_;
+    }
+    auto __n = __x.__current_ - __y.__current_;
+    if (__n < 0) {
+      return -ranges::__div_ceil(-__n, __x.__stride_);
+    }
+    return ranges::__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_);
+  }
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type
+  operator-(__iterator const& __x, default_sentinel_t __y)
+    requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>>
+  {
+    return -(__y - __x);
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr range_rvalue_reference_t<_Base>
+  iter_move(__iterator const& __it) noexcept(noexcept(ranges::iter_move(__it.__current_))) {
+    return ranges::iter_move(__it.__current_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend constexpr void
+  iter_swap(__iterator const& __x,
+            __iterator const& __y) noexcept(noexcept(ranges::iter_swap(__x.__current_, __y.__current_)))
+    requires indirectly_swappable<iterator_t<_Base>>
+  {
+    return ranges::iter_swap(__x.__current_, __y.__current_);
+  }
+}; // class stride_view::__iterator
+
+template <class _Tp>
+inline constexpr bool enable_borrowed_range<stride_view<_Tp>> = enable_borrowed_range<_Tp>;
+
+namespace views {
+namespace __stride_view {
+struct __fn {
+  // clang-format off
+  template <viewable_range _Range>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI
+  constexpr auto operator()(_Range&& __range, range_difference_t<_Range> __n) const
+    noexcept(noexcept(stride_view{std::forward<_Range>(__range), __n}))
+    -> decltype(      stride_view{std::forward<_Range>(__range), __n})
+    { return          stride_view(std::forward<_Range>(__range), __n); }
+  // clang-format on
+
+  template <class _Np>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Np&& __n) const {
+    return __pipeable(std::__bind_back(*this, std::forward<_Np>(__n)));
+  }
+};
+} // namespace __stride_view
+
+inline namespace __cpo {
+inline constexpr auto stride = __stride_view::__fn{};
+} // namespace __cpo
+} // namespace views
+
+} // namespace ranges
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___RANGES_STRIDE_VIEW_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index ce168f77dfea4..d7ead133927c4 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1925,6 +1925,10 @@ module std [system] {
     module subrange_fwd {
       header "__fwd/subrange.h"
     }
+    module stride_view {
+      header "__ranges/stride_view.h"
+      export std.functional.bind_back
+    }
     module take_view {
       header "__ranges/take_view.h"
       export std.functional.bind_back
diff --git a/libcxx/include/ranges b/libcxx/include/ranges
index aa7f0b36c3877..0a15f1dc80f16 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -385,6 +385,17 @@ namespace std::ranges {
   class chunk_by_view;                                                      // C++23
 
   namespace views { inline constexpr unspecified chunk_by = unspecified; }  // C++23
+
+  // [range.stride.view], stride view
+  template<input_range V>
+    requires view<V>
+  class stride_view;                                                       // C++23
+
+  template<class V>
+    constexpr bool enable_borrowed_range<stride_view<V>> =
+      enable_borrowed_range<V>;                                            // C++23
+
+  namespace views { inline constexpr unspecified stride = unspecified; }   // C++23
 }
 
 namespace std {
@@ -473,6 +484,7 @@ namespace std {
 #    include <__ranges/from_range.h>
 #    include <__ranges/join_with_view.h>
 #    include <__ranges/repeat_view.h>
+#    include <__ranges/stride_view.h>
 #    include <__ranges/to.h>
 #    include <__ranges/zip_transform_view.h>
 #    include <__ranges/zip_view.h>
diff --git a/libcxx/include/version b/libcxx/include/version
index c4daaffd89acf..6fc0918c5438a 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -215,6 +215,7 @@ __cpp_lib_ranges_join_with                              202202L <ranges>
 __cpp_lib_ranges_repeat                                 202207L <ranges>
 __cpp_lib_ranges_slide                                  202202L <ranges>
 __cpp_lib_ranges_starts_ends_with                       202106L <algorithm>
+__cpp_lib_ranges_stride                                 202207L <ranges>
 __cpp_lib_ranges_to_container                           202202L <ranges>
 __cpp_lib_ranges_zip                                    202110L <ranges> <tuple> <utility>
 __cpp_lib_ratio                                         202306L <ratio>
@@ -531,6 +532,7 @@ __cpp_lib_void_t                                        201411L <type_traits>
 # define __cpp_lib_ranges_repeat                        202207L
 // # define __cpp_lib_ranges_slide                         202202L
 # define __cpp_lib_ranges_starts_ends_with              202106L
+# define __cpp_lib_ranges_stride                        202207L
 # define __cpp_lib_ranges_to_container                  202202L
 // # define __cpp_lib_ranges_zip                           202110L
 // # define __cpp_lib_reference_from_temporary             202202L
diff --git a/libcxx/modules/std/ranges.inc b/libcxx/modules/std/ranges.inc
index 67e571b9567dd..947667a4e1cd9 100644
--- a/libcxx/modules/std/ranges.inc
+++ b/libcxx/modules/std/ranges.inc
@@ -301,6 +301,9 @@ export namespace std {
     namespace views {
       using std::ranges::views::zip_transform;
     }
+#endif // _LIBCPP_STD_VER >= 23
+
+#if 0
     using std::ranges::adjacent_view;
 
     namespace views {
@@ -340,16 +343,16 @@ export namespace std {
     namespace views {
       using std::ranges::views::chunk_by;
     }
-#endif // _LIBCPP_STD_VER >= 23
 
-#if 0
     // [range.stride], stride view
     using std::ranges::stride_view;
 
     namespace views {
       using std::ranges::views::stride;
     }
+#endif // _LIBCPP_STD_VER >= 23
 
+#if 0
     using std::ranges::cartesian_product_view;
 
     namespace views {
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/ctor.assert.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/ctor.assert.pass.cpp
new file mode 100644
index 0000000000000..e564891b15a15
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/ctor.assert.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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
+// XFAIL:libcpp-hardening-mode=debug && availability-verbose_abort-missing
+
+// constexpr explicit stride_view(_View, range_difference_t<_View>)
+
+#include <ranges>
+
+#include "check_assertion.h"
+
+int main(int, char**) {
+  int range[] = {1, 2, 3};
+  TEST_LIBCPP_ASSERT_FAILURE(
+      [&range] { std::ranges::stride_view sv(range, 0); }(), "The value of stride must be greater than 0");
+  TEST_LIBCPP_ASSERT_FAILURE(
+      [&range] { std::ranges::stride_view sv(range, -1); }(), "The value of stride must be greater than 0");
+
+  return 0;
+}
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/base.nodiscard.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/base.nodiscard.verify.cpp
new file mode 100644
index 0000000000000..0f64846bbff2f
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/base.nodiscard.verify.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// Test that std::ranges::stride_view::iterator::base() is marked nodiscard.
+
+#include <ranges>
+#include <utility>
+
+void test() {
+  {
+    int range[] = {1, 2, 3};
+    auto view   = std::ranges::views::stride(range, 3);
+    auto it     = view.begin();
+
+    it.base();            // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::move(it).base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+}
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/dereference.nodiscard.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/dereference.nodiscard.verify.cpp
new file mode 100644
index 0000000000000..366bcebd52d87
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/dereference.nodiscard.verify.cpp
@@ -0,0 +1,24 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// Test that std::ranges::stride_view::iterator::operator*() is marked nodiscard.
+
+#include <ranges>
+#include <utility>
+
+void test() {
+  {
+    int range[] = {1, 2, 3};
+    auto view   = std::ranges::views::stride(range, 3);
+    auto it     = view.begin();
+    ++it;
+    *std::as_const(it); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+}
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/dereference.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/dereference.pass.cpp
new file mode 100644
index 0000000000000..5094c0bf532d9
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/dereference.pass.cpp
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// REQUIRES: libcpp-hardening-mode={{fast|extensive|debug}}
+// XFAIL:libcpp-hardening-mode=debug && availability-verbose_abort-missing
+
+// constexpr decltype(auto) operator*() const
+
+#include "check_assertion.h"
+#include <ranges>
+
+int main(int, char**) {
+  {
+    int range[] = {1, 2, 3};
+    auto view   = std::ranges::views::stride(range, 3);
+    auto it     = view.begin();
+    ++it;
+    TEST_LIBCPP_ASSERT_FAILURE(*std::as_const(it), "Cannot dereference an iterator at the end.");
+  }
+  {
+    int range[] = {1, 2, 3};
+    auto view   = std::ranges::views::stride(range, 4);
+    auto it     = view.begin();
+    ++it;
+    TEST_LIBCPP_ASSERT_FAILURE(*std::as_const(it), "Cannot dereference an iterator at the end.");
+  }
+  return 0;
+}
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/increment.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/increment.pass.cpp
new file mode 100644
index 0000000000000..6cd3b11fd7e89
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/increment.pass.cpp
@@ -0,0 +1,45 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// REQUIRES: libcpp-hardening-mode={{fast|extensive|debug}}
+// XFAIL:libcpp-hardening-mode=debug && availability-verbose_abort-missing
+
+// constexpr stride_view::<iterator>& operator++()
+// constexpr __iterator& operator++()
+// constexpr void operator++(int) {
+// constexpr __iterator operator++(int)
+
+#include <ranges>
+
+#include "check_assertion.h"
+#include "test_iterators.h"
+
+#include "../../../../../std/ranges/range.adaptors/range.stride.view/types.h"
+
+int main(int, char**) {
+  {
+    int range[] = {1, 2, 3};
+    using Base  = BasicTestView<cpp17_input_iterator<int*>>;
+    auto view   = std::ranges::views::stride(Base(cpp17_input_iterator(range), cpp17_input_iterator(range + 3)), 3);
+    auto it     = view.begin();
+    ++it;
+    TEST_LIBCPP_ASSERT_FAILURE(it++, "Cannot increment an iterator already at the end.");
+    TEST_LIBCPP_ASSERT_FAILURE(++it, "Cannot increment an iterator already at the end.");
+  }
+  {
+    int range[] = {1, 2, 3};
+    using Base  = BasicTestView<forward_iterator<int*>, forward_iterator<int*>>;
+    auto view   = std::ranges::views::stride(Base(forward_iterator(range), forward_iterator(range + 3)), 3);
+    auto it     = view.begin();
+    ++it;
+    TEST_LIBCPP_ASSERT_FAILURE(it++, "Cannot increment an iterator already at the end.");
+    TEST_LIBCPP_ASSERT_FAILURE(++it, "Cannot increment an iterator already at the end.");
+  }
+  return 0;
+}
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/iter_move.nodiscard.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/iter_move.nodiscard.verify.cpp
new file mode 100644
index 0000000000000..a560bcc899841
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/iter_move.nodiscard.verify.cpp
@@ -0,0 +1,37 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// friend constexpr range_rvalue_reference_t<_Base> iter_move(__iterator const& __it)
+// noexcept(noexcept(ranges::iter_move(__it.__current_)))
+
+#include <ranges>
+
+#include "../../../../../std/ranges/range.adaptors/range.stride.view/types.h"
+
+constexpr bool test() {
+  {
+    int a[] = {4, 3, 2, 1};
+
+    int iter_move_counter(0);
+    using View       = IterMoveIterSwapTestRange<int*, true, true>;
+    using StrideView = std::ranges::stride_view<View>;
+    auto svb         = StrideView(View(a, a + 4, &iter_move_counter), 1).begin();
+
+    static_assert(std::is_same_v<int, decltype(std::ranges::iter_move(svb))>);
+    static_assert(noexcept(std::ranges::iter_move(svb)));
+
+    // These lines need to be in sync so that clang-verify knows where the warning comes from.
+    // clang-format off
+    std::ranges::iter_move( // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+        svb);
+    // clang-format on
+  }
+  return true;
+}
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/operator.nodiscard.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/operator.nodiscard.verify.cpp
new file mode 100644
index 0000000000000..e1121b7efc2bf
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/operator.nodiscard.verify.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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// Test that std::ranges::stride_view::iterator::operator- is marked nodiscard.
+
+#include <ranges>
+
+#include "../../../../../std/ranges/range.adaptors/range.stride.view/types.h"
+
+constexpr bool test_non_forward_operator_minus() {
+  int arr[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+
+  using Base = BasicTestView<SizedInputIter, SizedInputIter>;
+
+  auto base_view_offset_zero             = Base(SizedInputIter(arr), SizedInputIter(arr + 10));
+  auto base_view_offset_one              = Base(SizedInputIter(arr + 1), SizedInputIter(arr + 10));
+  auto stride_view_over_base_zero_offset = std::ranges::stride_view(base_view_offset_zero, 3);
+  auto stride_view_over_base_one_offset  = std::ranges::stride_view(base_view_offset_one, 3);
+
+  auto sv_zero_offset_begin = stride_view_over_base_zero_offset.begin();
+  auto sv_one_offset_begin  = stride_view_over_base_one_offset.begin();
+
+  sv_one_offset_begin - // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+      sv_zero_offset_begin;
+  return true;
+}
+
+constexpr bool test_forward_operator_minus() {
+  int arr[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+
+  using Base = BasicTestView<int*, int*>;
+
+  auto base_view_offset_zero             = Base(arr, arr + 10);
+  auto base_view_offset_one              = Base(arr + 1, arr + 10);
+  auto stride_view_over_base_zero_offset = std::ranges::stride_view(base_view_offset_zero, 3);
+  auto stride_view_over_base_one_offset  = std::ranges::stride_view(base_view_offset_one, 3);
+
+  auto sv_zero_offset_begin = stride_view_over_base_zero_offset.begin();
+  auto sv_one_offset_begin  = stride_view_over_base_one_offset.begin();
+
+  sv_zero_offset_begin + // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+      1;
+  1 + sv_zero_offset_begin; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+  sv_one_offset_begin - 1; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+
+  sv_one_offset_begin - // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+      sv_zero_offset_begin;
+
+  std::default_sentinel_t() - // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+      sv_zero_offset_begin;
+
+  sv_zero_offset_begin - // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+      std::default_sentinel_t();
+
+  return true;
+}
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/operator_plus_equal.pass.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/operator_plus_equal.pass.cpp
new file mode 100644
index 0000000000000..0a84436444cd5
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/operator_plus_equal.pass.cpp
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// REQUIRES: libcpp-hardening-mode={{fast|extensive|debug}}
+// XFAIL:libcpp-hardening-mode=debug && availability-verbose_abort-missing
+
+// constexpr __iterator& operator+=(difference_type __n)
+
+#include <ranges>
+
+#include "check_assertion.h"
+
+int main(int, char**) {
+  int range[] = {1, 2, 3};
+  auto view   = std::ranges::views::stride(range, 2);
+  auto it     = view.begin();
+  TEST_LIBCPP_ASSERT_FAILURE(it += 3, "Advancing the iterator beyond the end is not allowed.");
+
+  return 0;
+}
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/subscript.nodiscard.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/subscript.nodiscard.verify.cpp
new file mode 100644
index 0000000000000..cfd048b66afe4
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/iterator/subscript.nodiscard.verify.cpp
@@ -0,0 +1,22 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr decltype(auto) operator[](difference_type __n) const
+
+#include <ranges>
+
+void test() {
+  {
+    int range[] = {1, 2, 3};
+    auto view   = std::ranges::views::stride(range, 3);
+    auto it     = view.begin();
+    it[0]; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  }
+}
diff --git a/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/nodiscard.verify.cpp b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/nodiscard.verify.cpp
new file mode 100644
index 0000000000000..280d9b822f4a7
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.adaptors/range.stride.view/nodiscard.verify.cpp
@@ -0,0 +1,70 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// Test that
+// std::view::stride()
+// std::ranges::stride_view::base()
+// std::ranges::stride_view::begin()
+// std::ranges::stride_view::end()
+// std::ranges::stride_view::size()
+// std::ranges::stride_view::stride()
+// are all marked nodiscard.
+
+#include <ranges>
+
+#include "../../../../std/ranges/range.adaptors/range.stride.view/types.h"
+
+void test_base_nodiscard() {
+  const int range[] = {1, 2, 3};
+  auto sv           = std::ranges::stride_view(range, 3);
+
+  sv.base();            // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  std::move(sv).base(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+}
+
+void test_begin_nodiscard() {
+  const auto const_sv = std::views::stride(SimpleCommonConstView{}, 2);
+  auto unsimple_sv    = std::views::stride(UnSimpleConstView{}, 2);
+
+  const_sv.begin();    // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  unsimple_sv.begin(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+}
+
+void test_views_stride_nodiscard() {
+  const int range[] = {1, 2, 3};
+
+  std::views::stride( // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+      range,
+      2);
+}
+
+void test_end_nodiscard() {
+  const int range[] = {1, 2, 3};
+
+  const auto const_sv = std::views::stride(range, 2);
+  auto unsimple_sv    = std::views::stride(UnSimpleConstView{}, 2);
+
+  const_sv.end();    // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  unsimple_sv.end(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+}
+
+void test_size_nodiscard() {
+  auto sv             = std::views::stride(SimpleNoConstSizedCommonView(), 2);
+  const auto const_sv = std::views::stride(SimpleCommonConstView(), 2);
+
+  sv.size();       // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+  const_sv.size(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+}
+
+void test_stride_nodiscard() {
+  const int range[] = {1, 2, 3};
+  auto const_sv     = std::views::stride(range, 2);
+  const_sv.stride(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+}
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..8d69867feba8f 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
@@ -64,6 +64,10 @@
 #    error "__cpp_lib_ranges_slide should not be defined before c++23"
 #  endif
 
+#  ifdef __cpp_lib_ranges_stride
+#    error "__cpp_lib_ranges_stride should not be defined before c++23"
+#  endif
+
 #  ifdef __cpp_lib_ranges_to_container
 #    error "__cpp_lib_ranges_to_container should not be defined before c++23"
 #  endif
@@ -118,6 +122,10 @@
 #    error "__cpp_lib_ranges_slide should not be defined before c++23"
 #  endif
 
+#  ifdef __cpp_lib_ranges_stride
+#    error "__cpp_lib_ranges_stride should not be defined before c++23"
+#  endif
+
 #  ifdef __cpp_lib_ranges_to_container
 #    error "__cpp_lib_ranges_to_container should not be defined before c++23"
 #  endif
@@ -172,6 +180,10 @@
 #    error "__cpp_lib_ranges_slide should not be defined before c++23"
 #  endif
 
+#  ifdef __cpp_lib_ranges_stride
+#    error "__cpp_lib_ranges_stride should not be defined before c++23"
+#  endif
+
 #  ifdef __cpp_lib_ranges_to_container
 #    error "__cpp_lib_ranges_to_container should not be defined before c++23"
 #  endif
@@ -229,6 +241,10 @@
 #    error "__cpp_lib_ranges_slide should not be defined before c++23"
 #  endif
 
+#  ifdef __cpp_lib_ranges_stride
+#    error "__cpp_lib_ranges_stride should not be defined before c++23"
+#  endif
+
 #  ifdef __cpp_lib_ranges_to_container
 #    error "__cpp_lib_ranges_to_container should not be defined before c++23"
 #  endif
@@ -325,6 +341,13 @@
 #    endif
 #  endif
 
+#  ifndef __cpp_lib_ranges_stride
+#    error "__cpp_lib_ranges_stride should be defined in c++23"
+#  endif
+#  if __cpp_lib_ranges_stride != 202207L
+#    error "__cpp_lib_ranges_stride should have the value 202207L in c++23"
+#  endif
+
 #  ifndef __cpp_lib_ranges_to_container
 #    error "__cpp_lib_ranges_to_container should be defined in c++23"
 #  endif
@@ -454,6 +477,13 @@
 #    endif
 #  endif
 
+#  ifndef __cpp_lib_ranges_stride
+#    error "__cpp_lib_ranges_stride should be defined in c++26"
+#  endif
+#  if __cpp_lib_ranges_stride != 202207L
+#    error "__cpp_lib_ranges_stride should have the value 202207L in c++26"
+#  endif
+
 #  ifndef __cpp_lib_ranges_to_container
 #    error "__cpp_lib_ranges_to_container should be defined in c++26"
 #  endif
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 65cdf2ded816d..beb488d053530 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
@@ -696,6 +696,10 @@
 #    error "__cpp_lib_ranges_starts_ends_with should not be defined before c++23"
 #  endif
 
+#  ifdef __cpp_lib_ranges_stride
+#    error "__cpp_lib_ranges_stride should not be defined before c++23"
+#  endif
+
 #  ifdef __cpp_lib_ranges_to_container
 #    error "__cpp_lib_ranges_to_container should not be defined before c++23"
 #  endif
@@ -1652,6 +1656,10 @@
 #    error "__cpp_lib_ranges_starts_ends_with should not be defined before c++23"
 #  endif
 
+#  ifdef __cpp_lib_ranges_stride
+#    error "__cpp_lib_ranges_stride should not be defined before c++23"
+#  endif
+
 #  ifdef __cpp_lib_ranges_to_container
 #    error "__cpp_lib_ranges_to_container should not be defined before c++23"
 #  endif
@@ -2146,14 +2154,6 @@
 #    error "__cpp_lib_constexpr_dynamic_alloc should not be defined before c++20"
 #  endif
 
-#  ifdef __cpp_lib_constexpr_flat_map
-#    error "__cpp_lib_constexpr_flat_map should not be defined before c++26"
-#  endif
-
-#  ifdef __cpp_lib_constexpr_flat_set
-#    error "__cpp_lib_constexpr_flat_set should not be defined before c++26"
-#  endif
-
 #  ifdef __cpp_lib_constexpr_forward_list
 #    error "__cpp_lib_constexpr_forward_list should not be defined before c++26"
 #  endif
@@ -2277,7 +2277,7 @@
 #    error "__cpp_lib_expected should not be defined before c++23"
 #  endif
 
-#  if !defined(_LIBCPP_VERSION) || _LIBCPP_HAS_FILESYSTEM
+#  if !defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_FILESYSTEM && _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_LIBRARY)
 #    ifndef __cpp_lib_filesystem
 #      error "__cpp_lib_filesystem should be defined in c++17"
 #    endif
@@ -2286,7 +2286,7 @@
 #    endif
 #  else
 #    ifdef __cpp_lib_filesystem
-#      error "__cpp_lib_filesystem should not be defined when the requirement '!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_FILESYSTEM' is not met!"
+#      error "__cpp_lib_filesystem should not be defined when the requirement '!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_FILESYSTEM && _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_LIBRARY)' is not met!"
 #    endif
 #  endif
 
@@ -2779,6 +2779,10 @@
 #    error "__cpp_lib_ranges_starts_ends_with should not be defined before c++23"
 #  endif
 
+#  ifdef __cpp_lib_ranges_stride
+#    error "__cpp_lib_ranges_stride should not be defined before c++23"
+#  endif
+
 #  ifdef __cpp_lib_ranges_to_container
 #    error "__cpp_lib_ranges_to_container should not be defined before c++23"
 #  endif
@@ -3232,14 +3236,20 @@
 #    error "__cpp_lib_atomic_value_initialization should have the value 201911L in c++20"
 #  endif
 
-#  ifndef __cpp_lib_atomic_wait
-#    error "__cpp_lib_atomic_wait should be defined in c++20"
-#  endif
-#  if __cpp_lib_atomic_wait != 201907L
-#    error "__cpp_lib_atomic_wait should have the value 201907L in c++20"
+#  if !defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_SYNC
+#    ifndef __cpp_lib_atomic_wait
+#      error "__cpp_lib_atomic_wait should be defined in c++20"
+#    endif
+#    if __cpp_lib_atomic_wait != 201907L
+#      error "__cpp_lib_atomic_wait should have the value 201907L in c++20"
+#    endif
+#  else
+#    ifdef __cpp_lib_atomic_wait
+#      error "__cpp_lib_atomic_wait should not be defined when the requirement '!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_SYNC' is not met!"
+#    endif
 #  endif
 
-#  if !defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS
+#  if !defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)
 #    ifndef __cpp_lib_barrier
 #      error "__cpp_lib_barrier should be defined in c++20"
 #    endif
@@ -3248,7 +3258,7 @@
 #    endif
 #  else
 #    ifdef __cpp_lib_barrier
-#      error "__cpp_lib_barrier should not be defined when the requirement '!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS' is not met!"
+#      error "__cpp_lib_barrier should not be defined when the requirement '!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)' is not met!"
 #    endif
 #  endif
 
@@ -3371,8 +3381,8 @@
 #  ifndef __cpp_lib_concepts
 #    error "__cpp_lib_concepts should be defined in c++20"
 #  endif
-#  if __cpp_lib_concepts != 202207L
-#    error "__cpp_lib_concepts should have the value 202207L in c++20"
+#  if __cpp_lib_concepts != 202002L
+#    error "__cpp_lib_concepts should have the value 202002L in c++20"
 #  endif
 
 #  ifndef __cpp_lib_constexpr_algorithms
@@ -3408,14 +3418,6 @@
 #    error "__cpp_lib_constexpr_dynamic_alloc should have the value 201907L in c++20"
 #  endif
 
-#  ifdef __cpp_lib_constexpr_flat_map
-#    error "__cpp_lib_constexpr_flat_map should not be defined before c++26"
-#  endif
-
-#  ifdef __cpp_lib_constexpr_flat_set
-#    error "__cpp_lib_constexpr_flat_set should not be defined before c++26"
-#  endif
-
 #  ifdef __cpp_lib_constexpr_forward_list
 #    error "__cpp_lib_constexpr_forward_list should not be defined before c++26"
 #  endif
@@ -3584,7 +3586,7 @@
 #    error "__cpp_lib_expected should not be defined before c++23"
 #  endif
 
-#  if !defined(_LIBCPP_VERSION) || _LIBCPP_HAS_FILESYSTEM
+#  if !defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_FILESYSTEM && _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_LIBRARY)
 #    ifndef __cpp_lib_filesystem
 #      error "__cpp_lib_filesystem should be defined in c++20"
 #    endif
@@ -3593,7 +3595,7 @@
 #    endif
 #  else
 #    ifdef __cpp_lib_filesystem
-#      error "__cpp_lib_filesystem should not be defined when the requirement '!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_FILESYSTEM' is not met!"
+#      error "__cpp_lib_filesystem should not be defined when the requirement '!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_FILESYSTEM && _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_LIBRARY)' is not met!"
 #    endif
 #  endif
 
@@ -3893,7 +3895,7 @@
 #    error "__cpp_lib_is_within_lifetime should not be defined before c++26"
 #  endif
 
-#  if !defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS
+#  if !defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)
 #    ifndef __cpp_lib_jthread
 #      error "__cpp_lib_jthread should be defined in c++20"
 #    endif
@@ -3902,11 +3904,11 @@
 #    endif
 #  else
 #    ifdef __cpp_lib_jthread
-#      error "__cpp_lib_jthread should not be defined when the requirement '!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS' is not met!"
+#      error "__cpp_lib_jthread should not be defined when the requirement '!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)' is not met!"
 #    endif
 #  endif
 
-#  if !defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS
+#  if !defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)
 #    ifndef __cpp_lib_latch
 #      error "__cpp_lib_latch should be defined in c++20"
 #    endif
@@ -3915,7 +3917,7 @@
 #    endif
 #  else
 #    ifdef __cpp_lib_latch
-#      error "__cpp_lib_latch should not be defined when the requirement '!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS' is not met!"
+#      error "__cpp_lib_latch should not be defined when the requirement '!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)' is not met!"
 #    endif
 #  endif
 
@@ -4173,6 +4175,10 @@
 #    error "__cpp_lib_ranges_starts_ends_with should not be defined before c++23"
 #  endif
 
+#  ifdef __cpp_lib_ranges_stride
+#    error "__cpp_lib_ranges_stride should not be defined before c++23"
+#  endif
+
 #  ifdef __cpp_lib_ranges_to_container
 #    error "__cpp_lib_ranges_to_container should not be defined before c++23"
 #  endif
@@ -4249,7 +4255,7 @@
 #    endif
 #  endif
 
-#  if !defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS
+#  if !defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)
 #    ifndef __cpp_lib_semaphore
 #      error "__cpp_lib_semaphore should be defined in c++20"
 #    endif
@@ -4258,7 +4264,7 @@
 #    endif
 #  else
 #    ifdef __cpp_lib_semaphore
-#      error "__cpp_lib_semaphore should not be defined when the requirement '!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS' is not met!"
+#      error "__cpp_lib_semaphore should not be defined when the requirement '!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)' is not met!"
 #    endif
 #  endif
 
@@ -4695,14 +4701,20 @@
 #    error "__cpp_lib_atomic_value_initialization should have the value 201911L in c++23"
 #  endif
 
-#  ifndef __cpp_lib_atomic_wait
-#    error "__cpp_lib_atomic_wait should be defined in c++23"
-#  endif
-#  if __cpp_lib_atomic_wait != 201907L
-#    error "__cpp_lib_atomic_wait should have the value 201907L in c++23"
+#  if !defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_SYNC
+#    ifndef __cpp_lib_atomic_wait
+#      error "__cpp_lib_atomic_wait should be defined in c++23"
+#    endif
+#    if __cpp_lib_atomic_wait != 201907L
+#      error "__cpp_lib_atomic_wait should have the value 201907L in c++23"
+#    endif
+#  else
+#    ifdef __cpp_lib_atomic_wait
+#      error "__cpp_lib_atomic_wait should not be defined when the requirement '!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_SYNC' is not met!"
+#    endif
 #  endif
 
-#  if !defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS
+#  if !defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)
 #    ifndef __cpp_lib_barrier
 #      error "__cpp_lib_barrier should be defined in c++23"
 #    endif
@@ -4711,7 +4723,7 @@
 #    endif
 #  else
 #    ifdef __cpp_lib_barrier
-#      error "__cpp_lib_barrier should not be defined when the requirement '!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS' is not met!"
+#      error "__cpp_lib_barrier should not be defined when the requirement '!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)' is not met!"
 #    endif
 #  endif
 
@@ -4840,8 +4852,8 @@
 #  ifndef __cpp_lib_concepts
 #    error "__cpp_lib_concepts should be defined in c++23"
 #  endif
-#  if __cpp_lib_concepts != 202207L
-#    error "__cpp_lib_concepts should have the value 202207L in c++23"
+#  if __cpp_lib_concepts != 202002L
+#    error "__cpp_lib_concepts should have the value 202002L in c++23"
 #  endif
 
 #  ifndef __cpp_lib_constexpr_algorithms
@@ -4892,14 +4904,6 @@
 #    error "__cpp_lib_constexpr_dynamic_alloc should have the value 201907L in c++23"
 #  endif
 
-#  ifdef __cpp_lib_constexpr_flat_map
-#    error "__cpp_lib_constexpr_flat_map should not be defined before c++26"
-#  endif
-
-#  ifdef __cpp_lib_constexpr_flat_set
-#    error "__cpp_lib_constexpr_flat_set should not be defined before c++26"
-#  endif
-
 #  ifdef __cpp_lib_constexpr_forward_list
 #    error "__cpp_lib_constexpr_forward_list should not be defined before c++26"
 #  endif
@@ -5077,7 +5081,7 @@
 #    error "__cpp_lib_expected should have the value 202211L in c++23"
 #  endif
 
-#  if !defined(_LIBCPP_VERSION) || _LIBCPP_HAS_FILESYSTEM
+#  if !defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_FILESYSTEM && _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_LIBRARY)
 #    ifndef __cpp_lib_filesystem
 #      error "__cpp_lib_filesystem should be defined in c++23"
 #    endif
@@ -5086,7 +5090,7 @@
 #    endif
 #  else
 #    ifdef __cpp_lib_filesystem
-#      error "__cpp_lib_filesystem should not be defined when the requirement '!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_FILESYSTEM' is not met!"
+#      error "__cpp_lib_filesystem should not be defined when the requirement '!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_FILESYSTEM && _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_LIBRARY)' is not met!"
 #    endif
 #  endif
 
@@ -5425,7 +5429,7 @@
 #    error "__cpp_lib_is_within_lifetime should not be defined before c++26"
 #  endif
 
-#  if !defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS
+#  if !defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)
 #    ifndef __cpp_lib_jthread
 #      error "__cpp_lib_jthread should be defined in c++23"
 #    endif
@@ -5434,11 +5438,11 @@
 #    endif
 #  else
 #    ifdef __cpp_lib_jthread
-#      error "__cpp_lib_jthread should not be defined when the requirement '!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS' is not met!"
+#      error "__cpp_lib_jthread should not be defined when the requirement '!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)' is not met!"
 #    endif
 #  endif
 
-#  if !defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS
+#  if !defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)
 #    ifndef __cpp_lib_latch
 #      error "__cpp_lib_latch should be defined in c++23"
 #    endif
@@ -5447,7 +5451,7 @@
 #    endif
 #  else
 #    ifdef __cpp_lib_latch
-#      error "__cpp_lib_latch should not be defined when the requirement '!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS' is not met!"
+#      error "__cpp_lib_latch should not be defined when the requirement '!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)' is not met!"
 #    endif
 #  endif
 
@@ -5783,6 +5787,13 @@
 #    error "__cpp_lib_ranges_starts_ends_with should have the value 202106L in c++23"
 #  endif
 
+#  ifndef __cpp_lib_ranges_stride
+#    error "__cpp_lib_ranges_stride should be defined in c++23"
+#  endif
+#  if __cpp_lib_ranges_stride != 202207L
+#    error "__cpp_lib_ranges_stride should have the value 202207L in c++23"
+#  endif
+
 #  ifndef __cpp_lib_ranges_to_container
 #    error "__cpp_lib_ranges_to_container should be defined in c++23"
 #  endif
@@ -5880,7 +5891,7 @@
 #    endif
 #  endif
 
-#  if !defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS
+#  if !defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)
 #    ifndef __cpp_lib_semaphore
 #      error "__cpp_lib_semaphore should be defined in c++23"
 #    endif
@@ -5889,7 +5900,7 @@
 #    endif
 #  else
 #    ifdef __cpp_lib_semaphore
-#      error "__cpp_lib_semaphore should not be defined when the requirement '!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS' is not met!"
+#      error "__cpp_lib_semaphore should not be defined when the requirement '!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)' is not met!"
 #    endif
 #  endif
 
@@ -6365,8 +6376,8 @@
 #  ifndef __cpp_lib_atomic_ref
 #    error "__cpp_lib_atomic_ref should be defined in c++26"
 #  endif
-#  if __cpp_lib_atomic_ref != 202411L
-#    error "__cpp_lib_atomic_ref should have the value 202411L in c++26"
+#  if __cpp_lib_atomic_ref != 201806L
+#    error "__cpp_lib_atomic_ref should have the value 201806L in c++26"
 #  endif
 
 #  if !defined(_LIBCPP_VERSION)
@@ -6389,14 +6400,20 @@
 #    error "__cpp_lib_atomic_value_initialization should have the value 201911L in c++26"
 #  endif
 
-#  ifndef __cpp_lib_atomic_wait
-#    error "__cpp_lib_atomic_wait should be defined in c++26"
-#  endif
-#  if __cpp_lib_atomic_wait != 201907L
-#    error "__cpp_lib_atomic_wait should have the value 201907L in c++26"
+#  if !defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_SYNC
+#    ifndef __cpp_lib_atomic_wait
+#      error "__cpp_lib_atomic_wait should be defined in c++26"
+#    endif
+#    if __cpp_lib_atomic_wait != 201907L
+#      error "__cpp_lib_atomic_wait should have the value 201907L in c++26"
+#    endif
+#  else
+#    ifdef __cpp_lib_atomic_wait
+#      error "__cpp_lib_atomic_wait should not be defined when the requirement '!defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_SYNC' is not met!"
+#    endif
 #  endif
 
-#  if !defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS
+#  if !defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)
 #    ifndef __cpp_lib_barrier
 #      error "__cpp_lib_barrier should be defined in c++26"
 #    endif
@@ -6405,7 +6422,7 @@
 #    endif
 #  else
 #    ifdef __cpp_lib_barrier
-#      error "__cpp_lib_barrier should not be defined when the requirement '!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS' is not met!"
+#      error "__cpp_lib_barrier should not be defined when the requirement '!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)' is not met!"
 #    endif
 #  endif
 
@@ -6537,8 +6554,8 @@
 #  ifndef __cpp_lib_concepts
 #    error "__cpp_lib_concepts should be defined in c++26"
 #  endif
-#  if __cpp_lib_concepts != 202207L
-#    error "__cpp_lib_concepts should have the value 202207L in c++26"
+#  if __cpp_lib_concepts != 202002L
+#    error "__cpp_lib_concepts should have the value 202002L in c++26"
 #  endif
 
 #  ifndef __cpp_lib_constexpr_algorithms
@@ -6589,20 +6606,6 @@
 #    error "__cpp_lib_constexpr_dynamic_alloc should have the value 201907L in c++26"
 #  endif
 
-#  ifndef __cpp_lib_constexpr_flat_map
-#    error "__cpp_lib_constexpr_flat_map should be defined in c++26"
-#  endif
-#  if __cpp_lib_constexpr_flat_map != 202502L
-#    error "__cpp_lib_constexpr_flat_map should have the value 202502L in c++26"
-#  endif
-
-#  ifndef __cpp_lib_constexpr_flat_set
-#    error "__cpp_lib_constexpr_flat_set should be defined in c++26"
-#  endif
-#  if __cpp_lib_constexpr_flat_set != 202502L
-#    error "__cpp_lib_constexpr_flat_set should have the value 202502L in c++26"
-#  endif
-
 #  ifndef __cpp_lib_constexpr_forward_list
 #    error "__cpp_lib_constexpr_forward_list should be defined in c++26"
 #  endif
@@ -6828,7 +6831,7 @@
 #    error "__cpp_lib_expected should have the value 202211L in c++26"
 #  endif
 
-#  if !defined(_LIBCPP_VERSION) || _LIBCPP_HAS_FILESYSTEM
+#  if !defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_FILESYSTEM && _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_LIBRARY)
 #    ifndef __cpp_lib_filesystem
 #      error "__cpp_lib_filesystem should be defined in c++26"
 #    endif
@@ -6837,7 +6840,7 @@
 #    endif
 #  else
 #    ifdef __cpp_lib_filesystem
-#      error "__cpp_lib_filesystem should not be defined when the requirement '!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_FILESYSTEM' is not met!"
+#      error "__cpp_lib_filesystem should not be defined when the requirement '!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_FILESYSTEM && _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_LIBRARY)' is not met!"
 #    endif
 #  endif
 
@@ -7310,7 +7313,7 @@
 #    endif
 #  endif
 
-#  if __has_builtin(__builtin_is_within_lifetime)
+#  if !defined(_LIBCPP_VERSION)
 #    ifndef __cpp_lib_is_within_lifetime
 #      error "__cpp_lib_is_within_lifetime should be defined in c++26"
 #    endif
@@ -7319,11 +7322,11 @@
 #    endif
 #  else
 #    ifdef __cpp_lib_is_within_lifetime
-#      error "__cpp_lib_is_within_lifetime should not be defined when the requirement '__has_builtin(__builtin_is_within_lifetime)' is not met!"
+#      error "__cpp_lib_is_within_lifetime should not be defined because it is unimplemented in libc++!"
 #    endif
 #  endif
 
-#  if !defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS
+#  if !defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)
 #    ifndef __cpp_lib_jthread
 #      error "__cpp_lib_jthread should be defined in c++26"
 #    endif
@@ -7332,11 +7335,11 @@
 #    endif
 #  else
 #    ifdef __cpp_lib_jthread
-#      error "__cpp_lib_jthread should not be defined when the requirement '!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS' is not met!"
+#      error "__cpp_lib_jthread should not be defined when the requirement '!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)' is not met!"
 #    endif
 #  endif
 
-#  if !defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS
+#  if !defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)
 #    ifndef __cpp_lib_latch
 #      error "__cpp_lib_latch should be defined in c++26"
 #    endif
@@ -7345,7 +7348,7 @@
 #    endif
 #  else
 #    ifdef __cpp_lib_latch
-#      error "__cpp_lib_latch should not be defined when the requirement '!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS' is not met!"
+#      error "__cpp_lib_latch should not be defined when the requirement '!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)' is not met!"
 #    endif
 #  endif
 
@@ -7509,8 +7512,8 @@
 #  ifndef __cpp_lib_optional
 #    error "__cpp_lib_optional should be defined in c++26"
 #  endif
-#  if __cpp_lib_optional != 202506L
-#    error "__cpp_lib_optional should have the value 202506L in c++26"
+#  if __cpp_lib_optional != 202110L
+#    error "__cpp_lib_optional should have the value 202110L in c++26"
 #  endif
 
 #  ifndef __cpp_lib_optional_range_support
@@ -7714,6 +7717,13 @@
 #    error "__cpp_lib_ranges_starts_ends_with should have the value 202106L in c++26"
 #  endif
 
+#  ifndef __cpp_lib_ranges_stride
+#    error "__cpp_lib_ranges_stride should be defined in c++26"
+#  endif
+#  if __cpp_lib_ranges_stride != 202207L
+#    error "__cpp_lib_ranges_stride should have the value 202207L in c++26"
+#  endif
+
 #  ifndef __cpp_lib_ranges_to_container
 #    error "__cpp_lib_ranges_to_container should be defined in c++26"
 #  endif
@@ -7829,7 +7839,7 @@
 #    endif
 #  endif
 
-#  if !defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS
+#  if !defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)
 #    ifndef __cpp_lib_semaphore
 #      error "__cpp_lib_semaphore should be defined in c++26"
 #    endif
@@ -7838,7 +7848,7 @@
 #    endif
 #  else
 #    ifdef __cpp_lib_semaphore
-#      error "__cpp_lib_semaphore should not be defined when the requirement '!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_THREADS' is not met!"
+#      error "__cpp_lib_semaphore should not be defined when the requirement '!defined(_LIBCPP_VERSION) || (_LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC)' is not met!"
 #    endif
 #  endif
 
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
new file mode 100644
index 0000000000000..37c4a20e6a196
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/adaptor.pass.cpp
@@ -0,0 +1,149 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// std::views::stride_view
+
+#include <ranges>
+
+#include "test_iterators.h"
+#include "types.h"
+
+constexpr BasicTestView<cpp17_input_iterator<int*>> make_input_view(int* begin, int* end) {
+  return BasicTestView<cpp17_input_iterator<int*>>(cpp17_input_iterator<int*>(begin), cpp17_input_iterator<int*>(end));
+}
+
+using ForwardStrideView      = std::ranges::stride_view<BasicTestView<forward_iterator<int*>>>;
+using BidirStrideView        = std::ranges::stride_view<BasicTestView<bidirectional_iterator<int*>>>;
+using RandomAccessStrideView = std::ranges::stride_view<BasicTestView<random_access_iterator<int*>>>;
+
+using SizedForwardStrideView =
+    std::ranges::stride_view<BasicTestView<random_access_iterator<int*>, random_access_iterator<int*>>>;
+using SizedInputStrideView = std::ranges::stride_view<BasicTestView<SizedInputIter, SizedInputIter>>;
+
+static_assert(std::ranges::forward_range<ForwardStrideView>);
+static_assert(std::ranges::bidirectional_range<BidirStrideView>);
+static_assert(std::ranges::random_access_range<RandomAccessStrideView>);
+static_assert(std::ranges::forward_range<SizedForwardStrideView>);
+static_assert(std::sized_sentinel_for<std::ranges::iterator_t<SizedForwardStrideView>,
+                                      std::ranges::iterator_t<SizedForwardStrideView>>);
+static_assert(std::sized_sentinel_for<std::ranges::iterator_t<SizedInputStrideView>,
+                                      std::ranges::iterator_t<SizedInputStrideView>>);
+
+constexpr bool test() {
+  constexpr int N = 3;
+  int arr[N]      = {1, 2, 3};
+
+  // Test that `std::views::stride` is a range adaptor.
+  // Check various forms of
+
+  // view | stride
+  // two tests: first with stride of 1; second with stride of 2.
+  {
+    using View                                                          = BasicTestView<cpp17_input_iterator<int*>>;
+    auto view                                                           = make_input_view(arr, arr + N);
+    std::same_as<std::ranges::stride_view<View>> decltype(auto) strided = view | std::views::stride(1);
+    auto strided_iter                                                   = strided.begin();
+
+    // Check that the begin() iter views arr[0]
+    assert(*strided_iter == arr[0]);
+
+    // Check that the strided_iter, after advancing it 2 * 1 steps, views arr[2].
+    std::ranges::advance(strided_iter, 2);
+    assert(*strided_iter == arr[2]);
+  }
+  {
+    using View                                                          = BasicTestView<cpp17_input_iterator<int*>>;
+    auto view                                                           = make_input_view(arr, arr + N);
+    std::same_as<std::ranges::stride_view<View>> decltype(auto) strided = view | std::views::stride(2);
+    auto strided_iter                                                   = strided.begin();
+
+    assert(*strided_iter == arr[0]);
+    std::ranges::advance(strided_iter, 1);
+    assert(*strided_iter == arr[2]);
+  }
+
+  // adaptor | stride
+  // two tests: first with stride of 1; second with stride of 2.
+  const auto i2 = [](int i) { return i * 2; };
+  {
+    auto view                           = make_input_view(arr, arr + N);
+    const auto transform_stride_partial = std::views::transform(i2) | std::views::stride(1);
+
+    auto transform_stride_applied      = transform_stride_partial(view);
+    auto transform_stride_applied_iter = transform_stride_applied.begin();
+
+    assert(*transform_stride_applied_iter == i2(arr[0]));
+    std::ranges::advance(transform_stride_applied_iter, 2);
+    assert(*transform_stride_applied_iter == i2(arr[2]));
+  }
+
+  {
+    auto view                           = make_input_view(arr, arr + N);
+    const auto transform_stride_partial = std::views::transform(i2) | std::views::stride(2);
+
+    const auto transform_stride_applied = transform_stride_partial(view);
+    auto transform_stride_applied_iter  = transform_stride_applied.begin();
+
+    assert(*transform_stride_applied_iter == i2(arr[0]));
+    std::ranges::advance(transform_stride_applied_iter, 1);
+    assert(*transform_stride_applied_iter == i2(arr[2]));
+  }
+
+  // stride | adaptor
+  // two tests: first with stride of 1; second with stride of 2.
+  {
+    auto view                   = make_input_view(arr, arr + N);
+    const auto stride_transform = std::views::stride(view, 1) | std::views::transform(i2);
+
+    auto stride_transform_iter = stride_transform.begin();
+
+    assert(*stride_transform_iter == i2(arr[0]));
+    std::ranges::advance(stride_transform_iter, 2);
+    assert(*stride_transform_iter == i2(arr[2]));
+  }
+  {
+    auto view                   = make_input_view(arr, arr + N);
+    const auto stride_transform = std::views::stride(view, 2) | std::views::transform(i2);
+
+    auto stride_transform_iter = stride_transform.begin();
+
+    assert(*stride_transform_iter == i2(arr[0]));
+    std::ranges::advance(stride_transform_iter, 1);
+    assert(*stride_transform_iter == i2(arr[2]));
+  }
+
+  // Check SFINAE friendliness
+  {
+    struct NotAViewableRange {};
+    using View = BasicTestView<bidirectional_iterator<int*>>;
+
+    static_assert(!std::is_invocable_v<decltype(std::views::stride)>);
+    static_assert(!std::is_invocable_v<decltype(std::views::stride), NotAViewableRange, int>);
+
+    static_assert(CanBePiped<View, decltype(std::views::stride(5))>);
+    static_assert(CanBePiped<View&, decltype(std::views::stride(5))>);
+    static_assert(!CanBePiped<NotAViewableRange, decltype(std::views::stride(5))>);
+    static_assert(!CanBePiped<View&, decltype(std::views::stride(NotAViewableRange{}))>);
+  }
+
+  // A final sanity check.
+  {
+    static_assert(std::same_as<decltype(std::views::stride), decltype(std::ranges::views::stride)>);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/base.pass.cpp
new file mode 100644
index 0000000000000..17b5afb070b8b
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/base.pass.cpp
@@ -0,0 +1,105 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr _View base() const& requires copy_constructible<_View>;
+// constexpr _View base() &&;
+
+#include <cassert>
+#include <ranges>
+
+#include "test_iterators.h"
+#include "types.h"
+
+template <typename T>
+constexpr bool hasLValueQualifiedBase(T&& t) {
+  // Thanks to forwarding references, t's type is
+  // preserved from the caller. No matter the type of
+  // the argument, when it is used here, t is an l value
+  // (after all, it has a name). Therefore, this code
+  // will test whether the l value const-ref-qualified
+  // version of base is callable.
+  return requires { t.base(); };
+}
+
+using CopyableInputView = CopyableView<cpp17_input_iterator<int*>>;
+using MoveOnlyInputView = MoveOnlyView<cpp17_input_iterator<int*>>;
+
+constexpr bool test() {
+  int buff[]      = {1, 2, 3, 4, 5, 6, 7, 8};
+  constexpr int N = 8;
+
+  // l-value ref qualified
+  // const &
+  {
+    const auto str(std::ranges::stride_view<CopyableInputView>(
+        CopyableInputView(cpp17_input_iterator<int*>(buff), cpp17_input_iterator<int*>(buff + N)), 1));
+
+    static_assert(hasLValueQualifiedBase(str));
+
+    std::same_as<CopyableInputView> decltype(auto) s = str.base();
+    assert(*s.begin() == *buff);
+  }
+
+  // &
+  {
+    auto str(std::ranges::stride_view<CopyableInputView>(
+        CopyableInputView(cpp17_input_iterator<int*>(buff), cpp17_input_iterator<int*>(buff + N)), 1));
+
+    std::same_as<CopyableInputView> decltype(auto) s = str.base();
+    assert(*s.begin() == *buff);
+
+    static_assert(hasLValueQualifiedBase(str));
+  }
+
+  // r-value ref qualified
+  // &&
+  {
+    auto str(std::ranges::stride_view<CopyableInputView>(
+        CopyableInputView(cpp17_input_iterator<int*>(buff), cpp17_input_iterator<int*>(buff + N)), 1));
+
+    static_assert(hasLValueQualifiedBase(str));
+
+    std::same_as<CopyableInputView> decltype(auto) s = std::move(str).base();
+    assert(*s.begin() == *buff);
+  }
+
+  // const &&
+  {
+    const auto str_a(std::ranges::stride_view<CopyableInputView>(
+        CopyableInputView(cpp17_input_iterator<int*>(buff), cpp17_input_iterator<int*>(buff + N)), 1));
+
+    static_assert(hasLValueQualifiedBase(str_a));
+
+    std::same_as<CopyableInputView> decltype(auto) s = std::move(str_a).base();
+    assert(*s.begin() == *buff);
+  }
+
+  // &&
+  {
+    auto str(std::ranges::stride_view<MoveOnlyInputView>(
+        MoveOnlyInputView(cpp17_input_iterator<int*>(buff), cpp17_input_iterator<int*>(buff + N)), 1));
+
+    // Because the base of the stride view is move only,
+    // the const & version is not applicable and, therefore,
+    // there is no l-value qualified base method.
+    static_assert(!hasLValueQualifiedBase(str));
+
+    std::same_as<MoveOnlyInputView> decltype(auto) s = std::move(str).base();
+    assert(*s.begin() == *buff);
+  }
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/begin.pass.cpp
new file mode 100644
index 0000000000000..c032e1e940311
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/begin.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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr auto begin() requires(!__simple_view<_View>)
+// constexpr auto begin() const requires range<const _View>
+
+// Note: Checks here are augmented by checks in
+// iterator/ctor.copy.pass.cpp.
+
+#include <concepts>
+#include <ranges>
+
+#include "types.h"
+
+template <class T>
+concept HasConstBegin = requires(const T& ct) { ct.begin(); };
+
+template <class T>
+concept HasBegin = requires(T& t) { t.begin(); };
+
+template <class T>
+concept HasConstAndNonConstBegin = requires(T& t, const T& ct) {
+  // The return types for begin are different when this is const or not:
+  // the iterator's _Const non-type-template parameter is true in the former
+  // and false in the latter.
+  requires !std::same_as<decltype(t.begin()), decltype(ct.begin())>;
+};
+
+template <class T>
+// There is a begin but it's not const qualified => Only non-const qualified begin.
+concept HasOnlyNonConstBegin = HasBegin<T> && !HasConstBegin<T>;
+
+template <class T>
+// There is a const-qualified begin and there are not both const- and non-const qualified begin => Only const-qualified begin.
+concept HasOnlyConstBegin = HasConstBegin<T> && !HasConstAndNonConstBegin<T>;
+
+static_assert(HasOnlyNonConstBegin<std::ranges::stride_view<UnSimpleNoConstCommonView>>);
+static_assert(HasOnlyConstBegin<std::ranges::stride_view<SimpleCommonConstView>>);
+static_assert(HasConstAndNonConstBegin<std::ranges::stride_view<UnSimpleConstView>>);
+
+constexpr bool test() {
+  const auto unsimple_const_view = UnSimpleConstView();
+  const auto sv_unsimple_const   = std::ranges::stride_view(unsimple_const_view, 1);
+  static_assert(std::same_as<decltype(*sv_unsimple_const.begin()), double&>);
+
+  auto simple_const_view = SimpleCommonConstView();
+  auto sv_simple_const   = std::ranges::stride_view(simple_const_view, 1);
+  static_assert(std::same_as<decltype(*sv_simple_const.begin()), int&>);
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+  return 0;
+}
\ No newline at end of file
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/borrowing.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/borrowing.compile.pass.cpp
new file mode 100644
index 0000000000000..cfadffbda28de
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/borrowing.compile.pass.cpp
@@ -0,0 +1,19 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// template<class V>
+// inline constexpr bool enable_borrowed_range<stride_view<V>> = ranges::enable_borrowed_range<V>;
+
+#include <ranges>
+
+#include "test_range.h"
+
+static_assert(std::ranges::enable_borrowed_range< std::ranges::stride_view<BorrowedView>>);
+static_assert(!std::ranges::enable_borrowed_range< std::ranges::stride_view<NonBorrowedView>>);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/concept.verify.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/concept.verify.cpp
new file mode 100644
index 0000000000000..d580d240f7a3b
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/concept.verify.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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// expected-no-diagnostics
+
+// template <input_range _View> requires view<_View>
+
+#include "almost_satisfies_types.h"
+#include "test_iterators.h"
+#include "test_range.h"
+
+template <typename I, std::ranges::range_difference_t<I> D>
+concept CanStrideView = requires { std::ranges::stride_view<I>{I{}, D}; };
+
+// Ensure that the InputRangeNotIndirectlyReadable is a valid range.
+static_assert(std::ranges::range<InputRangeNotIndirectlyReadable>);
+// Ensure that the InputRangeNotIndirectlyReadable's is not an input range ...
+static_assert(!std::ranges::input_range<std::ranges::iterator_t<InputRangeNotIndirectlyReadable>>);
+// Because CanStrideView requires that the range/view type be default constructible, let's double check that ...
+static_assert(std::is_constructible_v<InputRangeNotIndirectlyReadable>);
+// And now, finally, let's make sure that we cannot stride over a range whose iterator is not an input iterator ...
+static_assert(!CanStrideView<InputRangeNotIndirectlyReadable, 1>);
+
+// Ensure that a range that is not a view cannot be the subject of a stride_view.
+static_assert(std::ranges::range<test_non_const_range<cpp17_input_iterator>>);
+static_assert(std::ranges::input_range<test_non_const_range<cpp17_input_iterator>>);
+static_assert(std::movable<test_non_const_range<cpp17_input_iterator>>);
+static_assert(!std::ranges::view<test_non_const_range<cpp17_input_iterator>>);
+static_assert(!CanStrideView<test_non_const_range<cpp17_input_iterator>, 1>);
+
+// And now, let's satisfy all the prerequisites and make sure that we can stride over a range (that is an input range
+// and is a view!)
+static_assert(std::ranges::range<test_view<cpp17_input_iterator>>);
+static_assert(std::ranges::input_range<test_view<cpp17_input_iterator>>);
+static_assert(std::ranges::view<test_view<cpp17_input_iterator>>);
+static_assert(CanStrideView<test_view<cpp17_input_iterator>, 1>);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.pass.cpp
new file mode 100644
index 0000000000000..df83e25d7fe6f
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctad.pass.cpp
@@ -0,0 +1,96 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// template <class _Range>
+// stride_view(_Range&&, range_difference_t<_Range>) -> stride_view<views::all_t<_Range>>;
+
+#include "types.h"
+#include <concepts>
+#include <ranges>
+
+struct View : std::ranges::view_base {
+  int* begin() const;
+  int* end() const;
+};
+
+struct Range {
+  int* begin() const;
+  int* end() const;
+};
+
+constexpr bool testCTAD() {
+  int a[] = {1, 2, 3, 4, 5};
+
+  using BaseRange = BasicTestRange<cpp17_input_iterator<int*>>;
+  using BaseView  = BasicTestView<int*>;
+
+  auto base_view          = BaseView(a, a + 5);
+  auto base_view_for_move = BaseView(a, a + 5);
+
+  auto base_range          = BaseRange(cpp17_input_iterator<int*>(a), cpp17_input_iterator<int*>(a + 5));
+  auto base_range_for_move = BaseRange(cpp17_input_iterator<int*>(a), cpp17_input_iterator<int*>(a + 5));
+
+  auto copied_stride_base_view = std::ranges::stride_view(base_view, 2);
+  auto moved_stride_base_view  = std::ranges::stride_view(std::move(base_view_for_move), 2);
+
+  auto copied_stride_base_range = std::ranges::stride_view(base_range, 2);
+  auto moved_stride_base_range  = std::ranges::stride_view(std::move(base_range_for_move), 2);
+
+  static_assert(std::same_as< decltype(copied_stride_base_view), std::ranges::stride_view<BaseView>>);
+  static_assert(std::same_as< decltype(moved_stride_base_view), std::ranges::stride_view<BaseView>>);
+
+  static_assert(
+      std::same_as< decltype(copied_stride_base_range), std::ranges::stride_view<std::ranges::ref_view<BaseRange>> >);
+  static_assert(
+      std::same_as< decltype(moved_stride_base_range), std::ranges::stride_view<std::ranges::owning_view<BaseRange>> >);
+
+  assert(*copied_stride_base_range.begin() == 1);
+  assert(*moved_stride_base_range.begin() == 1);
+
+  assert(*copied_stride_base_view.begin() == 1);
+  assert(*moved_stride_base_view.begin() == 1);
+
+  auto copied_stride_range_it = copied_stride_base_range.begin();
+  copied_stride_range_it++;
+  assert(*copied_stride_range_it == 3);
+  copied_stride_range_it++;
+  copied_stride_range_it++;
+  assert(copied_stride_range_it == copied_stride_base_range.end());
+
+  auto moved_stride_range_it = moved_stride_base_range.begin();
+  moved_stride_range_it++;
+  moved_stride_range_it++;
+  assert(*moved_stride_range_it == 5);
+  moved_stride_range_it++;
+  assert(moved_stride_range_it == moved_stride_base_range.end());
+
+  auto copied_stride_view_it = copied_stride_base_view.begin();
+  copied_stride_view_it++;
+  assert(*copied_stride_view_it == 3);
+  copied_stride_view_it++;
+  copied_stride_view_it++;
+  assert(copied_stride_view_it == copied_stride_base_view.end());
+
+  auto moved_stride_view_it = copied_stride_base_view.begin();
+  moved_stride_view_it++;
+  moved_stride_view_it++;
+  assert(*moved_stride_view_it == 5);
+  moved_stride_view_it++;
+  assert(moved_stride_view_it == moved_stride_base_view.end());
+
+  return true;
+}
+
+int main(int, char**) {
+  testCTAD();
+  static_assert(testCTAD());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
new file mode 100644
index 0000000000000..ef360c8d17eba
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/ctor.pass.cpp
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr explicit stride_view(_View, range_difference_t<_View>)
+
+#include <type_traits>
+
+#include "test_convertible.h"
+#include "test_iterators.h"
+#include "types.h"
+
+// There is no default ctor for stride_view.
+using View = BasicTestView<cpp17_input_iterator<int*>>;
+static_assert(!std::is_default_constructible_v<std::ranges::stride_view<View>>);
+
+// Test that the stride_view can only be explicitly constructed.
+static_assert(!test_convertible<std::ranges::stride_view<View>, View, int>());
+
+constexpr bool test() {
+  {
+    int arr[] = {1, 2, 3};
+    // Test that what we will stride over is move only.
+    static_assert(!std::is_copy_constructible_v<MoveOnlyView<cpp17_input_iterator<int*>>>);
+    static_assert(std::is_move_constructible_v<MoveOnlyView<cpp17_input_iterator<int*>>>);
+
+    MoveOnlyView<cpp17_input_iterator<int*>> mov(cpp17_input_iterator<int*>(arr), cpp17_input_iterator<int*>(arr + 3));
+    // Because MoveOnlyView is, well, move only, we can test that it is moved
+    // from when the stride view is constructed.
+    std::ranges::stride_view<MoveOnlyView<cpp17_input_iterator<int*>>> mosv(std::move(mov), 1);
+
+    // While we are here, make sure that the ctor captured the stride.
+    assert(mosv.stride() == 1);
+  }
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/end.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/end.pass.cpp
new file mode 100644
index 0000000000000..a33349d554761
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/end.pass.cpp
@@ -0,0 +1,111 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr auto end() requires(!__simple_view<_View>)
+// constexpr auto end() const requires(range<const _View>)
+
+// Note: Checks here are augmented by checks in
+// iterator/ctor.copy.pass.cpp.
+
+#include <ranges>
+
+#include "test_iterators.h"
+#include "types.h"
+
+template <class T>
+concept HasConstEnd = requires(const T& ct) { ct.end(); };
+
+template <class T>
+concept HasEnd = requires(T& t) { t.end(); };
+
+template <class T>
+concept HasConstAndNonConstEnd =
+    HasConstEnd<T> && requires(T& t, const T& ct) { requires !std::same_as<decltype(t.end()), decltype(ct.end())>; };
+
+template <class T>
+concept HasOnlyNonConstEnd = HasEnd<T> && !HasConstEnd<T>;
+
+template <class T>
+concept HasOnlyConstEnd = HasConstEnd<T> && !HasConstAndNonConstEnd<T>;
+
+static_assert(HasOnlyNonConstEnd<std::ranges::stride_view<UnSimpleNoConstCommonView>>);
+static_assert(HasOnlyConstEnd<std::ranges::stride_view<SimpleCommonConstView>>);
+static_assert(HasConstAndNonConstEnd<std::ranges::stride_view<UnSimpleConstView>>);
+
+constexpr bool test_non_default_sentinel() {
+  {
+    const int data[3] = {1, 2, 3};
+    // A const, simple, common-, sized- and forward-range
+    // Note: sized because it is possible to get a difference between its
+    // beginning and its end.
+    auto v  = BasicTestView<const int*, const int*>{data, data + 3};
+    auto sv = std::ranges::stride_view<BasicTestView<const int*, const int*>>(v, 1);
+    static_assert(!std::is_same_v<std::default_sentinel_t, decltype(sv.end())>);
+  }
+
+  {
+    int data[3] = {1, 2, 3};
+    // ForwardTestView is not sized and not bidirectional, but it is common.
+    // Note: It is not sized because BasicTestView has no member function named size (by default)
+    // and nor is it possible to get a difference between its beginning and its end.
+    using ForwardTestView = BasicTestView<forward_iterator<int*>, forward_iterator<int*>>;
+
+    auto v  = ForwardTestView{forward_iterator(data), forward_iterator(data + 3)};
+    auto sv = std::ranges::stride_view<ForwardTestView>(v, 1);
+    static_assert(!std::is_same_v<std::default_sentinel_t, decltype(sv.end())>);
+  }
+
+  {
+    // TODO: Start here.
+    static_assert(!simple_view<UnSimpleNoConstCommonView>);
+    static_assert(std::ranges::common_range<UnSimpleNoConstCommonView>);
+    static_assert(std::ranges::sized_range<UnSimpleNoConstCommonView>);
+    static_assert(std::ranges::forward_range<UnSimpleNoConstCommonView>);
+
+    // An unconst, unsimple, common-, sized- and forward-range
+    auto v  = UnSimpleNoConstCommonView{};
+    auto sv = std::ranges::stride_view<UnSimpleNoConstCommonView>(v, 1);
+    static_assert(!std::is_same_v<std::default_sentinel_t, decltype(sv.end())>);
+  }
+  return true;
+}
+
+constexpr bool test_default_sentinel() {
+  {
+    static_assert(!simple_view<UnsimpleUnCommonConstView>);
+    static_assert(!std::ranges::common_range<UnsimpleUnCommonConstView>);
+    static_assert(std::ranges::sized_range<UnSimpleConstView>);
+    static_assert(std::ranges::forward_range<UnSimpleConstView>);
+
+    auto v  = UnsimpleUnCommonConstView{};
+    auto sv = std::ranges::stride_view<UnsimpleUnCommonConstView>(v, 1);
+    ASSERT_SAME_TYPE(std::default_sentinel_t, decltype(sv.end()));
+  }
+
+  {
+    static_assert(simple_view<SimpleUnCommonConstView>);
+    static_assert(!std::ranges::common_range<SimpleUnCommonConstView>);
+
+    auto v  = SimpleUnCommonConstView{};
+    auto sv = std::ranges::stride_view<SimpleUnCommonConstView>(v, 1);
+
+    ASSERT_SAME_TYPE(std::default_sentinel_t, decltype(sv.end()));
+  }
+  return true;
+}
+
+int main(int, char**) {
+  test_non_default_sentinel();
+  test_default_sentinel();
+  static_assert(test_non_default_sentinel());
+  static_assert(test_default_sentinel());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/base.pass.cpp
new file mode 100644
index 0000000000000..7d32432725388
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/base.pass.cpp
@@ -0,0 +1,132 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr iterator_t<_Base> const& base() const& noexcept
+// constexpr iterator_t<_Base> base() &&
+
+#include <ranges>
+#include <type_traits>
+
+#include "../types.h"
+
+constexpr bool base_noexcept() {
+  {
+    int arr[]                         = {1, 2, 3};
+    auto stride                       = std::ranges::stride_view(arr, 1);
+    [[maybe_unused]] auto stride_iter = stride.begin();
+
+    // Check that calling base on an iterator where this is an lvalue reference
+    // is noexcept.
+    static_assert(noexcept(stride_iter.base()));
+    // Calling base on an iterator where this is an rvalue reference may except.
+    static_assert(!noexcept((std::move(stride_iter).base())));
+  }
+
+  return true;
+}
+
+constexpr bool base_const() {
+  {
+    int arr[]                         = {1, 2, 3};
+    auto stride                       = std::ranges::stride_view(arr, 1);
+    [[maybe_unused]] auto stride_iter = stride.begin();
+
+    // Calling base on an iterator where this is lvalue returns a const ref to an iterator.
+    static_assert(std::is_const_v<std::remove_reference_t<decltype(stride_iter.base())>>);
+    // Calling base on an iterator where this is an rvalue reference returns a non-const iterator.
+    static_assert(!std::is_const_v<decltype(std::move(stride_iter).base())>);
+  }
+
+  return true;
+}
+
+constexpr bool base_move() {
+  // Keep track of how many times the original iterator is moved
+  // and/or copied during the test.
+  int move_counter = 0;
+  int copy_counter = 0;
+
+  auto start         = SizedInputIter();
+  start.move_counter = &move_counter;
+  start.copy_counter = &copy_counter;
+  auto stop          = SizedInputIter();
+
+  auto view = BasicTestView<SizedInputIter>{start, stop};
+  assert(move_counter == 0);
+  // One copies of _start_ occurs when it is copied to the basic test view's member variable.
+  assert(copy_counter == 1);
+
+  auto sv = std::ranges::stride_view<BasicTestView<SizedInputIter>>(view, 1);
+  // There is a copy of _view_ made when it is passed by value.
+  // There is a move done of _view_ when it is used as the initial value of __base.
+  assert(move_counter == 1);
+  assert(copy_counter == 2);
+
+  auto svi = sv.begin();
+  // Another copy of _start_ when begin uses the iterator to the first element
+  // of the view underlying sv as the by-value parameter to the stride view iterator's
+  // constructor.
+  assert(copy_counter == 3);
+  // Another move of __start_ happens right after that when it is std::move'd to
+  // become the first __current of the iterator.
+  assert(move_counter == 2);
+
+  [[maybe_unused]] auto result = std::move(svi).base();
+  // Ensure that base std::move'd the iterator and did not copy it.
+  assert(move_counter == 3);
+  assert(copy_counter == 3);
+  return true;
+}
+
+constexpr bool base_copy() {
+  // See base_move() for complete description of when/why
+  // moves/copies take place..
+  int move_counter = 0;
+  int copy_counter = 0;
+  auto start       = SizedInputIter();
+
+  start.move_counter = &move_counter;
+  start.copy_counter = &copy_counter;
+  auto stop          = SizedInputIter();
+
+  auto view = BasicTestView<SizedInputIter>{start, stop};
+  assert(move_counter == 0);
+  assert(copy_counter == 1);
+
+  auto sv = std::ranges::stride_view<BasicTestView<SizedInputIter>>(view, 1);
+  assert(move_counter == 1);
+  assert(copy_counter == 2);
+
+  [[maybe_unused]] auto svi = sv.begin();
+  assert(copy_counter == 3);
+  assert(move_counter == 2);
+
+  [[maybe_unused]] const SizedInputIter result = svi.base();
+  // Ensure that base did _not_ std::move'd the iterator.
+  assert(move_counter == 2);
+  assert(copy_counter == 4);
+
+  return true;
+}
+
+int main(int, char**) {
+  base_noexcept();
+  static_assert(base_noexcept());
+
+  base_const();
+  static_assert(base_const());
+
+  base_move();
+  static_assert(base_move());
+
+  base_copy();
+  static_assert(base_copy());
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.copy.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.copy.pass.cpp
new file mode 100644
index 0000000000000..eb0998cb0c8bb
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.copy.pass.cpp
@@ -0,0 +1,374 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr __iterator(__iterator<!_Const> __i)
+//    requires _Const && convertible_to<ranges::iterator_t<_View>, iterator_t<_Base>> &&
+//                 convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
+
+#include <ranges>
+
+#include "../types.h"
+#include "test_macros.h"
+
+struct NotSimpleViewIterEnd;
+template <bool, bool>
+struct NotSimpleViewConstIterEnd;
+template <bool, bool>
+struct NotSimpleViewConstIterBegin;
+
+struct NotSimpleViewIterBegin : InputIter<NotSimpleViewIterBegin> {
+  template <bool CopyConvertible, bool MoveConvertible>
+  friend constexpr bool
+  operator==(const NotSimpleViewIterBegin&, const NotSimpleViewConstIterEnd<CopyConvertible, MoveConvertible>&) {
+    return true;
+  }
+  template <bool CopyConvertible, bool MoveConvertible>
+  friend constexpr bool
+  operator==(const NotSimpleViewIterBegin&, const NotSimpleViewConstIterBegin<CopyConvertible, MoveConvertible>&) {
+    return true;
+  }
+};
+
+template <bool CopyConvertible, bool MoveConvertible>
+struct NotSimpleViewConstIterBegin : InputIter<NotSimpleViewConstIterBegin<CopyConvertible, MoveConvertible>> {
+  constexpr NotSimpleViewConstIterBegin()                                              = default;
+  constexpr NotSimpleViewConstIterBegin(NotSimpleViewConstIterBegin&&)                 = default;
+  constexpr NotSimpleViewConstIterBegin& operator=(const NotSimpleViewConstIterBegin&) = default;
+  constexpr NotSimpleViewConstIterBegin& operator=(NotSimpleViewConstIterBegin&&)      = default;
+
+  constexpr NotSimpleViewConstIterBegin(const NotSimpleViewConstIterBegin&) {}
+  constexpr NotSimpleViewConstIterBegin(const NotSimpleViewIterBegin&)
+    requires CopyConvertible
+  {}
+  constexpr NotSimpleViewConstIterBegin(NotSimpleViewIterBegin&&)
+    requires MoveConvertible
+  {}
+
+  friend constexpr bool
+  operator==(const NotSimpleViewConstIterBegin<CopyConvertible, MoveConvertible>&, const NotSimpleViewIterEnd&) {
+    return true;
+  }
+  friend constexpr bool
+  operator==(const NotSimpleViewConstIterBegin<CopyConvertible, MoveConvertible>&, const NotSimpleViewIterBegin&) {
+    return true;
+  }
+};
+
+struct NotSimpleViewIterEnd : InputIter<NotSimpleViewIterEnd> {
+  template <bool CopyConvertible, bool MoveConvertible>
+  friend constexpr bool
+  operator==(const NotSimpleViewIterEnd&, const NotSimpleViewConstIterBegin<CopyConvertible, MoveConvertible>&) {
+    return true;
+  }
+  template <bool CopyConvertible, bool MoveConvertible>
+  friend constexpr bool
+  operator==(const NotSimpleViewIterEnd&, const NotSimpleViewConstIterEnd<CopyConvertible, MoveConvertible>&) {
+    return true;
+  }
+
+  friend constexpr bool operator==(const NotSimpleViewIterEnd&, const NotSimpleViewIterBegin&) { return true; }
+};
+
+template <bool CopyConvertible, bool MoveConvertible>
+struct NotSimpleViewConstIterEnd : InputIter<NotSimpleViewConstIterEnd<CopyConvertible, MoveConvertible>> {
+  constexpr NotSimpleViewConstIterEnd()                                            = default;
+  constexpr NotSimpleViewConstIterEnd(NotSimpleViewConstIterEnd&&)                 = default;
+  constexpr NotSimpleViewConstIterEnd& operator=(const NotSimpleViewConstIterEnd&) = default;
+  constexpr NotSimpleViewConstIterEnd& operator=(NotSimpleViewConstIterEnd&&)      = default;
+
+  constexpr NotSimpleViewConstIterEnd(const NotSimpleViewConstIterEnd&) {}
+  constexpr NotSimpleViewConstIterEnd(const NotSimpleViewIterEnd&)
+    requires CopyConvertible
+  {}
+  constexpr NotSimpleViewConstIterEnd(NotSimpleViewIterEnd&&)
+    requires MoveConvertible
+  {}
+
+  friend constexpr bool
+  operator==(const NotSimpleViewConstIterEnd<CopyConvertible, MoveConvertible>&, const NotSimpleViewIterEnd&) {
+    return true;
+  }
+  friend constexpr bool
+  operator==(const NotSimpleViewConstIterEnd<CopyConvertible, MoveConvertible>&, const NotSimpleViewIterBegin&) {
+    return true;
+  }
+};
+
+/*
+ * Goal: We will need a way to get a stride_view<true>::__iterator and a
+ * stride_view<false>::__iterator because those are the two possible types
+ * of the stride_view::__iterator constructor. The template value is determined
+ * by whether the stride_view::__iterator is derivative of a stride_view over a
+ * view that is simple.
+ *
+ * So, first things first, we need to build a stride_view over a (non-)simple view.
+ * There are (at least) two ways that a view can be non-simple:
+ * 1. The iterator type for const begin is different than the iterator type for begin
+ * 2. The iterator type for const end is different that the iterator type for end
+ *
+ * So, let's create two different classes where that is the case so that we can test
+ * for those conditions individually. We parameterize with a template to decide
+ * whether to
+ * 1. enable converting constructors between the non-const and the const version.
+ * That feature is important for testing the stride_view::__iterator<true> converting
+ * constructor from a stride_view::_iterator<false> iterator.
+ * 2. enable copyability. That feature is important for testing whether the requirement
+ * the that copy constructor for the stride_view::__iterator<false> type actually moves
+ * the underlying iterator.
+ */
+template <bool CopyConvertible = false, bool MoveConvertible = true>
+struct NotSimpleViewDifferentBegin : std::ranges::view_base {
+  constexpr NotSimpleViewConstIterBegin<CopyConvertible, MoveConvertible> begin() const { return {}; }
+  constexpr NotSimpleViewIterBegin begin() { return {}; }
+
+  constexpr NotSimpleViewIterEnd end() const { return {}; }
+};
+
+template <bool CopyConvertible = false, bool MoveConvertible = true>
+struct NotSimpleViewDifferentEnd : std::ranges::view_base {
+  constexpr NotSimpleViewIterBegin begin() const { return {}; }
+  constexpr NotSimpleViewConstIterEnd<CopyConvertible, MoveConvertible> end() const { return {}; }
+  constexpr NotSimpleViewIterEnd end() { return {}; }
+};
+
+constexpr bool non_simple_view_iter_ctor_test() {
+  using NotSimpleStrideView          = std::ranges::stride_view<NotSimpleViewDifferentBegin<false>>;
+  using NotSimpleStrideViewIter      = std::ranges::iterator_t<NotSimpleStrideView>;
+  using NotSimpleStrideViewIterConst = std::ranges::iterator_t<const NotSimpleStrideView>;
+  static_assert(!std::is_same_v<NotSimpleStrideViewIterConst, NotSimpleStrideViewIter>);
+  return true;
+}
+
+constexpr bool non_const_iterator_copy_ctor() {
+  // All tests share the following general configuration.
+  //
+  // Instantiate a stride view StrideView over a non-simple view (NotSimpleViewBeingStrided) whose
+  // 1. std::ranges::iterator_t<StrideView> base's type is NotSimpleViewBeingStridedIterator
+  // 2. std::ranges::iterator_t<const StrideView> base's type is NotSimpleViewBeingStridedConstIterator
+  // 3. NotSimpleViewBeingStridedIterator is ONLY move-convertible to NotSimpleViewBeingStridedConstIterator
+  // 4. std::ranges::sentinel_t are the same whether SV is const or not.
+  // 5. the type of StrideView::end is the same whether StrideView is const or not.
+  // 6. the type of StrideView::begin is stride_view::iterator<true> when StrideView is const and
+  //    stride_view::iterator<false> when StrideView is non const.
+  // Visually, it looks like this:
+  //
+  //  NotSimpleViewBeingStrided(Const)Iterator <-----
+  //                ^                               |
+  //                |                               |
+  //                | begin (const?)                |
+  //                |                               |
+  //     NotSimpleViewBeingStrided                  |
+  //                ^                               |
+  //                |                               |
+  //                | Strides over                  |
+  //                |                               |
+  //            StrideView                          |
+  //                |                               |
+  //                | begin (const?)                |
+  //                |                               |
+  //                \/                              |
+  //       StrideView(Const)Iter                    |
+  //                |                               |
+  //                | base                          |
+  //                |                               |
+  //                ---------------------------------
+
+  {
+    // Stride over non-simple view over whose iterators are copy convertible -- should look (statically)
+    // like it is possible copy construct the stride view's iterator (the move-only requirement comes from
+    // a move of the current between the copied-from iterator to the copied-to iterator).
+    using NotSimpleViewBeingStrided = NotSimpleViewDifferentEnd<true, false>;
+    // using NotSimpleViewBeingStridedIterator      = std::ranges::iterator_t<NotSimpleViewBeingStrided>;
+    // using NotSimpleViewBeingStridedConstIterator = std::ranges::iterator_t<const NotSimpleViewBeingStrided>;
+
+    using StrideView = std::ranges::stride_view<NotSimpleViewBeingStrided>;
+
+    using StrideViewIter      = std::ranges::iterator_t<StrideView>;
+    using StrideViewConstIter = std::ranges::iterator_t<const StrideView>;
+
+    // using StrideViewSentinel      = std::ranges::sentinel_t<StrideView>;
+    // using StrideViewConstSentinel = std::ranges::sentinel_t<const StrideView>;
+
+    static_assert(std::convertible_to<StrideViewIter, StrideViewConstIter>);
+    static_assert(std::constructible_from<StrideViewConstIter, StrideViewIter>);
+  }
+
+  {
+    // Stride over non-simple view over whose iterators are move convertible -- should look (statically)
+    // like it is possible copy construct the stride view's iterator (the move-only requirement comes from
+    // a move of the current between the copied-from iterator to the copied-to iterator).
+    using NotSimpleViewBeingStrided = NotSimpleViewDifferentEnd<false, true>;
+    // using NotSimpleViewBeingStridedIterator      = std::ranges::iterator_t<NotSimpleViewBeingStrided>;
+    // using NotSimpleViewBeingStridedConstIterator = std::ranges::iterator_t<const NotSimpleViewBeingStrided>;
+
+    using StrideView = std::ranges::stride_view<NotSimpleViewBeingStrided>;
+
+    using StrideViewIter      = std::ranges::iterator_t<StrideView>;
+    using StrideViewConstIter = std::ranges::iterator_t<const StrideView>;
+
+    // using StrideViewSentinel      = std::ranges::sentinel_t<StrideView>;
+    // using StrideViewConstSentinel = std::ranges::sentinel_t<const StrideView>;
+
+    static_assert(std::convertible_to<StrideViewIter, StrideViewConstIter>);
+    static_assert(std::constructible_from<StrideViewConstIter, StrideViewIter>);
+  }
+
+  {
+    // Stride over non-simple view over whose iterators are not convertible -- should not be able
+    // to copy construct the stride view's iterator.
+    using NotSimpleViewBeingStrided = NotSimpleViewDifferentEnd<false, false>;
+    // using NotSimpleViewBeingStridedIterator      = std::ranges::iterator_t<NotSimpleViewBeingStrided>;
+    // using NotSimpleViewBeingStridedConstIterator = std::ranges::iterator_t<const NotSimpleViewBeingStrided>;
+
+    using StrideView = std::ranges::stride_view<NotSimpleViewBeingStrided>;
+
+    using StrideViewIter      = std::ranges::iterator_t<StrideView>;
+    using StrideViewConstIter = std::ranges::iterator_t<const StrideView>;
+
+    // using StrideViewSentinel      = std::ranges::sentinel_t<StrideView>;
+    // using StrideViewConstSentinel = std::ranges::sentinel_t<const StrideView>;
+
+    static_assert(!std::convertible_to<StrideViewIter, StrideViewConstIter>);
+    static_assert(!std::constructible_from<StrideViewConstIter, StrideViewIter>);
+  }
+
+  {
+    // Stride over non-simple view over whose iterators are not convertible -- should not be able
+    // to copy construct the stride view's iterator.
+    using NotSimpleViewBeingStrided         = NotSimpleViewDifferentEnd<false, true>;
+    using NotSimpleViewBeingStridedIterator = std::ranges::iterator_t<NotSimpleViewBeingStrided>;
+    // using NotSimpleViewBeingStridedConstIterator = std::ranges::iterator_t<const NotSimpleViewBeingStrided>;
+
+    using StrideView = std::ranges::stride_view<NotSimpleViewBeingStrided>;
+
+    using StrideViewIter      = std::ranges::iterator_t<StrideView>;
+    using StrideViewConstIter = std::ranges::iterator_t<const StrideView>;
+
+    // using StrideViewSentinel      = std::ranges::sentinel_t<StrideView>;
+    // using StrideViewConstSentinel = std::ranges::sentinel_t<const StrideView>;
+
+    static_assert(std::convertible_to<NotSimpleViewBeingStridedIterator, NotSimpleViewBeingStridedIterator>);
+    static_assert(std::convertible_to<StrideViewIter, StrideViewConstIter>);
+
+    StrideView str{NotSimpleViewBeingStrided{}, 5};
+    // Confirm (5)
+    ASSERT_SAME_TYPE(StrideViewIter, decltype(str.begin()));
+
+    // Now, do what we wanted the whole time: make sure that we can copy construct a
+    // stride_view::iterator<true> from a stride_view::iterator<false>. The copy
+    // constructor requires that the new __current_ StrideViewConstIter (type
+    // NotSimpleViewBeingStridedConstIterator) be constructable
+    // from the moved str.begin() __current_ (type NotSimpleViewBeingStridedConstIterator).
+    StrideViewConstIter iterator_copy{str.begin()};
+  }
+
+  {
+    // Stride over non-simple view over whose iterators are copy convertible -- should look (statically)
+    // like it is possible copy construct the stride view's iterator (the move-only requirement comes from
+    // a move of the current between the copied-from iterator to the copied-to iterator).
+    using NotSimpleViewBeingStrided = NotSimpleViewDifferentBegin<true, false>;
+    // using NotSimpleViewBeingStridedIterator      = std::ranges::iterator_t<NotSimpleViewBeingStrided>;
+    // using NotSimpleViewBeingStridedConstIterator = std::ranges::iterator_t<const NotSimpleViewBeingStrided>;
+
+    using StrideView = std::ranges::stride_view<NotSimpleViewBeingStrided>;
+
+    using StrideViewIter      = std::ranges::iterator_t<StrideView>;
+    using StrideViewConstIter = std::ranges::iterator_t<const StrideView>;
+
+    // using StrideViewSentinel      = std::ranges::sentinel_t<StrideView>;
+    // using StrideViewConstSentinel = std::ranges::sentinel_t<const StrideView>;
+
+    static_assert(std::convertible_to<StrideViewIter, StrideViewConstIter>);
+    static_assert(std::constructible_from<StrideViewConstIter, StrideViewIter>);
+  }
+
+  {
+    // Stride over non-simple view over whose iterators are move convertible -- should look (statically)
+    // like it is possible copy construct the stride view's iterator (the move-only requirement comes from
+    // a move of the current between the copied-from iterator to the copied-to iterator).
+    using NotSimpleViewBeingStrided = NotSimpleViewDifferentBegin<false, true>;
+    // using NotSimpleViewBeingStridedIterator      = std::ranges::iterator_t<NotSimpleViewBeingStrided>;
+    // using NotSimpleViewBeingStridedConstIterator = std::ranges::iterator_t<const NotSimpleViewBeingStrided>;
+
+    using StrideView = std::ranges::stride_view<NotSimpleViewBeingStrided>;
+
+    using StrideViewIter      = std::ranges::iterator_t<StrideView>;
+    using StrideViewConstIter = std::ranges::iterator_t<const StrideView>;
+
+    // using StrideViewSentinel      = std::ranges::sentinel_t<StrideView>;
+    // using StrideViewConstSentinel = std::ranges::sentinel_t<const StrideView>;
+
+    static_assert(std::convertible_to<StrideViewIter, StrideViewConstIter>);
+    static_assert(std::constructible_from<StrideViewConstIter, StrideViewIter>);
+  }
+
+  {
+    // Stride over non-simple view over whose iterators are not convertible -- should not be able
+    // to copy construct the stride view's iterator.
+    using NotSimpleViewBeingStrided = NotSimpleViewDifferentBegin<false, false>;
+    // using NotSimpleViewBeingStridedIterator      = std::ranges::iterator_t<NotSimpleViewBeingStrided>;
+    // using NotSimpleViewBeingStridedConstIterator = std::ranges::iterator_t<const NotSimpleViewBeingStrided>;
+
+    using StrideView = std::ranges::stride_view<NotSimpleViewBeingStrided>;
+
+    using StrideViewIter      = std::ranges::iterator_t<StrideView>;
+    using StrideViewConstIter = std::ranges::iterator_t<const StrideView>;
+
+    // using StrideViewSentinel      = std::ranges::sentinel_t<StrideView>;
+    // using StrideViewConstSentinel = std::ranges::sentinel_t<const StrideView>;
+
+    static_assert(!std::convertible_to<StrideViewIter, StrideViewConstIter>);
+    static_assert(!std::constructible_from<StrideViewConstIter, StrideViewIter>);
+  }
+
+  {
+    // The NotSimpleViewBeingStrided template parameters mean that NotSimpleViewBeingStridedIterator
+    // can be move-converted to NotSimpleViewBeingStridedConstIterator but not copy-converted.
+    using NotSimpleViewBeingStrided              = NotSimpleViewDifferentBegin<false, true>;
+    using NotSimpleViewBeingStridedIterator      = std::ranges::iterator_t<NotSimpleViewBeingStrided>;
+    using NotSimpleViewBeingStridedConstIterator = std::ranges::iterator_t<const NotSimpleViewBeingStrided>;
+
+    using StrideView = std::ranges::stride_view<NotSimpleViewBeingStrided>;
+
+    using StrideViewIter      = std::ranges::iterator_t<StrideView>;
+    using StrideViewConstIter = std::ranges::iterator_t<const StrideView>;
+
+    using StrideViewSentinel      = std::ranges::sentinel_t<StrideView>;
+    using StrideViewConstSentinel = std::ranges::sentinel_t<const StrideView>;
+
+    // Confirm (1) and (2)
+    ASSERT_SAME_TYPE(NotSimpleViewBeingStridedIterator, decltype(std::declval<StrideViewIter>().base()));
+    ASSERT_SAME_TYPE(NotSimpleViewBeingStridedConstIterator, decltype(std::declval<StrideViewConstIter>().base()));
+    // Confirm (3)
+    static_assert(std::convertible_to<NotSimpleViewBeingStridedIterator, NotSimpleViewBeingStridedIterator>);
+    static_assert(std::convertible_to<StrideViewIter, StrideViewConstIter>);
+    // Confirm (4)
+    ASSERT_SAME_TYPE(StrideViewSentinel, StrideViewConstSentinel);
+
+    StrideView str{NotSimpleViewBeingStrided{}, 5};
+    // Confirm (5)
+    ASSERT_SAME_TYPE(StrideViewIter, decltype(str.begin()));
+
+    // Now, do what we wanted the whole time: make sure that we can copy construct a
+    // stride_view::iterator<true> from a stride_view::iterator<false>. The copy
+    // constructor requires that the new __current_ StrideViewConstIter (type
+    // NotSimpleViewBeingStridedConstIterator) be constructable
+    // from the moved str.begin() __current_ (type NotSimpleViewBeingStridedConstIterator).
+    StrideViewConstIter iterator_copy{str.begin()};
+  }
+  return true;
+}
+
+int main(int, char**) {
+  non_simple_view_iter_ctor_test();
+  static_assert(non_simple_view_iter_ctor_test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.verify.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.verify.cpp
new file mode 100644
index 0000000000000..eb90fa2e674e2
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/ctor.default.verify.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// expected-no-diagnostics
+
+// __iterator() requires default_initializable<iterator_t<_Base>> = default;
+
+#include <ranges>
+
+#include "../types.h"
+
+struct NonDefaultConstructibleIterator : InputIter<NonDefaultConstructibleIterator> {
+  NonDefaultConstructibleIterator() = delete;
+  constexpr NonDefaultConstructibleIterator(int) {}
+};
+
+struct ViewWithNonDefaultConstructibleIterator : std::ranges::view_base {
+  constexpr NonDefaultConstructibleIterator begin() const { return NonDefaultConstructibleIterator{5}; }
+  constexpr std::default_sentinel_t end() const { return {}; }
+};
+template <>
+inline constexpr bool std::ranges::enable_borrowed_range<ViewWithNonDefaultConstructibleIterator> = true;
+
+// If the type of the iterator of the range being strided is non-default
+// constructible, then the stride view's iterator should not be default
+// constructible, either!
+static_assert(!std::is_default_constructible< std::ranges::iterator_t<ViewWithNonDefaultConstructibleIterator>>());
+// If the type of the iterator of the range being strided is default
+// constructible, then the stride view's iterator should be default
+// constructible, too!
+static_assert(std::is_default_constructible<
+              std::ranges::iterator_t< std::ranges::stride_view<std::ranges::ref_view<const int[3]>>>>());
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/decrement.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/decrement.pass.cpp
new file mode 100644
index 0000000000000..4c51c4b03965b
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/decrement.pass.cpp
@@ -0,0 +1,93 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr __iterator& operator--()
+// constexpr __iterator operator--(int)
+
+#include <ranges>
+#include <vector>
+
+#include "../types.h"
+
+template <class T>
+concept CanPostDecrement = std::is_same_v<T, decltype(std::declval<T>()--)> && requires(T& t) { t--; };
+template <class T>
+concept CanPreDecrement = std::is_same_v<T, decltype(--(std::declval<T>()))> && requires(T& t) { --t; };
+
+// What operators are valid for an iterator derived from a stride view
+// over an input view.
+using InputView = BasicTestView<cpp17_input_iterator<int*>, sized_sentinel<cpp17_input_iterator<int*>>>;
+using StrideViewOverInputViewIterator = std::ranges::iterator_t<std::ranges::stride_view<InputView>>;
+
+static_assert(!std::ranges::bidirectional_range<InputView>);
+static_assert(!CanPostDecrement<StrideViewOverInputViewIterator>);
+static_assert(!CanPreDecrement<StrideViewOverInputViewIterator>);
+
+// What operators are valid for an iterator derived from a stride view
+// over a forward view.
+using ForwardView                       = BasicTestView<forward_iterator<int*>, sized_sentinel<forward_iterator<int*>>>;
+using StrideViewOverForwardViewIterator = std::ranges::iterator_t<std::ranges::stride_view<ForwardView>>;
+
+static_assert(!std::ranges::bidirectional_range<ForwardView>);
+static_assert(!CanPostDecrement<StrideViewOverForwardViewIterator>);
+static_assert(!CanPostDecrement<StrideViewOverForwardViewIterator>);
+
+// What operators are valid for an iterator derived from a stride view
+// over a bidirectional view.
+using BidirectionalView = BasicTestView<bidirectional_iterator<int*>, sized_sentinel<bidirectional_iterator<int*>>>;
+using StrideViewOverBidirectionalViewIterator = std::ranges::iterator_t<std::ranges::stride_view<BidirectionalView>>;
+
+static_assert(std::ranges::bidirectional_range<BidirectionalView>);
+static_assert(CanPostDecrement<StrideViewOverBidirectionalViewIterator>);
+static_assert(CanPostDecrement<StrideViewOverBidirectionalViewIterator>);
+
+// What operators are valid for an iterator derived from a stride view
+// over a random access view.
+using RandomAccessView                       = BasicTestView<random_access_iterator<int*>>;
+using StrideViewOverRandomAccessViewIterator = std::ranges::iterator_t<std::ranges::stride_view<RandomAccessView>>;
+
+static_assert(std::ranges::bidirectional_range<RandomAccessView>);
+static_assert(CanPostDecrement<StrideViewOverRandomAccessViewIterator>);
+static_assert(CanPostDecrement<StrideViewOverRandomAccessViewIterator>);
+
+template <typename Iter, typename Difference>
+  requires(std::bidirectional_iterator<Iter>)
+constexpr bool test_operator_decrement(Iter begin, Iter end, Difference delta) {
+  using Base = BasicTestView<Iter, Iter>;
+
+  auto base_view_offset_zero = Base(begin, end);
+  // Because of the requires on the Iter template type, we are sure
+  // that the type of sv_incr_one is a bidirectional range.
+  auto sv_incr_diff = std::ranges::stride_view(base_view_offset_zero, delta);
+  auto sv_incr_end  = sv_incr_diff.end();
+
+  // Recreate the "missing" calculation here -- to make sure that it matches.
+  auto missing = delta - (std::ranges::distance(base_view_offset_zero) % delta) % delta;
+
+  auto sought = end + (missing - delta);
+
+  assert(*sought == *(--sv_incr_end));
+  assert(*sought == *(sv_incr_end));
+
+  sv_incr_end = sv_incr_diff.end();
+  sv_incr_end--;
+  assert(*(end + (missing - delta)) == *(sv_incr_end));
+
+  return true;
+}
+
+int main(int, char**) {
+  constexpr int arr[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
+  std::vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
+  test_operator_decrement(vec.begin(), vec.end(), 3);
+  test_operator_decrement(arr, arr + 11, 3);
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/equal.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/equal.pass.cpp
new file mode 100644
index 0000000000000..c1d2c3b6d7cd9
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/equal.pass.cpp
@@ -0,0 +1,97 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// friend constexpr bool operator==(__iterator const& __x, default_sentinel_t)
+// friend constexpr bool operator==(__iterator const& __x, __iterator const& __y)
+
+#include <cassert>
+#include <ranges>
+
+#include "../types.h"
+#include "test_iterators.h"
+
+template <class Iter>
+constexpr void testOne() {
+  using Range = BasicTestView<Iter, Iter>;
+  static_assert(std::ranges::common_range<Range>);
+  using StrideView = std::ranges::stride_view<Range>;
+
+  {
+    // simple test
+    {
+      int buffer[] = {0, 1, 2, -1, 4, 5, 6, 7};
+      const Range input(Iter{buffer}, Iter{buffer + 8});
+      const StrideView sv(input, 1);
+      const StrideView sv_too(input, 2);
+      auto b     = sv.begin();
+      auto e     = sv.end();
+      auto b_too = sv_too.begin();
+
+      assert(b == b);
+      assert(!(b != b));
+
+      // When Range is a bidirectional_range, the type of e is
+      // default_sentinel_t and those do not compare to one another.
+      if constexpr (!std::ranges::bidirectional_range<Range>) {
+        assert(e == e);
+        assert(!(e != e));
+      }
+      assert(!(b == e));
+      assert(b != e);
+
+      std::advance(b, 8);
+      std::advance(b_too, 4);
+
+      assert(b == b_too);
+      assert(!(b != b_too));
+
+      assert(b == b);
+      assert(!(b != b));
+
+      // See above.
+      if constexpr (!std::ranges::bidirectional_range<Range>) {
+        assert(e == e);
+        assert(!(e != e));
+      }
+
+      assert(b == e);
+      assert(!(b != e));
+    }
+
+    // Default-constructed iterators compare equal.
+    {
+      int buffer[] = {0, 1, 2, -1, 4, 5, 6};
+      const Range input(Iter{buffer}, Iter{buffer + 7});
+      const std::ranges::stride_view sv(input, 1);
+      using StrideViewIter = decltype(sv.begin());
+      StrideViewIter i1;
+      StrideViewIter i2;
+      assert(i1 == i2);
+      assert(!(i1 != i2));
+    }
+  }
+}
+
+constexpr bool test() {
+  testOne<forward_iterator<int*>>();
+  testOne<bidirectional_iterator<int*>>();
+  testOne<random_access_iterator<int*>>();
+  testOne<contiguous_iterator<int*>>();
+  testOne<int*>();
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/greater_than.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/greater_than.pass.cpp
new file mode 100644
index 0000000000000..08845f59d58ed
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/greater_than.pass.cpp
@@ -0,0 +1,426 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr __iterator& operator++()
+// constexpr void operator++(int)
+// constexpr __iterator operator++(int)
+// constexpr __iterator& operator--()
+// constexpr __iterator operator--(int)
+// constexpr __iterator& operator+=(difference_type __n)
+// constexpr __iterator& operator-=(difference_type __n)
+// friend constexpr bool operator==(__iterator const& __x, default_sentinel_t)
+// friend constexpr bool operator==(__iterator const& __x, __iterator const& __y)
+// friend constexpr bool operator<(__iterator const& __x, __iterator const& __y)
+// friend constexpr bool operator>(__iterator const& __x, __iterator const& __y)
+// friend constexpr bool operator<=(__iterator const& __x, __iterator const& __y)
+// friend constexpr bool operator>=(__iterator const& __x, __iterator const& __y)
+// friend constexpr bool operator<=>(__iterator const& __x, __iterator const& __y)
+
+#include <functional>
+#include <iterator>
+#include <ranges>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "../types.h"
+#include "test_iterators.h"
+
+template <class T>
+concept CanPlus = std::is_same_v<T&, decltype(std::declval<T>() += 1)> && requires(T& t) { t += 1; };
+template <class T>
+concept CanMinusEqual = std::is_same_v<T&, decltype(std::declval<T>() -= 1)> && requires(T& t) { t -= 1; };
+
+template <class T>
+concept CanMinus =
+    // Note: Do *not* use std::iterator_traits here because T may not have
+    // all the required pieces when it is not a forward_range.
+    std::is_same_v<typename T::difference_type, decltype(std::declval<T>() - std::declval<T>())> &&
+    requires(T& t) { t - t; };
+
+template <class T>
+concept CanSentinelMinus =
+    // Note: Do *not* use std::iterator_traits here because T may not have
+    // all the required pieces when it is not a forward_range.
+    std::is_same_v<typename T::difference_type, decltype(std::declval<T>() - std::default_sentinel)> &&
+    std::is_same_v<typename T::difference_type, decltype(std::default_sentinel - std::declval<T>())> && requires(T& t) {
+      t - std::default_sentinel;
+      std::default_sentinel - t;
+    };
+
+template <class T>
+concept CanDifferencePlus = std::is_same_v<T, decltype(std::declval<T>() + 1)> && requires(T& t) {
+  t + 1;
+} && std::is_same_v<T, decltype(1 + std::declval<T>())> && requires(T& t) { 1 + t; };
+template <class T>
+concept CanDifferenceMinus = std::is_same_v<T, decltype(std::declval<T>() - 1)> && requires(T& t) { t - 1; };
+
+template <class T>
+concept CanPostDecrement = std::is_same_v<T, decltype(std::declval<T>()--)> && requires(T& t) { t--; };
+template <class T>
+concept CanPreDecrement = std::is_same_v<T&, decltype(--std::declval<T>())> && requires(T& t) { --t; };
+
+template <class T>
+concept CanSubscript = requires(T& t) { t[5]; };
+
+// What operators are valid for an iterator derived from a stride view
+// over an input view.(sized sentinel)
+using InputView = BasicTestView<cpp17_input_iterator<int*>, sized_sentinel<cpp17_input_iterator<int*>>>;
+using StrideViewOverInputViewIterator = std::ranges::iterator_t<std::ranges::stride_view<InputView>>;
+
+static_assert(std::weakly_incrementable<StrideViewOverInputViewIterator>);
+
+static_assert(!CanPostDecrement<StrideViewOverInputViewIterator>);
+static_assert(!CanPreDecrement<StrideViewOverInputViewIterator>);
+static_assert(!CanPlus<StrideViewOverInputViewIterator>);
+static_assert(!CanMinusEqual<StrideViewOverInputViewIterator>);
+static_assert(!CanMinus<StrideViewOverInputViewIterator>);
+static_assert(!CanDifferencePlus<StrideViewOverInputViewIterator>);
+static_assert(!CanDifferenceMinus<StrideViewOverInputViewIterator>);
+static_assert(CanSentinelMinus<StrideViewOverInputViewIterator>);
+static_assert(std::invocable<std::equal_to<>, StrideViewOverInputViewIterator, StrideViewOverInputViewIterator>);
+static_assert(std::invocable<std::equal_to<>, StrideViewOverInputViewIterator, std::default_sentinel_t>);
+static_assert(std::invocable<std::equal_to<>, std::default_sentinel_t, StrideViewOverInputViewIterator>);
+
+static_assert(!std::is_invocable_v<std::less<>, StrideViewOverInputViewIterator, StrideViewOverInputViewIterator>);
+static_assert(
+    !std::is_invocable_v<std::less_equal<>, StrideViewOverInputViewIterator, StrideViewOverInputViewIterator>);
+static_assert(!std::is_invocable_v<std::greater<>, StrideViewOverInputViewIterator, StrideViewOverInputViewIterator>);
+static_assert(
+    !std::is_invocable_v<std::greater_equal<>, StrideViewOverInputViewIterator, StrideViewOverInputViewIterator>);
+
+static_assert(!CanSubscript<StrideViewOverInputViewIterator>);
+
+// What operators are valid for an iterator derived from a stride view
+// over a forward view.(sized sentinel)
+using ForwardView                       = BasicTestView<forward_iterator<int*>, sized_sentinel<forward_iterator<int*>>>;
+using StrideViewOverForwardViewIterator = std::ranges::iterator_t<std::ranges::stride_view<ForwardView>>;
+
+static_assert(std::weakly_incrementable<StrideViewOverForwardViewIterator>);
+
+static_assert(!CanPostDecrement<StrideViewOverForwardViewIterator>);
+static_assert(!CanPreDecrement<StrideViewOverForwardViewIterator>);
+static_assert(!CanPlus<StrideViewOverForwardViewIterator>);
+static_assert(!CanMinusEqual<StrideViewOverForwardViewIterator>);
+static_assert(!CanMinus<StrideViewOverForwardViewIterator>);
+static_assert(!CanDifferencePlus<StrideViewOverForwardViewIterator>);
+static_assert(!CanDifferenceMinus<StrideViewOverForwardViewIterator>);
+static_assert(CanSentinelMinus<StrideViewOverForwardViewIterator>);
+static_assert(std::invocable<std::equal_to<>, StrideViewOverForwardViewIterator, StrideViewOverForwardViewIterator>);
+static_assert(std::invocable<std::equal_to<>, StrideViewOverForwardViewIterator, std::default_sentinel_t>);
+static_assert(std::invocable<std::equal_to<>, std::default_sentinel_t, StrideViewOverForwardViewIterator>);
+
+static_assert(!std::is_invocable_v<std::less<>, StrideViewOverForwardViewIterator, StrideViewOverForwardViewIterator>);
+static_assert(
+    !std::is_invocable_v<std::less_equal<>, StrideViewOverForwardViewIterator, StrideViewOverForwardViewIterator>);
+static_assert(
+    !std::is_invocable_v<std::greater<>, StrideViewOverForwardViewIterator, StrideViewOverForwardViewIterator>);
+static_assert(
+    !std::is_invocable_v<std::greater_equal<>, StrideViewOverForwardViewIterator, StrideViewOverForwardViewIterator>);
+
+static_assert(!CanSubscript<StrideViewOverForwardViewIterator>);
+
+// What operators are valid for an iterator derived from a stride view
+// over a bidirectional view. (sized sentinel)
+using BidirectionalView = BasicTestView<bidirectional_iterator<int*>, sized_sentinel<bidirectional_iterator<int*>>>;
+using StrideViewOverBidirectionalViewIterator = std::ranges::iterator_t<std::ranges::stride_view<BidirectionalView>>;
+
+static_assert(CanPostDecrement<StrideViewOverBidirectionalViewIterator>);
+static_assert(CanPreDecrement<StrideViewOverBidirectionalViewIterator>);
+static_assert(!CanPlus<StrideViewOverBidirectionalViewIterator>);
+static_assert(!CanMinusEqual<StrideViewOverBidirectionalViewIterator>);
+static_assert(!CanMinus<StrideViewOverBidirectionalViewIterator>);
+static_assert(!CanDifferencePlus<StrideViewOverBidirectionalViewIterator>);
+static_assert(!CanDifferenceMinus<StrideViewOverBidirectionalViewIterator>);
+static_assert(CanSentinelMinus<StrideViewOverBidirectionalViewIterator>);
+static_assert(
+    std::invocable<std::equal_to<>, StrideViewOverBidirectionalViewIterator, StrideViewOverBidirectionalViewIterator>);
+static_assert(std::invocable<std::equal_to<>, StrideViewOverBidirectionalViewIterator, std::default_sentinel_t>);
+static_assert(std::invocable<std::equal_to<>, std::default_sentinel_t, StrideViewOverBidirectionalViewIterator>);
+
+static_assert(!std::is_invocable_v<std::less<>,
+                                   StrideViewOverBidirectionalViewIterator,
+                                   StrideViewOverBidirectionalViewIterator>);
+static_assert(!std::is_invocable_v<std::less_equal<>,
+                                   StrideViewOverBidirectionalViewIterator,
+                                   StrideViewOverBidirectionalViewIterator>);
+static_assert(!std::is_invocable_v<std::greater<>,
+                                   StrideViewOverBidirectionalViewIterator,
+                                   StrideViewOverBidirectionalViewIterator>);
+static_assert(!std::is_invocable_v<std::greater_equal<>,
+                                   StrideViewOverBidirectionalViewIterator,
+                                   StrideViewOverBidirectionalViewIterator>);
+
+static_assert(!CanSubscript<StrideViewOverBidirectionalViewIterator>);
+
+// What operators are valid for an iterator derived from a stride view
+// over a random access view. (non sized sentinel)
+using RandomAccessView                       = BasicTestView<random_access_iterator<int*>>;
+using StrideViewOverRandomAccessViewIterator = std::ranges::iterator_t<std::ranges::stride_view<RandomAccessView>>;
+
+static_assert(std::weakly_incrementable<StrideViewOverRandomAccessViewIterator>);
+
+static_assert(CanPostDecrement<StrideViewOverRandomAccessViewIterator>);
+static_assert(CanPreDecrement<StrideViewOverRandomAccessViewIterator>);
+static_assert(CanPlus<StrideViewOverRandomAccessViewIterator>);
+static_assert(CanMinusEqual<StrideViewOverRandomAccessViewIterator>);
+static_assert(CanMinus<StrideViewOverRandomAccessViewIterator>);
+static_assert(CanDifferencePlus<StrideViewOverRandomAccessViewIterator>);
+static_assert(CanDifferenceMinus<StrideViewOverRandomAccessViewIterator>);
+static_assert(!CanSentinelMinus<StrideViewOverRandomAccessViewIterator>);
+static_assert(
+    std::invocable<std::equal_to<>, StrideViewOverRandomAccessViewIterator, StrideViewOverRandomAccessViewIterator>);
+static_assert(std::invocable<std::equal_to<>, StrideViewOverRandomAccessViewIterator, std::default_sentinel_t>);
+static_assert(std::invocable<std::equal_to<>, std::default_sentinel_t, StrideViewOverRandomAccessViewIterator>);
+
+static_assert(
+    std::is_invocable_v<std::less<>, StrideViewOverRandomAccessViewIterator, StrideViewOverRandomAccessViewIterator>);
+static_assert(std::is_invocable_v<std::less_equal<>,
+                                  StrideViewOverRandomAccessViewIterator,
+                                  StrideViewOverRandomAccessViewIterator>);
+static_assert(std::is_invocable_v<std::greater<>,
+                                  StrideViewOverRandomAccessViewIterator,
+                                  StrideViewOverRandomAccessViewIterator>);
+static_assert(std::is_invocable_v<std::greater_equal<>,
+                                  StrideViewOverRandomAccessViewIterator,
+                                  StrideViewOverRandomAccessViewIterator>);
+
+static_assert(CanSubscript<StrideViewOverRandomAccessViewIterator>);
+
+using EqualableView               = BasicTestView<cpp17_input_iterator<int*>>;
+using EqualableViewStrideView     = std::ranges::stride_view<EqualableView>;
+using EqualableViewStrideViewIter = std::ranges::iterator_t<EqualableViewStrideView>;
+
+static_assert(std::equality_comparable<std::ranges::iterator_t<EqualableView>>);
+static_assert(std::equality_comparable<EqualableViewStrideViewIter>);
+
+static_assert(!std::three_way_comparable<std::ranges::iterator_t<EqualableView>>);
+static_assert(!std::ranges::random_access_range<EqualableView>);
+static_assert(!std::three_way_comparable<EqualableView>);
+
+using ThreeWayComparableView           = BasicTestView<three_way_contiguous_iterator<int*>>;
+using ThreeWayComparableViewStrideView = std::ranges::stride_view<ThreeWayComparableView>;
+using ThreeWayComparableStrideViewIter = std::ranges::iterator_t<ThreeWayComparableViewStrideView>;
+
+static_assert(std::three_way_comparable<std::ranges::iterator_t<ThreeWayComparableView>>);
+static_assert(std::ranges::random_access_range<ThreeWayComparableView>);
+static_assert(std::three_way_comparable<ThreeWayComparableStrideViewIter>);
+
+using UnEqualableView               = ViewOverNonCopyableIterator<cpp20_input_iterator<int*>>;
+using UnEqualableViewStrideView     = std::ranges::stride_view<UnEqualableView>;
+using UnEqualableViewStrideViewIter = std::ranges::iterator_t<UnEqualableViewStrideView>;
+
+static_assert(!std::equality_comparable<std::ranges::iterator_t<UnEqualableView>>);
+static_assert(!std::equality_comparable<UnEqualableViewStrideViewIter>);
+
+static_assert(!std::three_way_comparable<std::ranges::iterator_t<UnEqualableView>>);
+static_assert(!std::ranges::random_access_range<UnEqualableView>);
+static_assert(!std::three_way_comparable<UnEqualableView>);
+
+template <typename Iter>
+  requires std::sized_sentinel_for<Iter, Iter> && (!std::forward_iterator<Iter>)
+constexpr bool test_non_forward_operator_minus(Iter zero_begin, Iter one_begin, Iter end) {
+  using Base = BasicTestView<Iter, Iter>;
+  // Test the non-forward-range operator- between two iterators (i.e., ceil) and an
+  // iterator and a default sentinel.
+  using StrideViewIterator = std::ranges::iterator_t<std::ranges::stride_view<Base>>;
+  static_assert(std::weakly_incrementable<StrideViewIterator>);
+  static_assert(!std::ranges::forward_range<Base>);
+
+  // First, what operators are valid for an iterator derived from a stride view
+  // over a sized input view.
+
+  static_assert(!CanPostDecrement<StrideViewIterator>);
+  static_assert(!CanPreDecrement<StrideViewIterator>);
+  static_assert(!CanPlus<StrideViewIterator>);
+  static_assert(!CanMinusEqual<StrideViewIterator>);
+  static_assert(!CanDifferencePlus<StrideViewIterator>);
+  static_assert(!CanDifferenceMinus<StrideViewIterator>);
+  static_assert(CanSentinelMinus<StrideViewIterator>);
+
+  static_assert(!std::is_invocable_v<std::less<>, StrideViewIterator, StrideViewIterator>);
+  static_assert(!std::is_invocable_v<std::less_equal<>, StrideViewIterator, StrideViewIterator>);
+  static_assert(!std::is_invocable_v<std::greater<>, StrideViewIterator, StrideViewIterator>);
+  static_assert(!std::is_invocable_v<std::greater_equal<>, StrideViewIterator, StrideViewIterator>);
+  static_assert(std::is_invocable_v<std::equal_to<>, StrideViewIterator, StrideViewIterator>);
+  static_assert(std::is_invocable_v<std::equal_to<>, std::default_sentinel_t, StrideViewIterator>);
+  static_assert(std::is_invocable_v<std::equal_to<>, StrideViewIterator, std::default_sentinel_t>);
+  static_assert(!CanSubscript<StrideViewIterator>);
+
+  auto base_view_offset_zero             = Base(zero_begin, end);
+  auto base_view_offset_one              = Base(one_begin, end);
+  auto stride_view_over_base_zero_offset = std::ranges::stride_view(base_view_offset_zero, 3);
+  auto stride_view_over_base_one_offset  = std::ranges::stride_view(base_view_offset_one, 3);
+
+  auto sv_zero_offset_begin = stride_view_over_base_zero_offset.begin();
+  auto sv_one_offset_begin  = stride_view_over_base_one_offset.begin();
+
+  auto sv_zero_offset_zeroth_index = sv_zero_offset_begin;
+  auto sv_zero_offset_third_index  = ++sv_zero_offset_begin; // With a stride of 3, so ++ moves 3 indexes.
+  auto sv_zero_offset_sixth_index  = ++sv_zero_offset_begin; // With a stride of 3, so ++ moves 3 indexes.
+
+  auto sv_one_offset_oneth_index  = sv_one_offset_begin;
+  auto sv_one_offset_fourth_index = ++sv_one_offset_begin; // With a stride of 3, so ++ moves 3 indexes.
+
+  static_assert(std::sized_sentinel_for<std::ranges::iterator_t<Base>, std::ranges::iterator_t<Base>>);
+  static_assert(CanMinus<decltype(sv_zero_offset_begin)>);
+
+  // Check positive __n with exact multiple of left's stride.
+  assert(sv_zero_offset_third_index - sv_zero_offset_zeroth_index == 1);
+  assert(sv_zero_offset_sixth_index - sv_zero_offset_zeroth_index == 2);
+  // Check positive __n with non-exact multiple of left's stride (will do ceil here).
+  assert(sv_one_offset_oneth_index - sv_zero_offset_zeroth_index == 1);
+  assert(sv_one_offset_fourth_index - sv_zero_offset_zeroth_index == 2);
+
+  // Check negative __n with exact multiple of left's stride.
+  assert(sv_zero_offset_zeroth_index - sv_zero_offset_third_index == -1);
+  assert(sv_zero_offset_zeroth_index - sv_zero_offset_sixth_index == -2);
+  // Check negative __n with non-exact multiple of left's stride (will do ceil here).
+  assert(sv_zero_offset_zeroth_index - sv_one_offset_oneth_index == -1);
+  assert(sv_zero_offset_zeroth_index - sv_one_offset_fourth_index == -2);
+
+  assert(stride_view_over_base_zero_offset.end() == std::default_sentinel);
+  assert(std::default_sentinel == stride_view_over_base_zero_offset.end());
+
+  assert(std::default_sentinel - stride_view_over_base_zero_offset.end() == 0);
+  assert(stride_view_over_base_zero_offset.end() - std::default_sentinel == 0);
+  // assert((std::default_sentinel - )== 0);
+
+  assert(std::default_sentinel - stride_view_over_base_zero_offset.begin() ==
+         std::ranges::distance(stride_view_over_base_zero_offset));
+  assert(stride_view_over_base_zero_offset.begin() - std::default_sentinel ==
+         -std::ranges::distance(stride_view_over_base_zero_offset));
+
+  return true;
+}
+
+template <std::forward_iterator Iter, typename difference_type>
+constexpr bool test_forward_operator_minus(Iter begin, Iter end, difference_type distance) {
+  // Test the forward-range operator- between two iterators (i.e., no ceil) and
+  // an iterator and a default sentinel.
+  using Base = BasicTestView<Iter, Iter>;
+
+  using StrideViewIterator = std::ranges::iterator_t<std::ranges::stride_view<Base>>;
+  static_assert(std::ranges::forward_range<Base>);
+  static_assert(std::weakly_incrementable<StrideViewIterator>);
+
+  // First, what operators are valid for an iterator derived from a stride view
+  // over a sized forward view (even though it is actually much more than that!).
+
+  static_assert(CanMinus<StrideViewIterator>);
+  static_assert(CanSentinelMinus<StrideViewIterator>);
+
+  auto base_view_offset_zero             = Base(begin, end);
+  auto base_view_offset_one              = Base(begin + 1, end);
+  auto stride_view_over_base_zero_offset = std::ranges::stride_view(base_view_offset_zero, 3);
+  auto stride_view_over_base_one_offset  = std::ranges::stride_view(base_view_offset_one, 3);
+
+  auto sv_zero_offset_begin = stride_view_over_base_zero_offset.begin();
+  auto sv_one_offset_begin  = stride_view_over_base_one_offset.begin();
+
+  auto sv_zero_offset_should_be_one   = sv_zero_offset_begin;
+  auto sv_zero_offset_should_be_four  = ++sv_zero_offset_begin;
+  auto sv_zero_offset_should_be_seven = ++sv_zero_offset_begin;
+
+  auto sv_one_offset_should_be_two  = sv_one_offset_begin;
+  auto sv_one_offset_should_be_five = ++sv_one_offset_begin;
+
+  static_assert(std::sized_sentinel_for<std::ranges::iterator_t<Base>, std::ranges::iterator_t<Base>>);
+  static_assert(CanMinus<decltype(sv_zero_offset_begin)>);
+  static_assert(std::forward_iterator<std::ranges::iterator_t<Base>>);
+
+  // Check positive __n with exact multiple of left's stride.
+  assert(sv_zero_offset_should_be_four - sv_zero_offset_should_be_one == 1);
+  assert(sv_zero_offset_should_be_seven - sv_zero_offset_should_be_one == 2);
+
+  // Check positive __n with non-exact multiple of left's stride.
+  assert(sv_one_offset_should_be_two - sv_zero_offset_should_be_one == 0);
+  assert(sv_one_offset_should_be_five - sv_zero_offset_should_be_one == 1);
+
+  // Check negative __n with exact multiple of left's stride.
+  assert(sv_zero_offset_should_be_one - sv_zero_offset_should_be_four == -1);
+  assert(sv_zero_offset_should_be_one - sv_zero_offset_should_be_seven == -2);
+
+  // Check negative __n with non-exact multiple of left's stride.
+  assert(sv_zero_offset_should_be_one - sv_one_offset_should_be_two == 0);
+  assert(sv_zero_offset_should_be_one - sv_one_offset_should_be_five == -1);
+
+  // Make sure that all sentinel operations work!
+  assert(stride_view_over_base_zero_offset.end() == std::default_sentinel);
+  assert(std::default_sentinel == stride_view_over_base_zero_offset.end());
+
+  assert(stride_view_over_base_zero_offset.end() - std::default_sentinel == 0);
+  assert(std::default_sentinel - stride_view_over_base_zero_offset.begin() ==
+         std::ranges::distance(stride_view_over_base_zero_offset));
+  assert(stride_view_over_base_zero_offset.begin() - std::default_sentinel ==
+         -std::ranges::distance(stride_view_over_base_zero_offset));
+  assert(stride_view_over_base_zero_offset.begin() - std::default_sentinel == -distance);
+  assert(std::default_sentinel - stride_view_over_base_zero_offset.begin() == distance);
+  return true;
+}
+
+constexpr bool test_properly_handling_missing() {
+  // Check whether __missing_ gets handled properly.
+  using Base = BasicTestView<int*, int*>;
+  int arr[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+  auto base    = Base(arr, arr + 10);
+  auto strider = std::ranges::stride_view<Base>(base, 7);
+
+  auto strider_iter = strider.end();
+
+  strider_iter--;
+  assert(*strider_iter == 8);
+
+  // Now that we are back among the valid, we should
+  // have a normal stride length back (i.e., __missing_
+  // should be equal to 0).
+  strider_iter--;
+  assert(*strider_iter == 1);
+
+  strider_iter++;
+  assert(*strider_iter == 8);
+
+  // By striding past the end, we are going to generate
+  // another __missing_ != 0 value.
+  strider_iter++;
+  assert(strider_iter == strider.end());
+
+  // Make sure that all sentinel operations work!
+  assert(strider.end() == std::default_sentinel);
+  assert(std::default_sentinel == strider.end());
+
+  assert(strider_iter - std::default_sentinel == 0);
+  assert(std::default_sentinel - strider.end() == 0);
+  assert(std::default_sentinel - strider_iter == 0);
+
+  // Let's make sure that the newly regenerated __missing__ gets used.
+  strider_iter += -2;
+  assert(*strider_iter == 1);
+
+  return true;
+}
+
+int main(int, char**) {
+  {
+    constexpr int arr[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
+    std::vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
+    test_forward_operator_minus(arr, arr + 11, 4);
+    test_forward_operator_minus(vec.begin(), vec.end(), 4);
+  }
+
+  {
+    int arr[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+    test_non_forward_operator_minus(SizedInputIter(arr), SizedInputIter(arr + 1), SizedInputIter(arr + 10));
+  }
+
+  test_properly_handling_missing();
+  static_assert(test_properly_handling_missing());
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/increment.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/increment.pass.cpp
new file mode 100644
index 0000000000000..036605d065fd3
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/increment.pass.cpp
@@ -0,0 +1,205 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr __iterator& operator++()
+// constexpr void operator++(int)
+// constexpr __iterator operator++(int)
+
+#include <iterator>
+#include <vector>
+
+#include "../types.h"
+
+template <class T>
+concept CanPostIncrementVoid = std::is_same_v<void, decltype(std::declval<T>()++)> && requires(T& t) { t++; };
+template <class T>
+concept CanPostIncrementIterator = std::is_same_v<T, decltype(std::declval<T>()++)> && requires(T& t) { t = t++; };
+template <class T>
+concept CanPreIncrementIterator = std::is_same_v<T&, decltype(++(std::declval<T>()))> && requires(T& t) { t = ++t; };
+
+// A stride view with a base that is a non forward range returns void from operator++
+using InputView = BasicTestView<cpp17_input_iterator<int*>, sized_sentinel<cpp17_input_iterator<int*>>>;
+using StrideViewOverInputViewIterator = std::ranges::iterator_t<std::ranges::stride_view<InputView>>;
+static_assert(CanPostIncrementVoid<StrideViewOverInputViewIterator>);
+static_assert(!CanPostIncrementIterator<StrideViewOverInputViewIterator>);
+static_assert(CanPreIncrementIterator<StrideViewOverInputViewIterator>);
+
+// A stride view with a base that is a forward range returns void from operator++
+using ForwardView                       = BasicTestView<forward_iterator<int*>, sized_sentinel<forward_iterator<int*>>>;
+using StrideViewOverForwardViewIterator = std::ranges::iterator_t<std::ranges::stride_view<ForwardView>>;
+static_assert(!CanPostIncrementVoid<StrideViewOverForwardViewIterator>);
+static_assert(CanPostIncrementIterator<StrideViewOverForwardViewIterator>);
+static_assert(CanPreIncrementIterator<StrideViewOverForwardViewIterator>);
+
+template <typename Iter>
+  requires std::sized_sentinel_for<Iter, Iter> && (!std::forward_iterator<Iter>)
+constexpr bool test_non_forward_operator_increment(Iter zero_begin, Iter three_begin, Iter end) {
+  using Base = BasicTestView<Iter, Iter>;
+
+  auto base_view_offset_zero              = Base(zero_begin, end);
+  auto base_view_offset_three             = Base(three_begin, end);
+  auto stride_view_over_base_zero_offset  = std::ranges::stride_view(base_view_offset_zero, 3);
+  auto stride_view_over_base_three_offset = std::ranges::stride_view(base_view_offset_three, 3);
+
+  auto sv_zero_offset_begin  = stride_view_over_base_zero_offset.begin();
+  auto sv_three_offset_begin = stride_view_over_base_three_offset.begin();
+
+  auto sv_zero_offset_third_index = sv_zero_offset_begin; // With a stride of 3, so ++ moves 3 indexes.
+  ++sv_zero_offset_third_index;
+  assert(*sv_three_offset_begin == *sv_zero_offset_third_index);
+
+  sv_zero_offset_third_index = sv_zero_offset_begin;
+  sv_zero_offset_third_index++;
+  assert(*sv_three_offset_begin == *sv_zero_offset_third_index);
+
+  // See if both get to the end (with pre-increment).
+  auto sv_zero_offset_incremented_to_end = sv_zero_offset_begin;
+  ++sv_zero_offset_incremented_to_end; // 3
+  ++sv_zero_offset_incremented_to_end; // 6
+  ++sv_zero_offset_incremented_to_end; // 9
+  ++sv_zero_offset_incremented_to_end; // End
+
+  auto sv_three_offset_incremented_to_end = sv_three_offset_begin; // With a stride of 3, so ++ moves 3 indexes.
+  ++sv_three_offset_incremented_to_end;                            // 6
+  ++sv_three_offset_incremented_to_end;                            // 9
+  ++sv_three_offset_incremented_to_end;                            // End
+
+  assert(sv_three_offset_incremented_to_end == sv_zero_offset_incremented_to_end);
+  assert(sv_three_offset_incremented_to_end == stride_view_over_base_three_offset.end());
+  assert(sv_zero_offset_incremented_to_end == stride_view_over_base_zero_offset.end());
+
+  // See if both get to the end (with post-increment).
+  sv_zero_offset_incremented_to_end = sv_zero_offset_begin;
+  sv_zero_offset_incremented_to_end++; // 3
+  sv_zero_offset_incremented_to_end++; // 6
+  sv_zero_offset_incremented_to_end++; // 9
+  sv_zero_offset_incremented_to_end++; // End
+
+  sv_three_offset_incremented_to_end = sv_three_offset_begin; // With a stride of 3, so ++ moves 3 indexes.
+  sv_three_offset_incremented_to_end++;                       // 6
+  sv_three_offset_incremented_to_end++;                       // 9
+  sv_three_offset_incremented_to_end++;                       // End
+
+  assert(sv_three_offset_incremented_to_end == sv_zero_offset_incremented_to_end);
+  assert(sv_three_offset_incremented_to_end == stride_view_over_base_three_offset.end());
+  assert(sv_zero_offset_incremented_to_end == stride_view_over_base_zero_offset.end());
+
+  return true;
+}
+
+template <std::forward_iterator Iter>
+constexpr bool test_forward_operator_increment(Iter begin, Iter end) {
+  using Base = BasicTestView<Iter, Iter>;
+
+  using StrideViewIterator = std::ranges::iterator_t<std::ranges::stride_view<Base>>;
+  static_assert(std::ranges::forward_range<Base>);
+  static_assert(std::weakly_incrementable<StrideViewIterator>);
+
+  auto base_view_offset_zero             = Base(begin, end);
+  auto stride_view_over_base_zero_offset = std::ranges::stride_view(base_view_offset_zero, 3);
+  auto sv_zero_offset_begin              = stride_view_over_base_zero_offset.begin();
+
+  // Create a ground truth for comparison.
+  auto sv_zero_offset_third_index_key = stride_view_over_base_zero_offset.begin();
+  sv_zero_offset_third_index_key++;
+
+  auto sv_zero_offset_third_index = ++sv_zero_offset_begin;
+  assert(*sv_zero_offset_third_index == *sv_zero_offset_begin);
+  assert(*sv_zero_offset_third_index == *sv_zero_offset_third_index_key);
+
+  sv_zero_offset_begin       = stride_view_over_base_zero_offset.begin();
+  sv_zero_offset_third_index = sv_zero_offset_begin;
+  sv_zero_offset_third_index++;
+  assert(*sv_zero_offset_third_index == *sv_zero_offset_third_index_key);
+
+  sv_zero_offset_begin                   = stride_view_over_base_zero_offset.begin();
+  auto sv_zero_offset_incremented_to_end = sv_zero_offset_begin;
+  ++sv_zero_offset_incremented_to_end; // 3
+  ++sv_zero_offset_incremented_to_end; // 6
+  ++sv_zero_offset_incremented_to_end; // 9
+  ++sv_zero_offset_incremented_to_end; // End
+
+  auto sv_zero_offset_incremented_to_end_reset = sv_zero_offset_begin; // With a stride of 3, so ++ moves 3 indexes.
+  sv_zero_offset_incremented_to_end_reset      = ++sv_zero_offset_incremented_to_end_reset; // 3
+  sv_zero_offset_incremented_to_end_reset      = ++sv_zero_offset_incremented_to_end_reset; // 6
+  sv_zero_offset_incremented_to_end_reset      = ++sv_zero_offset_incremented_to_end_reset; // 9
+  sv_zero_offset_incremented_to_end_reset      = ++sv_zero_offset_incremented_to_end_reset; // End
+
+  assert(sv_zero_offset_incremented_to_end == sv_zero_offset_incremented_to_end_reset);
+  assert(sv_zero_offset_incremented_to_end == stride_view_over_base_zero_offset.end());
+
+  sv_zero_offset_incremented_to_end = sv_zero_offset_begin;
+  sv_zero_offset_incremented_to_end++; // 3
+  sv_zero_offset_incremented_to_end++; // 6
+  sv_zero_offset_incremented_to_end++; // 9
+  sv_zero_offset_incremented_to_end++; // End
+  assert(sv_zero_offset_incremented_to_end == stride_view_over_base_zero_offset.end());
+
+  return true;
+}
+
+constexpr bool test_properly_handling_missing() {
+  // Check whether __missing_ gets handled properly.
+  using Base = BasicTestView<int*, int*>;
+  int arr[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+  auto base    = Base(arr, arr + 10);
+  auto strider = std::ranges::stride_view<Base>(base, 7);
+
+  auto strider_iter = strider.end();
+
+  strider_iter--;
+  assert(*strider_iter == 8);
+
+  // Now that we are back among the valid, we should
+  // have a normal stride length back (i.e., __missing_
+  // should be equal to 0).
+  strider_iter--;
+  assert(*strider_iter == 1);
+
+  strider_iter++;
+  assert(*strider_iter == 8);
+
+  // By striding past the end, we are going to generate
+  // another __missing_ != 0 value.
+  strider_iter++;
+  assert(strider_iter == strider.end());
+
+  // Make sure that all sentinel operations work!
+  assert(strider.end() == std::default_sentinel);
+  assert(std::default_sentinel == strider.end());
+
+  assert(strider_iter - std::default_sentinel == 0);
+  assert(std::default_sentinel - strider.end() == 0);
+  assert(std::default_sentinel - strider_iter == 0);
+
+  // Let's make sure that the newly regenerated __missing__ gets used.
+  strider_iter += -2;
+  assert(*strider_iter == 1);
+
+  return true;
+}
+
+int main(int, char**) {
+  {
+    constexpr int arr[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
+    std::vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
+    test_forward_operator_increment(arr, arr + 11);
+    test_forward_operator_increment(vec.begin(), vec.end());
+  }
+
+  {
+    int arr[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+    test_non_forward_operator_increment(SizedInputIter(arr), SizedInputIter(arr + 3), SizedInputIter(arr + 10));
+  }
+
+  test_properly_handling_missing();
+  static_assert(test_properly_handling_missing());
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/iter_move.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/iter_move.pass.cpp
new file mode 100644
index 0000000000000..5275115437bcc
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/iter_move.pass.cpp
@@ -0,0 +1,97 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+//  friend constexpr range_rvalue_reference_t<_Base> iter_move(__iterator const& __it)
+//         noexcept(noexcept(ranges::iter_move(__it.__current_)))
+
+#include <ranges>
+#include <vector>
+
+#include "../types.h"
+#include "test_macros.h"
+
+template <typename T>
+concept iter_moveable = requires(T&& t) { std::ranges::iter_move(t); };
+
+constexpr bool test() {
+  {
+    int a[] = {4, 3, 2, 1};
+
+    int iter_move_counter(0);
+    using View       = IterMoveIterSwapTestRange<int*, true, true>;
+    using StrideView = std::ranges::stride_view<View>;
+    auto svb         = StrideView(View(a, a + 4, &iter_move_counter), 1).begin();
+
+    static_assert(iter_moveable<std::ranges::iterator_t<StrideView>>);
+    ASSERT_SAME_TYPE(int, decltype(std::ranges::iter_move(svb)));
+    static_assert(noexcept(std::ranges::iter_move(svb)));
+
+    auto&& result = std::ranges::iter_move(svb);
+    assert(iter_move_counter == 1);
+    assert(result == 4);
+
+    svb++;
+    result = std::ranges::iter_move(svb);
+    assert(iter_move_counter == 2);
+    assert(result == 3);
+  }
+
+  {
+    int a[] = {1, 2, 3, 4};
+
+    int iter_move_counter(0);
+    using View       = IterMoveIterSwapTestRange<int*, true, false>;
+    using StrideView = std::ranges::stride_view<View>;
+    auto svb         = StrideView(View(a, a + 4, &iter_move_counter), 1).begin();
+
+    static_assert(iter_moveable<std::ranges::iterator_t<StrideView>>);
+    ASSERT_SAME_TYPE(int, decltype(std::ranges::iter_move(svb)));
+    static_assert(!noexcept(std::ranges::iter_move(svb)));
+
+    auto&& result = std::ranges::iter_move(svb);
+    assert(iter_move_counter == 1);
+    assert(result == 1);
+
+    svb++;
+    result = std::ranges::iter_move(svb);
+    assert(iter_move_counter == 2);
+    assert(result == 2);
+  }
+
+  {
+    std::vector<int> a = {4, 5, 6, 7, 8};
+
+    int iter_move_counter(0);
+    using View = IterMoveIterSwapTestRange<std::vector<int>::iterator, true, false>;
+
+    using StrideView = std::ranges::stride_view<View>;
+    auto svb         = StrideView(View(a.begin(), a.end(), &iter_move_counter), 1).begin();
+
+    static_assert(!noexcept(std::ranges::iter_move(svb)));
+
+    auto&& result = std::ranges::iter_move(svb);
+    assert(iter_move_counter == 1);
+    assert(result == 4);
+
+    svb++;
+    result = std::ranges::iter_move(svb);
+    assert(iter_move_counter == 2);
+    assert(result == 5);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/iter_swap.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/iter_swap.pass.cpp
new file mode 100644
index 0000000000000..c9b87dfec6ecd
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/iter_swap.pass.cpp
@@ -0,0 +1,88 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+//  friend constexpr void iter_swap(__iterator const& __x, __iterator const& __y)
+//  noexcept(noexcept(ranges::iter_swap(__x.__current_, __y.__current_)))
+//  requires indirectly_swappable<iterator_t<_Base>>
+
+#include <ranges>
+
+#include "../types.h"
+
+template <typename T>
+concept swappable = requires(T&& t, T&& u) { std::ranges::iter_swap(t, u); };
+
+constexpr bool test() {
+  {
+    int a[] = {1, 2, 3, 4};
+    int b[] = {5, 6, 7, 8};
+
+    int iter_move_counter_one(0);
+    int iter_move_counter_two(0);
+    using View       = IterMoveIterSwapTestRange<int*, true, true>;
+    using StrideView = std::ranges::stride_view<View>;
+    auto svba        = StrideView(View(a, a + 4, &iter_move_counter_one), 1).begin();
+    auto svbb        = StrideView(View(b, b + 4, &iter_move_counter_two), 1).begin();
+
+    static_assert(swappable<std::ranges::iterator_t<StrideView>>);
+    static_assert(noexcept(std::ranges::iter_swap(svba, svbb)));
+
+    assert(a[0] == 1);
+    assert(b[0] == 5);
+
+    std::ranges::iter_swap(svba, svbb);
+    assert(iter_move_counter_one == 1);
+    assert(iter_move_counter_two == 1);
+
+    assert(a[0] == 5);
+    assert(b[0] == 1);
+  }
+
+  {
+    int a[] = {1, 2, 3, 4};
+    int b[] = {5, 6, 7, 8};
+
+    int iter_move_counter_one(0);
+    int iter_move_counter_two(0);
+    using View       = IterMoveIterSwapTestRange<int*, true, false>;
+    using StrideView = std::ranges::stride_view<View>;
+    auto svba        = StrideView(View(a, a + 4, &iter_move_counter_one), 1).begin();
+    auto svbb        = StrideView(View(b, b + 4, &iter_move_counter_two), 1).begin();
+
+    static_assert(swappable<std::ranges::iterator_t<StrideView>>);
+    static_assert(!noexcept(std::ranges::iter_swap(svba, svbb)));
+
+    assert(a[0] == 1);
+    assert(b[0] == 5);
+
+    std::ranges::iter_swap(svba, svbb);
+
+    assert(iter_move_counter_one == 1);
+    assert(iter_move_counter_two == 1);
+    assert(a[0] == 5);
+    assert(b[0] == 1);
+  }
+
+  {
+    using View       = IterMoveIterSwapTestRange<int*, false, false>;
+    using StrideView = std::ranges::stride_view<View>;
+
+    static_assert(!swappable<std::ranges::iterator_t<StrideView>>);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/less_than.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/less_than.pass.cpp
new file mode 100644
index 0000000000000..13eecf9283dee
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/less_than.pass.cpp
@@ -0,0 +1,426 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr __iterator& operator++()
+// constexpr void operator++(int)
+// constexpr __iterator operator++(int)
+// constexpr __iterator& operator--()
+// constexpr __iterator operator--(int)
+// constexpr __iterator& operator+=(difference_type __n)
+// constexpr __iterator& operator-=(difference_type __n)
+// friend constexpr bool operator==(__iterator const& __x, default_sentinel_t)
+// friend constexpr bool operator==(__iterator const& __x, __iterator const& __y)
+// friend constexpr bool operator<(__iterator const& __x, __iterator const& __y)
+// friend constexpr bool operator>(__iterator const& __x, __iterator const& __y)
+// friend constexpr bool operator<=(__iterator const& __x, __iterator const& __y)
+// friend constexpr bool operator>=(__iterator const& __x, __iterator const& __y)
+// friend constexpr bool operator<=>(__iterator const& __x, __iterator const& __y)
+
+#include <functional>
+#include <iterator>
+#include <ranges>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "../types.h"
+#include "test_iterators.h"
+
+template <class T>
+concept CanPlusEqual = std::is_same_v<T&, decltype(std::declval<T>() += 1)> && requires(T& t) { t += 1; };
+template <class T>
+concept CanMinusEqual = std::is_same_v<T&, decltype(std::declval<T>() -= 1)> && requires(T& t) { t -= 1; };
+
+template <class T>
+concept CanMinus =
+    // Note: Do *not* use std::iterator_traits here because T may not have
+    // all the required pieces when it is not a forward_range.
+    std::is_same_v<typename T::difference_type, decltype(std::declval<T>() - std::declval<T>())> &&
+    requires(T& t) { t - t; };
+
+template <class T>
+concept CanSentinelMinus =
+    // Note: Do *not* use std::iterator_traits here because T may not have
+    // all the required pieces when it is not a forward_range.
+    std::is_same_v<typename T::difference_type, decltype(std::declval<T>() - std::default_sentinel)> &&
+    std::is_same_v<typename T::difference_type, decltype(std::default_sentinel - std::declval<T>())> && requires(T& t) {
+      t - std::default_sentinel;
+      std::default_sentinel - t;
+    };
+
+template <class T>
+concept CanDifferencePlus = std::is_same_v<T, decltype(std::declval<T>() + 1)> && requires(T& t) {
+  t + 1;
+} && std::is_same_v<T, decltype(1 + std::declval<T>())> && requires(T& t) { 1 + t; };
+template <class T>
+concept CanDifferenceMinus = std::is_same_v<T, decltype(std::declval<T>() - 1)> && requires(T& t) { t - 1; };
+
+template <class T>
+concept CanPostDecrement = std::is_same_v<T, decltype(std::declval<T>()--)> && requires(T& t) { t--; };
+template <class T>
+concept CanPreDecrement = std::is_same_v<T&, decltype(--std::declval<T>())> && requires(T& t) { --t; };
+
+template <class T>
+concept CanSubscript = requires(T& t) { t[5]; };
+
+// What operators are valid for an iterator derived from a stride view
+// over an input view.(sized sentinel)
+using InputView = BasicTestView<cpp17_input_iterator<int*>, sized_sentinel<cpp17_input_iterator<int*>>>;
+using StrideViewOverInputViewIterator = std::ranges::iterator_t<std::ranges::stride_view<InputView>>;
+
+static_assert(std::weakly_incrementable<StrideViewOverInputViewIterator>);
+
+static_assert(!CanPostDecrement<StrideViewOverInputViewIterator>);
+static_assert(!CanPreDecrement<StrideViewOverInputViewIterator>);
+static_assert(!CanPlusEqual<StrideViewOverInputViewIterator>);
+static_assert(!CanMinusEqual<StrideViewOverInputViewIterator>);
+static_assert(!CanMinus<StrideViewOverInputViewIterator>);
+static_assert(!CanDifferencePlus<StrideViewOverInputViewIterator>);
+static_assert(!CanDifferenceMinus<StrideViewOverInputViewIterator>);
+static_assert(CanSentinelMinus<StrideViewOverInputViewIterator>);
+static_assert(std::invocable<std::equal_to<>, StrideViewOverInputViewIterator, StrideViewOverInputViewIterator>);
+static_assert(std::invocable<std::equal_to<>, StrideViewOverInputViewIterator, std::default_sentinel_t>);
+static_assert(std::invocable<std::equal_to<>, std::default_sentinel_t, StrideViewOverInputViewIterator>);
+
+static_assert(!std::is_invocable_v<std::less<>, StrideViewOverInputViewIterator, StrideViewOverInputViewIterator>);
+static_assert(
+    !std::is_invocable_v<std::less_equal<>, StrideViewOverInputViewIterator, StrideViewOverInputViewIterator>);
+static_assert(!std::is_invocable_v<std::greater<>, StrideViewOverInputViewIterator, StrideViewOverInputViewIterator>);
+static_assert(
+    !std::is_invocable_v<std::greater_equal<>, StrideViewOverInputViewIterator, StrideViewOverInputViewIterator>);
+
+static_assert(!CanSubscript<StrideViewOverInputViewIterator>);
+
+// What operators are valid for an iterator derived from a stride view
+// over a forward view.(sized sentinel)
+using ForwardView                       = BasicTestView<forward_iterator<int*>, sized_sentinel<forward_iterator<int*>>>;
+using StrideViewOverForwardViewIterator = std::ranges::iterator_t<std::ranges::stride_view<ForwardView>>;
+
+static_assert(std::weakly_incrementable<StrideViewOverForwardViewIterator>);
+
+static_assert(!CanPostDecrement<StrideViewOverForwardViewIterator>);
+static_assert(!CanPreDecrement<StrideViewOverForwardViewIterator>);
+static_assert(!CanPlusEqual<StrideViewOverForwardViewIterator>);
+static_assert(!CanMinusEqual<StrideViewOverForwardViewIterator>);
+static_assert(!CanMinus<StrideViewOverForwardViewIterator>);
+static_assert(!CanDifferencePlus<StrideViewOverForwardViewIterator>);
+static_assert(!CanDifferenceMinus<StrideViewOverForwardViewIterator>);
+static_assert(CanSentinelMinus<StrideViewOverForwardViewIterator>);
+static_assert(std::invocable<std::equal_to<>, StrideViewOverForwardViewIterator, StrideViewOverForwardViewIterator>);
+static_assert(std::invocable<std::equal_to<>, StrideViewOverForwardViewIterator, std::default_sentinel_t>);
+static_assert(std::invocable<std::equal_to<>, std::default_sentinel_t, StrideViewOverForwardViewIterator>);
+
+static_assert(!std::is_invocable_v<std::less<>, StrideViewOverForwardViewIterator, StrideViewOverForwardViewIterator>);
+static_assert(
+    !std::is_invocable_v<std::less_equal<>, StrideViewOverForwardViewIterator, StrideViewOverForwardViewIterator>);
+static_assert(
+    !std::is_invocable_v<std::greater<>, StrideViewOverForwardViewIterator, StrideViewOverForwardViewIterator>);
+static_assert(
+    !std::is_invocable_v<std::greater_equal<>, StrideViewOverForwardViewIterator, StrideViewOverForwardViewIterator>);
+
+static_assert(!CanSubscript<StrideViewOverForwardViewIterator>);
+
+// What operators are valid for an iterator derived from a stride view
+// over a bidirectional view. (sized sentinel)
+using BidirectionalView = BasicTestView<bidirectional_iterator<int*>, sized_sentinel<bidirectional_iterator<int*>>>;
+using StrideViewOverBidirectionalViewIterator = std::ranges::iterator_t<std::ranges::stride_view<BidirectionalView>>;
+
+static_assert(CanPostDecrement<StrideViewOverBidirectionalViewIterator>);
+static_assert(CanPreDecrement<StrideViewOverBidirectionalViewIterator>);
+static_assert(!CanPlusEqual<StrideViewOverBidirectionalViewIterator>);
+static_assert(!CanMinusEqual<StrideViewOverBidirectionalViewIterator>);
+static_assert(!CanMinus<StrideViewOverBidirectionalViewIterator>);
+static_assert(!CanDifferencePlus<StrideViewOverBidirectionalViewIterator>);
+static_assert(!CanDifferenceMinus<StrideViewOverBidirectionalViewIterator>);
+static_assert(CanSentinelMinus<StrideViewOverBidirectionalViewIterator>);
+static_assert(
+    std::invocable<std::equal_to<>, StrideViewOverBidirectionalViewIterator, StrideViewOverBidirectionalViewIterator>);
+static_assert(std::invocable<std::equal_to<>, StrideViewOverBidirectionalViewIterator, std::default_sentinel_t>);
+static_assert(std::invocable<std::equal_to<>, std::default_sentinel_t, StrideViewOverBidirectionalViewIterator>);
+
+static_assert(!std::is_invocable_v<std::less<>,
+                                   StrideViewOverBidirectionalViewIterator,
+                                   StrideViewOverBidirectionalViewIterator>);
+static_assert(!std::is_invocable_v<std::less_equal<>,
+                                   StrideViewOverBidirectionalViewIterator,
+                                   StrideViewOverBidirectionalViewIterator>);
+static_assert(!std::is_invocable_v<std::greater<>,
+                                   StrideViewOverBidirectionalViewIterator,
+                                   StrideViewOverBidirectionalViewIterator>);
+static_assert(!std::is_invocable_v<std::greater_equal<>,
+                                   StrideViewOverBidirectionalViewIterator,
+                                   StrideViewOverBidirectionalViewIterator>);
+
+static_assert(!CanSubscript<StrideViewOverBidirectionalViewIterator>);
+
+// What operators are valid for an iterator derived from a stride view
+// over a random access view. (non sized sentinel)
+using RandomAccessView                       = BasicTestView<random_access_iterator<int*>>;
+using StrideViewOverRandomAccessViewIterator = std::ranges::iterator_t<std::ranges::stride_view<RandomAccessView>>;
+
+static_assert(std::weakly_incrementable<StrideViewOverRandomAccessViewIterator>);
+
+static_assert(CanPostDecrement<StrideViewOverRandomAccessViewIterator>);
+static_assert(CanPreDecrement<StrideViewOverRandomAccessViewIterator>);
+static_assert(CanPlusEqual<StrideViewOverRandomAccessViewIterator>);
+static_assert(CanMinusEqual<StrideViewOverRandomAccessViewIterator>);
+static_assert(CanMinus<StrideViewOverRandomAccessViewIterator>);
+static_assert(CanDifferencePlus<StrideViewOverRandomAccessViewIterator>);
+static_assert(CanDifferenceMinus<StrideViewOverRandomAccessViewIterator>);
+static_assert(!CanSentinelMinus<StrideViewOverRandomAccessViewIterator>);
+static_assert(
+    std::invocable<std::equal_to<>, StrideViewOverRandomAccessViewIterator, StrideViewOverRandomAccessViewIterator>);
+static_assert(std::invocable<std::equal_to<>, StrideViewOverRandomAccessViewIterator, std::default_sentinel_t>);
+static_assert(std::invocable<std::equal_to<>, std::default_sentinel_t, StrideViewOverRandomAccessViewIterator>);
+
+static_assert(
+    std::is_invocable_v<std::less<>, StrideViewOverRandomAccessViewIterator, StrideViewOverRandomAccessViewIterator>);
+static_assert(std::is_invocable_v<std::less_equal<>,
+                                  StrideViewOverRandomAccessViewIterator,
+                                  StrideViewOverRandomAccessViewIterator>);
+static_assert(std::is_invocable_v<std::greater<>,
+                                  StrideViewOverRandomAccessViewIterator,
+                                  StrideViewOverRandomAccessViewIterator>);
+static_assert(std::is_invocable_v<std::greater_equal<>,
+                                  StrideViewOverRandomAccessViewIterator,
+                                  StrideViewOverRandomAccessViewIterator>);
+
+static_assert(CanSubscript<StrideViewOverRandomAccessViewIterator>);
+
+using EqualableView               = BasicTestView<cpp17_input_iterator<int*>>;
+using EqualableViewStrideView     = std::ranges::stride_view<EqualableView>;
+using EqualableViewStrideViewIter = std::ranges::iterator_t<EqualableViewStrideView>;
+
+static_assert(std::equality_comparable<std::ranges::iterator_t<EqualableView>>);
+static_assert(std::equality_comparable<EqualableViewStrideViewIter>);
+
+static_assert(!std::three_way_comparable<std::ranges::iterator_t<EqualableView>>);
+static_assert(!std::ranges::random_access_range<EqualableView>);
+static_assert(!std::three_way_comparable<EqualableView>);
+
+using ThreeWayComparableView           = BasicTestView<three_way_contiguous_iterator<int*>>;
+using ThreeWayComparableViewStrideView = std::ranges::stride_view<ThreeWayComparableView>;
+using ThreeWayComparableStrideViewIter = std::ranges::iterator_t<ThreeWayComparableViewStrideView>;
+
+static_assert(std::three_way_comparable<std::ranges::iterator_t<ThreeWayComparableView>>);
+static_assert(std::ranges::random_access_range<ThreeWayComparableView>);
+static_assert(std::three_way_comparable<ThreeWayComparableStrideViewIter>);
+
+using UnEqualableView               = ViewOverNonCopyableIterator<cpp20_input_iterator<int*>>;
+using UnEqualableViewStrideView     = std::ranges::stride_view<UnEqualableView>;
+using UnEqualableViewStrideViewIter = std::ranges::iterator_t<UnEqualableViewStrideView>;
+
+static_assert(!std::equality_comparable<std::ranges::iterator_t<UnEqualableView>>);
+static_assert(!std::equality_comparable<UnEqualableViewStrideViewIter>);
+
+static_assert(!std::three_way_comparable<std::ranges::iterator_t<UnEqualableView>>);
+static_assert(!std::ranges::random_access_range<UnEqualableView>);
+static_assert(!std::three_way_comparable<UnEqualableView>);
+
+template <typename Iter>
+  requires std::sized_sentinel_for<Iter, Iter> && (!std::forward_iterator<Iter>)
+constexpr bool test_non_forward_operator_minus(Iter zero_begin, Iter one_begin, Iter end) {
+  using Base = BasicTestView<Iter, Iter>;
+  // Test the non-forward-range operator- between two iterators (i.e., ceil) and an
+  // iterator and a default sentinel.
+  using StrideViewIterator = std::ranges::iterator_t<std::ranges::stride_view<Base>>;
+  static_assert(std::weakly_incrementable<StrideViewIterator>);
+  static_assert(!std::ranges::forward_range<Base>);
+
+  // First, what operators are valid for an iterator derived from a stride view
+  // over a sized input view.
+
+  static_assert(!CanPostDecrement<StrideViewIterator>);
+  static_assert(!CanPreDecrement<StrideViewIterator>);
+  static_assert(!CanPlusEqual<StrideViewIterator>);
+  static_assert(!CanMinusEqual<StrideViewIterator>);
+  static_assert(!CanDifferencePlus<StrideViewIterator>);
+  static_assert(!CanDifferenceMinus<StrideViewIterator>);
+  static_assert(CanSentinelMinus<StrideViewIterator>);
+
+  static_assert(!std::is_invocable_v<std::less<>, StrideViewIterator, StrideViewIterator>);
+  static_assert(!std::is_invocable_v<std::less_equal<>, StrideViewIterator, StrideViewIterator>);
+  static_assert(!std::is_invocable_v<std::greater<>, StrideViewIterator, StrideViewIterator>);
+  static_assert(!std::is_invocable_v<std::greater_equal<>, StrideViewIterator, StrideViewIterator>);
+  static_assert(std::is_invocable_v<std::equal_to<>, StrideViewIterator, StrideViewIterator>);
+  static_assert(std::is_invocable_v<std::equal_to<>, std::default_sentinel_t, StrideViewIterator>);
+  static_assert(std::is_invocable_v<std::equal_to<>, StrideViewIterator, std::default_sentinel_t>);
+  static_assert(!CanSubscript<StrideViewIterator>);
+
+  auto base_view_offset_zero             = Base(zero_begin, end);
+  auto base_view_offset_one              = Base(one_begin, end);
+  auto stride_view_over_base_zero_offset = std::ranges::stride_view(base_view_offset_zero, 3);
+  auto stride_view_over_base_one_offset  = std::ranges::stride_view(base_view_offset_one, 3);
+
+  auto sv_zero_offset_begin = stride_view_over_base_zero_offset.begin();
+  auto sv_one_offset_begin  = stride_view_over_base_one_offset.begin();
+
+  auto sv_zero_offset_zeroth_index = sv_zero_offset_begin;
+  auto sv_zero_offset_third_index  = ++sv_zero_offset_begin; // With a stride of 3, so ++ moves 3 indexes.
+  auto sv_zero_offset_sixth_index  = ++sv_zero_offset_begin; // With a stride of 3, so ++ moves 3 indexes.
+
+  auto sv_one_offset_oneth_index  = sv_one_offset_begin;
+  auto sv_one_offset_fourth_index = ++sv_one_offset_begin; // With a stride of 3, so ++ moves 3 indexes.
+
+  static_assert(std::sized_sentinel_for<std::ranges::iterator_t<Base>, std::ranges::iterator_t<Base>>);
+  static_assert(CanMinus<decltype(sv_zero_offset_begin)>);
+
+  // Check positive __n with exact multiple of left's stride.
+  assert(sv_zero_offset_third_index - sv_zero_offset_zeroth_index == 1);
+  assert(sv_zero_offset_sixth_index - sv_zero_offset_zeroth_index == 2);
+  // Check positive __n with non-exact multiple of left's stride (will do ceil here).
+  assert(sv_one_offset_oneth_index - sv_zero_offset_zeroth_index == 1);
+  assert(sv_one_offset_fourth_index - sv_zero_offset_zeroth_index == 2);
+
+  // Check negative __n with exact multiple of left's stride.
+  assert(sv_zero_offset_zeroth_index - sv_zero_offset_third_index == -1);
+  assert(sv_zero_offset_zeroth_index - sv_zero_offset_sixth_index == -2);
+  // Check negative __n with non-exact multiple of left's stride (will do ceil here).
+  assert(sv_zero_offset_zeroth_index - sv_one_offset_oneth_index == -1);
+  assert(sv_zero_offset_zeroth_index - sv_one_offset_fourth_index == -2);
+
+  assert(stride_view_over_base_zero_offset.end() == std::default_sentinel);
+  assert(std::default_sentinel == stride_view_over_base_zero_offset.end());
+
+  assert(std::default_sentinel - stride_view_over_base_zero_offset.end() == 0);
+  assert(stride_view_over_base_zero_offset.end() - std::default_sentinel == 0);
+  // assert((std::default_sentinel - )== 0);
+
+  assert(std::default_sentinel - stride_view_over_base_zero_offset.begin() ==
+         std::ranges::distance(stride_view_over_base_zero_offset));
+  assert(stride_view_over_base_zero_offset.begin() - std::default_sentinel ==
+         -std::ranges::distance(stride_view_over_base_zero_offset));
+
+  return true;
+}
+
+template <std::forward_iterator Iter, typename difference_type>
+constexpr bool test_forward_operator_minus(Iter begin, Iter end, difference_type distance) {
+  // Test the forward-range operator- between two iterators (i.e., no ceil) and
+  // an iterator and a default sentinel.
+  using Base = BasicTestView<Iter, Iter>;
+
+  using StrideViewIterator = std::ranges::iterator_t<std::ranges::stride_view<Base>>;
+  static_assert(std::ranges::forward_range<Base>);
+  static_assert(std::weakly_incrementable<StrideViewIterator>);
+
+  // First, what operators are valid for an iterator derived from a stride view
+  // over a sized forward view (even though it is actually much more than that!).
+
+  static_assert(CanMinus<StrideViewIterator>);
+  static_assert(CanSentinelMinus<StrideViewIterator>);
+
+  auto base_view_offset_zero             = Base(begin, end);
+  auto base_view_offset_one              = Base(begin + 1, end);
+  auto stride_view_over_base_zero_offset = std::ranges::stride_view(base_view_offset_zero, 3);
+  auto stride_view_over_base_one_offset  = std::ranges::stride_view(base_view_offset_one, 3);
+
+  auto sv_zero_offset_begin = stride_view_over_base_zero_offset.begin();
+  auto sv_one_offset_begin  = stride_view_over_base_one_offset.begin();
+
+  auto sv_zero_offset_should_be_one   = sv_zero_offset_begin;
+  auto sv_zero_offset_should_be_four  = ++sv_zero_offset_begin;
+  auto sv_zero_offset_should_be_seven = ++sv_zero_offset_begin;
+
+  auto sv_one_offset_should_be_two  = sv_one_offset_begin;
+  auto sv_one_offset_should_be_five = ++sv_one_offset_begin;
+
+  static_assert(std::sized_sentinel_for<std::ranges::iterator_t<Base>, std::ranges::iterator_t<Base>>);
+  static_assert(CanMinus<decltype(sv_zero_offset_begin)>);
+  static_assert(std::forward_iterator<std::ranges::iterator_t<Base>>);
+
+  // Check positive __n with exact multiple of left's stride.
+  assert(sv_zero_offset_should_be_four - sv_zero_offset_should_be_one == 1);
+  assert(sv_zero_offset_should_be_seven - sv_zero_offset_should_be_one == 2);
+
+  // Check positive __n with non-exact multiple of left's stride.
+  assert(sv_one_offset_should_be_two - sv_zero_offset_should_be_one == 0);
+  assert(sv_one_offset_should_be_five - sv_zero_offset_should_be_one == 1);
+
+  // Check negative __n with exact multiple of left's stride.
+  assert(sv_zero_offset_should_be_one - sv_zero_offset_should_be_four == -1);
+  assert(sv_zero_offset_should_be_one - sv_zero_offset_should_be_seven == -2);
+
+  // Check negative __n with non-exact multiple of left's stride.
+  assert(sv_zero_offset_should_be_one - sv_one_offset_should_be_two == 0);
+  assert(sv_zero_offset_should_be_one - sv_one_offset_should_be_five == -1);
+
+  // Make sure that all sentinel operations work!
+  assert(stride_view_over_base_zero_offset.end() == std::default_sentinel);
+  assert(std::default_sentinel == stride_view_over_base_zero_offset.end());
+
+  assert(stride_view_over_base_zero_offset.end() - std::default_sentinel == 0);
+  assert(std::default_sentinel - stride_view_over_base_zero_offset.begin() ==
+         std::ranges::distance(stride_view_over_base_zero_offset));
+  assert(stride_view_over_base_zero_offset.begin() - std::default_sentinel ==
+         -std::ranges::distance(stride_view_over_base_zero_offset));
+  assert(stride_view_over_base_zero_offset.begin() - std::default_sentinel == -distance);
+  assert(std::default_sentinel - stride_view_over_base_zero_offset.begin() == distance);
+  return true;
+}
+
+constexpr bool test_properly_handling_missing() {
+  // Check whether __missing_ gets handled properly.
+  using Base = BasicTestView<int*, int*>;
+  int arr[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+  auto base    = Base(arr, arr + 10);
+  auto strider = std::ranges::stride_view<Base>(base, 7);
+
+  auto strider_iter = strider.end();
+
+  strider_iter--;
+  assert(*strider_iter == 8);
+
+  // Now that we are back among the valid, we should
+  // have a normal stride length back (i.e., __missing_
+  // should be equal to 0).
+  strider_iter--;
+  assert(*strider_iter == 1);
+
+  strider_iter++;
+  assert(*strider_iter == 8);
+
+  // By striding past the end, we are going to generate
+  // another __missing_ != 0 value.
+  strider_iter++;
+  assert(strider_iter == strider.end());
+
+  // Make sure that all sentinel operations work!
+  assert(strider.end() == std::default_sentinel);
+  assert(std::default_sentinel == strider.end());
+
+  assert(strider_iter - std::default_sentinel == 0);
+  assert(std::default_sentinel - strider.end() == 0);
+  assert(std::default_sentinel - strider_iter == 0);
+
+  // Let's make sure that the newly regenerated __missing__ gets used.
+  strider_iter += -2;
+  assert(*strider_iter == 1);
+
+  return true;
+}
+
+int main(int, char**) {
+  {
+    constexpr int arr[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
+    std::vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
+    test_forward_operator_minus(arr, arr + 11, 4);
+    test_forward_operator_minus(vec.begin(), vec.end(), 4);
+  }
+
+  {
+    int arr[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+    test_non_forward_operator_minus(SizedInputIter(arr), SizedInputIter(arr + 1), SizedInputIter(arr + 10));
+  }
+
+  test_properly_handling_missing();
+  static_assert(test_properly_handling_missing());
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp
new file mode 100644
index 0000000000000..c3d71b7387ea7
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/operator.pass.cpp
@@ -0,0 +1,426 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr __iterator& operator++()
+// constexpr void operator++(int)
+// constexpr __iterator operator++(int)
+// constexpr __iterator& operator--()
+// constexpr __iterator operator--(int)
+// constexpr __iterator& operator+=(difference_type __n)
+// constexpr __iterator& operator-=(difference_type __n)
+// friend constexpr bool operator==(__iterator const& __x, default_sentinel_t)
+// friend constexpr bool operator==(__iterator const& __x, __iterator const& __y)
+// friend constexpr bool operator<(__iterator const& __x, __iterator const& __y)
+// friend constexpr bool operator>(__iterator const& __x, __iterator const& __y)
+// friend constexpr bool operator<=(__iterator const& __x, __iterator const& __y)
+// friend constexpr bool operator>=(__iterator const& __x, __iterator const& __y)
+// friend constexpr bool operator<=>(__iterator const& __x, __iterator const& __y)
+
+#include <functional>
+#include <iterator>
+#include <ranges>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "../types.h"
+#include "test_iterators.h"
+
+template <class T>
+concept CanPlus = std::is_same_v<T&, decltype(std::declval<T>() += 1)> && requires(T& t) { t += 1; };
+template <class T>
+concept CanMinusEqual = std::is_same_v<T&, decltype(std::declval<T>() -= 1)> && requires(T& t) { t -= 1; };
+
+template <class T>
+concept CanMinus =
+    // Note: Do *not* use std::iterator_traits here because T may not have
+    // all the required pieces when it is not a forward_range.
+    std::is_same_v<typename T::difference_type, decltype(std::declval<T>() - std::declval<T>())> &&
+    requires(T& t) { t - t; };
+
+template <class T>
+concept CanSentinelMinus =
+    // Note: Do *not* use std::iterator_traits here because T may not have
+    // all the required pieces when it is not a forward_range.
+    std::is_same_v<typename T::difference_type, decltype(std::declval<T>() - std::default_sentinel)> &&
+    std::is_same_v<typename T::difference_type, decltype(std::default_sentinel - std::declval<T>())> && requires(T& t) {
+      t - std::default_sentinel;
+      std::default_sentinel - t;
+    };
+
+template <class T>
+concept CanDifferencePlus = std::is_same_v<T, decltype(std::declval<T>() + 1)> && requires(T& t) {
+  t + 1;
+} && std::is_same_v<T, decltype(1 + std::declval<T>())> && requires(T& t) { 1 + t; };
+template <class T>
+concept CanDifferenceMinus = std::is_same_v<T, decltype(std::declval<T>() - 1)> && requires(T& t) { t - 1; };
+
+template <class T>
+concept CanPostDecrement = std::is_same_v<T, decltype(std::declval<T>()--)> && requires(T& t) { t--; };
+template <class T>
+concept CanPreDecrement = std::is_same_v<T&, decltype(--std::declval<T>())> && requires(T& t) { --t; };
+
+template <class T>
+concept CanSubscript = requires(T& t) { t[5]; };
+
+// What operators are valid for an iterator derived from a stride view
+// over an input view.(sized sentinel)
+using InputView = BasicTestView<cpp17_input_iterator<int*>, sized_sentinel<cpp17_input_iterator<int*>>>;
+using StrideViewOverInputViewIterator = std::ranges::iterator_t<std::ranges::stride_view<InputView>>;
+
+static_assert(std::weakly_incrementable<StrideViewOverInputViewIterator>);
+
+static_assert(!CanPostDecrement<StrideViewOverInputViewIterator>);
+static_assert(!CanPreDecrement<StrideViewOverInputViewIterator>);
+static_assert(!CanPlus<StrideViewOverInputViewIterator>);
+static_assert(!CanMinusEqual<StrideViewOverInputViewIterator>);
+static_assert(!CanMinus<StrideViewOverInputViewIterator>);
+static_assert(!CanDifferencePlus<StrideViewOverInputViewIterator>);
+static_assert(!CanDifferenceMinus<StrideViewOverInputViewIterator>);
+static_assert(CanSentinelMinus<StrideViewOverInputViewIterator>);
+static_assert(std::invocable<std::equal_to<>, StrideViewOverInputViewIterator, StrideViewOverInputViewIterator>);
+static_assert(std::invocable<std::equal_to<>, StrideViewOverInputViewIterator, std::default_sentinel_t>);
+static_assert(std::invocable<std::equal_to<>, std::default_sentinel_t, StrideViewOverInputViewIterator>);
+
+static_assert(!std::is_invocable_v<std::less<>, StrideViewOverInputViewIterator, StrideViewOverInputViewIterator>);
+static_assert(
+    !std::is_invocable_v<std::less_equal<>, StrideViewOverInputViewIterator, StrideViewOverInputViewIterator>);
+static_assert(!std::is_invocable_v<std::greater<>, StrideViewOverInputViewIterator, StrideViewOverInputViewIterator>);
+static_assert(
+    !std::is_invocable_v<std::greater_equal<>, StrideViewOverInputViewIterator, StrideViewOverInputViewIterator>);
+
+static_assert(!CanSubscript<StrideViewOverInputViewIterator>);
+
+// What operators are valid for an iterator derived from a stride view
+// over a forward view.(sized sentinel)
+using ForwardView                       = BasicTestView<forward_iterator<int*>, sized_sentinel<forward_iterator<int*>>>;
+using StrideViewOverForwardViewIterator = std::ranges::iterator_t<std::ranges::stride_view<ForwardView>>;
+
+static_assert(std::weakly_incrementable<StrideViewOverForwardViewIterator>);
+
+static_assert(!CanPostDecrement<StrideViewOverForwardViewIterator>);
+static_assert(!CanPreDecrement<StrideViewOverForwardViewIterator>);
+static_assert(!CanPlus<StrideViewOverForwardViewIterator>);
+static_assert(!CanMinusEqual<StrideViewOverForwardViewIterator>);
+static_assert(!CanMinus<StrideViewOverForwardViewIterator>);
+static_assert(!CanDifferencePlus<StrideViewOverForwardViewIterator>);
+static_assert(!CanDifferenceMinus<StrideViewOverForwardViewIterator>);
+static_assert(CanSentinelMinus<StrideViewOverForwardViewIterator>);
+static_assert(std::invocable<std::equal_to<>, StrideViewOverForwardViewIterator, StrideViewOverForwardViewIterator>);
+static_assert(std::invocable<std::equal_to<>, StrideViewOverForwardViewIterator, std::default_sentinel_t>);
+static_assert(std::invocable<std::equal_to<>, std::default_sentinel_t, StrideViewOverForwardViewIterator>);
+
+static_assert(!std::is_invocable_v<std::less<>, StrideViewOverForwardViewIterator, StrideViewOverForwardViewIterator>);
+static_assert(
+    !std::is_invocable_v<std::less_equal<>, StrideViewOverForwardViewIterator, StrideViewOverForwardViewIterator>);
+static_assert(
+    !std::is_invocable_v<std::greater<>, StrideViewOverForwardViewIterator, StrideViewOverForwardViewIterator>);
+static_assert(
+    !std::is_invocable_v<std::greater_equal<>, StrideViewOverForwardViewIterator, StrideViewOverForwardViewIterator>);
+
+static_assert(!CanSubscript<StrideViewOverForwardViewIterator>);
+
+// What operators are valid for an iterator derived from a stride view
+// over a bidirectional view. (sized sentinel)
+using BidirectionalView = BasicTestView<bidirectional_iterator<int*>, sized_sentinel<bidirectional_iterator<int*>>>;
+using StrideViewOverBidirectionalViewIterator = std::ranges::iterator_t<std::ranges::stride_view<BidirectionalView>>;
+
+static_assert(CanPostDecrement<StrideViewOverBidirectionalViewIterator>);
+static_assert(CanPreDecrement<StrideViewOverBidirectionalViewIterator>);
+static_assert(!CanPlus<StrideViewOverBidirectionalViewIterator>);
+static_assert(!CanMinusEqual<StrideViewOverBidirectionalViewIterator>);
+static_assert(!CanMinus<StrideViewOverBidirectionalViewIterator>);
+static_assert(!CanDifferencePlus<StrideViewOverBidirectionalViewIterator>);
+static_assert(!CanDifferenceMinus<StrideViewOverBidirectionalViewIterator>);
+static_assert(CanSentinelMinus<StrideViewOverBidirectionalViewIterator>);
+static_assert(
+    std::invocable<std::equal_to<>, StrideViewOverBidirectionalViewIterator, StrideViewOverBidirectionalViewIterator>);
+static_assert(std::invocable<std::equal_to<>, StrideViewOverBidirectionalViewIterator, std::default_sentinel_t>);
+static_assert(std::invocable<std::equal_to<>, std::default_sentinel_t, StrideViewOverBidirectionalViewIterator>);
+
+static_assert(!std::is_invocable_v<std::less<>,
+                                   StrideViewOverBidirectionalViewIterator,
+                                   StrideViewOverBidirectionalViewIterator>);
+static_assert(!std::is_invocable_v<std::less_equal<>,
+                                   StrideViewOverBidirectionalViewIterator,
+                                   StrideViewOverBidirectionalViewIterator>);
+static_assert(!std::is_invocable_v<std::greater<>,
+                                   StrideViewOverBidirectionalViewIterator,
+                                   StrideViewOverBidirectionalViewIterator>);
+static_assert(!std::is_invocable_v<std::greater_equal<>,
+                                   StrideViewOverBidirectionalViewIterator,
+                                   StrideViewOverBidirectionalViewIterator>);
+
+static_assert(!CanSubscript<StrideViewOverBidirectionalViewIterator>);
+
+// What operators are valid for an iterator derived from a stride view
+// over a random access view. (non sized sentinel)
+using RandomAccessView                       = BasicTestView<random_access_iterator<int*>>;
+using StrideViewOverRandomAccessViewIterator = std::ranges::iterator_t<std::ranges::stride_view<RandomAccessView>>;
+
+static_assert(std::weakly_incrementable<StrideViewOverRandomAccessViewIterator>);
+
+static_assert(CanPostDecrement<StrideViewOverRandomAccessViewIterator>);
+static_assert(CanPreDecrement<StrideViewOverRandomAccessViewIterator>);
+static_assert(CanPlus<StrideViewOverRandomAccessViewIterator>);
+static_assert(CanMinusEqual<StrideViewOverRandomAccessViewIterator>);
+static_assert(CanMinus<StrideViewOverRandomAccessViewIterator>);
+static_assert(CanDifferencePlus<StrideViewOverRandomAccessViewIterator>);
+static_assert(CanDifferenceMinus<StrideViewOverRandomAccessViewIterator>);
+static_assert(!CanSentinelMinus<StrideViewOverRandomAccessViewIterator>);
+static_assert(
+    std::invocable<std::equal_to<>, StrideViewOverRandomAccessViewIterator, StrideViewOverRandomAccessViewIterator>);
+static_assert(std::invocable<std::equal_to<>, StrideViewOverRandomAccessViewIterator, std::default_sentinel_t>);
+static_assert(std::invocable<std::equal_to<>, std::default_sentinel_t, StrideViewOverRandomAccessViewIterator>);
+
+static_assert(
+    std::is_invocable_v<std::less<>, StrideViewOverRandomAccessViewIterator, StrideViewOverRandomAccessViewIterator>);
+static_assert(std::is_invocable_v<std::less_equal<>,
+                                  StrideViewOverRandomAccessViewIterator,
+                                  StrideViewOverRandomAccessViewIterator>);
+static_assert(std::is_invocable_v<std::greater<>,
+                                  StrideViewOverRandomAccessViewIterator,
+                                  StrideViewOverRandomAccessViewIterator>);
+static_assert(std::is_invocable_v<std::greater_equal<>,
+                                  StrideViewOverRandomAccessViewIterator,
+                                  StrideViewOverRandomAccessViewIterator>);
+
+static_assert(CanSubscript<StrideViewOverRandomAccessViewIterator>);
+
+using EqualableView               = BasicTestView<cpp17_input_iterator<int*>>;
+using EqualableViewStrideView     = std::ranges::stride_view<EqualableView>;
+using EqualableViewStrideViewIter = std::ranges::iterator_t<EqualableViewStrideView>;
+
+static_assert(std::equality_comparable<std::ranges::iterator_t<EqualableView>>);
+static_assert(std::equality_comparable<EqualableViewStrideViewIter>);
+
+static_assert(!std::three_way_comparable<std::ranges::iterator_t<EqualableView>>);
+static_assert(!std::ranges::random_access_range<EqualableView>);
+static_assert(!std::three_way_comparable<EqualableView>);
+
+using ThreeWayComparableView           = BasicTestView<three_way_contiguous_iterator<int*>>;
+using ThreeWayComparableViewStrideView = std::ranges::stride_view<ThreeWayComparableView>;
+using ThreeWayComparableStrideViewIter = std::ranges::iterator_t<ThreeWayComparableViewStrideView>;
+
+static_assert(std::three_way_comparable<std::ranges::iterator_t<ThreeWayComparableView>>);
+static_assert(std::ranges::random_access_range<ThreeWayComparableView>);
+static_assert(std::three_way_comparable<ThreeWayComparableStrideViewIter>);
+
+using UnEqualableView               = ViewOverNonCopyableIterator<cpp20_input_iterator<int*>>;
+using UnEqualableViewStrideView     = std::ranges::stride_view<UnEqualableView>;
+using UnEqualableViewStrideViewIter = std::ranges::iterator_t<UnEqualableViewStrideView>;
+
+static_assert(!std::equality_comparable<std::ranges::iterator_t<UnEqualableView>>);
+static_assert(!std::equality_comparable<UnEqualableViewStrideViewIter>);
+
+static_assert(!std::three_way_comparable<std::ranges::iterator_t<UnEqualableView>>);
+static_assert(!std::ranges::random_access_range<UnEqualableView>);
+static_assert(!std::three_way_comparable<UnEqualableView>);
+
+template <typename Iter>
+  requires std::sized_sentinel_for<Iter, Iter> && (!std::forward_iterator<Iter>)
+constexpr bool test_non_forward_operator_plus(Iter zero_begin, Iter one_begin, Iter end) {
+  using Base = BasicTestView<Iter, Iter>;
+  // Test the non-forward-range operator- between two iterators (i.e., ceil) and an
+  // iterator and a default sentinel.
+  using StrideViewIterator = std::ranges::iterator_t<std::ranges::stride_view<Base>>;
+  static_assert(std::weakly_incrementable<StrideViewIterator>);
+  static_assert(!std::ranges::forward_range<Base>);
+
+  // First, what operators are valid for an iterator derived from a stride view
+  // over a sized input view.
+
+  static_assert(!CanPostDecrement<StrideViewIterator>);
+  static_assert(!CanPreDecrement<StrideViewIterator>);
+  static_assert(!CanPlus<StrideViewIterator>);
+  static_assert(!CanMinusEqual<StrideViewIterator>);
+  static_assert(!CanDifferencePlus<StrideViewIterator>);
+  static_assert(!CanDifferenceMinus<StrideViewIterator>);
+  static_assert(CanSentinelMinus<StrideViewIterator>);
+
+  static_assert(!std::is_invocable_v<std::less<>, StrideViewIterator, StrideViewIterator>);
+  static_assert(!std::is_invocable_v<std::less_equal<>, StrideViewIterator, StrideViewIterator>);
+  static_assert(!std::is_invocable_v<std::greater<>, StrideViewIterator, StrideViewIterator>);
+  static_assert(!std::is_invocable_v<std::greater_equal<>, StrideViewIterator, StrideViewIterator>);
+  static_assert(std::is_invocable_v<std::equal_to<>, StrideViewIterator, StrideViewIterator>);
+  static_assert(std::is_invocable_v<std::equal_to<>, std::default_sentinel_t, StrideViewIterator>);
+  static_assert(std::is_invocable_v<std::equal_to<>, StrideViewIterator, std::default_sentinel_t>);
+  static_assert(!CanSubscript<StrideViewIterator>);
+
+  auto base_view_offset_zero             = Base(zero_begin, end);
+  auto base_view_offset_one              = Base(one_begin, end);
+  auto stride_view_over_base_zero_offset = std::ranges::stride_view(base_view_offset_zero, 3);
+  auto stride_view_over_base_one_offset  = std::ranges::stride_view(base_view_offset_one, 3);
+
+  auto sv_zero_offset_begin = stride_view_over_base_zero_offset.begin();
+  auto sv_one_offset_begin  = stride_view_over_base_one_offset.begin();
+
+  auto sv_zero_offset_zeroth_index = sv_zero_offset_begin;
+  auto sv_zero_offset_third_index  = ++sv_zero_offset_begin; // With a stride of 3, so ++ moves 3 indexes.
+  auto sv_zero_offset_sixth_index  = ++sv_zero_offset_begin; // With a stride of 3, so ++ moves 3 indexes.
+
+  auto sv_one_offset_oneth_index  = sv_one_offset_begin;
+  auto sv_one_offset_fourth_index = ++sv_one_offset_begin; // With a stride of 3, so ++ moves 3 indexes.
+
+  static_assert(std::sized_sentinel_for<std::ranges::iterator_t<Base>, std::ranges::iterator_t<Base>>);
+  static_assert(CanMinus<decltype(sv_zero_offset_begin)>);
+
+  // Check positive __n with exact multiple of left's stride.
+  assert(sv_zero_offset_third_index - sv_zero_offset_zeroth_index == 1);
+  assert(sv_zero_offset_sixth_index - sv_zero_offset_zeroth_index == 2);
+  // Check positive __n with non-exact multiple of left's stride (will do ceil here).
+  assert(sv_one_offset_oneth_index - sv_zero_offset_zeroth_index == 1);
+  assert(sv_one_offset_fourth_index - sv_zero_offset_zeroth_index == 2);
+
+  // Check negative __n with exact multiple of left's stride.
+  assert(sv_zero_offset_zeroth_index - sv_zero_offset_third_index == -1);
+  assert(sv_zero_offset_zeroth_index - sv_zero_offset_sixth_index == -2);
+  // Check negative __n with non-exact multiple of left's stride (will do ceil here).
+  assert(sv_zero_offset_zeroth_index - sv_one_offset_oneth_index == -1);
+  assert(sv_zero_offset_zeroth_index - sv_one_offset_fourth_index == -2);
+
+  assert(stride_view_over_base_zero_offset.end() == std::default_sentinel);
+  assert(std::default_sentinel == stride_view_over_base_zero_offset.end());
+
+  assert(std::default_sentinel - stride_view_over_base_zero_offset.end() == 0);
+  assert(stride_view_over_base_zero_offset.end() - std::default_sentinel == 0);
+  // assert((std::default_sentinel - )== 0);
+
+  assert(std::default_sentinel - stride_view_over_base_zero_offset.begin() ==
+         std::ranges::distance(stride_view_over_base_zero_offset));
+  assert(stride_view_over_base_zero_offset.begin() - std::default_sentinel ==
+         -std::ranges::distance(stride_view_over_base_zero_offset));
+
+  return true;
+}
+
+template <std::forward_iterator Iter, typename difference_type>
+constexpr bool test_forward_operator_plus(Iter begin, Iter end, difference_type distance) {
+  // Test the forward-range operator- between two iterators (i.e., no ceil) and
+  // an iterator and a default sentinel.
+  using Base = BasicTestView<Iter, Iter>;
+
+  using StrideViewIterator = std::ranges::iterator_t<std::ranges::stride_view<Base>>;
+  static_assert(std::ranges::forward_range<Base>);
+  static_assert(std::weakly_incrementable<StrideViewIterator>);
+
+  // First, what operators are valid for an iterator derived from a stride view
+  // over a sized forward view (even though it is actually much more than that!).
+
+  static_assert(CanMinus<StrideViewIterator>);
+  static_assert(CanSentinelMinus<StrideViewIterator>);
+
+  auto base_view_offset_zero             = Base(begin, end);
+  auto base_view_offset_one              = Base(begin + 1, end);
+  auto stride_view_over_base_zero_offset = std::ranges::stride_view(base_view_offset_zero, 3);
+  auto stride_view_over_base_one_offset  = std::ranges::stride_view(base_view_offset_one, 3);
+
+  auto sv_zero_offset_begin = stride_view_over_base_zero_offset.begin();
+  auto sv_one_offset_begin  = stride_view_over_base_one_offset.begin();
+
+  auto sv_zero_offset_should_be_one   = sv_zero_offset_begin;
+  auto sv_zero_offset_should_be_four  = ++sv_zero_offset_begin;
+  auto sv_zero_offset_should_be_seven = ++sv_zero_offset_begin;
+
+  auto sv_one_offset_should_be_two  = sv_one_offset_begin;
+  auto sv_one_offset_should_be_five = ++sv_one_offset_begin;
+
+  static_assert(std::sized_sentinel_for<std::ranges::iterator_t<Base>, std::ranges::iterator_t<Base>>);
+  static_assert(CanMinus<decltype(sv_zero_offset_begin)>);
+  static_assert(std::forward_iterator<std::ranges::iterator_t<Base>>);
+
+  // Check positive __n with exact multiple of left's stride.
+  assert(sv_zero_offset_should_be_four - sv_zero_offset_should_be_one == 1);
+  assert(sv_zero_offset_should_be_seven - sv_zero_offset_should_be_one == 2);
+
+  // Check positive __n with non-exact multiple of left's stride.
+  assert(sv_one_offset_should_be_two - sv_zero_offset_should_be_one == 0);
+  assert(sv_one_offset_should_be_five - sv_zero_offset_should_be_one == 1);
+
+  // Check negative __n with exact multiple of left's stride.
+  assert(sv_zero_offset_should_be_one - sv_zero_offset_should_be_four == -1);
+  assert(sv_zero_offset_should_be_one - sv_zero_offset_should_be_seven == -2);
+
+  // Check negative __n with non-exact multiple of left's stride.
+  assert(sv_zero_offset_should_be_one - sv_one_offset_should_be_two == 0);
+  assert(sv_zero_offset_should_be_one - sv_one_offset_should_be_five == -1);
+
+  // Make sure that all sentinel operations work!
+  assert(stride_view_over_base_zero_offset.end() == std::default_sentinel);
+  assert(std::default_sentinel == stride_view_over_base_zero_offset.end());
+
+  assert(stride_view_over_base_zero_offset.end() - std::default_sentinel == 0);
+  assert(std::default_sentinel - stride_view_over_base_zero_offset.begin() ==
+         std::ranges::distance(stride_view_over_base_zero_offset));
+  assert(stride_view_over_base_zero_offset.begin() - std::default_sentinel ==
+         -std::ranges::distance(stride_view_over_base_zero_offset));
+  assert(stride_view_over_base_zero_offset.begin() - std::default_sentinel == -distance);
+  assert(std::default_sentinel - stride_view_over_base_zero_offset.begin() == distance);
+  return true;
+}
+
+constexpr bool test_properly_handling_missing() {
+  // Check whether __missing_ gets handled properly.
+  using Base = BasicTestView<int*, int*>;
+  int arr[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+  auto base    = Base(arr, arr + 10);
+  auto strider = std::ranges::stride_view<Base>(base, 7);
+
+  auto strider_iter = strider.end();
+
+  strider_iter--;
+  assert(*strider_iter == 8);
+
+  // Now that we are back among the valid, we should
+  // have a normal stride length back (i.e., __missing_
+  // should be equal to 0).
+  strider_iter--;
+  assert(*strider_iter == 1);
+
+  strider_iter++;
+  assert(*strider_iter == 8);
+
+  // By striding past the end, we are going to generate
+  // another __missing_ != 0 value.
+  strider_iter++;
+  assert(strider_iter == strider.end());
+
+  // Make sure that all sentinel operations work!
+  assert(strider.end() == std::default_sentinel);
+  assert(std::default_sentinel == strider.end());
+
+  assert(strider_iter - std::default_sentinel == 0);
+  assert(std::default_sentinel - strider.end() == 0);
+  assert(std::default_sentinel - strider_iter == 0);
+
+  // Let's make sure that the newly regenerated __missing__ gets used.
+  strider_iter += -2;
+  assert(*strider_iter == 1);
+
+  return true;
+}
+
+int main(int, char**) {
+  {
+    constexpr int arr[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
+    std::vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
+    test_forward_operator_plus(arr, arr + 11, 4);
+    test_forward_operator_plus(vec.begin(), vec.end(), 4);
+  }
+
+  {
+    int arr[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+    test_non_forward_operator_plus(SizedInputIter(arr), SizedInputIter(arr + 1), SizedInputIter(arr + 10));
+  }
+
+  test_properly_handling_missing();
+  static_assert(test_properly_handling_missing());
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/plus.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/plus.pass.cpp
new file mode 100644
index 0000000000000..d18dc0b0d1b2f
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/plus.pass.cpp
@@ -0,0 +1,103 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr __iterator operator+(difference_type __n, const __iterator &__i)
+// constexpr __iterator operator+(const __iterator &__i, difference_type __n)
+
+#include <ranges>
+#include <vector>
+
+#include "../types.h"
+#include "test_iterators.h"
+
+template <class T>
+concept CanPlus =
+    std::is_same_v<T, decltype(std::declval<T>() + std::declval<typename T::__iterator::difference_type>())> &&
+    std::is_same_v<T, decltype(std::declval<typename T::__iterator::difference_type>() + std::declval<T>())> &&
+    requires(T& t, T::__iterator::difference_type& u) { t = t + u; } &&
+    requires(T& t, T::__iterator::difference_type& u) { t = u + t; };
+
+// Make sure that we cannot use + on a stride view iterator and difference_type
+// over an input view.(sized sentinel)
+using InputView = BasicTestView<cpp17_input_iterator<int*>, sized_sentinel<cpp17_input_iterator<int*>>>;
+using StrideViewOverInputViewIterator = std::ranges::iterator_t<std::ranges::stride_view<InputView>>;
+
+static_assert(std::ranges::input_range<InputView>);
+static_assert(!CanPlus<StrideViewOverInputViewIterator>);
+
+// Make sure that we cannot use + on a stride view iterator and difference_type
+// over a forward view.(sized sentinel)
+using ForwardView                       = BasicTestView<forward_iterator<int*>, sized_sentinel<forward_iterator<int*>>>;
+using StrideViewOverForwardViewIterator = std::ranges::iterator_t<std::ranges::stride_view<ForwardView>>;
+
+static_assert(std::ranges::forward_range<ForwardView>);
+static_assert(!CanPlus<StrideViewOverForwardViewIterator>);
+
+// Make sure that we cannot use + on a stride view iterator and difference_type
+// over a bidirectional view. (sized sentinel)
+using BidirectionalView = BasicTestView<bidirectional_iterator<int*>, sized_sentinel<bidirectional_iterator<int*>>>;
+using StrideViewOverBidirectionalViewIterator = std::ranges::iterator_t<std::ranges::stride_view<BidirectionalView>>;
+
+static_assert(std::ranges::bidirectional_range<BidirectionalView>);
+static_assert(!CanPlus<StrideViewOverBidirectionalViewIterator>);
+
+// Make sure that we can use += on a stride view iterator and difference_type
+// over a random access view. (non sized sentinel)
+template <typename RandomAccessIterator = random_access_iterator<int*>>
+using RandomAccessView                       = BasicTestView<RandomAccessIterator>;
+using StrideViewOverRandomAccessViewIterator = std::ranges::iterator_t<std::ranges::stride_view<RandomAccessView<>>>;
+
+static_assert(std::ranges::random_access_range<RandomAccessView<>>);
+static_assert(CanPlus<StrideViewOverRandomAccessViewIterator>);
+
+constexpr bool test_random_access_operator_plus_equal() {
+  using Iter = std::vector<int>::iterator;
+  using Diff = Iter::difference_type;
+  std::vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
+  // Test the operator+ between an iterator and its difference type. Pay attention solely to
+  // stride views over random-access ranges because operator+ is not applicable to others.
+
+  auto begin    = vec.begin();
+  auto end      = vec.end();
+  Diff distance = 4;
+
+  // Do not use the RandomAccessView defined in types.h to give the test user more power
+  // to customize an iterator and a default sentinel.
+  using Base = RandomAccessView<Iter>;
+  static_assert(std::ranges::random_access_range<Base>);
+
+  auto base_view                  = Base(begin, end);
+  auto stride_view_over_base_view = std::ranges::stride_view(base_view, 1);
+
+  auto base_view_offset                  = Base(begin + distance, end);
+  auto stride_view_over_base_view_offset = std::ranges::stride_view(base_view_offset, 1);
+
+  assert(*(stride_view_over_base_view.begin() + distance) == *(stride_view_over_base_view_offset.begin()));
+
+  auto distance_to_last                    = (end - 1) - begin;
+  auto stride_view_over_base_view_big_step = std::ranges::stride_view(base_view, distance_to_last);
+
+  assert(*(stride_view_over_base_view_big_step.begin() + 1) ==
+         *(stride_view_over_base_view.begin() + distance_to_last));
+  assert((stride_view_over_base_view_big_step.begin() + 2) == (stride_view_over_base_view.end()));
+
+  return true;
+}
+
+consteval bool do_static_tests() {
+  assert(test_random_access_operator_plus_equal());
+  return true;
+}
+
+int main(int, char**) {
+  static_assert(do_static_tests());
+  assert(do_static_tests());
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/plus_equal.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/plus_equal.pass.cpp
new file mode 100644
index 0000000000000..17cb295a48e6b
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/iterator/plus_equal.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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr __iterator& operator+=(difference_type __n)
+
+#include <ranges>
+#include <utility>
+#include <vector>
+
+#include "../types.h"
+#include "test_iterators.h"
+
+template <class T>
+concept CanPlus =
+    std::is_same_v<T&, decltype(std::declval<T>() += std::declval<typename T::__iterator::difference_type>())> &&
+    requires(T& t, T::__iterator::difference_type& u) { t += u; };
+
+// Make sure that we cannot use += on a stride view iterator
+// over an input view.(sized sentinel)
+using InputView = BasicTestView<cpp17_input_iterator<int*>, sized_sentinel<cpp17_input_iterator<int*>>>;
+using StrideViewOverInputViewIterator = std::ranges::iterator_t<std::ranges::stride_view<InputView>>;
+
+static_assert(std::ranges::input_range<InputView>);
+static_assert(!CanPlus<StrideViewOverInputViewIterator>);
+
+// Make sure that we cannot use += on a stride view iterator
+// over a forward view.(sized sentinel)
+using ForwardView                       = BasicTestView<forward_iterator<int*>, sized_sentinel<forward_iterator<int*>>>;
+using StrideViewOverForwardViewIterator = std::ranges::iterator_t<std::ranges::stride_view<ForwardView>>;
+
+static_assert(std::ranges::forward_range<ForwardView>);
+static_assert(!CanPlus<StrideViewOverForwardViewIterator>);
+
+// Make sure that we cannot use += on a stride view iterator
+// over a bidirectional view. (sized sentinel)
+using BidirectionalView = BasicTestView<bidirectional_iterator<int*>, sized_sentinel<bidirectional_iterator<int*>>>;
+using StrideViewOverBidirectionalViewIterator = std::ranges::iterator_t<std::ranges::stride_view<BidirectionalView>>;
+
+static_assert(std::ranges::bidirectional_range<BidirectionalView>);
+static_assert(!CanPlus<StrideViewOverBidirectionalViewIterator>);
+
+// Make sure that we can use += on a stride view iterator
+// over a random access view. (non sized sentinel)
+template <typename RandomAccessIterator = random_access_iterator<int*>>
+using RandomAccessView                       = BasicTestView<RandomAccessIterator>;
+using StrideViewOverRandomAccessViewIterator = std::ranges::iterator_t<std::ranges::stride_view<RandomAccessView<>>>;
+
+static_assert(std::ranges::random_access_range<RandomAccessView<>>);
+static_assert(CanPlus<StrideViewOverRandomAccessViewIterator>);
+
+constexpr bool test_random_access_operator_plus_equal() {
+  using Iter = std::vector<int>::iterator;
+  using Diff = Iter::difference_type;
+  std::vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
+  // Test the operator+ between an iterator and its difference type. Pay attention solely to
+  // stride views over random-access ranges because operator+ is not applicable to others.
+
+  auto begin    = vec.begin();
+  auto end      = vec.end();
+  Diff distance = 4;
+
+  // Test the forward-range operator+= between an iterator and its difference type.
+  // Do not use the RandomAccessView defined in types.h to give the test user more power
+  // to customize an iterator and a default sentinel.
+  using Base = RandomAccessView<Iter>;
+  static_assert(std::ranges::random_access_range<Base>);
+
+  auto base_view                  = Base(begin, end);
+  auto stride_view_over_base_view = std::ranges::stride_view(base_view, 1);
+
+  auto base_view_offset                  = Base(begin + distance, end);
+  auto stride_view_over_base_view_offset = std::ranges::stride_view(base_view_offset, 1);
+
+  auto sv_bv_begin        = stride_view_over_base_view.begin();
+  auto sv_bv_offset_begin = stride_view_over_base_view_offset.begin();
+
+  auto sv_bv_begin_after_distance = sv_bv_begin += distance;
+  assert(*sv_bv_begin == *sv_bv_offset_begin);
+  assert(*sv_bv_begin_after_distance == *sv_bv_offset_begin);
+
+  auto big_step                            = (end - 1) - begin;
+  auto stride_view_over_base_view_big_step = std::ranges::stride_view(base_view, big_step);
+  sv_bv_begin                              = stride_view_over_base_view_big_step.begin();
+
+  // This += should move us into a position where the __missing_ will come into play.
+  // Do a -= 1 here to confirm that the __missing_ is taken into account.
+  sv_bv_begin += 2;
+  sv_bv_begin -= 1;
+  assert(*sv_bv_begin == *(stride_view_over_base_view.begin() + big_step));
+  return true;
+}
+
+consteval bool do_static_tests() {
+  assert(test_random_access_operator_plus_equal());
+  return true;
+}
+
+int main(int, char**) {
+  static_assert(do_static_tests());
+  assert(do_static_tests());
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/size.verify.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/size.verify.cpp
new file mode 100644
index 0000000000000..64dec9460323f
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/size.verify.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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// expected-no-diagnostics
+
+// constexpr auto size()
+
+#include <ranges>
+
+#include "test_iterators.h"
+#include "types.h"
+
+// There is no size member function on a stride view over a view that
+// is *not* a sized range
+static_assert(!std::ranges::sized_range<BasicTestView<cpp17_input_iterator<int*>>>);
+static_assert(!std::ranges::sized_range<std::ranges::stride_view<BasicTestView<cpp17_input_iterator<int*>>>>);
+
+// There is a size member function on a stride view over a view that
+// *is* a sized range
+static_assert(std::ranges::sized_range<BasicTestView<int*, sentinel_wrapper<int*>, true>>);
+static_assert(std::ranges::sized_range<std::ranges::stride_view<BasicTestView<int*, sentinel_wrapper<int*>, true>>>);
+
+constexpr bool test() {
+  {
+    // Test with stride as exact multiple of number of elements in view strided over.
+    constexpr auto iota_twelve = std::views::iota(0, 12);
+    static_assert(std::ranges::sized_range<decltype(iota_twelve)>);
+    constexpr auto stride_iota_twelve = std::views::stride(iota_twelve, 3);
+    static_assert(std::ranges::sized_range<decltype(stride_iota_twelve)>);
+    static_assert(4 == stride_iota_twelve.size(), "Striding by 3 through a 12 member list has size 4.");
+  }
+
+  {
+    // Test with stride as inexact multiple of number of elements in view strided over.
+    constexpr auto iota_twenty_two = std::views::iota(0, 22);
+    static_assert(std::ranges::sized_range<decltype(iota_twenty_two)>);
+    constexpr auto stride_iota_twenty_two = std::views::stride(iota_twenty_two, 3);
+    static_assert(std::ranges::sized_range<decltype(stride_iota_twenty_two)>);
+    static_assert(8 == stride_iota_twenty_two.size(), "Striding by 3 through a 22 member list has size 8.");
+  }
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp
new file mode 100644
index 0000000000000..b9879c1c473f8
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/stride.pass.cpp
@@ -0,0 +1,40 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr range_difference_t<_View> stride() const noexcept;
+
+#include <ranges>
+
+#include "test_iterators.h"
+#include "types.h"
+
+constexpr bool test() {
+  using View = BasicTestView<cpp17_input_iterator<int*>>;
+  int arr[]{1, 2, 3};
+  auto arrv(View(cpp17_input_iterator<int*>(arr), cpp17_input_iterator<int*>(arr + 3)));
+  // Mark str const so that we confirm that stride is a const member function.
+  const std::ranges::stride_view<View> str(arrv, 1);
+
+  // Make sure that stride member function is noexcept.
+  static_assert(noexcept(str.stride()));
+  // Make sure that the type returned by stride matches what is expected.
+  ASSERT_SAME_TYPE(std::ranges::range_difference_t<View>, decltype(str.stride()));
+  // Make sure that we get back a stride equal to the one that we gave in the ctor.
+  assert(str.stride() == 1);
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/types.h b/libcxx/test/std/ranges/range.adaptors/range.stride.view/types.h
new file mode 100644
index 0000000000000..5879c5022006e
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/types.h
@@ -0,0 +1,296 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_STRIDE_TYPES_H
+#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_STRIDE_TYPES_H
+
+#include <cstddef>
+#include <functional>
+#include <iterator>
+#include <ranges>
+
+#include "test_iterators.h"
+#include "test_range.h"
+
+// Concepts
+
+template <typename Iter>
+concept IterDifferable = std::invocable<std::minus<>, Iter, Iter>;
+
+// Iterators
+
+// The base for an iterator that keeps a count of the times that it is
+// moved and copied.
+template <class Derived, std::input_iterator Iter>
+struct IterBase {
+  using value_type      = typename std::iterator_traits<Iter>::value_type;
+  using difference_type = typename std::iterator_traits<Iter>::difference_type;
+
+  int* move_counter = nullptr;
+  int* copy_counter = nullptr;
+
+  Iter value_{};
+
+  constexpr IterBase() = default;
+  constexpr explicit IterBase(Iter value) : value_(value) {}
+
+  constexpr IterBase(const IterBase& other) noexcept {
+    copy_counter = other.copy_counter;
+    move_counter = other.move_counter;
+    if (copy_counter != nullptr) {
+      (*copy_counter)++;
+    }
+    value_ = other.value_;
+  }
+
+  constexpr IterBase(IterBase&& other) noexcept {
+    copy_counter = other.copy_counter;
+    move_counter = other.move_counter;
+    if (move_counter != nullptr) {
+      (*move_counter)++;
+    }
+    value_ = std::move(other.value_);
+  }
+  constexpr IterBase& operator=(const IterBase& other) = default;
+  constexpr IterBase& operator=(IterBase&& other)      = default;
+};
+
+// The base for an input iterator that keeps a count of the times that it is
+// moved and copied.
+template <class Derived, std::input_iterator Iter = int*, bool IsSized = false>
+  requires((!IsSized) || (IsSized && IterDifferable<Iter>))
+struct InputIter : IterBase<Derived, Iter> {
+  using Base = IterBase<Derived, Iter>;
+
+  using typename Base::difference_type;
+  using typename Base::value_type;
+
+  using iterator_concept  = std::input_iterator_tag;
+  using iterator_category = std::input_iterator_tag;
+
+  using Base::Base;
+
+  constexpr value_type operator*() const { return *Base::value_; }
+  constexpr Derived& operator++() {
+    Base::value_++;
+    return static_cast<Derived&>(*this);
+  }
+  constexpr Derived operator++(int) {
+    auto nv = *this;
+    Base::value_++;
+    return nv;
+  }
+  friend constexpr bool operator==(const Derived& left, const Derived& right) { return left.value_ == right.value_; }
+  friend constexpr difference_type operator-(const Derived& left, const Derived& right)
+    requires IsSized
+  {
+    return left.value_ - right.value_;
+  }
+};
+
+// In input iterator that is unsized.
+struct UnsizedInputIter : InputIter<UnsizedInputIter, int*, false> {
+  using InputIter::InputIter;
+};
+static_assert(std::input_iterator<UnsizedInputIter>);
+static_assert(!std::sized_sentinel_for<UnsizedInputIter, UnsizedInputIter>);
+
+// In input iterator that is sized.
+struct SizedInputIter : InputIter<SizedInputIter, int*, true> {
+  using InputIter::InputIter;
+};
+static_assert(std::input_iterator<SizedInputIter>);
+static_assert(std::sized_sentinel_for<SizedInputIter, SizedInputIter>);
+
+// Views
+
+// Put IterMoveIterSwapTestRangeIterator in a namespace to test ADL of CPOs iter_swap and iter_move
+// (see iter_swap.pass.cpp and iter_move.pass.cpp).
+namespace adl {
+template <std::input_iterator Iter = int*, bool IsIterSwappable = true, bool IsNoExceptIterMoveable = true>
+struct IterMoveIterSwapTestRangeIterator
+    : InputIter<IterMoveIterSwapTestRangeIterator<Iter, IsIterSwappable, IsNoExceptIterMoveable>, Iter, false> {
+  int* counter_{nullptr};
+
+  using InputIter<IterMoveIterSwapTestRangeIterator<Iter, IsIterSwappable, IsNoExceptIterMoveable>, Iter, false>::
+      InputIter;
+
+  constexpr IterMoveIterSwapTestRangeIterator(Iter value, int* counter)
+      : InputIter<IterMoveIterSwapTestRangeIterator<Iter, IsIterSwappable, IsNoExceptIterMoveable>, Iter, false>(value),
+        counter_(counter) {}
+
+  friend constexpr void iter_swap(IterMoveIterSwapTestRangeIterator t, IterMoveIterSwapTestRangeIterator u) noexcept
+    requires IsIterSwappable && IsNoExceptIterMoveable
+  {
+    (*t.counter_)++;
+    (*u.counter_)++;
+    std::swap(*t.value_, *u.value_);
+  }
+
+  friend constexpr void iter_swap(IterMoveIterSwapTestRangeIterator t, IterMoveIterSwapTestRangeIterator u)
+    requires IsIterSwappable && (!IsNoExceptIterMoveable)
+  {
+    (*t.counter_)++;
+    (*u.counter_)++;
+    std::swap(*t.value_, *u.value_);
+  }
+
+  friend constexpr auto iter_move(const IterMoveIterSwapTestRangeIterator& t)
+    requires(!IsNoExceptIterMoveable)
+  {
+    (*t.counter_)++;
+    return *t.value_;
+  }
+  friend constexpr auto iter_move(const IterMoveIterSwapTestRangeIterator& t) noexcept
+    requires IsNoExceptIterMoveable
+  {
+    (*t.counter_)++;
+    return *t.value_;
+  }
+};
+} // namespace adl
+
+template <typename Iter = int*, bool IsSwappable = true, bool IsNoExcept = true>
+struct IterMoveIterSwapTestRange : std::ranges::view_base {
+  adl::IterMoveIterSwapTestRangeIterator<Iter, IsSwappable, IsNoExcept> begin_;
+  adl::IterMoveIterSwapTestRangeIterator<Iter, IsSwappable, IsNoExcept> end_;
+  constexpr IterMoveIterSwapTestRange(const Iter& begin, const Iter& end, int* counter)
+      : begin_(adl::IterMoveIterSwapTestRangeIterator<Iter, IsSwappable, IsNoExcept>(begin, counter)),
+        end_(adl::IterMoveIterSwapTestRangeIterator<Iter, IsSwappable, IsNoExcept>(end, counter)) {}
+  constexpr adl::IterMoveIterSwapTestRangeIterator<Iter, IsSwappable, IsNoExcept> begin() const { return begin_; }
+  constexpr adl::IterMoveIterSwapTestRangeIterator<Iter, IsSwappable, IsNoExcept> end() const { return end_; }
+};
+
+// Views
+
+// Depending upon configuration, ViewOrRange is either a View or not.
+template <bool IsView>
+struct MaybeView {};
+template <>
+struct MaybeView<true> : std::ranges::view_base {};
+
+template <std::input_iterator Iter,
+          std::sentinel_for<Iter> Sent = sentinel_wrapper<Iter>,
+          bool IsSized                 = false,
+          bool IsView                  = false,
+          bool IsCopyable              = false >
+  requires((!IsSized) || (IsSized && IterDifferable<Iter>))
+struct BasicTestViewOrRange : MaybeView<IsView> {
+  Iter begin_{};
+  Iter end_{};
+
+  constexpr BasicTestViewOrRange(const Iter& b, const Iter& e) : begin_(b), end_(e) {}
+
+  constexpr Iter begin() { return begin_; }
+  constexpr Iter begin() const { return begin_; }
+  constexpr Sent end() { return Sent{end_}; }
+  constexpr Sent end() const { return Sent{end_}; }
+
+  constexpr auto size() const
+    requires IsSized
+  {
+    return begin_ - end_;
+  }
+
+  constexpr BasicTestViewOrRange(BasicTestViewOrRange&& other)      = default;
+  constexpr BasicTestViewOrRange& operator=(BasicTestViewOrRange&&) = default;
+
+  constexpr BasicTestViewOrRange(const BasicTestViewOrRange&)
+    requires(!IsCopyable)
+  = delete;
+  constexpr BasicTestViewOrRange(const BasicTestViewOrRange&)
+    requires IsCopyable
+  = default;
+
+  constexpr BasicTestViewOrRange& operator=(const BasicTestViewOrRange&)
+    requires(!IsCopyable)
+  = delete;
+  constexpr BasicTestViewOrRange& operator=(const BasicTestViewOrRange&)
+    requires IsCopyable
+  = default;
+};
+
+template <std::input_iterator Iter, std::sentinel_for<Iter> Sent = sentinel_wrapper<Iter>, bool IsSized = false>
+  requires((!IsSized) || (IsSized && IterDifferable<Iter>))
+using BasicTestView = BasicTestViewOrRange<Iter, Sent, IsSized, true /* IsView */, true /* IsCopyable */>;
+
+template <std::input_iterator Iter, std::sentinel_for<Iter> Sent = sentinel_wrapper<Iter>, bool IsCopyable = true>
+using MaybeCopyableAlwaysMoveableView = BasicTestViewOrRange<Iter, Sent, false, true, IsCopyable>;
+
+static_assert(std::ranges::view<MaybeCopyableAlwaysMoveableView<cpp17_input_iterator<int*>>>);
+static_assert(std::ranges::view<MaybeCopyableAlwaysMoveableView<cpp17_input_iterator<int*>,
+                                                                sentinel_wrapper<cpp17_input_iterator<int*>>,
+                                                                false>>);
+
+static_assert(std::copyable<MaybeCopyableAlwaysMoveableView<cpp17_input_iterator<int*>>>);
+template <std::input_iterator Iter, std::sentinel_for<Iter> Sent = sentinel_wrapper<Iter>>
+using CopyableView = MaybeCopyableAlwaysMoveableView<Iter, Sent>;
+static_assert(std::copyable<CopyableView<cpp17_input_iterator<int*>>>);
+
+template <class Iter, std::sentinel_for<Iter> Sent = sentinel_wrapper<Iter>>
+using MoveOnlyView = MaybeCopyableAlwaysMoveableView<Iter, Sent, false>;
+static_assert(!std::copyable<MoveOnlyView<cpp17_input_iterator<int*>>>);
+
+template <bool IsSimple, bool IsConst = IsSimple, bool IsCommon = true, bool IsSized = false>
+struct MaybeConstCommonSimpleView : std::ranges::view_base {
+  int* begin();
+  int* begin() const
+    requires(IsConst && IsSimple);
+  double* begin() const
+    requires(IsConst && !IsSimple);
+
+  int* end()
+    requires(IsCommon);
+  void* end()
+    requires(!IsCommon);
+
+  int* end() const
+    requires(IsConst && IsCommon && IsSimple);
+  double* end() const
+    requires(IsConst && IsCommon && !IsSimple);
+
+  void* end() const
+    requires(IsConst && !IsCommon);
+
+  size_t size() const
+    requires(IsSized);
+};
+
+using UnSimpleNoConstCommonView    = MaybeConstCommonSimpleView<false, false, true>;
+using UnSimpleConstView            = MaybeConstCommonSimpleView<false, true, true>;
+using UnsimpleUnCommonConstView    = MaybeConstCommonSimpleView<false, true, false>;
+using SimpleUnCommonConstView      = MaybeConstCommonSimpleView<true, true, false>;
+using SimpleCommonConstView        = MaybeConstCommonSimpleView<true, true, true>;
+using SimpleNoConstSizedCommonView = MaybeConstCommonSimpleView<true, false, true, true>;
+
+// Don't move/hold the iterator itself, copy/hold the base
+// of that iterator and reconstruct the iterator on demand.
+// May result in aliasing (if, e.g., Iterator is an iterator
+// over int *).
+template <class Iter, std::sentinel_for<Iter> Sent = sentinel_wrapper<Iter>>
+struct ViewOverNonCopyableIterator : std::ranges::view_base {
+  constexpr explicit ViewOverNonCopyableIterator(Iter it, Sent sent) : it_(base(it)), sent_(base(sent)) {}
+
+  ViewOverNonCopyableIterator(ViewOverNonCopyableIterator&&)            = default;
+  ViewOverNonCopyableIterator& operator=(ViewOverNonCopyableIterator&&) = default;
+
+  constexpr Iter begin() const { return Iter(it_); }
+  constexpr Sent end() const { return Sent(sent_); }
+
+private:
+  decltype(base(std::declval<Iter>())) it_;
+  decltype(base(std::declval<Sent>())) sent_;
+};
+
+// Ranges
+
+template <std::input_iterator Iter, std::sentinel_for<Iter> Sent = sentinel_wrapper<Iter>, bool IsSized = false>
+  requires((!IsSized) || (IsSized && IterDifferable<Iter>))
+using BasicTestRange = BasicTestViewOrRange<Iter, Sent, IsSized, false>;
+
+#endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_STRIDE_TYPES_H
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index c91bdf4ed99ec..887429585d3a3 100644
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -1157,6 +1157,11 @@ def add_version_header(tc):
             "values": {"c++23": 202106},
             "headers": ["algorithm"],
         },
+        {
+            "name": "__cpp_lib_ranges_stride",
+            "values": {"c++23": 202207},
+            "headers": ["ranges"],
+        },
         {
             "name": "__cpp_lib_ranges_to_container",
             "values": {"c++23": 202202},



More information about the libcxx-commits mailing list