Index: libcxx/include/__ranges/access.h =================================================================== --- libcxx/include/__ranges/access.h +++ libcxx/include/__ranges/access.h @@ -9,14 +9,13 @@ #ifndef _LIBCPP___RANGES_ACCESS_H #define _LIBCPP___RANGES_ACCESS_H +#include <__concepts/class_or_enum.h> #include <__config> #include <__iterator/concepts.h> -#include <__iterator/readable_traits.h> #include <__ranges/enable_borrowed_range.h> -#include <__utility/as_const.h> -#include <__utility/decay_copy.h> +#include <__utility/decay_copy.h> // TODO: replace with auto(x) when all compilers support it #include <__utility/forward.h> -#include +#include <__utility/priority_tag.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -27,189 +26,195 @@ #if !defined(_LIBCPP_HAS_NO_RANGES) -// clang-format off +// [ranges.access.begin] namespace ranges { - template - concept __can_borrow = - is_lvalue_reference_v<_Tp> || enable_borrowed_range >; - - template - concept __is_complete = requires { sizeof(_Tp); }; -} // namespace ranges - -// [range.access.begin] -namespace ranges::__begin { - template - concept __member_begin = - __can_borrow<_Tp> && - requires(_Tp&& __t) { - { _VSTD::__decay_copy(__t.begin()) } -> input_or_output_iterator; - }; - +namespace __begin { 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) { + concept __basic_requirements = + is_array_v> || + requires (_Tp __t) { + requires __class_or_enum>; + { _VSTD::__decay_copy(__t.begin()) } -> input_or_output_iterator; + } || + requires (_Tp __t) { + requires __class_or_enum>; { _VSTD::__decay_copy(begin(__t)) } -> input_or_output_iterator; }; struct __fn { template - requires is_array_v> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp& __t) const noexcept { - constexpr bool __complete = __is_complete >; - if constexpr (__complete) { // used to disable cryptic diagnostic - return __t + 0; - } - else { - static_assert(__complete, "`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."); - } - } - - template - requires __member_begin<_Tp> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const - noexcept(noexcept(_VSTD::__decay_copy(__t.begin()))) - { - return __t.begin(); - } + requires is_rvalue_reference_v<_Tp&&> && (!enable_borrowed_range>) + _LIBCPP_HIDE_FROM_ABI + static constexpr void __go(_Tp&& __t, __priority_tag<3>) = delete; + + template >>* = nullptr> + _LIBCPP_HIDE_FROM_ABI + static constexpr auto __go(_Tp&& __t, __priority_tag<2>) + noexcept(noexcept(__t + 0)) + -> decltype( __t + 0) + { return __t + 0; } + + template >>* = nullptr> + _LIBCPP_HIDE_FROM_ABI + static constexpr auto __go(_Tp&& __t, __priority_tag<1>) + noexcept(noexcept(_VSTD::__decay_copy(__t.begin()))) + -> decltype( _VSTD::__decay_copy(__t.begin())) + requires input_or_output_iterator + { return _VSTD::__decay_copy(__t.begin()); } + + template >>* = nullptr> + _LIBCPP_HIDE_FROM_ABI + static constexpr auto __go(_Tp&& __t, __priority_tag<0>) + noexcept(noexcept(_VSTD::__decay_copy(begin(__t)))) + -> decltype( _VSTD::__decay_copy(begin(__t))) + requires input_or_output_iterator + { return _VSTD::__decay_copy(begin(__t)); } template - requires __unqualified_begin<_Tp> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const - noexcept(noexcept(_VSTD::__decay_copy(begin(__t)))) - { - return begin(__t); - } - - void operator()(auto&&) const = delete; + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI + constexpr decltype(auto) operator()(_Tp&& __t) const + noexcept(noexcept(__go(_VSTD::forward<_Tp>(__t), __priority_tag<3>()))) + requires __basic_requirements<_Tp&&> && + (requires { __go(_VSTD::forward<_Tp>(__t), __priority_tag<3>()); }) + { return __go(_VSTD::forward<_Tp>(__t), __priority_tag<3>()); } }; -} // namespace ranges::__begin +} -namespace ranges { - inline namespace __cpo { - inline constexpr auto begin = __begin::__fn{}; - } // namespace __cpo +inline namespace __cpo { + inline constexpr auto begin = __begin::__fn{}; +} // namespace __cpo +} // namespace ranges +namespace ranges { template using iterator_t = decltype(ranges::begin(declval<_Tp&>())); } // namespace ranges -// [range.access.end] -namespace ranges::__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 >; - }; +// [ranges.access.end] +namespace ranges { +namespace __end { 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 >; + concept __basic_requirements = + is_bounded_array_v> || + requires (_Tp __t) { + requires __class_or_enum>; + { _VSTD::__decay_copy(__t.end()) } -> sentinel_for>>; + } || + requires (_Tp __t) { + requires __class_or_enum>; + { _VSTD::__decay_copy(end(__t)) } -> sentinel_for>>; }; - class __fn { - public: - template - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp (&__t)[_Np]) const noexcept { - constexpr bool __complete = __is_complete >; - if constexpr (__complete) { // used to disable cryptic diagnostic - return __t + _Np; - } - else { - static_assert(__complete, "`std::ranges::end` is SFINAE-unfriendly on arrays of an incomplete type."); - } - } + struct __fn { + template + requires is_rvalue_reference_v<_Tp&&> && (!enable_borrowed_range>) + _LIBCPP_HIDE_FROM_ABI + static constexpr void __go(_Tp&& __t, __priority_tag<4>) = delete; template - requires __member_end<_Tp> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const - noexcept(noexcept(_VSTD::__decay_copy(__t.end()))) - { - return _VSTD::forward<_Tp>(__t).end(); - } + requires is_unbounded_array_v> + _LIBCPP_HIDE_FROM_ABI + static constexpr void __go(_Tp&& __t, __priority_tag<3>) = delete; + + template >>* = nullptr> + _LIBCPP_HIDE_FROM_ABI + static constexpr auto __go(_Tp&& __t, __priority_tag<2>) + noexcept(noexcept(__t + extent_v>)) + -> decltype( __t + extent_v>) + { return __t + extent_v>; } + + template >>* = nullptr> + _LIBCPP_HIDE_FROM_ABI + static constexpr auto __go(_Tp&& __t, __priority_tag<1>) + noexcept(noexcept(_VSTD::__decay_copy(__t.end()))) + -> decltype( _VSTD::__decay_copy(__t.end())) + requires sentinel_for>> + { return _VSTD::__decay_copy(__t.end()); } + + template >>* = nullptr> + _LIBCPP_HIDE_FROM_ABI + static constexpr auto __go(_Tp&& __t, __priority_tag<0>) + noexcept(noexcept(_VSTD::__decay_copy(end(__t)))) + -> decltype( _VSTD::__decay_copy(end(__t))) + requires sentinel_for>> + { return _VSTD::__decay_copy(end(__t)); } template - requires __unqualified_end<_Tp> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const - noexcept(noexcept(_VSTD::__decay_copy(end(__t)))) - { - return end(__t); - } - - void operator()(auto&&) const = delete; + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI + constexpr decltype(auto) operator()(_Tp&& __t) const + noexcept(noexcept(__go(_VSTD::forward<_Tp>(__t), __priority_tag<4>()))) + requires __basic_requirements<_Tp&&> && + (requires { __go(_VSTD::forward<_Tp>(__t), __priority_tag<4>()); }) + { return __go(_VSTD::forward<_Tp>(__t), __priority_tag<4>()); } }; -} // namespace ranges::__end +} -namespace ranges::inline __cpo { +inline namespace __cpo { inline constexpr auto end = __end::__fn{}; -} // namespace ranges::__cpo +} // namespace __cpo +} // namespace ranges + +// [range.access.cbegin] -namespace ranges::__cbegin { +namespace ranges { +namespace __cbegin { struct __fn { template - requires invocable - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp& __t) const - noexcept(noexcept(ranges::begin(_VSTD::as_const(__t)))) - { - return ranges::begin(_VSTD::as_const(__t)); - } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI + constexpr auto operator()(_Tp& __t) const + noexcept(noexcept(ranges::begin(static_cast(__t)))) + -> decltype( ranges::begin(static_cast(__t))) + { return ranges::begin(static_cast(__t)); } template - requires is_rvalue_reference_v<_Tp> && invocable - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const - noexcept(noexcept(ranges::begin(static_cast<_Tp const&&>(__t)))) - { - return ranges::begin(static_cast<_Tp const&&>(__t)); - } + requires is_rvalue_reference_v<_Tp&&> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI + constexpr auto operator()(_Tp&& __t) const + noexcept(noexcept(ranges::begin(static_cast(__t)))) + -> decltype( ranges::begin(static_cast(__t))) + { return ranges::begin(static_cast(__t)); } }; -} // namespace ranges::__cbegin +} -namespace ranges::inline __cpo { +inline namespace __cpo { inline constexpr auto cbegin = __cbegin::__fn{}; -} // namespace ranges::__cpo +} // namespace __cpo +} // namespace ranges + +// [range.access.cend] -namespace ranges::__cend { +namespace ranges { +namespace __cend { struct __fn { template - requires invocable - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp& __t) const - noexcept(noexcept(ranges::end(_VSTD::as_const(__t)))) - { - return ranges::end(_VSTD::as_const(__t)); - } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI + constexpr auto operator()(_Tp& __t) const + noexcept(noexcept(ranges::end(static_cast(__t)))) + -> decltype( ranges::end(static_cast(__t))) + { return ranges::end(static_cast(__t)); } template - requires is_rvalue_reference_v<_Tp> && invocable - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const - noexcept(noexcept(ranges::end(static_cast<_Tp const&&>(__t)))) - { - return ranges::end(static_cast<_Tp const&&>(__t)); - } + requires is_rvalue_reference_v<_Tp&&> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI + constexpr auto operator()(_Tp&& __t) const + noexcept(noexcept(ranges::end(static_cast(__t)))) + -> decltype( ranges::end(static_cast(__t))) + { return ranges::end(static_cast(__t)); } }; -} // namespace ranges::__cend +} -namespace ranges::inline __cpo { +inline namespace __cpo { inline constexpr auto cend = __cend::__fn{}; -} // namespace ranges::__cpo - -// clang-format off +} // namespace __cpo +} // namespace ranges #endif // !defined(_LIBCPP_HAS_NO_RANGES) Index: libcxx/include/__ranges/data.h =================================================================== --- libcxx/include/__ranges/data.h +++ libcxx/include/__ranges/data.h @@ -9,13 +9,15 @@ #ifndef _LIBCPP___RANGES_DATA_H #define _LIBCPP___RANGES_DATA_H +#include <__concepts/class_or_enum.h> #include <__config> #include <__iterator/concepts.h> -#include <__iterator/iterator_traits.h> #include <__memory/pointer_traits.h> #include <__ranges/access.h> +#include <__ranges/enable_borrowed_range.h> +#include <__utility/decay_copy.h> // TODO: replace with auto(x) when all compilers support it #include <__utility/forward.h> -#include +#include <__utility/priority_tag.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -26,54 +28,55 @@ #if !defined(_LIBCPP_HAS_NO_RANGES) -// clang-format off -namespace ranges { // [range.prim.data] -namespace __data { - template - concept __ptr_to_object = is_pointer_v<_Tp> && is_object_v>; - - template - concept __member_data = - requires(_Tp&& __t) { - { _VSTD::forward<_Tp>(__t) } -> __can_borrow; - { __t.data() } -> __ptr_to_object; - }; +namespace ranges { +namespace __data { template - concept __ranges_begin_invocable = - !__member_data<_Tp> && - requires(_Tp&& __t) { - { _VSTD::forward<_Tp>(__t) } -> __can_borrow; - { ranges::begin(_VSTD::forward<_Tp>(__t)) } -> contiguous_iterator; - }; + concept __basic_requirements = + requires (_Tp __t) { + requires __class_or_enum>; + _VSTD::__decay_copy(__t.data()); + } || + requires (_Tp __t) { { ranges::begin(__t) } -> contiguous_iterator; }; struct __fn { - template <__member_data _Tp> - requires __can_borrow<_Tp> + template + requires is_rvalue_reference_v<_Tp&&> && (!enable_borrowed_range>) + _LIBCPP_HIDE_FROM_ABI + static constexpr void __go(_Tp&& __t, __priority_tag<2>) = delete; + + template >>* = nullptr> _LIBCPP_HIDE_FROM_ABI - constexpr __ptr_to_object auto operator()(_Tp&& __t) const - noexcept(noexcept(__t.data())) { - return __t.data(); - } + static constexpr auto __go(_Tp&& __t, __priority_tag<1>) + noexcept(noexcept(_VSTD::__decay_copy(__t.data()))) + -> decltype( _VSTD::__decay_copy(__t.data())) + requires is_pointer_v().data()))> && + is_object_v().data()))>> + { return _VSTD::__decay_copy(__t.data()); } - template<__ranges_begin_invocable _Tp> - requires __can_borrow<_Tp> + template >>* = nullptr> _LIBCPP_HIDE_FROM_ABI - constexpr __ptr_to_object auto operator()(_Tp&& __t) const - noexcept(noexcept(_VSTD::to_address(ranges::begin(_VSTD::forward<_Tp>(__t))))) { - return _VSTD::to_address(ranges::begin(_VSTD::forward<_Tp>(__t))); - } + static constexpr auto __go(_Tp&& __t, __priority_tag<0>) + noexcept(noexcept(_VSTD::to_address(ranges::begin(__t)))) + -> decltype( _VSTD::to_address(ranges::begin(__t))) + { return _VSTD::to_address(ranges::begin(__t)); } + + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI + constexpr decltype(auto) operator()(_Tp&& __t) const + noexcept(noexcept(__go(_VSTD::forward<_Tp>(__t), __priority_tag<2>()))) + requires __basic_requirements<_Tp&&> && + (requires { __go(_VSTD::forward<_Tp>(__t), __priority_tag<2>()); }) + { return __go(_VSTD::forward<_Tp>(__t), __priority_tag<2>()); } }; -} // end namespace __data +} inline namespace __cpo { inline constexpr auto data = __data::__fn{}; } // namespace __cpo } // namespace ranges -// clang-format off - #endif // !defined(_LIBCPP_HAS_NO_RANGES) _LIBCPP_END_NAMESPACE_STD Index: libcxx/include/__ranges/size.h =================================================================== --- libcxx/include/__ranges/size.h +++ libcxx/include/__ranges/size.h @@ -9,13 +9,14 @@ #ifndef _LIBCPP___RANGES_SIZE_H #define _LIBCPP___RANGES_SIZE_H +#include <__concepts/class_or_enum.h> #include <__config> #include <__iterator/concepts.h> -#include <__iterator/iterator_traits.h> #include <__ranges/access.h> -#include <__utility/decay_copy.h> +#include <__utility/decay_copy.h> // TODO: replace with auto(x) when all compilers support it +#include <__utility/declval.h> #include <__utility/forward.h> -#include +#include <__utility/priority_tag.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -26,89 +27,101 @@ #if !defined(_LIBCPP_HAS_NO_RANGES) -// clang-format off +// [range.prim.size] + namespace ranges { + template inline constexpr bool disable_sized_range = false; -// [range.prim.size] namespace __size { void size(auto&) = delete; void size(const auto&) = delete; template - concept __size_enabled = !disable_sized_range>; - - template - concept __member_size = __size_enabled<_Tp> && requires(_Tp&& __t) { - { _VSTD::__decay_copy(_VSTD::forward<_Tp>(__t).size()) } -> __integer_like; - }; - - template - concept __unqualified_size = - __size_enabled<_Tp> && - !__member_size<_Tp> && - __class_or_enum> && - requires(_Tp&& __t) { - { _VSTD::__decay_copy(size(_VSTD::forward<_Tp>(__t))) } -> __integer_like; - }; - - template - concept __difference = - !__member_size<_Tp> && - !__unqualified_size<_Tp> && - __class_or_enum> && - requires(_Tp&& __t) { - { ranges::begin(__t) } -> forward_iterator; - { ranges::end(__t) } -> sized_sentinel_for()))>; - }; + concept __basic_requirements = + is_bounded_array_v> || + requires (_Tp __t) { + requires __class_or_enum>; + { _VSTD::__decay_copy(__t.size()) } -> __integer_like; + } || + requires (_Tp __t) { + requires __class_or_enum>; + { _VSTD::__decay_copy(size(__t)) } -> __integer_like; + } || + requires (_Tp __t) { ranges::end(__t) - ranges::begin(__t); }; struct __fn { - template - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr size_t operator()(_Tp (&&)[_Sz]) const noexcept { - return _Sz; - } - - template - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr size_t operator()(_Tp (&)[_Sz]) const noexcept { - return _Sz; - } - - template <__member_size _Tp> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __integer_like auto operator()(_Tp&& __t) const - noexcept(noexcept(_VSTD::forward<_Tp>(__t).size())) { - return _VSTD::forward<_Tp>(__t).size(); - } - - template <__unqualified_size _Tp> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __integer_like auto operator()(_Tp&& __t) const - noexcept(noexcept(size(_VSTD::forward<_Tp>(__t)))) { - return size(_VSTD::forward<_Tp>(__t)); - } - - template<__difference _Tp> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __integer_like auto operator()(_Tp&& __t) const - noexcept(noexcept(ranges::end(__t) - ranges::begin(__t))) { - return _VSTD::__to_unsigned_like(ranges::end(__t) - ranges::begin(__t)); - } + template + requires is_unbounded_array_v> + _LIBCPP_HIDE_FROM_ABI + static constexpr void __go(_Tp&& __t, __priority_tag<4>) = delete; + + template + requires is_bounded_array_v> + _LIBCPP_HIDE_FROM_ABI + static constexpr auto __go(_Tp&& __t, __priority_tag<3>) + noexcept(noexcept(_VSTD::__decay_copy(extent_v>))) + -> decltype( _VSTD::__decay_copy(extent_v>)) + { return _VSTD::__decay_copy(extent_v>); } + + template >>* = nullptr> + requires (!disable_sized_range>) + _LIBCPP_HIDE_FROM_ABI + static constexpr auto __go(_Tp&& __t, __priority_tag<2>) + noexcept(noexcept(_VSTD::__decay_copy(__t.size()))) + -> decltype( _VSTD::__decay_copy(__t.size())) + requires __integer_like + { return _VSTD::__decay_copy(__t.size()); } + + template >>* = nullptr> + requires __class_or_enum> && + (!disable_sized_range>) + _LIBCPP_HIDE_FROM_ABI + static constexpr auto __go(_Tp&& __t, __priority_tag<1>) + noexcept(noexcept(_VSTD::__decay_copy(size(__t)))) + -> decltype( _VSTD::__decay_copy(size(__t))) + requires __integer_like + { return _VSTD::__decay_copy(size(__t)); } + + template ()))> + _LIBCPP_HIDE_FROM_ABI + static constexpr auto __go(_Tp&& __t, __priority_tag<0>) + noexcept(noexcept(_VSTD::__to_unsigned_like(ranges::end(__t) - ranges::begin(__t)))) + -> decltype( _VSTD::__to_unsigned_like(ranges::end(__t) - ranges::begin(__t))) + requires forward_iterator<_It> && sized_sentinel_for + { return _VSTD::__to_unsigned_like(ranges::end(__t) - ranges::begin(__t)); } + + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI + constexpr decltype(auto) operator()(_Tp&& __t) const + noexcept(noexcept(__go(_VSTD::forward<_Tp>(__t), __priority_tag<4>()))) + requires __basic_requirements<_Tp&&> && + (requires { __go(_VSTD::forward<_Tp>(__t), __priority_tag<4>()); }) + { return __go(_VSTD::forward<_Tp>(__t), __priority_tag<4>()); } }; -} // end namespace __size +} inline namespace __cpo { inline constexpr auto size = __size::__fn{}; } // namespace __cpo +} // namespace ranges +// [range.prim.ssize] + +namespace ranges { namespace __ssize { struct __fn { - template - requires requires (_Tp&& __t) { ranges::size(__t); } - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr integral auto operator()(_Tp&& __t) const - noexcept(noexcept(ranges::size(__t))) { - using _Signed = make_signed_t; - if constexpr (sizeof(ptrdiff_t) > sizeof(_Signed)) + template()))>> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI + constexpr auto operator()(_Tp&& __t) const + noexcept(noexcept(ranges::size(__t))) + requires requires { ranges::size(__t); } + { + if constexpr (sizeof(ptrdiff_t) > sizeof(_Dp)) return static_cast(ranges::size(__t)); else - return static_cast<_Signed>(ranges::size(__t)); + return static_cast<_Dp>(ranges::size(__t)); } }; } @@ -118,8 +131,6 @@ } // namespace __cpo } // namespace ranges -// clang-format off - #endif // !defined(_LIBCPP_HAS_NO_RANGES) _LIBCPP_END_NAMESPACE_STD Index: libcxx/test/libcxx/ranges/range.access/begin.verify.cpp =================================================================== --- /dev/null +++ libcxx/test/libcxx/ranges/range.access/begin.verify.cpp @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// 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: libcpp-has-no-incomplete-ranges + +// std::ranges::begin +// Substitution failure should give reasonably nice diagnostics. + +#include +#include + +void f() { + // expected-error@*:* {{no matching function for call}} + // expected-note@*:* {{'is_array_v >' evaluated to false}} + // expected-note@*:* {{does not satisfy '__class_or_enum'}} + // expected-note@*:* {{does not satisfy '__class_or_enum'}} + std::ranges::begin(42); +} + +void g() { + struct S {} s; + // expected-error@*:* {{no matching function for call}} + // expected-note@*:* {{'is_array_v >' evaluated to false}} + // expected-note@*:* {{'std::__1::__decay_copy(__t.begin())' would be invalid}} + // expected-note@*:* {{'std::__1::__decay_copy(begin(__t))' would be invalid}} + std::ranges::begin(s); +} + +void h() { + // expected-error@*:* {{no matching function for call}} + // expected-note@*:* {{call to deleted function '__go'}} + std::ranges::begin(std::string()); +} Index: libcxx/test/libcxx/ranges/range.access/cbegin.verify.cpp =================================================================== --- /dev/null +++ libcxx/test/libcxx/ranges/range.access/cbegin.verify.cpp @@ -0,0 +1,21 @@ +//===----------------------------------------------------------------------===// +// +// 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: libcpp-has-no-incomplete-ranges + +// std::ranges::cbegin +// Substitution failure should give reasonably nice diagnostics. + +#include + +void f() { + // expected-error@*:* {{no matching function for call}} + std::ranges::cbegin(42); +} Index: libcxx/test/libcxx/ranges/range.access/cend.verify.cpp =================================================================== --- /dev/null +++ libcxx/test/libcxx/ranges/range.access/cend.verify.cpp @@ -0,0 +1,21 @@ +//===----------------------------------------------------------------------===// +// +// 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: libcpp-has-no-incomplete-ranges + +// std::ranges::cend +// Substitution failure should give reasonably nice diagnostics. + +#include + +void f() { + // expected-error@*:* {{no matching function for call}} + std::ranges::cend(42); +} Index: libcxx/test/libcxx/ranges/range.access/data.verify.cpp =================================================================== --- /dev/null +++ libcxx/test/libcxx/ranges/range.access/data.verify.cpp @@ -0,0 +1,31 @@ +//===----------------------------------------------------------------------===// +// +// 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: libcpp-has-no-incomplete-ranges + +// std::ranges::data +// Substitution failure should give reasonably nice diagnostics. + +#include + +void f() { + // expected-error@*:* {{no matching function for call}} + // expected-note@*:* {{does not satisfy '__class_or_enum'}} + // expected-note@*:* {{'ranges::begin(__t)' would be invalid}} + std::ranges::data(42); +} + +void g() { + struct S {} s; + // expected-error@*:* {{no matching function for call}} + // expected-note@*:* {{'std::__1::__decay_copy(__t.data())' would be invalid}} + // expected-note@*:* {{'ranges::begin(__t)' would be invalid}} + std::ranges::data(s); +} Index: libcxx/test/libcxx/ranges/range.access/end.verify.cpp =================================================================== --- /dev/null +++ libcxx/test/libcxx/ranges/range.access/end.verify.cpp @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// 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: libcpp-has-no-incomplete-ranges + +// std::ranges::end +// Substitution failure should give reasonably nice diagnostics. + +#include +#include + +void f() { + // expected-error@*:* {{no matching function for call}} + // expected-note@*:* {{'is_bounded_array_v >' evaluated to false}} + // expected-note@*:* {{does not satisfy '__class_or_enum'}} + // expected-note@*:* {{does not satisfy '__class_or_enum'}} + std::ranges::end(42); +} + +void g() { + struct S {} s; + // expected-error@*:* {{no matching function for call}} + // expected-note@*:* {{'is_bounded_array_v >' evaluated to false}} + // expected-note@*:* {{'std::__1::__decay_copy(__t.end())' would be invalid}} + // expected-note@*:* {{'std::__1::__decay_copy(end(__t))' would be invalid}} + std::ranges::end(s); +} + +void h() { + // expected-error@*:* {{no matching function for call}} + // expected-note@*:* {{call to deleted function '__go'}} + std::ranges::end(std::string()); +} Index: libcxx/test/libcxx/ranges/range.access/range.access.begin/incomplete.verify.cpp =================================================================== --- libcxx/test/libcxx/ranges/range.access/range.access.begin/incomplete.verify.cpp +++ /dev/null @@ -1,36 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-no-concepts -// UNSUPPORTED: libcpp-has-no-incomplete-ranges - -// Test the libc++ specific behavior that we provide a better diagnostic when calling -// std::ranges::begin on an array of incomplete type. - -#include - -#include - -using begin_t = decltype(std::ranges::begin); - -template void f() requires std::invocable { } -template void f() { } - -void test() { - struct incomplete; - f(); - // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}} - f(); - // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}} - f(); - // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}} - - // This is okay because calling `std::ranges::begin` on any rvalue is ill-formed. - f(); -} Index: libcxx/test/libcxx/ranges/range.access/range.access.cbegin/incomplete.verify.cpp =================================================================== --- libcxx/test/libcxx/ranges/range.access/range.access.cbegin/incomplete.verify.cpp +++ /dev/null @@ -1,32 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-no-concepts -// UNSUPPORTED: libcpp-has-no-incomplete-ranges - -// Test the libc++ specific behavior that we provide a better diagnostic when calling -// std::ranges::cbegin on an array of incomplete type. - -#include - -#include - -using cbegin_t = decltype(std::ranges::cbegin); - -template void f() requires std::invocable { } -template void f() { } - -void test() { - struct incomplete; - f(); - // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}} - - // This is okay because calling `std::ranges::end` on any rvalue is ill-formed. - f(); -} Index: libcxx/test/libcxx/ranges/range.access/range.access.cend/incomplete.verify.cpp =================================================================== --- libcxx/test/libcxx/ranges/range.access/range.access.cend/incomplete.verify.cpp +++ /dev/null @@ -1,38 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-no-concepts -// UNSUPPORTED: libcpp-has-no-incomplete-ranges - -// Test the libc++ specific behavior that we provide a better diagnostic when calling -// std::ranges::cend on an array of incomplete type. - -#include - -#include - -using cend_t = decltype(std::ranges::cend); - -template void f() requires std::invocable { } -template void f() { } - -void test() { - struct incomplete; - f(); - // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}} - // expected-error@*:* {{"`std::ranges::end` is SFINAE-unfriendly on arrays of an incomplete type."}} - f(); - // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}} - // expected-error@*:* {{"`std::ranges::end` is SFINAE-unfriendly on arrays of an incomplete type."}} - f(); - // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}} - - // This is okay because calling `std::ranges::end` on any rvalue is ill-formed. - f(); -} Index: libcxx/test/libcxx/ranges/range.access/range.access.end/incomplete.verify.cpp =================================================================== --- libcxx/test/libcxx/ranges/range.access/range.access.end/incomplete.verify.cpp +++ /dev/null @@ -1,38 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-no-concepts -// UNSUPPORTED: libcpp-has-no-incomplete-ranges - -// Test the libc++ specific behavior that we provide a better diagnostic when calling -// std::ranges::end on an array of incomplete type. - -#include - -#include - -using end_t = decltype(std::ranges::end); - -template void f() requires std::invocable { } -template void f() { } - -void test() { - struct incomplete; - f(); - // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}} - // expected-error@*:* {{"`std::ranges::end` is SFINAE-unfriendly on arrays of an incomplete type."}} - f(); - // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}} - // expected-error@*:* {{"`std::ranges::end` is SFINAE-unfriendly on arrays of an incomplete type."}} - f(); - // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}} - - // This is okay because calling `std::ranges::end` on any rvalue is ill-formed. - f(); -} Index: libcxx/test/libcxx/ranges/range.access/range.prim/data.incomplete.verify.cpp =================================================================== --- libcxx/test/libcxx/ranges/range.access/range.prim/data.incomplete.verify.cpp +++ /dev/null @@ -1,56 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-no-concepts -// UNSUPPORTED: libcpp-has-no-incomplete-ranges - -// Test the libc++ specific behavior that we provide a better diagnostic when calling -// std::ranges::data on an array of incomplete type. - -#include - -struct Incomplete; - -void f(Incomplete arr[]) { - // expected-error@*:* {{is SFINAE-unfriendly on arrays of an incomplete type.}} - // expected-error@*:* {{no matching function for call}} - std::ranges::data(arr); -} - -void f(Incomplete(&arr)[]) { - // expected-error@*:* {{is SFINAE-unfriendly on arrays of an incomplete type.}} - // expected-error@*:* {{no matching function for call}} - std::ranges::data(arr); -} - -void f(Incomplete(&&arr)[]) { - // expected-error@*:* {{is SFINAE-unfriendly on arrays of an incomplete type.}} - // expected-error@*:* {{no matching function for call}} - std::ranges::data(arr); -} - -void f2(Incomplete arr[2]) { - // expected-error@*:* {{no matching function for call}} - std::ranges::data(arr); -} - -void f(Incomplete(&arr)[2]) { - // expected-error@*:* {{no matching function for call}} - std::ranges::data(arr); -} - -void f(Incomplete(&&arr)[2]) { - // expected-error@*:* {{no matching function for call}} - std::ranges::data(arr); -} - -void f(Incomplete(&arr)[2][2]) { - // expected-error@*:* {{no matching function for call}} - std::ranges::data(arr); -} Index: libcxx/test/libcxx/ranges/range.access/size.verify.cpp =================================================================== --- /dev/null +++ libcxx/test/libcxx/ranges/range.access/size.verify.cpp @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// 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: libcpp-has-no-incomplete-ranges + +// std::ranges::size +// Substitution failure should give reasonably nice diagnostics. + +#include + +void f() { + // expected-error@*:* {{no matching function for call}} + // expected-note@*:* {{'is_bounded_array_v >' evaluated to false}} + // expected-note@*:* {{does not satisfy '__class_or_enum'}} + // expected-note@*:* {{does not satisfy '__class_or_enum'}} + // expected-note@*:* {{'ranges::end(__t) - ranges::begin(__t)' would be invalid}} + std::ranges::size(42); +} + +void g() { + struct S {} s; + // expected-error@*:* {{no matching function for call}} + // expected-note@*:* {{'is_bounded_array_v >' evaluated to false}} + // expected-note@*:* {{'std::__1::__decay_copy(__t.size())' would be invalid}} + // expected-note@*:* {{'std::__1::__decay_copy(size(__t))' would be invalid}} + // expected-note@*:* {{'ranges::end(__t) - ranges::begin(__t)' would be invalid}} + std::ranges::size(s); +} Index: libcxx/test/libcxx/ranges/range.access/ssize.verify.cpp =================================================================== --- /dev/null +++ libcxx/test/libcxx/ranges/range.access/ssize.verify.cpp @@ -0,0 +1,21 @@ +//===----------------------------------------------------------------------===// +// +// 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: libcpp-has-no-incomplete-ranges + +// std::ranges::ssize +// Substitution failure should give reasonably nice diagnostics. + +#include + +void f() { + // expected-error@*:* {{no matching function for call}} + std::ranges::ssize(42); +} Index: libcxx/test/std/ranges/range.access/begin.pass.cpp =================================================================== --- libcxx/test/std/ranges/range.access/begin.pass.cpp +++ libcxx/test/std/ranges/range.access/begin.pass.cpp @@ -11,6 +11,7 @@ // UNSUPPORTED: libcpp-has-no-incomplete-ranges // std::ranges::begin +// std::ranges::cbegin #include @@ -18,8 +19,8 @@ #include "test_macros.h" #include "test_iterators.h" -using RangeBeginT = decltype(std::ranges::begin)&; -using RangeCBeginT = decltype(std::ranges::cbegin)&; +using RangeBeginT = decltype(std::ranges::begin); +using RangeCBeginT = decltype(std::ranges::cbegin); static int globalBuff[8]; @@ -114,12 +115,18 @@ BeginMember a; assert(std::ranges::begin(a) == &a.x); assert(std::ranges::cbegin(a) == &a.x); + static_assert(!std::is_invocable_v); + static_assert(!std::is_invocable_v); NonConstBeginMember b; assert(std::ranges::begin(b) == &b.x); + static_assert(!std::is_invocable_v); EnabledBorrowingBeginMember c; + assert(std::ranges::begin(c) == &globalBuff[0]); + assert(std::ranges::cbegin(c) == &globalBuff[0]); assert(std::ranges::begin(std::move(c)) == &globalBuff[0]); + assert(std::ranges::cbegin(std::move(c)) == &globalBuff[0]); BeginMemberFunction d; assert(std::ranges::begin(d) == &d.x); @@ -198,44 +205,44 @@ constexpr bool testBeginFunction() { BeginFunction a{}; const BeginFunction aa{}; - static_assert(!std::invocable); - assert(std::ranges::begin(aa) == &aa.x); + static_assert(!std::invocable); assert(std::ranges::cbegin(a) == &a.x); + assert(std::ranges::begin(aa) == &aa.x); assert(std::ranges::cbegin(aa) == &aa.x); BeginFunctionByValue b{}; const BeginFunctionByValue bb{}; assert(std::ranges::begin(b) == &globalBuff[1]); - assert(std::ranges::begin(bb) == &globalBuff[1]); assert(std::ranges::cbegin(b) == &globalBuff[1]); + assert(std::ranges::begin(bb) == &globalBuff[1]); assert(std::ranges::cbegin(bb) == &globalBuff[1]); BeginFunctionEnabledBorrowing c{}; const BeginFunctionEnabledBorrowing cc{}; assert(std::ranges::begin(std::move(c)) == &globalBuff[2]); - static_assert(!std::invocable); + assert(std::ranges::cbegin(std::move(c)) == &globalBuff[2]); assert(std::ranges::begin(std::move(cc)) == &globalBuff[2]); assert(std::ranges::cbegin(std::move(cc)) == &globalBuff[2]); BeginFunctionReturnsEmptyPtr d{}; const BeginFunctionReturnsEmptyPtr dd{}; - static_assert(!std::invocable); - assert(std::ranges::begin(dd) == &dd.x); + static_assert(!std::invocable); assert(std::ranges::cbegin(d) == &d.x); + assert(std::ranges::begin(dd) == &dd.x); assert(std::ranges::cbegin(dd) == &dd.x); BeginFunctionWithDataMember e{}; const BeginFunctionWithDataMember ee{}; - static_assert(!std::invocable); + static_assert(!std::invocable); assert(std::ranges::begin(ee) == &ee.x); assert(std::ranges::cbegin(e) == &e.x); assert(std::ranges::cbegin(ee) == &ee.x); BeginFunctionWithPrivateBeginMember f{}; const BeginFunctionWithPrivateBeginMember ff{}; - static_assert(!std::invocable); - assert(std::ranges::begin(ff) == &ff.y); + static_assert(!std::invocable); assert(std::ranges::cbegin(f) == &f.y); + assert(std::ranges::begin(ff) == &ff.y); assert(std::ranges::cbegin(ff) == &ff.y); return true; @@ -264,6 +271,11 @@ ASSERT_NOT_NOEXCEPT(std::ranges::begin(std::declval>&>())); ASSERT_NOT_NOEXCEPT(std::ranges::cbegin(std::declval>&>())); +// Test ADL-proofing. +struct Incomplete; +template struct Holder { T t; }; +static_assert(!std::is_invocable_v*>); +static_assert(!std::is_invocable_v*>); int main(int, char**) { testArray(); Index: libcxx/test/std/ranges/range.access/data.pass.cpp =================================================================== --- libcxx/test/std/ranges/range.access/data.pass.cpp +++ libcxx/test/std/ranges/range.access/data.pass.cpp @@ -116,9 +116,10 @@ random_access_iterator begin() const; }; -static_assert(!std::is_invocable_v); -static_assert(!std::is_invocable_v); -static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); struct BeginFriendContiguousIterator { int buff[8]; @@ -135,9 +136,10 @@ struct BeginFriendRandomAccess { friend random_access_iterator begin(const BeginFriendRandomAccess iter); }; -static_assert(!std::is_invocable_v); -static_assert(!std::is_invocable_v); -static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); struct BeginMemberRvalue { int buff[8]; @@ -173,6 +175,17 @@ return true; } +// Test ADL-proofing. +struct Incomplete; +template struct Holder { T t; }; +static_assert(!std::is_invocable_v*>); + +struct RandomButNotContiguous { + random_access_iterator begin() const; + random_access_iterator end() const; +}; +static_assert(!std::is_invocable_v); + int main(int, char**) { testDataMember(); static_assert(testDataMember()); Index: libcxx/test/std/ranges/range.access/empty.pass.cpp =================================================================== --- libcxx/test/std/ranges/range.access/empty.pass.cpp +++ libcxx/test/std/ranges/range.access/empty.pass.cpp @@ -30,7 +30,6 @@ static_assert( std::is_invocable_v); static_assert( std::is_invocable_v); -#if 0 // TODO struct Incomplete; static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); @@ -41,7 +40,6 @@ static_assert(!std::ranges::empty(std::move(array_of_incomplete))); static_assert(!std::ranges::empty(std::as_const(array_of_incomplete))); static_assert(!std::ranges::empty(static_cast(array_of_incomplete))); -#endif struct InputRangeWithoutSize { cpp17_input_iterator begin() const; @@ -170,6 +168,11 @@ return true; } +// Test ADL-proofing. +struct Incomplete; +template struct Holder { T t; }; +static_assert(!std::is_invocable_v*>); + int main(int, char**) { testEmptyMember(); static_assert(testEmptyMember()); Index: libcxx/test/std/ranges/range.access/end.pass.cpp =================================================================== --- libcxx/test/std/ranges/range.access/end.pass.cpp +++ libcxx/test/std/ranges/range.access/end.pass.cpp @@ -11,6 +11,7 @@ // UNSUPPORTED: libcpp-has-no-incomplete-ranges // std::ranges::end +// std::ranges::cend #include @@ -18,8 +19,8 @@ #include "test_macros.h" #include "test_iterators.h" -using RangeEndT = decltype(std::ranges::end)&; -using RangeCEndT = decltype(std::ranges::cend)&; +using RangeEndT = decltype(std::ranges::end); +using RangeCEndT = decltype(std::ranges::cend); static int globalBuff[8]; @@ -133,9 +134,11 @@ NonConstEndMember b; assert(std::ranges::end(b) == &b.x); + static_assert(!std::is_invocable_v); EnabledBorrowingEndMember c; assert(std::ranges::end(std::move(c)) == &globalBuff[0]); + assert(std::ranges::cend(std::move(c)) == &globalBuff[0]); EndMemberFunction d; assert(std::ranges::end(d) == &d.x); @@ -240,7 +243,9 @@ constexpr bool testEndFunction() { const EndFunction a{}; assert(std::ranges::end(a) == &a.x); + assert(std::ranges::cend(a) == &a.x); EndFunction aa{}; + static_assert(!std::is_invocable_v); assert(std::ranges::cend(aa) == &aa.x); EndFunctionByValue b; @@ -249,25 +254,34 @@ EndFunctionEnabledBorrowing c; assert(std::ranges::end(std::move(c)) == &globalBuff[2]); + assert(std::ranges::cend(std::move(c)) == &globalBuff[2]); const EndFunctionReturnsEmptyPtr d{}; assert(std::ranges::end(d) == &d.x); + assert(std::ranges::cend(d) == &d.x); EndFunctionReturnsEmptyPtr dd{}; + static_assert(!std::is_invocable_v); assert(std::ranges::cend(dd) == &dd.x); const EndFunctionWithDataMember e{}; assert(std::ranges::end(e) == &e.x); + assert(std::ranges::cend(e) == &e.x); EndFunctionWithDataMember ee{}; + static_assert(!std::is_invocable_v); assert(std::ranges::cend(ee) == &ee.x); const EndFunctionWithPrivateEndMember f{}; assert(std::ranges::end(f) == &f.y); + assert(std::ranges::cend(f) == &f.y); EndFunctionWithPrivateEndMember ff{}; + static_assert(!std::is_invocable_v); assert(std::ranges::cend(ff) == &ff.y); const BeginMemberEndFunction g{}; assert(std::ranges::end(g) == &g.x); + assert(std::ranges::cend(g) == &g.x); BeginMemberEndFunction gg{}; + static_assert(!std::is_invocable_v); assert(std::ranges::cend(gg) == &gg.x); return true; @@ -298,6 +312,11 @@ ASSERT_NOT_NOEXCEPT(std::ranges::end(std::declval>&>())); ASSERT_NOT_NOEXCEPT(std::ranges::cend(std::declval>&>())); +// Test ADL-proofing. +struct Incomplete; +template struct Holder { T t; }; +static_assert(!std::is_invocable_v*>); +static_assert(!std::is_invocable_v*>); int main(int, char**) { testArray(); Index: libcxx/test/std/ranges/range.access/size.pass.cpp =================================================================== --- libcxx/test/std/ranges/range.access/size.pass.cpp +++ libcxx/test/std/ranges/range.access/size.pass.cpp @@ -124,7 +124,7 @@ bool constexpr testHasSizeFunction() { assert(std::ranges::size(SizeFunction()) == 42); ASSERT_SAME_TYPE(decltype(std::ranges::size(SizeFunction())), size_t); - assert(std::ranges::size(MoveOnlySizeFunction()) == 42); + static_assert(!std::is_invocable_v); assert(std::ranges::size(EnumSizeFunction()) == 42); assert(std::ranges::size(SizeFunctionConst()) == 42); @@ -305,6 +305,11 @@ return true; } +// Test ADL-proofing. +struct Incomplete; +template struct Holder { T t; }; +static_assert(!std::is_invocable_v*>); + int main(int, char**) { testArrayType(); static_assert(testArrayType()); Index: libcxx/test/std/ranges/range.access/ssize.pass.cpp =================================================================== --- libcxx/test/std/ranges/range.access/ssize.pass.cpp +++ libcxx/test/std/ranges/range.access/ssize.pass.cpp @@ -80,6 +80,11 @@ return true; } +// Test ADL-proofing. +struct Incomplete; +template struct Holder { T t; }; +static_assert(!std::is_invocable_v*>); + int main(int, char**) { test(); static_assert(test()); Index: libcxx/test/std/ranges/range.req/range.range/range.compile.pass.cpp =================================================================== --- libcxx/test/std/ranges/range.req/range.range/range.compile.pass.cpp +++ libcxx/test/std/ranges/range.req/range.range/range.compile.pass.cpp @@ -46,3 +46,8 @@ int* end(); }; static_assert(!std::ranges::range); + +// Test ADL-proofing. +struct Incomplete; +template struct Holder { T t; }; +static_assert(!std::ranges::range*>); Index: libcxx/test/std/ranges/range.req/range.sized/sized_range.compile.pass.cpp =================================================================== --- libcxx/test/std/ranges/range.req/range.sized/sized_range.compile.pass.cpp +++ libcxx/test/std/ranges/range.req/range.sized/sized_range.compile.pass.cpp @@ -17,13 +17,14 @@ #include "test_iterators.h" - - static_assert(std::ranges::sized_range); static_assert(std::ranges::sized_range); static_assert(!std::ranges::sized_range); static_assert(!std::ranges::sized_range); +struct Incomplete; +static_assert(!std::ranges::sized_range); + struct range_has_size { bidirectional_iterator begin(); bidirectional_iterator end();