diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2020-01-29 13:36:15 +0000 |
---|---|---|
committer | Jonathan Wakely <jwakely@redhat.com> | 2020-01-29 13:36:15 +0000 |
commit | 5cd2e126f5c5705fa1aa7fafef3d6b94a99593da (patch) | |
tree | d759fca7ab12d32e415c712b9afef00827a6a259 | |
parent | 6693911f069b1ada7c04aa1d00c3653ba694958a (diff) | |
download | gcc-5cd2e126f5c5705fa1aa7fafef3d6b94a99593da.zip gcc-5cd2e126f5c5705fa1aa7fafef3d6b94a99593da.tar.gz gcc-5cd2e126f5c5705fa1aa7fafef3d6b94a99593da.tar.bz2 |
libstdc++: Make tests for std::ranges access functions more robust
* testsuite/std/ranges/access/end.cc: Do not assume test_range::end()
returns the same type as test_range::begin(). Add comments.
* testsuite/std/ranges/access/rbegin.cc: Likewise.
* testsuite/std/ranges/access/rend.cc: Likewise.
* testsuite/std/ranges/range.cc: Do not assume the sentinel for
test_range is the same as its iterator type.
* testsuite/util/testsuite_iterators.h (test_range::sentinel): Add
operator- overloads to satisfy sized_sentinel_for when the iterator
satisfies random_access_iterator.
-rw-r--r-- | libstdc++-v3/ChangeLog | 12 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/std/ranges/access/end.cc | 12 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/std/ranges/access/rbegin.cc | 28 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/std/ranges/access/rend.cc | 83 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/std/ranges/range.cc | 2 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/util/testsuite_iterators.h | 10 |
6 files changed, 112 insertions, 35 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 151ede0..133e216 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,15 @@ +2020-01-29 Jonathan Wakely <jwakely@redhat.com> + + * testsuite/std/ranges/access/end.cc: Do not assume test_range::end() + returns the same type as test_range::begin(). Add comments. + * testsuite/std/ranges/access/rbegin.cc: Likewise. + * testsuite/std/ranges/access/rend.cc: Likewise. + * testsuite/std/ranges/range.cc: Do not assume the sentinel for + test_range is the same as its iterator type. + * testsuite/util/testsuite_iterators.h (test_range::sentinel): Add + operator- overloads to satisfy sized_sentinel_for when the iterator + satisfies random_access_iterator. + 2020-01-28 Jonathan Wakely <jwakely@redhat.com> PR libstdc++/93470 diff --git a/libstdc++-v3/testsuite/std/ranges/access/end.cc b/libstdc++-v3/testsuite/std/ranges/access/end.cc index 2bb0e52..c3a1028 100644 --- a/libstdc++-v3/testsuite/std/ranges/access/end.cc +++ b/libstdc++-v3/testsuite/std/ranges/access/end.cc @@ -29,6 +29,8 @@ test01() { int a[2] = {}; + // t + extent_v<T> if E is of array type T. + static_assert(same_as<decltype(std::ranges::end(a)), decltype(a + 2)>); static_assert(noexcept(std::ranges::end(a))); VERIFY( std::ranges::end(a) == (a + 2) ); @@ -44,13 +46,16 @@ test02() int a[] = { 0, 1 }; + // Otherwise, decay-copy(t.end()) if it is a valid expression + // and its type S models sentinel_for<decltype(ranges::begin(E))>. + test_range<int, random_access_iterator_wrapper> r(a); static_assert(same_as<decltype(std::ranges::end(r)), decltype(r.end())>); - VERIFY( std::ranges::end(r) == r.end() ); + VERIFY( std::ranges::end(r) == std::ranges::next(r.begin(), 2) ); test_range<int, input_iterator_wrapper> i(a); static_assert(same_as<decltype(std::ranges::end(i)), decltype(i.end())>); - VERIFY( std::ranges::end(i) == i.end() ); + VERIFY( std::ranges::end(i) == std::ranges::next(i.begin(), 2) ); test_range<int, output_iterator_wrapper> o(a); static_assert(same_as<decltype(std::ranges::end(o)), decltype(o.end())>); @@ -93,6 +98,9 @@ test03() R r; const R& c = r; + // Otherwise, decay-copy(end(t)) if it is a valid expression + // and its type S models sentinel_for<decltype(ranges::begin(E))>. + static_assert(same_as<decltype(std::ranges::end(r)), decltype(end(r))>); static_assert(!noexcept(std::ranges::end(r))); VERIFY( std::ranges::end(r) == end(r) ); diff --git a/libstdc++-v3/testsuite/std/ranges/access/rbegin.cc b/libstdc++-v3/testsuite/std/ranges/access/rbegin.cc index 03e73a9..e92e5bc 100644 --- a/libstdc++-v3/testsuite/std/ranges/access/rbegin.cc +++ b/libstdc++-v3/testsuite/std/ranges/access/rbegin.cc @@ -38,6 +38,8 @@ void test01() { constexpr R1 r; + // decay-copy(t.rbegin()) if it is a valid expression + // and its type I models input_or_output_iterator. static_assert( std::ranges::rbegin(r) == &r.i ); static_assert( std::ranges::rbegin(std::move(r)) == &r.i ); } @@ -60,6 +62,8 @@ void test02() { constexpr R2 r; + // Otherwise, decay-copy(rbegin(t)) if it is a valid expression + // and its type I models input_or_output_iterator [...] static_assert( std::ranges::rbegin(r) == std::make_reverse_iterator(std::ranges::end(r)) ); static_assert( std::ranges::rbegin(std::move(r)) @@ -69,11 +73,29 @@ test02() void test03() { - using __gnu_test::test_range; - using __gnu_test::bidirectional_iterator_wrapper; + struct R3 + : __gnu_test::test_range<int, __gnu_test::bidirectional_iterator_wrapper> + { + R3(int (&a)[2]) : test_range(a) { } + + using test_range::begin; + + // Replace test_range::end() to return same type as begin() + // so ranges::rbegin will wrap it in a reverse_iterator . + auto end() & + { + using __gnu_test::bidirectional_iterator_wrapper; + return bidirectional_iterator_wrapper<int>(bounds.last, &bounds); + } + }; int a[2] = { }; - test_range<int, bidirectional_iterator_wrapper> r(a); + R3 r(a); + + // Otherwise, make_reverse_iterator(ranges::end(t)) if both ranges::begin(t) + // and ranges::end(t) are valid expressions of the same type I which models + // bidirectional_iterator. + VERIFY( std::ranges::rbegin(r) == std::make_reverse_iterator(std::ranges::end(r)) ); } diff --git a/libstdc++-v3/testsuite/std/ranges/access/rend.cc b/libstdc++-v3/testsuite/std/ranges/access/rend.cc index 42816d9..f6909b8 100644 --- a/libstdc++-v3/testsuite/std/ranges/access/rend.cc +++ b/libstdc++-v3/testsuite/std/ranges/access/rend.cc @@ -40,65 +40,91 @@ void test01() { constexpr R1 r; + + // decay-copy(t.rend()) if it is a valid expression + // and its type S models sentinel_for<decltype(ranges::rbegin(E))> + static_assert( std::ranges::rend(r) == &r.i + 1 ); static_assert( std::ranges::rend(std::move(r)) == &r.i + 1 ); } struct R2 { - int a[2] = { }; - long l[2] = { }; + int i = 0; - constexpr const int* begin() const { return a; } - constexpr const int* end() const { return a + 2; } + int* rbegin() noexcept { return &i + 1; } + long* rend() noexcept { return nullptr; } // not a sentinel for rbegin() - friend constexpr const long* begin(const R2&& r) { return r.l; } - friend constexpr const long* end(const R2&& r) { return r.l + 2; } + friend long* rbegin(R2&) noexcept { return nullptr; } + friend int* rend(R2& r) { return &r.i; } }; -// N.B. this is a lie, begin/end on an R2 rvalue will return a dangling pointer. -template<> constexpr bool std::ranges::enable_safe_range<R2> = true; - void test02() { - constexpr R2 r; - static_assert( std::ranges::rend(r) - == std::make_reverse_iterator(std::ranges::begin(r)) ); - static_assert( std::ranges::rend(std::move(r)) - == std::make_reverse_iterator(std::ranges::begin(std::move(r))) ); + R2 r; + + // Otherwise, decay-copy(rend(t)) if it is a valid expression + // and its type S models sentinel_for<decltype(ranges::rbegin(E))> + + auto i1 = std::ranges::rbegin(r); + auto i2 = rend(r); + static_assert( std::sentinel_for<decltype(i2), decltype(i1)> ); + VERIFY( std::ranges::rend(r) == &r.i ); + static_assert( !noexcept(std::ranges::rend(r)) ); } struct R3 { - int i = 0; + int a[2] = { }; + long l[2] = { }; - int* rbegin() noexcept { return &i + 1; } - long* rend() noexcept { return nullptr; } // not a sentinel for rbegin() + constexpr const int* begin() const { return a; } + constexpr const int* end() const { return a + 2; } - friend long* rbegin(R3&) noexcept { return nullptr; } - friend int* rend(R3& r) { return &r.i; } + friend constexpr const long* begin(const R3&& r) { return r.l; } + friend constexpr const long* end(const R3&& r) { return r.l + 2; } }; +// N.B. this is a lie, begin/end on an R3 rvalue will return a dangling pointer. +template<> constexpr bool std::ranges::enable_safe_range<R3> = true; + void test03() { - R3 r; - auto i1 = std::ranges::rbegin(r); - auto i2 = rend(r); - static_assert( std::sentinel_for<decltype(i2), decltype(i1)> ); - // VERIFY( std::ranges::rend(r) == r.i ); - // static_assert( !noexcept(std::ranges::rend(r)) ); + constexpr R3 r; + + // Otherwise, make_reverse_iterator(ranges::begin(t)) if both + // ranges::begin(t) and ranges::end(t) are valid expressions + // of the same type I which models bidirectional_iterator. + + static_assert( std::ranges::rend(r) + == std::make_reverse_iterator(std::ranges::begin(r)) ); + static_assert( std::ranges::rend(std::move(r)) + == std::make_reverse_iterator(std::ranges::begin(std::move(r))) ); } void test04() { - using __gnu_test::test_range; - using __gnu_test::bidirectional_iterator_wrapper; + struct R4 + : __gnu_test::test_range<int, __gnu_test::bidirectional_iterator_wrapper> + { + R4(int (&a)[2]) : test_range(a) { } + + using test_range::begin; + + // Replace test_range::end() to return same type as begin() + // so ranges::rend will wrap it in a reverse_iterator. + auto end() & + { + using __gnu_test::bidirectional_iterator_wrapper; + return bidirectional_iterator_wrapper<int>(bounds.last, &bounds); + } + }; int a[2] = { }; - test_range<int, bidirectional_iterator_wrapper> r(a); + R4 r(a); VERIFY( std::ranges::rend(r) == std::make_reverse_iterator(std::ranges::begin(r)) ); } @@ -108,4 +134,5 @@ main() test01(); test02(); test03(); + test04(); } diff --git a/libstdc++-v3/testsuite/std/ranges/range.cc b/libstdc++-v3/testsuite/std/ranges/range.cc index fabbcf9..cf349de 100644 --- a/libstdc++-v3/testsuite/std/ranges/range.cc +++ b/libstdc++-v3/testsuite/std/ranges/range.cc @@ -66,7 +66,7 @@ static_assert( same_as<std::ranges::iterator_t<O>, decltype(std::declval<O&>().begin())> ); static_assert( same_as<std::ranges::sentinel_t<C>, - contiguous_iterator_wrapper<char>> ); + decltype(std::declval<C&>().end())> ); static_assert( same_as<std::ranges::sentinel_t<O>, decltype(std::declval<O&>().end())> ); diff --git a/libstdc++-v3/testsuite/util/testsuite_iterators.h b/libstdc++-v3/testsuite/util/testsuite_iterators.h index eb15257..1c7fbd0 100644 --- a/libstdc++-v3/testsuite/util/testsuite_iterators.h +++ b/libstdc++-v3/testsuite/util/testsuite_iterators.h @@ -675,8 +675,16 @@ namespace __gnu_test { T* end; - friend bool operator==(const sentinel& s, const I& i) + friend bool operator==(const sentinel& s, const I& i) noexcept { return s.end == i.ptr; } + + friend auto operator-(const sentinel& s, const I& i) noexcept + requires std::random_access_iterator<I> + { return s.end - i.ptr; } + + friend auto operator-(const I& i, const sentinel& s) noexcept + requires std::random_access_iterator<I> + { return i.ptr - s.end; } }; auto |