forked from OSchip/llvm-project
[libc++] [ranges] Fix a missing auto(x) cast in ranges::data.
Also remove some bogus `std::forward`s. My impression is that these forwards were actually harmless, because `ranges::begin(FWD(t))` is always identical to `ranges::begin(t)` (except when it's ill-formed, and that can't happen in this case). However, they're also superfluous and don't reflect the wording in the standard, so let's eliminate them. Differential Revision: https://reviews.llvm.org/D117043
This commit is contained in:
parent
b9499e14d2
commit
4163f61f29
|
@ -14,8 +14,7 @@
|
|||
#include <__iterator/iterator_traits.h>
|
||||
#include <__memory/pointer_traits.h>
|
||||
#include <__ranges/access.h>
|
||||
#include <__utility/forward.h>
|
||||
#include <concepts>
|
||||
#include <__utility/auto_cast.h>
|
||||
#include <type_traits>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
|
@ -35,34 +34,32 @@ namespace __data {
|
|||
|
||||
template <class _Tp>
|
||||
concept __member_data =
|
||||
__can_borrow<_Tp> &&
|
||||
requires(_Tp&& __t) {
|
||||
{ _VSTD::forward<_Tp>(__t) } -> __can_borrow;
|
||||
{ __t.data() } -> __ptr_to_object;
|
||||
{ _LIBCPP_AUTO_CAST(__t.data()) } -> __ptr_to_object;
|
||||
};
|
||||
|
||||
template <class _Tp>
|
||||
concept __ranges_begin_invocable =
|
||||
!__member_data<_Tp> &&
|
||||
__can_borrow<_Tp> &&
|
||||
requires(_Tp&& __t) {
|
||||
{ _VSTD::forward<_Tp>(__t) } -> __can_borrow;
|
||||
{ ranges::begin(_VSTD::forward<_Tp>(__t)) } -> contiguous_iterator;
|
||||
{ ranges::begin(__t) } -> contiguous_iterator;
|
||||
};
|
||||
|
||||
struct __fn {
|
||||
template <__member_data _Tp>
|
||||
requires __can_borrow<_Tp>
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr __ptr_to_object auto operator()(_Tp&& __t) const
|
||||
constexpr auto operator()(_Tp&& __t) const
|
||||
noexcept(noexcept(__t.data())) {
|
||||
return __t.data();
|
||||
}
|
||||
|
||||
template<__ranges_begin_invocable _Tp>
|
||||
requires __can_borrow<_Tp>
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr __ptr_to_object auto operator()(_Tp&& __t) const
|
||||
noexcept(noexcept(_VSTD::to_address(ranges::begin(_VSTD::forward<_Tp>(__t))))) {
|
||||
return _VSTD::to_address(ranges::begin(_VSTD::forward<_Tp>(__t)));
|
||||
constexpr auto operator()(_Tp&& __t) const
|
||||
noexcept(noexcept(_VSTD::to_address(ranges::begin(__t)))) {
|
||||
return _VSTD::to_address(ranges::begin(__t));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -36,9 +36,45 @@ struct DataMember {
|
|||
int x;
|
||||
constexpr const int *data() const { return &x; }
|
||||
};
|
||||
|
||||
static_assert( std::is_invocable_v<RangeDataT, DataMember &>);
|
||||
static_assert(!std::is_invocable_v<RangeDataT, DataMember &&>);
|
||||
static_assert( std::is_invocable_v<RangeDataT, DataMember const&>);
|
||||
static_assert(!std::is_invocable_v<RangeDataT, DataMember const&&>);
|
||||
|
||||
constexpr bool testReturnTypes() {
|
||||
{
|
||||
int *x[2];
|
||||
ASSERT_SAME_TYPE(decltype(std::ranges::data(x)), int**);
|
||||
}
|
||||
{
|
||||
int x[2][2];
|
||||
ASSERT_SAME_TYPE(decltype(std::ranges::data(x)), int(*)[2]);
|
||||
}
|
||||
{
|
||||
struct D {
|
||||
char*& data();
|
||||
short*& data() const;
|
||||
};
|
||||
ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval<D&>())), char*);
|
||||
static_assert(!std::is_invocable_v<RangeDataT, D&&>);
|
||||
ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval<const D&>())), short*);
|
||||
static_assert(!std::is_invocable_v<RangeDataT, const D&&>);
|
||||
}
|
||||
{
|
||||
struct NC {
|
||||
char *begin() const;
|
||||
char *end() const;
|
||||
int *data();
|
||||
};
|
||||
static_assert(!std::ranges::contiguous_range<NC>);
|
||||
static_assert( std::ranges::contiguous_range<const NC>);
|
||||
ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval<NC&>())), int*);
|
||||
static_assert(!std::is_invocable_v<RangeDataT, NC&&>);
|
||||
ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval<const NC&>())), char*);
|
||||
static_assert(!std::is_invocable_v<RangeDataT, const NC&&>);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct VoidDataMember {
|
||||
void *data() const;
|
||||
|
@ -49,21 +85,14 @@ struct Empty { };
|
|||
struct EmptyDataMember {
|
||||
Empty data() const;
|
||||
};
|
||||
|
||||
static_assert(!std::is_invocable_v<RangeDataT, EmptyDataMember const&>);
|
||||
|
||||
struct EmptyPtrDataMember {
|
||||
Empty x;
|
||||
constexpr const Empty *data() const { return &x; }
|
||||
};
|
||||
|
||||
struct PtrConvertible {
|
||||
operator int*() const;
|
||||
};
|
||||
struct PtrConvertibleDataMember {
|
||||
PtrConvertible data() const;
|
||||
struct Ptr {
|
||||
operator int*() const;
|
||||
};
|
||||
Ptr data() const;
|
||||
};
|
||||
|
||||
static_assert(!std::is_invocable_v<RangeDataT, PtrConvertibleDataMember const&>);
|
||||
|
||||
struct NonConstDataMember {
|
||||
|
@ -74,14 +103,13 @@ struct NonConstDataMember {
|
|||
struct EnabledBorrowingDataMember {
|
||||
constexpr int *data() { return &globalBuff[0]; }
|
||||
};
|
||||
|
||||
template<>
|
||||
inline constexpr bool std::ranges::enable_borrowed_range<EnabledBorrowingDataMember> = true;
|
||||
|
||||
struct DataMemberAndBegin {
|
||||
int x;
|
||||
constexpr const int *data() const { return &x; }
|
||||
constexpr const int *begin() const { return &x; }
|
||||
const int *begin() const;
|
||||
};
|
||||
|
||||
constexpr bool testDataMember() {
|
||||
|
@ -147,8 +175,10 @@ struct BeginMemberRvalue {
|
|||
|
||||
ContiguousIter begin() &&;
|
||||
};
|
||||
static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRvalue&>);
|
||||
static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRvalue&&>);
|
||||
static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRvalue const&>);
|
||||
static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRvalue const&&>);
|
||||
|
||||
struct BeginMemberBorrowingEnabled {
|
||||
constexpr contiguous_iterator<int*> begin() { return contiguous_iterator<int*>{&globalBuff[1]}; }
|
||||
|
@ -188,6 +218,8 @@ struct RandomButNotContiguous {
|
|||
static_assert(!std::is_invocable_v<RangeDataT, RandomButNotContiguous>);
|
||||
|
||||
int main(int, char**) {
|
||||
static_assert(testReturnTypes());
|
||||
|
||||
testDataMember();
|
||||
static_assert(testDataMember());
|
||||
|
||||
|
|
|
@ -46,8 +46,8 @@ struct ContiguousWhenNonConst {
|
|||
int *end();
|
||||
int *data() const;
|
||||
};
|
||||
static_assert( std::ranges::random_access_range<ContiguousWhenNonConst>);
|
||||
static_assert( std::ranges::contiguous_range<ContiguousWhenNonConst>);
|
||||
static_assert( std::ranges::random_access_range<const ContiguousWhenNonConst>);
|
||||
static_assert(!std::ranges::contiguous_range<const ContiguousWhenNonConst>);
|
||||
|
||||
struct ContiguousWhenConst {
|
||||
|
@ -57,9 +57,9 @@ struct ContiguousWhenConst {
|
|||
int *end();
|
||||
const int *data() const;
|
||||
};
|
||||
static_assert( std::ranges::contiguous_range<const ContiguousWhenConst>);
|
||||
static_assert( std::ranges::random_access_range<ContiguousWhenConst>);
|
||||
static_assert(!std::ranges::contiguous_range<ContiguousWhenConst>);
|
||||
static_assert( std::ranges::contiguous_range<const ContiguousWhenConst>);
|
||||
|
||||
struct DataFunctionWrongReturnType {
|
||||
const int *begin() const;
|
||||
|
@ -67,7 +67,7 @@ struct DataFunctionWrongReturnType {
|
|||
const char *data() const;
|
||||
};
|
||||
static_assert( std::ranges::random_access_range<DataFunctionWrongReturnType>);
|
||||
static_assert(!std::ranges::contiguous_range<const DataFunctionWrongReturnType>);
|
||||
static_assert(!std::ranges::contiguous_range<DataFunctionWrongReturnType>);
|
||||
|
||||
struct WrongObjectness {
|
||||
const int *begin() const;
|
||||
|
|
Loading…
Reference in New Issue