xref: /llvm-project/libcxx/test/std/ranges/range.access/rbegin.pass.cpp (revision 12978b3e23a2766732595391c193e5631f40a3db)
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::rbegin
1255bd22f8SKonstantin Varlamov // std::ranges::crbegin
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 RangeRBeginT = decltype(std::ranges::rbegin);
2255bd22f8SKonstantin Varlamov using RangeCRBeginT = decltype(std::ranges::crbegin);
2355bd22f8SKonstantin Varlamov 
2455bd22f8SKonstantin Varlamov static int globalBuff[8];
2555bd22f8SKonstantin Varlamov 
2655bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT, int (&&)[10]>);
2755bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeRBeginT, int (&)[10]>);
2855bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT, int (&&)[]>);
2955bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT, int (&)[]>);
3055bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCRBeginT, int (&&)[10]>);
3155bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeCRBeginT, int (&)[10]>);
3255bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCRBeginT, int (&&)[]>);
3355bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCRBeginT, int (&)[]>);
3455bd22f8SKonstantin Varlamov 
3555bd22f8SKonstantin Varlamov struct Incomplete;
3655bd22f8SKonstantin Varlamov 
3755bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT, Incomplete(&&)[]>);
3855bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT, const Incomplete(&&)[]>);
3955bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCRBeginT, Incomplete(&&)[]>);
4055bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCRBeginT, const Incomplete(&&)[]>);
4155bd22f8SKonstantin Varlamov 
4255bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT, Incomplete(&&)[10]>);
4355bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT, const Incomplete(&&)[10]>);
4455bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCRBeginT, Incomplete(&&)[10]>);
4555bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCRBeginT, const Incomplete(&&)[10]>);
4655bd22f8SKonstantin Varlamov 
4755bd22f8SKonstantin Varlamov // This case is IFNDR; we handle it SFINAE-friendly.
4855bd22f8SKonstantin Varlamov LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeRBeginT, Incomplete(&)[]>);
4955bd22f8SKonstantin Varlamov LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeRBeginT, const Incomplete(&)[]>);
5055bd22f8SKonstantin Varlamov LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, Incomplete(&)[]>);
5155bd22f8SKonstantin Varlamov LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, const Incomplete(&)[]>);
5255bd22f8SKonstantin Varlamov 
5355bd22f8SKonstantin Varlamov // This case is IFNDR; we handle it SFINAE-friendly.
5455bd22f8SKonstantin Varlamov LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeRBeginT, Incomplete(&)[10]>);
5555bd22f8SKonstantin Varlamov LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeRBeginT, const Incomplete(&)[10]>);
5655bd22f8SKonstantin Varlamov LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, Incomplete(&)[10]>);
5755bd22f8SKonstantin Varlamov LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCRBeginT, const Incomplete(&)[10]>);
5855bd22f8SKonstantin Varlamov 
5955bd22f8SKonstantin Varlamov struct RBeginMember {
6055bd22f8SKonstantin Varlamov   int x;
rbeginRBeginMember6155bd22f8SKonstantin Varlamov   constexpr const int *rbegin() const { return &x; }
6255bd22f8SKonstantin Varlamov };
6355bd22f8SKonstantin Varlamov 
6455bd22f8SKonstantin Varlamov // Ensure that we can't call with rvalues with borrowing disabled.
6555bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeRBeginT, RBeginMember &>);
6655bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT, RBeginMember &&>);
6755bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeRBeginT, RBeginMember const&>);
6855bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT, RBeginMember const&&>);
6955bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeCRBeginT, RBeginMember &>);
7055bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCRBeginT, RBeginMember &&>);
7155bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeCRBeginT, RBeginMember const&>);
7255bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCRBeginT, RBeginMember const&&>);
7355bd22f8SKonstantin Varlamov 
testReturnTypes()7455bd22f8SKonstantin Varlamov constexpr bool testReturnTypes() {
7555bd22f8SKonstantin Varlamov   {
7655bd22f8SKonstantin Varlamov     int *x[2];
7755bd22f8SKonstantin Varlamov     ASSERT_SAME_TYPE(decltype(std::ranges::rbegin(x)), std::reverse_iterator<int**>);
7855bd22f8SKonstantin Varlamov     ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(x)), std::reverse_iterator<int* const*>);
7955bd22f8SKonstantin Varlamov   }
8055bd22f8SKonstantin Varlamov   {
8155bd22f8SKonstantin Varlamov     int x[2][2];
8255bd22f8SKonstantin Varlamov     ASSERT_SAME_TYPE(decltype(std::ranges::rbegin(x)), std::reverse_iterator<int(*)[2]>);
8355bd22f8SKonstantin Varlamov     ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(x)), std::reverse_iterator<const int(*)[2]>);
8455bd22f8SKonstantin Varlamov   }
8555bd22f8SKonstantin Varlamov   {
8655bd22f8SKonstantin Varlamov     struct Different {
8755bd22f8SKonstantin Varlamov       char*& rbegin();
8855bd22f8SKonstantin Varlamov       short*& rbegin() const;
8955bd22f8SKonstantin Varlamov     } x;
9055bd22f8SKonstantin Varlamov     ASSERT_SAME_TYPE(decltype(std::ranges::rbegin(x)), char*);
9155bd22f8SKonstantin Varlamov     ASSERT_SAME_TYPE(decltype(std::ranges::crbegin(x)), short*);
9255bd22f8SKonstantin Varlamov   }
9355bd22f8SKonstantin Varlamov   return true;
9455bd22f8SKonstantin Varlamov }
9555bd22f8SKonstantin Varlamov 
testArray()9655bd22f8SKonstantin Varlamov constexpr bool testArray() {
9755bd22f8SKonstantin Varlamov   int a[2];
9855bd22f8SKonstantin Varlamov   assert(std::ranges::rbegin(a).base() == a + 2);
9955bd22f8SKonstantin Varlamov   assert(std::ranges::crbegin(a).base() == a + 2);
10055bd22f8SKonstantin Varlamov 
10155bd22f8SKonstantin Varlamov   int b[2][2];
10255bd22f8SKonstantin Varlamov   assert(std::ranges::rbegin(b).base() == b + 2);
10355bd22f8SKonstantin Varlamov   assert(std::ranges::crbegin(b).base() == b + 2);
10455bd22f8SKonstantin Varlamov 
10555bd22f8SKonstantin Varlamov   RBeginMember c[2];
10655bd22f8SKonstantin Varlamov   assert(std::ranges::rbegin(c).base() == c + 2);
10755bd22f8SKonstantin Varlamov   assert(std::ranges::crbegin(c).base() == c + 2);
10855bd22f8SKonstantin Varlamov 
10955bd22f8SKonstantin Varlamov   return true;
11055bd22f8SKonstantin Varlamov }
11155bd22f8SKonstantin Varlamov 
11255bd22f8SKonstantin Varlamov struct RBeginMemberReturnsInt {
11355bd22f8SKonstantin Varlamov   int rbegin() const;
11455bd22f8SKonstantin Varlamov };
11555bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT, RBeginMemberReturnsInt const&>);
11655bd22f8SKonstantin Varlamov 
11755bd22f8SKonstantin Varlamov struct RBeginMemberReturnsVoidPtr {
11855bd22f8SKonstantin Varlamov   const void *rbegin() const;
11955bd22f8SKonstantin Varlamov };
12055bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT, RBeginMemberReturnsVoidPtr const&>);
12155bd22f8SKonstantin Varlamov 
12255bd22f8SKonstantin Varlamov struct PtrConvertibleRBeginMember {
12355bd22f8SKonstantin Varlamov   struct iterator { operator int*() const; };
12455bd22f8SKonstantin Varlamov   iterator rbegin() const;
12555bd22f8SKonstantin Varlamov };
12655bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT, PtrConvertibleRBeginMember const&>);
12755bd22f8SKonstantin Varlamov 
12855bd22f8SKonstantin Varlamov struct NonConstRBeginMember {
12955bd22f8SKonstantin Varlamov   int x;
rbeginNonConstRBeginMember13055bd22f8SKonstantin Varlamov   constexpr int* rbegin() { return &x; }
13155bd22f8SKonstantin Varlamov };
13255bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeRBeginT,  NonConstRBeginMember &>);
13355bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT,  NonConstRBeginMember const&>);
13455bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCRBeginT, NonConstRBeginMember &>);
13555bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCRBeginT, NonConstRBeginMember const&>);
13655bd22f8SKonstantin Varlamov 
13755bd22f8SKonstantin Varlamov struct EnabledBorrowingRBeginMember {
rbeginEnabledBorrowingRBeginMember13855bd22f8SKonstantin Varlamov   constexpr int *rbegin() const { return globalBuff; }
13955bd22f8SKonstantin Varlamov };
14055bd22f8SKonstantin Varlamov template<>
14155bd22f8SKonstantin Varlamov inline constexpr bool std::ranges::enable_borrowed_range<EnabledBorrowingRBeginMember> = true;
14255bd22f8SKonstantin Varlamov 
14355bd22f8SKonstantin Varlamov struct RBeginMemberFunction {
14455bd22f8SKonstantin Varlamov   int x;
rbeginRBeginMemberFunction14555bd22f8SKonstantin Varlamov   constexpr const int *rbegin() const { return &x; }
14655bd22f8SKonstantin Varlamov   friend int* rbegin(RBeginMemberFunction const&);
14755bd22f8SKonstantin Varlamov };
14855bd22f8SKonstantin Varlamov 
14955bd22f8SKonstantin Varlamov struct EmptyPtrRBeginMember {
15055bd22f8SKonstantin Varlamov   struct Empty {};
15155bd22f8SKonstantin Varlamov   Empty x;
rbeginEmptyPtrRBeginMember15255bd22f8SKonstantin Varlamov   constexpr const Empty* rbegin() const { return &x; }
15355bd22f8SKonstantin Varlamov };
15455bd22f8SKonstantin Varlamov 
testRBeginMember()15555bd22f8SKonstantin Varlamov constexpr bool testRBeginMember() {
15655bd22f8SKonstantin Varlamov   RBeginMember a;
15755bd22f8SKonstantin Varlamov   assert(std::ranges::rbegin(a) == &a.x);
15855bd22f8SKonstantin Varlamov   assert(std::ranges::crbegin(a) == &a.x);
15955bd22f8SKonstantin Varlamov   static_assert(!std::is_invocable_v<RangeRBeginT, RBeginMember&&>);
16055bd22f8SKonstantin Varlamov   static_assert(!std::is_invocable_v<RangeCRBeginT, RBeginMember&&>);
16155bd22f8SKonstantin Varlamov 
16255bd22f8SKonstantin Varlamov   NonConstRBeginMember b;
16355bd22f8SKonstantin Varlamov   assert(std::ranges::rbegin(b) == &b.x);
16455bd22f8SKonstantin Varlamov   static_assert(!std::is_invocable_v<RangeCRBeginT, NonConstRBeginMember&>);
16555bd22f8SKonstantin Varlamov 
16655bd22f8SKonstantin Varlamov   EnabledBorrowingRBeginMember c;
16755bd22f8SKonstantin Varlamov   assert(std::ranges::rbegin(c) == globalBuff);
16855bd22f8SKonstantin Varlamov   assert(std::ranges::crbegin(c) == globalBuff);
16955bd22f8SKonstantin Varlamov   assert(std::ranges::rbegin(std::move(c)) == globalBuff);
17055bd22f8SKonstantin Varlamov   assert(std::ranges::crbegin(std::move(c)) == globalBuff);
17155bd22f8SKonstantin Varlamov 
17255bd22f8SKonstantin Varlamov   RBeginMemberFunction d;
17355bd22f8SKonstantin Varlamov   assert(std::ranges::rbegin(d) == &d.x);
17455bd22f8SKonstantin Varlamov   assert(std::ranges::crbegin(d) == &d.x);
17555bd22f8SKonstantin Varlamov 
17655bd22f8SKonstantin Varlamov   EmptyPtrRBeginMember e;
17755bd22f8SKonstantin Varlamov   assert(std::ranges::rbegin(e) == &e.x);
17855bd22f8SKonstantin Varlamov   assert(std::ranges::crbegin(e) == &e.x);
17955bd22f8SKonstantin Varlamov 
18055bd22f8SKonstantin Varlamov   return true;
18155bd22f8SKonstantin Varlamov }
18255bd22f8SKonstantin Varlamov 
18355bd22f8SKonstantin Varlamov 
18455bd22f8SKonstantin Varlamov struct RBeginFunction {
18555bd22f8SKonstantin Varlamov   int x;
rbegin(RBeginFunction const & bf)18655bd22f8SKonstantin Varlamov   friend constexpr const int* rbegin(RBeginFunction const& bf) { return &bf.x; }
18755bd22f8SKonstantin Varlamov };
18855bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeRBeginT,  RBeginFunction const&>);
18955bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT,  RBeginFunction &&>);
190*12978b3eSJakub Mazurkiewicz static_assert(
191*12978b3eSJakub Mazurkiewicz     std::is_invocable_v<RangeRBeginT, RBeginFunction&>); // Ill-formed before P2602R2 Poison Pills are Too Toxic
19255bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeCRBeginT, RBeginFunction const&>);
19355bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeCRBeginT, RBeginFunction &>);
19455bd22f8SKonstantin Varlamov 
19555bd22f8SKonstantin Varlamov struct RBeginFunctionReturnsInt {
19655bd22f8SKonstantin Varlamov   friend int rbegin(RBeginFunctionReturnsInt const&);
19755bd22f8SKonstantin Varlamov };
19855bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT, RBeginFunctionReturnsInt const&>);
19955bd22f8SKonstantin Varlamov 
20055bd22f8SKonstantin Varlamov struct RBeginFunctionReturnsVoidPtr {
20155bd22f8SKonstantin Varlamov   friend void *rbegin(RBeginFunctionReturnsVoidPtr const&);
20255bd22f8SKonstantin Varlamov };
20355bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT, RBeginFunctionReturnsVoidPtr const&>);
20455bd22f8SKonstantin Varlamov 
20555bd22f8SKonstantin Varlamov struct RBeginFunctionReturnsEmpty {
20655bd22f8SKonstantin Varlamov   struct Empty {};
20755bd22f8SKonstantin Varlamov   friend Empty rbegin(RBeginFunctionReturnsEmpty const&);
20855bd22f8SKonstantin Varlamov };
20955bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT, RBeginFunctionReturnsEmpty const&>);
21055bd22f8SKonstantin Varlamov 
21155bd22f8SKonstantin Varlamov struct RBeginFunctionReturnsPtrConvertible {
21255bd22f8SKonstantin Varlamov   struct iterator { operator int*() const; };
21355bd22f8SKonstantin Varlamov   friend iterator rbegin(RBeginFunctionReturnsPtrConvertible const&);
21455bd22f8SKonstantin Varlamov };
21555bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT, RBeginFunctionReturnsPtrConvertible const&>);
21655bd22f8SKonstantin Varlamov 
21755bd22f8SKonstantin Varlamov struct RBeginFunctionByValue {
rbegin(RBeginFunctionByValue)21855bd22f8SKonstantin Varlamov   friend constexpr int *rbegin(RBeginFunctionByValue) { return globalBuff + 1; }
21955bd22f8SKonstantin Varlamov };
22055bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCRBeginT, RBeginFunctionByValue>);
22155bd22f8SKonstantin Varlamov 
22255bd22f8SKonstantin Varlamov struct RBeginFunctionEnabledBorrowing {
rbegin(RBeginFunctionEnabledBorrowing)22355bd22f8SKonstantin Varlamov   friend constexpr int *rbegin(RBeginFunctionEnabledBorrowing) { return globalBuff + 2; }
22455bd22f8SKonstantin Varlamov };
22555bd22f8SKonstantin Varlamov template<>
22655bd22f8SKonstantin Varlamov inline constexpr bool std::ranges::enable_borrowed_range<RBeginFunctionEnabledBorrowing> = true;
22755bd22f8SKonstantin Varlamov 
22855bd22f8SKonstantin Varlamov struct RBeginFunctionReturnsEmptyPtr {
22955bd22f8SKonstantin Varlamov   struct Empty {};
23055bd22f8SKonstantin Varlamov   Empty x;
rbegin(RBeginFunctionReturnsEmptyPtr const & bf)23155bd22f8SKonstantin Varlamov   friend constexpr const Empty *rbegin(RBeginFunctionReturnsEmptyPtr const& bf) { return &bf.x; }
23255bd22f8SKonstantin Varlamov };
23355bd22f8SKonstantin Varlamov 
23455bd22f8SKonstantin Varlamov struct RBeginFunctionWithDataMember {
23555bd22f8SKonstantin Varlamov   int x;
23655bd22f8SKonstantin Varlamov   int rbegin;
rbegin(RBeginFunctionWithDataMember const & bf)23755bd22f8SKonstantin Varlamov   friend constexpr const int *rbegin(RBeginFunctionWithDataMember const& bf) { return &bf.x; }
23855bd22f8SKonstantin Varlamov };
23955bd22f8SKonstantin Varlamov 
24055bd22f8SKonstantin Varlamov struct RBeginFunctionWithPrivateBeginMember {
24155bd22f8SKonstantin Varlamov   int y;
rbegin(RBeginFunctionWithPrivateBeginMember const & bf)24255bd22f8SKonstantin Varlamov   friend constexpr const int *rbegin(RBeginFunctionWithPrivateBeginMember const& bf) { return &bf.y; }
24355bd22f8SKonstantin Varlamov private:
24455bd22f8SKonstantin Varlamov   const int *rbegin() const;
24555bd22f8SKonstantin Varlamov };
24655bd22f8SKonstantin Varlamov 
testRBeginFunction()24755bd22f8SKonstantin Varlamov constexpr bool testRBeginFunction() {
24855bd22f8SKonstantin Varlamov   RBeginFunction a{};
24955bd22f8SKonstantin Varlamov   const RBeginFunction aa{};
250*12978b3eSJakub Mazurkiewicz   assert(std::ranges::rbegin(a) == &a.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
25155bd22f8SKonstantin Varlamov   assert(std::ranges::crbegin(a) == &a.x);
25255bd22f8SKonstantin Varlamov   assert(std::ranges::rbegin(aa) == &aa.x);
25355bd22f8SKonstantin Varlamov   assert(std::ranges::crbegin(aa) == &aa.x);
25455bd22f8SKonstantin Varlamov 
25555bd22f8SKonstantin Varlamov   RBeginFunctionByValue b{};
25655bd22f8SKonstantin Varlamov   const RBeginFunctionByValue bb{};
25755bd22f8SKonstantin Varlamov   assert(std::ranges::rbegin(b) == globalBuff + 1);
25855bd22f8SKonstantin Varlamov   assert(std::ranges::crbegin(b) == globalBuff + 1);
25955bd22f8SKonstantin Varlamov   assert(std::ranges::rbegin(bb) == globalBuff + 1);
26055bd22f8SKonstantin Varlamov   assert(std::ranges::crbegin(bb) == globalBuff + 1);
26155bd22f8SKonstantin Varlamov 
26255bd22f8SKonstantin Varlamov   RBeginFunctionEnabledBorrowing c{};
26355bd22f8SKonstantin Varlamov   const RBeginFunctionEnabledBorrowing cc{};
26455bd22f8SKonstantin Varlamov   assert(std::ranges::rbegin(std::move(c)) == globalBuff + 2);
26555bd22f8SKonstantin Varlamov   assert(std::ranges::crbegin(std::move(c)) == globalBuff + 2);
26655bd22f8SKonstantin Varlamov   assert(std::ranges::rbegin(std::move(cc)) == globalBuff + 2);
26755bd22f8SKonstantin Varlamov   assert(std::ranges::crbegin(std::move(cc)) == globalBuff + 2);
26855bd22f8SKonstantin Varlamov 
26955bd22f8SKonstantin Varlamov   RBeginFunctionReturnsEmptyPtr d{};
27055bd22f8SKonstantin Varlamov   const RBeginFunctionReturnsEmptyPtr dd{};
271*12978b3eSJakub Mazurkiewicz   assert(std::ranges::rbegin(d) == &d.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
27255bd22f8SKonstantin Varlamov   assert(std::ranges::crbegin(d) == &d.x);
27355bd22f8SKonstantin Varlamov   assert(std::ranges::rbegin(dd) == &dd.x);
27455bd22f8SKonstantin Varlamov   assert(std::ranges::crbegin(dd) == &dd.x);
27555bd22f8SKonstantin Varlamov 
27655bd22f8SKonstantin Varlamov   RBeginFunctionWithDataMember e{};
27755bd22f8SKonstantin Varlamov   const RBeginFunctionWithDataMember ee{};
278*12978b3eSJakub Mazurkiewicz   assert(std::ranges::rbegin(e) == &e.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
27955bd22f8SKonstantin Varlamov   assert(std::ranges::rbegin(ee) == &ee.x);
28055bd22f8SKonstantin Varlamov   assert(std::ranges::crbegin(e) == &e.x);
28155bd22f8SKonstantin Varlamov   assert(std::ranges::crbegin(ee) == &ee.x);
28255bd22f8SKonstantin Varlamov 
28355bd22f8SKonstantin Varlamov   RBeginFunctionWithPrivateBeginMember f{};
28455bd22f8SKonstantin Varlamov   const RBeginFunctionWithPrivateBeginMember ff{};
285*12978b3eSJakub Mazurkiewicz   assert(std::ranges::rbegin(f) == &f.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic
28655bd22f8SKonstantin Varlamov   assert(std::ranges::crbegin(f) == &f.y);
28755bd22f8SKonstantin Varlamov   assert(std::ranges::rbegin(ff) == &ff.y);
28855bd22f8SKonstantin Varlamov   assert(std::ranges::crbegin(ff) == &ff.y);
28955bd22f8SKonstantin Varlamov 
29055bd22f8SKonstantin Varlamov   return true;
29155bd22f8SKonstantin Varlamov }
29255bd22f8SKonstantin Varlamov 
29355bd22f8SKonstantin Varlamov 
29455bd22f8SKonstantin Varlamov struct MemberBeginEnd {
29555bd22f8SKonstantin Varlamov   int b, e;
29655bd22f8SKonstantin Varlamov   char cb, ce;
beginMemberBeginEnd29755bd22f8SKonstantin Varlamov   constexpr bidirectional_iterator<int*> begin() { return bidirectional_iterator<int*>(&b); }
endMemberBeginEnd29855bd22f8SKonstantin Varlamov   constexpr bidirectional_iterator<int*> end() { return bidirectional_iterator<int*>(&e); }
beginMemberBeginEnd29955bd22f8SKonstantin Varlamov   constexpr bidirectional_iterator<const char*> begin() const { return bidirectional_iterator<const char*>(&cb); }
endMemberBeginEnd30055bd22f8SKonstantin Varlamov   constexpr bidirectional_iterator<const char*> end() const { return bidirectional_iterator<const char*>(&ce); }
30155bd22f8SKonstantin Varlamov };
30255bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeRBeginT, MemberBeginEnd&>);
30355bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeRBeginT, MemberBeginEnd const&>);
30455bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeCRBeginT, MemberBeginEnd const&>);
30555bd22f8SKonstantin Varlamov 
30655bd22f8SKonstantin Varlamov struct FunctionBeginEnd {
30755bd22f8SKonstantin Varlamov   int b, e;
30855bd22f8SKonstantin Varlamov   char cb, ce;
begin(FunctionBeginEnd & v)30955bd22f8SKonstantin Varlamov   friend constexpr bidirectional_iterator<int*> begin(FunctionBeginEnd& v) {
31055bd22f8SKonstantin Varlamov     return bidirectional_iterator<int*>(&v.b);
31155bd22f8SKonstantin Varlamov   }
end(FunctionBeginEnd & v)31255bd22f8SKonstantin Varlamov   friend constexpr bidirectional_iterator<int*> end(FunctionBeginEnd& v) { return bidirectional_iterator<int*>(&v.e); }
begin(const FunctionBeginEnd & v)31355bd22f8SKonstantin Varlamov   friend constexpr bidirectional_iterator<const char*> begin(const FunctionBeginEnd& v) {
31455bd22f8SKonstantin Varlamov     return bidirectional_iterator<const char*>(&v.cb);
31555bd22f8SKonstantin Varlamov   }
end(const FunctionBeginEnd & v)31655bd22f8SKonstantin Varlamov   friend constexpr bidirectional_iterator<const char*> end(const FunctionBeginEnd& v) {
31755bd22f8SKonstantin Varlamov     return bidirectional_iterator<const char*>(&v.ce);
31855bd22f8SKonstantin Varlamov   }
31955bd22f8SKonstantin Varlamov };
32055bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeRBeginT, FunctionBeginEnd&>);
32155bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeRBeginT, FunctionBeginEnd const&>);
32255bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeCRBeginT, FunctionBeginEnd const&>);
32355bd22f8SKonstantin Varlamov 
32455bd22f8SKonstantin Varlamov struct MemberBeginFunctionEnd {
32555bd22f8SKonstantin Varlamov   int b, e;
32655bd22f8SKonstantin Varlamov   char cb, ce;
beginMemberBeginFunctionEnd32755bd22f8SKonstantin Varlamov   constexpr bidirectional_iterator<int*> begin() { return bidirectional_iterator<int*>(&b); }
end(MemberBeginFunctionEnd & v)32855bd22f8SKonstantin Varlamov   friend constexpr bidirectional_iterator<int*> end(MemberBeginFunctionEnd& v) {
32955bd22f8SKonstantin Varlamov     return bidirectional_iterator<int*>(&v.e);
33055bd22f8SKonstantin Varlamov   }
beginMemberBeginFunctionEnd33155bd22f8SKonstantin Varlamov   constexpr bidirectional_iterator<const char*> begin() const { return bidirectional_iterator<const char*>(&cb); }
end(const MemberBeginFunctionEnd & v)33255bd22f8SKonstantin Varlamov   friend constexpr bidirectional_iterator<const char*> end(const MemberBeginFunctionEnd& v) {
33355bd22f8SKonstantin Varlamov     return bidirectional_iterator<const char*>(&v.ce);
33455bd22f8SKonstantin Varlamov   }
33555bd22f8SKonstantin Varlamov };
33655bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeRBeginT, MemberBeginFunctionEnd&>);
33755bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeRBeginT, MemberBeginFunctionEnd const&>);
33855bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeCRBeginT, MemberBeginFunctionEnd const&>);
33955bd22f8SKonstantin Varlamov 
34055bd22f8SKonstantin Varlamov struct FunctionBeginMemberEnd {
34155bd22f8SKonstantin Varlamov   int b, e;
34255bd22f8SKonstantin Varlamov   char cb, ce;
begin(FunctionBeginMemberEnd & v)34355bd22f8SKonstantin Varlamov   friend constexpr bidirectional_iterator<int*> begin(FunctionBeginMemberEnd& v) {
34455bd22f8SKonstantin Varlamov     return bidirectional_iterator<int*>(&v.b);
34555bd22f8SKonstantin Varlamov   }
endFunctionBeginMemberEnd34655bd22f8SKonstantin Varlamov   constexpr bidirectional_iterator<int*> end() { return bidirectional_iterator<int*>(&e); }
begin(const FunctionBeginMemberEnd & v)34755bd22f8SKonstantin Varlamov   friend constexpr bidirectional_iterator<const char*> begin(const FunctionBeginMemberEnd& v) {
34855bd22f8SKonstantin Varlamov     return bidirectional_iterator<const char*>(&v.cb);
34955bd22f8SKonstantin Varlamov   }
endFunctionBeginMemberEnd35055bd22f8SKonstantin Varlamov   constexpr bidirectional_iterator<const char*> end() const { return bidirectional_iterator<const char*>(&ce); }
35155bd22f8SKonstantin Varlamov };
35255bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeRBeginT, FunctionBeginMemberEnd&>);
35355bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeRBeginT, FunctionBeginMemberEnd const&>);
35455bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeCRBeginT, FunctionBeginMemberEnd const&>);
35555bd22f8SKonstantin Varlamov 
35655bd22f8SKonstantin Varlamov struct MemberBeginEndDifferentTypes {
35755bd22f8SKonstantin Varlamov   bidirectional_iterator<int*> begin();
35855bd22f8SKonstantin Varlamov   bidirectional_iterator<const int*> end();
35955bd22f8SKonstantin Varlamov };
36055bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT, MemberBeginEndDifferentTypes&>);
36155bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCRBeginT, MemberBeginEndDifferentTypes&>);
36255bd22f8SKonstantin Varlamov 
36355bd22f8SKonstantin Varlamov struct FunctionBeginEndDifferentTypes {
36455bd22f8SKonstantin Varlamov   friend bidirectional_iterator<int*> begin(FunctionBeginEndDifferentTypes&);
36555bd22f8SKonstantin Varlamov   friend bidirectional_iterator<const int*> end(FunctionBeginEndDifferentTypes&);
36655bd22f8SKonstantin Varlamov };
36755bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT, FunctionBeginEndDifferentTypes&>);
36855bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCRBeginT, FunctionBeginEndDifferentTypes&>);
36955bd22f8SKonstantin Varlamov 
37055bd22f8SKonstantin Varlamov struct MemberBeginEndForwardIterators {
37155bd22f8SKonstantin Varlamov   forward_iterator<int*> begin();
37255bd22f8SKonstantin Varlamov   forward_iterator<int*> end();
37355bd22f8SKonstantin Varlamov };
37455bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT, MemberBeginEndForwardIterators&>);
37555bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCRBeginT, MemberBeginEndForwardIterators&>);
37655bd22f8SKonstantin Varlamov 
37755bd22f8SKonstantin Varlamov struct FunctionBeginEndForwardIterators {
37855bd22f8SKonstantin Varlamov   friend forward_iterator<int*> begin(FunctionBeginEndForwardIterators&);
37955bd22f8SKonstantin Varlamov   friend forward_iterator<int*> end(FunctionBeginEndForwardIterators&);
38055bd22f8SKonstantin Varlamov };
38155bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT, FunctionBeginEndForwardIterators&>);
38255bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCRBeginT, FunctionBeginEndForwardIterators&>);
38355bd22f8SKonstantin Varlamov 
38455bd22f8SKonstantin Varlamov struct MemberBeginOnly {
38555bd22f8SKonstantin Varlamov   bidirectional_iterator<int*> begin() const;
38655bd22f8SKonstantin Varlamov };
38755bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT, MemberBeginOnly&>);
38855bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCRBeginT, MemberBeginOnly&>);
38955bd22f8SKonstantin Varlamov 
39055bd22f8SKonstantin Varlamov struct FunctionBeginOnly {
39155bd22f8SKonstantin Varlamov   friend bidirectional_iterator<int*> begin(FunctionBeginOnly&);
39255bd22f8SKonstantin Varlamov };
39355bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT, FunctionBeginOnly&>);
39455bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCRBeginT, FunctionBeginOnly&>);
39555bd22f8SKonstantin Varlamov 
39655bd22f8SKonstantin Varlamov struct MemberEndOnly {
39755bd22f8SKonstantin Varlamov   bidirectional_iterator<int*> end() const;
39855bd22f8SKonstantin Varlamov };
39955bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT, MemberEndOnly&>);
40055bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCRBeginT, MemberEndOnly&>);
40155bd22f8SKonstantin Varlamov 
40255bd22f8SKonstantin Varlamov struct FunctionEndOnly {
40355bd22f8SKonstantin Varlamov   friend bidirectional_iterator<int*> end(FunctionEndOnly&);
40455bd22f8SKonstantin Varlamov };
40555bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT, FunctionEndOnly&>);
40655bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCRBeginT, FunctionEndOnly&>);
40755bd22f8SKonstantin Varlamov 
40855bd22f8SKonstantin Varlamov // Make sure there is no clash between the following cases:
40955bd22f8SKonstantin Varlamov // - the case that handles classes defining member `rbegin` and `rend` functions;
41055bd22f8SKonstantin Varlamov // - the case that handles classes defining `begin` and `end` functions returning reversible iterators.
41155bd22f8SKonstantin Varlamov struct MemberBeginAndRBegin {
41255bd22f8SKonstantin Varlamov   int* begin() const;
41355bd22f8SKonstantin Varlamov   int* end() const;
41455bd22f8SKonstantin Varlamov   int* rbegin() const;
41555bd22f8SKonstantin Varlamov   int* rend() const;
41655bd22f8SKonstantin Varlamov };
41755bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeRBeginT, MemberBeginAndRBegin&>);
41855bd22f8SKonstantin Varlamov static_assert( std::is_invocable_v<RangeCRBeginT, MemberBeginAndRBegin&>);
41955bd22f8SKonstantin Varlamov static_assert( std::same_as<std::invoke_result_t<RangeRBeginT, MemberBeginAndRBegin&>, int*>);
42055bd22f8SKonstantin Varlamov static_assert( std::same_as<std::invoke_result_t<RangeCRBeginT, MemberBeginAndRBegin&>, int*>);
42155bd22f8SKonstantin Varlamov 
testBeginEnd()42255bd22f8SKonstantin Varlamov constexpr bool testBeginEnd() {
42355bd22f8SKonstantin Varlamov   MemberBeginEnd a{};
42455bd22f8SKonstantin Varlamov   const MemberBeginEnd aa{};
4255f26d863SMark de Wever   assert(base(std::ranges::rbegin(a).base()) == &a.e);
4265f26d863SMark de Wever   assert(base(std::ranges::crbegin(a).base()) == &a.ce);
4275f26d863SMark de Wever   assert(base(std::ranges::rbegin(aa).base()) == &aa.ce);
4285f26d863SMark de Wever   assert(base(std::ranges::crbegin(aa).base()) == &aa.ce);
42955bd22f8SKonstantin Varlamov 
43055bd22f8SKonstantin Varlamov   FunctionBeginEnd b{};
43155bd22f8SKonstantin Varlamov   const FunctionBeginEnd bb{};
4325f26d863SMark de Wever   assert(base(std::ranges::rbegin(b).base()) == &b.e);
4335f26d863SMark de Wever   assert(base(std::ranges::crbegin(b).base()) == &b.ce);
4345f26d863SMark de Wever   assert(base(std::ranges::rbegin(bb).base()) == &bb.ce);
4355f26d863SMark de Wever   assert(base(std::ranges::crbegin(bb).base()) == &bb.ce);
43655bd22f8SKonstantin Varlamov 
43755bd22f8SKonstantin Varlamov   MemberBeginFunctionEnd c{};
43855bd22f8SKonstantin Varlamov   const MemberBeginFunctionEnd cc{};
4395f26d863SMark de Wever   assert(base(std::ranges::rbegin(c).base()) == &c.e);
4405f26d863SMark de Wever   assert(base(std::ranges::crbegin(c).base()) == &c.ce);
4415f26d863SMark de Wever   assert(base(std::ranges::rbegin(cc).base()) == &cc.ce);
4425f26d863SMark de Wever   assert(base(std::ranges::crbegin(cc).base()) == &cc.ce);
44355bd22f8SKonstantin Varlamov 
44455bd22f8SKonstantin Varlamov   FunctionBeginMemberEnd d{};
44555bd22f8SKonstantin Varlamov   const FunctionBeginMemberEnd dd{};
4465f26d863SMark de Wever   assert(base(std::ranges::rbegin(d).base()) == &d.e);
4475f26d863SMark de Wever   assert(base(std::ranges::crbegin(d).base()) == &d.ce);
4485f26d863SMark de Wever   assert(base(std::ranges::rbegin(dd).base()) == &dd.ce);
4495f26d863SMark de Wever   assert(base(std::ranges::crbegin(dd).base()) == &dd.ce);
45055bd22f8SKonstantin Varlamov 
45155bd22f8SKonstantin Varlamov   return true;
45255bd22f8SKonstantin Varlamov }
45355bd22f8SKonstantin Varlamov 
45455bd22f8SKonstantin Varlamov 
45555bd22f8SKonstantin Varlamov ASSERT_NOEXCEPT(std::ranges::rbegin(std::declval<int (&)[10]>()));
45655bd22f8SKonstantin Varlamov ASSERT_NOEXCEPT(std::ranges::crbegin(std::declval<int (&)[10]>()));
45755bd22f8SKonstantin Varlamov 
45855bd22f8SKonstantin Varlamov struct NoThrowMemberRBegin {
45955bd22f8SKonstantin Varlamov   ThrowingIterator<int> rbegin() const noexcept; // auto(t.rbegin()) doesn't throw
46055bd22f8SKonstantin Varlamov } ntmb;
46155bd22f8SKonstantin Varlamov static_assert(noexcept(std::ranges::rbegin(ntmb)));
46255bd22f8SKonstantin Varlamov static_assert(noexcept(std::ranges::crbegin(ntmb)));
46355bd22f8SKonstantin Varlamov 
46455bd22f8SKonstantin Varlamov struct NoThrowADLRBegin {
46555bd22f8SKonstantin Varlamov   friend ThrowingIterator<int> rbegin(NoThrowADLRBegin&) noexcept;  // auto(rbegin(t)) doesn't throw
46655bd22f8SKonstantin Varlamov   friend ThrowingIterator<int> rbegin(const NoThrowADLRBegin&) noexcept;
46755bd22f8SKonstantin Varlamov } ntab;
46855bd22f8SKonstantin Varlamov static_assert(noexcept(std::ranges::rbegin(ntab)));
46955bd22f8SKonstantin Varlamov static_assert(noexcept(std::ranges::crbegin(ntab)));
47055bd22f8SKonstantin Varlamov 
47155bd22f8SKonstantin Varlamov struct NoThrowMemberRBeginReturnsRef {
47255bd22f8SKonstantin Varlamov   ThrowingIterator<int>& rbegin() const noexcept; // auto(t.rbegin()) may throw
47355bd22f8SKonstantin Varlamov } ntmbrr;
47455bd22f8SKonstantin Varlamov static_assert(!noexcept(std::ranges::rbegin(ntmbrr)));
47555bd22f8SKonstantin Varlamov static_assert(!noexcept(std::ranges::crbegin(ntmbrr)));
47655bd22f8SKonstantin Varlamov 
47755bd22f8SKonstantin Varlamov struct RBeginReturnsArrayRef {
47855bd22f8SKonstantin Varlamov     auto rbegin() const noexcept -> int(&)[10];
47955bd22f8SKonstantin Varlamov } brar;
48055bd22f8SKonstantin Varlamov static_assert(noexcept(std::ranges::rbegin(brar)));
48155bd22f8SKonstantin Varlamov static_assert(noexcept(std::ranges::crbegin(brar)));
48255bd22f8SKonstantin Varlamov 
48355bd22f8SKonstantin Varlamov struct NoThrowBeginThrowingEnd {
48455bd22f8SKonstantin Varlamov   int* begin() const noexcept;
48555bd22f8SKonstantin Varlamov   int* end() const;
48655bd22f8SKonstantin Varlamov } ntbte;
48755bd22f8SKonstantin Varlamov static_assert(!noexcept(std::ranges::rbegin(ntbte)));
48855bd22f8SKonstantin Varlamov static_assert(!noexcept(std::ranges::crbegin(ntbte)));
48955bd22f8SKonstantin Varlamov 
49055bd22f8SKonstantin Varlamov struct NoThrowEndThrowingBegin {
49155bd22f8SKonstantin Varlamov   int* begin() const;
49255bd22f8SKonstantin Varlamov   int* end() const noexcept;
49355bd22f8SKonstantin Varlamov } ntetb;
49455bd22f8SKonstantin Varlamov static_assert(noexcept(std::ranges::rbegin(ntetb)));
49555bd22f8SKonstantin Varlamov static_assert(noexcept(std::ranges::crbegin(ntetb)));
49655bd22f8SKonstantin Varlamov 
49755bd22f8SKonstantin Varlamov // Test ADL-proofing.
49855bd22f8SKonstantin Varlamov struct Incomplete;
49955bd22f8SKonstantin Varlamov template<class T> struct Holder { T t; };
50055bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT, Holder<Incomplete>*>);
50155bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeRBeginT, Holder<Incomplete>*&>);
50255bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCRBeginT, Holder<Incomplete>*>);
50355bd22f8SKonstantin Varlamov static_assert(!std::is_invocable_v<RangeCRBeginT, Holder<Incomplete>*&>);
50455bd22f8SKonstantin Varlamov 
main(int,char **)50555bd22f8SKonstantin Varlamov int main(int, char**) {
50655bd22f8SKonstantin Varlamov   static_assert(testReturnTypes());
50755bd22f8SKonstantin Varlamov 
50855bd22f8SKonstantin Varlamov   testArray();
50955bd22f8SKonstantin Varlamov   static_assert(testArray());
51055bd22f8SKonstantin Varlamov 
51155bd22f8SKonstantin Varlamov   testRBeginMember();
51255bd22f8SKonstantin Varlamov   static_assert(testRBeginMember());
51355bd22f8SKonstantin Varlamov 
51455bd22f8SKonstantin Varlamov   testRBeginFunction();
51555bd22f8SKonstantin Varlamov   static_assert(testRBeginFunction());
51655bd22f8SKonstantin Varlamov 
51755bd22f8SKonstantin Varlamov   testBeginEnd();
51855bd22f8SKonstantin Varlamov   static_assert(testBeginEnd());
51955bd22f8SKonstantin Varlamov 
52055bd22f8SKonstantin Varlamov   return 0;
52155bd22f8SKonstantin Varlamov }
522