Skip to content

Commit 4163f61

Browse files
committed
[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
1 parent b9499e1 commit 4163f61

File tree

3 files changed

+58
-29
lines changed

3 files changed

+58
-29
lines changed

libcxx/include/__ranges/data.h

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@
1414
#include <__iterator/iterator_traits.h>
1515
#include <__memory/pointer_traits.h>
1616
#include <__ranges/access.h>
17-
#include <__utility/forward.h>
18-
#include <concepts>
17+
#include <__utility/auto_cast.h>
1918
#include <type_traits>
2019

2120
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -35,34 +34,32 @@ namespace __data {
3534

3635
template <class _Tp>
3736
concept __member_data =
37+
__can_borrow<_Tp> &&
3838
requires(_Tp&& __t) {
39-
{ _VSTD::forward<_Tp>(__t) } -> __can_borrow;
40-
{ __t.data() } -> __ptr_to_object;
39+
{ _LIBCPP_AUTO_CAST(__t.data()) } -> __ptr_to_object;
4140
};
4241

4342
template <class _Tp>
4443
concept __ranges_begin_invocable =
4544
!__member_data<_Tp> &&
45+
__can_borrow<_Tp> &&
4646
requires(_Tp&& __t) {
47-
{ _VSTD::forward<_Tp>(__t) } -> __can_borrow;
48-
{ ranges::begin(_VSTD::forward<_Tp>(__t)) } -> contiguous_iterator;
47+
{ ranges::begin(__t) } -> contiguous_iterator;
4948
};
5049

5150
struct __fn {
5251
template <__member_data _Tp>
53-
requires __can_borrow<_Tp>
5452
_LIBCPP_HIDE_FROM_ABI
55-
constexpr __ptr_to_object auto operator()(_Tp&& __t) const
53+
constexpr auto operator()(_Tp&& __t) const
5654
noexcept(noexcept(__t.data())) {
5755
return __t.data();
5856
}
5957

6058
template<__ranges_begin_invocable _Tp>
61-
requires __can_borrow<_Tp>
6259
_LIBCPP_HIDE_FROM_ABI
63-
constexpr __ptr_to_object auto operator()(_Tp&& __t) const
64-
noexcept(noexcept(_VSTD::to_address(ranges::begin(_VSTD::forward<_Tp>(__t))))) {
65-
return _VSTD::to_address(ranges::begin(_VSTD::forward<_Tp>(__t)));
60+
constexpr auto operator()(_Tp&& __t) const
61+
noexcept(noexcept(_VSTD::to_address(ranges::begin(__t)))) {
62+
return _VSTD::to_address(ranges::begin(__t));
6663
}
6764
};
6865
}

libcxx/test/std/ranges/range.access/data.pass.cpp

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,45 @@ struct DataMember {
3636
int x;
3737
constexpr const int *data() const { return &x; }
3838
};
39-
4039
static_assert( std::is_invocable_v<RangeDataT, DataMember &>);
4140
static_assert(!std::is_invocable_v<RangeDataT, DataMember &&>);
41+
static_assert( std::is_invocable_v<RangeDataT, DataMember const&>);
42+
static_assert(!std::is_invocable_v<RangeDataT, DataMember const&&>);
43+
44+
constexpr bool testReturnTypes() {
45+
{
46+
int *x[2];
47+
ASSERT_SAME_TYPE(decltype(std::ranges::data(x)), int**);
48+
}
49+
{
50+
int x[2][2];
51+
ASSERT_SAME_TYPE(decltype(std::ranges::data(x)), int(*)[2]);
52+
}
53+
{
54+
struct D {
55+
char*& data();
56+
short*& data() const;
57+
};
58+
ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval<D&>())), char*);
59+
static_assert(!std::is_invocable_v<RangeDataT, D&&>);
60+
ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval<const D&>())), short*);
61+
static_assert(!std::is_invocable_v<RangeDataT, const D&&>);
62+
}
63+
{
64+
struct NC {
65+
char *begin() const;
66+
char *end() const;
67+
int *data();
68+
};
69+
static_assert(!std::ranges::contiguous_range<NC>);
70+
static_assert( std::ranges::contiguous_range<const NC>);
71+
ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval<NC&>())), int*);
72+
static_assert(!std::is_invocable_v<RangeDataT, NC&&>);
73+
ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval<const NC&>())), char*);
74+
static_assert(!std::is_invocable_v<RangeDataT, const NC&&>);
75+
}
76+
return true;
77+
}
4278

