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,7 @@ __mutex_base __node_handle __nullptr + __ranges/access.h __ranges/enable_borrowed_range.h __split_buffer __sso_allocator @@ -150,6 +151,7 @@ random ranges ratio + ranges regex scoped_allocator semaphore diff --git a/libcxx/include/__ranges/access.h b/libcxx/include/__ranges/access.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__ranges/access.h @@ -0,0 +1,218 @@ +// -*- 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_ACCESS_H +#define _LIBCPP___RANGES_ACCESS_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) + +// clang-format off + +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; + }; + + 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(__t)) } -> input_or_output_iterator; + }; + + struct __fn { + template + requires is_array_v> + [[nodiscard]] 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]] constexpr auto operator()(_Tp&& __t) const + noexcept(noexcept(_VSTD::__decay_copy(__t.begin()))) + { + return __t.begin(); + } + + template + requires __unqualified_begin<_Tp> + [[nodiscard]] constexpr auto operator()(_Tp&& __t) const + noexcept(noexcept(_VSTD::__decay_copy(begin(__t)))) + { + return begin(__t); + } + + void operator()(auto&&) const = delete; + }; +} // namespace ranges::__begin + +namespace ranges { + inline namespace __cpo { + inline constexpr auto begin = __begin::__fn{}; + } // namespace __cpo + + 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 >; + }; + + 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 + [[nodiscard]] 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."); + } + } + + template + requires __member_end<_Tp> + [[nodiscard]] constexpr auto operator()(_Tp&& __t) const + noexcept(noexcept(_VSTD::__decay_copy(__t.end()))) + { + return _VSTD::forward<_Tp>(__t).end(); + } + + template + requires __unqualified_end<_Tp> + [[nodiscard]] constexpr auto operator()(_Tp&& __t) const + noexcept(noexcept(_VSTD::__decay_copy(end(__t)))) + { + return end(__t); + } + + void operator()(auto&&) const = delete; + }; +} // namespace ranges::__end + +namespace ranges::inline __cpo { + inline constexpr auto end = __end::__fn{}; +} // namespace ranges::__cpo + +namespace ranges::__cbegin { + struct __fn { + template + requires invocable + [[nodiscard]] constexpr auto operator()(_Tp& __t) const + noexcept(noexcept(ranges::begin(_VSTD::as_const(__t)))) + { + return ranges::begin(_VSTD::as_const(__t)); + } + + template + requires is_rvalue_reference_v<_Tp> && invocable + [[nodiscard]] constexpr auto operator()(_Tp&& __t) const + noexcept(noexcept(ranges::begin(static_cast<_Tp const&&>(__t)))) + { + return ranges::begin(static_cast<_Tp const&&>(__t)); + } + }; +} // namespace ranges::__cbegin + +namespace ranges::inline __cpo { + inline constexpr auto cbegin = __cbegin::__fn{}; +} // namespace ranges::__cpo + +namespace ranges::__cend { + struct __fn { + template + requires invocable + [[nodiscard]] constexpr auto operator()(_Tp& __t) const + noexcept(noexcept(ranges::end(_VSTD::as_const(__t)))) + { + return ranges::end(_VSTD::as_const(__t)); + } + + template + requires is_rvalue_reference_v<_Tp> && invocable + [[nodiscard]] constexpr auto operator()(_Tp&& __t) const + noexcept(noexcept(ranges::end(static_cast<_Tp const&&>(__t)))) + { + return ranges::end(static_cast<_Tp const&&>(__t)); + } + }; +} // namespace ranges::__cend + +namespace ranges::inline __cpo { + inline constexpr auto cend = __cend::__fn{}; +} // namespace ranges::__cpo + +// clang-format off + +#endif // !defined(_LIBCPP_HAS_NO_RANGES) + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___RANGES_ACCESS_H diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -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,26 @@ #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/access.h> #include <__ranges/enable_borrowed_range.h> #include // Required by the standard. #include // Required by the standard. diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits --- a/libcxx/include/type_traits +++ b/libcxx/include/type_traits @@ -2814,6 +2814,9 @@ inline _LIBCPP_INLINE_VISIBILITY typename decay<_Tp>::type __decay_copy(_Tp&& __t) +#if _LIBCPP_STD_VER > 17 +noexcept(is_nothrow_convertible_v<_Tp, remove_reference_t<_Tp>>) +#endif { return _VSTD::forward<_Tp>(__t); } diff --git a/libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// map + +#include + +#include +#include + +using range = std::map; +namespace stdr = std::ranges; + +static_assert(std::same_as, range::iterator>); +static_assert(std::same_as, range::const_iterator>); diff --git a/libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// multimap + +#include + +#include +#include + +using range = std::multimap; +namespace stdr = std::ranges; + +static_assert(std::same_as, range::iterator>); +static_assert(std::same_as, range::const_iterator>); diff --git a/libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// multiset + +#include + +#include +#include + +using range = std::multiset; +namespace stdr = std::ranges; + +static_assert(std::same_as, range::iterator>); +static_assert(std::same_as, range::const_iterator>); diff --git a/libcxx/test/std/containers/associative/set/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/set/range_concept_conformance.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/associative/set/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// set + +#include + +#include +#include + +using range = std::set; +namespace stdr = std::ranges; + +static_assert(std::same_as, range::iterator>); +static_assert(std::same_as, range::const_iterator>); diff --git a/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// array + +#include + +#include +#include + +using range = std::array; +namespace stdr = std::ranges; + +static_assert(std::same_as, range::iterator>); +static_assert(std::same_as, range::const_iterator>); diff --git a/libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// deque + +#include + +#include +#include + +using range = std::deque; +namespace stdr = std::ranges; + +static_assert(std::same_as, range::iterator>); +static_assert(std::same_as, range::const_iterator>); diff --git a/libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// forward_list + +#include + +#include +#include + +using range = std::forward_list; +namespace stdr = std::ranges; + +static_assert(std::same_as, range::iterator>); +static_assert(std::same_as, range::const_iterator>); diff --git a/libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// list + +#include + +#include +#include + +using range = std::list; +namespace stdr = std::ranges; + +static_assert(std::same_as, range::iterator>); +static_assert(std::same_as, range::const_iterator>); diff --git a/libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// vector + +#include + +#include +#include + +using range = std::vector; +namespace stdr = std::ranges; + +static_assert(std::same_as, range::iterator>); +static_assert(std::same_as, range::const_iterator>); diff --git a/libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// vector + +#include + +#include +#include + +using range = std::vector; +namespace stdr = std::ranges; + +static_assert(std::same_as, range::iterator>); +static_assert(std::same_as, range::const_iterator>); diff --git a/libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// unordered_map + +#include + +#include +#include + +using range = std::unordered_map; +namespace stdr = std::ranges; + +static_assert(std::same_as, range::iterator>); +static_assert(std::same_as, range::const_iterator>); diff --git a/libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// unordered_multimap + +#include + +#include +#include + +using range = std::unordered_multimap; +namespace stdr = std::ranges; + +static_assert(std::same_as, range::iterator>); +static_assert(std::same_as, range::const_iterator>); diff --git a/libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// unordered_multiset + +#include + +#include +#include + +using range = std::unordered_multiset; +namespace stdr = std::ranges; + +static_assert(std::same_as, range::iterator>); +static_assert(std::same_as, range::const_iterator>); diff --git a/libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// unordered_multiset + +#include + +#include +#include + +using range = std::unordered_set; +namespace stdr = std::ranges; + +static_assert(std::same_as, range::iterator>); +static_assert(std::same_as, range::const_iterator>); diff --git a/libcxx/test/std/containers/views/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/views/range_concept_conformance.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/views/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// span + +#include + +#include +#include + +using range = std::span; +namespace stdr = std::ranges; + +static_assert(std::same_as, range::iterator>); diff --git a/libcxx/test/std/input.output/filesystems/class.directory_iterator/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/input.output/filesystems/class.directory_iterator/range_concept_conformance.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/input.output/filesystems/class.directory_iterator/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// directory_iterator, recursive_directory_iterator + +#include "filesystem_include.h" + +#include +#include + +namespace stdr = std::ranges; + +static_assert(std::same_as, fs::directory_iterator>); +static_assert(std::same_as, fs::directory_iterator>); +static_assert(std::same_as, fs::recursive_directory_iterator>); +static_assert(std::same_as, fs::recursive_directory_iterator>); diff --git a/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// path + +#include "filesystem_include.h" + +#include +#include + +namespace stdr = std::ranges; + +static_assert(std::same_as, fs::path::iterator>); +static_assert(std::same_as, fs::path::const_iterator>); diff --git a/libcxx/test/std/ranges/range.access/range.access.begin/begin.pass.cpp b/libcxx/test/std/ranges/range.access/range.access.begin/begin.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/range.access.begin/begin.pass.cpp @@ -0,0 +1,263 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// std::ranges::begin + +#include + +#include +#include "test_macros.h" +#include "test_iterators.h" + +using RangeBeginT = decltype(std::ranges::begin)&; +using RangeCBeginT = decltype(std::ranges::cbegin)&; + +static int globalBuff[8]; + +struct Incomplete; + +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 BeginMember { + int x; + constexpr const int *begin() const { return &x; } +}; + +// Ensure that we can't call with rvalues with borrowing disabled. +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); + +constexpr bool testArray() { + int a[2]; + assert(std::ranges::begin(a) == a); + assert(std::ranges::cbegin(a) == a); + + int b[2][2]; + assert(std::ranges::begin(b) == b); + assert(std::ranges::cbegin(b) == b); + + BeginMember c[2]; + assert(std::ranges::begin(c) == c); + assert(std::ranges::cbegin(c) == c); + + return true; +} + +struct BeginMemberFunction { + int x; + constexpr const int *begin() const { return &x; } + friend constexpr int *begin(BeginMemberFunction const& bf); +}; + +struct BeginMemberReturnsInt { + int begin() const; +}; + +static_assert(!std::is_invocable_v); + +struct BeginMemberReturnsVoidPtr { + const void *begin() const; +}; + +static_assert(!std::is_invocable_v); + +struct Empty { }; +struct EmptyBeginMember { + Empty begin() const; +}; +struct EmptyPtrBeginMember { + Empty x; + constexpr const Empty *begin() const { return &x; } +}; + +static_assert(!std::is_invocable_v); + +struct PtrConvertible { + operator int*() const; +}; +struct PtrConvertibleBeginMember { + PtrConvertible begin() const; +}; + +static_assert(!std::is_invocable_v); + +struct NonConstBeginMember { + int x; + constexpr int *begin() { return &x; } +}; + +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 EnabledBorrowingBeginMember { + constexpr int *begin() const { return &globalBuff[0]; } +}; + +template<> +inline constexpr bool std::ranges::enable_borrowed_range = true; + +constexpr bool testBeginMember() { + BeginMember a; + assert(std::ranges::begin(a) == &a.x); + assert(std::ranges::cbegin(a) == &a.x); + + NonConstBeginMember b; + assert(std::ranges::begin(b) == &b.x); + + EnabledBorrowingBeginMember c; + assert(std::ranges::begin(std::move(c)) == &globalBuff[0]); + + BeginMemberFunction d; + assert(std::ranges::begin(d) == &d.x); + assert(std::ranges::cbegin(d) == &d.x); + + EmptyPtrBeginMember e; + assert(std::ranges::begin(e) == &e.x); + assert(std::ranges::cbegin(e) == &e.x); + + return true; +} + +struct BeginFunction { + int x; + friend constexpr const int *begin(BeginFunction const& bf) { return &bf.x; } +}; + +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 BeginFunctionWithDataMember { + int x; + int begin; + friend constexpr const int *begin(BeginFunctionWithDataMember const& bf) { return &bf.x; } +}; + +struct BeginFunctionWithPrivateBeginMember : private BeginMember { + int y; + friend constexpr const int *begin(BeginFunctionWithPrivateBeginMember const& bf) { return &bf.y; } +}; + +struct BeginFunctionReturnsEmptyPtr { + Empty x; + friend constexpr const Empty *begin(BeginFunctionReturnsEmptyPtr const& bf) { return &bf.x; } +}; + +struct BeginFunctionByValue { + friend constexpr int *begin(BeginFunctionByValue) { return &globalBuff[1]; } +}; + +static_assert(!std::is_invocable_v); + +struct BeginFunctionEnabledBorrowing { + friend constexpr int *begin(BeginFunctionEnabledBorrowing) { return &globalBuff[2]; } +}; + +template<> +inline constexpr bool std::ranges::enable_borrowed_range = true; + +struct BeginFunctionReturnsInt { + friend constexpr int begin(BeginFunctionReturnsInt const&); +}; + +static_assert(!std::is_invocable_v); + +struct BeginFunctionReturnsVoidPtr { + friend constexpr void *begin(BeginFunctionReturnsVoidPtr const&); +}; + +static_assert(!std::is_invocable_v); + +struct BeginFunctionReturnsEmpty { + friend constexpr Empty begin(BeginFunctionReturnsEmpty const&); +}; + +static_assert(!std::is_invocable_v); + +struct BeginFunctionReturnsPtrConvertible { + friend constexpr PtrConvertible begin(BeginFunctionReturnsPtrConvertible const&); +}; + +static_assert(!std::is_invocable_v); + +constexpr bool testBeginFunction() { + const BeginFunction a{}; + assert(std::ranges::begin(a) == &a.x); + BeginFunction aa{}; + assert(std::ranges::cbegin(aa) == &aa.x); + + BeginFunctionByValue b; + assert(std::ranges::begin(b) == &globalBuff[1]); + assert(std::ranges::cbegin(b) == &globalBuff[1]); + + BeginFunctionEnabledBorrowing c; + assert(std::ranges::begin(std::move(c)) == &globalBuff[2]); + + const BeginFunctionReturnsEmptyPtr d{}; + assert(std::ranges::begin(d) == &d.x); + BeginFunctionReturnsEmptyPtr dd{}; + assert(std::ranges::cbegin(dd) == &dd.x); + + const BeginFunctionWithDataMember e{}; + assert(std::ranges::begin(e) == &e.x); + BeginFunctionWithDataMember ee{}; + assert(std::ranges::cbegin(ee) == &ee.x); + + const BeginFunctionWithPrivateBeginMember f{}; + assert(std::ranges::begin(f) == &f.y); + BeginFunctionWithPrivateBeginMember ff{}; + assert(std::ranges::cbegin(ff) == &ff.y); + + return true; +} + +template +struct NoThrowMemberBegin { + T begin() noexcept; + T begin() const noexcept; +}; + +template +struct NoThrowADLBegin { + friend T begin(NoThrowADLBegin&) noexcept; + friend T begin(NoThrowADLBegin const&) noexcept; +}; +ASSERT_NOEXCEPT(std::ranges::begin(std::declval())); +ASSERT_NOEXCEPT(std::ranges::begin(std::declval&>())); +ASSERT_NOT_NOEXCEPT(std::ranges::begin(std::declval >&>())); +ASSERT_NOEXCEPT(std::ranges::begin(std::declval&>())); +ASSERT_NOT_NOEXCEPT(std::ranges::begin(std::declval >&>())); + + +int main(int, char**) { + testArray(); + static_assert(testArray()); + + testBeginMember(); + static_assert(testBeginMember()); + + testBeginFunction(); + static_assert(testBeginFunction()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.access/range.access.begin/incomplete.compile.verify.cpp b/libcxx/test/std/ranges/range.access/range.access.begin/incomplete.compile.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/range.access.begin/incomplete.compile.verify.cpp @@ -0,0 +1,42 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// unspecified begin; + +#include + +#include + +using begin_t = decltype(std::ranges::begin); + +// clang-format off +template +requires(!std::invocable) +void f() {} +// clang-format on + +void test() { + struct incomplete; + f(); + // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}} + // expected-error@-2 {{no matching function for call to 'f'}} + f(); + // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}} + // expected-error@-2 {{no matching function for call to 'f'}} + f(); + // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}} + // expected-error@-2 {{no matching function for call to 'f'}} + + // This is okay because calling `std::ranges::begin` on any rvalue is ill-formed. + f(); +} diff --git a/libcxx/test/std/ranges/range.access/range.access.cbegin/cbegin.compile.pass.cpp b/libcxx/test/std/ranges/range.access/range.access.cbegin/cbegin.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/range.access.cbegin/cbegin.compile.pass.cpp @@ -0,0 +1 @@ +// Tested in begin.pass.cpp. diff --git a/libcxx/test/std/ranges/range.access/range.access.cbegin/incomplete.compile.verify copy.cpp b/libcxx/test/std/ranges/range.access/range.access.cbegin/incomplete.compile.verify copy.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/range.access.cbegin/incomplete.compile.verify copy.cpp @@ -0,0 +1,42 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// unspecified begin; + +#include + +#include + +using cbegin_t = decltype(std::ranges::cbegin); + +// clang-format off +template +requires(!std::invocable) +void f() {} +// clang-format on + +void test() { + struct incomplete; + f(); + // expected-error@*:* {{"`std::ranges::cbegin` is SFINAE-unfriendly on arrays of an incomplete type."}} + // expected-error@-2 {{no matching function for call to 'f'}} + f(); + // expected-error@*:* {{"`std::ranges::cbegin` is SFINAE-unfriendly on arrays of an incomplete type."}} + // expected-error@-2 {{no matching function for call to 'f'}} + f(); + // expected-error@*:* {{"`std::ranges::cbegin` is SFINAE-unfriendly on arrays of an incomplete type."}} + // expected-error@-2 {{no matching function for call to 'f'}} + + // This is okay because calling `std::ranges::cbegin` on any rvalue is ill-formed. + f(); +} diff --git a/libcxx/test/std/ranges/range.access/range.access.cbegin/incomplete.compile.verify.cpp b/libcxx/test/std/ranges/range.access/range.access.cbegin/incomplete.compile.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/range.access.cbegin/incomplete.compile.verify.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 +// XFAIL: msvc && clang + +// ranges::cbegin; + +#include + +#include + +using cbegin_t = decltype(std::ranges::cbegin); + +// clang-format off +template +requires(!std::invocable) +void f() {} +// clang-format on + +void test() { + struct incomplete; + f(); + // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}} + // expected-error@-2 {{no matching function for call to 'f'}} + + // This is okay because calling `std::ranges::end` on any rvalue is ill-formed. + f(); +} diff --git a/libcxx/test/std/ranges/range.access/range.access.cend/cend.compile.pass.cpp b/libcxx/test/std/ranges/range.access/range.access.cend/cend.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/range.access.cend/cend.compile.pass.cpp @@ -0,0 +1 @@ +// Tested in end.pass.cpp. diff --git a/libcxx/test/std/ranges/range.access/range.access.cend/incomplete.compile.verify.cpp b/libcxx/test/std/ranges/range.access/range.access.cend/incomplete.compile.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/range.access.cend/incomplete.compile.verify.cpp @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// unspecified begin; + +#include + +#include + +using cend_t = decltype(std::ranges::cend); + +// clang-format off +template +requires(!std::invocable) +void f() {} +// clang-format on + +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."}} + // expected-error@-3 {{no matching function for call to 'f'}} + f(); + // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}} + // expected-error@-2 {{no matching function for call to 'f'}} + + // This is okay because calling `std::ranges::end` on any rvalue is ill-formed. + f(); +} diff --git a/libcxx/test/std/ranges/range.access/range.access.end/end.cpp b/libcxx/test/std/ranges/range.access/range.access.end/end.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/range.access.end/end.cpp @@ -0,0 +1,309 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// std::ranges::end + +#include + +#include +#include "test_macros.h" +#include "test_iterators.h" + +using RangeEndT = decltype(std::ranges::end)&; +using RangeCEndT = decltype(std::ranges::cend)&; + +static int globalBuff[8]; + +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 EndMember { + int x; + constexpr const int *begin() const { return nullptr; } + constexpr const int *end() const { return &x; } +}; + +// Ensure that we can't call with rvalues with borrowing disabled. +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); + +constexpr bool testArray() { + int a[2]; + assert(std::ranges::end(a) == a + 2); + assert(std::ranges::cend(a) == a + 2); + + int b[2][2]; + assert(std::ranges::end(b) == b + 2); + assert(std::ranges::cend(b) == b + 2); + + EndMember c[2]; + assert(std::ranges::end(c) == c + 2); + assert(std::ranges::cend(c) == c + 2); + + return true; +} + +struct EndMemberFunction { + int x; + constexpr const int *begin() const { return nullptr; } + constexpr const int *end() const { return &x; } + friend constexpr int *end(EndMemberFunction const&); +}; + +struct EndMemberReturnsInt { + int begin() const; + int end() const; +}; + +static_assert(!std::is_invocable_v); + +struct EndMemberReturnsVoidPtr { + const void *begin() const; + const void *end() const; +}; + +static_assert(!std::is_invocable_v); + +struct Empty { }; +struct EmptyEndMember { + Empty begin() const; + Empty end() const; +}; +struct EmptyPtrEndMember { + Empty x; + constexpr const Empty *begin() const { return nullptr; } + constexpr const Empty *end() const { return &x; } +}; + +static_assert(!std::is_invocable_v); + +struct PtrConvertible { + operator int*() const; +}; +struct PtrConvertibleEndMember { + PtrConvertible begin() const; + PtrConvertible end() const; +}; + +static_assert(!std::is_invocable_v); + +struct NoBeginMember { + constexpr const int *end(); +}; + +static_assert(!std::is_invocable_v); + +struct NonConstEndMember { + int x; + constexpr int *begin() { return nullptr; } + constexpr int *end() { return &x; } +}; + +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 EnabledBorrowingEndMember { + constexpr int *begin() const { return nullptr; } + constexpr int *end() const { return &globalBuff[0]; } +}; + +template<> +inline constexpr bool std::ranges::enable_borrowed_range = true; + +constexpr bool testEndMember() { + EndMember a; + assert(std::ranges::end(a) == &a.x); + assert(std::ranges::cend(a) == &a.x); + + NonConstEndMember b; + assert(std::ranges::end(b) == &b.x); + + EnabledBorrowingEndMember c; + assert(std::ranges::end(std::move(c)) == &globalBuff[0]); + + EndMemberFunction d; + assert(std::ranges::end(d) == &d.x); + assert(std::ranges::cend(d) == &d.x); + + EmptyPtrEndMember e; + assert(std::ranges::end(e) == &e.x); + assert(std::ranges::cend(e) == &e.x); + + return true; +} + +struct EndFunction { + int x; + friend constexpr const int *begin(EndFunction const&) { return nullptr; } + friend constexpr const int *end(EndFunction const& bf) { return &bf.x; } +}; + +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 EndFunctionWithDataMember { + int x; + int end; + friend constexpr const int *begin(EndFunctionWithDataMember const&) { return nullptr; } + friend constexpr const int *end(EndFunctionWithDataMember const& bf) { return &bf.x; } +}; + +struct EndFunctionWithPrivateEndMember : private EndMember { + int y; + friend constexpr const int *begin(EndFunctionWithPrivateEndMember const&) { return nullptr; } + friend constexpr const int *end(EndFunctionWithPrivateEndMember const& bf) { return &bf.y; } +}; + +struct EndFunctionReturnsEmptyPtr { + Empty x; + friend constexpr const Empty *begin(EndFunctionReturnsEmptyPtr const&) { return nullptr; } + friend constexpr const Empty *end(EndFunctionReturnsEmptyPtr const& bf) { return &bf.x; } +}; + +struct EndFunctionByValue { + friend constexpr int *begin(EndFunctionByValue) { return nullptr; } + friend constexpr int *end(EndFunctionByValue) { return &globalBuff[1]; } +}; + +static_assert(!std::is_invocable_v); + +struct EndFunctionEnabledBorrowing { + friend constexpr int *begin(EndFunctionEnabledBorrowing) { return nullptr; } + friend constexpr int *end(EndFunctionEnabledBorrowing) { return &globalBuff[2]; } +}; + +template<> +inline constexpr bool std::ranges::enable_borrowed_range = true; + +struct EndFunctionReturnsInt { + friend constexpr int begin(EndFunctionReturnsInt const&); + friend constexpr int end(EndFunctionReturnsInt const&); +}; + +static_assert(!std::is_invocable_v); + +struct EndFunctionReturnsVoidPtr { + friend constexpr void *begin(EndFunctionReturnsVoidPtr const&); + friend constexpr void *end(EndFunctionReturnsVoidPtr const&); +}; + +static_assert(!std::is_invocable_v); + +struct EndFunctionReturnsEmpty { + friend constexpr Empty begin(EndFunctionReturnsEmpty const&); + friend constexpr Empty end(EndFunctionReturnsEmpty const&); +}; + +static_assert(!std::is_invocable_v); + +struct EndFunctionReturnsPtrConvertible { + friend constexpr PtrConvertible begin(EndFunctionReturnsPtrConvertible const&); + friend constexpr PtrConvertible end(EndFunctionReturnsPtrConvertible const&); +}; + +static_assert(!std::is_invocable_v); + +struct NoBeginFunction { + friend constexpr const int *end(NoBeginFunction const&); +}; + +static_assert(!std::is_invocable_v); + +struct BeginMemberEndFunction { + int x; + constexpr const int *begin() const { return nullptr; } + friend constexpr const int *end(BeginMemberEndFunction const& bf) { return &bf.x; } +}; + +constexpr bool testEndFunction() { + const EndFunction a{}; + assert(std::ranges::end(a) == &a.x); + EndFunction aa{}; + assert(std::ranges::cend(aa) == &aa.x); + + EndFunctionByValue b; + assert(std::ranges::end(b) == &globalBuff[1]); + assert(std::ranges::cend(b) == &globalBuff[1]); + + EndFunctionEnabledBorrowing c; + assert(std::ranges::end(std::move(c)) == &globalBuff[2]); + + const EndFunctionReturnsEmptyPtr d{}; + assert(std::ranges::end(d) == &d.x); + EndFunctionReturnsEmptyPtr dd{}; + assert(std::ranges::cend(dd) == &dd.x); + + const EndFunctionWithDataMember e{}; + assert(std::ranges::end(e) == &e.x); + EndFunctionWithDataMember ee{}; + assert(std::ranges::cend(ee) == &ee.x); + + const EndFunctionWithPrivateEndMember f{}; + assert(std::ranges::end(f) == &f.y); + EndFunctionWithPrivateEndMember ff{}; + assert(std::ranges::cend(ff) == &ff.y); + + const BeginMemberEndFunction g{}; + assert(std::ranges::end(g) == &g.x); + BeginMemberEndFunction gg{}; + assert(std::ranges::cend(gg) == &gg.x); + + return true; +} + +template +struct NoThrowMemberEnd { + T begin() noexcept; + T begin() const noexcept; + T end() noexcept; + T end() const noexcept; +}; + +template +struct NoThrowADLEnd { + friend T begin(NoThrowADLEnd&) noexcept; + friend T begin(NoThrowADLEnd const&) noexcept; + friend T end(NoThrowADLEnd&) noexcept; + friend T end(NoThrowADLEnd const&) noexcept; +}; +ASSERT_NOEXCEPT(std::ranges::begin(std::declval())); +ASSERT_NOEXCEPT(std::ranges::begin(std::declval&>())); +ASSERT_NOT_NOEXCEPT(std::ranges::begin(std::declval >&>())); +ASSERT_NOEXCEPT(std::ranges::begin(std::declval&>())); +ASSERT_NOT_NOEXCEPT(std::ranges::begin(std::declval >&>())); + +int main(int, char**) { + testArray(); + static_assert(testArray()); + + testEndMember(); + static_assert(testEndMember()); + + testEndFunction(); + static_assert(testEndFunction()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.access/range.access.end/incomplete.compile.verify.cpp b/libcxx/test/std/ranges/range.access/range.access.end/incomplete.compile.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/range.access.end/incomplete.compile.verify.cpp @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// unspecified begin; + +#include + +#include + +using end_t = decltype(std::ranges::end); + +// clang-format off +template +requires(!std::invocable) +void f() {} +// clang-format on + +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."}} + // expected-error@-3 {{no matching function for call to 'f'}} + f(); + // expected-error@*:* {{"`std::ranges::begin` is SFINAE-unfriendly on arrays of an incomplete type."}} + // expected-error@-2 {{no matching function for call to 'f'}} + + // This is okay because calling `std::ranges::end` on any rvalue is ill-formed. + f(); +} 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,33 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// template +// using iterator_t = decltype(ranges::begin(declval())); + +#include + +#include + +#include "test_range.h" + +namespace stdr = std::ranges; + +static_assert(std::same_as >, input_iterator >); +static_assert(std::same_as const>, input_iterator >); + +static_assert(std::same_as >, input_iterator >); + +static_assert(std::same_as >, input_iterator >); +static_assert(std::same_as const>, input_iterator >); + +static_assert(std::same_as >, input_iterator >); diff --git a/libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// match_results + +#include + +#include +#include + +namespace stdr = std::ranges; + +static_assert(std::same_as, std::cmatch::iterator>); +static_assert(std::same_as, std::cmatch::const_iterator>); diff --git a/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// string + +#include + +#include +#include + +namespace stdr = std::ranges; + +static_assert(std::same_as, std::string::iterator>); +static_assert(std::same_as, std::string::const_iterator>); diff --git a/libcxx/test/std/strings/string.view/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/strings/string.view/range_concept_conformance.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/string.view/range_concept_conformance.compile.pass.cpp @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// XFAIL: msvc && clang + +// string_view + +#include + +#include +#include + +namespace stdr = std::ranges; + +static_assert(std::same_as, std::string_view::iterator>); +static_assert(std::same_as, std::string_view::const_iterator>); diff --git a/libcxx/test/support/test_range.h b/libcxx/test/support/test_range.h new file mode 100644 --- /dev/null +++ b/libcxx/test/support/test_range.h @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// +// 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_SUPPORT_TEST_RANGE_H +#define LIBCXX_TEST_SUPPORT_TEST_RANGE_H + +#include +#include + +#include "test_iterators.h" + +#ifdef _LIBCPP_HAS_NO_RANGES +#error "test/suppoort/test_range.h" can only be included in builds supporting ranges +#endif + +struct sentinel { + bool operator==(std::input_or_output_iterator auto) const; +}; + +// clang-format off +template