diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -35,6 +35,10 @@ __mutex_base __node_handle __nullptr + __ranges/begin.h + __ranges/cbegin.h + __ranges/cend.h + __ranges/end.h __ranges/enable_borrowed_range.h __split_buffer __sso_allocator @@ -149,6 +153,7 @@ random ranges ratio + ranges regex scoped_allocator semaphore diff --git a/libcxx/include/__ranges/begin.h b/libcxx/include/__ranges/begin.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__ranges/begin.h @@ -0,0 +1,104 @@ +// -*- C++ -*- +//===------------------------ __ranges/begin.h ----------------------------===// +// +// 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_BEGIN_H +#define _LIBCPP_RANGES_BEGIN_H + +#include <__config> +#include <__iterator/concepts.h> +#include <__ranges/enable_borrowed_range.h> +#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 { +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 > && + 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 + +template +using iterator_t = decltype(ranges::begin(declval<_Tp&>())); +} // namespace ranges + +// clang-format off + +#undef _LIBCPP_NOEXCEPT_RETURN + +#endif // !defined(_LIBCPP_HAS_NO_RANGES) + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP_RANGES_BEGIN_H diff --git a/libcxx/include/__ranges/cbegin.h b/libcxx/include/__ranges/cbegin.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__ranges/cbegin.h @@ -0,0 +1,66 @@ +// -*- C++ -*- +//===----------------------- __ranges/cbegin.h ----------------------------===// +// +// 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_CBEGIN_H +#define _LIBCPP_RANGES_CBEGIN_H + +#include <__config> +#include <__ranges/begin.h> +#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 { +// [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 + requires is_rvalue_reference_v<_Tp> && 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 +} // namespace ranges + +// clang-format off + +#undef _LIBCPP_NOEXCEPT_RETURN + +#endif // !defined(_LIBCPP_HAS_NO_RANGES) + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP_RANGES_CBEGIN_H diff --git a/libcxx/include/__ranges/cend.h b/libcxx/include/__ranges/cend.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__ranges/cend.h @@ -0,0 +1,66 @@ +// -*- C++ -*- +//===----------------------- __ranges/cend.h ------------------------------===// +// +// 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_CEND_H +#define _LIBCPP_RANGES_CEND_H + +#include <__config> +#include <__ranges/end.h> +#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 { +// [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 + requires is_rvalue_reference_v<_Tp> && 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_CEND_H diff --git a/libcxx/include/__ranges/end.h b/libcxx/include/__ranges/end.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__ranges/end.h @@ -0,0 +1,95 @@ +// -*- C++ -*- +//===------------------------ __ranges/end.h ------------------------------===// +// +// 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_END_H +#define _LIBCPP_RANGES_END_H + +#include <__config> +#include <__iterator/concepts.h> +#include <__ranges/begin.h> +#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 { +// [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 > && + 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 +} // namespace ranges + +// clang-format off + +#undef _LIBCPP_NOEXCEPT_RETURN + +#endif // !defined(_LIBCPP_HAS_NO_RANGES) + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP_RANGES_END_H diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -411,6 +411,9 @@ } module ranges { header "ranges" + export compare + export initializer_list + export iterator export * } module ratio { diff --git a/libcxx/include/ranges b/libcxx/include/ranges --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -17,14 +17,29 @@ #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 inline constexpr bool enable_borrowed_range = false; + + template + using iterator_t = decltype(ranges::begin(declval())); } */ #include <__config> +#include <__ranges/begin.h> +#include <__ranges/cbegin.h> +#include <__ranges/cend.h> +#include <__ranges/end.h> #include <__ranges/enable_borrowed_range.h> #include // Required by the standard. #include // Required by the standard. 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,369 @@ +//===----------------------------------------------------------------------===// +// +// 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 = 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); \ + 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::__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::__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::__member_##cpo) + +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 = 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 && \ + std::ranges::__##cpo::__unqualified_##cpo); \ + static_assert(!std::ranges::__##cpo::__member_##cpo && \ + std::ranges::__##cpo::__unqualified_##cpo); \ + static_assert(!std::ranges::__##cpo::__member_##cpo && \ + std::ranges::__##cpo::__unqualified_##cpo); \ + static_assert(!std::ranges::__##cpo::__member_##cpo && \ + std::ranges::__##cpo::__unqualified_##cpo); \ + static_assert(!std::ranges::__##cpo::__member_##cpo && \ + 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::ranges::__##cpo::__unqualified_##cpo); \ + static_assert(!std::ranges::__##cpo::__unqualified_##cpo); \ + static_assert(!std::ranges::__##cpo::__unqualified_##cpo); \ + \ + static_assert(!std::ranges::__##cpo::__member_##cpo && \ + std::ranges::__##cpo::__unqualified_##cpo); \ + static_assert(!std::ranges::__##cpo::__member_##cpo && \ + std::ranges::__##cpo::__unqualified_##cpo); \ + static_assert(!std::ranges::__##cpo::__member_##cpo && \ + std::ranges::__##cpo::__unqualified_##cpo); \ + static_assert(!std::ranges::__##cpo::__member_##cpo && \ + std::ranges::__##cpo::__unqualified_##cpo); \ + static_assert(!std::ranges::__##cpo::__member_##cpo && \ + std::ranges::__##cpo::__unqualified_##cpo); \ + static_assert(!std::ranges::__##cpo::__member_##cpo && \ + std::ranges::__##cpo::__unqualified_##cpo); \ + static_assert(!std::ranges::__##cpo::__member_##cpo && \ + std::ranges::__##cpo::__unqualified_##cpo); \ + static_assert(!std::ranges::__##cpo::__member_##cpo && \ + std::ranges::__##cpo::__unqualified_##cpo); \ + static_assert(!std::ranges::__##cpo::__member_##cpo && \ + std::ranges::__##cpo::__unqualified_##cpo); \ + static_assert(!std::ranges::__##cpo::__member_##cpo && \ + std::ranges::__##cpo::__unqualified_##cpo); \ + static_assert(!std::ranges::__##cpo::__member_##cpo && \ + std::ranges::__##cpo::__unqualified_##cpo); \ + static_assert(!std::ranges::__##cpo::__member_##cpo && \ + std::ranges::__##cpo::__unqualified_##cpo) + +#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,48 @@ +//===----------------------------------------------------------------------===// +// +// 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,92 @@ +//===----------------------------------------------------------------------===// +// +// 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,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 "../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,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 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,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 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,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 "../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,47 @@ +//===----------------------------------------------------------------------===// +// +// 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,36 @@ +//===----------------------------------------------------------------------===// +// +// 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 */