diff options
Diffstat (limited to 'libstdc++-v3')
8 files changed, 154 insertions, 7 deletions
diff --git a/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc b/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc index 1037604..3667b0d 100644 --- a/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc +++ b/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc @@ -48,6 +48,10 @@ struct R friend int* begin(R&&); // this function is not defined friend const int* begin(const R& r) noexcept { return r.a + 2; } friend const int* begin(const R&&); // this function is not defined + +#if __cpp_lib_ranges_as_const + friend const int* end(const R&) noexcept; // C++23 requires this. +#endif }; struct RV // view on an R @@ -56,6 +60,10 @@ struct RV // view on an R friend int* begin(RV&); // this function is not defined friend const int* begin(const RV& rv) noexcept { return begin(std::as_const(rv.r)); } + +#if __cpp_lib_ranges_as_const + friend const int* end(const RV&) noexcept; // C++23 requires this. +#endif }; // Allow ranges::begin to work with RV&& @@ -88,6 +96,11 @@ struct RR friend int* begin(RR&& r) { return r.a + 1; } friend const int* begin(const RR& r) { return r.a + 2; } friend const int* begin(const RR&& r) noexcept { return r.a + 3; } + +#if __cpp_lib_ranges_as_const + short* end() noexcept { return &s + 1; } // C++23 requires this. + const long* end() const { return &l + 1; } // C++23 requires this. +#endif }; // N.B. this is a lie, cbegin on an RR rvalue will return a dangling pointer. diff --git a/libstdc++-v3/testsuite/std/ranges/access/cdata.cc b/libstdc++-v3/testsuite/std/ranges/access/cdata.cc index f0f45ee..d69b04c 100644 --- a/libstdc++-v3/testsuite/std/ranges/access/cdata.cc +++ b/libstdc++-v3/testsuite/std/ranges/access/cdata.cc @@ -41,15 +41,43 @@ test01() static_assert( has_cdata<R&> ); static_assert( has_cdata<const R&> ); R r; - const R& c = r; +#if ! __cpp_lib_ranges_as_const VERIFY( std::ranges::cdata(r) == (R*)nullptr ); static_assert( noexcept(std::ranges::cdata(r)) ); +#else + // constant_range<const R> is not satisfied, so cdata(r) == data(r). + VERIFY( std::ranges::cdata(r) == &r.j ); + static_assert( ! noexcept(std::ranges::cdata(r)) ); +#endif + const R& c = r; VERIFY( std::ranges::cdata(c) == (R*)nullptr ); static_assert( noexcept(std::ranges::cdata(c)) ); // not lvalues and not borrowed ranges static_assert( !has_cdata<R> ); static_assert( !has_cdata<const R> ); + + struct R2 + { + // These overloads mean that range<R2> and range<const R2> are satisfied. + int* begin(); + int* end(); + const int* begin() const; + const int* end() const; + + int i = 0; + int j = 0; + int* data() { return &j; } + const R2* data() const noexcept { return nullptr; } + }; + static_assert( has_cdata<R2&> ); + static_assert( has_cdata<const R2&> ); + R2 r2; + VERIFY( std::ranges::cdata(r2) == (R2*)nullptr ); + static_assert( noexcept(std::ranges::cdata(r2)) ); + const R2& c2 = r2; + VERIFY( std::ranges::cdata(c2) == (R2*)nullptr ); + static_assert( noexcept(std::ranges::cdata(c2)) ); } void @@ -71,6 +99,14 @@ struct R3 friend long* begin(R3&& r); // not defined friend const long* begin(const R3& r) { return &r.l; } friend const short* begin(const R3&&); // not defined + +#if __cpp_lib_ranges_as_const + // C++23 needs these so that range<R3> is satisfied and so that + // possibly-const-range<R3> is not the same type as R3. + friend long* begin(R3&); + friend long* end(R3&); + friend const long* end(const R3& r); +#endif }; template<> constexpr bool std::ranges::enable_borrowed_range<R3> = true; diff --git a/libstdc++-v3/testsuite/std/ranges/access/cend.cc b/libstdc++-v3/testsuite/std/ranges/access/cend.cc index f47bd9d..3726ebb 100644 --- a/libstdc++-v3/testsuite/std/ranges/access/cend.cc +++ b/libstdc++-v3/testsuite/std/ranges/access/cend.cc @@ -42,7 +42,7 @@ 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; } + friend const int* begin(const R&&) noexcept { return nullptr; } // Should be ignored because it doesn't return a sentinel for int* const long* end() const { return nullptr; } @@ -53,6 +53,15 @@ struct R friend const int* end(const R&& r) noexcept { return r.a + 3; } }; +#if __cpp_lib_ranges_as_const +struct R2 : R +{ + // This overload means constant_range<const R2> will be satisfied: + friend const int* begin(const R2&) noexcept; + friend const int* end(const R2& r2) noexcept { return r2.a + 2; } +}; +#endif + struct RV // view on an R { R& r; @@ -71,12 +80,28 @@ test03() { R r; const R& c = r; +#if ! __cpp_lib_ranges_as_const VERIFY( std::ranges::cend(r) == std::ranges::end(c) ); +#else + // constant_range<const R> is not satisfied, so cend(r) == end(r) instead. + VERIFY( std::ranges::cend(r) == std::ranges::end(r) ); + R2 r2; + const R& c2 = r2; + // But constant_range<const R2> is satisfied, so cend(r2) == end(c2). + VERIFY( std::ranges::cend(r2) == std::ranges::end(c2) ); + VERIFY( std::ranges::cend(r2) == std::ranges::end((const R&)c2) ); +#endif VERIFY( std::ranges::cend(c) == std::ranges::end(c) ); RV v{r}; - const RV cv{r}; +#if ! __cpp_lib_ranges_as_const VERIFY( std::ranges::cend(std::move(v)) == std::ranges::end(c) ); +#else + // constant_range<RV> is already satisfied, so cend(v) == end(r) instead. + VERIFY( std::ranges::cend(std::move(v)) == std::ranges::end(r) ); +#endif + + const RV cv{r}; VERIFY( std::ranges::cend(std::move(cv)) == std::ranges::end(c) ); } diff --git a/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc b/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc index db58d95..95b4607f 100644 --- a/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc +++ b/libstdc++-v3/testsuite/std/ranges/access/crbegin.cc @@ -37,13 +37,33 @@ struct R1V // view on an R1 { R1& r; - friend const long* rbegin(R1V&); // this is not defined + friend const long* rbegin(R1V&) { return nullptr; } friend const int* rbegin(const R1V& rv) noexcept { return rv.r.rbegin(); } }; // Allow ranges::end to work with R1V&& template<> constexpr bool std::ranges::enable_borrowed_range<R1V> = true; +#if __cpp_lib_ranges_as_const +struct R1VC // view on an R1 +{ + R1& r; + + friend const long* rbegin(R1VC&); // this is not defined + friend const int* rbegin(const R1VC& rv) noexcept { return rv.r.rbegin(); } + + // The following ensure that the following are satisfied: + // constant_range<const R1VC> && ! constant_range<R1VC> + friend int* begin(R1VC&); + friend int* end(R1VC&); + friend const int* begin(const R1VC&); + friend const int* end(const R1VC&); +}; + +// Allow ranges::end to work with R1VC&& +template<> constexpr bool std::ranges::enable_borrowed_range<R1VC> = true; +#endif + void test01() { @@ -53,8 +73,24 @@ test01() VERIFY( std::ranges::crbegin(c) == std::ranges::rbegin(c) ); R1V v{r}; - const R1V cv{r}; +#if ! __cpp_lib_ranges_as_const + VERIFY( std::ranges::crbegin(v) == std::ranges::rbegin(c) ); VERIFY( std::ranges::crbegin(std::move(v)) == std::ranges::rbegin(c) ); +#else + // constant_range<const R1V> is not satisfied, so crbegin(v) == rbegin(v). + VERIFY( std::ranges::crbegin(v) == (long*)nullptr ); + VERIFY( std::ranges::crbegin(std::move(v)) == (long*)nullptr ); + R1VC v2{r}; + // But constant_range<const R1VC> is satisfied: + VERIFY( std::ranges::crbegin(v2) == std::ranges::rbegin(c) ); + VERIFY( std::ranges::crbegin(std::move(v2)) == std::ranges::rbegin(c) ); + const R1VC cv2{r}; + VERIFY( std::ranges::crbegin(cv2) == std::ranges::rbegin(c) ); + VERIFY( std::ranges::crbegin(std::move(cv2)) == std::ranges::rbegin(c) ); +#endif + + const R1V cv{r}; + VERIFY( std::ranges::crbegin(cv) == std::ranges::rbegin(c) ); VERIFY( std::ranges::crbegin(std::move(cv)) == std::ranges::rbegin(c) ); } diff --git a/libstdc++-v3/testsuite/std/ranges/access/crend.cc b/libstdc++-v3/testsuite/std/ranges/access/crend.cc index a7e033f..2e4c0f3 100644 --- a/libstdc++-v3/testsuite/std/ranges/access/crend.cc +++ b/libstdc++-v3/testsuite/std/ranges/access/crend.cc @@ -86,18 +86,47 @@ struct R3 friend const int* rend(const R3& r) { return &r.i; } }; -// N.B. this is a lie, rend on an R3 rvalue will return a dangling pointer. -template<> constexpr bool std::ranges::enable_borrowed_range<R3> = true; +struct R4 +{ + int i = 0; + + // These members mean that range<R4> and range<const R4> are satisfied. + const short* begin() const { return 0; } + const short* end() const { return 0; } + + const int* rbegin() const noexcept { return &i + 1; } + const long* rend() const noexcept { return nullptr; } // not a sentinel for rbegin() + + friend const long* rbegin(const R4&) noexcept { return nullptr; } + friend const int* rend(const R4& r) { return &r.i; } +}; void test03() { R3 r; const R3& c = r; +#if ! __cpp_lib_ranges_as_const VERIFY( std::ranges::crend(r) == std::ranges::rend(c) ); static_assert( !noexcept(std::ranges::crend(r)) ); +#else + // constant_range<const R3> is not satisfied, so crend(r) is equivalent + // to const_sentinel{rend(r)}, which is ill-formed because range<R3> + // is not satisfied. + static_assert( not std::ranges::range<R3> ); + static_assert( not std::ranges::range<const R3> ); +#endif VERIFY( std::ranges::crend(c) == std::ranges::rend(c) ); static_assert( !noexcept(std::ranges::crend(c)) ); + + R4 r4; + const R4& c4 = r4; + auto b = std::ranges::rbegin(r4); + auto s0 = std::ranges::rend(r4); + static_assert( std::ranges::__access::__adl_rend<R4&> ); + auto s = std::ranges::crend(r4); + auto s2 = std::ranges::rend(c4); + // VERIFY( std::ranges::crend(r4) == std::ranges::rend(c4) ); } void diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc index 290b5c2..a1f6068 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc @@ -94,8 +94,10 @@ test05() // Verify that _Sentinel<false> is implicitly convertible to _Sentinel<true>. static_assert(!ranges::common_range<decltype(v)>); +#if ! __cpp_lib_ranges_as_const static_assert(!std::same_as<decltype(ranges::end(v)), decltype(ranges::cend(v))>); +#endif auto b = ranges::cend(v); b = ranges::end(v); } diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc index 4606077..098091e 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc @@ -64,8 +64,10 @@ test03() // Verify that _Sentinel<false> is implicitly convertible to _Sentinel<true>. static_assert(!ranges::common_range<decltype(v)>); +#if ! __cpp_lib_ranges_as_const static_assert(!std::same_as<decltype(ranges::end(v)), decltype(ranges::cend(v))>); +#endif auto b = ranges::cend(v); b = ranges::end(v); } diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc index 9d52cb0..d9801d5 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc @@ -108,16 +108,20 @@ test05() auto r = ranges::subrange{i, std::default_sentinel}; auto v = r | views::transform(std::negate{}); +#if ! __cpp_lib_ranges_as_const // Verify that _Iterator<false> is implicitly convertible to _Iterator<true>. static_assert(!std::same_as<decltype(ranges::begin(v)), decltype(ranges::cbegin(v))>); +#endif auto a = ranges::cbegin(v); a = ranges::begin(v); +#if ! __cpp_lib_ranges_as_const // Verify that _Sentinel<false> is implicitly convertible to _Sentinel<true>. static_assert(!ranges::common_range<decltype(v)>); static_assert(!std::same_as<decltype(ranges::end(v)), decltype(ranges::cend(v))>); +#endif auto b = ranges::cend(v); b = ranges::end(v); } |