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