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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // UNSUPPORTED: c++03, c++11, c++14, c++17 10 // UNSUPPORTED: libcpp-no-concepts 11 // UNSUPPORTED: libcpp-has-no-incomplete-ranges 12 13 // std::ranges::rend 14 // std::ranges::crend 15 16 #include <ranges> 17 18 #include <cassert> 19 #include <utility> 20 #include "test_macros.h" 21 #include "test_iterators.h" 22 23 using RangeREndT = decltype(std::ranges::rend); 24 using RangeCREndT = decltype(std::ranges::crend); 25 26 static int globalBuff[8]; 27 28 static_assert(!std::is_invocable_v<RangeREndT, int (&&)[]>); 29 static_assert(!std::is_invocable_v<RangeREndT, int (&)[]>); 30 static_assert(!std::is_invocable_v<RangeREndT, int (&&)[10]>); 31 static_assert( std::is_invocable_v<RangeREndT, int (&)[10]>); 32 static_assert(!std::is_invocable_v<RangeCREndT, int (&&)[]>); 33 static_assert(!std::is_invocable_v<RangeCREndT, int (&)[]>); 34 static_assert(!std::is_invocable_v<RangeCREndT, int (&&)[10]>); 35 static_assert( std::is_invocable_v<RangeCREndT, int (&)[10]>); 36 37 struct Incomplete; 38 static_assert(!std::is_invocable_v<RangeREndT, Incomplete(&&)[]>); 39 static_assert(!std::is_invocable_v<RangeREndT, Incomplete(&&)[42]>); 40 static_assert(!std::is_invocable_v<RangeCREndT, Incomplete(&&)[]>); 41 static_assert(!std::is_invocable_v<RangeCREndT, Incomplete(&&)[42]>); 42 43 struct REndMember { 44 int x; 45 const int* rbegin() const; 46 constexpr const int* rend() const { return &x; } 47 }; 48 49 // Ensure that we can't call with rvalues with borrowing disabled. 50 static_assert( std::is_invocable_v<RangeREndT, REndMember&>); 51 static_assert(!std::is_invocable_v<RangeREndT, REndMember &&>); 52 static_assert( std::is_invocable_v<RangeREndT, REndMember const&>); 53 static_assert(!std::is_invocable_v<RangeREndT, REndMember const&&>); 54 static_assert( std::is_invocable_v<RangeCREndT, REndMember &>); 55 static_assert(!std::is_invocable_v<RangeCREndT, REndMember &&>); 56 static_assert( std::is_invocable_v<RangeCREndT, REndMember const&>); 57 static_assert(!std::is_invocable_v<RangeCREndT, REndMember const&&>); 58 59 constexpr bool testReturnTypes() { 60 { 61 int *x[2]; 62 ASSERT_SAME_TYPE(decltype(std::ranges::rend(x)), std::reverse_iterator<int**>); 63 ASSERT_SAME_TYPE(decltype(std::ranges::crend(x)), std::reverse_iterator<int* const*>); 64 } 65 66 { 67 int x[2][2]; 68 ASSERT_SAME_TYPE(decltype(std::ranges::rend(x)), std::reverse_iterator<int(*)[2]>); 69 ASSERT_SAME_TYPE(decltype(std::ranges::crend(x)), std::reverse_iterator<const int(*)[2]>); 70 } 71 72 { 73 struct Different { 74 char* rbegin(); 75 sentinel_wrapper<char*>& rend(); 76 short* rbegin() const; 77 sentinel_wrapper<short*>& rend() const; 78 } x; 79 ASSERT_SAME_TYPE(decltype(std::ranges::rend(x)), sentinel_wrapper<char*>); 80 ASSERT_SAME_TYPE(decltype(std::ranges::crend(x)), sentinel_wrapper<short*>); 81 } 82 83 return true; 84 } 85 86 constexpr bool testArray() { 87 int a[2]; 88 assert(std::ranges::rend(a).base() == a); 89 assert(std::ranges::crend(a).base() == a); 90 91 int b[2][2]; 92 assert(std::ranges::rend(b).base() == b); 93 assert(std::ranges::crend(b).base() == b); 94 95 REndMember c[2]; 96 assert(std::ranges::rend(c).base() == c); 97 assert(std::ranges::crend(c).base() == c); 98 99 return true; 100 } 101 102 struct REndMemberReturnsInt { 103 int rbegin() const; 104 int rend() const; 105 }; 106 static_assert(!std::is_invocable_v<RangeREndT, REndMemberReturnsInt const&>); 107 108 struct REndMemberReturnsVoidPtr { 109 const void *rbegin() const; 110 const void *rend() const; 111 }; 112 static_assert(!std::is_invocable_v<RangeREndT, REndMemberReturnsVoidPtr const&>); 113 114 struct PtrConvertible { 115 operator int*() const; 116 }; 117 struct PtrConvertibleREndMember { 118 PtrConvertible rbegin() const; 119 PtrConvertible rend() const; 120 }; 121 static_assert(!std::is_invocable_v<RangeREndT, PtrConvertibleREndMember const&>); 122 123 struct NoRBeginMember { 124 constexpr const int* rend(); 125 }; 126 static_assert(!std::is_invocable_v<RangeREndT, NoRBeginMember const&>); 127 128 struct NonConstREndMember { 129 int x; 130 constexpr int* rbegin() { return nullptr; } 131 constexpr int* rend() { return &x; } 132 }; 133 static_assert( std::is_invocable_v<RangeREndT, NonConstREndMember &>); 134 static_assert(!std::is_invocable_v<RangeREndT, NonConstREndMember const&>); 135 static_assert(!std::is_invocable_v<RangeCREndT, NonConstREndMember &>); 136 static_assert(!std::is_invocable_v<RangeCREndT, NonConstREndMember const&>); 137 138 struct EnabledBorrowingREndMember { 139 constexpr int* rbegin() const { return nullptr; } 140 constexpr int* rend() const { return &globalBuff[0]; } 141 }; 142 143 template <> 144 inline constexpr bool std::ranges::enable_borrowed_range<EnabledBorrowingREndMember> = true; 145 146 struct REndMemberFunction { 147 int x; 148 constexpr const int* rbegin() const { return nullptr; } 149 constexpr const int* rend() const { return &x; } 150 friend constexpr int* rend(REndMemberFunction const&); 151 }; 152 153 struct Empty { }; 154 struct EmptyEndMember { 155 Empty rbegin() const; 156 Empty rend() const; 157 }; 158 static_assert(!std::is_invocable_v<RangeREndT, EmptyEndMember const&>); 159 160 struct EmptyPtrREndMember { 161 Empty x; 162 constexpr const Empty* rbegin() const { return nullptr; } 163 constexpr const Empty* rend() const { return &x; } 164 }; 165 166 constexpr bool testREndMember() { 167 REndMember a; 168 assert(std::ranges::rend(a) == &a.x); 169 assert(std::ranges::crend(a) == &a.x); 170 171 NonConstREndMember b; 172 assert(std::ranges::rend(b) == &b.x); 173 static_assert(!std::is_invocable_v<RangeCREndT, decltype((b))>); 174 175 EnabledBorrowingREndMember c; 176 assert(std::ranges::rend(std::move(c)) == &globalBuff[0]); 177 assert(std::ranges::crend(std::move(c)) == &globalBuff[0]); 178 179 REndMemberFunction d; 180 assert(std::ranges::rend(d) == &d.x); 181 assert(std::ranges::crend(d) == &d.x); 182 183 EmptyPtrREndMember e; 184 assert(std::ranges::rend(e) == &e.x); 185 assert(std::ranges::crend(e) == &e.x); 186 187 return true; 188 } 189 190 struct REndFunction { 191 int x; 192 friend constexpr const int* rbegin(REndFunction const&) { return nullptr; } 193 friend constexpr const int* rend(REndFunction const& bf) { return &bf.x; } 194 }; 195 196 static_assert( std::is_invocable_v<RangeREndT, REndFunction const&>); 197 static_assert(!std::is_invocable_v<RangeREndT, REndFunction &&>); 198 199 static_assert( std::is_invocable_v<RangeREndT, REndFunction const&>); 200 static_assert(!std::is_invocable_v<RangeREndT, REndFunction &&>); 201 static_assert(!std::is_invocable_v<RangeREndT, REndFunction &>); 202 static_assert( std::is_invocable_v<RangeCREndT, REndFunction const&>); 203 static_assert( std::is_invocable_v<RangeCREndT, REndFunction &>); 204 205 struct REndFunctionReturnsInt { 206 friend constexpr int rbegin(REndFunctionReturnsInt const&); 207 friend constexpr int rend(REndFunctionReturnsInt const&); 208 }; 209 static_assert(!std::is_invocable_v<RangeREndT, REndFunctionReturnsInt const&>); 210 211 struct REndFunctionReturnsVoidPtr { 212 friend constexpr void* rbegin(REndFunctionReturnsVoidPtr const&); 213 friend constexpr void* rend(REndFunctionReturnsVoidPtr const&); 214 }; 215 static_assert(!std::is_invocable_v<RangeREndT, REndFunctionReturnsVoidPtr const&>); 216 217 struct REndFunctionReturnsEmpty { 218 friend constexpr Empty rbegin(REndFunctionReturnsEmpty const&); 219 friend constexpr Empty rend(REndFunctionReturnsEmpty const&); 220 }; 221 static_assert(!std::is_invocable_v<RangeREndT, REndFunctionReturnsEmpty const&>); 222 223 struct REndFunctionReturnsPtrConvertible { 224 friend constexpr PtrConvertible rbegin(REndFunctionReturnsPtrConvertible const&); 225 friend constexpr PtrConvertible rend(REndFunctionReturnsPtrConvertible const&); 226 }; 227 static_assert(!std::is_invocable_v<RangeREndT, REndFunctionReturnsPtrConvertible const&>); 228 229 struct NoRBeginFunction { 230 friend constexpr const int* rend(NoRBeginFunction const&); 231 }; 232 static_assert(!std::is_invocable_v<RangeREndT, NoRBeginFunction const&>); 233 234 struct REndFunctionByValue { 235 friend constexpr int* rbegin(REndFunctionByValue) { return nullptr; } 236 friend constexpr int* rend(REndFunctionByValue) { return &globalBuff[1]; } 237 }; 238 static_assert(!std::is_invocable_v<RangeCREndT, REndFunctionByValue>); 239 240 struct REndFunctionEnabledBorrowing { 241 friend constexpr int* rbegin(REndFunctionEnabledBorrowing) { return nullptr; } 242 friend constexpr int* rend(REndFunctionEnabledBorrowing) { return &globalBuff[2]; } 243 }; 244 template<> 245 inline constexpr bool std::ranges::enable_borrowed_range<REndFunctionEnabledBorrowing> = true; 246 247 struct REndFunctionReturnsEmptyPtr { 248 Empty x; 249 friend constexpr const Empty* rbegin(REndFunctionReturnsEmptyPtr const&) { return nullptr; } 250 friend constexpr const Empty* rend(REndFunctionReturnsEmptyPtr const& bf) { return &bf.x; } 251 }; 252 253 struct REndFunctionWithDataMember { 254 int x; 255 int rend; 256 friend constexpr const int* rbegin(REndFunctionWithDataMember const&) { return nullptr; } 257 friend constexpr const int* rend(REndFunctionWithDataMember const& bf) { return &bf.x; } 258 }; 259 260 struct REndFunctionWithPrivateEndMember : private REndMember { 261 int y; 262 friend constexpr const int* rbegin(REndFunctionWithPrivateEndMember const&) { return nullptr; } 263 friend constexpr const int* rend(REndFunctionWithPrivateEndMember const& bf) { return &bf.y; } 264 }; 265 266 struct RBeginMemberEndFunction { 267 int x; 268 constexpr const int* rbegin() const { return nullptr; } 269 friend constexpr const int* rend(RBeginMemberEndFunction const& bf) { return &bf.x; } 270 }; 271 272 constexpr bool testREndFunction() { 273 const REndFunction a{}; 274 assert(std::ranges::rend(a) == &a.x); 275 assert(std::ranges::crend(a) == &a.x); 276 REndFunction aa{}; 277 static_assert(!std::is_invocable_v<RangeREndT, decltype((aa))>); 278 assert(std::ranges::crend(aa) == &aa.x); 279 280 REndFunctionByValue b; 281 assert(std::ranges::rend(b) == &globalBuff[1]); 282 assert(std::ranges::crend(b) == &globalBuff[1]); 283 284 REndFunctionEnabledBorrowing c; 285 assert(std::ranges::rend(std::move(c)) == &globalBuff[2]); 286 assert(std::ranges::crend(std::move(c)) == &globalBuff[2]); 287 288 const REndFunctionReturnsEmptyPtr d{}; 289 assert(std::ranges::rend(d) == &d.x); 290 assert(std::ranges::crend(d) == &d.x); 291 REndFunctionReturnsEmptyPtr dd{}; 292 static_assert(!std::is_invocable_v<RangeREndT, decltype((dd))>); 293 assert(std::ranges::crend(dd) == &dd.x); 294 295 const REndFunctionWithDataMember e{}; 296 assert(std::ranges::rend(e) == &e.x); 297 assert(std::ranges::crend(e) == &e.x); 298 REndFunctionWithDataMember ee{}; 299 static_assert(!std::is_invocable_v<RangeREndT, decltype((ee))>); 300 assert(std::ranges::crend(ee) == &ee.x); 301 302 const REndFunctionWithPrivateEndMember f{}; 303 assert(std::ranges::rend(f) == &f.y); 304 assert(std::ranges::crend(f) == &f.y); 305 REndFunctionWithPrivateEndMember ff{}; 306 static_assert(!std::is_invocable_v<RangeREndT, decltype((ff))>); 307 assert(std::ranges::crend(ff) == &ff.y); 308 309 const RBeginMemberEndFunction g{}; 310 assert(std::ranges::rend(g) == &g.x); 311 assert(std::ranges::crend(g) == &g.x); 312 RBeginMemberEndFunction gg{}; 313 static_assert(!std::is_invocable_v<RangeREndT, decltype((gg))>); 314 assert(std::ranges::crend(gg) == &gg.x); 315 316 return true; 317 } 318 319 320 struct MemberBeginEnd { 321 int b, e; 322 char cb, ce; 323 constexpr bidirectional_iterator<int*> begin() { return bidirectional_iterator<int*>(&b); } 324 constexpr bidirectional_iterator<int*> end() { return bidirectional_iterator<int*>(&e); } 325 constexpr bidirectional_iterator<const char*> begin() const { return bidirectional_iterator<const char*>(&cb); } 326 constexpr bidirectional_iterator<const char*> end() const { return bidirectional_iterator<const char*>(&ce); } 327 }; 328 static_assert( std::is_invocable_v<RangeREndT, MemberBeginEnd&>); 329 static_assert( std::is_invocable_v<RangeREndT, MemberBeginEnd const&>); 330 static_assert( std::is_invocable_v<RangeCREndT, MemberBeginEnd const&>); 331 332 struct FunctionBeginEnd { 333 int b, e; 334 char cb, ce; 335 friend constexpr bidirectional_iterator<int*> begin(FunctionBeginEnd& v) { 336 return bidirectional_iterator<int*>(&v.b); 337 } 338 friend constexpr bidirectional_iterator<int*> end(FunctionBeginEnd& v) { return bidirectional_iterator<int*>(&v.e); } 339 friend constexpr bidirectional_iterator<const char*> begin(const FunctionBeginEnd& v) { 340 return bidirectional_iterator<const char*>(&v.cb); 341 } 342 friend constexpr bidirectional_iterator<const char*> end(const FunctionBeginEnd& v) { 343 return bidirectional_iterator<const char*>(&v.ce); 344 } 345 }; 346 static_assert( std::is_invocable_v<RangeREndT, FunctionBeginEnd&>); 347 static_assert( std::is_invocable_v<RangeREndT, FunctionBeginEnd const&>); 348 static_assert( std::is_invocable_v<RangeCREndT, FunctionBeginEnd const&>); 349 350 struct MemberBeginFunctionEnd { 351 int b, e; 352 char cb, ce; 353 constexpr bidirectional_iterator<int*> begin() { return bidirectional_iterator<int*>(&b); } 354 friend constexpr bidirectional_iterator<int*> end(MemberBeginFunctionEnd& v) { 355 return bidirectional_iterator<int*>(&v.e); 356 } 357 constexpr bidirectional_iterator<const char*> begin() const { return bidirectional_iterator<const char*>(&cb); } 358 friend constexpr bidirectional_iterator<const char*> end(const MemberBeginFunctionEnd& v) { 359 return bidirectional_iterator<const char*>(&v.ce); 360 } 361 }; 362 static_assert( std::is_invocable_v<RangeREndT, MemberBeginFunctionEnd&>); 363 static_assert( std::is_invocable_v<RangeREndT, MemberBeginFunctionEnd const&>); 364 static_assert( std::is_invocable_v<RangeCREndT, MemberBeginFunctionEnd const&>); 365 366 struct FunctionBeginMemberEnd { 367 int b, e; 368 char cb, ce; 369 friend constexpr bidirectional_iterator<int*> begin(FunctionBeginMemberEnd& v) { 370 return bidirectional_iterator<int*>(&v.b); 371 } 372 constexpr bidirectional_iterator<int*> end() { return bidirectional_iterator<int*>(&e); } 373 friend constexpr bidirectional_iterator<const char*> begin(const FunctionBeginMemberEnd& v) { 374 return bidirectional_iterator<const char*>(&v.cb); 375 } 376 constexpr bidirectional_iterator<const char*> end() const { return bidirectional_iterator<const char*>(&ce); } 377 }; 378 static_assert( std::is_invocable_v<RangeREndT, FunctionBeginMemberEnd&>); 379 static_assert( std::is_invocable_v<RangeREndT, FunctionBeginMemberEnd const&>); 380 static_assert( std::is_invocable_v<RangeCREndT, FunctionBeginMemberEnd const&>); 381 382 struct MemberBeginEndDifferentTypes { 383 bidirectional_iterator<int*> begin(); 384 bidirectional_iterator<const int*> end(); 385 }; 386 static_assert(!std::is_invocable_v<RangeREndT, MemberBeginEndDifferentTypes&>); 387 static_assert(!std::is_invocable_v<RangeCREndT, MemberBeginEndDifferentTypes&>); 388 389 struct FunctionBeginEndDifferentTypes { 390 friend bidirectional_iterator<int*> begin(FunctionBeginEndDifferentTypes&); 391 friend bidirectional_iterator<const int*> end(FunctionBeginEndDifferentTypes&); 392 }; 393 static_assert(!std::is_invocable_v<RangeREndT, FunctionBeginEndDifferentTypes&>); 394 static_assert(!std::is_invocable_v<RangeCREndT, FunctionBeginEndDifferentTypes&>); 395 396 struct MemberBeginEndForwardIterators { 397 forward_iterator<int*> begin(); 398 forward_iterator<int*> end(); 399 }; 400 static_assert(!std::is_invocable_v<RangeREndT, MemberBeginEndForwardIterators&>); 401 static_assert(!std::is_invocable_v<RangeCREndT, MemberBeginEndForwardIterators&>); 402 403 struct FunctionBeginEndForwardIterators { 404 friend forward_iterator<int*> begin(FunctionBeginEndForwardIterators&); 405 friend forward_iterator<int*> end(FunctionBeginEndForwardIterators&); 406 }; 407 static_assert(!std::is_invocable_v<RangeREndT, FunctionBeginEndForwardIterators&>); 408 static_assert(!std::is_invocable_v<RangeCREndT, FunctionBeginEndForwardIterators&>); 409 410 struct MemberBeginOnly { 411 bidirectional_iterator<int*> begin() const; 412 }; 413 static_assert(!std::is_invocable_v<RangeREndT, MemberBeginOnly&>); 414 static_assert(!std::is_invocable_v<RangeCREndT, MemberBeginOnly&>); 415 416 struct FunctionBeginOnly { 417 friend bidirectional_iterator<int*> begin(FunctionBeginOnly&); 418 }; 419 static_assert(!std::is_invocable_v<RangeREndT, FunctionBeginOnly&>); 420 static_assert(!std::is_invocable_v<RangeCREndT, FunctionBeginOnly&>); 421 422 struct MemberEndOnly { 423 bidirectional_iterator<int*> end() const; 424 }; 425 static_assert(!std::is_invocable_v<RangeREndT, MemberEndOnly&>); 426 static_assert(!std::is_invocable_v<RangeCREndT, MemberEndOnly&>); 427 428 struct FunctionEndOnly { 429 friend bidirectional_iterator<int*> end(FunctionEndOnly&); 430 }; 431 static_assert(!std::is_invocable_v<RangeREndT, FunctionEndOnly&>); 432 static_assert(!std::is_invocable_v<RangeCREndT, FunctionEndOnly&>); 433 434 // Make sure there is no clash between the following cases: 435 // - the case that handles classes defining member `rbegin` and `rend` functions; 436 // - the case that handles classes defining `begin` and `end` functions returning reversible iterators. 437 struct MemberBeginAndRBegin { 438 int* begin() const; 439 int* end() const; 440 int* rbegin() const; 441 int* rend() const; 442 }; 443 static_assert( std::is_invocable_v<RangeREndT, MemberBeginAndRBegin&>); 444 static_assert( std::is_invocable_v<RangeCREndT, MemberBeginAndRBegin&>); 445 static_assert( std::same_as<std::invoke_result_t<RangeREndT, MemberBeginAndRBegin&>, int*>); 446 static_assert( std::same_as<std::invoke_result_t<RangeCREndT, MemberBeginAndRBegin&>, int*>); 447 448 constexpr bool testBeginEnd() { 449 MemberBeginEnd a{}; 450 const MemberBeginEnd aa{}; 451 assert(std::ranges::rend(a).base().base() == &a.b); 452 assert(std::ranges::crend(a).base().base() == &a.cb); 453 assert(std::ranges::rend(aa).base().base() == &aa.cb); 454 assert(std::ranges::crend(aa).base().base() == &aa.cb); 455 456 FunctionBeginEnd b{}; 457 const FunctionBeginEnd bb{}; 458 assert(std::ranges::rend(b).base().base() == &b.b); 459 assert(std::ranges::crend(b).base().base() == &b.cb); 460 assert(std::ranges::rend(bb).base().base() == &bb.cb); 461 assert(std::ranges::crend(bb).base().base() == &bb.cb); 462 463 MemberBeginFunctionEnd c{}; 464 const MemberBeginFunctionEnd cc{}; 465 assert(std::ranges::rend(c).base().base() == &c.b); 466 assert(std::ranges::crend(c).base().base() == &c.cb); 467 assert(std::ranges::rend(cc).base().base() == &cc.cb); 468 assert(std::ranges::crend(cc).base().base() == &cc.cb); 469 470 FunctionBeginMemberEnd d{}; 471 const FunctionBeginMemberEnd dd{}; 472 assert(std::ranges::rend(d).base().base() == &d.b); 473 assert(std::ranges::crend(d).base().base() == &d.cb); 474 assert(std::ranges::rend(dd).base().base() == &dd.cb); 475 assert(std::ranges::crend(dd).base().base() == &dd.cb); 476 477 return true; 478 } 479 480 481 ASSERT_NOEXCEPT(std::ranges::rend(std::declval<int (&)[10]>())); 482 ASSERT_NOEXCEPT(std::ranges::crend(std::declval<int (&)[10]>())); 483 484 struct NoThrowMemberREnd { 485 ThrowingIterator<int> rbegin() const; 486 ThrowingIterator<int> rend() const noexcept; // auto(t.rend()) doesn't throw 487 } ntmre; 488 static_assert(noexcept(std::ranges::rend(ntmre))); 489 static_assert(noexcept(std::ranges::crend(ntmre))); 490 491 struct NoThrowADLREnd { 492 ThrowingIterator<int> rbegin() const; 493 friend ThrowingIterator<int> rend(NoThrowADLREnd&) noexcept; // auto(rend(t)) doesn't throw 494 friend ThrowingIterator<int> rend(const NoThrowADLREnd&) noexcept; 495 } ntare; 496 static_assert(noexcept(std::ranges::rend(ntare))); 497 static_assert(noexcept(std::ranges::crend(ntare))); 498 499 struct NoThrowMemberREndReturnsRef { 500 ThrowingIterator<int> rbegin() const; 501 ThrowingIterator<int>& rend() const noexcept; // auto(t.rend()) may throw 502 } ntmrerr; 503 static_assert(!noexcept(std::ranges::rend(ntmrerr))); 504 static_assert(!noexcept(std::ranges::crend(ntmrerr))); 505 506 struct REndReturnsArrayRef { 507 auto rbegin() const noexcept -> int(&)[10]; 508 auto rend() const noexcept -> int(&)[10]; 509 } rerar; 510 static_assert(noexcept(std::ranges::rend(rerar))); 511 static_assert(noexcept(std::ranges::crend(rerar))); 512 513 struct NoThrowBeginThrowingEnd { 514 int* begin() const noexcept; 515 int* end() const; 516 } ntbte; 517 static_assert(noexcept(std::ranges::rend(ntbte))); 518 static_assert(noexcept(std::ranges::crend(ntbte))); 519 520 struct NoThrowEndThrowingBegin { 521 int* begin() const; 522 int* end() const noexcept; 523 } ntetb; 524 static_assert(!noexcept(std::ranges::rend(ntetb))); 525 static_assert(!noexcept(std::ranges::crend(ntetb))); 526 527 // Test ADL-proofing. 528 struct Incomplete; 529 template<class T> struct Holder { T t; }; 530 static_assert(!std::is_invocable_v<RangeREndT, Holder<Incomplete>*>); 531 static_assert(!std::is_invocable_v<RangeREndT, Holder<Incomplete>*&>); 532 static_assert(!std::is_invocable_v<RangeCREndT, Holder<Incomplete>*>); 533 static_assert(!std::is_invocable_v<RangeCREndT, Holder<Incomplete>*&>); 534 535 int main(int, char**) { 536 static_assert(testReturnTypes()); 537 538 testArray(); 539 static_assert(testArray()); 540 541 testREndMember(); 542 static_assert(testREndMember()); 543 544 testREndFunction(); 545 static_assert(testREndFunction()); 546 547 testBeginEnd(); 548 static_assert(testBeginEnd()); 549 550 return 0; 551 } 552