155bd22f8SKonstantin Varlamov //===----------------------------------------------------------------------===//
255bd22f8SKonstantin Varlamov //
355bd22f8SKonstantin Varlamov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
455bd22f8SKonstantin Varlamov // See https://llvm.org/LICENSE.txt for license information.
555bd22f8SKonstantin Varlamov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
655bd22f8SKonstantin Varlamov //
755bd22f8SKonstantin Varlamov //===----------------------------------------------------------------------===//
855bd22f8SKonstantin Varlamov
955bd22f8SKonstantin Varlamov // UNSUPPORTED: c++03, c++11, c++14, c++17
1055bd22f8SKonstantin Varlamov
1155bd22f8SKonstantin Varlamov // std::ranges::rend
1255bd22f8SKonstantin Varlamov // std::ranges::crend
1355bd22f8SKonstantin Varlamov
1455bd22f8SKonstantin Varlamov #include <ranges>
1555bd22f8SKonstantin Varlamov
1655bd22f8SKonstantin Varlamov #include <cassert>
1755bd22f8SKonstantin Varlamov #include <utility>
1855bd22f8SKonstantin Varlamov #include "test_macros.h"
1955bd22f8SKonstantin Varlamov #include "test_iterators.h"
2055bd22f8SKonstantin Varlamov
2155bd22f8SKonstantin Varlamov using RangeREndT = decltype(std::ranges::rend);
2255bd22f8SKonstantin Varlamov using RangeCREndT = decltype(std::ranges::crend);
2355bd22f8SKonstantin Varlamov
2455bd22f8SKonstantin Varlamov static int globalBuff[8];
2555bd22f8SKonstantin Varlamov
2655bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, int (&&)[]>);
2755bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, int (&)[]>);
2855bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, int (&&)[10]>);
2955bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeREndT, int (&)[10]>);
3055bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCREndT, int (&&)[]>);
3155bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCREndT, int (&)[]>);
3255bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCREndT, int (&&)[10]>);
3355bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeCREndT, int (&)[10]>);
3455bd22f8SKonstantin Varlamov
3555bd22f8SKonstantin Varlamov struct Incomplete;
3655bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, Incomplete(&&)[]>);
3755bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, Incomplete(&&)[42]>);
3855bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCREndT, Incomplete(&&)[]>);
3955bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCREndT, Incomplete(&&)[42]>);
4055bd22f8SKonstantin Varlamov
4155bd22f8SKonstantin Varlamov struct REndMember {
4255bd22f8SKonstantin Varlamov int x;
4355bd22f8SKonstantin Varlamov const int* rbegin() const;
rendREndMember4455bd22f8SKonstantin Varlamov constexpr const int* rend() const { return &x; }
4555bd22f8SKonstantin Varlamov };
4655bd22f8SKonstantin Varlamov
4755bd22f8SKonstantin Varlamov // Ensure that we can't call with rvalues with borrowing disabled.
4855bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeREndT, REndMember&>);
4955bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, REndMember &&>);
5055bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeREndT, REndMember const&>);
5155bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, REndMember const&&>);
5255bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeCREndT, REndMember &>);
5355bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCREndT, REndMember &&>);
5455bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeCREndT, REndMember const&>);
5555bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCREndT, REndMember const&&>);
5655bd22f8SKonstantin Varlamov
testReturnTypes()5755bd22f8SKonstantin Varlamov constexpr bool testReturnTypes() {
5855bd22f8SKonstantin Varlamov {
5955bd22f8SKonstantin Varlamov int *x[2];
6055bd22f8SKonstantin Varlamov ASSERT_SAME_TYPE(decltype(std::ranges::rend(x)), std::reverse_iterator<int**>);
6155bd22f8SKonstantin Varlamov ASSERT_SAME_TYPE(decltype(std::ranges::crend(x)), std::reverse_iterator<int* const*>);
6255bd22f8SKonstantin Varlamov }
6355bd22f8SKonstantin Varlamov
6455bd22f8SKonstantin Varlamov {
6555bd22f8SKonstantin Varlamov int x[2][2];
6655bd22f8SKonstantin Varlamov ASSERT_SAME_TYPE(decltype(std::ranges::rend(x)), std::reverse_iterator<int(*)[2]>);
6755bd22f8SKonstantin Varlamov ASSERT_SAME_TYPE(decltype(std::ranges::crend(x)), std::reverse_iterator<const int(*)[2]>);
6855bd22f8SKonstantin Varlamov }
6955bd22f8SKonstantin Varlamov
7055bd22f8SKonstantin Varlamov {
7155bd22f8SKonstantin Varlamov struct Different {
7255bd22f8SKonstantin Varlamov char* rbegin();
7355bd22f8SKonstantin Varlamov sentinel_wrapper<char*>& rend();
7455bd22f8SKonstantin Varlamov short* rbegin() const;
7555bd22f8SKonstantin Varlamov sentinel_wrapper<short*>& rend() const;
7655bd22f8SKonstantin Varlamov } x;
7755bd22f8SKonstantin Varlamov ASSERT_SAME_TYPE(decltype(std::ranges::rend(x)), sentinel_wrapper<char*>);
7855bd22f8SKonstantin Varlamov ASSERT_SAME_TYPE(decltype(std::ranges::crend(x)), sentinel_wrapper<short*>);
7955bd22f8SKonstantin Varlamov }
8055bd22f8SKonstantin Varlamov
8155bd22f8SKonstantin Varlamov return true;
8255bd22f8SKonstantin Varlamov }
8355bd22f8SKonstantin Varlamov
testArray()8455bd22f8SKonstantin Varlamov constexpr bool testArray() {
8555bd22f8SKonstantin Varlamov int a[2];
8655bd22f8SKonstantin Varlamov assert(std::ranges::rend(a).base() == a);
8755bd22f8SKonstantin Varlamov assert(std::ranges::crend(a).base() == a);
8855bd22f8SKonstantin Varlamov
8955bd22f8SKonstantin Varlamov int b[2][2];
9055bd22f8SKonstantin Varlamov assert(std::ranges::rend(b).base() == b);
9155bd22f8SKonstantin Varlamov assert(std::ranges::crend(b).base() == b);
9255bd22f8SKonstantin Varlamov
9355bd22f8SKonstantin Varlamov REndMember c[2];
9455bd22f8SKonstantin Varlamov assert(std::ranges::rend(c).base() == c);
9555bd22f8SKonstantin Varlamov assert(std::ranges::crend(c).base() == c);
9655bd22f8SKonstantin Varlamov
9755bd22f8SKonstantin Varlamov return true;
9855bd22f8SKonstantin Varlamov }
9955bd22f8SKonstantin Varlamov
10055bd22f8SKonstantin Varlamov struct REndMemberReturnsInt {
10155bd22f8SKonstantin Varlamov int rbegin() const;
10255bd22f8SKonstantin Varlamov int rend() const;
10355bd22f8SKonstantin Varlamov };
10455bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, REndMemberReturnsInt const&>);
10555bd22f8SKonstantin Varlamov
10655bd22f8SKonstantin Varlamov struct REndMemberReturnsVoidPtr {
10755bd22f8SKonstantin Varlamov const void *rbegin() const;
10855bd22f8SKonstantin Varlamov const void *rend() const;
10955bd22f8SKonstantin Varlamov };
11055bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, REndMemberReturnsVoidPtr const&>);
11155bd22f8SKonstantin Varlamov
11255bd22f8SKonstantin Varlamov struct PtrConvertible {
11355bd22f8SKonstantin Varlamov operator int*() const;
11455bd22f8SKonstantin Varlamov };
11555bd22f8SKonstantin Varlamov struct PtrConvertibleREndMember {
11655bd22f8SKonstantin Varlamov PtrConvertible rbegin() const;
11755bd22f8SKonstantin Varlamov PtrConvertible rend() const;
11855bd22f8SKonstantin Varlamov };
11955bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, PtrConvertibleREndMember const&>);
12055bd22f8SKonstantin Varlamov
12155bd22f8SKonstantin Varlamov struct NoRBeginMember {
12255bd22f8SKonstantin Varlamov constexpr const int* rend();
12355bd22f8SKonstantin Varlamov };
12455bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, NoRBeginMember const&>);
12555bd22f8SKonstantin Varlamov
12655bd22f8SKonstantin Varlamov struct NonConstREndMember {
12755bd22f8SKonstantin Varlamov int x;
rbeginNonConstREndMember12855bd22f8SKonstantin Varlamov constexpr int* rbegin() { return nullptr; }
rendNonConstREndMember12955bd22f8SKonstantin Varlamov constexpr int* rend() { return &x; }
13055bd22f8SKonstantin Varlamov };
13155bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeREndT, NonConstREndMember &>);
13255bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, NonConstREndMember const&>);
13355bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCREndT, NonConstREndMember &>);
13455bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCREndT, NonConstREndMember const&>);
13555bd22f8SKonstantin Varlamov
13655bd22f8SKonstantin Varlamov struct EnabledBorrowingREndMember {
rbeginEnabledBorrowingREndMember13755bd22f8SKonstantin Varlamov constexpr int* rbegin() const { return nullptr; }
rendEnabledBorrowingREndMember13855bd22f8SKonstantin Varlamov constexpr int* rend() const { return &globalBuff[0]; }
13955bd22f8SKonstantin Varlamov };
14055bd22f8SKonstantin Varlamov
14155bd22f8SKonstantin Varlamov template <>
14255bd22f8SKonstantin Varlamov inline constexpr bool std::ranges::enable_borrowed_range<EnabledBorrowingREndMember> = true;
14355bd22f8SKonstantin Varlamov
14455bd22f8SKonstantin Varlamov struct REndMemberFunction {
14555bd22f8SKonstantin Varlamov int x;
rbeginREndMemberFunction14655bd22f8SKonstantin Varlamov constexpr const int* rbegin() const { return nullptr; }
rendREndMemberFunction14755bd22f8SKonstantin Varlamov constexpr const int* rend() const { return &x; }
14855bd22f8SKonstantin Varlamov friend constexpr int* rend(REndMemberFunction const&);
14955bd22f8SKonstantin Varlamov };
15055bd22f8SKonstantin Varlamov
15155bd22f8SKonstantin Varlamov struct Empty { };
15255bd22f8SKonstantin Varlamov struct EmptyEndMember {
15355bd22f8SKonstantin Varlamov Empty rbegin() const;
15455bd22f8SKonstantin Varlamov Empty rend() const;
15555bd22f8SKonstantin Varlamov };
15655bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, EmptyEndMember const&>);
15755bd22f8SKonstantin Varlamov
15855bd22f8SKonstantin Varlamov struct EmptyPtrREndMember {
15955bd22f8SKonstantin Varlamov Empty x;
rbeginEmptyPtrREndMember16055bd22f8SKonstantin Varlamov constexpr const Empty* rbegin() const { return nullptr; }
rendEmptyPtrREndMember16155bd22f8SKonstantin Varlamov constexpr const Empty* rend() const { return &x; }
16255bd22f8SKonstantin Varlamov };
16355bd22f8SKonstantin Varlamov
testREndMember()16455bd22f8SKonstantin Varlamov constexpr bool testREndMember() {
16555bd22f8SKonstantin Varlamov REndMember a;
16655bd22f8SKonstantin Varlamov assert(std::ranges::rend(a) == &a.x);
16755bd22f8SKonstantin Varlamov assert(std::ranges::crend(a) == &a.x);
16855bd22f8SKonstantin Varlamov
16955bd22f8SKonstantin Varlamov NonConstREndMember b;
17055bd22f8SKonstantin Varlamov assert(std::ranges::rend(b) == &b.x);
17155bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCREndT, decltype((b))>);
17255bd22f8SKonstantin Varlamov
17355bd22f8SKonstantin Varlamov EnabledBorrowingREndMember c;
17455bd22f8SKonstantin Varlamov assert(std::ranges::rend(std::move(c)) == &globalBuff[0]);
17555bd22f8SKonstantin Varlamov assert(std::ranges::crend(std::move(c)) == &globalBuff[0]);
17655bd22f8SKonstantin Varlamov
17755bd22f8SKonstantin Varlamov REndMemberFunction d;
17855bd22f8SKonstantin Varlamov assert(std::ranges::rend(d) == &d.x);
17955bd22f8SKonstantin Varlamov assert(std::ranges::crend(d) == &d.x);
18055bd22f8SKonstantin Varlamov
18155bd22f8SKonstantin Varlamov EmptyPtrREndMember e;
18255bd22f8SKonstantin Varlamov assert(std::ranges::rend(e) == &e.x);
18355bd22f8SKonstantin Varlamov assert(std::ranges::crend(e) == &e.x);
18455bd22f8SKonstantin Varlamov
18555bd22f8SKonstantin Varlamov return true;
18655bd22f8SKonstantin Varlamov }
18755bd22f8SKonstantin Varlamov
18855bd22f8SKonstantin Varlamov struct REndFunction {
18955bd22f8SKonstantin Varlamov int x;
rbegin(REndFunction const &)19055bd22f8SKonstantin Varlamov friend constexpr const int* rbegin(REndFunction const&) { return nullptr; }
rend(REndFunction const & bf)19155bd22f8SKonstantin Varlamov friend constexpr const int* rend(REndFunction const& bf) { return &bf.x; }
19255bd22f8SKonstantin Varlamov };
19355bd22f8SKonstantin Varlamov
19455bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeREndT, REndFunction const&>);
19555bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, REndFunction &&>);
19655bd22f8SKonstantin Varlamov
19755bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeREndT, REndFunction const&>);
19855bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, REndFunction &&>);
199*12978b3eSJakub Mazurkiewicz static_assert(std::is_invocable_v<RangeREndT, REndFunction&>); // Ill-formed before P2602R2 Poison Pills are Too Toxic
20055bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeCREndT, REndFunction const&>);
20155bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeCREndT, REndFunction &>);
20255bd22f8SKonstantin Varlamov
20355bd22f8SKonstantin Varlamov struct REndFunctionReturnsInt {
20455bd22f8SKonstantin Varlamov friend constexpr int rbegin(REndFunctionReturnsInt const&);
20555bd22f8SKonstantin Varlamov friend constexpr int rend(REndFunctionReturnsInt const&);
20655bd22f8SKonstantin Varlamov };
20755bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, REndFunctionReturnsInt const&>);
20855bd22f8SKonstantin Varlamov
20955bd22f8SKonstantin Varlamov struct REndFunctionReturnsVoidPtr {
21055bd22f8SKonstantin Varlamov friend constexpr void* rbegin(REndFunctionReturnsVoidPtr const&);
21155bd22f8SKonstantin Varlamov friend constexpr void* rend(REndFunctionReturnsVoidPtr const&);
21255bd22f8SKonstantin Varlamov };
21355bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, REndFunctionReturnsVoidPtr const&>);
21455bd22f8SKonstantin Varlamov
21555bd22f8SKonstantin Varlamov struct REndFunctionReturnsEmpty {
21655bd22f8SKonstantin Varlamov friend constexpr Empty rbegin(REndFunctionReturnsEmpty const&);
21755bd22f8SKonstantin Varlamov friend constexpr Empty rend(REndFunctionReturnsEmpty const&);
21855bd22f8SKonstantin Varlamov };
21955bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, REndFunctionReturnsEmpty const&>);
22055bd22f8SKonstantin Varlamov
22155bd22f8SKonstantin Varlamov struct REndFunctionReturnsPtrConvertible {
22255bd22f8SKonstantin Varlamov friend constexpr PtrConvertible rbegin(REndFunctionReturnsPtrConvertible const&);
22355bd22f8SKonstantin Varlamov friend constexpr PtrConvertible rend(REndFunctionReturnsPtrConvertible const&);
22455bd22f8SKonstantin Varlamov };
22555bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, REndFunctionReturnsPtrConvertible const&>);
22655bd22f8SKonstantin Varlamov
22755bd22f8SKonstantin Varlamov struct NoRBeginFunction {
22855bd22f8SKonstantin Varlamov friend constexpr const int* rend(NoRBeginFunction const&);
22955bd22f8SKonstantin Varlamov };
23055bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, NoRBeginFunction const&>);
23155bd22f8SKonstantin Varlamov
23255bd22f8SKonstantin Varlamov struct REndFunctionByValue {
rbegin(REndFunctionByValue)23355bd22f8SKonstantin Varlamov friend constexpr int* rbegin(REndFunctionByValue) { return nullptr; }
rend(REndFunctionByValue)23455bd22f8SKonstantin Varlamov friend constexpr int* rend(REndFunctionByValue) { return &globalBuff[1]; }
23555bd22f8SKonstantin Varlamov };
23655bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCREndT, REndFunctionByValue>);
23755bd22f8SKonstantin Varlamov
23855bd22f8SKonstantin Varlamov struct REndFunctionEnabledBorrowing {
rbegin(REndFunctionEnabledBorrowing)23955bd22f8SKonstantin Varlamov friend constexpr int* rbegin(REndFunctionEnabledBorrowing) { return nullptr; }
rend(REndFunctionEnabledBorrowing)24055bd22f8SKonstantin Varlamov friend constexpr int* rend(REndFunctionEnabledBorrowing) { return &globalBuff[2]; }
24155bd22f8SKonstantin Varlamov };
24255bd22f8SKonstantin Varlamov template<>
24355bd22f8SKonstantin Varlamov inline constexpr bool std::ranges::enable_borrowed_range<REndFunctionEnabledBorrowing> = true;
24455bd22f8SKonstantin Varlamov
24555bd22f8SKonstantin Varlamov struct REndFunctionReturnsEmptyPtr {
24655bd22f8SKonstantin Varlamov Empty x;
rbegin(REndFunctionReturnsEmptyPtr const &)24755bd22f8SKonstantin Varlamov friend constexpr const Empty* rbegin(REndFunctionReturnsEmptyPtr const&) { return nullptr; }
rend(REndFunctionReturnsEmptyPtr const & bf)24855bd22f8SKonstantin Varlamov friend constexpr const Empty* rend(REndFunctionReturnsEmptyPtr const& bf) { return &bf.x; }
24955bd22f8SKonstantin Varlamov };
25055bd22f8SKonstantin Varlamov
25155bd22f8SKonstantin Varlamov struct REndFunctionWithDataMember {
25255bd22f8SKonstantin Varlamov int x;
25355bd22f8SKonstantin Varlamov int rend;
rbegin(REndFunctionWithDataMember const &)25455bd22f8SKonstantin Varlamov friend constexpr const int* rbegin(REndFunctionWithDataMember const&) { return nullptr; }
rend(REndFunctionWithDataMember const & bf)25555bd22f8SKonstantin Varlamov friend constexpr const int* rend(REndFunctionWithDataMember const& bf) { return &bf.x; }
25655bd22f8SKonstantin Varlamov };
25755bd22f8SKonstantin Varlamov
25855bd22f8SKonstantin Varlamov struct REndFunctionWithPrivateEndMember : private REndMember {
25955bd22f8SKonstantin Varlamov int y;
rbegin(REndFunctionWithPrivateEndMember const &)26055bd22f8SKonstantin Varlamov friend constexpr const int* rbegin(REndFunctionWithPrivateEndMember const&) { return nullptr; }
rend(REndFunctionWithPrivateEndMember const & bf)26155bd22f8SKonstantin Varlamov friend constexpr const int* rend(REndFunctionWithPrivateEndMember const& bf) { return &bf.y; }
26255bd22f8SKonstantin Varlamov };
26355bd22f8SKonstantin Varlamov
26455bd22f8SKonstantin Varlamov struct RBeginMemberEndFunction {
26555bd22f8SKonstantin Varlamov int x;
rbeginRBeginMemberEndFunction26655bd22f8SKonstantin Varlamov constexpr const int* rbegin() const { return nullptr; }
rend(RBeginMemberEndFunction const & bf)26755bd22f8SKonstantin Varlamov friend constexpr const int* rend(RBeginMemberEndFunction const& bf) { return &bf.x; }
26855bd22f8SKonstantin Varlamov };
26955bd22f8SKonstantin Varlamov
testREndFunction()27055bd22f8SKonstantin Varlamov constexpr bool testREndFunction() {
27155bd22f8SKonstantin Varlamov const REndFunction a{};
27255bd22f8SKonstantin Varlamov assert(std::ranges::rend(a) == &a.x);
27355bd22f8SKonstantin Varlamov assert(std::ranges::crend(a) == &a.x);
27455bd22f8SKonstantin Varlamov REndFunction aa{};
275*12978b3eSJakub Mazurkiewicz assert(std::ranges::rend(aa) == &aa.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
27655bd22f8SKonstantin Varlamov assert(std::ranges::crend(aa) == &aa.x);
27755bd22f8SKonstantin Varlamov
27855bd22f8SKonstantin Varlamov REndFunctionByValue b;
27955bd22f8SKonstantin Varlamov assert(std::ranges::rend(b) == &globalBuff[1]);
28055bd22f8SKonstantin Varlamov assert(std::ranges::crend(b) == &globalBuff[1]);
28155bd22f8SKonstantin Varlamov
28255bd22f8SKonstantin Varlamov REndFunctionEnabledBorrowing c;
28355bd22f8SKonstantin Varlamov assert(std::ranges::rend(std::move(c)) == &globalBuff[2]);
28455bd22f8SKonstantin Varlamov assert(std::ranges::crend(std::move(c)) == &globalBuff[2]);
28555bd22f8SKonstantin Varlamov
28655bd22f8SKonstantin Varlamov const REndFunctionReturnsEmptyPtr d{};
28755bd22f8SKonstantin Varlamov assert(std::ranges::rend(d) == &d.x);
28855bd22f8SKonstantin Varlamov assert(std::ranges::crend(d) == &d.x);
28955bd22f8SKonstantin Varlamov REndFunctionReturnsEmptyPtr dd{};
290*12978b3eSJakub Mazurkiewicz assert(std::ranges::rend(dd) == &dd.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
29155bd22f8SKonstantin Varlamov assert(std::ranges::crend(dd) == &dd.x);
29255bd22f8SKonstantin Varlamov
29355bd22f8SKonstantin Varlamov const REndFunctionWithDataMember e{};
29455bd22f8SKonstantin Varlamov assert(std::ranges::rend(e) == &e.x);
29555bd22f8SKonstantin Varlamov assert(std::ranges::crend(e) == &e.x);
29655bd22f8SKonstantin Varlamov REndFunctionWithDataMember ee{};
297*12978b3eSJakub Mazurkiewicz assert(std::ranges::rend(ee) == &ee.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
29855bd22f8SKonstantin Varlamov assert(std::ranges::crend(ee) == &ee.x);
29955bd22f8SKonstantin Varlamov
30055bd22f8SKonstantin Varlamov const REndFunctionWithPrivateEndMember f{};
30155bd22f8SKonstantin Varlamov assert(std::ranges::rend(f) == &f.y);
30255bd22f8SKonstantin Varlamov assert(std::ranges::crend(f) == &f.y);
30355bd22f8SKonstantin Varlamov REndFunctionWithPrivateEndMember ff{};
304*12978b3eSJakub Mazurkiewicz assert(std::ranges::rend(ff) == &ff.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic
30555bd22f8SKonstantin Varlamov assert(std::ranges::crend(ff) == &ff.y);
30655bd22f8SKonstantin Varlamov
30755bd22f8SKonstantin Varlamov const RBeginMemberEndFunction g{};
30855bd22f8SKonstantin Varlamov assert(std::ranges::rend(g) == &g.x);
30955bd22f8SKonstantin Varlamov assert(std::ranges::crend(g) == &g.x);
31055bd22f8SKonstantin Varlamov RBeginMemberEndFunction gg{};
311*12978b3eSJakub Mazurkiewicz assert(std::ranges::rend(gg) == &gg.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
31255bd22f8SKonstantin Varlamov assert(std::ranges::crend(gg) == &gg.x);
31355bd22f8SKonstantin Varlamov
31455bd22f8SKonstantin Varlamov return true;
31555bd22f8SKonstantin Varlamov }
31655bd22f8SKonstantin Varlamov
31755bd22f8SKonstantin Varlamov
31855bd22f8SKonstantin Varlamov struct MemberBeginEnd {
31955bd22f8SKonstantin Varlamov int b, e;
32055bd22f8SKonstantin Varlamov char cb, ce;
beginMemberBeginEnd32155bd22f8SKonstantin Varlamov constexpr bidirectional_iterator<int*> begin() { return bidirectional_iterator<int*>(&b); }
endMemberBeginEnd32255bd22f8SKonstantin Varlamov constexpr bidirectional_iterator<int*> end() { return bidirectional_iterator<int*>(&e); }
beginMemberBeginEnd32355bd22f8SKonstantin Varlamov constexpr bidirectional_iterator<const char*> begin() const { return bidirectional_iterator<const char*>(&cb); }
endMemberBeginEnd32455bd22f8SKonstantin Varlamov constexpr bidirectional_iterator<const char*> end() const { return bidirectional_iterator<const char*>(&ce); }
32555bd22f8SKonstantin Varlamov };
32655bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeREndT, MemberBeginEnd&>);
32755bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeREndT, MemberBeginEnd const&>);
32855bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeCREndT, MemberBeginEnd const&>);
32955bd22f8SKonstantin Varlamov
33055bd22f8SKonstantin Varlamov struct FunctionBeginEnd {
33155bd22f8SKonstantin Varlamov int b, e;
33255bd22f8SKonstantin Varlamov char cb, ce;
begin(FunctionBeginEnd & v)33355bd22f8SKonstantin Varlamov friend constexpr bidirectional_iterator<int*> begin(FunctionBeginEnd& v) {
33455bd22f8SKonstantin Varlamov return bidirectional_iterator<int*>(&v.b);
33555bd22f8SKonstantin Varlamov }
end(FunctionBeginEnd & v)33655bd22f8SKonstantin Varlamov friend constexpr bidirectional_iterator<int*> end(FunctionBeginEnd& v) { return bidirectional_iterator<int*>(&v.e); }
begin(const FunctionBeginEnd & v)33755bd22f8SKonstantin Varlamov friend constexpr bidirectional_iterator<const char*> begin(const FunctionBeginEnd& v) {
33855bd22f8SKonstantin Varlamov return bidirectional_iterator<const char*>(&v.cb);
33955bd22f8SKonstantin Varlamov }
end(const FunctionBeginEnd & v)34055bd22f8SKonstantin Varlamov friend constexpr bidirectional_iterator<const char*> end(const FunctionBeginEnd& v) {
34155bd22f8SKonstantin Varlamov return bidirectional_iterator<const char*>(&v.ce);
34255bd22f8SKonstantin Varlamov }
34355bd22f8SKonstantin Varlamov };
34455bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeREndT, FunctionBeginEnd&>);
34555bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeREndT, FunctionBeginEnd const&>);
34655bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeCREndT, FunctionBeginEnd const&>);
34755bd22f8SKonstantin Varlamov
34855bd22f8SKonstantin Varlamov struct MemberBeginFunctionEnd {
34955bd22f8SKonstantin Varlamov int b, e;
35055bd22f8SKonstantin Varlamov char cb, ce;
beginMemberBeginFunctionEnd35155bd22f8SKonstantin Varlamov constexpr bidirectional_iterator<int*> begin() { return bidirectional_iterator<int*>(&b); }
end(MemberBeginFunctionEnd & v)35255bd22f8SKonstantin Varlamov friend constexpr bidirectional_iterator<int*> end(MemberBeginFunctionEnd& v) {
35355bd22f8SKonstantin Varlamov return bidirectional_iterator<int*>(&v.e);
35455bd22f8SKonstantin Varlamov }
beginMemberBeginFunctionEnd35555bd22f8SKonstantin Varlamov constexpr bidirectional_iterator<const char*> begin() const { return bidirectional_iterator<const char*>(&cb); }
end(const MemberBeginFunctionEnd & v)35655bd22f8SKonstantin Varlamov friend constexpr bidirectional_iterator<const char*> end(const MemberBeginFunctionEnd& v) {
35755bd22f8SKonstantin Varlamov return bidirectional_iterator<const char*>(&v.ce);
35855bd22f8SKonstantin Varlamov }
35955bd22f8SKonstantin Varlamov };
36055bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeREndT, MemberBeginFunctionEnd&>);
36155bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeREndT, MemberBeginFunctionEnd const&>);
36255bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeCREndT, MemberBeginFunctionEnd const&>);
36355bd22f8SKonstantin Varlamov
36455bd22f8SKonstantin Varlamov struct FunctionBeginMemberEnd {
36555bd22f8SKonstantin Varlamov int b, e;
36655bd22f8SKonstantin Varlamov char cb, ce;
begin(FunctionBeginMemberEnd & v)36755bd22f8SKonstantin Varlamov friend constexpr bidirectional_iterator<int*> begin(FunctionBeginMemberEnd& v) {
36855bd22f8SKonstantin Varlamov return bidirectional_iterator<int*>(&v.b);
36955bd22f8SKonstantin Varlamov }
endFunctionBeginMemberEnd37055bd22f8SKonstantin Varlamov constexpr bidirectional_iterator<int*> end() { return bidirectional_iterator<int*>(&e); }
begin(const FunctionBeginMemberEnd & v)37155bd22f8SKonstantin Varlamov friend constexpr bidirectional_iterator<const char*> begin(const FunctionBeginMemberEnd& v) {
37255bd22f8SKonstantin Varlamov return bidirectional_iterator<const char*>(&v.cb);
37355bd22f8SKonstantin Varlamov }
endFunctionBeginMemberEnd37455bd22f8SKonstantin Varlamov constexpr bidirectional_iterator<const char*> end() const { return bidirectional_iterator<const char*>(&ce); }
37555bd22f8SKonstantin Varlamov };
37655bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeREndT, FunctionBeginMemberEnd&>);
37755bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeREndT, FunctionBeginMemberEnd const&>);
37855bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeCREndT, FunctionBeginMemberEnd const&>);
37955bd22f8SKonstantin Varlamov
38055bd22f8SKonstantin Varlamov struct MemberBeginEndDifferentTypes {
38155bd22f8SKonstantin Varlamov bidirectional_iterator<int*> begin();
38255bd22f8SKonstantin Varlamov bidirectional_iterator<const int*> end();
38355bd22f8SKonstantin Varlamov };
38455bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, MemberBeginEndDifferentTypes&>);
38555bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCREndT, MemberBeginEndDifferentTypes&>);
38655bd22f8SKonstantin Varlamov
38755bd22f8SKonstantin Varlamov struct FunctionBeginEndDifferentTypes {
38855bd22f8SKonstantin Varlamov friend bidirectional_iterator<int*> begin(FunctionBeginEndDifferentTypes&);
38955bd22f8SKonstantin Varlamov friend bidirectional_iterator<const int*> end(FunctionBeginEndDifferentTypes&);
39055bd22f8SKonstantin Varlamov };
39155bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, FunctionBeginEndDifferentTypes&>);
39255bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCREndT, FunctionBeginEndDifferentTypes&>);
39355bd22f8SKonstantin Varlamov
39455bd22f8SKonstantin Varlamov struct MemberBeginEndForwardIterators {
39555bd22f8SKonstantin Varlamov forward_iterator<int*> begin();
39655bd22f8SKonstantin Varlamov forward_iterator<int*> end();
39755bd22f8SKonstantin Varlamov };
39855bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, MemberBeginEndForwardIterators&>);
39955bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCREndT, MemberBeginEndForwardIterators&>);
40055bd22f8SKonstantin Varlamov
40155bd22f8SKonstantin Varlamov struct FunctionBeginEndForwardIterators {
40255bd22f8SKonstantin Varlamov friend forward_iterator<int*> begin(FunctionBeginEndForwardIterators&);
40355bd22f8SKonstantin Varlamov friend forward_iterator<int*> end(FunctionBeginEndForwardIterators&);
40455bd22f8SKonstantin Varlamov };
40555bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, FunctionBeginEndForwardIterators&>);
40655bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCREndT, FunctionBeginEndForwardIterators&>);
40755bd22f8SKonstantin Varlamov
40855bd22f8SKonstantin Varlamov struct MemberBeginOnly {
40955bd22f8SKonstantin Varlamov bidirectional_iterator<int*> begin() const;
41055bd22f8SKonstantin Varlamov };
41155bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, MemberBeginOnly&>);
41255bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCREndT, MemberBeginOnly&>);
41355bd22f8SKonstantin Varlamov
41455bd22f8SKonstantin Varlamov struct FunctionBeginOnly {
41555bd22f8SKonstantin Varlamov friend bidirectional_iterator<int*> begin(FunctionBeginOnly&);
41655bd22f8SKonstantin Varlamov };
41755bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, FunctionBeginOnly&>);
41855bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCREndT, FunctionBeginOnly&>);
41955bd22f8SKonstantin Varlamov
42055bd22f8SKonstantin Varlamov struct MemberEndOnly {
42155bd22f8SKonstantin Varlamov bidirectional_iterator<int*> end() const;
42255bd22f8SKonstantin Varlamov };
42355bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, MemberEndOnly&>);
42455bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCREndT, MemberEndOnly&>);
42555bd22f8SKonstantin Varlamov
42655bd22f8SKonstantin Varlamov struct FunctionEndOnly {
42755bd22f8SKonstantin Varlamov friend bidirectional_iterator<int*> end(FunctionEndOnly&);
42855bd22f8SKonstantin Varlamov };
42955bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, FunctionEndOnly&>);
43055bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCREndT, FunctionEndOnly&>);
43155bd22f8SKonstantin Varlamov
43255bd22f8SKonstantin Varlamov // Make sure there is no clash between the following cases:
43355bd22f8SKonstantin Varlamov // - the case that handles classes defining member `rbegin` and `rend` functions;
43455bd22f8SKonstantin Varlamov // - the case that handles classes defining `begin` and `end` functions returning reversible iterators.
43555bd22f8SKonstantin Varlamov struct MemberBeginAndRBegin {
43655bd22f8SKonstantin Varlamov int* begin() const;
43755bd22f8SKonstantin Varlamov int* end() const;
43855bd22f8SKonstantin Varlamov int* rbegin() const;
43955bd22f8SKonstantin Varlamov int* rend() const;
44055bd22f8SKonstantin Varlamov };
44155bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeREndT, MemberBeginAndRBegin&>);
44255bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeCREndT, MemberBeginAndRBegin&>);
44355bd22f8SKonstantin Varlamov static_assert( std::same_as<std::invoke_result_t<RangeREndT, MemberBeginAndRBegin&>, int*>);
44455bd22f8SKonstantin Varlamov static_assert( std::same_as<std::invoke_result_t<RangeCREndT, MemberBeginAndRBegin&>, int*>);
44555bd22f8SKonstantin Varlamov
testBeginEnd()44655bd22f8SKonstantin Varlamov constexpr bool testBeginEnd() {
44755bd22f8SKonstantin Varlamov MemberBeginEnd a{};
44855bd22f8SKonstantin Varlamov const MemberBeginEnd aa{};
4495f26d863SMark de Wever assert(base(std::ranges::rend(a).base()) == &a.b);
4505f26d863SMark de Wever assert(base(std::ranges::crend(a).base()) == &a.cb);
4515f26d863SMark de Wever assert(base(std::ranges::rend(aa).base()) == &aa.cb);
4525f26d863SMark de Wever assert(base(std::ranges::crend(aa).base()) == &aa.cb);
45355bd22f8SKonstantin Varlamov
45455bd22f8SKonstantin Varlamov FunctionBeginEnd b{};
45555bd22f8SKonstantin Varlamov const FunctionBeginEnd bb{};
4565f26d863SMark de Wever assert(base(std::ranges::rend(b).base()) == &b.b);
4575f26d863SMark de Wever assert(base(std::ranges::crend(b).base()) == &b.cb);
4585f26d863SMark de Wever assert(base(std::ranges::rend(bb).base()) == &bb.cb);
4595f26d863SMark de Wever assert(base(std::ranges::crend(bb).base()) == &bb.cb);
46055bd22f8SKonstantin Varlamov
46155bd22f8SKonstantin Varlamov MemberBeginFunctionEnd c{};
46255bd22f8SKonstantin Varlamov const MemberBeginFunctionEnd cc{};
4635f26d863SMark de Wever assert(base(std::ranges::rend(c).base()) == &c.b);
4645f26d863SMark de Wever assert(base(std::ranges::crend(c).base()) == &c.cb);
4655f26d863SMark de Wever assert(base(std::ranges::rend(cc).base()) == &cc.cb);
4665f26d863SMark de Wever assert(base(std::ranges::crend(cc).base()) == &cc.cb);
46755bd22f8SKonstantin Varlamov
46855bd22f8SKonstantin Varlamov FunctionBeginMemberEnd d{};
46955bd22f8SKonstantin Varlamov const FunctionBeginMemberEnd dd{};
4705f26d863SMark de Wever assert(base(std::ranges::rend(d).base()) == &d.b);
4715f26d863SMark de Wever assert(base(std::ranges::crend(d).base()) == &d.cb);
4725f26d863SMark de Wever assert(base(std::ranges::rend(dd).base()) == &dd.cb);
4735f26d863SMark de Wever assert(base(std::ranges::crend(dd).base()) == &dd.cb);
47455bd22f8SKonstantin Varlamov
47555bd22f8SKonstantin Varlamov return true;
47655bd22f8SKonstantin Varlamov }
47755bd22f8SKonstantin Varlamov
47855bd22f8SKonstantin Varlamov
47955bd22f8SKonstantin Varlamov ASSERT_NOEXCEPT(std::ranges::rend(std::declval<int (&)[10]>()));
48055bd22f8SKonstantin Varlamov ASSERT_NOEXCEPT(std::ranges::crend(std::declval<int (&)[10]>()));
48155bd22f8SKonstantin Varlamov
48255bd22f8SKonstantin Varlamov struct NoThrowMemberREnd {
48355bd22f8SKonstantin Varlamov ThrowingIterator<int> rbegin() const;
48455bd22f8SKonstantin Varlamov ThrowingIterator<int> rend() const noexcept; // auto(t.rend()) doesn't throw
48555bd22f8SKonstantin Varlamov } ntmre;
48655bd22f8SKonstantin Varlamov static_assert(noexcept(std::ranges::rend(ntmre)));
48755bd22f8SKonstantin Varlamov static_assert(noexcept(std::ranges::crend(ntmre)));
48855bd22f8SKonstantin Varlamov
48955bd22f8SKonstantin Varlamov struct NoThrowADLREnd {
49055bd22f8SKonstantin Varlamov ThrowingIterator<int> rbegin() const;
49155bd22f8SKonstantin Varlamov friend ThrowingIterator<int> rend(NoThrowADLREnd&) noexcept; // auto(rend(t)) doesn't throw
49255bd22f8SKonstantin Varlamov friend ThrowingIterator<int> rend(const NoThrowADLREnd&) noexcept;
49355bd22f8SKonstantin Varlamov } ntare;
49455bd22f8SKonstantin Varlamov static_assert(noexcept(std::ranges::rend(ntare)));
49555bd22f8SKonstantin Varlamov static_assert(noexcept(std::ranges::crend(ntare)));
49655bd22f8SKonstantin Varlamov
49755bd22f8SKonstantin Varlamov struct NoThrowMemberREndReturnsRef {
49855bd22f8SKonstantin Varlamov ThrowingIterator<int> rbegin() const;
49955bd22f8SKonstantin Varlamov ThrowingIterator<int>& rend() const noexcept; // auto(t.rend()) may throw
50055bd22f8SKonstantin Varlamov } ntmrerr;
50155bd22f8SKonstantin Varlamov static_assert(!noexcept(std::ranges::rend(ntmrerr)));
50255bd22f8SKonstantin Varlamov static_assert(!noexcept(std::ranges::crend(ntmrerr)));
50355bd22f8SKonstantin Varlamov
50455bd22f8SKonstantin Varlamov struct REndReturnsArrayRef {
50555bd22f8SKonstantin Varlamov auto rbegin() const noexcept -> int(&)[10];
50655bd22f8SKonstantin Varlamov auto rend() const noexcept -> int(&)[10];
50755bd22f8SKonstantin Varlamov } rerar;
50855bd22f8SKonstantin Varlamov static_assert(noexcept(std::ranges::rend(rerar)));
50955bd22f8SKonstantin Varlamov static_assert(noexcept(std::ranges::crend(rerar)));
51055bd22f8SKonstantin Varlamov
51155bd22f8SKonstantin Varlamov struct NoThrowBeginThrowingEnd {
51255bd22f8SKonstantin Varlamov int* begin() const noexcept;
51355bd22f8SKonstantin Varlamov int* end() const;
51455bd22f8SKonstantin Varlamov } ntbte;
51555bd22f8SKonstantin Varlamov static_assert(noexcept(std::ranges::rend(ntbte)));
51655bd22f8SKonstantin Varlamov static_assert(noexcept(std::ranges::crend(ntbte)));
51755bd22f8SKonstantin Varlamov
51855bd22f8SKonstantin Varlamov struct NoThrowEndThrowingBegin {
51955bd22f8SKonstantin Varlamov int* begin() const;
52055bd22f8SKonstantin Varlamov int* end() const noexcept;
52155bd22f8SKonstantin Varlamov } ntetb;
52255bd22f8SKonstantin Varlamov static_assert(!noexcept(std::ranges::rend(ntetb)));
52355bd22f8SKonstantin Varlamov static_assert(!noexcept(std::ranges::crend(ntetb)));
52455bd22f8SKonstantin Varlamov
52555bd22f8SKonstantin Varlamov // Test ADL-proofing.
52655bd22f8SKonstantin Varlamov struct Incomplete;
52755bd22f8SKonstantin Varlamov template<class T> struct Holder { T t; };
52855bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, Holder<Incomplete>*>);
52955bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeREndT, Holder<Incomplete>*&>);
53055bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCREndT, Holder<Incomplete>*>);
53155bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCREndT, Holder<Incomplete>*&>);
53255bd22f8SKonstantin Varlamov
main(int,char **)53355bd22f8SKonstantin Varlamov int main(int, char**) {
53455bd22f8SKonstantin Varlamov static_assert(testReturnTypes());
53555bd22f8SKonstantin Varlamov
53655bd22f8SKonstantin Varlamov testArray();
53755bd22f8SKonstantin Varlamov static_assert(testArray());
53855bd22f8SKonstantin Varlamov
53955bd22f8SKonstantin Varlamov testREndMember();
54055bd22f8SKonstantin Varlamov static_assert(testREndMember());
54155bd22f8SKonstantin Varlamov
54255bd22f8SKonstantin Varlamov testREndFunction();
54355bd22f8SKonstantin Varlamov static_assert(testREndFunction());
54455bd22f8SKonstantin Varlamov
54555bd22f8SKonstantin Varlamov testBeginEnd();
54655bd22f8SKonstantin Varlamov static_assert(testBeginEnd());
54755bd22f8SKonstantin Varlamov
54855bd22f8SKonstantin Varlamov return 0;
54955bd22f8SKonstantin Varlamov }
550