From 4163f61f29f47d3e0d82cec2ba4cf8997d4b6820 Mon Sep 17 00:00:00 2001 From: Arthur O'Dwyer Date: Tue, 11 Jan 2022 11:05:41 -0500 Subject: [PATCH] [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 --- libcxx/include/__ranges/data.h | 21 ++++---- libcxx/test/std/ranges/range.access/data.pass.cpp | 60 +++++++++++++++++----- .../contiguous_range.compile.pass.cpp | 6 +-- 3 files changed, 58 insertions(+), 29 deletions(-) diff --git a/libcxx/include/__ranges/data.h b/libcxx/include/__ranges/data.h index cc151c5..de39312b 100644 --- a/libcxx/include/__ranges/data.h +++ b/libcxx/include/__ranges/data.h @@ -14,8 +14,7 @@ #include <__iterator/iterator_traits.h> #include <__memory/pointer_traits.h> #include <__ranges/access.h> -#include <__utility/forward.h> -#include +#include <__utility/auto_cast.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -35,34 +34,32 @@ namespace __data { template 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 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)); } }; } diff --git a/libcxx/test/std/ranges/range.access/data.pass.cpp b/libcxx/test/std/ranges/range.access/data.pass.cpp index 6d0b718f..da4d79d 100644 --- a/libcxx/test/std/ranges/range.access/data.pass.cpp +++ b/libcxx/test/std/ranges/range.access/data.pass.cpp @@ -36,9 +36,45 @@ struct DataMember { int x; constexpr const int *data() const { 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); + +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())), char*); + static_assert(!std::is_invocable_v); + ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval())), short*); + static_assert(!std::is_invocable_v); + } + { + struct NC { + char *begin() const; + char *end() const; + int *data(); + }; + static_assert(!std::ranges::contiguous_range); + static_assert( std::ranges::contiguous_range); + ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval())), int*); + static_assert(!std::is_invocable_v); + ASSERT_SAME_TYPE(decltype(std::ranges::data(std::declval())), char*); + static_assert(!std::is_invocable_v); + } + return true; +} struct VoidDataMember { void *data() const; @@ -49,21 +85,14 @@ struct Empty { }; struct EmptyDataMember { Empty data() const; }; - static_assert(!std::is_invocable_v); -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); 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 = 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); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); struct BeginMemberBorrowingEnabled { constexpr contiguous_iterator begin() { return contiguous_iterator{&globalBuff[1]}; } @@ -188,6 +218,8 @@ struct RandomButNotContiguous { static_assert(!std::is_invocable_v); int main(int, char**) { + static_assert(testReturnTypes()); + testDataMember(); static_assert(testDataMember()); diff --git a/libcxx/test/std/ranges/range.req/range.refinements/contiguous_range.compile.pass.cpp b/libcxx/test/std/ranges/range.req/range.refinements/contiguous_range.compile.pass.cpp index 228c277..1b5aa35 100644 --- a/libcxx/test/std/ranges/range.req/range.refinements/contiguous_range.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.req/range.refinements/contiguous_range.compile.pass.cpp @@ -46,8 +46,8 @@ struct ContiguousWhenNonConst { int *end(); int *data() const; }; -static_assert( std::ranges::random_access_range); static_assert( std::ranges::contiguous_range); +static_assert( std::ranges::random_access_range); static_assert(!std::ranges::contiguous_range); struct ContiguousWhenConst { @@ -57,9 +57,9 @@ struct ContiguousWhenConst { int *end(); const int *data() const; }; +static_assert( std::ranges::contiguous_range); static_assert( std::ranges::random_access_range); static_assert(!std::ranges::contiguous_range); -static_assert( std::ranges::contiguous_range); struct DataFunctionWrongReturnType { const int *begin() const; @@ -67,7 +67,7 @@ struct DataFunctionWrongReturnType { const char *data() const; }; static_assert( std::ranges::random_access_range); -static_assert(!std::ranges::contiguous_range); +static_assert(!std::ranges::contiguous_range); struct WrongObjectness { const int *begin() const; -- 2.7.4