[libcxx-commits] [libcxx] 9f01ac3 - [libcxx] makes `iterator_traits` C++20-aware

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Tue Apr 20 08:30:48 PDT 2021


Author: zoecarver
Date: 2021-04-20T11:30:08-04:00
New Revision: 9f01ac3b3257ab925a2b1229dba19e3eb86a706b

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

LOG: [libcxx] makes `iterator_traits` C++20-aware

* adds `iterator_traits` specialisation that supports all expected
  member aliases except for `pointer`
* adds `iterator_traits` specialisations for iterators that meet the
  legacy iterator requirements but might lack multiple member aliases
* makes pointer `iterator_traits` specialisation require objects

Depends on D99854.

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

Added: 
    libcxx/test/std/iterators/iterator.primitives/iterator.traits/cxx20_iterator_traits.compile.pass.cpp
    libcxx/test/support/iterator_traits_cpp17_iterators.h

Modified: 
    libcxx/include/iterator
    libcxx/test/std/iterators/iterator.primitives/iterator.traits/const_pointer.pass.cpp
    libcxx/test/std/iterators/iterator.primitives/iterator.traits/const_volatile_pointer.pass.cpp
    libcxx/test/std/iterators/iterator.primitives/iterator.traits/empty.fail.cpp
    libcxx/test/std/iterators/iterator.primitives/iterator.traits/empty.pass.cpp
    libcxx/test/std/iterators/iterator.primitives/iterator.traits/volatile_pointer.pass.cpp

Removed: 
    libcxx/test/libcxx/iterators/iterator.requirements/iterator.assoc.types/iterator.traits/iterator_traits_cpp17_iterators.h


################################################################################
diff  --git a/libcxx/include/iterator b/libcxx/include/iterator
index 3158cf0b51040..b24f25457589d 100644
--- a/libcxx/include/iterator
+++ b/libcxx/include/iterator
@@ -21,24 +21,11 @@ template<class> struct incrementable_traits;       // since C++20
 template<class> struct indirectly_readable_traits; // since C++20
 
 template<class Iterator>
-struct iterator_traits
-{
-    typedef typename Iterator::
diff erence_type 
diff erence_type;
-    typedef typename Iterator::value_type value_type;
-    typedef typename Iterator::pointer pointer;
-    typedef typename Iterator::reference reference;
-    typedef typename Iterator::iterator_category iterator_category;
-};
+struct iterator_traits;
 
 template<class T>
-struct iterator_traits<T*>
-{
-    typedef ptr
diff _t 
diff erence_type;
-    typedef T value_type;
-    typedef T* pointer;
-    typedef T& reference;
-    typedef random_access_iterator_tag iterator_category;
-};
+  requires is_object_v<T>                    // since C++20
+struct iterator_traits<T*>;
 
 template<dereferenceable T>
   using iter_reference_t = decltype(*declval<T&>());
@@ -546,18 +533,6 @@ public:
     static const bool value = sizeof(__test<_Tp>(nullptr)) == 1;
 };
 
-template <class _Iter, bool> struct __iterator_traits_impl {};
-
-template <class _Iter>
-struct __iterator_traits_impl<_Iter, true>
-{
-    typedef typename _Iter::
diff erence_type   
diff erence_type;
-    typedef typename _Iter::value_type        value_type;
-    typedef typename _Iter::pointer           pointer;
-    typedef typename _Iter::reference         reference;
-    typedef typename _Iter::iterator_category iterator_category;
-};
-
 #if !defined(_LIBCPP_HAS_NO_RANGES)
 
 // The `cpp17-*-iterator` exposition-only concepts are easily confused with the Cpp17*Iterator tables,
@@ -621,10 +596,188 @@ concept __cpp17_random_access_iterator =
     {  __i[__n]  } -> convertible_to<iter_reference_t<_Ip>>;
   };
 } // namespace __iterator_traits_detail
