xref: /llvm-project/libcxx/test/std/ranges/range.access/rend.pass.cpp (revision d2baefae6846765eef6a6dd69d4fdf1082ce29ad)
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