371 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++14, c++1710 11// std::ranges::end12// std::ranges::cend13 14#include <ranges>15 16#include <cassert>17#include <utility>18#include "test_macros.h"19#include "test_iterators.h"20 21using RangeEndT = decltype(std::ranges::end);22using RangeCEndT = decltype(std::ranges::cend);23 24static int globalBuff[8];25 26static_assert(!std::is_invocable_v<RangeEndT, int (&&)[]>);27static_assert(!std::is_invocable_v<RangeEndT, int (&)[]>);28static_assert(!std::is_invocable_v<RangeEndT, int (&&)[10]>);29static_assert( std::is_invocable_v<RangeEndT, int (&)[10]>);30static_assert(!std::is_invocable_v<RangeCEndT, int (&&)[]>);31static_assert(!std::is_invocable_v<RangeCEndT, int (&)[]>);32static_assert(!std::is_invocable_v<RangeCEndT, int (&&)[10]>);33static_assert( std::is_invocable_v<RangeCEndT, int (&)[10]>);34 35struct Incomplete;36static_assert(!std::is_invocable_v<RangeEndT, Incomplete(&&)[]>);37static_assert(!std::is_invocable_v<RangeEndT, Incomplete(&&)[42]>);38static_assert(!std::is_invocable_v<RangeCEndT, Incomplete(&&)[]>);39static_assert(!std::is_invocable_v<RangeCEndT, Incomplete(&&)[42]>);40 41struct EndMember {42 int x;43 const int *begin() const;44 constexpr const int *end() const { return &x; }45};46 47// Ensure that we can't call with rvalues with borrowing disabled.48static_assert( std::is_invocable_v<RangeEndT, EndMember &>);49static_assert(!std::is_invocable_v<RangeEndT, EndMember &&>);50static_assert( std::is_invocable_v<RangeEndT, EndMember const&>);51static_assert(!std::is_invocable_v<RangeEndT, EndMember const&&>);52static_assert( std::is_invocable_v<RangeCEndT, EndMember &>);53static_assert(!std::is_invocable_v<RangeCEndT, EndMember &&>);54static_assert( std::is_invocable_v<RangeCEndT, EndMember const&>);55static_assert(!std::is_invocable_v<RangeCEndT, EndMember const&&>);56 57constexpr bool testReturnTypes() {58 {59 int *x[2];60 ASSERT_SAME_TYPE(decltype(std::ranges::end(x)), int**);61 ASSERT_SAME_TYPE(decltype(std::ranges::cend(x)), int* const*);62 }63 {64 int x[2][2];65 ASSERT_SAME_TYPE(decltype(std::ranges::end(x)), int(*)[2]);66 ASSERT_SAME_TYPE(decltype(std::ranges::cend(x)), const int(*)[2]);67 }68 {69 struct Different {70 char *begin();71 sentinel_wrapper<char*>& end();72 short *begin() const;73 sentinel_wrapper<short*>& end() const;74 } x;75 ASSERT_SAME_TYPE(decltype(std::ranges::end(x)), sentinel_wrapper<char*>);76 ASSERT_SAME_TYPE(decltype(std::ranges::cend(x)), sentinel_wrapper<short*>);77 }78 return true;79}80 81constexpr bool testArray() {82 int a[2];83 assert(std::ranges::end(a) == a + 2);84 assert(std::ranges::cend(a) == a + 2);85 86 int b[2][2];87 assert(std::ranges::end(b) == b + 2);88 assert(std::ranges::cend(b) == b + 2);89 90 EndMember c[2];91 assert(std::ranges::end(c) == c + 2);92 assert(std::ranges::cend(c) == c + 2);93 94 return true;95}96 97struct EndMemberReturnsInt {98 int begin() const;99 int end() const;100};101static_assert(!std::is_invocable_v<RangeEndT, EndMemberReturnsInt const&>);102 103struct EndMemberReturnsVoidPtr {104 const void *begin() const;105 const void *end() const;106};107static_assert(!std::is_invocable_v<RangeEndT, EndMemberReturnsVoidPtr const&>);108 109struct PtrConvertible {110 operator int*() const;111};112struct PtrConvertibleEndMember {113 PtrConvertible begin() const;114 PtrConvertible end() const;115};116static_assert(!std::is_invocable_v<RangeEndT, PtrConvertibleEndMember const&>);117 118struct NoBeginMember {119 constexpr const int *end();120};121static_assert(!std::is_invocable_v<RangeEndT, NoBeginMember const&>);122 123struct NonConstEndMember {124 int x;125 constexpr int *begin() { return nullptr; }126 constexpr int *end() { return &x; }127};128static_assert( std::is_invocable_v<RangeEndT, NonConstEndMember &>);129static_assert(!std::is_invocable_v<RangeEndT, NonConstEndMember const&>);130static_assert(!std::is_invocable_v<RangeCEndT, NonConstEndMember &>);131static_assert(!std::is_invocable_v<RangeCEndT, NonConstEndMember const&>);132 133struct EnabledBorrowingEndMember {134 constexpr int *begin() const { return nullptr; }135 constexpr int *end() const { return &globalBuff[0]; }136};137 138template<>139inline constexpr bool std::ranges::enable_borrowed_range<EnabledBorrowingEndMember> = true;140 141struct EndMemberFunction {142 int x;143 constexpr const int *begin() const { return nullptr; }144 constexpr const int *end() const { return &x; }145 friend constexpr int *end(EndMemberFunction const&);146};147 148struct Empty { };149struct EmptyEndMember {150 Empty begin() const;151 Empty end() const;152};153static_assert(!std::is_invocable_v<RangeEndT, EmptyEndMember const&>);154 155struct EmptyPtrEndMember {156 Empty x;157 constexpr const Empty *begin() const { return nullptr; }158 constexpr const Empty *end() const { return &x; }159};160 161constexpr bool testEndMember() {162 EndMember a;163 assert(std::ranges::end(a) == &a.x);164 assert(std::ranges::cend(a) == &a.x);165 166 NonConstEndMember b;167 assert(std::ranges::end(b) == &b.x);168 static_assert(!std::is_invocable_v<RangeCEndT, decltype((b))>);169 170 EnabledBorrowingEndMember c;171 assert(std::ranges::end(std::move(c)) == &globalBuff[0]);172 assert(std::ranges::cend(std::move(c)) == &globalBuff[0]);173 174 EndMemberFunction d;175 assert(std::ranges::end(d) == &d.x);176 assert(std::ranges::cend(d) == &d.x);177 178 EmptyPtrEndMember e;179 assert(std::ranges::end(e) == &e.x);180 assert(std::ranges::cend(e) == &e.x);181 182 return true;183}184 185struct EndFunction {186 int x;187 friend constexpr const int *begin(EndFunction const&) { return nullptr; }188 friend constexpr const int *end(EndFunction const& bf) { return &bf.x; }189};190 191static_assert( std::is_invocable_v<RangeEndT, EndFunction const&>);192static_assert(!std::is_invocable_v<RangeEndT, EndFunction &&>);193 194static_assert( std::is_invocable_v<RangeEndT, EndFunction const&>);195static_assert(!std::is_invocable_v<RangeEndT, EndFunction &&>);196static_assert(std::is_invocable_v<RangeEndT, EndFunction&>); // Ill-formed before P2602R2 Poison Pills are Too Toxic197static_assert( std::is_invocable_v<RangeCEndT, EndFunction const&>);198static_assert( std::is_invocable_v<RangeCEndT, EndFunction &>);199 200struct EndFunctionReturnsInt {201 friend constexpr int begin(EndFunctionReturnsInt const&);202 friend constexpr int end(EndFunctionReturnsInt const&);203};204static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsInt const&>);205 206struct EndFunctionReturnsVoidPtr {207 friend constexpr void *begin(EndFunctionReturnsVoidPtr const&);208 friend constexpr void *end(EndFunctionReturnsVoidPtr const&);209};210static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsVoidPtr const&>);211 212struct EndFunctionReturnsEmpty {213 friend constexpr Empty begin(EndFunctionReturnsEmpty const&);214 friend constexpr Empty end(EndFunctionReturnsEmpty const&);215};216static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsEmpty const&>);217 218struct EndFunctionReturnsPtrConvertible {219 friend constexpr PtrConvertible begin(EndFunctionReturnsPtrConvertible const&);220 friend constexpr PtrConvertible end(EndFunctionReturnsPtrConvertible const&);221};222static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsPtrConvertible const&>);223 224struct NoBeginFunction {225 friend constexpr const int *end(NoBeginFunction const&);226};227static_assert(!std::is_invocable_v<RangeEndT, NoBeginFunction const&>);228 229struct EndFunctionByValue {230 friend constexpr int *begin(EndFunctionByValue) { return nullptr; }231 friend constexpr int *end(EndFunctionByValue) { return &globalBuff[1]; }232};233static_assert(!std::is_invocable_v<RangeCEndT, EndFunctionByValue>);234 235struct EndFunctionEnabledBorrowing {236 friend constexpr int *begin(EndFunctionEnabledBorrowing) { return nullptr; }237 friend constexpr int *end(EndFunctionEnabledBorrowing) { return &globalBuff[2]; }238};239template<>240inline constexpr bool std::ranges::enable_borrowed_range<EndFunctionEnabledBorrowing> = true;241 242struct EndFunctionReturnsEmptyPtr {243 Empty x;244 friend constexpr const Empty *begin(EndFunctionReturnsEmptyPtr const&) { return nullptr; }245 friend constexpr const Empty *end(EndFunctionReturnsEmptyPtr const& bf) { return &bf.x; }246};247 248struct EndFunctionWithDataMember {249 int x;250 int end;251 friend constexpr const int *begin(EndFunctionWithDataMember const&) { return nullptr; }252 friend constexpr const int *end(EndFunctionWithDataMember const& bf) { return &bf.x; }253};254 255struct EndFunctionWithPrivateEndMember {256 int y;257 friend constexpr const int *begin(EndFunctionWithPrivateEndMember const&) { return nullptr; }258 friend constexpr const int *end(EndFunctionWithPrivateEndMember const& bf) { return &bf.y; }259private:260 const int *end() const;261};262 263struct BeginMemberEndFunction {264 int x;265 constexpr const int *begin() const { return nullptr; }266 friend constexpr const int *end(BeginMemberEndFunction const& bf) { return &bf.x; }267};268 269constexpr bool testEndFunction() {270 const EndFunction a{};271 assert(std::ranges::end(a) == &a.x);272 assert(std::ranges::cend(a) == &a.x);273 EndFunction aa{};274 assert(std::ranges::end(aa) == &aa.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic275 assert(std::ranges::cend(aa) == &aa.x);276 277 EndFunctionByValue b;278 assert(std::ranges::end(b) == &globalBuff[1]);279 assert(std::ranges::cend(b) == &globalBuff[1]);280 281 EndFunctionEnabledBorrowing c;282 assert(std::ranges::end(std::move(c)) == &globalBuff[2]);283 assert(std::ranges::cend(std::move(c)) == &globalBuff[2]);284 285 const EndFunctionReturnsEmptyPtr d{};286 assert(std::ranges::end(d) == &d.x);287 assert(std::ranges::cend(d) == &d.x);288 EndFunctionReturnsEmptyPtr dd{};289 assert(std::ranges::end(dd) == &dd.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic290 assert(std::ranges::cend(dd) == &dd.x);291 292 const EndFunctionWithDataMember e{};293 assert(std::ranges::end(e) == &e.x);294 assert(std::ranges::cend(e) == &e.x);295 EndFunctionWithDataMember ee{};296 assert(std::ranges::end(ee) == &ee.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic297 assert(std::ranges::cend(ee) == &ee.x);298 299 const EndFunctionWithPrivateEndMember f{};300 assert(std::ranges::end(f) == &f.y);301 assert(std::ranges::cend(f) == &f.y);302 EndFunctionWithPrivateEndMember ff{};303 assert(std::ranges::end(ff) == &ff.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic304 assert(std::ranges::cend(ff) == &ff.y);305 306 const BeginMemberEndFunction g{};307 assert(std::ranges::end(g) == &g.x);308 assert(std::ranges::cend(g) == &g.x);309 BeginMemberEndFunction gg{};310 assert(std::ranges::end(gg) == &gg.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic311 assert(std::ranges::cend(gg) == &gg.x);312 313 return true;314}315 316 317ASSERT_NOEXCEPT(std::ranges::end(std::declval<int (&)[10]>()));318ASSERT_NOEXCEPT(std::ranges::cend(std::declval<int (&)[10]>()));319 320struct NoThrowMemberEnd {321 ThrowingIterator<int> begin() const;322 ThrowingIterator<int> end() const noexcept; // auto(t.end()) doesn't throw323} ntme;324static_assert(noexcept(std::ranges::end(ntme)));325static_assert(noexcept(std::ranges::cend(ntme)));326 327struct NoThrowADLEnd {328 ThrowingIterator<int> begin() const;329 friend ThrowingIterator<int> end(NoThrowADLEnd&) noexcept; // auto(end(t)) doesn't throw330 friend ThrowingIterator<int> end(const NoThrowADLEnd&) noexcept;331} ntae;332static_assert(noexcept(std::ranges::end(ntae)));333static_assert(noexcept(std::ranges::cend(ntae)));334 335struct NoThrowMemberEndReturnsRef {336 ThrowingIterator<int> begin() const;337 ThrowingIterator<int>& end() const noexcept; // auto(t.end()) may throw338} ntmerr;339static_assert(!noexcept(std::ranges::end(ntmerr)));340static_assert(!noexcept(std::ranges::cend(ntmerr)));341 342struct EndReturnsArrayRef {343 auto begin() const noexcept -> int(&)[10];344 auto end() const noexcept -> int(&)[10];345} erar;346static_assert(noexcept(std::ranges::end(erar)));347static_assert(noexcept(std::ranges::cend(erar)));348 349// Test ADL-proofing.350struct Incomplete;351template<class T> struct Holder { T t; };352static_assert(!std::is_invocable_v<RangeEndT, Holder<Incomplete>*>);353static_assert(!std::is_invocable_v<RangeEndT, Holder<Incomplete>*&>);354static_assert(!std::is_invocable_v<RangeCEndT, Holder<Incomplete>*>);355static_assert(!std::is_invocable_v<RangeCEndT, Holder<Incomplete>*&>);356 357int main(int, char**) {358 static_assert(testReturnTypes());359 360 testArray();361 static_assert(testArray());362 363 testEndMember();364 static_assert(testEndMember());365 366 testEndFunction();367 static_assert(testEndFunction());368 369 return 0;370}371