[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:
Arthur O'Dwyer 2022-01-11 11:05:41 -05:00
parent b9499e14d2
commit 4163f61f29
3 changed files with 58 additions and 29 deletions

View File

@ -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));
}
};
}

View File

@ -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());

View File

@ -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;