[libcxx-commits] [libcxx] 9c5d86a - [libcxx][iterator][ranges] adds `bidirectional_iterator` and `bidirectional_range`

Christopher Di Bella via libcxx-commits libcxx-commits at lists.llvm.org
Mon May 3 14:25:39 PDT 2021


Author: Christopher Di Bella
Date: 2021-05-03T21:21:33Z
New Revision: 9c5d86aac505228eddbfda86aa558467d0b7c5e6

URL: https://github.com/llvm/llvm-project/commit/9c5d86aac505228eddbfda86aa558467d0b7c5e6
DIFF: https://github.com/llvm/llvm-project/commit/9c5d86aac505228eddbfda86aa558467d0b7c5e6.diff

LOG: [libcxx][iterator][ranges] adds `bidirectional_iterator` and `bidirectional_range`

Implements parts of:
    * P0896R4 The One Ranges Proposal`

Depends on D100275.

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

Added: 
    libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.bidir/bidirectional_iterator.compile.pass.cpp
    libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.bidir/subsumption.compile.pass.cpp
    libcxx/test/std/ranges/range.refinements/bidirectional_range.compile.pass.cpp

Modified: 
    libcxx/include/__iterator/concepts.h
    libcxx/include/__ranges/concepts.h
    libcxx/include/iterator
    libcxx/include/ranges
    libcxx/test/std/containers/associative/map/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/associative/multimap/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/associative/multiset/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/associative/set/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/sequences/array/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/sequences/deque/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/sequences/forwardlist/forwardlist.iter/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/sequences/list/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/sequences/vector.bool/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/sequences/vector/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/unord/unord.map/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/unord/unord.multimap/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/unord/unord.multiset/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/unord/unord.set/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/views/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/views/span.iterators/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/iterators/predef.iterators/reverse.iterators/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/ranges/range.refinements/subsumption.compile.pass.cpp
    libcxx/test/std/re/re.iter/re.regiter/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/re/re.iter/re.tokiter/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/strings/basic.string/string.iterators/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/strings/string.view/range_concept_conformance.compile.pass.cpp
    libcxx/test/std/strings/string.view/string.view.iterators/iterator_concept_conformance.compile.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/include/__iterator/concepts.h b/libcxx/include/__iterator/concepts.h
index 3e6022b7cd8f..c83fd92364c8 100644
--- a/libcxx/include/__iterator/concepts.h
+++ b/libcxx/include/__iterator/concepts.h
@@ -127,7 +127,17 @@ concept forward_iterator =
   incrementable<_Ip> &&
   sentinel_for<_Ip, _Ip>;
 
-// clang-format on
+// [iterator.concept.bidir]
+template<class _Ip>
+concept bidirectional_iterator =
+  forward_iterator<_Ip> &&
+  derived_from<_ITER_CONCEPT<_Ip>, bidirectional_iterator_tag> &&
+  requires(_Ip __i) {
+    { --__i } -> same_as<_Ip&>;
+    { __i-- } -> same_as<_Ip>;
+  };
+
+  // clang-format on
 
 #endif // !defined(_LIBCPP_HAS_NO_RANGES)
 

diff  --git a/libcxx/include/__ranges/concepts.h b/libcxx/include/__ranges/concepts.h
index 36e6739e1851..578b153ad00e 100644
--- a/libcxx/include/__ranges/concepts.h
+++ b/libcxx/include/__ranges/concepts.h
@@ -58,8 +58,10 @@ namespace ranges {
   concept forward_range = input_range<_Tp> && forward_iterator<iterator_t<_Tp> >;
 
   template <class _Tp>
-  concept common_range = range<_Tp> && same_as<iterator_t<_Tp>, sentinel_t<_Tp> >;
+  concept bidirectional_range = forward_range<_Tp> && bidirectional_iterator<iterator_t<_Tp> >;
 
+  template <class _Tp>
+  concept common_range = range<_Tp> && same_as<iterator_t<_Tp>, sentinel_t<_Tp> >;
 } // namespace ranges
 
 #endif // !defined(_LIBCPP_HAS_NO_RANGES)

diff  --git a/libcxx/include/iterator b/libcxx/include/iterator
index 78f67ddf2229..97677feee030 100644
--- a/libcxx/include/iterator
+++ b/libcxx/include/iterator
@@ -83,6 +83,10 @@ template<class I>
 template<class I>
   concept forward_iterator = see below;                    // since C++20
 
+// [iterator.concept.bidir], concept bidirectional_iterator
+template<class I>
+  concept bidirectional_iterator = see below;              // since C++20
+
 template<class Category, class T, class Distance = ptr
diff _t,
          class Pointer = T*, class Reference = T&>
 struct iterator

diff  --git a/libcxx/include/ranges b/libcxx/include/ranges
index 58b67f1d086e..0328360b4ffe 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -54,6 +54,9 @@ namespace std::ranges {
   template<class T>
     concept forward_range = see below;
 
+  template<class T>
+  concept bidirectional_range = see below;
+
   template <class _Tp>
     concept common_range = see below;
 }

diff  --git a/libcxx/test/std/containers/associative/map/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/map/iterator_concept_conformance.compile.pass.cpp
index a833200a17c0..1f2707a9c9eb 100644
--- a/libcxx/test/std/containers/associative/map/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/associative/map/iterator_concept_conformance.compile.pass.cpp
@@ -22,7 +22,7 @@ using reverse_iterator = std::map<int, int>::reverse_iterator;
 using const_reverse_iterator = std::map<int, int>::const_reverse_iterator;
 using value_type = std::pair<const int, int>;
 
-static_assert(std::forward_iterator<iterator>);
+static_assert(std::bidirectional_iterator<iterator>);
 static_assert(!std::indirectly_writable<iterator, value_type>);
 static_assert(std::sentinel_for<iterator, iterator>);
 static_assert(std::sentinel_for<iterator, const_iterator>);
@@ -33,7 +33,7 @@ static_assert(!std::sized_sentinel_for<iterator, const_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, reverse_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, const_reverse_iterator>);
 
-static_assert(std::forward_iterator<const_iterator>);
+static_assert(std::bidirectional_iterator<const_iterator>);
 static_assert(!std::indirectly_writable<const_iterator, value_type>);
 static_assert(std::sentinel_for<const_iterator, iterator>);
 static_assert(std::sentinel_for<const_iterator, const_iterator>);

diff  --git a/libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp
index 998227d0e0de..2995a5256c64 100644
--- a/libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp
@@ -22,8 +22,8 @@ namespace stdr = std::ranges;
 
 static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
 static_assert(stdr::common_range<range>);
-static_assert(stdr::forward_range<range>);
+static_assert(stdr::bidirectional_range<range>);
 
 static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);
 static_assert(stdr::common_range<range const>);
-static_assert(stdr::forward_range<range const>);
+static_assert(stdr::bidirectional_range<range const>);

diff  --git a/libcxx/test/std/containers/associative/multimap/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/multimap/iterator_concept_conformance.compile.pass.cpp
index 1693fa076d6e..1f223d9984a6 100644
--- a/libcxx/test/std/containers/associative/multimap/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/associative/multimap/iterator_concept_conformance.compile.pass.cpp
@@ -22,7 +22,7 @@ using reverse_iterator = std::multimap<int, int>::reverse_iterator;
 using const_reverse_iterator = std::multimap<int, int>::const_reverse_iterator;
 using value_type = std::pair<const int, int>;
 
-static_assert(std::forward_iterator<iterator>);
+static_assert(std::bidirectional_iterator<iterator>);
 static_assert(!std::indirectly_writable<iterator, value_type>);
 static_assert(std::sentinel_for<iterator, iterator>);
 static_assert(std::sentinel_for<iterator, const_iterator>);
@@ -33,7 +33,7 @@ static_assert(!std::sized_sentinel_for<iterator, const_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, reverse_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, const_reverse_iterator>);
 
-static_assert(std::forward_iterator<const_iterator>);
+static_assert(std::bidirectional_iterator<const_iterator>);
 static_assert(!std::indirectly_writable<const_iterator, value_type>);
 static_assert(std::sentinel_for<const_iterator, iterator>);
 static_assert(std::sentinel_for<const_iterator, const_iterator>);

diff  --git a/libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp
index dde9ba12f73a..f9d28d48813f 100644
--- a/libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp
@@ -22,8 +22,8 @@ namespace stdr = std::ranges;
 
 static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
 static_assert(stdr::common_range<range>);
-static_assert(stdr::forward_range<range>);
+static_assert(stdr::bidirectional_range<range>);
 
 static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);
 static_assert(stdr::common_range<range const>);
-static_assert(stdr::forward_range<range const>);
+static_assert(stdr::bidirectional_range<range const>);

diff  --git a/libcxx/test/std/containers/associative/multiset/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/multiset/iterator_concept_conformance.compile.pass.cpp
index 1c88b557dab3..f09efa6aed00 100644
--- a/libcxx/test/std/containers/associative/multiset/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/associative/multiset/iterator_concept_conformance.compile.pass.cpp
@@ -22,7 +22,7 @@ using reverse_iterator = std::multiset<int>::reverse_iterator;
 using const_reverse_iterator = std::multiset<int>::const_reverse_iterator;
 using value_type = int;
 
-static_assert(std::forward_iterator<iterator>);
+static_assert(std::bidirectional_iterator<iterator>);
 static_assert(!std::indirectly_writable<iterator, value_type>);
 static_assert(std::sentinel_for<iterator, iterator>);
 static_assert(std::sentinel_for<iterator, const_iterator>);
@@ -33,7 +33,7 @@ static_assert(!std::sized_sentinel_for<iterator, const_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, reverse_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, const_reverse_iterator>);
 
-static_assert(std::forward_iterator<const_iterator>);
+static_assert(std::bidirectional_iterator<const_iterator>);
 static_assert(!std::indirectly_writable<const_iterator, value_type>);
 static_assert(std::sentinel_for<const_iterator, const_iterator>);
 static_assert(std::sentinel_for<const_iterator, iterator>);

diff  --git a/libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp
index b5c8e2459b90..d35995a91be0 100644
--- a/libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp
@@ -22,8 +22,8 @@ namespace stdr = std::ranges;
 
 static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
 static_assert(stdr::common_range<range>);
-static_assert(stdr::forward_range<range>);
+static_assert(stdr::bidirectional_range<range>);
 
 static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);
 static_assert(stdr::common_range<range const>);
-static_assert(stdr::forward_range<range const>);
+static_assert(stdr::bidirectional_range<range const>);

diff  --git a/libcxx/test/std/containers/associative/set/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/set/iterator_concept_conformance.compile.pass.cpp
index f5f92a997906..662bf74fa261 100644
--- a/libcxx/test/std/containers/associative/set/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/associative/set/iterator_concept_conformance.compile.pass.cpp
@@ -22,7 +22,7 @@ using reverse_iterator = std::set<int>::reverse_iterator;
 using const_reverse_iterator = std::set<int>::const_reverse_iterator;
 using value_type = int;
 
-static_assert(std::forward_iterator<iterator>);
+static_assert(std::bidirectional_iterator<iterator>);
 static_assert(!std::indirectly_writable<iterator, value_type>);
 static_assert(std::sentinel_for<iterator, iterator>);
 static_assert(std::sentinel_for<iterator, const_iterator>);
@@ -33,7 +33,7 @@ static_assert(!std::sized_sentinel_for<iterator, const_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, reverse_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, const_reverse_iterator>);
 
-static_assert(std::forward_iterator<const_iterator>);
+static_assert(std::bidirectional_iterator<const_iterator>);
 static_assert(!std::indirectly_writable<const_iterator, value_type>);
 static_assert(std::sentinel_for<const_iterator, iterator>);
 static_assert(std::sentinel_for<const_iterator, const_iterator>);

diff  --git a/libcxx/test/std/containers/sequences/array/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/array/iterator_concept_conformance.compile.pass.cpp
index 846c0e39890f..2816cd29b6f3 100644
--- a/libcxx/test/std/containers/sequences/array/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/array/iterator_concept_conformance.compile.pass.cpp
@@ -21,7 +21,7 @@ using const_iterator = std::array<int, 10>::const_iterator;
 using reverse_iterator = std::array<int, 10>::reverse_iterator;
 using const_reverse_iterator = std::array<int, 10>::const_reverse_iterator;
 
-static_assert(std::forward_iterator<iterator>);
+static_assert(std::bidirectional_iterator<iterator>);
 static_assert(std::indirectly_writable<iterator, int>);
 static_assert(std::sentinel_for<iterator, iterator>);
 static_assert(std::sentinel_for<iterator, const_iterator>);
@@ -32,7 +32,7 @@ static_assert(std::sized_sentinel_for<iterator, const_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, reverse_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, const_reverse_iterator>);
 
-static_assert(std::forward_iterator<const_iterator>);
+static_assert(std::bidirectional_iterator<const_iterator>);
 static_assert(!std::indirectly_writable<const_iterator, int>);
 static_assert(std::sentinel_for<const_iterator, iterator>);
 static_assert(std::sentinel_for<const_iterator, const_iterator>);

diff  --git a/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp
index cdb245ba71f0..02ea3ca87ece 100644
--- a/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp
@@ -22,8 +22,8 @@ namespace stdr = std::ranges;
 
 static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
 static_assert(stdr::common_range<range>);
-static_assert(stdr::forward_range<range>);
+static_assert(stdr::bidirectional_range<range>);
 
 static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);
 static_assert(stdr::common_range<range const>);
-static_assert(stdr::forward_range<range const>);
+static_assert(stdr::bidirectional_range<range const>);

diff  --git a/libcxx/test/std/containers/sequences/deque/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/deque/iterator_concept_conformance.compile.pass.cpp
index d5d455eda13e..f301f4d61123 100644
--- a/libcxx/test/std/containers/sequences/deque/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/iterator_concept_conformance.compile.pass.cpp
@@ -22,7 +22,7 @@ using reverse_iterator = std::deque<int>::reverse_iterator;
 using const_reverse_iterator = std::deque<int>::const_reverse_iterator;
 using value_type = int;
 
-static_assert(std::forward_iterator<iterator>);
+static_assert(std::bidirectional_iterator<iterator>);
 static_assert(std::indirectly_writable<iterator, value_type>);
 static_assert(std::sentinel_for<iterator, iterator>);
 static_assert(std::sentinel_for<iterator, const_iterator>);
@@ -33,7 +33,7 @@ static_assert(std::sized_sentinel_for<iterator, const_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, reverse_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, const_reverse_iterator>);
 
-static_assert(std::forward_iterator<const_iterator>);
+static_assert(std::bidirectional_iterator<const_iterator>);
 static_assert(!std::indirectly_writable<const_iterator, value_type>);
 static_assert(std::sentinel_for<const_iterator, iterator>);
 static_assert(std::sentinel_for<const_iterator, const_iterator>);

diff  --git a/libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp
index afb76778141f..ce8f709e66a2 100644
--- a/libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp
@@ -22,8 +22,8 @@ namespace stdr = std::ranges;
 
 static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
 static_assert(stdr::common_range<range>);
-static_assert(stdr::forward_range<range>);
+static_assert(stdr::bidirectional_range<range>);
 
 static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);
 static_assert(stdr::common_range<range const>);
-static_assert(stdr::forward_range<range const>);
+static_assert(stdr::bidirectional_range<range const>);

diff  --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.iter/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.iter/iterator_concept_conformance.compile.pass.cpp
index fae264870619..6a3edcbd98b5 100644
--- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.iter/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.iter/iterator_concept_conformance.compile.pass.cpp
@@ -21,6 +21,7 @@ using const_iterator = std::forward_list<int>::const_iterator;
 using value_type = int;
 
 static_assert(std::forward_iterator<iterator>);
+static_assert(!std::bidirectional_iterator<iterator>);
 static_assert(std::indirectly_writable<iterator, value_type>);
 static_assert(std::sentinel_for<iterator, iterator>);
 static_assert(std::sentinel_for<iterator, const_iterator>);
@@ -28,6 +29,7 @@ static_assert(!std::sized_sentinel_for<iterator, iterator>);
 static_assert(!std::sized_sentinel_for<iterator, const_iterator>);
 
 static_assert(std::forward_iterator<const_iterator>);
+static_assert(!std::bidirectional_iterator<const_iterator>);
 static_assert(!std::indirectly_writable<const_iterator, value_type>);
 static_assert(std::sentinel_for<const_iterator, iterator>);
 static_assert(std::sentinel_for<const_iterator, const_iterator>);

diff  --git a/libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp
index 19fe3537163a..a5a73a9e0a9b 100644
--- a/libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp
@@ -23,7 +23,9 @@ namespace stdr = std::ranges;
 static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
 static_assert(stdr::common_range<range>);
 static_assert(stdr::forward_range<range>);
+static_assert(!stdr::bidirectional_range<range>);
 
 static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);
 static_assert(stdr::common_range<range const>);
 static_assert(stdr::forward_range<range const>);
+static_assert(!stdr::bidirectional_range<range const>);

diff  --git a/libcxx/test/std/containers/sequences/list/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/list/iterator_concept_conformance.compile.pass.cpp
index e2b60ce74157..3acaa34bb33d 100644
--- a/libcxx/test/std/containers/sequences/list/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/list/iterator_concept_conformance.compile.pass.cpp
@@ -22,7 +22,7 @@ using reverse_iterator = std::list<int>::reverse_iterator;
 using const_reverse_iterator = std::list<int>::const_reverse_iterator;
 using value_type = int;
 
-static_assert(std::forward_iterator<iterator>);
+static_assert(std::bidirectional_iterator<iterator>);
 static_assert(std::indirectly_writable<iterator, value_type>);
 static_assert(std::sentinel_for<iterator, iterator>);
 static_assert(std::sentinel_for<iterator, const_iterator>);
@@ -33,7 +33,7 @@ static_assert(!std::sized_sentinel_for<iterator, const_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, reverse_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, const_reverse_iterator>);
 
-static_assert(std::forward_iterator<const_iterator>);
+static_assert(std::bidirectional_iterator<const_iterator>);
 static_assert(!std::indirectly_writable<const_iterator, value_type>);
 static_assert(std::sentinel_for<const_iterator, iterator>);
 static_assert(std::sentinel_for<const_iterator, const_iterator>);

diff  --git a/libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp
index c83185036b6f..404d424d31f0 100644
--- a/libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp
@@ -22,8 +22,8 @@ namespace stdr = std::ranges;
 
 static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
 static_assert(stdr::common_range<range>);
-static_assert(stdr::forward_range<range>);
+static_assert(stdr::bidirectional_range<range>);
 
 static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);
 static_assert(stdr::common_range<range const>);
-static_assert(stdr::forward_range<range const>);
+static_assert(stdr::bidirectional_range<range const>);

diff  --git a/libcxx/test/std/containers/sequences/vector.bool/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/iterator_concept_conformance.compile.pass.cpp
index 33203170e716..1fc5f5d6c386 100644
--- a/libcxx/test/std/containers/sequences/vector.bool/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector.bool/iterator_concept_conformance.compile.pass.cpp
@@ -22,7 +22,7 @@ using reverse_iterator = std::vector<bool>::reverse_iterator;
 using const_reverse_iterator = std::vector<bool>::const_reverse_iterator;
 using value_type = bool;
 
-static_assert(std::forward_iterator<iterator>);
+static_assert(std::bidirectional_iterator<iterator>);
 static_assert(!std::indirectly_writable<iterator, value_type>);
 static_assert(std::sentinel_for<iterator, iterator>);
 static_assert(std::sentinel_for<iterator, const_iterator>);
@@ -33,7 +33,7 @@ static_assert(std::sized_sentinel_for<iterator, const_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, reverse_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, const_reverse_iterator>);
 
-static_assert(std::forward_iterator<const_iterator>);
+static_assert(std::bidirectional_iterator<const_iterator>);
 static_assert(!std::indirectly_writable<const_iterator, value_type>);
 static_assert(std::sentinel_for<const_iterator, iterator>);
 static_assert(std::sentinel_for<const_iterator, const_iterator>);

diff  --git a/libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp
index 3fe82de40598..0ed361879765 100644
--- a/libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp
@@ -22,8 +22,8 @@ namespace stdr = std::ranges;
 
 static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
 static_assert(stdr::common_range<range>);
-static_assert(stdr::forward_range<range>);
+static_assert(stdr::bidirectional_range<range>);
 
 static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);
 static_assert(stdr::common_range<range const>);
-static_assert(stdr::forward_range<range const>);
+static_assert(stdr::bidirectional_range<range const>);

diff  --git a/libcxx/test/std/containers/sequences/vector/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/vector/iterator_concept_conformance.compile.pass.cpp
index 8f676705047e..c8a76470debe 100644
--- a/libcxx/test/std/containers/sequences/vector/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector/iterator_concept_conformance.compile.pass.cpp
@@ -22,7 +22,7 @@ using reverse_iterator = std::vector<int>::reverse_iterator;
 using const_reverse_iterator = std::vector<int>::const_reverse_iterator;
 using value_type = int;
 
-static_assert(std::forward_iterator<iterator>);
+static_assert(std::bidirectional_iterator<iterator>);
 static_assert(std::indirectly_writable<iterator, value_type>);
 static_assert(std::sentinel_for<iterator, iterator>);
 static_assert(std::sentinel_for<iterator, const_iterator>);
@@ -33,7 +33,7 @@ static_assert(std::sized_sentinel_for<iterator, const_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, reverse_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, const_reverse_iterator>);
 
-static_assert(std::forward_iterator<const_iterator>);
+static_assert(std::bidirectional_iterator<const_iterator>);
 static_assert(!std::indirectly_writable<const_iterator, value_type>);
 static_assert(std::sentinel_for<const_iterator, iterator>);
 static_assert(std::sentinel_for<const_iterator, const_iterator>);

diff  --git a/libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp
index ab8005427d65..880f5bd5195e 100644
--- a/libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp
@@ -22,8 +22,8 @@ namespace stdr = std::ranges;
 
 static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
 static_assert(stdr::common_range<range>);
-static_assert(stdr::forward_range<range>);
+static_assert(stdr::bidirectional_range<range>);
 
 static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);
 static_assert(stdr::common_range<range const>);
-static_assert(stdr::forward_range<range const>);
+static_assert(stdr::bidirectional_range<range const>);

diff  --git a/libcxx/test/std/containers/unord/unord.map/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.map/iterator_concept_conformance.compile.pass.cpp
index 1bc67b21ccdc..8f23959c1181 100644
--- a/libcxx/test/std/containers/unord/unord.map/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.map/iterator_concept_conformance.compile.pass.cpp
@@ -23,6 +23,7 @@ using const_local_iterator = std::unordered_map<int, int>::const_local_iterator;
 using value_type = std::pair<const int, int>;
 
 static_assert(std::forward_iterator<iterator>);
+static_assert(!std::bidirectional_iterator<iterator>);
 static_assert(!std::indirectly_writable<iterator, value_type>);
 static_assert(std::sentinel_for<iterator, iterator>);
 static_assert(std::sentinel_for<iterator, const_iterator>);
@@ -34,6 +35,7 @@ static_assert(!std::sized_sentinel_for<iterator, local_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, const_local_iterator>);
 
 static_assert(std::forward_iterator<const_iterator>);
+static_assert(!std::bidirectional_iterator<const_iterator>);
 static_assert(!std::indirectly_writable<const_iterator, value_type>);
 static_assert(std::sentinel_for<const_iterator, iterator>);
 static_assert(std::sentinel_for<const_iterator, const_iterator>);
@@ -45,6 +47,7 @@ static_assert(!std::sized_sentinel_for<const_iterator, local_iterator>);
 static_assert(!std::sized_sentinel_for<const_iterator, const_local_iterator>);
 
 static_assert(std::forward_iterator<local_iterator>);
+static_assert(!std::bidirectional_iterator<local_iterator>);
 static_assert(!std::indirectly_writable<local_iterator, value_type>);
 static_assert(!std::sentinel_for<local_iterator, iterator>);
 static_assert(!std::sentinel_for<local_iterator, const_iterator>);
@@ -56,6 +59,7 @@ static_assert(!std::sized_sentinel_for<local_iterator, local_iterator>);
 static_assert(!std::sized_sentinel_for<local_iterator, const_local_iterator>);
 
 static_assert(std::forward_iterator<const_local_iterator>);
+static_assert(!std::bidirectional_iterator<const_local_iterator>);
 static_assert(!std::indirectly_writable<const_local_iterator, value_type>);
 static_assert(!std::sentinel_for<const_local_iterator, iterator>);
 static_assert(!std::sentinel_for<const_local_iterator, const_iterator>);

diff  --git a/libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp
index a62ca693f00b..dd50b31c4f24 100644
--- a/libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp
@@ -23,7 +23,9 @@ namespace stdr = std::ranges;
 static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
 static_assert(stdr::common_range<range>);
 static_assert(stdr::forward_range<range>);
+static_assert(!stdr::bidirectional_range<range>);
 
 static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);
 static_assert(stdr::common_range<range const>);
 static_assert(stdr::forward_range<range const>);
+static_assert(!stdr::bidirectional_range<range const>);

diff  --git a/libcxx/test/std/containers/unord/unord.multimap/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.multimap/iterator_concept_conformance.compile.pass.cpp
index a53edc95a2c6..1b73f1785b2f 100644
--- a/libcxx/test/std/containers/unord/unord.multimap/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.multimap/iterator_concept_conformance.compile.pass.cpp
@@ -23,6 +23,7 @@ using const_local_iterator = std::unordered_multimap<int, int>::const_local_iter
 using value_type = std::pair<const int, int>;
 
 static_assert(std::forward_iterator<iterator>);
+static_assert(!std::bidirectional_iterator<iterator>);
 static_assert(!std::indirectly_writable<iterator, value_type>);
 static_assert(std::sentinel_for<iterator, iterator>);
 static_assert(std::sentinel_for<iterator, const_iterator>);
@@ -34,6 +35,7 @@ static_assert(!std::sized_sentinel_for<iterator, local_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, const_local_iterator>);
 
 static_assert(std::forward_iterator<const_iterator>);
+static_assert(!std::bidirectional_iterator<const_iterator>);
 static_assert(!std::indirectly_writable<const_iterator, value_type>);
 static_assert(std::sentinel_for<const_iterator, iterator>);
 static_assert(std::sentinel_for<const_iterator, const_iterator>);
@@ -45,6 +47,7 @@ static_assert(!std::sized_sentinel_for<const_iterator, local_iterator>);
 static_assert(!std::sized_sentinel_for<const_iterator, const_local_iterator>);
 
 static_assert(std::forward_iterator<local_iterator>);
+static_assert(!std::bidirectional_iterator<local_iterator>);
 static_assert(!std::indirectly_writable<local_iterator, value_type>);
 static_assert(!std::sentinel_for<local_iterator, iterator>);
 static_assert(!std::sentinel_for<local_iterator, const_iterator>);
@@ -56,6 +59,7 @@ static_assert(!std::sized_sentinel_for<local_iterator, local_iterator>);
 static_assert(!std::sized_sentinel_for<local_iterator, const_local_iterator>);
 
 static_assert(std::forward_iterator<const_local_iterator>);
+static_assert(!std::bidirectional_iterator<const_local_iterator>);
 static_assert(!std::indirectly_writable<const_local_iterator, value_type>);
 static_assert(!std::sentinel_for<const_local_iterator, iterator>);
 static_assert(!std::sentinel_for<const_local_iterator, const_iterator>);

diff  --git a/libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp
index 2418b0f0fa95..0a6a10f1bb83 100644
--- a/libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp
@@ -23,7 +23,9 @@ namespace stdr = std::ranges;
 static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
 static_assert(stdr::common_range<range>);
 static_assert(stdr::forward_range<range>);
+static_assert(!stdr::bidirectional_range<range>);
 
 static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);
 static_assert(stdr::common_range<range const>);
 static_assert(stdr::forward_range<range const>);
+static_assert(!stdr::bidirectional_range<range const>);

diff  --git a/libcxx/test/std/containers/unord/unord.multiset/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.multiset/iterator_concept_conformance.compile.pass.cpp
index c1b05fe57b22..25e25c4493fe 100644
--- a/libcxx/test/std/containers/unord/unord.multiset/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.multiset/iterator_concept_conformance.compile.pass.cpp
@@ -23,6 +23,7 @@ using const_local_iterator = std::unordered_multiset<int>::const_local_iterator;
 using value_type = int;
 
 static_assert(std::forward_iterator<iterator>);
+static_assert(!std::bidirectional_iterator<iterator>);
 static_assert(!std::indirectly_writable<iterator, value_type>);
 static_assert(std::sentinel_for<iterator, iterator>);
 static_assert(std::sentinel_for<iterator, const_iterator>);
@@ -34,6 +35,7 @@ static_assert(!std::sized_sentinel_for<iterator, local_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, const_local_iterator>);
 
 static_assert(std::forward_iterator<const_iterator>);
+static_assert(!std::bidirectional_iterator<const_iterator>);
 static_assert(!std::indirectly_writable<const_iterator, value_type>);
 static_assert(std::sentinel_for<const_iterator, iterator>);
 static_assert(std::sentinel_for<const_iterator, const_iterator>);
@@ -45,6 +47,7 @@ static_assert(!std::sized_sentinel_for<const_iterator, local_iterator>);
 static_assert(!std::sized_sentinel_for<const_iterator, const_local_iterator>);
 
 static_assert(std::forward_iterator<local_iterator>);
+static_assert(!std::bidirectional_iterator<local_iterator>);
 static_assert(!std::indirectly_writable<local_iterator, value_type>);
 static_assert(!std::sentinel_for<local_iterator, iterator>);
 static_assert(!std::sentinel_for<local_iterator, const_iterator>);
@@ -56,6 +59,7 @@ static_assert(!std::sized_sentinel_for<local_iterator, local_iterator>);
 static_assert(!std::sized_sentinel_for<local_iterator, const_local_iterator>);
 
 static_assert(std::forward_iterator<const_local_iterator>);
+static_assert(!std::bidirectional_iterator<const_local_iterator>);
 static_assert(!std::indirectly_writable<const_local_iterator, value_type>);
 static_assert(!std::sentinel_for<const_local_iterator, iterator>);
 static_assert(!std::sentinel_for<const_local_iterator, const_iterator>);

diff  --git a/libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp
index 8d34570890d1..b244fce256fd 100644
--- a/libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp
@@ -23,7 +23,9 @@ namespace stdr = std::ranges;
 static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
 static_assert(stdr::common_range<range>);
 static_assert(stdr::forward_range<range>);
+static_assert(!stdr::bidirectional_range<range>);
 
 static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);
 static_assert(stdr::common_range<range const>);
 static_assert(stdr::forward_range<range const>);
+static_assert(!stdr::bidirectional_range<range const>);

diff  --git a/libcxx/test/std/containers/unord/unord.set/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.set/iterator_concept_conformance.compile.pass.cpp
index 01e36e191fe5..50426a2a4c37 100644
--- a/libcxx/test/std/containers/unord/unord.set/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.set/iterator_concept_conformance.compile.pass.cpp
@@ -23,6 +23,7 @@ using const_local_iterator = std::unordered_set<int>::const_local_iterator;
 using value_type = int;
 
 static_assert(std::forward_iterator<iterator>);
+static_assert(!std::bidirectional_iterator<iterator>);
 static_assert(!std::indirectly_writable<iterator, value_type>);
 static_assert(std::sentinel_for<iterator, iterator>);
 static_assert(std::sentinel_for<iterator, const_iterator>);
@@ -34,6 +35,7 @@ static_assert(!std::sized_sentinel_for<iterator, local_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, const_local_iterator>);
 
 static_assert(std::forward_iterator<const_iterator>);
+static_assert(!std::bidirectional_iterator<const_iterator>);
 static_assert(!std::indirectly_writable<const_iterator, value_type>);
 static_assert(std::sentinel_for<const_iterator, iterator>);
 static_assert(std::sentinel_for<const_iterator, const_iterator>);
@@ -45,6 +47,7 @@ static_assert(!std::sized_sentinel_for<const_iterator, local_iterator>);
 static_assert(!std::sized_sentinel_for<const_iterator, const_local_iterator>);
 
 static_assert(std::forward_iterator<local_iterator>);
+static_assert(!std::bidirectional_iterator<local_iterator>);
 static_assert(!std::sentinel_for<local_iterator, iterator>);
 static_assert(!std::sentinel_for<local_iterator, const_iterator>);
 static_assert(std::sentinel_for<local_iterator, local_iterator>);
@@ -55,6 +58,7 @@ static_assert(!std::sized_sentinel_for<local_iterator, local_iterator>);
 static_assert(!std::sized_sentinel_for<local_iterator, const_local_iterator>);
 
 static_assert(std::forward_iterator<const_local_iterator>);
+static_assert(!std::bidirectional_iterator<const_local_iterator>);
 static_assert(!std::indirectly_writable<const_local_iterator, value_type>);
 static_assert(!std::sentinel_for<const_local_iterator, iterator>);
 static_assert(!std::sentinel_for<const_local_iterator, const_iterator>);

diff  --git a/libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp
index e792ce052d64..ab72da83b543 100644
--- a/libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp
@@ -23,7 +23,9 @@ namespace stdr = std::ranges;
 static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
 static_assert(stdr::common_range<range>);
 static_assert(stdr::forward_range<range>);
+static_assert(!stdr::bidirectional_range<range>);
 
 static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);
 static_assert(stdr::common_range<range const>);
 static_assert(stdr::forward_range<range const>);
+static_assert(!stdr::bidirectional_range<range const>);

diff  --git a/libcxx/test/std/containers/views/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/views/range_concept_conformance.compile.pass.cpp
index 53f4e9082ec4..9234639dcf18 100644
--- a/libcxx/test/std/containers/views/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/views/range_concept_conformance.compile.pass.cpp
@@ -22,8 +22,8 @@ namespace stdr = std::ranges;
 
 static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
 static_assert(stdr::common_range<range>);
-static_assert(stdr::forward_range<range>);
+static_assert(stdr::bidirectional_range<range>);
 
 static_assert(std::same_as<stdr::iterator_t<range const>, range::iterator>);
 static_assert(stdr::common_range<range const>);
-static_assert(stdr::forward_range<range const>);
+static_assert(stdr::bidirectional_range<range const>);

diff  --git a/libcxx/test/std/containers/views/span.iterators/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/views/span.iterators/iterator_concept_conformance.compile.pass.cpp
index 55d5c3856931..355ece63681c 100644
--- a/libcxx/test/std/containers/views/span.iterators/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/views/span.iterators/iterator_concept_conformance.compile.pass.cpp
@@ -20,7 +20,7 @@ using iterator = std::span<int>::iterator;
 using reverse_iterator = std::span<int>::reverse_iterator;
 using value_type = int;
 
-static_assert(std::forward_iterator<iterator>);
+static_assert(std::bidirectional_iterator<iterator>);
 static_assert(std::indirectly_writable<iterator, value_type>);
 static_assert(std::sentinel_for<iterator, iterator>);
 static_assert(!std::sentinel_for<iterator, reverse_iterator>);

diff  --git a/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp
index 6f22e25da77a..281679c6dfda 100644
--- a/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp
@@ -21,8 +21,8 @@ namespace stdr = std::ranges;
 
 static_assert(std::same_as<stdr::iterator_t<fs::path>, fs::path::iterator>);
 static_assert(stdr::common_range<fs::path>);
-static_assert(stdr::forward_range<fs::path>);
+static_assert(stdr::bidirectional_range<fs::path>);
 
 static_assert(std::same_as<stdr::iterator_t<fs::path const>, fs::path::const_iterator>);
 static_assert(stdr::common_range<fs::path const>);
-static_assert(stdr::forward_range<fs::path const>);
+static_assert(stdr::bidirectional_range<fs::path const>);

diff  --git a/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.bidir/bidirectional_iterator.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.bidir/bidirectional_iterator.compile.pass.cpp
new file mode 100644
index 000000000000..3fec74d2f86d
--- /dev/null
+++ b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.bidir/bidirectional_iterator.compile.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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: gcc-10
+
+// template<class T>
+// concept bidirectional_iterator;
+
+#include <iterator>
+
+#include <concepts>
+
+#include "test_iterators.h"
+
+static_assert(!std::bidirectional_iterator<cpp17_input_iterator<int*> >);
+static_assert(!std::bidirectional_iterator<cpp20_input_iterator<int*> >);
+static_assert(!std::bidirectional_iterator<forward_iterator<int*> >);
+static_assert(std::bidirectional_iterator<bidirectional_iterator<int*> >);
+static_assert(std::bidirectional_iterator<random_access_iterator<int*> >);
+static_assert(std::bidirectional_iterator<contiguous_iterator<int*> >);
+
+
+static_assert(std::bidirectional_iterator<int*>);
+static_assert(std::bidirectional_iterator<int const*>);
+static_assert(std::bidirectional_iterator<int volatile*>);
+static_assert(std::bidirectional_iterator<int const volatile*>);
+
+struct not_forward_iterator {
+  using value_type = int;
+  using 
diff erence_type = std::ptr
diff _t;
+  using iterator_concept = std::bidirectional_iterator_tag;
+
+  value_type operator*() const;
+
+  not_forward_iterator& operator++();
+  not_forward_iterator operator++(int);
+
+  not_forward_iterator& operator--();
+  not_forward_iterator& operator--(int);
+};
+static_assert(std::input_iterator<not_forward_iterator> && !std::forward_iterator<not_forward_iterator> &&
+              !std::bidirectional_iterator<not_forward_iterator>);
+
+struct wrong_iterator_category {
+  using value_type = int;
+  using 
diff erence_type = std::ptr
diff _t;
+  using iterator_category = std::forward_iterator_tag;
+
+  value_type& operator*() const;
+
+  wrong_iterator_category& operator++();
+  wrong_iterator_category operator++(int);
+
+  wrong_iterator_category& operator--();
+  wrong_iterator_category operator--(int);
+
+  bool operator==(wrong_iterator_category const&) const = default;
+};
+static_assert(!std::bidirectional_iterator<wrong_iterator_category>);
+
+struct wrong_iterator_concept {
+  using value_type = int;
+  using 
diff erence_type = std::ptr
diff _t;
+  using iterator_concept = std::forward_iterator_tag;
+
+  value_type& operator*() const;
+
+  wrong_iterator_concept& operator++();
+  wrong_iterator_concept operator++(int);
+
+  wrong_iterator_concept& operator--();
+  wrong_iterator_concept operator--(int);
+
+  bool operator==(wrong_iterator_concept const&) const = default;
+};
+static_assert(!std::bidirectional_iterator<wrong_iterator_concept>);
+
+struct no_predecrement {
+  using value_type = int;
+  using 
diff erence_type = std::ptr
diff _t;
+  using iterator_concept = std::bidirectional_iterator_tag;
+
+  value_type& operator*() const;
+
+  no_predecrement& operator++();
+  no_predecrement operator++(int);
+
+  no_predecrement operator--(int);
+
+  bool operator==(no_predecrement const&) const = default;
+};
+static_assert(!std::bidirectional_iterator<no_predecrement>);
+
+struct bad_predecrement {
+  using value_type = int;
+  using 
diff erence_type = std::ptr
diff _t;
+  using iterator_concept = std::bidirectional_iterator_tag;
+
+  value_type& operator*() const;
+
+  bad_predecrement& operator++();
+  bad_predecrement operator++(int);
+
+  bad_predecrement operator--();
+  bad_predecrement operator--(int);
+
+  bool operator==(bad_predecrement const&) const = default;
+};
+static_assert(!std::bidirectional_iterator<bad_predecrement>);
+
+struct no_postdecrement {
+  using value_type = int;
+  using 
diff erence_type = std::ptr
diff _t;
+  using iterator_concept = std::bidirectional_iterator_tag;
+
+  value_type& operator*() const;
+
+  no_postdecrement& operator++();
+  no_postdecrement operator++(int);
+
+  no_postdecrement& operator--();
+
+  bool operator==(no_postdecrement const&) const = default;
+};
+static_assert(!std::bidirectional_iterator<no_postdecrement>);
+
+struct bad_postdecrement {
+  using value_type = int;
+  using 
diff erence_type = std::ptr
diff _t;
+  using iterator_concept = std::bidirectional_iterator_tag;
+
+  value_type& operator*() const;
+
+  bad_postdecrement& operator++();
+  bad_postdecrement operator++(int);
+
+  bad_postdecrement& operator--();
+  bad_postdecrement& operator--(int);
+
+  bool operator==(bad_postdecrement const&) const = default;
+};
+static_assert(!std::bidirectional_iterator<bad_postdecrement>);

diff  --git a/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.bidir/subsumption.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.bidir/subsumption.compile.pass.cpp
new file mode 100644
index 000000000000..b3d0e9c931d3
--- /dev/null
+++ b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.bidir/subsumption.compile.pass.cpp
@@ -0,0 +1,30 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: gcc-10
+
+// template<class T>
+// concept bidirectional_iterator;
+
+#include <iterator>
+
+#include <concepts>
+
+template<std::forward_iterator I>
+[[nodiscard]] constexpr bool check_subsumption() {
+  return false;
+}
+
+template<std::bidirectional_iterator>
+[[nodiscard]] constexpr bool check_subsumption() {
+  return true;
+}
+
+static_assert(check_subsumption<int*>());

diff  --git a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/iterator_concept_conformance.compile.pass.cpp
index 4144617e233e..dac2c4dbcf05 100644
--- a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/iterator_concept_conformance.compile.pass.cpp
@@ -27,15 +27,15 @@ template<class I1>
 
 using reverse_bidirectional_iterator = std::reverse_iterator<bidirectional_iterator<int*>>;
 static_assert(common_reverse_iterator_checks<reverse_bidirectional_iterator>());
-static_assert(std::forward_iterator<reverse_bidirectional_iterator>);
+static_assert(std::bidirectional_iterator<reverse_bidirectional_iterator>);
 static_assert(!std::sized_sentinel_for<reverse_bidirectional_iterator, reverse_bidirectional_iterator>);
 
 using reverse_random_access_iterator = std::reverse_iterator<random_access_iterator<int*>>;
 static_assert(common_reverse_iterator_checks<reverse_random_access_iterator>());
-static_assert(std::forward_iterator<reverse_random_access_iterator>);
+static_assert(std::bidirectional_iterator<reverse_random_access_iterator>);
 static_assert(std::sized_sentinel_for<reverse_random_access_iterator, reverse_random_access_iterator>);
 
 using reverse_contiguous_iterator = std::reverse_iterator<contiguous_iterator<int*>>;
 static_assert(common_reverse_iterator_checks<reverse_contiguous_iterator>());
-static_assert(std::forward_iterator<reverse_contiguous_iterator>);
+static_assert(std::bidirectional_iterator<reverse_contiguous_iterator>);
 static_assert(std::sized_sentinel_for<reverse_contiguous_iterator, reverse_contiguous_iterator>);

diff  --git a/libcxx/test/std/ranges/range.refinements/bidirectional_range.compile.pass.cpp b/libcxx/test/std/ranges/range.refinements/bidirectional_range.compile.pass.cpp
new file mode 100644
index 000000000000..56245c9f7dbf
--- /dev/null
+++ b/libcxx/test/std/ranges/range.refinements/bidirectional_range.compile.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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: gcc-10
+
+// template<range _Rp>
+// concept bidirectional_range;
+
+#include <ranges>
+
+#include "test_range.h"
+
+namespace stdr = std::ranges;
+
+template <template <class...> class I>
+constexpr bool check_bidirectional_range() {
+  constexpr bool result = stdr::bidirectional_range<test_range<I> >;
+  static_assert(stdr::bidirectional_range<test_range<I> const> == result);
+  static_assert(stdr::bidirectional_range<test_non_const_common_range<I> > == result);
+  static_assert(stdr::bidirectional_range<test_non_const_range<I> > == result);
+  static_assert(stdr::bidirectional_range<test_common_range<I> > == result);
+  static_assert(stdr::bidirectional_range<test_common_range<I> const> == result);
+  static_assert(!stdr::bidirectional_range<test_non_const_common_range<I> const>);
+  static_assert(!stdr::bidirectional_range<test_non_const_range<I> const>);
+  return result;
+}
+
+static_assert(!check_bidirectional_range<cpp17_input_iterator>());
+static_assert(!check_bidirectional_range<cpp20_input_iterator>());
+static_assert(!check_bidirectional_range<forward_iterator>());
+static_assert(check_bidirectional_range<bidirectional_iterator>());
+static_assert(check_bidirectional_range<random_access_iterator>());
+static_assert(check_bidirectional_range<contiguous_iterator>());

diff  --git a/libcxx/test/std/ranges/range.refinements/subsumption.compile.pass.cpp b/libcxx/test/std/ranges/range.refinements/subsumption.compile.pass.cpp
index 0480557a4f13..c0896e0efcbc 100644
--- a/libcxx/test/std/ranges/range.refinements/subsumption.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.refinements/subsumption.compile.pass.cpp
@@ -55,3 +55,19 @@ requires true
 // clang-format on
 
 static_assert(check_forward_range_subsumption<range>());
+
+// clang-format off
+template<std::ranges::forward_range R>
+requires std::bidirectional_iterator<std::ranges::iterator_t<R> >
+[[nodiscard]] constexpr bool check_bidirectional_range_subsumption() {
+  return false;
+}
+
+template<std::ranges::bidirectional_range>
+requires true
+[[nodiscard]] constexpr bool check_bidirectional_range_subsumption() {
+  return true;
+}
+// clang-format on
+
+static_assert(check_bidirectional_range_subsumption<range>());

diff  --git a/libcxx/test/std/re/re.iter/re.regiter/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/re/re.iter/re.regiter/iterator_concept_conformance.compile.pass.cpp
index b37640bfd338..74fd8796ef00 100644
--- a/libcxx/test/std/re/re.iter/re.regiter/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/re/re.iter/re.regiter/iterator_concept_conformance.compile.pass.cpp
@@ -17,6 +17,7 @@
 #include <iterator>
 
 static_assert(std::forward_iterator<std::cregex_iterator>);
+static_assert(!std::bidirectional_iterator<std::cregex_iterator>);
 static_assert(!std::indirectly_writable<std::cregex_iterator, char>);
 static_assert(std::sentinel_for<std::cregex_iterator, std::cregex_iterator>);
 static_assert(!std::sized_sentinel_for<std::cregex_iterator, std::cregex_iterator>);

diff  --git a/libcxx/test/std/re/re.iter/re.tokiter/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/re/re.iter/re.tokiter/iterator_concept_conformance.compile.pass.cpp
index b3e69d5448fe..b8de464eb881 100644
--- a/libcxx/test/std/re/re.iter/re.tokiter/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/re/re.iter/re.tokiter/iterator_concept_conformance.compile.pass.cpp
@@ -17,6 +17,7 @@
 #include <iterator>
 
 static_assert(std::forward_iterator<std::cregex_token_iterator>);
+static_assert(!std::bidirectional_iterator<std::cregex_token_iterator>);
 static_assert(!std::indirectly_writable<std::cregex_token_iterator, char>);
 static_assert(std::sentinel_for<std::cregex_token_iterator, std::cregex_token_iterator>);
 static_assert(!std::sized_sentinel_for<std::cregex_token_iterator, std::cregex_token_iterator>);

diff  --git a/libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp
index 2bc1f75b5210..2a6f17749b89 100644
--- a/libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp
@@ -21,8 +21,8 @@ namespace stdr = std::ranges;
 
 static_assert(std::same_as<stdr::iterator_t<std::cmatch>, std::cmatch::iterator>);
 static_assert(stdr::common_range<std::cmatch>);
-static_assert(stdr::forward_range<std::cmatch>);
+static_assert(stdr::bidirectional_range<std::cmatch>);
 
 static_assert(std::same_as<stdr::iterator_t<std::cmatch const>, std::cmatch::const_iterator>);
 static_assert(stdr::common_range<std::cmatch const>);
-static_assert(stdr::forward_range<std::cmatch const>);
+static_assert(stdr::bidirectional_range<std::cmatch const>);

diff  --git a/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp
index 4605cfd4a1bc..7fd0eff2b664 100644
--- a/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp
@@ -21,8 +21,8 @@ namespace stdr = std::ranges;
 
 static_assert(std::same_as<stdr::iterator_t<std::string>, std::string::iterator>);
 static_assert(stdr::common_range<std::string>);
-static_assert(stdr::forward_range<std::string>);
+static_assert(stdr::bidirectional_range<std::string>);
 
 static_assert(std::same_as<stdr::iterator_t<std::string const>, std::string::const_iterator>);
 static_assert(stdr::common_range<std::string const>);
-static_assert(stdr::forward_range<std::string const>);
+static_assert(stdr::bidirectional_range<std::string const>);

diff  --git a/libcxx/test/std/strings/basic.string/string.iterators/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/strings/basic.string/string.iterators/iterator_concept_conformance.compile.pass.cpp
index 2777b1fec0c9..5aa1b60bdc4d 100644
--- a/libcxx/test/std/strings/basic.string/string.iterators/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.iterators/iterator_concept_conformance.compile.pass.cpp
@@ -22,7 +22,7 @@ using reverse_iterator = std::string::reverse_iterator;
 using const_reverse_iterator = std::string::const_reverse_iterator;
 using value_type = char;
 
-static_assert(std::forward_iterator<iterator>);
+static_assert(std::bidirectional_iterator<iterator>);
 static_assert(std::indirectly_writable<iterator, value_type>);
 static_assert(std::sentinel_for<iterator, iterator>);
 static_assert(std::sentinel_for<iterator, const_iterator>);
@@ -33,7 +33,7 @@ static_assert(std::sized_sentinel_for<iterator, const_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, reverse_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, const_reverse_iterator>);
 
-static_assert(std::forward_iterator<const_iterator>);
+static_assert(std::bidirectional_iterator<const_iterator>);
 static_assert(!std::indirectly_writable<const_iterator, value_type>);
 static_assert(std::sentinel_for<const_iterator, iterator>);
 static_assert(std::sentinel_for<const_iterator, const_iterator>);

diff  --git a/libcxx/test/std/strings/string.view/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/strings/string.view/range_concept_conformance.compile.pass.cpp
index f4ee18b0c34c..21bd14e59ba8 100644
--- a/libcxx/test/std/strings/string.view/range_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/strings/string.view/range_concept_conformance.compile.pass.cpp
@@ -21,8 +21,8 @@ namespace stdr = std::ranges;
 
 static_assert(std::same_as<stdr::iterator_t<std::string_view>, std::string_view::iterator>);
 static_assert(stdr::common_range<std::string_view>);
-static_assert(stdr::forward_range<std::string_view>);
+static_assert(stdr::bidirectional_range<std::string_view>);
 
 static_assert(std::same_as<stdr::iterator_t<std::string_view const>, std::string_view::const_iterator>);
 static_assert(stdr::common_range<std::string_view const>);
-static_assert(stdr::forward_range<std::string_view const>);
+static_assert(stdr::bidirectional_range<std::string_view const>);

diff  --git a/libcxx/test/std/strings/string.view/string.view.iterators/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/strings/string.view/string.view.iterators/iterator_concept_conformance.compile.pass.cpp
index db8d8be9fbf8..f86f49184360 100644
--- a/libcxx/test/std/strings/string.view/string.view.iterators/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/strings/string.view/string.view.iterators/iterator_concept_conformance.compile.pass.cpp
@@ -21,7 +21,7 @@ using const_iterator = std::string_view::const_iterator;
 using reverse_iterator = std::string_view::reverse_iterator;
 using const_reverse_iterator = std::string_view::const_reverse_iterator;
 
-static_assert(std::forward_iterator<iterator>);
+static_assert(std::bidirectional_iterator<iterator>);
 static_assert(!std::indirectly_writable<iterator, char>);
 static_assert(std::sentinel_for<iterator, iterator>);
 static_assert(std::sentinel_for<iterator, const_iterator>);
@@ -32,7 +32,7 @@ static_assert(std::sized_sentinel_for<iterator, const_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, reverse_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, const_reverse_iterator>);
 
-static_assert(std::forward_iterator<const_iterator>);
+static_assert(std::bidirectional_iterator<const_iterator>);
 static_assert(!std::indirectly_writable<const_iterator, char>);
 static_assert(std::sentinel_for<const_iterator, iterator>);
 static_assert(std::sentinel_for<const_iterator, const_iterator>);


        


More information about the libcxx-commits mailing list