//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 // std::ranges::begin // std::ranges::cbegin #include #include #include #include "test_macros.h" #include "test_iterators.h" using RangeBeginT = decltype(std::ranges::begin); using RangeCBeginT = decltype(std::ranges::cbegin); static int globalBuff[8]; static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); struct Incomplete; static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); // This case is IFNDR; we handle it SFINAE-friendly. LIBCPP_STATIC_ASSERT(!std::is_invocable_v); LIBCPP_STATIC_ASSERT(!std::is_invocable_v); LIBCPP_STATIC_ASSERT(!std::is_invocable_v); LIBCPP_STATIC_ASSERT(!std::is_invocable_v); // This case is IFNDR; we handle it SFINAE-friendly. LIBCPP_STATIC_ASSERT(!std::is_invocable_v); LIBCPP_STATIC_ASSERT(!std::is_invocable_v); LIBCPP_STATIC_ASSERT(!std::is_invocable_v); LIBCPP_STATIC_ASSERT(!std::is_invocable_v); struct BeginMember { int x; constexpr const int *begin() const { return &x; } }; // Ensure that we can't call with rvalues with borrowing disabled. static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); constexpr bool testReturnTypes() { { int *x[2]; ASSERT_SAME_TYPE(decltype(std::ranges::begin(x)), int**); ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(x)), int* const*); } { int x[2][2]; ASSERT_SAME_TYPE(decltype(std::ranges::begin(x)), int(*)[2]); ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(x)), const int(*)[2]); } { struct Different { char*& begin(); short*& begin() const; } x; ASSERT_SAME_TYPE(decltype(std::ranges::begin(x)), char*); ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(x)), short*); } return true; } constexpr bool testArray() { int a[2]; assert(std::ranges::begin(a) == a); assert(std::ranges::cbegin(a) == a); int b[2][2]; assert(std::ranges::begin(b) == b); assert(std::ranges::cbegin(b) == b); BeginMember c[2]; assert(std::ranges::begin(c) == c); assert(std::ranges::cbegin(c) == c); return true; } struct BeginMemberReturnsInt { int begin() const; }; static_assert(!std::is_invocable_v); struct BeginMemberReturnsVoidPtr { const void *begin() const; }; static_assert(!std::is_invocable_v); struct EmptyBeginMember { struct iterator {}; iterator begin() const; }; static_assert(!std::is_invocable_v); struct PtrConvertibleBeginMember { struct iterator { operator int*() const; }; iterator begin() const; }; static_assert(!std::is_invocable_v); struct NonConstBeginMember { int x; constexpr int *begin() { return &x; } }; static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); struct EnabledBorrowingBeginMember { constexpr int *begin() const { return &globalBuff[0]; } }; template<> inline constexpr bool std::ranges::enable_borrowed_range = true; struct BeginMemberFunction { int x; constexpr const int *begin() const { return &x; } friend int *begin(BeginMemberFunction const&); }; struct EmptyPtrBeginMember { struct Empty {}; Empty x; constexpr const Empty *begin() const { return &x; } }; constexpr bool testBeginMember() { BeginMember a; assert(std::ranges::begin(a) == &a.x); assert(std::ranges::cbegin(a) == &a.x); static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); NonConstBeginMember b; assert(std::ranges::begin(b) == &b.x); static_assert(!std::is_invocable_v); EnabledBorrowingBeginMember c; assert(std::ranges::begin(c) == &globalBuff[0]); assert(std::ranges::cbegin(c) == &globalBuff[0]); assert(std::ranges::begin(std::move(c)) == &globalBuff[0]); assert(std::ranges::cbegin(std::move(c)) == &globalBuff[0]); BeginMemberFunction d; assert(std::ranges::begin(d) == &d.x); assert(std::ranges::cbegin(d) == &d.x); EmptyPtrBeginMember e; assert(std::ranges::begin(e) == &e.x); assert(std::ranges::cbegin(e) == &e.x); return true; } struct BeginFunction { int x; friend constexpr const int *begin(BeginFunction const& bf) { return &bf.x; } }; static_assert( std::is_invocable_v); static_assert(!std::is_invocable_v); static_assert(std::is_invocable_v); // Ill-formed before P2602R2 Poison Pills are Too Toxic static_assert( std::is_invocable_v); static_assert( std::is_invocable_v); struct BeginFunctionReturnsInt { friend int begin(BeginFunctionReturnsInt const&); }; static_assert(!std::is_invocable_v); struct BeginFunctionReturnsVoidPtr { friend void *begin(BeginFunctionReturnsVoidPtr const&); }; static_assert(!std::is_invocable_v); struct BeginFunctionReturnsPtrConvertible { struct iterator { operator int*() const; }; friend iterator begin(BeginFunctionReturnsPtrConvertible const&); }; static_assert(!std::is_invocable_v); struct BeginFunctionByValue { friend constexpr int *begin(BeginFunctionByValue) { return &globalBuff[1]; } }; static_assert(!std::is_invocable_v); struct BeginFunctionEnabledBorrowing { friend constexpr int *begin(BeginFunctionEnabledBorrowing) { return &globalBuff[2]; } }; template<> inline constexpr bool std::ranges::enable_borrowed_range = true; struct BeginFunctionReturnsEmptyPtr { struct Empty {}; Empty x; friend constexpr const Empty *begin(BeginFunctionReturnsEmptyPtr const& bf) { return &bf.x; } }; struct BeginFunctionWithDataMember { int x; int begin; friend constexpr const int *begin(BeginFunctionWithDataMember const& bf) { return &bf.x; } }; struct BeginFunctionWithPrivateBeginMember { int y; friend constexpr const int *begin(BeginFunctionWithPrivateBeginMember const& bf) { return &bf.y; } private: const int *begin() const; }; constexpr bool testBeginFunction() { BeginFunction a{}; const BeginFunction aa{}; assert(std::ranges::begin(a) == &a.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic assert(std::ranges::cbegin(a) == &a.x); assert(std::ranges::begin(aa) == &aa.x); assert(std::ranges::cbegin(aa) == &aa.x); BeginFunctionByValue b{}; const BeginFunctionByValue bb{}; assert(std::ranges::begin(b) == &globalBuff[1]); assert(std::ranges::cbegin(b) == &globalBuff[1]); assert(std::ranges::begin(bb) == &globalBuff[1]); assert(std::ranges::cbegin(bb) == &globalBuff[1]); BeginFunctionEnabledBorrowing c{}; const BeginFunctionEnabledBorrowing cc{}; assert(std::ranges::begin(std::move(c)) == &globalBuff[2]); assert(std::ranges::cbegin(std::move(c)) == &globalBuff[2]); assert(std::ranges::begin(std::move(cc)) == &globalBuff[2]); assert(std::ranges::cbegin(std::move(cc)) == &globalBuff[2]); BeginFunctionReturnsEmptyPtr d{}; const BeginFunctionReturnsEmptyPtr dd{}; assert(std::ranges::begin(d) == &d.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic assert(std::ranges::cbegin(d) == &d.x); assert(std::ranges::begin(dd) == &dd.x); assert(std::ranges::cbegin(dd) == &dd.x); BeginFunctionWithDataMember e{}; const BeginFunctionWithDataMember ee{}; assert(std::ranges::begin(e) == &e.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic assert(std::ranges::begin(ee) == &ee.x); assert(std::ranges::cbegin(e) == &e.x); assert(std::ranges::cbegin(ee) == &ee.x); BeginFunctionWithPrivateBeginMember f{}; const BeginFunctionWithPrivateBeginMember ff{}; assert(std::ranges::begin(f) == &f.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic assert(std::ranges::cbegin(f) == &f.y); assert(std::ranges::begin(ff) == &ff.y); assert(std::ranges::cbegin(ff) == &ff.y); return true; } ASSERT_NOEXCEPT(std::ranges::begin(std::declval())); ASSERT_NOEXCEPT(std::ranges::cbegin(std::declval())); struct NoThrowMemberBegin { ThrowingIterator begin() const noexcept; // auto(t.begin()) doesn't throw } ntmb; static_assert(noexcept(std::ranges::begin(ntmb))); static_assert(noexcept(std::ranges::cbegin(ntmb))); struct NoThrowADLBegin { friend ThrowingIterator begin(NoThrowADLBegin&) noexcept; // auto(begin(t)) doesn't throw friend ThrowingIterator begin(const NoThrowADLBegin&) noexcept; } ntab; static_assert(noexcept(std::ranges::begin(ntab))); static_assert(noexcept(std::ranges::cbegin(ntab))); struct NoThrowMemberBeginReturnsRef { ThrowingIterator& begin() const noexcept; // auto(t.begin()) may throw } ntmbrr; static_assert(!noexcept(std::ranges::begin(ntmbrr))); static_assert(!noexcept(std::ranges::cbegin(ntmbrr))); struct BeginReturnsArrayRef { auto begin() const noexcept -> int(&)[10]; } brar; static_assert(noexcept(std::ranges::begin(brar))); static_assert(noexcept(std::ranges::cbegin(brar))); // Test ADL-proofing. struct Incomplete; template struct Holder { T t; }; static_assert(!std::is_invocable_v*>); static_assert(!std::is_invocable_v*&>); static_assert(!std::is_invocable_v*>); static_assert(!std::is_invocable_v*&>); int main(int, char**) { static_assert(testReturnTypes()); testArray(); static_assert(testArray()); testBeginMember(); static_assert(testBeginMember()); testBeginFunction(); static_assert(testBeginFunction()); return 0; }