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