[libcxx-commits] [libcxx] [libc++] Move _ITER_TRAITS and _ITER_CONCEPT into <__iterator/concepts.h> (PR #140528)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Sat May 31 00:52:30 PDT 2025


https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/140528

>From a5fb1bcbd6a9cdc442421f672b871c7a2a8ae77a Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Mon, 19 May 2025 13:10:13 +0200
Subject: [PATCH] [libc++] Move _ITER_TRAITS and _ITER_CONCEPT into
 <__iterator/concepts.h>

---
 libcxx/include/__iterator/concepts.h          | 41 ++++++++++-
 libcxx/include/__iterator/iterator_traits.h   | 53 ++------------
 ...p => cpp20_iter_concepts.compile.pass.cpp} | 69 ++++++++-----------
 .../cpp20_iter_traits.compile.pass.cpp        | 14 ++--
 4 files changed, 80 insertions(+), 97 deletions(-)
 rename libcxx/test/libcxx/iterators/iterator.requirements/iterator.concepts/{cpp20_iter_concepts.pass.cpp => cpp20_iter_concepts.compile.pass.cpp} (51%)

diff --git a/libcxx/include/__iterator/concepts.h b/libcxx/include/__iterator/concepts.h
index ddfc84ed710cb..20a1ab4691100 100644
--- a/libcxx/include/__iterator/concepts.h
+++ b/libcxx/include/__iterator/concepts.h
@@ -29,16 +29,19 @@
 #include <__iterator/incrementable_traits.h>
 #include <__iterator/iter_move.h>
 #include <__iterator/iterator_traits.h>
-#include <__iterator/readable_traits.h>
 #include <__memory/pointer_traits.h>
 #include <__type_traits/add_pointer.h>
 #include <__type_traits/common_reference.h>
+#include <__type_traits/conditional.h>
+#include <__type_traits/disjunction.h>
+#include <__type_traits/enable_if.h>
 #include <__type_traits/integral_constant.h>
 #include <__type_traits/invoke.h>
 #include <__type_traits/is_pointer.h>
 #include <__type_traits/is_primary_template.h>
 #include <__type_traits/is_reference.h>
 #include <__type_traits/is_referenceable.h>
+#include <__type_traits/is_valid_expansion.h>
 #include <__type_traits/remove_cv.h>
 #include <__type_traits/remove_cvref.h>
 #include <__utility/forward.h>
@@ -151,6 +154,42 @@ concept sized_sentinel_for =
       { __i - __s } -> same_as<iter_difference_t<_Ip>>;
     };
 