4379
struct VoidDataMember {
4480
void *data() const;
@@ -49,21 +85,14 @@ struct Empty { };
4985
struct EmptyDataMember {
5086
Empty data() const;
5187
};
52-
5388
static_assert(!std::is_invocable_v<RangeDataT, EmptyDataMember const&>);
5489

55-
struct EmptyPtrDataMember {
56-
Empty x;
57-
constexpr const Empty *data() const { return &x; }
58-
};
59-
60-
struct PtrConvertible {
61-
operator int*() const;
62-
};
6390
struct PtrConvertibleDataMember {
64-
PtrConvertible data() const;
91+
struct Ptr {
92+
operator int*() const;
93+
};
94+
Ptr data() const;
6595
};
66-
6796
static_assert(!std::is_invocable_v<RangeDataT, PtrConvertibleDataMember const&>);
6897

6998
struct NonConstDataMember {
@@ -74,14 +103,13 @@ struct NonConstDataMember {
74103
struct EnabledBorrowingDataMember {
75104
constexpr int *data() { return &globalBuff[0]; }
76105
};
77-
78106
template<>
79107
inline constexpr bool std::ranges::enable_borrowed_range<EnabledBorrowingDataMember> = true;
80108

81109
struct DataMemberAndBegin {
82110
int x;
83111
constexpr const int *data() const { return &x; }
84-
constexpr const int *begin() const { return &x; }
112+
const int *begin() const;
85113
};
86114

87115
constexpr bool testDataMember() {
@@ -147,8 +175,10 @@ struct BeginMemberRvalue {
147175

148176
ContiguousIter begin() &&;
149177
};
178+
static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRvalue&>);
150179
static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRvalue&&>);
151180
static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRvalue const&>);
181+
static_assert(!std::is_invocable_v<RangeDataT, BeginMemberRvalue const&&>);
152182

153183
struct BeginMemberBorrowingEnabled {
154184
constexpr contiguous_iterator<int*> begin() { return contiguous_iterator<int*>{&globalBuff[1]}; }
@@ -188,6 +218,8 @@ struct RandomButNotContiguous {
188218
static_assert(!std::is_invocable_v<RangeDataT, RandomButNotContiguous>);
189219

190220
int main(int, char**) {
221+
static_assert(testReturnTypes());
222+
191223
testDataMember();
192224
static_assert(testDataMember());
193225

libcxx/test/std/ranges/range.req/range.refinements/contiguous_range.compile.pass.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ struct ContiguousWhenNonConst {
4646
int *end();
4747
int *data() const;
4848
};
49-
static_assert( std::ranges::random_access_range<ContiguousWhenNonConst>);
5049
static_assert( std::ranges::contiguous_range<ContiguousWhenNonConst>);
50+
static_assert( std::ranges::random_access_range<const ContiguousWhenNonConst>);
5151
static_assert(!std::ranges::contiguous_range<const ContiguousWhenNonConst>);
5252

5353
struct ContiguousWhenConst {
@@ -57,17 +57,17 @@ struct ContiguousWhenConst {
5757
int *end();
5858
const int *data() const;
5959
};
60+
static_assert( std::ranges::contiguous_range<const ContiguousWhenConst>);
6061
static_assert( std::ranges::random_access_range<ContiguousWhenConst>);
6162
static_assert(!std::ranges::contiguous_range<ContiguousWhenConst>);
62-
static_assert( std::ranges::contiguous_range<const ContiguousWhenConst>);
6363

6464
struct DataFunctionWrongReturnType {
6565
const int *begin() const;
6666
const int *end() const;
6767
const char *data() const;
6868
};
6969
static_assert( std::ranges::random_access_range<DataFunctionWrongReturnType>);
70-
static_assert(!std::ranges::contiguous_range<const DataFunctionWrongReturnType>);
70+
static_assert(!std::ranges::contiguous_range<DataFunctionWrongReturnType>);
7171

7272
struct WrongObjectness {
7373
const int *begin() const;

0 commit comments

Comments
 (0)