commit 9faf3f15a81c9f4a575f2c6c72d88bcbdd476a6c Author: Jonathan Wakely Date: Thu Oct 31 11:53:08 2019 +0000 Remove PR 92268 workaround and fix new test failures With the compiler bug fixed we can simplify the __sizable concept to use a return-type-requirement again. I also realised it was redundantly re-checking a subset of the sized_sentinel_for requirements. The compiler fix also revealed bugs in two tests which started to fail and are fixed by this patch. * include/bits/range_access.h (__sizable): Rename to __sentinel_size. Remove workaround for PR c++/92268 and remove redundant requirements that are already checked by sized_sentinel_for. * testsuite/std/ranges/access/cend.cc: Fix failures. * testsuite/std/ranges/access/end.cc: Likewise. diff --git a/libstdc++-v3/include/bits/range_access.h b/libstdc++-v3/include/bits/range_access.h index f0a339277e9..de074460c16 100644 --- a/libstdc++-v3/include/bits/range_access.h +++ b/libstdc++-v3/include/bits/range_access.h @@ -689,19 +689,13 @@ namespace ranges -> __detail::__is_integer_like; }; - // FIXME: needed due to PR c++/92268 - template _End> - requires requires (_It __it, _End __end) - { { __end - __it } -> __detail::__is_integer_like; } - void - __subtractable_fwd_iter(_It, _End) - { } - template - concept __sizable = requires(_Tp&& __t) + concept __sentinel_size = requires(_Tp&& __t) { - __subtractable_fwd_iter(_Begin{}(std::forward<_Tp>(__t)), - _End{}(std::forward<_Tp>(__t))); + { _Begin{}(std::forward<_Tp>(__t)) } -> forward_iterator; + + { _End{}(std::forward<_Tp>(__t)) } + -> sized_sentinel_for(__t)))>; }; struct _Size @@ -717,7 +711,7 @@ namespace ranges return noexcept(__decay_copy(std::declval<_Tp>().size())); else if constexpr (__adl_size<_Tp>) return noexcept(__decay_copy(size(std::declval<_Tp>()))); - else if constexpr (__sizable<_Tp>) + else if constexpr (__sentinel_size<_Tp>) return noexcept(_End{}(std::declval<_Tp>()) - _Begin{}(std::declval<_Tp>())); } @@ -725,7 +719,7 @@ namespace ranges public: template requires is_array_v> - || __member_size<_Tp> || __adl_size<_Tp> || __sizable<_Tp> + || __member_size<_Tp> || __adl_size<_Tp> || __sentinel_size<_Tp> constexpr auto operator()(_Tp&& __e) const noexcept(_S_noexcept<_Tp>()) { @@ -738,7 +732,7 @@ namespace ranges return std::forward<_Tp>(__e).size(); else if constexpr (__adl_size<_Tp>) return size(std::forward<_Tp>(__e)); - else if constexpr (__sizable<_Tp>) + else if constexpr (__sentinel_size<_Tp>) return __detail::__to_unsigned_like( _End{}(std::forward<_Tp>(__e)) - _Begin{}(std::forward<_Tp>(__e))); diff --git a/libstdc++-v3/testsuite/std/ranges/access/cend.cc b/libstdc++-v3/testsuite/std/ranges/access/cend.cc index 789c6ca3837..94349c35d51 100644 --- a/libstdc++-v3/testsuite/std/ranges/access/cend.cc +++ b/libstdc++-v3/testsuite/std/ranges/access/cend.cc @@ -66,15 +66,18 @@ struct RR long l = 0; int a[4] = { 0, 1, 2, 3 }; - const void* begin() const { return nullptr; } - friend const void* begin(const RR&&) noexcept { return nullptr; } - - short* end() noexcept { return &s; } - const long* end() const { return &l; } + const void* begin() const; // return type not an iterator friend int* end(RR&) { throw 1; } + short* end() noexcept { return &s; } + + friend const long* begin(const RR&) noexcept; + const long* end() const { return &l; } + + friend int* begin(RR&&) noexcept; friend int* end(RR&& r) { return r.a + 1; } - friend const int* end(const RR&) { throw 1; } + + friend const int* begin(const RR&&) noexcept; friend const int* end(const RR&& r) noexcept { return r.a + 3; } }; diff --git a/libstdc++-v3/testsuite/std/ranges/access/end.cc b/libstdc++-v3/testsuite/std/ranges/access/end.cc index 7f09cc2a4ab..6638bb35721 100644 --- a/libstdc++-v3/testsuite/std/ranges/access/end.cc +++ b/libstdc++-v3/testsuite/std/ranges/access/end.cc @@ -61,11 +61,12 @@ struct R { int a[4] = { 0, 1, 2, 3 }; - const int* begin() const { return nullptr; } - friend const int* begin(const R&& r) noexcept { return nullptr; } + const int* begin() const; + friend int* begin(R&&) noexcept; + friend const int* begin(const R&&) noexcept; // Should be ignored because it doesn't return a sentinel for int* - const long* end() const { return nullptr; } + const long* end() const; friend int* end(R& r) { return r.a + 0; } friend int* end(R&& r) { return r.a + 1; } @@ -105,15 +106,20 @@ struct RR long l = 0; int a[4] = { 0, 1, 2, 3 }; - const void* begin() const { return nullptr; } - friend const void* begin(const RR&&) noexcept { return nullptr; } + const void* begin() const; // return type not an iterator + friend const short* begin(RR&) noexcept; short* end() noexcept { return &s; } + + friend const long* begin(const RR&) noexcept; const long* end() const { return &l; } - friend int* end(RR&) { throw 1; } + friend const int* begin(RR&&) noexcept; + friend int* end(RR&) { throw 1; } // not valid for rvalues friend int* end(RR&& r) { return r.a + 1; } - friend const int* end(const RR&) { throw 1; } + + friend const int* begin(const RR&&) noexcept; + friend const int* end(const RR&) { throw 1; } // not valid for rvalues friend const int* end(const RR&& r) noexcept { return r.a + 3; } };