+template <class _Iter>
+struct __iter_traits_cache {
+  using type _LIBCPP_NODEBUG =
+      _If<__is_primary_template<iterator_traits<_Iter> >::value, _Iter, iterator_traits<_Iter> >;
+};
+template <class _Iter>
+using _ITER_TRAITS _LIBCPP_NODEBUG = typename __iter_traits_cache<_Iter>::type;
+
+struct __iter_concept_concept_test {
+  template <class _Iter>
+  using _Apply _LIBCPP_NODEBUG = typename _ITER_TRAITS<_Iter>::iterator_concept;
+};
+struct __iter_concept_category_test {
+  template <class _Iter>
+  using _Apply _LIBCPP_NODEBUG = typename _ITER_TRAITS<_Iter>::iterator_category;
+};
+struct __iter_concept_random_fallback {
+  template <class _Iter>
+  using _Apply _LIBCPP_NODEBUG =
+      __enable_if_t<__is_primary_template<iterator_traits<_Iter> >::value, random_access_iterator_tag>;
+};
+
+template <class _Iter, class _Tester>
+struct __test_iter_concept : _IsValidExpansion<_Tester::template _Apply, _Iter>, _Tester {};
+
+template <class _Iter>
+struct __iter_concept_cache {
+  using type _LIBCPP_NODEBUG =
+      _Or<__test_iter_concept<_Iter, __iter_concept_concept_test>,
+          __test_iter_concept<_Iter, __iter_concept_category_test>,
+          __test_iter_concept<_Iter, __iter_concept_random_fallback> >;
+};
+
+template <class _Iter>
+using _ITER_CONCEPT _LIBCPP_NODEBUG = typename __iter_concept_cache<_Iter>::type::template _Apply<_Iter>;
+
 // [iterator.concept.input]
 template <class _Ip>
 concept input_iterator = input_or_output_iterator<_Ip> && indirectly_readable<_Ip> && requires {
diff --git a/libcxx/include/__iterator/iterator_traits.h b/libcxx/include/__iterator/iterator_traits.h
index 8256580acb291..221d36614db08 100644
--- a/libcxx/include/__iterator/iterator_traits.h
+++ b/libcxx/include/__iterator/iterator_traits.h
@@ -27,14 +27,12 @@
 #include <__type_traits/conditional.h>
 #include <__type_traits/detected_or.h>
 #include <__type_traits/disjunction.h>
-#include <__type_traits/enable_if.h>
 #include <__type_traits/integral_constant.h>
 #include <__type_traits/is_convertible.h>
 #include <__type_traits/is_object.h>
 #include <__type_traits/is_primary_template.h>
 #include <__type_traits/is_reference.h>
 #include <__type_traits/is_referenceable.h>
-#include <__type_traits/is_valid_expansion.h>
 #include <__type_traits/nat.h>
 #include <__type_traits/remove_const.h>
 #include <__type_traits/remove_cv.h>
@@ -73,42 +71,6 @@ struct random_access_iterator_tag : public bidirectional_iterator_tag {};
 struct contiguous_iterator_tag : public random_access_iterator_tag {};
 #endif
 
-template <class _Iter>
-struct __iter_traits_cache {
-  using type _LIBCPP_NODEBUG =
-      _If<__is_primary_template<iterator_traits<_Iter> >::value, _Iter, iterator_traits<_Iter> >;
-};
-template <class _Iter>
-using _ITER_TRAITS _LIBCPP_NODEBUG = typename __iter_traits_cache<_Iter>::type;
-
-struct __iter_concept_concept_test {
-  template <class _Iter>
-  using _Apply _LIBCPP_NODEBUG = typename _ITER_TRAITS<_Iter>::iterator_concept;
-};
-struct __iter_concept_category_test {
-  template <class _Iter>
-  using _Apply _LIBCPP_NODEBUG = typename _ITER_TRAITS<_Iter>::iterator_category;
-};
-struct __iter_concept_random_fallback {
-  template <class _Iter>
-  using _Apply _LIBCPP_NODEBUG =
-      __enable_if_t<__is_primary_template<iterator_traits<_Iter> >::value, random_access_iterator_tag>;
-};
-
-template <class _Iter, class _Tester>
-struct __test_iter_concept : _IsValidExpansion<_Tester::template _Apply, _Iter>, _Tester {};
-
-template <class _Iter>
-struct __iter_concept_cache {
-  using type _LIBCPP_NODEBUG =
-      _Or<__test_iter_concept<_Iter, __iter_concept_concept_test>,
-          __test_iter_concept<_Iter, __iter_concept_category_test>,
-          __test_iter_concept<_Iter, __iter_concept_random_fallback> >;
-};
-
-template <class _Iter>
-using _ITER_CONCEPT _LIBCPP_NODEBUG = typename __iter_concept_cache<_Iter>::type::template _Apply<_Iter>;
-
 template <class _Tp>
 struct __has_iterator_typedefs {
 private:
@@ -195,16 +157,6 @@ concept __specifies_members = requires {
   requires __has_member_iterator_category<_Ip>;
 };
 
-template <class>
-struct __iterator_traits_member_pointer_or_void {
-  using type _LIBCPP_NODEBUG = void;
-};
-
-template <__has_member_pointer _Tp>
-struct __iterator_traits_member_pointer_or_void<_Tp> {
-  using type _LIBCPP_NODEBUG = typename _Tp::pointer;
-};
-
 template <class _Tp>
 concept __cpp17_iterator_missing_members = !__specifies_members<_Tp> && __iterator_traits_detail::__cpp17_iterator<_Tp>;
 
@@ -304,6 +256,9 @@ struct __iterator_traits_difference_type<_Ip> {
 template <class>
 struct __iterator_traits {};
 
+template <class _Tp>
+using __pointer_member _LIBCPP_NODEBUG = typename _Tp::pointer;
+
 // [iterator.traits]/3.1
 // If `I` has valid ([temp.deduct]) member types `difference-type`, `value-type`, `reference`, and
 // `iterator-category`, then `iterator-traits<I>` has the following publicly accessible members:
@@ -312,7 +267,7 @@ struct __iterator_traits<_Ip> {
   using iterator_category = typename _Ip::iterator_category;
   using value_type        = typename _Ip::value_type;
   using difference_type   = typename _Ip::difference_type;
-  using pointer           = typename __iterator_traits_member_pointer_or_void<_Ip>::type;
+  using pointer           = __detected_or_t<void, __pointer_member, _Ip>;
   using reference         = typename _Ip::reference;
 };
 
diff --git a/libcxx/test/libcxx/iterators/iterator.requirements/iterator.concepts/cpp20_iter_concepts.pass.cpp b/libcxx/test/libcxx/iterators/iterator.requirements/iterator.concepts/cpp20_iter_concepts.compile.pass.cpp
similarity index 51%
rename from libcxx/test/libcxx/iterators/iterator.requirements/iterator.concepts/cpp20_iter_concepts.pass.cpp
rename to libcxx/test/libcxx/iterators/iterator.requirements/iterator.concepts/cpp20_iter_concepts.compile.pass.cpp
index d551a551795ff..87549b8a81e9d 100644
--- a/libcxx/test/libcxx/iterators/iterator.requirements/iterator.concepts/cpp20_iter_concepts.pass.cpp
+++ b/libcxx/test/libcxx/iterators/iterator.requirements/iterator.concepts/cpp20_iter_concepts.compile.pass.cpp
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-// UNSUPPORTED: c++03
+// REQUIRES: std-at-least-c++20
 
 // ITER_TRAITS(I)
 
@@ -19,9 +19,9 @@
 // random_access_iterator_tag.
 // (1.4) -- Otherwise, ITER_CONCEPT(I) does not denote a type.
 
+#include <__iterator/concepts.h>
 #include <__type_traits/is_valid_expansion.h>
 #include <cstddef>
-#include <iterator>
 
 #include "test_macros.h"
 
@@ -30,19 +30,19 @@ struct OtherTagTwo : std::output_iterator_tag {};
 
 struct MyIter {
   using iterator_category = std::random_access_iterator_tag;
-  using iterator_concept = int;
-  using value_type = char;
-  using difference_type = std::ptrdiff_t;
-  using pointer = char*;
-  using reference = char&;
+  using iterator_concept  = int;
+  using value_type        = char;
+  using difference_type   = std::ptrdiff_t;
+  using pointer           = char*;
+  using reference         = char&;
 };
 
 struct MyIter2 {
   using iterator_category = OtherTag;
-  using value_type = char;
-  using difference_type = std::ptrdiff_t;
-  using pointer = char*;
-  using reference = char&;
+  using value_type        = char;
+  using difference_type   = std::ptrdiff_t;
+  using pointer           = char*;
+  using reference         = char&;
 };
 
 struct MyIter3 {};
@@ -52,10 +52,10 @@ struct EmptyWithSpecial {};
 template <>
 struct std::iterator_traits<MyIter3> {
   using iterator_category = OtherTagTwo;
-  using value_type = char;
-  using difference_type = std::ptrdiff_t;
-  using pointer = char*;
-  using reference = char&;
+  using value_type        = char;
+  using difference_type   = std::ptrdiff_t;
+  using pointer           = char*;
+  using reference         = char&;
 };
 
 template <>
@@ -63,29 +63,18 @@ struct std::iterator_traits<EmptyWithSpecial> {
   // empty non-default.
 };
 
-int main(int, char**) {
-  // If the qualified-id ITER_TRAITS(I)::iterator_concept is valid and names a type,
-  // then ITER_CONCEPT(I) denotes that type.
-  {
-#if TEST_STD_VER > 17
-    ASSERT_SAME_TYPE(std::_ITER_CONCEPT<char*>, std::contiguous_iterator_tag);
-#endif
-    ASSERT_SAME_TYPE(std::_ITER_CONCEPT<MyIter>, int);
-  }
-  // Otherwise, if the qualified-id ITER_TRAITS(I)::iterator_category is valid
-  // and names a type, then ITER_CONCEPT(I) denotes that type.
-  {
-    ASSERT_SAME_TYPE(std::_ITER_CONCEPT<MyIter2>, OtherTag);
-    ASSERT_SAME_TYPE(std::_ITER_CONCEPT<MyIter3>, OtherTagTwo);
-  }
-  // FIXME - This requirement makes no sense to me. Why does an empty type with
-  // an empty default iterator_traits get a category of random?
-  {
-    ASSERT_SAME_TYPE(std::_ITER_CONCEPT<Empty>, std::random_access_iterator_tag);
-  }
-  {
-    static_assert(!std::_IsValidExpansion<std::_ITER_CONCEPT, EmptyWithSpecial>::value, "");
-  }
+// If the qualified-id ITER_TRAITS(I)::iterator_concept is valid and names a type,
+// then ITER_CONCEPT(I) denotes that type.
+ASSERT_SAME_TYPE(std::_ITER_CONCEPT<char*>, std::contiguous_iterator_tag);
+ASSERT_SAME_TYPE(std::_ITER_CONCEPT<MyIter>, int);
 
-  return 0;
-}
+// Otherwise, if the qualified-id ITER_TRAITS(I)::iterator_category is valid
+// and names a type, then ITER_CONCEPT(I) denotes that type.
+ASSERT_SAME_TYPE(std::_ITER_CONCEPT<MyIter2>, OtherTag);
+ASSERT_SAME_TYPE(std::_ITER_CONCEPT<MyIter3>, OtherTagTwo);
+
+// FIXME - This requirement makes no sense to me. Why does an empty type with
+// an empty default iterator_traits get a category of random?
+ASSERT_SAME_TYPE(std::_ITER_CONCEPT<Empty>, std::random_access_iterator_tag);
+
+static_assert(!std::_IsValidExpansion<std::_ITER_CONCEPT, EmptyWithSpecial>::value);
diff --git a/libcxx/test/libcxx/iterators/iterator.requirements/iterator.concepts/cpp20_iter_traits.compile.pass.cpp b/libcxx/test/libcxx/iterators/iterator.requirements/iterator.concepts/cpp20_iter_traits.compile.pass.cpp
index 50047c1b90513..066587d68cd3b 100644
--- a/libcxx/test/libcxx/iterators/iterator.requirements/iterator.concepts/cpp20_iter_traits.compile.pass.cpp
+++ b/libcxx/test/libcxx/iterators/iterator.requirements/iterator.concepts/cpp20_iter_traits.compile.pass.cpp
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-// UNSUPPORTED: c++03
+// REQUIRES: std-at-least-c++20
 
 // ITER_TRAITS(I)
 
@@ -14,7 +14,7 @@
 // a specialization generated from the primary template. Otherwise,
 // ITER_TRAITS(I) denotes iterator_traits<I>.
 
-#include <iterator>
+#include <__iterator/concepts.h>
 #include <type_traits>
 
 #include "test_iterators.h"
@@ -27,8 +27,8 @@ template<> struct std::iterator_traits<B> {};
 template<> struct std::iterator_traits<C> : std::iterator_traits<A> {};
 template<> struct std::iterator_traits<D> : std::iterator_traits<int*> {};
 
-static_assert(std::is_same<std::_ITER_TRAITS<int*>, std::iterator_traits<int*>>::value, "");
-static_assert(std::is_same<std::_ITER_TRAITS<A>, A>::value, "");
-static_assert(std::is_same<std::_ITER_TRAITS<B>, std::iterator_traits<B>>::value, "");
-static_assert(std::is_same<std::_ITER_TRAITS<C>, std::iterator_traits<C>>::value, "");
-static_assert(std::is_same<std::_ITER_TRAITS<D>, std::iterator_traits<D>>::value, "");
+static_assert(std::is_same<std::_ITER_TRAITS<int*>, std::iterator_traits<int*>>::value);
+static_assert(std::is_same<std::_ITER_TRAITS<A>, A>::value);
+static_assert(std::is_same<std::_ITER_TRAITS<B>, std::iterator_traits<B>>::value);
+static_assert(std::is_same<std::_ITER_TRAITS<C>, std::iterator_traits<C>>::value);
+static_assert(std::is_same<std::_ITER_TRAITS<D>, std::iterator_traits<D>>::value);



More information about the libcxx-commits mailing list