diff --git a/libcxx/docs/Cxx2aStatusPaperStatus.csv b/libcxx/docs/Cxx2aStatusPaperStatus.csv --- a/libcxx/docs/Cxx2aStatusPaperStatus.csv +++ b/libcxx/docs/Cxx2aStatusPaperStatus.csv @@ -61,7 +61,7 @@ "`P0608R3 `__","LWG","A sane variant converting constructor","San Diego","|Complete|","9.0" "`P0655R1 `__","LWG","visit: Explicit Return Type for visit","San Diego","|Complete|","12.0" "`P0771R1 `__","LWG","std::function move constructor should be noexcept","San Diego","|Complete|","6.0" -"`P0896R4 `__","LWG","The One Ranges Proposal","San Diego","* *","" +"`P0896R4 `__","LWG","The One Ranges Proposal","San Diego","|In Progress|","" "`P0899R1 `__","LWG","P0899R1 - LWG 3016 is not a defect","San Diego","|Nothing To Do|","" "`P0919R3 `__","LWG","Heterogeneous lookup for unordered containers","San Diego","|Complete|","12.0" "`P0972R0 `__","LWG"," ``zero()``\ , ``min()``\ , and ``max()``\ should be noexcept","San Diego","|Complete|","8.0" diff --git a/libcxx/include/__config b/libcxx/include/__config --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -848,6 +848,10 @@ #define _LIBCPP_HAS_NO_CONCEPTS #endif +#if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_HAS_NO_CONCEPTS) +#define _LIBCPP_HAS_NO_RANGES +#endif + #ifdef _LIBCPP_CXX03_LANG # define _LIBCPP_DEFAULT {} #else diff --git a/libcxx/include/iterator b/libcxx/include/iterator --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -13,8 +13,11 @@ /* iterator synopsis +#include + namespace std { +template struct incrementable_traits; // since C++20 template struct iterator_traits @@ -425,6 +428,7 @@ #include <__memory/base.h> #include <__memory/pointer_traits.h> #include +#include #include <__debug> @@ -433,6 +437,43 @@ #endif _LIBCPP_BEGIN_NAMESPACE_STD + +#if !defined(_LIBCPP_HAS_NO_RANGES) +// [incrementable.traits] +template struct incrementable_traits {}; + +template +requires is_object_v<_Tp> +struct incrementable_traits<_Tp*> { + using difference_type = ptrdiff_t; +}; + +template +struct incrementable_traits : incrementable_traits<_Ip> {}; + +template +concept __has_member_difference_type = requires { typename _Tp::difference_type; }; + +template<__has_member_difference_type _Tp> +struct incrementable_traits<_Tp> { + using difference_type = typename _Tp::difference_type; +}; + +template +concept __has_integral_minus = + !__has_member_difference_type<_Tp> && + requires(const _Tp& __x, const _Tp& __y) { + { __x - __y } -> integral; + }; + +template<__has_integral_minus _Tp> +struct incrementable_traits<_Tp> { + using difference_type = make_signed_t() - declval<_Tp>())>; +}; + +// TODO(cjdb): add iter_difference_t once iterator_traits is cleaned up. +#endif // !defined(_LIBCPP_HAS_NO_RANGES) + template struct _LIBCPP_TEMPLATE_VIS iterator_traits; diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/incrementable.traits/incrementable_traits.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/incrementable.traits/incrementable_traits.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.assoc.types/incrementable.traits/incrementable_traits.compile.pass.cpp @@ -0,0 +1,260 @@ +//===----------------------------------------------------------------------===// +// +// 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 incrementable_traits; + +#include + +#include + +#include "test_macros.h" + +// clang-format off +template +concept check_has_difference_type = requires { + typename std::incrementable_traits::difference_type; +}; + +template +concept check_difference_type_matches = + check_has_difference_type && + std::same_as::difference_type, Expected>; +// clang-format on + +template +[[nodiscard]] constexpr bool check_incrementable_traits() noexcept { + constexpr bool result = check_difference_type_matches; + static_assert(check_difference_type_matches == result); + return result; +} + +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert( + check_incrementable_traits()); +static_assert(check_incrementable_traits()); + +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); + +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); + +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); + +static_assert(check_incrementable_traits()); +static_assert(check_incrementable_traits()); + +struct integral_difference_type { + using difference_type = int; +}; +static_assert(check_incrementable_traits()); + +struct non_integral_difference_type { + using difference_type = void; +}; +static_assert(check_incrementable_traits()); + +struct int_subtraction { + friend int operator-(int_subtraction, int_subtraction) noexcept; +}; +static_assert(check_incrementable_traits()); +static_assert(!check_incrementable_traits()); +static_assert( + !check_incrementable_traits()); + +struct char_subtraction { + friend char operator-(char_subtraction, char_subtraction) noexcept; +}; +static_assert(check_incrementable_traits()); + +struct unsigned_int_subtraction_with_cv { + friend unsigned int + operator-(unsigned_int_subtraction_with_cv const&, + unsigned_int_subtraction_with_cv const&) noexcept; + friend unsigned int + operator-(unsigned_int_subtraction_with_cv const volatile&, + unsigned_int_subtraction_with_cv const volatile&) noexcept; +}; +static_assert( + check_incrementable_traits()); +static_assert(check_incrementable_traits< + unsigned_int_subtraction_with_cv volatile&, int>()); +static_assert(check_incrementable_traits< + unsigned_int_subtraction_with_cv const volatile&, int>()); + +struct specialised_incrementable_traits {}; +namespace std { +template <> +struct incrementable_traits { + using difference_type = int; +}; +} // namespace std +static_assert( + check_incrementable_traits()); + +static_assert(!check_has_difference_type); +static_assert(!check_has_difference_type); +static_assert(!check_has_difference_type); +static_assert(!check_has_difference_type); +static_assert(!check_has_difference_type); +static_assert(!check_has_difference_type); + +static_assert(!check_has_difference_type); +static_assert(!check_has_difference_type); +static_assert(!check_has_difference_type); +static_assert(!check_has_difference_type); +static_assert(!check_has_difference_type); +static_assert(!check_has_difference_type); +static_assert(!check_has_difference_type); +static_assert(!check_has_difference_type); + +#define TEST_POINTER_TO_MEMBER_FUNCTION(type, cv_qualifier) \ + static_assert(!check_has_difference_type); \ + static_assert( \ + !check_has_difference_type); \ + static_assert(!check_has_difference_type); \ + static_assert( \ + !check_has_difference_type); \ + static_assert(!check_has_difference_type); \ + static_assert(!check_has_difference_type < int (type::*)() \ + cv_qualifier&& noexcept >); \ + /**/ + +struct empty {}; + +#define NO_QUALIFIER +TEST_POINTER_TO_MEMBER_FUNCTION(empty, NO_QUALIFIER); +TEST_POINTER_TO_MEMBER_FUNCTION(empty, const); +TEST_POINTER_TO_MEMBER_FUNCTION(empty, volatile); +TEST_POINTER_TO_MEMBER_FUNCTION(empty, const volatile); + +struct void_subtraction { + friend void operator-(void_subtraction, void_subtraction) noexcept; +}; +static_assert(!check_has_difference_type); + +#define TEST_NOT_DIFFERENCE_TYPE(qual1, qual2) \ + struct TEST_CONCAT(test_subtraction_, __LINE__) { \ + friend int operator-(TEST_CONCAT(test_subtraction_, __LINE__) qual1, \ + TEST_CONCAT(test_subtraction_, __LINE__) qual2); \ + }; \ + static_assert(!check_has_difference_type) /**/ + +TEST_NOT_DIFFERENCE_TYPE(&, &); +TEST_NOT_DIFFERENCE_TYPE(&, const&); +TEST_NOT_DIFFERENCE_TYPE(&, volatile&); +TEST_NOT_DIFFERENCE_TYPE(&, const volatile&); +TEST_NOT_DIFFERENCE_TYPE(&, &&); +TEST_NOT_DIFFERENCE_TYPE(&, const&&); +TEST_NOT_DIFFERENCE_TYPE(&, volatile&&); +TEST_NOT_DIFFERENCE_TYPE(&, const volatile&&); + +TEST_NOT_DIFFERENCE_TYPE(const&, &); +// TEST_NOT_DIFFERENCE_TYPE(const&, const&); // == true +TEST_NOT_DIFFERENCE_TYPE(const&, volatile&); +// TEST_NOT_DIFFERENCE_TYPE(const&, const volatile&); // invalid +TEST_NOT_DIFFERENCE_TYPE(const&, &&); +TEST_NOT_DIFFERENCE_TYPE(const&, const&&); +TEST_NOT_DIFFERENCE_TYPE(const&, volatile&&); +TEST_NOT_DIFFERENCE_TYPE(const&, const volatile&&); + +TEST_NOT_DIFFERENCE_TYPE(volatile&, &); +TEST_NOT_DIFFERENCE_TYPE(volatile&, const&); +TEST_NOT_DIFFERENCE_TYPE(volatile&, volatile&); +TEST_NOT_DIFFERENCE_TYPE(volatile&, const volatile&); +TEST_NOT_DIFFERENCE_TYPE(volatile&, &&); +TEST_NOT_DIFFERENCE_TYPE(volatile&, const&&); +TEST_NOT_DIFFERENCE_TYPE(volatile&, volatile&&); +TEST_NOT_DIFFERENCE_TYPE(volatile&, const volatile&&); + +TEST_NOT_DIFFERENCE_TYPE(const volatile&, &); +// TEST_NOT_DIFFERENCE_TYPE(const volatile&, const&); // invalid +TEST_NOT_DIFFERENCE_TYPE(const volatile&, volatile&); +// TEST_NOT_DIFFERENCE_TYPE(const volatile&, const volatile&); // invalid +TEST_NOT_DIFFERENCE_TYPE(const volatile&, &&); +TEST_NOT_DIFFERENCE_TYPE(const volatile&, const&&); +TEST_NOT_DIFFERENCE_TYPE(const volatile&, volatile&&); +TEST_NOT_DIFFERENCE_TYPE(const volatile&, const volatile&&); + +TEST_NOT_DIFFERENCE_TYPE(&&, &); +TEST_NOT_DIFFERENCE_TYPE(&&, const&); +TEST_NOT_DIFFERENCE_TYPE(&&, volatile&); +TEST_NOT_DIFFERENCE_TYPE(&&, const volatile&); +TEST_NOT_DIFFERENCE_TYPE(&&, &&); +TEST_NOT_DIFFERENCE_TYPE(&&, const&&); +TEST_NOT_DIFFERENCE_TYPE(&&, volatile&&); +TEST_NOT_DIFFERENCE_TYPE(&&, const volatile&&); + +TEST_NOT_DIFFERENCE_TYPE(const&&, &); +TEST_NOT_DIFFERENCE_TYPE(const&&, const&); +TEST_NOT_DIFFERENCE_TYPE(const&&, volatile&); +TEST_NOT_DIFFERENCE_TYPE(const&&, const volatile&); +TEST_NOT_DIFFERENCE_TYPE(const&&, &&); +TEST_NOT_DIFFERENCE_TYPE(const&&, const&&); +TEST_NOT_DIFFERENCE_TYPE(const&&, volatile&&); +TEST_NOT_DIFFERENCE_TYPE(const&&, const volatile&&); + +TEST_NOT_DIFFERENCE_TYPE(volatile&&, &); +TEST_NOT_DIFFERENCE_TYPE(volatile&&, const&); +TEST_NOT_DIFFERENCE_TYPE(volatile&&, volatile&); +TEST_NOT_DIFFERENCE_TYPE(volatile&&, const volatile&); +TEST_NOT_DIFFERENCE_TYPE(volatile&&, &&); +TEST_NOT_DIFFERENCE_TYPE(volatile&&, const&&); +TEST_NOT_DIFFERENCE_TYPE(volatile&&, volatile&&); +TEST_NOT_DIFFERENCE_TYPE(volatile&&, const volatile&&); + +TEST_NOT_DIFFERENCE_TYPE(const volatile&&, &); +TEST_NOT_DIFFERENCE_TYPE(const volatile&&, const&); +TEST_NOT_DIFFERENCE_TYPE(const volatile&&, volatile&); +TEST_NOT_DIFFERENCE_TYPE(const volatile&&, const volatile&); +TEST_NOT_DIFFERENCE_TYPE(const volatile&&, &&); +TEST_NOT_DIFFERENCE_TYPE(const volatile&&, const&&); +TEST_NOT_DIFFERENCE_TYPE(const volatile&&, volatile&&); +TEST_NOT_DIFFERENCE_TYPE(const volatile&&, const volatile&&); + +TEST_NOT_DIFFERENCE_TYPE(&, NO_QUALIFIER); +// TEST_NOT_DIFFERENCE_TYPE(const&, NO_QUALIFIER); // == true +TEST_NOT_DIFFERENCE_TYPE(volatile&, NO_QUALIFIER); +// TEST_NOT_DIFFERENCE_TYPE(const volatile&, NO_QUALIFIER); // invalid +TEST_NOT_DIFFERENCE_TYPE(&&, NO_QUALIFIER); +TEST_NOT_DIFFERENCE_TYPE(const&&, NO_QUALIFIER); +TEST_NOT_DIFFERENCE_TYPE(volatile&&, NO_QUALIFIER); +TEST_NOT_DIFFERENCE_TYPE(const volatile&&, NO_QUALIFIER); + +TEST_NOT_DIFFERENCE_TYPE(NO_QUALIFIER, &); +// TEST_NOT_DIFFERENCE_TYPE(NO_QUALIFIER, const&); // == true +TEST_NOT_DIFFERENCE_TYPE(NO_QUALIFIER, volatile&); +// TEST_NOT_DIFFERENCE_TYPE(NO_QUALIFIER, const volatile&); // invalid +TEST_NOT_DIFFERENCE_TYPE(NO_QUALIFIER, &&); +TEST_NOT_DIFFERENCE_TYPE(NO_QUALIFIER, const&&); +TEST_NOT_DIFFERENCE_TYPE(NO_QUALIFIER, volatile&&); +TEST_NOT_DIFFERENCE_TYPE(NO_QUALIFIER, const volatile&&);