-#endif // !defined(_LIBCPP_HAS_NO_RANGES)
+
+template<class _Ip>
+concept __has_member_reference = requires { typename _Ip::reference; };
+
+template<class _Ip>
+concept __has_member_pointer = requires { typename _Ip::pointer; };
+
+template<class _Ip>
+concept __has_member_iterator_category = requires { typename _Ip::iterator_category; };
+
+template<class _Ip>
+concept __specifies_members = requires {
+    typename _Ip::value_type;
+    typename _Ip::
diff erence_type;
+    requires __has_member_reference<_Ip>;
+    requires __has_member_iterator_category<_Ip>;
+  };
+
+template<class>
+struct __iterator_traits_member_pointer_or_void {
+  using type = void;
+};
+
+template<__has_member_pointer _Tp>
+struct __iterator_traits_member_pointer_or_void<_Tp> {
+  using type = typename _Tp::pointer;
+};
+
+template<class _Tp>
+concept __cpp17_iterator_missing_members =
+  !__specifies_members<_Tp> &&
+  __iterator_traits_detail::__cpp17_iterator<_Tp>;
+
+template<class _Tp>
+concept __cpp17_input_iterator_missing_members =
+  __cpp17_iterator_missing_members<_Tp> &&
+  __iterator_traits_detail::__cpp17_input_iterator<_Tp>;
+
+// Otherwise, `pointer` names `void`.
+template<class>
+struct __iterator_traits_member_pointer_or_arrow_or_void { using type = void; };
+
+// [iterator.traits]/3.2.1
+// If the qualified-id `I::pointer` is valid and denotes a type, `pointer` names that type.
+template<__has_member_pointer _Ip>
+struct __iterator_traits_member_pointer_or_arrow_or_void<_Ip> { using type = typename _Ip::pointer; };
+
+// Otherwise, if `decltype(declval<I&>().operator->())` is well-formed, then `pointer` names that
+// type.
+template<class _Ip>
+concept __has_arrow =
+  requires(_Ip& __i) {
+    __i.operator->();
+  };
+
+template<class _Ip>
+  requires __has_arrow<_Ip> && (!__has_member_pointer<_Ip>)
+struct __iterator_traits_member_pointer_or_arrow_or_void<_Ip> {
+  using type = decltype(declval<_Ip&>().operator->());
+};
+
+// Otherwise, `reference` names `iter-reference-t<I>`.
+template<class _Ip>
+struct __iterator_traits_member_reference { using type = iter_reference_t<_Ip>; };
+
+// [iterator.traits]/3.2.2
+// If the qualified-id `I::reference` is valid and denotes a type, `reference` names that type.
+template<__has_member_reference _Ip>
+struct __iterator_traits_member_reference<_Ip> { using type = typename _Ip::reference; };
+
+// [iterator.traits]/3.2.3.4
+// input_iterator_tag
+template<class _Ip>
+struct __deduce_iterator_category {
+  using type = input_iterator_tag;
+};
+
+// [iterator.traits]/3.2.3.1
+// `random_access_iterator_tag` if `I` satisfies `cpp17-random-access-iterator`, or otherwise
+template<__iterator_traits_detail::__cpp17_random_access_iterator _Ip>
+struct __deduce_iterator_category<_Ip> {
+  using type = random_access_iterator_tag;
+};
+
+// [iterator.traits]/3.2.3.2
+// `bidirectional_iterator_tag` if `I` satisfies `cpp17-bidirectional-iterator`, or otherwise
+template<__iterator_traits_detail::__cpp17_bidirectional_iterator _Ip>
+struct __deduce_iterator_category<_Ip> {
+  using type = bidirectional_iterator_tag;
+};
+
+// [iterator.traits]/3.2.3.3
+// `forward_iterator_tag` if `I` satisfies `cpp17-forward-iterator`, or otherwise
+template<__iterator_traits_detail::__cpp17_forward_iterator _Ip>
+struct __deduce_iterator_category<_Ip> {
+  using type = forward_iterator_tag;
+};
+
+template<class _Ip>
+struct __iterator_traits_iterator_category : __deduce_iterator_category<_Ip> {};
+
+// [iterator.traits]/3.2.3
+// If the qualified-id `I::iterator-category` is valid and denotes a type, `iterator-category` names
+// that type.
+template<__has_member_iterator_category _Ip>
+struct __iterator_traits_iterator_category<_Ip> {
+  using type = typename _Ip::iterator_category;
+};
+
+// otherwise, it names void.
+template<class>
+struct __iterator_traits_
diff erence_type { using type = void; };
+
+// If the qualified-id `incrementable_traits<I>::
diff erence_type` is valid and denotes a type, then
+// `
diff erence_type` names that type;
+template<class _Ip>
+requires requires { typename incrementable_traits<_Ip>::
diff erence_type; }
+struct __iterator_traits_
diff erence_type<_Ip> {
+  using type = typename incrementable_traits<_Ip>::
diff erence_type;
+};
+
+// [iterator.traits]/3.4
+// Otherwise, `iterator_traits<I>` has no members by any of the above names.
+template<class>
+struct __iterator_traits {};
+
+// [iterator.traits]/3.1
+// If `I` has valid ([temp.deduct]) member types `
diff erence-type`, `value-type`, `reference`, and
+// `iterator-category`, then `iterator-traits<I>` has the following publicly accessible members:
+template<__specifies_members _Ip>
+struct __iterator_traits<_Ip> {
+  using iterator_category  = typename _Ip::iterator_category;
+  using value_type         = typename _Ip::value_type;
+  using 
diff erence_type    = typename _Ip::
diff erence_type;
+  using pointer            = typename __iterator_traits_member_pointer_or_void<_Ip>::type;
+  using reference          = typename _Ip::reference;
+};
+
+// [iterator.traits]/3.2
+// Otherwise, if `I` satisfies the exposition-only concept `cpp17-input-iterator`,
+// `iterator-traits<I>` has the following publicly accessible members:
+template<__cpp17_input_iterator_missing_members _Ip>
+struct __iterator_traits<_Ip> {
+  using iterator_category = typename __iterator_traits_iterator_category<_Ip>::type;
+  using value_type        = typename indirectly_readable_traits<_Ip>::value_type;
+  using 
diff erence_type   = typename incrementable_traits<_Ip>::
diff erence_type;
+  using pointer           = typename __iterator_traits_member_pointer_or_arrow_or_void<_Ip>::type;
+  using reference         = typename __iterator_traits_member_reference<_Ip>::type;
+};
+
+// Otherwise, if `I` satisfies the exposition-only concept `cpp17-iterator`, then
+// `iterator_traits<I>` has the following publicly accessible members:
+template<__cpp17_iterator_missing_members _Ip>
+struct __iterator_traits<_Ip> {
+  using iterator_category = output_iterator_tag;
+  using value_type        = void;
+  using 
diff erence_type   = typename __iterator_traits_
diff erence_type<_Ip>::type;
+  using pointer           = void;
+  using reference         = void;
+};
+
+template<class _Ip>
+struct iterator_traits : __iterator_traits<_Ip> {
+  using __primary_template = iterator_traits;
+};
+
+#else // !defined(_LIBCPP_HAS_NO_RANGES)
 
 template <class _Iter, bool> struct __iterator_traits {};
 
+template <class _Iter, bool> struct __iterator_traits_impl {};
+
+template <class _Iter>
+struct __iterator_traits_impl<_Iter, true>
+{
+    typedef typename _Iter::
diff erence_type   
diff erence_type;
+    typedef typename _Iter::value_type        value_type;
+    typedef typename _Iter::pointer           pointer;
+    typedef typename _Iter::reference         reference;
+    typedef typename _Iter::iterator_category iterator_category;
+};
+
 template <class _Iter>
 struct __iterator_traits<_Iter, true>
     :  __iterator_traits_impl
@@ -646,8 +799,12 @@ struct _LIBCPP_TEMPLATE_VIS iterator_traits
 
   using __primary_template = iterator_traits;
 };
+#endif // !defined(_LIBCPP_HAS_NO_RANGES)
 
 template<class _Tp>
+#if !defined(_LIBCPP_HAS_NO_RANGES)
+requires is_object_v<_Tp>
+#endif
 struct _LIBCPP_TEMPLATE_VIS iterator_traits<_Tp*>
 {
     typedef ptr
diff _t 
diff erence_type;

diff  --git a/libcxx/test/std/iterators/iterator.primitives/iterator.traits/const_pointer.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/iterator.traits/const_pointer.pass.cpp
index b167f58fd5a4d..7090a30a80f9e 100644
--- a/libcxx/test/std/iterators/iterator.primitives/iterator.traits/const_pointer.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.primitives/iterator.traits/const_pointer.pass.cpp
@@ -34,5 +34,9 @@ int main(int, char**)
     static_assert((std::is_same<It::reference, const A&>::value), "");
     static_assert((std::is_same<It::iterator_category, std::random_access_iterator_tag>::value), "");
 
-  return 0;
+#if TEST_STD_VER > 17
+    ASSERT_SAME_TYPE(It::iterator_concept, std::contiguous_iterator_tag);
+#endif
+
+    return 0;
 }

diff  --git a/libcxx/test/std/iterators/iterator.primitives/iterator.traits/const_volatile_pointer.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/iterator.traits/const_volatile_pointer.pass.cpp
index 5bda7e7190dbd..e410d3d57470e 100644
--- a/libcxx/test/std/iterators/iterator.primitives/iterator.traits/const_volatile_pointer.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.primitives/iterator.traits/const_volatile_pointer.pass.cpp
@@ -26,6 +26,8 @@ int main(int, char**)
     static_assert((std::is_same<It::pointer, const volatile A*>::value), "");
     static_assert((std::is_same<It::reference, const volatile A&>::value), "");
     static_assert((std::is_same<It::iterator_category, std::random_access_iterator_tag>::value), "");
-
-  return 0;
+#if TEST_STD_VER > 17
+    ASSERT_SAME_TYPE(It::iterator_concept, std::contiguous_iterator_tag);
+#endif
+    return 0;
 }

diff  --git a/libcxx/test/std/iterators/iterator.primitives/iterator.traits/cxx20_iterator_traits.compile.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/iterator.traits/cxx20_iterator_traits.compile.pass.cpp
new file mode 100644
index 0000000000000..77f4183919052
--- /dev/null
+++ b/libcxx/test/std/iterators/iterator.primitives/iterator.traits/cxx20_iterator_traits.compile.pass.cpp
@@ -0,0 +1,696 @@
+//===----------------------------------------------------------------------===//
+//
+// 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>
+// struct iterator_traits;
+
+#include <iterator>
+
+#include <array>
+#include <concepts>
+#include <cstddef>
+#include <deque>
+#include <forward_list>
+#include <list>
+#include <map>
+#include <memory>
+#include <optional>
+#include <set>
+#include <string>
+#include <string_view>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#ifndef _LIBCPP_HAS_NO_LOCALIZATION
+# include <regex>
+# include <ostream>
+# include <istream>
+#endif
+
+#ifndef _LIBCPP_HAS_NO_FILESYSTEM_LIBRARY
+# include <filesystem>
+#endif
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "iterator_traits_cpp17_iterators.h"
+
+template <class Traits>
+constexpr bool has_iterator_concept_v = requires {
+  typename Traits::iterator_concept;
+};
+
+// Standard types.
+
+template <class Iter, class ValueType, class Category, class IterConcept = void>
+constexpr bool testStdlibIteratorConst() {
+  using Traits = std::iterator_traits<Iter>;
+  static_assert(std::same_as<typename Traits::iterator_category, Category>);
+  static_assert(std::same_as<typename Traits::value_type, ValueType>);
+  static_assert(std::same_as<typename Traits::
diff erence_type, std::ptr
diff _t>);
+  static_assert(std::same_as<typename Traits::reference, const ValueType&>);
+  static_assert(std::same_as<typename Traits::pointer, const ValueType*>);
+  if constexpr (std::same_as<IterConcept, void>)
+    static_assert(!has_iterator_concept_v<Traits>);
+  else
+    static_assert(std::same_as<typename Traits::iterator_concept, IterConcept>);
+
+  return true;
+}
+
+template <class Iter, class ValueType, class Category, class IterConcept = void>
+constexpr bool testStdlibIterator() {
+  using Traits = std::iterator_traits<Iter>;
+  static_assert(std::same_as<typename Traits::iterator_category, Category>);
+  static_assert(std::same_as<typename Traits::value_type, ValueType>);
+  static_assert(std::same_as<typename Traits::
diff erence_type, std::ptr
diff _t>);
+  static_assert(std::same_as<typename Traits::reference, ValueType&>);
+  static_assert(std::same_as<typename Traits::pointer, ValueType*>);
+  if constexpr (std::same_as<IterConcept, void>)
+    static_assert(!has_iterator_concept_v<Traits>);
+  else
+    static_assert(std::same_as<typename Traits::iterator_concept, IterConcept>);
+
+  return true;
+}
+
+template <class Iter, class ValueType, class Category, class Diff = void>
+requires std::same_as<ValueType, void> constexpr bool testStdlibIterator() {
+  using Traits = std::iterator_traits<Iter>;
+  static_assert(std::same_as<typename Traits::iterator_category, Category>);
+  static_assert(std::same_as<typename Traits::value_type, void>);
+  static_assert(std::same_as<typename Traits::
diff erence_type, Diff>);
+  static_assert(std::same_as<typename Traits::reference, void>);
+  static_assert(std::same_as<typename Traits::pointer, void>);
+  static_assert(!has_iterator_concept_v<Traits>);
+
+  return true;
+}
+
+template <class Iter, class ValueType, class DiffType, class RefType, class PtrType, class Category,
+          class IterConcept = void>
+constexpr bool testStdlibIterator() {
+  using Traits = std::iterator_traits<Iter>;
+  static_assert(std::same_as<typename Traits::iterator_category, Category>);
+  static_assert(std::same_as<typename Traits::value_type, ValueType>);
+  static_assert(std::same_as<typename Traits::
diff erence_type, DiffType>);
+  static_assert(std::same_as<typename Traits::reference, RefType>);
+  static_assert(std::same_as<typename Traits::pointer, PtrType>);
+  if constexpr (std::same_as<IterConcept, void>)
+    static_assert(!has_iterator_concept_v<Traits>);
+  else
+    static_assert(std::same_as<typename Traits::iterator_concept, IterConcept>);
+
+  return true;
+}
+
+template <class T, class... Args>
+constexpr bool testBothStdlibIterators() {
+  static_assert(testStdlibIteratorConst<typename T::const_iterator, Args...>());
+  static_assert(testStdlibIterator<typename T::iterator, Args...>());
+
+  return true;
+}
+
+static_assert(testBothStdlibIterators<std::vector<int>, int, std::random_access_iterator_tag>());
+static_assert(testBothStdlibIterators<std::string, char, std::random_access_iterator_tag>());
+static_assert(testStdlibIteratorConst<std::string_view::iterator, char, std::random_access_iterator_tag,
+                                      std::contiguous_iterator_tag>());
+static_assert(testStdlibIteratorConst<std::string_view::const_iterator, char, std::random_access_iterator_tag,
+                                      std::contiguous_iterator_tag>());
+static_assert(
+    testBothStdlibIterators<std::array<int, 10>, int, std::random_access_iterator_tag, std::contiguous_iterator_tag>());
+static_assert(testBothStdlibIterators<std::deque<int>, int, std::random_access_iterator_tag>());
+#ifndef _LIBCPP_HAS_NO_FILESYSTEM_LIBRARY
+static_assert(testStdlibIterator<std::filesystem::directory_iterator, std::filesystem::directory_entry, std::ptr
diff _t,
+                                 const std::filesystem::directory_entry&, const std::filesystem::directory_entry*,
+                                 std::input_iterator_tag>());
+static_assert(testStdlibIterator<std::filesystem::recursive_directory_iterator, std::filesystem::directory_entry,
+                                 std::ptr
diff _t, const std::filesystem::directory_entry&,
+                                 const std::filesystem::directory_entry*, std::input_iterator_tag>());
+#endif
+static_assert(testBothStdlibIterators<std::forward_list<int>, int, std::forward_iterator_tag>());
+static_assert(testBothStdlibIterators<std::deque<int>, int, std::random_access_iterator_tag>());
+static_assert(testBothStdlibIterators<std::list<int>, int, std::bidirectional_iterator_tag>());
+static_assert(testStdlibIterator<std::set<int>::iterator, int, std::ptr
diff _t, const int&, const int*,
+                                 std::bidirectional_iterator_tag>());
+static_assert(testStdlibIterator<std::set<int>::const_iterator, int, std::ptr
diff _t, const int&, const int*,
+                                 std::bidirectional_iterator_tag>());
+static_assert(
+    testBothStdlibIterators<std::map<int, int>, std::pair<const int, int>, std::bidirectional_iterator_tag>());
+static_assert(
+    testBothStdlibIterators<std::unordered_map<int, int>, std::pair<const int, int>, std::forward_iterator_tag>());
+static_assert(testStdlibIterator<std::unordered_map<int, int>::local_iterator, std::pair<const int, int>,
+                                 std::forward_iterator_tag>());
+static_assert(testStdlibIteratorConst<std::unordered_map<int, int>::const_local_iterator, std::pair<const int, int>,
+                                      std::forward_iterator_tag>());
+static_assert(
+    testBothStdlibIterators<std::unordered_multimap<int, int>, std::pair<const int, int>, std::forward_iterator_tag>());
+static_assert(testStdlibIterator<std::unordered_multimap<int, int>::local_iterator, std::pair<const int, int>,
+                                 std::forward_iterator_tag>());
+static_assert(testStdlibIteratorConst<std::unordered_multimap<int, int>::const_local_iterator,
+                                      std::pair<const int, int>, std::forward_iterator_tag>());
+static_assert(testStdlibIteratorConst<std::unordered_set<int>::iterator, int, std::forward_iterator_tag>());
+static_assert(testStdlibIteratorConst<std::unordered_set<int>::const_iterator, int, std::forward_iterator_tag>());
+static_assert(testStdlibIteratorConst<std::unordered_set<int>::local_iterator, int, std::forward_iterator_tag>());
+static_assert(testStdlibIteratorConst<std::unordered_set<int>::const_local_iterator, int, std::forward_iterator_tag>());
+static_assert(testStdlibIteratorConst<std::unordered_multiset<int>::iterator, int, std::forward_iterator_tag>());
+static_assert(testStdlibIteratorConst<std::unordered_multiset<int>::const_iterator, int, std::forward_iterator_tag>());
+static_assert(testStdlibIteratorConst<std::unordered_multiset<int>::local_iterator, int, std::forward_iterator_tag>());
+static_assert(
+    testStdlibIteratorConst<std::unordered_multiset<int>::const_local_iterator, int, std::forward_iterator_tag>());
+
+static_assert(
+    testStdlibIterator<std::reverse_iterator<std::vector<int>::iterator>, int, std::random_access_iterator_tag>());
+static_assert(
+    testStdlibIterator<std::back_insert_iterator<std::vector<int>::iterator>, void, std::output_iterator_tag>());
+static_assert(
+    testStdlibIterator<std::front_insert_iterator<std::vector<int>::iterator>, void, std::output_iterator_tag>());
+static_assert(testStdlibIterator<std::insert_iterator<std::vector<int> >, void, std::output_iterator_tag>());
+static_assert(testStdlibIteratorConst<std::istream_iterator<int, char>, int, std::input_iterator_tag>());
+
+#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+static_assert(
+    testStdlibIterator<std::istreambuf_iterator<char>, char, long long, char, char*, std::input_iterator_tag>());
+using MoveIter = std::move_iterator<std::vector<int>::iterator>;
+static_assert(
+    testStdlibIterator<MoveIter, int, std::ptr
diff _t, int&&, MoveIter::pointer, std::random_access_iterator_tag>());
+static_assert(testStdlibIterator<std::ostream_iterator<int, char>, void, std::output_iterator_tag, std::ptr
diff _t>());
+static_assert(
+    testStdlibIterator<std::ostreambuf_iterator<int, char>, void, std::output_iterator_tag, std::ptr
diff _t>());
+static_assert(testStdlibIteratorConst<std::cregex_iterator, std::cmatch, std::forward_iterator_tag>());
+static_assert(testStdlibIteratorConst<std::cregex_token_iterator, std::csub_match, std::forward_iterator_tag>());
+#endif // !_LIBCPP_HAS_NO_LOCALIZATION
+
+// Local test iterators.
+
+struct AllMembers {
+  struct iterator_category {};
+  struct value_type {};
+  struct 
diff erence_type {};
+  struct reference {};
+  struct pointer {};
+};
+using AllMembersTraits = std::iterator_traits<AllMembers>;
+static_assert(std::same_as<AllMembersTraits::iterator_category,
+                           AllMembers::iterator_category>);
+static_assert(
+    std::same_as<AllMembersTraits::value_type, AllMembers::value_type>);
+static_assert(std::same_as<AllMembersTraits::
diff erence_type,
+                           AllMembers::
diff erence_type>);
+static_assert(std::same_as<AllMembersTraits::reference, AllMembers::reference>);
+static_assert(std::same_as<AllMembersTraits::pointer, AllMembers::pointer>);
+static_assert(!has_iterator_concept_v<AllMembersTraits>);
+
+struct NoPointerMember {
+  struct iterator_category {};
+  struct value_type {};
+  struct 
diff erence_type {};
+  struct reference {};
+  // ignored, because NoPointerMember is not a LegacyInputIterator:
+  value_type* operator->() const;
+};
+using NoPointerMemberTraits = std::iterator_traits<NoPointerMember>;
+static_assert(std::same_as<NoPointerMemberTraits::iterator_category,
+                           NoPointerMember::iterator_category>);
+static_assert(std::same_as<NoPointerMemberTraits::value_type,
+                           NoPointerMember::value_type>);
+static_assert(std::same_as<NoPointerMemberTraits::
diff erence_type,
+                           NoPointerMember::
diff erence_type>);
+static_assert(
+    std::same_as<NoPointerMemberTraits::reference, NoPointerMember::reference>);
+static_assert(std::same_as<NoPointerMemberTraits::pointer, void>);
+static_assert(!has_iterator_concept_v<NoPointerMemberTraits>);
+
+struct IterConcept {
+  struct iterator_category {};
+  // "iterator_concept" must be defined in a specialization of "iterator_traits", it
+  // should not be a member of the iterator itself, so this is ignored.
+  struct iterator_concept {};
+  struct value_type {};
+  struct 
diff erence_type {};
+  struct reference {};
+  struct pointer {};
+};
+using IterConceptTraits = std::iterator_traits<IterConcept>;
+static_assert(std::same_as<IterConceptTraits::iterator_category,
+                           IterConcept::iterator_category>);
+static_assert(
+    std::same_as<IterConceptTraits::value_type, IterConcept::value_type>);
+static_assert(std::same_as<IterConceptTraits::
diff erence_type,
+                           IterConcept::
diff erence_type>);
+static_assert(
+    std::same_as<IterConceptTraits::reference, IterConcept::reference>);
+static_assert(std::same_as<IterConceptTraits::pointer, IterConcept::pointer>);
+static_assert(!has_iterator_concept_v<IterConceptTraits>);
+
+struct LegacyInput {
+  struct iterator_category {};
+  struct value_type {};
+  struct reference {
+    operator value_type() const;
+  };
+
+  friend bool operator==(LegacyInput, LegacyInput);
+  reference operator*() const;
+  LegacyInput& operator++();
+  LegacyInput operator++(int);
+};
+template <>
+struct std::incrementable_traits<LegacyInput> {
+  using 
diff erence_type = short;
+};
+using LegacyInputTraits = std::iterator_traits<LegacyInput>;
+static_assert(std::same_as<LegacyInputTraits::iterator_category,
+                           LegacyInput::iterator_category>);
+static_assert(
+    std::same_as<LegacyInputTraits::value_type, LegacyInput::value_type>);
+static_assert(std::same_as<LegacyInputTraits::
diff erence_type, short>);
+static_assert(
+    std::same_as<LegacyInputTraits::reference, LegacyInput::reference>);
+static_assert(std::same_as<LegacyInputTraits::pointer, void>);
+static_assert(!has_iterator_concept_v<LegacyInputTraits>);
+
+struct LegacyInputNoValueType {
+  struct not_value_type {};
+  using 
diff erence_type = int; // or any signed integral type
+  struct reference {
+    operator not_value_type() const;
+  };
+
+  friend bool operator==(LegacyInputNoValueType, LegacyInputNoValueType);
+  reference operator*() const;
+  LegacyInputNoValueType& operator++();
+  LegacyInputNoValueType operator++(int);
+};
+template <>
+struct std::indirectly_readable_traits<LegacyInputNoValueType> {
+  using value_type = LegacyInputNoValueType::not_value_type;
+};
+using LegacyInputNoValueTypeTraits =
+    std::iterator_traits<LegacyInputNoValueType>;
+static_assert(std::same_as<LegacyInputNoValueTypeTraits::iterator_category,
+                           std::input_iterator_tag>);
+static_assert(std::same_as<LegacyInputNoValueTypeTraits::value_type,
+                           LegacyInputNoValueType::not_value_type>);
+static_assert(std::same_as<LegacyInputNoValueTypeTraits::
diff erence_type, int>);
+static_assert(std::same_as<LegacyInputNoValueTypeTraits::reference,
+                           LegacyInputNoValueType::reference>);
+static_assert(std::same_as<LegacyInputNoValueTypeTraits::pointer, void>);
+static_assert(!has_iterator_concept_v<LegacyInputNoValueTypeTraits>);
+
+struct LegacyForward {
+  struct not_value_type {};
+
+  friend bool operator==(LegacyForward, LegacyForward);
+  const not_value_type& operator*() const;
+  LegacyForward& operator++();
+  LegacyForward operator++(int);
+};
+template <>
+struct std::indirectly_readable_traits<LegacyForward> {
+  using value_type = LegacyForward::not_value_type;
+};
+template <>
+struct std::incrementable_traits<LegacyForward> {
+  using 
diff erence_type = short; // or any signed integral type
+};
+using LegacyForwardTraits = std::iterator_traits<LegacyForward>;
+static_assert(std::same_as<LegacyForwardTraits::iterator_category,
+                           std::forward_iterator_tag>);
+static_assert(std::same_as<LegacyForwardTraits::value_type,
+                           LegacyForward::not_value_type>);
+static_assert(std::same_as<LegacyForwardTraits::
diff erence_type, short>);
+static_assert(std::same_as<LegacyForwardTraits::reference,
+                           const LegacyForward::not_value_type&>);
+static_assert(std::same_as<LegacyForwardTraits::pointer, void>);
+static_assert(!has_iterator_concept_v<LegacyForwardTraits>);
+
+struct LegacyBidirectional {
+  struct value_type {};
+
+  friend bool operator==(LegacyBidirectional, LegacyBidirectional);
+  const value_type& operator*() const;
+  LegacyBidirectional& operator++();
+  LegacyBidirectional operator++(int);
+  LegacyBidirectional& operator--();
+  LegacyBidirectional operator--(int);
+  friend short operator-(LegacyBidirectional, LegacyBidirectional);
+};
+using LegacyBidirectionalTraits = std::iterator_traits<LegacyBidirectional>;
+static_assert(std::same_as<LegacyBidirectionalTraits::iterator_category,
+                           std::bidirectional_iterator_tag>);
+static_assert(std::same_as<LegacyBidirectionalTraits::value_type,
+                           LegacyBidirectional::value_type>);
+static_assert(std::same_as<LegacyBidirectionalTraits::
diff erence_type, short>);
+static_assert(std::same_as<LegacyBidirectionalTraits::reference,
+                           const LegacyBidirectional::value_type&>);
+static_assert(std::same_as<LegacyBidirectionalTraits::pointer, void>);
+static_assert(!has_iterator_concept_v<LegacyBidirectionalTraits>);
+
+// Almost a random access iterator except it is missing operator-(It, It).
+struct MinusNotDeclaredIter {
+  struct value_type {};
+
+  friend auto operator<=>(MinusNotDeclaredIter, MinusNotDeclaredIter) = default;
+  const value_type& operator*() const;
+  const value_type& operator[](long) const;
+  MinusNotDeclaredIter& operator++();
+  MinusNotDeclaredIter operator++(int);
+  MinusNotDeclaredIter& operator--();
+  MinusNotDeclaredIter operator--(int);
+  MinusNotDeclaredIter& operator+=(long);
+  MinusNotDeclaredIter& operator-=(long);
+
+  // Providing 
diff erence_type does not fully compensate for missing operator-(It, It).
+  friend MinusNotDeclaredIter operator-(MinusNotDeclaredIter, int);
+  friend MinusNotDeclaredIter operator+(MinusNotDeclaredIter, int);
+  friend MinusNotDeclaredIter operator+(int, MinusNotDeclaredIter);
+};
+template <>
+struct std::incrementable_traits<MinusNotDeclaredIter> {
+  using 
diff erence_type = short;
+};
+using MinusNotDeclaredIterTraits = std::iterator_traits<MinusNotDeclaredIter>;
+static_assert(std::same_as<MinusNotDeclaredIterTraits::iterator_category,
+                           std::bidirectional_iterator_tag>);
+static_assert(std::same_as<MinusNotDeclaredIterTraits::value_type,
+                           MinusNotDeclaredIter::value_type>);
+static_assert(std::same_as<MinusNotDeclaredIterTraits::
diff erence_type, short>);
+static_assert(std::same_as<MinusNotDeclaredIterTraits::reference,
+                           const MinusNotDeclaredIter::value_type&>);
+static_assert(std::same_as<MinusNotDeclaredIterTraits::pointer, void>);
+static_assert(!has_iterator_concept_v<MinusNotDeclaredIterTraits>);
+
+struct WrongSubscriptReturnType {
+  struct value_type {};
+
+  friend auto operator<=>(WrongSubscriptReturnType,
+                          WrongSubscriptReturnType) = default;
+  // The type of it[n] is not convertible to the type of *it; therefore, this is not random-access.
+  value_type& operator*() const;
+  const value_type& operator[](long) const;
+  WrongSubscriptReturnType& operator++();
+  WrongSubscriptReturnType operator++(int);
+  WrongSubscriptReturnType& operator--();
+  WrongSubscriptReturnType operator--(int);
+  WrongSubscriptReturnType& operator+=(long);
+  WrongSubscriptReturnType& operator-=(long);
+  friend short operator-(WrongSubscriptReturnType, WrongSubscriptReturnType);
+  friend WrongSubscriptReturnType operator-(WrongSubscriptReturnType, int);
+  friend WrongSubscriptReturnType operator+(WrongSubscriptReturnType, int);
+  friend WrongSubscriptReturnType operator+(int, WrongSubscriptReturnType);
+};
+using WrongSubscriptReturnTypeTraits =
+    std::iterator_traits<WrongSubscriptReturnType>;
+static_assert(std::same_as<WrongSubscriptReturnTypeTraits::iterator_category,
+                           std::bidirectional_iterator_tag>);
+static_assert(std::same_as<WrongSubscriptReturnTypeTraits::value_type,
+                           WrongSubscriptReturnType::value_type>);
+static_assert(
+    std::same_as<WrongSubscriptReturnTypeTraits::
diff erence_type, short>);
+static_assert(std::same_as<WrongSubscriptReturnTypeTraits::reference,
+                           WrongSubscriptReturnType::value_type&>);
+static_assert(std::same_as<WrongSubscriptReturnTypeTraits::pointer, void>);
+static_assert(!has_iterator_concept_v<WrongSubscriptReturnTypeTraits>);
+
+struct LegacyRandomAccess {
+  struct value_type {};
+
+  friend bool operator==(LegacyRandomAccess, LegacyRandomAccess);
+  friend bool operator<(LegacyRandomAccess, LegacyRandomAccess);
+  friend bool operator<=(LegacyRandomAccess, LegacyRandomAccess);
+  friend bool operator>(LegacyRandomAccess, LegacyRandomAccess);
+  friend bool operator>=(LegacyRandomAccess, LegacyRandomAccess);
+  const value_type& operator*() const;
+  const value_type& operator[](long) const;
+  LegacyRandomAccess& operator++();
+  LegacyRandomAccess operator++(int);
+  LegacyRandomAccess& operator--();
+  LegacyRandomAccess operator--(int);
+  LegacyRandomAccess& operator+=(long);
+  LegacyRandomAccess& operator-=(long);
+  friend short operator-(LegacyRandomAccess, LegacyRandomAccess);
+  friend LegacyRandomAccess operator-(LegacyRandomAccess, int);
+  friend LegacyRandomAccess operator+(LegacyRandomAccess, int);
+  friend LegacyRandomAccess operator+(int, LegacyRandomAccess);
+};
+using LegacyRandomAccessTraits = std::iterator_traits<LegacyRandomAccess>;
+static_assert(std::same_as<LegacyRandomAccessTraits::iterator_category,
+                           std::random_access_iterator_tag>);
+static_assert(std::same_as<LegacyRandomAccessTraits::value_type,
+                           LegacyRandomAccess::value_type>);
+static_assert(std::same_as<LegacyRandomAccessTraits::
diff erence_type, short>);
+static_assert(std::same_as<LegacyRandomAccessTraits::reference,
+                           const LegacyRandomAccess::value_type&>);
+static_assert(std::same_as<LegacyRandomAccessTraits::pointer, void>);
+static_assert(!has_iterator_concept_v<LegacyRandomAccessTraits>);
+
+struct LegacyRandomAccessSpaceship {
+  struct not_value_type {};
+  struct ReferenceConvertible {
+    operator not_value_type&() const;
+  };
+
+  friend auto operator<=>(LegacyRandomAccessSpaceship,
+                          LegacyRandomAccessSpaceship) = default;
+  not_value_type& operator*() const;
+  ReferenceConvertible operator[](long) const;
+  LegacyRandomAccessSpaceship& operator++();
+  LegacyRandomAccessSpaceship operator++(int);
+  LegacyRandomAccessSpaceship& operator--();
+  LegacyRandomAccessSpaceship operator--(int);
+  LegacyRandomAccessSpaceship& operator+=(long);
+  LegacyRandomAccessSpaceship& operator-=(long);
+  friend short operator-(LegacyRandomAccessSpaceship,
+                         LegacyRandomAccessSpaceship);
+  friend LegacyRandomAccessSpaceship operator-(LegacyRandomAccessSpaceship,
+                                               int);
+  friend LegacyRandomAccessSpaceship operator+(LegacyRandomAccessSpaceship,
+                                               int);
+  friend LegacyRandomAccessSpaceship operator+(int,
+                                               LegacyRandomAccessSpaceship);
+};
+template <>
+struct std::indirectly_readable_traits<LegacyRandomAccessSpaceship> {
+  using value_type = LegacyRandomAccessSpaceship::not_value_type;
+};
+template <>
+struct std::incrementable_traits<LegacyRandomAccessSpaceship> {
+  using 
diff erence_type = short; // or any signed integral type
+};
+using LegacyRandomAccessSpaceshipTraits =
+    std::iterator_traits<LegacyRandomAccessSpaceship>;
+static_assert(std::same_as<LegacyRandomAccessSpaceshipTraits::iterator_category,
+                           std::random_access_iterator_tag>);
+static_assert(std::same_as<LegacyRandomAccessSpaceshipTraits::value_type,
+                           LegacyRandomAccessSpaceship::not_value_type>);
+static_assert(
+    std::same_as<LegacyRandomAccessSpaceshipTraits::
diff erence_type, short>);
+static_assert(std::same_as<LegacyRandomAccessSpaceshipTraits::reference,
+                           LegacyRandomAccessSpaceship::not_value_type&>);
+static_assert(std::same_as<LegacyRandomAccessSpaceshipTraits::pointer, void>);
+static_assert(!has_iterator_concept_v<LegacyRandomAccessSpaceshipTraits>);
+
+// For output iterators, value_type, 
diff erence_type, and reference may be void.
+struct BareLegacyOutput {
+  struct Empty {};
+  Empty operator*() const;
+  BareLegacyOutput& operator++();
+  BareLegacyOutput operator++(int);
+};
+using BareLegacyOutputTraits = std::iterator_traits<BareLegacyOutput>;
+static_assert(std::same_as<BareLegacyOutputTraits::iterator_category,
+                           std::output_iterator_tag>);
+static_assert(std::same_as<BareLegacyOutputTraits::value_type, void>);
+static_assert(std::same_as<BareLegacyOutputTraits::
diff erence_type, void>);
+static_assert(std::same_as<BareLegacyOutputTraits::reference, void>);
+static_assert(std::same_as<BareLegacyOutputTraits::pointer, void>);
+static_assert(!has_iterator_concept_v<BareLegacyOutputTraits>);
+
+// The operator- means we get 
diff erence_type.
+struct LegacyOutputWithMinus {
+  struct Empty {};
+  Empty operator*() const;
+  LegacyOutputWithMinus& operator++();
+  LegacyOutputWithMinus operator++(int);
+  friend short operator-(LegacyOutputWithMinus, LegacyOutputWithMinus);
+  // Lacking operator==, this is a LegacyIterator but not a LegacyInputIterator.
+};
+using LegacyOutputWithMinusTraits = std::iterator_traits<LegacyOutputWithMinus>;
+static_assert(std::same_as<LegacyOutputWithMinusTraits::iterator_category,
+                           std::output_iterator_tag>);
+static_assert(std::same_as<LegacyOutputWithMinusTraits::value_type, void>);
+static_assert(
+    std::same_as<LegacyOutputWithMinusTraits::
diff erence_type, short>);
+static_assert(std::same_as<LegacyOutputWithMinusTraits::reference, void>);
+static_assert(std::same_as<LegacyOutputWithMinusTraits::pointer, void>);
+static_assert(!has_iterator_concept_v<LegacyOutputWithMinusTraits>);
+
+struct LegacyOutputWithMemberTypes {
+  struct value_type {}; // ignored
+  struct reference {};  // ignored
+  using 
diff erence_type = long;
+
+  friend bool operator==(LegacyOutputWithMemberTypes,
+                         LegacyOutputWithMemberTypes);
+  reference operator*() const;
+  LegacyOutputWithMemberTypes& operator++();
+  LegacyOutputWithMemberTypes operator++(int);
+  friend short operator-(LegacyOutputWithMemberTypes,
+                         LegacyOutputWithMemberTypes); // ignored
+  // Since (*it) is not convertible to value_type, this is not a LegacyInputIterator.
+};
+using LegacyOutputWithMemberTypesTraits =
+    std::iterator_traits<LegacyOutputWithMemberTypes>;
+static_assert(std::same_as<LegacyOutputWithMemberTypesTraits::iterator_category,
+                           std::output_iterator_tag>);
+static_assert(
+    std::same_as<LegacyOutputWithMemberTypesTraits::value_type, void>);
+static_assert(
+    std::same_as<LegacyOutputWithMemberTypesTraits::
diff erence_type, long>);
+static_assert(std::same_as<LegacyOutputWithMemberTypesTraits::reference, void>);
+static_assert(std::same_as<LegacyOutputWithMemberTypesTraits::pointer, void>);
+static_assert(!has_iterator_concept_v<LegacyOutputWithMemberTypesTraits>);
+
+struct LegacyRandomAccessSpecialized {
+  struct not_value_type {};
+
+  friend auto operator<=>(LegacyRandomAccessSpecialized,
+                          LegacyRandomAccessSpecialized) = default;
+  not_value_type& operator*() const;
+  not_value_type& operator[](long) const;
+  LegacyRandomAccessSpecialized& operator++();
+  LegacyRandomAccessSpecialized operator++(int);
+  LegacyRandomAccessSpecialized& operator--();
+  LegacyRandomAccessSpecialized operator--(int);
+  LegacyRandomAccessSpecialized& operator+=(long);
+  LegacyRandomAccessSpecialized& operator-=(long);
+  friend long operator-(LegacyRandomAccessSpecialized,
+                        LegacyRandomAccessSpecialized);
+  friend LegacyRandomAccessSpecialized operator-(LegacyRandomAccessSpecialized,
+                                                 int);
+  friend LegacyRandomAccessSpecialized operator+(LegacyRandomAccessSpecialized,
+                                                 int);
+  friend LegacyRandomAccessSpecialized operator+(int,
+                                                 LegacyRandomAccessSpecialized);
+};
+template <class I>
+requires std::same_as<
+    I, LegacyRandomAccessSpecialized> struct std::iterator_traits<I> {
+  using iterator_category = std::output_iterator_tag;
+  using value_type = short;
+  using 
diff erence_type = short;
+  using reference = short&;
+  using pointer = short*;
+};
+using LegacyRandomAccessSpecializedTraits =
+    std::iterator_traits<LegacyRandomAccessSpecialized>;
+static_assert(
+    std::same_as<LegacyRandomAccessSpecializedTraits::iterator_category,
+                 std::output_iterator_tag>);
+static_assert(
+    std::same_as<LegacyRandomAccessSpecializedTraits::value_type, short>);
+static_assert(
+    std::same_as<LegacyRandomAccessSpecializedTraits::
diff erence_type, short>);
+static_assert(
+    std::same_as<LegacyRandomAccessSpecializedTraits::reference, short&>);
+static_assert(
+    std::same_as<LegacyRandomAccessSpecializedTraits::pointer, short*>);
+static_assert(!has_iterator_concept_v<LegacyRandomAccessSpecializedTraits>);
+
+// Other test iterators.
+
+using InputTestItereatorTraits = std::iterator_traits<input_iterator<int*> >;
+static_assert(std::same_as<InputTestItereatorTraits::iterator_category,
+                           std::input_iterator_tag>);
+static_assert(std::same_as<InputTestItereatorTraits::value_type, int>);
+static_assert(std::same_as<InputTestItereatorTraits::
diff erence_type, std::ptr
diff _t>);
+static_assert(std::same_as<InputTestItereatorTraits::reference, int&>);
+static_assert(std::same_as<InputTestItereatorTraits::pointer, int*>);
+static_assert(!has_iterator_concept_v<InputTestItereatorTraits>);
+
+using OutputTestItereatorTraits = std::iterator_traits<output_iterator<int*> >;
+static_assert(std::same_as<OutputTestItereatorTraits::iterator_category,
+                           std::output_iterator_tag>);
+static_assert(std::same_as<OutputTestItereatorTraits::value_type, void>);
+static_assert(std::same_as<OutputTestItereatorTraits::
diff erence_type, std::ptr
diff _t>);
+static_assert(std::same_as<OutputTestItereatorTraits::reference, int&>);
+static_assert(std::same_as<OutputTestItereatorTraits::pointer, int*>);
+static_assert(!has_iterator_concept_v<OutputTestItereatorTraits>);
+
+using ForwardTestIteratorTraits = std::iterator_traits<forward_iterator<int*> >;
+static_assert(std::same_as<ForwardTestIteratorTraits::iterator_category,
+                           std::forward_iterator_tag>);
+static_assert(std::same_as<ForwardTestIteratorTraits::value_type, int>);
+static_assert(std::same_as<ForwardTestIteratorTraits::
diff erence_type, std::ptr
diff _t>);
+static_assert(std::same_as<ForwardTestIteratorTraits::reference, int&>);
+static_assert(std::same_as<ForwardTestIteratorTraits::pointer, int*>);
+static_assert(!has_iterator_concept_v<ForwardTestIteratorTraits>);
+
+using BidirectionalTestIteratorTraits =
+    std::iterator_traits<bidirectional_iterator<int*> >;
+static_assert(std::same_as<BidirectionalTestIteratorTraits::iterator_category,
+                           std::bidirectional_iterator_tag>);
+static_assert(std::same_as<BidirectionalTestIteratorTraits::value_type, int>);
+static_assert(
+    std::same_as<BidirectionalTestIteratorTraits::
diff erence_type, std::ptr
diff _t>);
+static_assert(std::same_as<BidirectionalTestIteratorTraits::reference, int&>);
+static_assert(std::same_as<BidirectionalTestIteratorTraits::pointer, int*>);
+static_assert(!has_iterator_concept_v<BidirectionalTestIteratorTraits>);
+
+using RandomAccessTestIteratorTraits =
+    std::iterator_traits<random_access_iterator<int*> >;
+static_assert(std::same_as<RandomAccessTestIteratorTraits::iterator_category,
+                           std::random_access_iterator_tag>);
+static_assert(std::same_as<RandomAccessTestIteratorTraits::value_type, int>);
+static_assert(
+    std::same_as<RandomAccessTestIteratorTraits::
diff erence_type, std::ptr
diff _t>);
+static_assert(std::same_as<RandomAccessTestIteratorTraits::reference, int&>);
+static_assert(std::same_as<RandomAccessTestIteratorTraits::pointer, int*>);
+static_assert(!has_iterator_concept_v<RandomAccessTestIteratorTraits>);
+
+using ContiguousTestIteratorTraits =
+    std::iterator_traits<contiguous_iterator<int*> >;
+static_assert(std::same_as<ContiguousTestIteratorTraits::iterator_category,
+                           std::contiguous_iterator_tag>);
+static_assert(std::same_as<ContiguousTestIteratorTraits::value_type, int>);
+static_assert(
+    std::same_as<ContiguousTestIteratorTraits::
diff erence_type, std::ptr
diff _t>);
+static_assert(std::same_as<ContiguousTestIteratorTraits::reference, int&>);
+static_assert(std::same_as<ContiguousTestIteratorTraits::pointer, int*>);
+static_assert(!has_iterator_concept_v<ContiguousTestIteratorTraits>);
+
+using Cpp17BasicIteratorTraits = std::iterator_traits<iterator_traits_cpp17_iterator>;
+static_assert(std::same_as<Cpp17BasicIteratorTraits::iterator_category, std::output_iterator_tag>);
+static_assert(std::same_as<Cpp17BasicIteratorTraits::value_type, void>);
+static_assert(std::same_as<Cpp17BasicIteratorTraits::
diff erence_type, void>);
+static_assert(std::same_as<Cpp17BasicIteratorTraits::reference, void>);
+static_assert(std::same_as<Cpp17BasicIteratorTraits::pointer, void>);
+static_assert(!has_iterator_concept_v<Cpp17BasicIteratorTraits>);
+
+using Cpp17InputIteratorTraits = std::iterator_traits<iterator_traits_cpp17_input_iterator>;
+static_assert(std::same_as<Cpp17InputIteratorTraits::iterator_category, std::input_iterator_tag>);
+static_assert(std::same_as<Cpp17InputIteratorTraits::value_type, long>);
+static_assert(std::same_as<Cpp17InputIteratorTraits::
diff erence_type, int>);
+static_assert(std::same_as<Cpp17InputIteratorTraits::reference, int&>);
+static_assert(std::same_as<Cpp17InputIteratorTraits::pointer, void>);
+static_assert(!has_iterator_concept_v<Cpp17InputIteratorTraits>);
+
+using Cpp17ForwardIteratorTraits = std::iterator_traits<iterator_traits_cpp17_forward_iterator>;
+static_assert(std::same_as<Cpp17ForwardIteratorTraits::iterator_category, std::forward_iterator_tag>);
+static_assert(std::same_as<Cpp17ForwardIteratorTraits::value_type, int>);
+static_assert(std::same_as<Cpp17ForwardIteratorTraits::
diff erence_type, int>);
+static_assert(std::same_as<Cpp17ForwardIteratorTraits::reference, int&>);
+static_assert(std::same_as<Cpp17ForwardIteratorTraits::pointer, void>);
+static_assert(!has_iterator_concept_v<Cpp17ForwardIteratorTraits>);

diff  --git a/libcxx/test/std/iterators/iterator.primitives/iterator.traits/empty.fail.cpp b/libcxx/test/std/iterators/iterator.primitives/iterator.traits/empty.fail.cpp
index 5ab7f05c5392f..f683ae93beac6 100644
--- a/libcxx/test/std/iterators/iterator.primitives/iterator.traits/empty.fail.cpp
+++ b/libcxx/test/std/iterators/iterator.primitives/iterator.traits/empty.fail.cpp
@@ -91,7 +91,7 @@ int main(int, char**)
     typedef T::reference         RT; // expected-error-re {{no type named 'reference' in 'std:{{.*}}:iterator_traits<{{.+}}>}}
     typedef T::iterator_category CT; // expected-error-re {{no type named 'iterator_category' in 'std:{{.*}}:iterator_traits<{{.+}}>}}
     }
-
+#if TEST_STD_VER <= 17 || !defined(__cpp_lib_concepts)
     {
     typedef std::iterator_traits<NotAnIteratorNoPointer> T;
     typedef T::
diff erence_type   DT; // expected-error-re {{no type named '
diff erence_type' in 'std:{{.*}}:iterator_traits<{{.+}}>}}
@@ -100,7 +100,7 @@ int main(int, char**)
     typedef T::reference         RT; // expected-error-re {{no type named 'reference' in 'std:{{.*}}:iterator_traits<{{.+}}>}}
     typedef T::iterator_category CT; // expected-error-re {{no type named 'iterator_category' in 'std:{{.*}}:iterator_traits<{{.+}}>}}
     }
-
+#endif // TEST_STD_VER <= 17 || !defined(__cpp_lib_concepts)
     {
     typedef std::iterator_traits<NotAnIteratorNoReference> T;
     typedef T::
diff erence_type   DT; // expected-error-re {{no type named '
diff erence_type' in 'std:{{.*}}:iterator_traits<{{.+}}>}}

diff  --git a/libcxx/test/std/iterators/iterator.primitives/iterator.traits/empty.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/iterator.traits/empty.pass.cpp
index b9917e5a51862..d9956f843313d 100644
--- a/libcxx/test/std/iterators/iterator.primitives/iterator.traits/empty.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.primitives/iterator.traits/empty.pass.cpp
@@ -37,5 +37,5 @@ int main(int, char**)
     typedef std::iterator_traits<not_an_iterator> It;
     static_assert(!(has_value_type<It>::value), "");
 
-  return 0;
+    return 0;
 }

diff  --git a/libcxx/test/std/iterators/iterator.primitives/iterator.traits/volatile_pointer.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/iterator.traits/volatile_pointer.pass.cpp
index 63933cf1b0b07..c6d5dfc74c432 100644
--- a/libcxx/test/std/iterators/iterator.primitives/iterator.traits/volatile_pointer.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.primitives/iterator.traits/volatile_pointer.pass.cpp
@@ -26,6 +26,8 @@ int main(int, char**)
     static_assert((std::is_same<It::pointer, volatile A*>::value), "");
     static_assert((std::is_same<It::reference, volatile A&>::value), "");
     static_assert((std::is_same<It::iterator_category, std::random_access_iterator_tag>::value), "");
-
-  return 0;
+#if TEST_STD_VER > 17
+    ASSERT_SAME_TYPE(It::iterator_concept, std::contiguous_iterator_tag);
+#endif
+    return 0;
 }

diff  --git a/libcxx/test/libcxx/iterators/iterator.requirements/iterator.assoc.types/iterator.traits/iterator_traits_cpp17_iterators.h b/libcxx/test/support/iterator_traits_cpp17_iterators.h
similarity index 91%
rename from libcxx/test/libcxx/iterators/iterator.requirements/iterator.assoc.types/iterator.traits/iterator_traits_cpp17_iterators.h
rename to libcxx/test/support/iterator_traits_cpp17_iterators.h
index ffd33aed31654..27856013cdb42 100644
--- a/libcxx/test/libcxx/iterators/iterator.requirements/iterator.assoc.types/iterator.traits/iterator_traits_cpp17_iterators.h
+++ b/libcxx/test/support/iterator_traits_cpp17_iterators.h
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef TEST_LIBCXX_ITERATORS_ITERATOR_REQUIREMENTS_ITERATOR_ASSOC_TYPES_ITERATOR_TRAITS_ITERATOR_TRAITS_CPP17_ITERATORS
-#define TEST_LIBCXX_ITERATORS_ITERATOR_REQUIREMENTS_ITERATOR_ASSOC_TYPES_ITERATOR_TRAITS_ITERATOR_TRAITS_CPP17_ITERATORS
+#ifndef TEST_SUPPORT_ITERATOR_TRAITS_ITERATOR_TRAITS_CPP17_ITERATORS
+#define TEST_SUPPORT_ITERATOR_TRAITS_ITERATOR_TRAITS_CPP17_ITERATORS
 
 struct iterator_traits_cpp17_iterator {
   int& operator*();
@@ -101,4 +101,4 @@ struct iterator_traits_cpp17_random_access_iterator {
                                    iterator_traits_cpp17_random_access_iterator);
 };
 
-#endif // TEST_LIBCXX_ITERATORS_ITERATOR_REQUIREMENTS_ITERATOR_ASSOC_TYPES_ITERATOR_TRAITS_ITERATOR_TRAITS_CPP17_ITERATORS
+#endif // TEST_SUPPORT_ITERATOR_TRAITS_ITERATOR_TRAITS_CPP17_ITERATORS


        


More information about the libcxx-commits mailing list