[libcxx][ranges] adds `range` access CPOs

* `std::ranges::begin`
* `std::ranges::cbegin`
* `std::ranges::end`
* `std::ranges::cend`
* `std::ranges::iterator` (required for `end`)

Implements parts of:
    * P0896R4 The One Ranges Proposal`

Co-author: @zoecarver

Depends on D90999, D100160.

Differential Revision: https://reviews.llvm.org/D100255
This commit is contained in:
Christopher Di Bella 2021-04-11 05:08:32 +00:00
parent a3fd82c289
commit 5a3309f825
36 changed files with 1606 additions and 0 deletions

View File

@ -35,6 +35,7 @@ set(files
__mutex_base
__node_handle
__nullptr
__ranges/access.h
__ranges/enable_borrowed_range.h
__split_buffer
__sso_allocator
@ -150,6 +151,7 @@ set(files
random
ranges
ratio
ranges
regex
scoped_allocator
semaphore

View File

@ -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 <type_traits>
#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 <class _Tp>
concept __can_borrow =
is_lvalue_reference_v<_Tp> || enable_borrowed_range<remove_cvref_t<_Tp> >;
template<class _Tp>
concept __is_complete = requires { sizeof(_Tp); };
} // namespace ranges
// [range.access.begin]
namespace ranges::__begin {
template <class _Tp>
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 <class _Tp>
concept __unqualified_begin =
!__member_begin<_Tp> &&
__can_borrow<_Tp> &&
__class_or_enum<remove_cvref_t<_Tp> > &&
requires(_Tp && __t) {
{ _VSTD::__decay_copy(begin(__t)) } -> input_or_output_iterator;
};
struct __fn {
template <class _Tp>
requires is_array_v<remove_cv_t<_Tp>>
[[nodiscard]] constexpr auto operator()(_Tp& __t) const noexcept {
constexpr bool __complete = __is_complete<iter_value_t<_Tp> >;
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 <class _Tp>
requires __member_begin<_Tp>
[[nodiscard]] constexpr auto operator()(_Tp&& __t) const
noexcept(noexcept(_VSTD::__decay_copy(__t.begin())))
{
return __t.begin();
}
template <class _Tp>
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 <class _Tp>
using iterator_t = decltype(ranges::begin(declval<_Tp&>()));
} // namespace ranges
// [range.access.end]
namespace ranges::__end {
template <class _Tp>
concept __member_end =
__can_borrow<_Tp> &&
requires(_Tp&& __t) {
typename iterator_t<_Tp>;
{ _VSTD::__decay_copy(_VSTD::forward<_Tp>(__t).end()) } -> sentinel_for<iterator_t<_Tp> >;
};
void end(auto&) = delete;
void end(const auto&) = delete;
template <class _Tp>
concept __unqualified_end =
!__member_end<_Tp> &&
__can_borrow<_Tp> &&
__class_or_enum<remove_cvref_t<_Tp> > &&
requires(_Tp && __t) {
typename iterator_t<_Tp>;
{ _VSTD::__decay_copy(end(_VSTD::forward<_Tp>(__t))) } -> sentinel_for<iterator_t<_Tp> >;
};
class __fn {
public:
template <class _Tp, size_t _Np>
[[nodiscard]] constexpr auto operator()(_Tp (&__t)[_Np]) const noexcept {
constexpr bool __complete = __is_complete<remove_cv_t<_Tp> >;
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 <class _Tp>
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 <class _Tp>
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 <class _Tp>
requires invocable<decltype(ranges::begin), _Tp const&>
[[nodiscard]] constexpr auto operator()(_Tp& __t) const
noexcept(noexcept(ranges::begin(_VSTD::as_const(__t))))
{
return ranges::begin(_VSTD::as_const(__t));
}
template <class _Tp>
requires is_rvalue_reference_v<_Tp> && invocable<decltype(ranges::begin), _Tp const&&>
[[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 <class _Tp>
requires invocable<decltype(ranges::end), _Tp const&>
[[nodiscard]] constexpr auto operator()(_Tp& __t) const
noexcept(noexcept(ranges::end(_VSTD::as_const(__t))))
{
return ranges::end(_VSTD::as_const(__t));
}
template <class _Tp>
requires is_rvalue_reference_v<_Tp> && invocable<decltype(ranges::end), _Tp const&&>
[[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

View File

@ -411,6 +411,9 @@ module std [system] {
}
module ranges {
header "ranges"
export compare
export initializer_list
export iterator
export *
}
module ratio {

View File

@ -17,14 +17,26 @@
#include <iterator> // 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<class T>
inline constexpr bool enable_borrowed_range = false;
template<class T>
using iterator_t = decltype(ranges::begin(declval<T&>()));
}
*/
#include <__config>
#include <__ranges/access.h>
#include <__ranges/enable_borrowed_range.h>
#include <compare> // Required by the standard.
#include <initializer_list> // Required by the standard.

View File

@ -2814,6 +2814,9 @@ template <class _Tp>
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);
}

View File

@ -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 <map>
#include <concepts>
#include <ranges>
using range = std::map<int, int>;
namespace stdr = std::ranges;
static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

View File

@ -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 <map>
#include <concepts>
#include <ranges>
using range = std::multimap<int, int>;
namespace stdr = std::ranges;
static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

View File

@ -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 <set>
#include <concepts>
#include <ranges>
using range = std::multiset<int>;
namespace stdr = std::ranges;
static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

View File

@ -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 <set>
#include <concepts>
#include <ranges>
using range = std::set<int>;
namespace stdr = std::ranges;
static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

View File

@ -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 <array>
#include <concepts>
#include <ranges>
using range = std::array<int, 10>;
namespace stdr = std::ranges;
static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

View File

@ -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 <deque>
#include <concepts>
#include <ranges>
using range = std::deque<int>;
namespace stdr = std::ranges;
static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

View File

@ -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 <forward_list>
#include <concepts>
#include <ranges>
using range = std::forward_list<int>;
namespace stdr = std::ranges;
static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

View File

@ -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 <list>
#include <concepts>
#include <ranges>
using range = std::list<int>;
namespace stdr = std::ranges;
static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

View File

@ -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 <vector>
#include <concepts>
#include <ranges>
using range = std::vector<bool>;
namespace stdr = std::ranges;
static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

View File

@ -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 <vector>
#include <concepts>
#include <ranges>
using range = std::vector<int>;
namespace stdr = std::ranges;
static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

View File

@ -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 <unordered_map>
#include <concepts>
#include <ranges>
using range = std::unordered_map<int, int>;
namespace stdr = std::ranges;
static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

View File

@ -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 <unordered_map>
#include <concepts>
#include <ranges>
using range = std::unordered_multimap<int, int>;
namespace stdr = std::ranges;
static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

View File

@ -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 <unordered_set>
#include <concepts>
#include <ranges>
using range = std::unordered_multiset<int>;
namespace stdr = std::ranges;
static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

View File

@ -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 <unordered_set>
#include <concepts>
#include <ranges>
using range = std::unordered_set<int>;
namespace stdr = std::ranges;
static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);
static_assert(std::same_as<stdr::iterator_t<range const>, range::const_iterator>);

View File

@ -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 <span>
#include <concepts>
#include <ranges>
using range = std::span<int>;
namespace stdr = std::ranges;
static_assert(std::same_as<stdr::iterator_t<range>, range::iterator>);

View File

@ -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 <concepts>
#include <ranges>
namespace stdr = std::ranges;
static_assert(std::same_as<stdr::iterator_t<fs::directory_iterator>, fs::directory_iterator>);
static_assert(std::same_as<stdr::iterator_t<fs::directory_iterator const>, fs::directory_iterator>);
static_assert(std::same_as<stdr::iterator_t<fs::recursive_directory_iterator>, fs::recursive_directory_iterator>);
static_assert(std::same_as<stdr::iterator_t<fs::recursive_directory_iterator const>, fs::recursive_directory_iterator>);

View File

@ -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 <concepts>
#include <ranges>
namespace stdr = std::ranges;
static_assert(std::same_as<stdr::iterator_t<fs::path>, fs::path::iterator>);
static_assert(std::same_as<stdr::iterator_t<fs::path const>, fs::path::const_iterator>);

View File

@ -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 <ranges>
#include <cassert>
#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<RangeBeginT, int (&&)[10]>);
static_assert( std::is_invocable_v<RangeBeginT, int (&)[10]>);
static_assert(!std::is_invocable_v<RangeBeginT, int (&&)[]>);
static_assert( std::is_invocable_v<RangeBeginT, int (&)[]>);
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<RangeBeginT, BeginMember &>);
static_assert( std::is_invocable_v<RangeBeginT, BeginMember const&>);
static_assert(!std::is_invocable_v<RangeBeginT, BeginMember &&>);
static_assert( std::is_invocable_v<RangeCBeginT, BeginMember &>);
static_assert( std::is_invocable_v<RangeCBeginT, BeginMember const&>);
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<RangeBeginT, BeginMemberReturnsInt const&>);
struct BeginMemberReturnsVoidPtr {
const void *begin() const;
};
static_assert(!std::is_invocable_v<RangeBeginT, BeginMemberReturnsVoidPtr const&>);
struct Empty { };
struct EmptyBeginMember {
Empty begin() const;
};
struct EmptyPtrBeginMember {
Empty x;
constexpr const Empty *begin() const { return &x; }
};
static_assert(!std::is_invocable_v<RangeBeginT, EmptyBeginMember const&>);
struct PtrConvertible {
operator int*() const;
};
struct PtrConvertibleBeginMember {
PtrConvertible begin() const;
};
static_assert(!std::is_invocable_v<RangeBeginT, PtrConvertibleBeginMember const&>);
struct NonConstBeginMember {
int x;
constexpr int *begin() { return &x; }
};
static_assert( std::is_invocable_v<RangeBeginT, NonConstBeginMember &>);
static_assert(!std::is_invocable_v<RangeBeginT, NonConstBeginMember const&>);
static_assert(!std::is_invocable_v<RangeCBeginT, NonConstBeginMember &>);
static_assert(!std::is_invocable_v<RangeCBeginT, NonConstBeginMember const&>);
struct EnabledBorrowingBeginMember {
constexpr int *begin() const { return &globalBuff[0]; }
};
template<>
inline constexpr bool std::ranges::enable_borrowed_range<EnabledBorrowingBeginMember> = 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<RangeBeginT, BeginFunction const&>);
static_assert(!std::is_invocable_v<RangeBeginT, BeginFunction &&>);
static_assert(!std::is_invocable_v<RangeBeginT, BeginFunction &>);
static_assert( std::is_invocable_v<RangeCBeginT, BeginFunction const&>);
static_assert( std::is_invocable_v<RangeCBeginT, BeginFunction &>);
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<RangeCBeginT, BeginFunctionByValue>);
struct BeginFunctionEnabledBorrowing {
friend constexpr int *begin(BeginFunctionEnabledBorrowing) { return &globalBuff[2]; }
};
template<>
inline constexpr bool std::ranges::enable_borrowed_range<BeginFunctionEnabledBorrowing> = true;
struct BeginFunctionReturnsInt {
friend constexpr int begin(BeginFunctionReturnsInt const&);
};
static_assert(!std::is_invocable_v<RangeBeginT, BeginFunctionReturnsInt const&>);
struct BeginFunctionReturnsVoidPtr {
friend constexpr void *begin(BeginFunctionReturnsVoidPtr const&);
};
static_assert(!std::is_invocable_v<RangeBeginT, BeginFunctionReturnsVoidPtr const&>);
struct BeginFunctionReturnsEmpty {
friend constexpr Empty begin(BeginFunctionReturnsEmpty const&);
};
static_assert(!std::is_invocable_v<RangeBeginT, BeginFunctionReturnsEmpty const&>);
struct BeginFunctionReturnsPtrConvertible {
friend constexpr PtrConvertible begin(BeginFunctionReturnsPtrConvertible const&);
};
static_assert(!std::is_invocable_v<RangeBeginT, BeginFunctionReturnsPtrConvertible const&>);
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<class T>
struct NoThrowMemberBegin {
T begin() noexcept;
T begin() const noexcept;
};
template<class T>
struct NoThrowADLBegin {
friend T begin(NoThrowADLBegin&) noexcept;
friend T begin(NoThrowADLBegin const&) noexcept;
};
ASSERT_NOEXCEPT(std::ranges::begin(std::declval<int (&)[10]>()));
ASSERT_NOEXCEPT(std::ranges::begin(std::declval<NoThrowMemberBegin<int*>&>()));
ASSERT_NOT_NOEXCEPT(std::ranges::begin(std::declval<NoThrowMemberBegin<ThrowingIterator<int> >&>()));
ASSERT_NOEXCEPT(std::ranges::begin(std::declval<NoThrowADLBegin<int*>&>()));
ASSERT_NOT_NOEXCEPT(std::ranges::begin(std::declval<NoThrowADLBegin<ThrowingIterator<int> >&>()));
int main(int, char**) {
testArray();
static_assert(testArray());
testBeginMember();
static_assert(testBeginMember());
testBeginFunction();
static_assert(testBeginFunction());
return 0;
}

View File

@ -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 <ranges>
#include <type_traits>
using begin_t = decltype(std::ranges::begin);
// clang-format off
template <class T>
requires(!std::invocable<begin_t&, T>)
void f() {}
// clang-format on
void test() {
struct incomplete;
f<incomplete(&)[]>();
// 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<incomplete(&)[10]>();
// 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<incomplete(&)[2][2]>();
// 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<incomplete(&&)[10]>();
}

View File

@ -0,0 +1 @@
// Tested in begin.pass.cpp.

View File

@ -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 <ranges>
#include <type_traits>
using cbegin_t = decltype(std::ranges::cbegin);
// clang-format off
template <class T>
requires(!std::invocable<cbegin_t&, T>)
void f() {}
// clang-format on
void test() {
struct incomplete;
f<incomplete(&)[]>();
// 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<incomplete(&)[10]>();
// 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<incomplete(&)[2][2]>();
// 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<incomplete(&&)[10]>();
}

View File

@ -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 <ranges>
#include <type_traits>
using cbegin_t = decltype(std::ranges::cbegin);
// clang-format off
template <class T>
requires(!std::invocable<cbegin_t&, T>)
void f() {}
// clang-format on
void test() {
struct incomplete;
f<incomplete(&)[10]>();
// 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<incomplete(&&)[10]>();
}

View File

@ -0,0 +1 @@
// Tested in end.pass.cpp.

View File

@ -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 <ranges>
#include <type_traits>
using cend_t = decltype(std::ranges::cend);
// clang-format off
template <class T>
requires(!std::invocable<cend_t&, T>)
void f() {}
// clang-format on
void test() {
struct incomplete;
f<incomplete(&)[]>();
// 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<incomplete(&)[10]>();
// 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<incomplete(&)[2][2]>();
// 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<incomplete(&&)[10]>();
}

View File

@ -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 <ranges>
#include <cassert>
#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<RangeEndT, int (&&)[]>);
static_assert(!std::is_invocable_v<RangeEndT, int (&)[]>);
static_assert(!std::is_invocable_v<RangeEndT, int (&&)[10]>);
static_assert( std::is_invocable_v<RangeEndT, int (&)[10]>);
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<RangeEndT, EndMember &>);
static_assert( std::is_invocable_v<RangeEndT, EndMember const&>);
static_assert(!std::is_invocable_v<RangeEndT, EndMember &&>);
static_assert( std::is_invocable_v<RangeCEndT, EndMember &>);
static_assert( std::is_invocable_v<RangeCEndT, EndMember const&>);
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<RangeEndT, EndMemberReturnsInt const&>);
struct EndMemberReturnsVoidPtr {
const void *begin() const;
const void *end() const;
};
static_assert(!std::is_invocable_v<RangeEndT, EndMemberReturnsVoidPtr const&>);
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<RangeEndT, EmptyEndMember const&>);
struct PtrConvertible {
operator int*() const;
};
struct PtrConvertibleEndMember {
PtrConvertible begin() const;
PtrConvertible end() const;
};
static_assert(!std::is_invocable_v<RangeEndT, PtrConvertibleEndMember const&>);
struct NoBeginMember {
constexpr const int *end();
};
static_assert(!std::is_invocable_v<RangeEndT, NoBeginMember const&>);
struct NonConstEndMember {
int x;
constexpr int *begin() { return nullptr; }
constexpr int *end() { return &x; }
};
static_assert( std::is_invocable_v<RangeEndT, NonConstEndMember &>);
static_assert(!std::is_invocable_v<RangeEndT, NonConstEndMember const&>);
static_assert(!std::is_invocable_v<RangeCEndT, NonConstEndMember &>);
static_assert(!std::is_invocable_v<RangeCEndT, NonConstEndMember const&>);
struct EnabledBorrowingEndMember {
constexpr int *begin() const { return nullptr; }
constexpr int *end() const { return &globalBuff[0]; }
};
template<>
inline constexpr bool std::ranges::enable_borrowed_range<EnabledBorrowingEndMember> = 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<RangeEndT, EndFunction const&>);
static_assert(!std::is_invocable_v<RangeEndT, EndFunction &&>);
static_assert( std::is_invocable_v<RangeEndT, EndFunction const&>);
static_assert(!std::is_invocable_v<RangeEndT, EndFunction &&>);
static_assert(!std::is_invocable_v<RangeEndT, EndFunction &>);
static_assert( std::is_invocable_v<RangeCEndT, EndFunction const&>);
static_assert( std::is_invocable_v<RangeCEndT, EndFunction &>);
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<RangeCEndT, EndFunctionByValue>);
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<EndFunctionEnabledBorrowing> = true;
struct EndFunctionReturnsInt {
friend constexpr int begin(EndFunctionReturnsInt const&);
friend constexpr int end(EndFunctionReturnsInt const&);
};
static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsInt const&>);
struct EndFunctionReturnsVoidPtr {
friend constexpr void *begin(EndFunctionReturnsVoidPtr const&);
friend constexpr void *end(EndFunctionReturnsVoidPtr const&);
};
static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsVoidPtr const&>);
struct EndFunctionReturnsEmpty {
friend constexpr Empty begin(EndFunctionReturnsEmpty const&);
friend constexpr Empty end(EndFunctionReturnsEmpty const&);
};
static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsEmpty const&>);
struct EndFunctionReturnsPtrConvertible {
friend constexpr PtrConvertible begin(EndFunctionReturnsPtrConvertible const&);
friend constexpr PtrConvertible end(EndFunctionReturnsPtrConvertible const&);
};
static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsPtrConvertible const&>);
struct NoBeginFunction {
friend constexpr const int *end(NoBeginFunction const&);
};
static_assert(!std::is_invocable_v<RangeEndT, NoBeginFunction const&>);
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<class T>
struct NoThrowMemberEnd {
T begin() noexcept;
T begin() const noexcept;
T end() noexcept;
T end() const noexcept;
};
template<class T>
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<int (&)[10]>()));
ASSERT_NOEXCEPT(std::ranges::begin(std::declval<NoThrowMemberEnd<int*>&>()));
ASSERT_NOT_NOEXCEPT(std::ranges::begin(std::declval<NoThrowMemberEnd<ThrowingIterator<int> >&>()));
ASSERT_NOEXCEPT(std::ranges::begin(std::declval<NoThrowADLEnd<int*>&>()));
ASSERT_NOT_NOEXCEPT(std::ranges::begin(std::declval<NoThrowADLEnd<ThrowingIterator<int> >&>()));
int main(int, char**) {
testArray();
static_assert(testArray());
testEndMember();
static_assert(testEndMember());
testEndFunction();
static_assert(testEndFunction());
return 0;
}

View File

@ -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 <ranges>
#include <type_traits>
using end_t = decltype(std::ranges::end);
// clang-format off
template <class T>
requires(!std::invocable<end_t&, T>)
void f() {}
// clang-format on
void test() {
struct incomplete;
f<incomplete(&)[]>();
// 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<incomplete(&)[10]>();
// 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<incomplete(&)[2][2]>();
// 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<incomplete(&&)[10]>();
}

View File

@ -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<class T>
// using iterator_t = decltype(ranges::begin(declval<T&>()));
#include <ranges>
#include <concepts>
#include "test_range.h"
namespace stdr = std::ranges;
static_assert(std::same_as<stdr::iterator_t<test_range<input_iterator> >, input_iterator<int*> >);
static_assert(std::same_as<stdr::iterator_t<test_range<input_iterator> const>, input_iterator<int const*> >);
static_assert(std::same_as<stdr::iterator_t<test_non_const_range<input_iterator> >, input_iterator<int*> >);
static_assert(std::same_as<stdr::iterator_t<test_common_range<input_iterator> >, input_iterator<int*> >);
static_assert(std::same_as<stdr::iterator_t<test_common_range<input_iterator> const>, input_iterator<int const*> >);
static_assert(std::same_as<stdr::iterator_t<test_non_const_common_range<input_iterator> >, input_iterator<int*> >);

View File

@ -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 <regex>
#include <concepts>
#include <ranges>
namespace stdr = std::ranges;
static_assert(std::same_as<stdr::iterator_t<std::cmatch>, std::cmatch::iterator>);
static_assert(std::same_as<stdr::iterator_t<std::cmatch const>, std::cmatch::const_iterator>);

View File

@ -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 <string>
#include <concepts>
#include <ranges>
namespace stdr = std::ranges;
static_assert(std::same_as<stdr::iterator_t<std::string>, std::string::iterator>);
static_assert(std::same_as<stdr::iterator_t<std::string const>, std::string::const_iterator>);

View File

@ -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 <string_view>
#include <concepts>
#include <ranges>
namespace stdr = std::ranges;
static_assert(std::same_as<stdr::iterator_t<std::string_view>, std::string_view::iterator>);
static_assert(std::same_as<stdr::iterator_t<std::string_view const>, std::string_view::const_iterator>);

View File

@ -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 <iterator>
#include <ranges>
#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 <template <class...> class I>
requires std::input_or_output_iterator<I<int*> >
struct test_range {
I<int*> begin();
I<int const*> begin() const;
sentinel end();
sentinel end() const;
};
template <template <class...> class I>
requires std::input_or_output_iterator<I<int*> >
struct test_non_const_range {
I<int*> begin();
sentinel end();
};
template <template <class...> class I>
requires std::input_or_output_iterator<I<int*> >
struct test_common_range {
I<int*> begin();
I<int const*> begin() const;
I<int*> end();
I<int*> end() const;
};
template <template <class...> class I>
requires std::input_or_output_iterator<I<int*> >
struct test_non_const_common_range {
I<int*> begin();
I<int*> end();
};
// clang-format on
#endif // LIBCXX_TEST_SUPPORT_TEST_RANGE_H