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