diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -132,6 +132,8 @@ queue random ratio + ranges + __ranges/access.h regex scoped_allocator semaphore diff --git a/libcxx/include/__ranges/access.h b/libcxx/include/__ranges/access.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__ranges/access.h @@ -0,0 +1,205 @@ +// -*- C++ -*- +//===-------------------------- concepts ----------------------------------===// +// +// 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 _LIBCPP_RANGES_ACCESS_H +#define _LIBCPP_RANGES_ACCESS_H + +#include <__config> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if !defined(_LIBCPP_HAS_NO_RANGES) + +#define _LIBCPP_NOEXCEPT_RETURN(...) \ + noexcept(noexcept(__VA_ARGS__)) { return __VA_ARGS__; } + +// clang-format off +namespace ranges { +// FIXME: enable_borrowed_range is only present until D90999 is merged. +template +inline constexpr bool enable_borrowed_range = false; + +template +concept __can_borrow = + is_lvalue_reference_v<_Tp> || enable_borrowed_range >; + +template +concept __is_complete = requires { sizeof(_Tp); }; + +// [range.access.begin] +namespace __begin { +template +concept __member_begin = + __can_borrow<_Tp> && + requires(_Tp&& __t) { + { _VSTD::__decay_copy(_VSTD::forward<_Tp>(__t).begin()) } -> input_or_output_iterator; + }; + +void begin(auto&) = delete; +void begin(const auto&) = delete; + +template +concept __unqualified_begin = + !__member_begin<_Tp> && + __can_borrow<_Tp> && + __class_or_enum<_Tp> && + requires(_Tp && __t) { + { _VSTD::__decay_copy(begin(_VSTD::forward<_Tp>(__t))) } -> input_or_output_iterator; + }; + +struct __fn { + template + requires __is_complete > + [[nodiscard]] constexpr _Tp* operator()(_Tp (&__t)[_Np]) const noexcept { + return __t; + } + + template + requires __member_begin<_Tp> + [[nodiscard]] constexpr auto operator()(_Tp&& __t) const + _LIBCPP_NOEXCEPT_RETURN( + _VSTD::forward<_Tp>(__t).begin() + ) + + template + requires __unqualified_begin<_Tp> + [[nodiscard]] constexpr auto operator()(_Tp&& __t) const + _LIBCPP_NOEXCEPT_RETURN( + begin(_VSTD::forward<_Tp>(__t)) + ) + + void operator()(auto&&) = delete; +}; +} // namespace __begin + +inline namespace __cpo { +inline constexpr auto begin = __begin::__fn{}; +} // namespace __cpo + +// `iterator_t` is repeated in <__ranges/access.h> and <__ranges/concepts.h> for clarity's sake. +template +using iterator_t = decltype(ranges::begin(declval<_Tp&>())); + +// [range.access.end] +namespace __end { +template +concept __member_end = __can_borrow<_Tp>&& requires(_Tp&& __t) { + typename iterator_t<_Tp>; + { _VSTD::__decay_copy(_VSTD::forward<_Tp>(__t).end()) } -> sentinel_for >; +}; + +void end(auto&) = delete; +void end(const auto&) = delete; + +template +concept __unqualified_end = + !__member_end<_Tp> && + __can_borrow<_Tp> && + __class_or_enum<_Tp> && + requires(_Tp && __t) { + typename iterator_t<_Tp>; + { _VSTD::__decay_copy(end(_VSTD::forward<_Tp>(__t))) } -> sentinel_for >; + }; + +class __fn { +public: + template + requires __is_complete > + [[nodiscard]] constexpr auto operator()(_Tp (&__t)[_Np]) const noexcept { + return __t + _Np; + } + + template + requires __member_end<_Tp> + [[nodiscard]] constexpr auto operator()(_Tp&& __t) const + _LIBCPP_NOEXCEPT_RETURN( + _VSTD::forward<_Tp>(__t).end() + ) + + template + requires __unqualified_end<_Tp> + [[nodiscard]] constexpr auto operator()(_Tp&& __t) const + _LIBCPP_NOEXCEPT_RETURN( + end(_VSTD::forward<_Tp>(__t)) + ) + + void operator()(auto&&) = delete; +}; +} // namespace __end + +inline namespace __cpo { +inline constexpr auto end = __end::__fn{}; +} // namespace __cpo + +// [range.access.cbegin] +namespace __cbegin { +struct __fn { + template + requires invocable + [[nodiscard]] constexpr auto operator()(_Tp& __t) const + _LIBCPP_NOEXCEPT_RETURN( + ranges::begin(static_cast<_Tp const&>(__t)) + ) + + template <__rvalue_reference _Tp> + requires invocable + [[nodiscard]] constexpr auto operator()(_Tp&& __t) const + _LIBCPP_NOEXCEPT_RETURN( + ranges::begin(static_cast<_Tp const&&>(__t)) + ) +}; +} // namespace __cbegin + +inline namespace __cpo { +inline constexpr auto cbegin = __cbegin::__fn{}; +} // namespace __cpo + +// [range.access.cend] +namespace __cend { +struct __fn { + template + requires invocable + [[nodiscard]] constexpr auto operator()(_Tp& __t) const + _LIBCPP_NOEXCEPT_RETURN( + ranges::end(static_cast<_Tp const&>(__t)) + ) + + template <__rvalue_reference _Tp> + requires invocable + [[nodiscard]] constexpr auto operator()(_Tp&& __t) const + _LIBCPP_NOEXCEPT_RETURN( + ranges::end(static_cast<_Tp const&&>(__t)) + ) +}; +} // namespace __cend + +inline namespace __cpo { +inline constexpr auto cend = __cend::__fn{}; +} // namespace __cpo +} // namespace ranges + +// clang-format on + +#undef _LIBCPP_NOEXCEPT_RETURN + +#endif // !defined(_LIBCPP_HAS_NO_RANGES) + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP_RANGES_ACCESS_H diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -409,6 +409,13 @@ export initializer_list export * } + module ranges { + header "ranges" + export compare + export initializer_list + export iterator + export * + } module ratio { header "ratio" export * diff --git a/libcxx/include/ranges b/libcxx/include/ranges new file mode 100644 --- /dev/null +++ b/libcxx/include/ranges @@ -0,0 +1,37 @@ +// -*- C++ -*- +//===-------------------------- concepts ----------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// #include // see [compare.syn] +// #include // see [initializer.list.syn] +// #include // see [iterator.synopsis] +// +// namespace std::ranges { +// inline namespace unspecified { +// // [range.access], range access +// inline constexpr unspecified begin = unspecified; +// inline constexpr unspecified end = unspecified; +// inline constexpr unspecified cbegin = unspecified; +// inline constexpr unspecified cend = unspecified; +// } +// +// // [range.range], ranges +// template +// using iterator_t = decltype(ranges::begin(declval())); +// } + +#ifndef _LIBCPP_RANGES +#define _LIBCPP_RANGES + +#include // see [compare.syn] +#include // see [initializer.list.syn] +#include // see [iterator.synopsis] + +#include <__ranges/access.h> + +#endif // _LIBCPP_RANGES diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits --- a/libcxx/include/type_traits +++ b/libcxx/include/type_traits @@ -2811,9 +2811,9 @@ } template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR typename decay<_Tp>::type -__decay_copy(_Tp&& __t) +__decay_copy(_Tp&& __t) _NOEXCEPT_(noexcept(_VSTD::forward<_Tp>(__t))) { return _VSTD::forward<_Tp>(__t); } diff --git a/libcxx/test/libcxx/ranges/range.access/access.h b/libcxx/test/libcxx/ranges/range.access/access.h new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.access/access.h @@ -0,0 +1,462 @@ +//===----------------------------------------------------------------------===// +// +// 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 LIBCXX_TEST_LIBCXX_RANGES_RANGE_ACCESS_ACCESS_H +#define LIBCXX_TEST_LIBCXX_RANGES_RANGE_ACCESS_ACCESS_H + +#include +#include + +class bad_lvalue_range_unqualified { +public: + int begin(bad_lvalue_range_unqualified&); + int begin(bad_lvalue_range_unqualified const&); + int end(bad_lvalue_range_unqualified&); + int end(bad_lvalue_range_unqualified const&); +}; + +class bad_lvalue_range_preferred { +public: + int begin(); + int begin() const; + int end(); + int end() const; + + int begin(bad_lvalue_range_preferred&); + int begin(bad_lvalue_range_preferred const&); + int end(bad_lvalue_range_preferred&); + int end(bad_lvalue_range_preferred const&); +}; + +class bad_lvalue_range_private_members { +public: + friend int begin(bad_lvalue_range_private_members&); + friend int begin(bad_lvalue_range_private_members const&); + friend int end(bad_lvalue_range_private_members&); + friend int end(bad_lvalue_range_private_members const&); + +private: + std::vector::iterator begin(); + std::vector::const_iterator begin() const; + std::vector::iterator end(); + std::vector::const_iterator end() const; +}; + +class rvalue_range_members_bad_return { +public: + int begin() &&; + int begin() const&&; + int end() &&; + int end() const&&; +}; + +// An otherwise okay "range", except that it isn't borrowable, and thus can't be accessed as an +// rvalue +class rvalue_range_members_not_borrowable { +public: + std::vector::iterator begin() &&; + std::vector::const_iterator begin() const&&; + std::vector::iterator end() &&; + std::vector::const_iterator end() const&&; +}; + +class rvalue_range_unqualified_bad_return { +public: + friend int begin(rvalue_range_unqualified_bad_return&&); + friend int begin(rvalue_range_unqualified_bad_return const&&); + friend int end(rvalue_range_unqualified_bad_return&&); + friend int end(rvalue_range_unqualified_bad_return const&&); +}; + +class rvalue_range_preferred_bad_return { +public: + int begin(); + int begin() const; + int end(); + int end() const; + + friend int begin(rvalue_range_preferred_bad_return&&); + friend int begin(rvalue_range_preferred_bad_return const&&); + friend int end(rvalue_range_preferred_bad_return&&); + friend int end(rvalue_range_preferred_bad_return const&&); +}; + +class rvalue_range_private_members_bad_return { +public: + friend int begin(rvalue_range_private_members_bad_return&&); + friend int begin(rvalue_range_private_members_bad_return const&&); + friend int end(rvalue_range_private_members_bad_return&&); + friend int end(rvalue_range_private_members_bad_return const&&); + +private: + std::vector::iterator begin(); + std::vector::const_iterator begin() const; + std::vector::iterator end(); + std::vector::const_iterator end() const; +}; + +// An otherwise okay "range", except that it isn't borrowable, and thus can't be accessed as an +// rvalue +class rvalue_range_unqualified_not_borrowable { +public: + friend std::vector::iterator + begin(rvalue_range_unqualified_not_borrowable&&); + friend std::vector::const_iterator + begin(rvalue_range_unqualified_not_borrowable const&&); + friend std::vector::iterator + end(rvalue_range_unqualified_not_borrowable&&); + friend std::vector::const_iterator + end(rvalue_range_unqualified_not_borrowable const&&); +}; + +// An otherwise okay "range", except that it isn't borrowable, and thus can't be accessed as an +// rvalue +class rvalue_range_preferred_not_borrowable { +public: + std::vector::iterator begin() &&; + std::vector::const_iterator begin() const&&; + std::vector::iterator end() &&; + std::vector::const_iterator end() const&&; + + friend std::vector::iterator + begin(rvalue_range_preferred_not_borrowable&&); + friend std::vector::const_iterator + begin(rvalue_range_preferred_not_borrowable const&&); + friend std::vector::iterator + end(rvalue_range_preferred_not_borrowable&&); + friend std::vector::const_iterator + end(rvalue_range_preferred_not_borrowable const&&); +}; + +// An otherwise okay "range", except that it isn't borrowable, and thus can't be accessed as an +// rvalue +class rvalue_range_private_members_not_borrowable { +public: + friend std::vector::iterator + begin(rvalue_range_private_members_not_borrowable&&); + friend std::vector::const_iterator + begin(rvalue_range_private_members_not_borrowable const&&); + friend std::vector::iterator + end(rvalue_range_private_members_not_borrowable&&); + friend std::vector::const_iterator + end(rvalue_range_private_members_not_borrowable const&&); + +private: + std::vector::iterator begin(); + std::vector::const_iterator begin() const; + std::vector::iterator end(); + std::vector::const_iterator end() const; +}; + +#define CHECK_BAD_ACCESS(cpo) \ + template \ + [[nodiscard]] constexpr bool faulty_##cpo() { \ + static_assert(!std::ranges::__##cpo::__member_##cpo); \ + static_assert(!std::ranges::__##cpo::__member_##cpo); \ + static_assert(!std::ranges::__##cpo::__member_##cpo); \ + static_assert(!std::ranges::__##cpo::__member_##cpo); \ + \ + static_assert(!std::ranges::__##cpo::__unqualified_##cpo); \ + static_assert(!std::ranges::__##cpo::__unqualified_##cpo); \ + static_assert(!std::ranges::__##cpo::__unqualified_##cpo); \ + static_assert(!std::ranges::__##cpo::__unqualified_##cpo); \ + \ + static_assert(!std::invocable); \ + static_assert(!std::invocable); \ + static_assert(!std::invocable); \ + static_assert(!std::invocable); \ + return true; \ + } \ + \ + static_assert(faulty_##cpo()); \ + static_assert(faulty_##cpo()); \ + static_assert(faulty_##cpo()); \ + static_assert(faulty_##cpo()); \ + static_assert(faulty_##cpo()); \ + static_assert(faulty_##cpo()); \ + static_assert(faulty_##cpo()); \ + static_assert(faulty_##cpo()); \ + static_assert(faulty_##cpo()); \ + static_assert(faulty_##cpo()) + +struct sentinel { + bool operator==(std::vector::iterator) const; +}; + +struct lvalue_range_with_members { + std::vector::iterator begin() &; + std::vector::iterator begin() const&; + sentinel end() &; + sentinel end() const&; +}; + +struct lvalue_range_with_members_and_unqualified_friends + : lvalue_range_with_members { + friend std::vector::iterator + begin(lvalue_range_with_members_and_unqualified_friends& x); + friend std::vector::iterator + begin(lvalue_range_with_members_and_unqualified_friends const& x); + friend sentinel end(lvalue_range_with_members_and_unqualified_friends& x); + friend sentinel + end(lvalue_range_with_members_and_unqualified_friends const& x); +}; + +struct rvalue_range_with_members { + std::vector::iterator begin(); + std::vector::iterator begin() const; + sentinel end(); + sentinel end() const; +}; + +template <> +inline constexpr bool + std::ranges::enable_borrowed_range = true; + +struct rvalue_range_with_members_and_unqualified_friends + : rvalue_range_with_members { + friend std::vector::iterator + begin(rvalue_range_with_members_and_unqualified_friends&& x); + friend std::vector::iterator + begin(rvalue_range_with_members_and_unqualified_friends const&& x); + friend sentinel end(rvalue_range_with_members_and_unqualified_friends&& x); + friend sentinel + end(rvalue_range_with_members_and_unqualified_friends const&& x); +}; + +template <> +inline constexpr bool std::ranges::enable_borrowed_range< + rvalue_range_with_members_and_unqualified_friends> = true; + +#define CHECK_MEMBER_CPO(cpo) \ + static_assert( \ + std::ranges::__##cpo::__member_##cpo); \ + static_assert( \ + std::ranges::__##cpo::__member_##cpo); \ + static_assert(std::ranges::__##cpo::__member_##cpo< \ + lvalue_range_with_members_and_unqualified_friends&>); \ + static_assert(std::ranges::__##cpo::__member_##cpo< \ + lvalue_range_with_members_and_unqualified_friends const&>); \ + static_assert( \ + !std::ranges::__##cpo::__member_##cpo); \ + static_assert(!std::ranges::__##cpo::__member_##cpo< \ + lvalue_range_with_members const&&>); \ + static_assert(!std::ranges::__##cpo::__member_##cpo< \ + lvalue_range_with_members_and_unqualified_friends&&>); \ + static_assert(!std::ranges::__##cpo::__member_##cpo< \ + lvalue_range_with_members_and_unqualified_friends const&&>); \ + \ + static_assert( \ + std::ranges::__##cpo::__member_##cpo); \ + static_assert( \ + std::ranges::__##cpo::__member_##cpo); \ + static_assert(std::ranges::__##cpo::__member_##cpo< \ + rvalue_range_with_members_and_unqualified_friends&>); \ + static_assert(std::ranges::__##cpo::__member_##cpo< \ + rvalue_range_with_members_and_unqualified_friends const&>); \ + static_assert( \ + std::ranges::__##cpo::__member_##cpo); \ + static_assert(std::ranges::__##cpo::__member_##cpo< \ + rvalue_range_with_members const&&>); \ + static_assert(std::ranges::__##cpo::__member_##cpo< \ + rvalue_range_with_members_and_unqualified_friends&&>); \ + static_assert(std::ranges::__##cpo::__member_##cpo< \ + rvalue_range_with_members_and_unqualified_friends const&&>) + +struct unqualified_lvalue_range { + friend std::vector::iterator begin(unqualified_lvalue_range& x); + friend std::vector::iterator begin(unqualified_lvalue_range const& x); + friend sentinel end(unqualified_lvalue_range& x); + friend sentinel end(unqualified_lvalue_range const& x); +}; + +struct unqualified_lvalue_range_preferred { + int begin(); + int begin() const; + int end(); + int end() const; + + friend std::vector::iterator + begin(unqualified_lvalue_range_preferred& x); + friend std::vector::iterator + begin(unqualified_lvalue_range_preferred const& x); + friend sentinel end(unqualified_lvalue_range_preferred& x); + friend sentinel end(unqualified_lvalue_range_preferred const& x); +}; + +class unqualified_lvalue_range_private_members { +public: + friend std::vector::iterator + begin(unqualified_lvalue_range_private_members& x); + friend std::vector::iterator + begin(unqualified_lvalue_range_private_members const& x); + friend sentinel end(unqualified_lvalue_range_private_members& x); + friend sentinel end(unqualified_lvalue_range_private_members const& x); + +private: + std::vector::iterator begin() noexcept; + std::vector::iterator begin() const; + sentinel end(); + sentinel end() const; +}; + +class unqualified_rvalue_range { +public: + friend std::vector::iterator begin(unqualified_rvalue_range& x); + friend std::vector::iterator begin(unqualified_rvalue_range const& x); + friend sentinel end(unqualified_rvalue_range& x); + friend sentinel end(unqualified_rvalue_range const& x); + + friend std::vector::iterator begin(unqualified_rvalue_range&& x); + friend std::vector::iterator begin(unqualified_rvalue_range const&& x); + friend sentinel end(unqualified_rvalue_range&& x); + friend sentinel end(unqualified_rvalue_range const&& x); +}; + +template <> +inline constexpr bool + std::ranges::enable_borrowed_range = true; + +class unqualified_rvalue_range_preferred { +public: + int begin(); + int begin() const; + int end(); + int end() const; + + friend std::vector::iterator + begin(unqualified_rvalue_range_preferred& x); + friend std::vector::iterator + begin(unqualified_rvalue_range_preferred const& x); + friend sentinel end(unqualified_rvalue_range_preferred& x); + friend sentinel end(unqualified_rvalue_range_preferred const& x); + + friend std::vector::iterator + begin(unqualified_rvalue_range_preferred&& x); + friend std::vector::iterator + begin(unqualified_rvalue_range_preferred const&& x); + friend sentinel end(unqualified_rvalue_range_preferred&& x); + friend sentinel end(unqualified_rvalue_range_preferred const&& x); +}; + +template <> +inline constexpr bool + std::ranges::enable_borrowed_range = + true; + +class unqualified_rvalue_range_private_members { +public: + friend std::vector::iterator + begin(unqualified_rvalue_range_private_members& x); + friend std::vector::iterator + begin(unqualified_rvalue_range_private_members const& x); + friend sentinel end(unqualified_rvalue_range_private_members& x); + friend sentinel end(unqualified_rvalue_range_private_members const& x); + + friend std::vector::iterator + begin(unqualified_rvalue_range_private_members&& x); + friend std::vector::iterator + begin(unqualified_rvalue_range_private_members const&& x); + friend sentinel end(unqualified_rvalue_range_private_members&& x); + friend sentinel end(unqualified_rvalue_range_private_members const&& x); + +private: + std::vector::iterator begin() noexcept; + std::vector::iterator begin() const; + sentinel end() noexcept; + sentinel end() const; +}; + +template <> +inline constexpr bool std::ranges::enable_borrowed_range< + unqualified_rvalue_range_private_members> = true; + +#define CHECK_UNQUALIFIED_CPO(cpo) \ + static_assert( \ + !std::ranges::__##cpo::__member_##cpo && \ + std::ranges::__##cpo::__unqualified_##cpo); \ + static_assert(!std::ranges::__##cpo::__member_##cpo< \ + unqualified_lvalue_range const&> && \ + std::ranges::__##cpo::__unqualified_##cpo< \ + unqualified_lvalue_range const&>); \ + static_assert(!std::ranges::__##cpo::__member_##cpo< \ + unqualified_lvalue_range_preferred&> && \ + std::ranges::__##cpo::__unqualified_##cpo< \ + unqualified_lvalue_range_preferred&>); \ + static_assert(!std::ranges::__##cpo::__member_##cpo< \ + unqualified_lvalue_range_preferred const&> && \ + std::ranges::__##cpo::__unqualified_##cpo< \ + unqualified_lvalue_range_preferred const&>); \ + static_assert(!std::ranges::__##cpo::__member_##cpo< \ + unqualified_lvalue_range_private_members&> && \ + std::ranges::__##cpo::__unqualified_##cpo< \ + unqualified_lvalue_range_private_members&>); \ + static_assert(!std::ranges::__##cpo::__member_##cpo< \ + unqualified_lvalue_range_private_members const&> && \ + std::ranges::__##cpo::__unqualified_##cpo< \ + unqualified_lvalue_range_private_members const&>); \ + \ + static_assert( \ + !std::ranges::__##cpo::__unqualified_##cpo); \ + static_assert(!std::ranges::__##cpo::__unqualified_##cpo< \ + unqualified_lvalue_range const&&>); \ + static_assert(!std::ranges::__##cpo::__unqualified_##cpo< \ + unqualified_lvalue_range_preferred&&>); \ + static_assert(!std::ranges::__##cpo::__unqualified_##cpo< \ + unqualified_lvalue_range_preferred const&&>); \ + static_assert(!std::ranges::__##cpo::__unqualified_##cpo< \ + unqualified_lvalue_range_private_members&&>); \ + static_assert(!std::ranges::__##cpo::__unqualified_##cpo< \ + unqualified_lvalue_range_private_members const&&>); \ + \ + static_assert( \ + !std::ranges::__##cpo::__member_##cpo && \ + std::ranges::__##cpo::__unqualified_##cpo); \ + static_assert(!std::ranges::__##cpo::__member_##cpo< \ + unqualified_rvalue_range const&> && \ + std::ranges::__##cpo::__unqualified_##cpo< \ + unqualified_rvalue_range const&>); \ + static_assert(!std::ranges::__##cpo::__member_##cpo< \ + unqualified_rvalue_range_preferred&> && \ + std::ranges::__##cpo::__unqualified_##cpo< \ + unqualified_rvalue_range_preferred&>); \ + static_assert(!std::ranges::__##cpo::__member_##cpo< \ + unqualified_rvalue_range_preferred const&> && \ + std::ranges::__##cpo::__unqualified_##cpo< \ + unqualified_rvalue_range_preferred const&>); \ + static_assert(!std::ranges::__##cpo::__member_##cpo< \ + unqualified_rvalue_range_private_members&> && \ + std::ranges::__##cpo::__unqualified_##cpo< \ + unqualified_rvalue_range_private_members&>); \ + static_assert(!std::ranges::__##cpo::__member_##cpo< \ + unqualified_rvalue_range_private_members const&> && \ + std::ranges::__##cpo::__unqualified_##cpo< \ + unqualified_rvalue_range_private_members const&>); \ + static_assert( \ + !std::ranges::__##cpo::__member_##cpo && \ + std::ranges::__##cpo::__unqualified_##cpo); \ + static_assert(!std::ranges::__##cpo::__member_##cpo< \ + unqualified_rvalue_range const&&> && \ + std::ranges::__##cpo::__unqualified_##cpo< \ + unqualified_rvalue_range const&&>); \ + static_assert(!std::ranges::__##cpo::__member_##cpo< \ + unqualified_rvalue_range_preferred&&> && \ + std::ranges::__##cpo::__unqualified_##cpo< \ + unqualified_rvalue_range_preferred&&>); \ + static_assert(!std::ranges::__##cpo::__member_##cpo< \ + unqualified_rvalue_range_preferred const&&> && \ + std::ranges::__##cpo::__unqualified_##cpo< \ + unqualified_rvalue_range_preferred const&&>); \ + static_assert(!std::ranges::__##cpo::__member_##cpo< \ + unqualified_rvalue_range_private_members&&> && \ + std::ranges::__##cpo::__unqualified_##cpo< \ + unqualified_rvalue_range_private_members&&>); \ + static_assert(!std::ranges::__##cpo::__member_##cpo< \ + unqualified_rvalue_range_private_members const&&> && \ + std::ranges::__##cpo::__unqualified_##cpo< \ + unqualified_rvalue_range_private_members const&&>) + +#endif // LIBCXX_TEST_LIBCXX_RANGES_RANGE_ACCESS_ACCESS_H diff --git a/libcxx/test/libcxx/ranges/range.access/range.access.begin/begin.compile.pass.cpp b/libcxx/test/libcxx/ranges/range.access/range.access.begin/begin.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.access/range.access.begin/begin.compile.pass.cpp @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// unspecified begin; +#include + +#include "../access.h" + +CHECK_BAD_ACCESS(begin); +CHECK_MEMBER_CPO(begin); +CHECK_UNQUALIFIED_CPO(begin); diff --git a/libcxx/test/libcxx/ranges/range.access/range.access.end/end.compile.pass.cpp b/libcxx/test/libcxx/ranges/range.access/range.access.end/end.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.access/range.access.end/end.compile.pass.cpp @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// unspecified end; +#include + +#include "../access.h" + +CHECK_BAD_ACCESS(end); +CHECK_MEMBER_CPO(end); +CHECK_UNQUALIFIED_CPO(end); diff --git a/libcxx/test/std/ranges/range.access/array_access.h b/libcxx/test/std/ranges/range.access/array_access.h new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/array_access.h @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// 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 LIBCXX_TEST_STD_RANGES_RANGE_ACCESS_ARRAY_ACCESS_H +#define LIBCXX_TEST_STD_RANGES_RANGE_ACCESS_ARRAY_ACCESS_H + +#include + +#include + +#include "test_macros.h" + +class dummy { +public: + [[nodiscard]] constexpr int* begin() noexcept { return &second_; } + + [[nodiscard]] constexpr int end() noexcept { return first_; } + +private: + int first_ = 0; + int second_ = 54; +}; + +#define CHECK_ARRAY_ACCESS(cpo) \ + static_assert(!std::invocable); \ + static_assert(!std::invocable); \ + \ + template \ + [[nodiscard]] constexpr bool check_lvalue_array() { \ + static_assert(std::invocable); \ + static_assert( \ + std::is_nothrow_invocable_v); \ + \ + T array[size]{}; \ + return std::ranges::cpo(array) == std::cpo(array); \ + } \ + \ + int main(int, char**) { \ + CONSTEXPR_ASSERT(check_lvalue_array()); \ + CONSTEXPR_ASSERT(check_lvalue_array()); \ + CONSTEXPR_ASSERT(check_lvalue_array()); \ + return 0; \ + } + +#endif // LIBCXX_TEST_STD_RANGES_RANGE_ACCESS_ARRAY_ACCESS_H diff --git a/libcxx/test/std/ranges/range.access/member_access.h b/libcxx/test/std/ranges/range.access/member_access.h new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/member_access.h @@ -0,0 +1,119 @@ +//===----------------------------------------------------------------------===// +// +// 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 LIBCXX_TEST_STD_RANGES_RANGE_ACCESS_MEMBER_ACCESS_H +#define LIBCXX_TEST_STD_RANGES_RANGE_ACCESS_MEMBER_ACCESS_H +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" + +#define RESULT_IS_ITERATOR std::input_or_output_iterator +#define RESULT_IS_SENTINEL \ + std::sentinel_for > +#define RESULT_IS_POINTER std::is_pointer_v + +// `cpo` can be any customisation point object in [range.access]. +// `base_cpo` can't be a CPO defined in terms of another CPO (e.g. cbegin) and it must be the "base" +// of `cpo` if the parameters are different. +// E.g. CHECK_MEMBER_ACCESS(begin, begin, RESULT_IS_ITERATOR) // okay +// E.g. CHECK_MEMBER_ACCESS(cdata, data, RESULT_IS_POINTER) // okay: `cdata` is implemented in terms of `data` +// E.g. CHECK_MEMBER_ACCESS(end, cend, RESULT_IS_SENTINEL) // invalid: `end` isn't implemented in terms of `cend` +// E.g. CHECK_MEMBER_ACCESS(rbegin, begin, RESULT_IS_REVERSE_ITERATOR) // invalid: `rbegin` isn't related to `begin` +#define CHECK_MEMBER_ACCESS(cpo, base_cpo, check_result_type) \ + static_assert( \ + std::invocable&>); \ + static_assert(std::invocable&>); \ + static_assert(std::invocable const&>); \ + static_assert(std::invocable&>); \ + static_assert(std::invocable const&>); \ + static_assert(std::invocable >&>); \ + static_assert(std::invocable > const&>); \ + static_assert(std::invocable >&>); \ + static_assert(std::invocable > const&>); \ + static_assert(std::invocable&>); \ + static_assert(std::invocable const&>); \ + static_assert(std::invocable&>); \ + static_assert(std::invocable const&>); \ + static_assert(std::invocable&>); \ + static_assert(std::invocable const&>); \ + static_assert(std::invocable&>); \ + static_assert(std::invocable const&>); \ + \ + static_assert(!std::invocable&&>); \ + static_assert(!std::invocable&&>); \ + static_assert(!std::invocable >&&>); \ + static_assert(!std::invocable >&&>); \ + static_assert(!std::invocable&&>); \ + static_assert(!std::invocable&&>); \ + static_assert(!std::invocable&&>); \ + static_assert(!std::invocable&&>); \ + \ + template \ + constexpr bool member_##cpo() { \ + using result_type = std::invoke_result_t; \ + static_assert(check_result_type); \ + static_assert(noexcept(std::ranges::cpo(std::declval())) == \ + noexcept(std::declval().base_cpo())); \ + \ + if (not std::is_constant_evaluated()) { \ + auto r = R(100, typename std::remove_cvref_t::value_type()); \ + assert(std::ranges::cpo(r) == r.base_cpo()); \ + } \ + return true; \ + } \ + \ + int main(int, char**) { \ + member_##cpo >(); \ + member_##cpo const>(); \ + member_##cpo >(); \ + member_##cpo const>(); \ + member_##cpo > >(); \ + member_##cpo > const>(); \ + CONSTEXPR_ASSERT(member_##cpo > >()); \ + CONSTEXPR_ASSERT(member_##cpo > const>()); \ + return 0; \ + } + +#endif // LIBCXX_TEST_STD_RANGES_RANGE_ACCESS_MEMBER_ACCESS_H diff --git a/libcxx/test/std/ranges/range.access/range.access.begin/array_access.pass.cpp b/libcxx/test/std/ranges/range.access/range.access.begin/array_access.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/range.access.begin/array_access.pass.cpp @@ -0,0 +1,18 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// unspecified begin; +#include + +#include "../array_access.h" + +CHECK_ARRAY_ACCESS(begin); diff --git a/libcxx/test/std/ranges/range.access/range.access.begin/member_access.pass.cpp b/libcxx/test/std/ranges/range.access/range.access.begin/member_access.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/range.access.begin/member_access.pass.cpp @@ -0,0 +1,16 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// unspecified begin; +#include "../member_access.h" + +CHECK_MEMBER_ACCESS(begin, begin, RESULT_IS_ITERATOR) diff --git a/libcxx/test/std/ranges/range.access/range.access.begin/unqualified_lookup.pass.cpp b/libcxx/test/std/ranges/range.access/range.access.begin/unqualified_lookup.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/range.access.begin/unqualified_lookup.pass.cpp @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// unspecified begin; +#include + +#include "../unqualified_lookup_access.h" + +static_assert( + !noexcept(std::ranges::begin(std::declval()))); +static_assert(noexcept( + std::ranges::begin(std::declval()))); +CHECK_UNQUALIFIED_LOOKUP_ACCESS(begin, begin) diff --git a/libcxx/test/std/ranges/range.access/range.access.cbegin/array_access.pass.cpp b/libcxx/test/std/ranges/range.access/range.access.cbegin/array_access.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/range.access.cbegin/array_access.pass.cpp @@ -0,0 +1,18 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// unspecified cbegin; +#include + +#include "../array_access.h" + +CHECK_ARRAY_ACCESS(cbegin); diff --git a/libcxx/test/std/ranges/range.access/range.access.cbegin/member_access.pass.cpp b/libcxx/test/std/ranges/range.access/range.access.cbegin/member_access.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/range.access.cbegin/member_access.pass.cpp @@ -0,0 +1,16 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// unspecified cbegin; +#include "../member_access.h" + +CHECK_MEMBER_ACCESS(cbegin, begin, RESULT_IS_ITERATOR) diff --git a/libcxx/test/std/ranges/range.access/range.access.cbegin/unqualified_lookup.pass.cpp b/libcxx/test/std/ranges/range.access/range.access.cbegin/unqualified_lookup.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/range.access.cbegin/unqualified_lookup.pass.cpp @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// unspecified cbegin; +#include + +#include "../unqualified_lookup_access.h" + +static_assert( + noexcept(std::ranges::cbegin(std::declval()))); +static_assert(noexcept( + std::ranges::cbegin(std::declval()))); +CHECK_UNQUALIFIED_LOOKUP_ACCESS(cbegin, begin) diff --git a/libcxx/test/std/ranges/range.access/range.access.cend/array_access.pass.cpp b/libcxx/test/std/ranges/range.access/range.access.cend/array_access.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/range.access.cend/array_access.pass.cpp @@ -0,0 +1,18 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// unspecified cend; +#include + +#include "../array_access.h" + +CHECK_ARRAY_ACCESS(cend); diff --git a/libcxx/test/std/ranges/range.access/range.access.cend/member_access.pass.cpp b/libcxx/test/std/ranges/range.access/range.access.cend/member_access.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/range.access.cend/member_access.pass.cpp @@ -0,0 +1,16 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// unspecified cend; +#include "../member_access.h" + +CHECK_MEMBER_ACCESS(cend, end, RESULT_IS_SENTINEL) diff --git a/libcxx/test/std/ranges/range.access/range.access.cend/unqualified_lookup.pass.cpp b/libcxx/test/std/ranges/range.access/range.access.cend/unqualified_lookup.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/range.access.cend/unqualified_lookup.pass.cpp @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// unspecified cend; +#include + +#include "../unqualified_lookup_access.h" + +static_assert( + noexcept(std::ranges::cend(std::declval()))); +static_assert(noexcept( + std::ranges::cend(std::declval()))); +CHECK_UNQUALIFIED_LOOKUP_ACCESS(cend, end) diff --git a/libcxx/test/std/ranges/range.access/range.access.end/array_access.pass.cpp b/libcxx/test/std/ranges/range.access/range.access.end/array_access.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/range.access.end/array_access.pass.cpp @@ -0,0 +1,18 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// unspecified end; +#include + +#include "../array_access.h" + +CHECK_ARRAY_ACCESS(end); diff --git a/libcxx/test/std/ranges/range.access/range.access.end/member_access.pass.cpp b/libcxx/test/std/ranges/range.access/range.access.end/member_access.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/range.access.end/member_access.pass.cpp @@ -0,0 +1,16 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// unspecified end; +#include "../member_access.h" + +CHECK_MEMBER_ACCESS(end, end, RESULT_IS_SENTINEL) diff --git a/libcxx/test/std/ranges/range.access/range.access.end/unqualified_lookup.pass.cpp b/libcxx/test/std/ranges/range.access/range.access.end/unqualified_lookup.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/range.access.end/unqualified_lookup.pass.cpp @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// unspecified end; +#include + +#include "../unqualified_lookup_access.h" + +static_assert( + !noexcept(std::ranges::end(std::declval()))); +static_assert(noexcept( + std::ranges::end(std::declval()))); +CHECK_UNQUALIFIED_LOOKUP_ACCESS(end, end) diff --git a/libcxx/test/std/ranges/range.access/unqualified_lookup_access.h b/libcxx/test/std/ranges/range.access/unqualified_lookup_access.h new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/unqualified_lookup_access.h @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// 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 LIBCXX_TEST_STD_RANGES_RANGE_ACCESS_UNQUALIFIED_LOOKUP_ACCESS_H +#define LIBCXX_TEST_STD_RANGES_RANGE_ACCESS_UNQUALIFIED_LOOKUP_ACCESS_H + +#include + +#include +#include +#include + +#include "test_macros.h" + +struct unqualified_lookup_access { + std::array data; + + [[nodiscard]] constexpr friend auto begin(unqualified_lookup_access& x) { + return x.data.begin(); + } + + [[nodiscard]] constexpr friend auto + begin(unqualified_lookup_access const& x) noexcept { + return x.data.begin(); + } + + [[nodiscard]] constexpr friend auto end(unqualified_lookup_access& x) { + return x.data.end(); + } + + [[nodiscard]] constexpr friend auto + end(unqualified_lookup_access const& x) noexcept { + return x.data.end(); + } +}; + +#define CHECK_UNQUALIFIED_LOOKUP_ACCESS(cpo, base_cpo) \ + [[nodiscard]] constexpr bool check_unqualified_lookup() { \ + auto r1 = unqualified_lookup_access(); \ + assert(std::ranges::cpo(r1) == r1.data.base_cpo()); \ + assert(std::ranges::cpo(r1) == std::as_const(r1.data).base_cpo()); \ + auto r2 = unqualified_lookup_access(); \ + assert(std::ranges::cpo(r1) != std::ranges::cpo(r2)); \ + assert(std::ranges::cpo(std::as_const(r1)) != \ + std::ranges::cpo(std::as_const(r2))); \ + return true; \ + } \ + \ + int main(int, char**) { \ + CONSTEXPR_ASSERT(check_unqualified_lookup()); \ + return 0; \ + } + +#endif // #ifndef LIBCXX_TEST_STD_RANGES_RANGE_ACCESS_UNQUALIFIED_LOOKUP_ACCESS_H diff --git a/libcxx/test/std/ranges/range.range/iterator_t.compile.pass.cpp b/libcxx/test/std/ranges/range.range/iterator_t.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.range/iterator_t.compile.pass.cpp @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// using iterator_t = decltype(ranges::begin(declval())); + +#include + +#include +#include +#include +#include +#include + +namespace stdr = std::ranges; + +static_assert(std::same_as >, + std::forward_list::iterator>); +static_assert(std::same_as const>, + std::forward_list::const_iterator>); + +static_assert(std::same_as >, + std::deque::iterator>); +static_assert(std::same_as const>, + std::deque::const_iterator>); + +static_assert( + std::same_as >, std::list::iterator>); +static_assert(std::same_as const>, + std::list::const_iterator>); + +static_assert(std::same_as >, + std::vector::iterator>); +static_assert(std::same_as const>, + std::vector::const_iterator>); diff --git a/libcxx/test/support/test_macros.h b/libcxx/test/support/test_macros.h --- a/libcxx/test/support/test_macros.h +++ b/libcxx/test/support/test_macros.h @@ -289,12 +289,17 @@ #if TEST_STD_VER < 11 #define ASSERT_NOEXCEPT(...) #define ASSERT_NOT_NOEXCEPT(...) +#define CONSTEXPR_ASSERT(...) assert((__VA_ARGS__)) #else #define ASSERT_NOEXCEPT(...) \ static_assert(noexcept(__VA_ARGS__), "Operation must be noexcept") #define ASSERT_NOT_NOEXCEPT(...) \ static_assert(!noexcept(__VA_ARGS__), "Operation must NOT be noexcept") + +#define CONSTEXPR_ASSERT(...) \ + static_assert(__VA_ARGS__); \ + assert((__VA_ARGS__)) #endif /* Macros for testing libc++ specific behavior and extensions */ diff --git a/libcxx/utils/generate_header_inclusion_tests.py b/libcxx/utils/generate_header_inclusion_tests.py --- a/libcxx/utils/generate_header_inclusion_tests.py +++ b/libcxx/utils/generate_header_inclusion_tests.py @@ -42,7 +42,7 @@ "optional": ["compare"], "queue": ["compare", "initializer_list"], "random": ["initializer_list"], - # TODO "ranges": ["compare", "initializer_list", "iterator"], + "ranges": ["compare", "initializer_list", "iterator"], "regex": ["compare", "initializer_list"], "set": ["compare", "initializer_list"], "stack": ["compare", "initializer_list"],