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>; }; +template +struct __iter_traits_cache { + using type _LIBCPP_NODEBUG = + _If<__is_primary_template >::value, _Iter, iterator_traits<_Iter> >; +}; +template +using _ITER_TRAITS _LIBCPP_NODEBUG = typename __iter_traits_cache<_Iter>::type; + +struct __iter_concept_concept_test { + template + using _Apply _LIBCPP_NODEBUG = typename _ITER_TRAITS<_Iter>::iterator_concept; +}; +struct __iter_concept_category_test { + template + using _Apply _LIBCPP_NODEBUG = typename _ITER_TRAITS<_Iter>::iterator_category; +}; +struct __iter_concept_random_fallback { + template + using _Apply _LIBCPP_NODEBUG = + __enable_if_t<__is_primary_template >::value, random_access_iterator_tag>; +}; + +template +struct __test_iter_concept : _IsValidExpansion<_Tester::template _Apply, _Iter>, _Tester {}; + +template +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 +using _ITER_CONCEPT _LIBCPP_NODEBUG = typename __iter_concept_cache<_Iter>::type::template _Apply<_Iter>; + // [iterator.concept.input] template 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 -struct __iter_traits_cache { - using type _LIBCPP_NODEBUG = - _If<__is_primary_template >::value, _Iter, iterator_traits<_Iter> >; -}; -template -using _ITER_TRAITS _LIBCPP_NODEBUG = typename __iter_traits_cache<_Iter>::type; - -struct __iter_concept_concept_test { - template - using _Apply _LIBCPP_NODEBUG = typename _ITER_TRAITS<_Iter>::iterator_concept; -}; -struct __iter_concept_category_test { - template - using _Apply _LIBCPP_NODEBUG = typename _ITER_TRAITS<_Iter>::iterator_category; -}; -struct __iter_concept_random_fallback { - template - using _Apply _LIBCPP_NODEBUG = - __enable_if_t<__is_primary_template >::value, random_access_iterator_tag>; -}; - -template -struct __test_iter_concept : _IsValidExpansion<_Tester::template _Apply, _Iter>, _Tester {}; - -template -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 -using _ITER_CONCEPT _LIBCPP_NODEBUG = typename __iter_concept_cache<_Iter>::type::template _Apply<_Iter>; - template struct __has_iterator_typedefs { private: @@ -195,16 +157,6 @@ concept __specifies_members = requires { requires __has_member_iterator_category<_Ip>; }; -template -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 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 struct __iterator_traits {}; +template +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` 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; 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 52% 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..ffe473c97fedc 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,6 +19,7 @@ // 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 #include @@ -30,19 +31,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 +53,10 @@ struct EmptyWithSpecial {}; template <> struct std::iterator_traits { 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 +64,18 @@ struct std::iterator_traits { // 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, std::contiguous_iterator_tag); -#endif - ASSERT_SAME_TYPE(std::_ITER_CONCEPT, 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, OtherTag); - ASSERT_SAME_TYPE(std::_ITER_CONCEPT, 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, std::random_access_iterator_tag); - } - { - static_assert(!std::_IsValidExpansion::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, std::contiguous_iterator_tag); +ASSERT_SAME_TYPE(std::_ITER_CONCEPT, 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, OtherTag); +ASSERT_SAME_TYPE(std::_ITER_CONCEPT, 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, std::random_access_iterator_tag); + +static_assert(!std::_IsValidExpansion::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. -#include +#include <__iterator/concepts.h> #include #include "test_iterators.h" @@ -27,8 +27,8 @@ template<> struct std::iterator_traits {}; template<> struct std::iterator_traits : std::iterator_traits {}; template<> struct std::iterator_traits : std::iterator_traits {}; -static_assert(std::is_same, std::iterator_traits>::value, ""); -static_assert(std::is_same, A>::value, ""); -static_assert(std::is_same, std::iterator_traits>::value, ""); -static_assert(std::is_same, std::iterator_traits>::value, ""); -static_assert(std::is_same, std::iterator_traits>::value, ""); +static_assert(std::is_same, std::iterator_traits>::value); +static_assert(std::is_same, A>::value); +static_assert(std::is_same, std::iterator_traits>::value); +static_assert(std::is_same, std::iterator_traits>::value); +static_assert(std::is_same, std::iterator_traits>::value);