diff --git a/libcxx/include/iterator b/libcxx/include/iterator --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -688,19 +688,11 @@ }; } // namespace __iterator_traits_detail -template struct __iterator_traits; - template -struct iterator_traits : __iterator_traits<_Ip> { - using __primary_template = iterator_traits; -}; - -template struct __iterator_traits_member_pointer; -template struct __iterator_traits_member_reference; -template struct __iterator_traits_iterator_category; +concept __has_member_reference = requires { typename _Ip::reference; }; template -concept __has_member_reference = requires { typename _Ip::reference; }; +concept __has_member_pointer = requires { typename _Ip::pointer; }; template concept __has_member_iterator_category = requires { typename _Ip::iterator_category; }; @@ -714,47 +706,50 @@ typename _Ip::value_type; }; +template +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; +}; + +// [iterator.traits]/3.4 +// Otherwise, `iterator_traits` has no members by any of the above names. +template +struct __iterator_traits {}; + // [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: +// 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: template<__specifies_members _Ip> 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<_Ip>::type; + using pointer = typename __iterator_traits_member_pointer_or_void<_Ip>::type; using reference = typename _Ip::reference; }; -namespace __iterator_traits_detail { +// TODO: do we need __iterator_traits_detail? template concept __cpp17_iterator_missing_members = !__specifies_members<_Tp> && - __cpp17_iterator<_Tp>; + __iterator_traits_detail::__cpp17_iterator<_Tp>; template concept __cpp17_input_iterator_missing_members = __cpp17_iterator_missing_members<_Tp> && - __cpp17_input_iterator<_Tp>; -} // namespace __iterator_traits_detail + __iterator_traits_detail::__cpp17_input_iterator<_Tp>; -// [iterator.traits]/3.2 -// Otherwise, if `I` satisfies the exposition-only concept `cpp17-input-iterator`, -// `iterator_­traits` has the following publicly accessible members: -template<__iterator_traits_detail::__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 difference_type = typename incrementable_traits<_Ip>::difference_type; - using pointer = typename __iterator_traits_member_pointer<_Ip>::type; - using reference = typename __iterator_traits_member_reference<_Ip>::type; -}; +// Otherwise, `pointer` names `void`. +template +struct __iterator_traits_member_pointer { 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 -concept __has_member_pointer = requires { typename _Ip::pointer; }; - template<__has_member_pointer _Ip> struct __iterator_traits_member_pointer<_Ip> { using type = typename _Ip::pointer; }; @@ -772,69 +767,81 @@ using type = decltype(declval<_Ip&>().operator->()); }; -// Otherwise, `pointer` names `void`. -template -struct __iterator_traits_member_pointer { using type = void; }; +// Otherwise, `reference` names `iter­reference­t`. +template +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; }; -// Otherwise, `reference` names `iter_­reference_­t`. +// [iterator.traits]/3.2.3.4 +// input_iterator_tag template -struct __iterator_traits_member_reference { using type = iter_reference_t<_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; +struct __deduce_iterator_category { + using type = input_iterator_tag; }; -// Otherwise, iterator_­category names: -template -struct __deduce_iterator_category; - -template -struct __iterator_traits_iterator_category : __deduce_iterator_category<_Ip> {}; - // [iterator.traits]/3.2.3.1 -// `random_­access_­iterator_­tag` if `I` satisfies `cpp17-random-access-iterator`, or otherwise +// `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 +// `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 +// `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; }; -// [iterator.traits]/3.2.3.4 -// input_­iterator_­tag template -struct __deduce_iterator_category { - using type = input_iterator_tag; +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; }; +// [iterator.traits]/3.2 +// Otherwise, if `I` satisfies the exposition-only concept `cpp17-input-iterator`, +// `iterator­traits` 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 difference_type = typename incrementable_traits<_Ip>::difference_type; + using pointer = typename __iterator_traits_member_pointer<_Ip>::type; + using reference = typename __iterator_traits_member_reference<_Ip>::type; +}; + +// otherwise, it names void. +template +struct __iterator_traits_difference_type { using type = void; }; -// [iterator.traits]/3.3 -template struct __iterator_traits_difference_type; +// If the qualified-id `incrementable_traits::difference_type` is valid and denotes a type, then +// `difference_type` names that type; +template +requires requires { typename incrementable_traits<_Ip>::difference_type; } +struct __iterator_traits_difference_type<_Ip> { + using type = typename incrementable_traits<_Ip>::difference_type; +}; // Otherwise, if `I` satisfies the exposition-only concept `cpp17-iterator`, then -// `iterator_­traits` has the following publicly accessible members: -template<__iterator_traits_detail::__cpp17_iterator_missing_members _Ip> +// `iterator_traits` 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; @@ -843,23 +850,13 @@ using reference = void; }; -// If the qualified-id `incrementable_­traits::difference_­type` is valid and denotes a type, then -// `difference_­type` names that type; template -requires requires { typename incrementable_traits<_Ip>::difference_type; } -struct __iterator_traits_difference_type<_Ip> { - using type = typename incrementable_traits<_Ip>::difference_type; +struct iterator_traits : __iterator_traits<_Ip> { + using __primary_template = iterator_traits; }; -// otherwise, it names void. -template -struct __iterator_traits_difference_type { using type = void; }; +#else // !defined(_LIBCPP_HAS_NO_RANGES) -// [iterator.traits]/3.4 -// Otherwise, `iterator_­traits` has no members by any of the above names. -template -struct __iterator_traits {}; -#else template struct __iterator_traits {}; template struct __iterator_traits_impl {}; 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 --- 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 @@ -14,245 +14,526 @@ // struct iterator_traits; #include - -#include +#include #include -#include "legacy_iterator_wrappers.h" +#include "test_macros.h" +#include "test_iterators.h" -template -struct explicit_members { - using iterator_category = Category; - using value_type = Value; - using difference_type = Difference; - using reference = Reference; +template +constexpr bool has_iterator_concept_v = requires { + typename Traits::iterator_concept; }; -template -struct explicit_members_with_pointer : explicit_members { - using pointer = typename explicit_members::value_type*; +using PointerIteratorTraits = std::iterator_traits; +static_assert(std::same_as); +static_assert(std::same_as); +static_assert( + std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); + +using ConstPointerIteratorTraits = std::iterator_traits; +static_assert(std::same_as); +static_assert(std::same_as); +static_assert( + std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); + +using VectorIteratorTraits = std::iterator_traits::iterator>; +static_assert(std::same_as); +static_assert(std::same_as); +static_assert( + std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); + +using StringIteratorTraits = std::iterator_traits; +static_assert(std::same_as); +static_assert(std::same_as); +static_assert( + std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); + +struct AllMembers { + struct iterator_category {}; + struct value_type {}; + struct difference_type {}; + struct reference {}; + struct pointer {}; }; - -template -[[nodiscard]] constexpr bool check_members_explicitly_provided() { - { - using fake_iterator = explicit_members; - using iterator_traits = std::iterator_traits; - static_assert(std::same_as); - static_assert(std::same_as); - static_assert(std::same_as); - static_assert(std::same_as); - static_assert(std::same_as); - } - - { - using fake_iterator = explicit_members_with_pointer; - using iterator_traits = std::iterator_traits; - static_assert(std::same_as); - static_assert(std::same_as); - static_assert(std::same_as); - static_assert(std::same_as); - static_assert(std::same_as); - } - return true; -} - -static_assert(check_members_explicitly_provided()); -static_assert(check_members_explicitly_provided()); -static_assert(check_members_explicitly_provided()); - -struct S {}; -static_assert(check_members_explicitly_provided()); -static_assert(check_members_explicitly_provided()); - -template -struct get_reference { - using type = std::iter_reference_t; +using AllMembersTraits = std::iterator_traits; +static_assert(std::same_as); +static_assert( + std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(!has_iterator_concept_v); + +struct NoPointerMember { + struct iterator_category {}; + struct value_type {}; + struct difference_type {}; + struct reference {}; + // ignored, because NoPointerMember is not a LegacyInputIterator: + value_type* operator->() const; }; - -template > Wrapper> -struct get_reference { - using type = typename Wrapper::reference; +using NoPointerMemberTraits = std::iterator_traits; +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert( + std::same_as); +static_assert(std::same_as); +static_assert(!has_iterator_concept_v); + +struct IterConcept { + struct iterator_category {}; + struct iterator_concept {}; // ignored + struct value_type {}; + struct difference_type {}; + struct reference {}; + struct pointer {}; }; - -template -struct get_pointer { - using type = void; +using IterConceptTraits = std::iterator_traits; +static_assert(std::same_as); +static_assert( + std::same_as); +static_assert(std::same_as); +static_assert( + std::same_as); +static_assert(std::same_as); +static_assert(!has_iterator_concept_v); + +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 > Wrapper> -struct get_pointer { - using type = typename Wrapper::pointer; +template <> +struct std::incrementable_traits { + using difference_type = short; }; - -template -struct get_pointer { - using type = decltype(std::declval().operator->()); +using LegacyInputTraits = std::iterator_traits; +static_assert(std::same_as); +static_assert( + std::same_as); +static_assert(std::same_as); +static_assert( + std::same_as); +static_assert(std::same_as); +static_assert(!has_iterator_concept_v); + +struct LegacyInputNoValueType { + struct not_value_type {}; + using difference_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 -[[nodiscard]] constexpr bool check_wrapper_traits() { - using Traits = std::iterator_traits; - static_assert(std::same_as); - static_assert(std::same_as::value_type>); - static_assert(std::same_as::difference_type>); - static_assert(std::same_as::type>); - static_assert(std::same_as::type>); - return true; -} - -template class... Args> -requires(sizeof...(Args) > 0) constexpr void check_with_legacy_input_iterator() { - { - using iterator = legacy_input_iterator; - static_assert(check_wrapper_traits()); - } - { - using iterator = legacy_forward_iterator; - static_assert(check_wrapper_traits()); - } - { - using iterator = legacy_bidirectional_iterator; - static_assert(check_wrapper_traits()); - } - { - using iterator = legacy_random_access_iterator; - static_assert(check_wrapper_traits()); - } -} - -template -[[nodiscard]] constexpr bool check_with_legacy_input_iterator() { - check_with_legacy_input_iterator(); - check_with_legacy_input_iterator(); - check_with_legacy_input_iterator(); - check_with_legacy_input_iterator(); - check_with_legacy_input_iterator(); - check_with_legacy_input_iterator(); - return true; -} -static_assert(check_with_legacy_input_iterator::iterator>()); -static_assert(check_with_legacy_input_iterator::const_iterator>()); - -template -[[nodiscard]] constexpr bool check_with_legacy_iterator() { - { - using iterator = legacy_iterator; - using iterator_traits = std::iterator_traits; - static_assert(std::same_as); - static_assert(std::same_as); - static_assert(std::same_as); - static_assert(std::same_as); - static_assert(std::same_as); - } - { - using iterator = legacy_iterator; - using iterator_traits = std::iterator_traits; - static_assert(std::same_as); - static_assert(std::same_as); - static_assert(std::same_as); - static_assert(std::same_as); - static_assert(std::same_as); - } - return true; -} - -static_assert(check_with_legacy_iterator::iterator>()); -static_assert(check_with_legacy_iterator::const_iterator>()); - -template -[[nodiscard]] constexpr bool check_fails() { - static_assert(!requires { typename std::iterator_traits::iterator_concept; }); - static_assert(!requires { typename std::iterator_traits::iterator_category; }); - static_assert(!requires { typename std::iterator_traits::value_type; }); - static_assert(!requires { typename std::iterator_traits::difference_type; }); - static_assert(!requires { typename std::iterator_traits::pointer; }); - static_assert(!requires { typename std::iterator_traits::reference; }); - return true; -} - -static_assert(check_fails()); -static_assert(check_fails()); -static_assert(check_fails()); -static_assert(check_fails()); -static_assert(check_fails()); - -static_assert(check_fails()); -static_assert(check_fails()); -static_assert(check_fails()); -static_assert(check_fails()); -static_assert(check_fails()); -static_assert(check_fails()); -static_assert(check_fails()); - -struct missing_iterator_category { - using value_type = int; - using difference_type = int; - using pointer = int*; - using reference = int&; +template <> +struct std::indirectly_readable_traits { + using value_type = LegacyInputNoValueType::not_value_type; }; -static_assert(check_fails()); - -struct iterator_category_as_static_member { - using value_type = int; - using difference_type = int; - using pointer = int*; - using reference = int&; - - inline static constexpr int iterator_category = 0; +using LegacyInputNoValueTypeTraits = + std::iterator_traits; +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(!has_iterator_concept_v); + +struct LegacyForward { + struct not_value_type {}; + + friend bool operator==(LegacyForward, LegacyForward); + const not_value_type& operator*() const; + LegacyForward& operator++(); + LegacyForward operator++(int); }; -static_assert(check_fails()); - -struct missing_value_type { - using iterator_category = std::input_iterator_tag; - using difference_type = int; - using pointer = int*; - using reference = int&; +template <> +struct std::indirectly_readable_traits { + using value_type = LegacyForward::not_value_type; }; -static_assert(check_fails()); - -struct value_type_as_static_member { - using iterator_category = std::input_iterator_tag; - using difference_type = int; - using pointer = int*; - using reference = int&; - - inline static constexpr int value_type = 0; +template <> +struct std::incrementable_traits { + using difference_type = short; // or any signed integral type }; -static_assert(check_fails()); - -struct missing_difference_type { - using iterator_category = std::input_iterator_tag; - using value_type = int; - using pointer = int*; - using reference = int&; +using LegacyForwardTraits = std::iterator_traits; +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(!has_iterator_concept_v); + +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); }; -static_assert(check_fails()); - -struct difference_type_as_static_member { - using iterator_category = std::input_iterator_tag; - using value_type = int; - using pointer = int*; - using reference = int&; - - inline static constexpr int difference_type = 0; +using LegacyBidirectionalTraits = std::iterator_traits; +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(!has_iterator_concept_v); + +// Almost a random access iterator except it is missing operator-(It, It). +struct MissingMinusIterIter { + struct value_type {}; + + friend auto operator<=>(MissingMinusIterIter, MissingMinusIterIter) = default; + const value_type& operator*() const; + const value_type& operator[](long) const; + MissingMinusIterIter& operator++(); + MissingMinusIterIter operator++(int); + MissingMinusIterIter& operator--(); + MissingMinusIterIter operator--(int); + MissingMinusIterIter& operator+=(long); + MissingMinusIterIter& operator-=(long); + + // Providing difference_type does not fully compensate for missing operator-(It, It). + friend MissingMinusIterIter operator-(MissingMinusIterIter, int); + friend MissingMinusIterIter operator+(MissingMinusIterIter, int); + friend MissingMinusIterIter operator+(int, MissingMinusIterIter); }; -static_assert(check_fails()); - -struct missing_reference { - using iterator_category = std::input_iterator_tag; - using value_type = int; - using difference_type = int; - using pointer = int*; +template <> +struct std::incrementable_traits { + using difference_type = short; }; -static_assert(check_fails()); - -struct reference_as_static_member { - using iterator_category = std::input_iterator_tag; - using value_type = int; - using difference_type = int; - using pointer = int*; - - inline static constexpr int reference = 0; +using MissingMinusIterIterTraits = std::iterator_traits; +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(!has_iterator_concept_v); + +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; +static_assert(std::same_as); +static_assert(std::same_as); +static_assert( + std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(!has_iterator_concept_v); + +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; +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(!has_iterator_concept_v); + +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 { + using value_type = LegacyRandomAccessSpaceship::not_value_type; +}; +template <> +struct std::incrementable_traits { + using difference_type = short; // or any signed integral type +}; +using LegacyRandomAccessSpaceshipTraits = + std::iterator_traits; +static_assert(std::same_as); +static_assert(std::same_as); +static_assert( + std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(!has_iterator_concept_v); + +// For output iterators, value_type, difference_type, and reference may be void. +struct BareLegacyOutput { + struct Empty {}; + Empty operator*() const; + BareLegacyOutput& operator++(); + BareLegacyOutput operator++(int); +}; +using BareLegacyOutputTraits = std::iterator_traits; +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(!has_iterator_concept_v); + +// The operator- means we get difference_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; +static_assert(std::same_as); +static_assert(std::same_as); +static_assert( + std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(!has_iterator_concept_v); + +struct LegacyOutputWithMemberTypes { + struct value_type {}; // ignored + struct reference {}; // ignored + using difference_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; +static_assert(std::same_as); +static_assert( + std::same_as); +static_assert( + std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(!has_iterator_concept_v); + +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 +requires std::same_as< + I, LegacyRandomAccessSpecialized> struct std::iterator_traits { + using iterator_category = std::output_iterator_tag; + using value_type = short; + using difference_type = short; + using reference = short&; + using pointer = short*; }; -static_assert(check_fails()); +using LegacyRandomAccessSpecializedTraits = + std::iterator_traits; +static_assert( + std::same_as); +static_assert( + std::same_as); +static_assert( + std::same_as); +static_assert( + std::same_as); +static_assert( + std::same_as); +static_assert(!has_iterator_concept_v); + +using InputTestItereatorTraits = std::iterator_traits >; +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(!has_iterator_concept_v); + +using OutputTestItereatorTraits = std::iterator_traits >; +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(!has_iterator_concept_v); + +using ForwardTestIteratorTraits = std::iterator_traits >; +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(!has_iterator_concept_v); + +using BidirectionalTestIteratorTraits = + std::iterator_traits >; +static_assert(std::same_as); +static_assert(std::same_as); +static_assert( + std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(!has_iterator_concept_v); + +using RandomAccessTestIteratorTraits = + std::iterator_traits >; +static_assert(std::same_as); +static_assert(std::same_as); +static_assert( + std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(!has_iterator_concept_v); + +using ContiguousTestIteratorTraits = + std::iterator_traits >; +static_assert(std::same_as); +static_assert(std::same_as); +static_assert( + std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(!has_iterator_concept_v); 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 --- a/libcxx/test/std/iterators/iterator.primitives/iterator.traits/empty.fail.cpp +++ b/libcxx/test/std/iterators/iterator.primitives/iterator.traits/empty.fail.cpp @@ -100,7 +100,7 @@ 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 +#endif // _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_HAS_NO_CONCEPTS) { typedef std::iterator_traits T; typedef T::difference_type DT; // expected-error-re {{no type named 'difference_type' in 'std:{{.*}}:iterator_traits<{{.+}}>}} diff --git a/libcxx/test/std/iterators/iterator.primitives/iterator.traits/legacy_iterator_wrappers.h b/libcxx/test/std/iterators/iterator.primitives/iterator.traits/legacy_iterator_wrappers.h deleted file mode 100644 --- a/libcxx/test/std/iterators/iterator.primitives/iterator.traits/legacy_iterator_wrappers.h +++ /dev/null @@ -1,125 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -#ifndef STD_ITERATORS_ITERATOR_PRIMITIVES_ITERATOR_TRAITS_LEGACY_ITERATORS_H -#define STD_ITERATORS_ITERATOR_PRIMITIVES_ITERATOR_TRAITS_LEGACY_ITERATORS_H - -template -concept has_arrow = requires(I& i) { - i.operator->(); -}; - -// Extension point for `legacy_iterator_wrapper` to support `operator->`. -template -struct arrow_extension { - decltype(std::declval().operator->()) operator->() const; -}; - -// Wrapper around a legacy C++ iterator to give it a minimal interface. -// -// The key difference between these `legacy.*_iterator` types and those found in -// `support/test_iterators.h` is that the legacy iterator class are designed to support mixins and -// specifically test C++20's changes to `iterator_traits`. Namely, the absence of members and the -// arrow operator is important. -template class... Args> -class legacy_iterator : public Args... { -public: - legacy_iterator() = default; - explicit legacy_iterator(I i) : base_(i) {} - - decltype(auto) operator*() const { return *base_; } - - legacy_iterator& operator++(); - legacy_iterator operator++(int); - -private: - I base_ = I(); -}; - -// Wrapper around a legacy C++ input iterator to give it a minimal interface. -template class... Args> -class legacy_input_iterator : public legacy_iterator { -public: - using iterator_category = std::input_iterator_tag; - using difference_type = typename std::incrementable_traits::difference_type; - using value_type = typename std::indirectly_readable_traits::value_type; - - using legacy_iterator::legacy_iterator; - bool operator==(legacy_input_iterator const&) const; - legacy_input_iterator& operator++(); - legacy_input_iterator operator++(int); -}; - -// Wrapper around a legacy C++ forward iterator to give it a minimal interface. -template class... Args> -class legacy_forward_iterator : public legacy_input_iterator { -public: - using iterator_category = std::forward_iterator_tag; - using legacy_input_iterator::legacy_input_iterator; - - legacy_forward_iterator& operator++(); - legacy_forward_iterator operator++(int); -}; - -// Wrapper around a legacy C++ bidirectional iterator to give it a minimal interface. -template class... Args> -class legacy_bidirectional_iterator : public legacy_forward_iterator { -public: - using iterator_category = std::bidirectional_iterator_tag; - using legacy_forward_iterator::legacy_forward_iterator; - - legacy_bidirectional_iterator& operator++(); - legacy_bidirectional_iterator operator++(int); - legacy_bidirectional_iterator& operator--(); - legacy_bidirectional_iterator operator--(int); -}; - -// Wrapper around a legacy C++ random-access iterator to give it a minimal interface. -template class... Args> -class legacy_random_access_iterator : public legacy_bidirectional_iterator { -public: - using iterator_category = std::random_access_iterator_tag; - using legacy_bidirectional_iterator::legacy_bidirectional_iterator; - using typename legacy_bidirectional_iterator::difference_type; - - legacy_random_access_iterator& operator++(); - legacy_random_access_iterator operator++(int); - legacy_random_access_iterator& operator--(); - legacy_random_access_iterator operator--(int); - legacy_random_access_iterator& operator+=(difference_type); - legacy_random_access_iterator& operator-=(difference_type); - - friend legacy_random_access_iterator operator+(legacy_random_access_iterator, difference_type); - friend legacy_random_access_iterator operator+(difference_type, legacy_random_access_iterator); - friend legacy_random_access_iterator operator-(legacy_random_access_iterator, difference_type); - - difference_type operator-(legacy_random_access_iterator) const; - decltype(auto) operator[](difference_type const n) const { return *(*this + n); } - bool operator<(legacy_random_access_iterator) const; - bool operator>(legacy_random_access_iterator) const; - bool operator<=(legacy_random_access_iterator) const; - bool operator>=(legacy_random_access_iterator) const; -}; - -// Extension point for reference member. -template -struct reference_extension { - using reference = typename I::reference; -}; - -// Extension point for pointer member. -template -struct pointer_extension { - using pointer = typename I::pointer; -}; - -// Extension point to indicate no extension points. -// This is used for function overloading when there isn't a better name for two overloads. -template -struct empty_extension {}; - -#endif // STD_ITERATORS_ITERATOR_PRIMITIVES_ITERATOR_TRAITS_LEGACY_ITERATORS_H