diff --git a/libcxx/include/iterator b/libcxx/include/iterator --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -21,24 +21,11 @@ template struct indirectly_readable_traits; // since C++20 template -struct iterator_traits -{ - typedef typename Iterator::difference_type difference_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 -struct iterator_traits -{ - typedef ptrdiff_t difference_type; - typedef T value_type; - typedef T* pointer; - typedef T& reference; - typedef random_access_iterator_tag iterator_category; -}; + requires is_object_v // since C++20 +struct iterator_traits; template using iter_reference_t = decltype(*declval()); @@ -546,18 +533,6 @@ static const bool value = sizeof(__test<_Tp>(nullptr)) == 1; }; -template struct __iterator_traits_impl {}; - -template -struct __iterator_traits_impl<_Iter, true> -{ - typedef typename _Iter::difference_type difference_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 @@ { __i[__n] } -> convertible_to>; }; } // namespace __iterator_traits_detail -#endif // !defined(_LIBCPP_HAS_NO_RANGES) + +template +concept __has_member_reference = requires { typename _Ip::reference; }; + +template +concept __has_member_pointer = requires { typename _Ip::pointer; }; + +template +concept __has_member_iterator_category = requires { typename _Ip::iterator_category; }; + +template +concept __specifies_members = requires { + typename _Ip::value_type; + typename _Ip::difference_type; + requires __has_member_reference<_Ip>; + requires __has_member_iterator_category<_Ip>; + }; + +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; +}; + +template +concept __cpp17_iterator_missing_members = + !__specifies_members<_Tp> && + __iterator_traits_detail::__cpp17_iterator<_Tp>; + +template +concept __cpp17_input_iterator_missing_members = + __cpp17_iterator_missing_members<_Tp> && + __iterator_traits_detail::__cpp17_input_iterator<_Tp>; + +// Otherwise, `pointer` names `void`. +template +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().operator->())` is well-formed, then `pointer` names that +// type. +template +concept __has_arrow = + requires(_Ip& __i) { + __i.operator->(); + }; + +template + 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`. +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; }; + +// [iterator.traits]/3.2.3.4 +// input_iterator_tag +template +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 +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 +struct __iterator_traits_difference_type { using type = 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; +}; + +// [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: +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_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` 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_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` 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 difference_type = typename __iterator_traits_difference_type<_Ip>::type; + using pointer = void; + using reference = void; +}; + +template +struct iterator_traits : __iterator_traits<_Ip> { + using __primary_template = iterator_traits; +}; + +#else // !defined(_LIBCPP_HAS_NO_RANGES) template struct __iterator_traits {}; +template struct __iterator_traits_impl {}; + +template +struct __iterator_traits_impl<_Iter, true> +{ + typedef typename _Iter::difference_type difference_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 struct __iterator_traits<_Iter, true> : __iterator_traits_impl @@ -646,8 +799,12 @@ using __primary_template = iterator_traits; }; +#endif // !defined(_LIBCPP_HAS_NO_RANGES) template +#if !defined(_LIBCPP_HAS_NO_RANGES) +requires is_object_v<_Tp> +#endif struct _LIBCPP_TEMPLATE_VIS iterator_traits<_Tp*> { typedef ptrdiff_t difference_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 --- 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 @@ static_assert((std::is_same::value), ""); static_assert((std::is_same::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 --- 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 @@ static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); static_assert((std::is_same::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 --- /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 +// struct iterator_traits; + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +# include +# include +#endif + +#ifndef _LIBCPP_HAS_NO_FILESYSTEM_LIBRARY +# include +#endif + +#include "test_macros.h" +#include "test_iterators.h" +#include "iterator_traits_cpp17_iterators.h" + +template +constexpr bool has_iterator_concept_v = requires { + typename Traits::iterator_concept; +}; + +// Standard types. + +template +constexpr bool testStdlibIteratorConst() { + using 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); + if constexpr (std::same_as) + static_assert(!has_iterator_concept_v); + else + static_assert(std::same_as); + + return true; +} + +template +constexpr bool testStdlibIterator() { + using 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); + if constexpr (std::same_as) + static_assert(!has_iterator_concept_v); + else + static_assert(std::same_as); + + return true; +} + +template +requires std::same_as constexpr bool testStdlibIterator() { + using 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); + static_assert(!has_iterator_concept_v); + + return true; +} + +template +constexpr bool testStdlibIterator() { + using 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); + if constexpr (std::same_as) + static_assert(!has_iterator_concept_v); + else + static_assert(std::same_as); + + return true; +} + +template +constexpr bool testBothStdlibIterators() { + static_assert(testStdlibIteratorConst()); + static_assert(testStdlibIterator()); + + return true; +} + +static_assert(testBothStdlibIterators, int, std::random_access_iterator_tag>()); +static_assert(testBothStdlibIterators()); +static_assert(testStdlibIteratorConst()); +static_assert(testStdlibIteratorConst()); +static_assert( + testBothStdlibIterators, int, std::random_access_iterator_tag, std::contiguous_iterator_tag>()); +static_assert(testBothStdlibIterators, int, std::random_access_iterator_tag>()); +#ifndef _LIBCPP_HAS_NO_FILESYSTEM_LIBRARY +static_assert(testStdlibIterator()); +static_assert(testStdlibIterator()); +#endif +static_assert(testBothStdlibIterators, int, std::forward_iterator_tag>()); +static_assert(testBothStdlibIterators, int, std::random_access_iterator_tag>()); +static_assert(testBothStdlibIterators, int, std::bidirectional_iterator_tag>()); +static_assert(testStdlibIterator::iterator, int, std::ptrdiff_t, const int&, const int*, + std::bidirectional_iterator_tag>()); +static_assert(testStdlibIterator::const_iterator, int, std::ptrdiff_t, const int&, const int*, + std::bidirectional_iterator_tag>()); +static_assert( + testBothStdlibIterators, std::pair, std::bidirectional_iterator_tag>()); +static_assert( + testBothStdlibIterators, std::pair, std::forward_iterator_tag>()); +static_assert(testStdlibIterator::local_iterator, std::pair, + std::forward_iterator_tag>()); +static_assert(testStdlibIteratorConst::const_local_iterator, std::pair, + std::forward_iterator_tag>()); +static_assert( + testBothStdlibIterators, std::pair, std::forward_iterator_tag>()); +static_assert(testStdlibIterator::local_iterator, std::pair, + std::forward_iterator_tag>()); +static_assert(testStdlibIteratorConst::const_local_iterator, + std::pair, std::forward_iterator_tag>()); +static_assert(testStdlibIteratorConst::iterator, int, std::forward_iterator_tag>()); +static_assert(testStdlibIteratorConst::const_iterator, int, std::forward_iterator_tag>()); +static_assert(testStdlibIteratorConst::local_iterator, int, std::forward_iterator_tag>()); +static_assert(testStdlibIteratorConst::const_local_iterator, int, std::forward_iterator_tag>()); +static_assert(testStdlibIteratorConst::iterator, int, std::forward_iterator_tag>()); +static_assert(testStdlibIteratorConst::const_iterator, int, std::forward_iterator_tag>()); +static_assert(testStdlibIteratorConst::local_iterator, int, std::forward_iterator_tag>()); +static_assert( + testStdlibIteratorConst::const_local_iterator, int, std::forward_iterator_tag>()); + +static_assert( + testStdlibIterator::iterator>, int, std::random_access_iterator_tag>()); +static_assert( + testStdlibIterator::iterator>, void, std::output_iterator_tag>()); +static_assert( + testStdlibIterator::iterator>, void, std::output_iterator_tag>()); +static_assert(testStdlibIterator >, void, std::output_iterator_tag>()); +static_assert(testStdlibIteratorConst, int, std::input_iterator_tag>()); + +#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) +static_assert( + testStdlibIterator, char, long long, char, char*, std::input_iterator_tag>()); +using MoveIter = std::move_iterator::iterator>; +static_assert( + testStdlibIterator()); +static_assert(testStdlibIterator, void, std::output_iterator_tag, std::ptrdiff_t>()); +static_assert( + testStdlibIterator, void, std::output_iterator_tag, std::ptrdiff_t>()); +static_assert(testStdlibIteratorConst()); +static_assert(testStdlibIteratorConst()); +#endif // !_LIBCPP_HAS_NO_LOCALIZATION + +// Local test iterators. + +struct AllMembers { + struct iterator_category {}; + struct value_type {}; + struct difference_type {}; + struct reference {}; + struct pointer {}; +}; +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; +}; +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 {}; + // "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 difference_type {}; + struct reference {}; + struct pointer {}; +}; +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 <> +struct std::incrementable_traits { + using difference_type = short; +}; +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 <> +struct std::indirectly_readable_traits { + using value_type = LegacyInputNoValueType::not_value_type; +}; +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); +}; +template <> +struct std::indirectly_readable_traits { + using value_type = LegacyForward::not_value_type; +}; +template <> +struct std::incrementable_traits { + using difference_type = short; // or any signed integral type +}; +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); +}; +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 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 difference_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 { + using difference_type = short; +}; +using MinusNotDeclaredIterTraits = 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*; +}; +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); + +// Other test iterators. + +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); + +using Cpp17BasicIteratorTraits = 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 Cpp17InputIteratorTraits = 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 Cpp17ForwardIteratorTraits = 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 @@ -91,7 +91,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<{{.+}}>}} } - +#if TEST_STD_VER <= 17 || !defined(__cpp_lib_concepts) { typedef std::iterator_traits T; typedef T::difference_type DT; // expected-error-re {{no type named 'difference_type' in 'std:{{.*}}:iterator_traits<{{.+}}>}} @@ -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 // TEST_STD_VER <= 17 || !defined(__cpp_lib_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/empty.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/iterator.traits/empty.pass.cpp --- 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 @@ typedef std::iterator_traits It; static_assert(!(has_value_type::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 --- 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 @@ static_assert((std::is_same::value), ""); static_assert((std::is_same::value), ""); static_assert((std::is_same::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 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 --- 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 @@ 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