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;
rendREndMember45 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
testReturnTypes()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
testArray()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;
rbeginNonConstREndMember129 constexpr int* rbegin() { return nullptr; }
rendNonConstREndMember130 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 {
rbeginEnabledBorrowingREndMember138 constexpr int* rbegin() const { return nullptr; }
rendEnabledBorrowingREndMember139 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;
rbeginREndMemberFunction147 constexpr const int* rbegin() const { return nullptr; }
rendREndMemberFunction148 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;
rbeginEmptyPtrREndMember161 constexpr const Empty* rbegin() const { return nullptr; }
rendEmptyPtrREndMember162 constexpr const Empty* rend() const { return &x; }
163 };
164
testREndMember()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;
rbegin(REndFunction const &)191 friend constexpr const int* rbegin(REndFunction const&) { return nullptr; }
rend(REndFunction const & bf)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 {
rbegin(REndFunctionByValue)234 friend constexpr int* rbegin(REndFunctionByValue) { return nullptr; }
rend(REndFunctionByValue)235 friend constexpr int* rend(REndFunctionByValue) { return &globalBuff[1]; }
236 };
237 static_assert(!std::is_invocable_v<RangeCREndT, REndFunctionByValue>);
238
239 struct REndFunctionEnabledBorrowing {
rbegin(REndFunctionEnabledBorrowing)240 friend constexpr int* rbegin(REndFunctionEnabledBorrowing) { return nullptr; }
rend(REndFunctionEnabledBorrowing)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;
rbegin(REndFunctionReturnsEmptyPtr const &)248 friend constexpr const Empty* rbegin(REndFunctionReturnsEmptyPtr const&) { return nullptr; }
rend(REndFunctionReturnsEmptyPtr const & bf)249 friend constexpr const Empty* rend(REndFunctionReturnsEmptyPtr const& bf) { return &bf.x; }
250 };
251
252 struct REndFunctionWithDataMember {
253 int x;
254 int rend;
rbegin(REndFunctionWithDataMember const &)255 friend constexpr const int* rbegin(REndFunctionWithDataMember const&) { return nullptr; }
rend(REndFunctionWithDataMember const & bf)256 friend constexpr const int* rend(REndFunctionWithDataMember const& bf) { return &bf.x; }
257 };
258
259 struct REndFunctionWithPrivateEndMember : private REndMember {
260 int y;
rbegin(REndFunctionWithPrivateEndMember const &)261 friend constexpr const int* rbegin(REndFunctionWithPrivateEndMember const&) { return nullptr; }
rend(REndFunctionWithPrivateEndMember const & bf)262 friend constexpr const int* rend(REndFunctionWithPrivateEndMember const& bf) { return &bf.y; }
263 };
264
265 struct RBeginMemberEndFunction {
266 int x;
rbeginRBeginMemberEndFunction267 constexpr const int* rbegin() const { return nullptr; }
rend(RBeginMemberEndFunction const & bf)268 friend constexpr const int* rend(RBeginMemberEndFunction const& bf) { return &bf.x; }
269 };
270
testREndFunction()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;
beginMemberBeginEnd322 constexpr bidirectional_iterator<int*> begin() { return bidirectional_iterator<int*>(&b); }
endMemberBeginEnd323 constexpr bidirectional_iterator<int*> end() { return bidirectional_iterator<int*>(&e); }
beginMemberBeginEnd324 constexpr bidirectional_iterator<const char*> begin() const { return bidirectional_iterator<const char*>(&cb); }
endMemberBeginEnd325 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;
begin(FunctionBeginEnd & v)334 friend constexpr bidirectional_iterator<int*> begin(FunctionBeginEnd& v) {
335 return bidirectional_iterator<int*>(&v.b);
336 }
end(FunctionBeginEnd & v)337 friend constexpr bidirectional_iterator<int*> end(FunctionBeginEnd& v) { return bidirectional_iterator<int*>(&v.e); }
begin(const FunctionBeginEnd & v)338 friend constexpr bidirectional_iterator<const char*> begin(const FunctionBeginEnd& v) {
339 return bidirectional_iterator<const char*>(&v.cb);
340 }
end(const FunctionBeginEnd & v)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;
beginMemberBeginFunctionEnd352 constexpr bidirectional_iterator<int*> begin() { return bidirectional_iterator<int*>(&b); }
end(MemberBeginFunctionEnd & v)353 friend constexpr bidirectional_iterator<int*> end(MemberBeginFunctionEnd& v) {
354 return bidirectional_iterator<int*>(&v.e);
355 }
beginMemberBeginFunctionEnd356 constexpr bidirectional_iterator<const char*> begin() const { return bidirectional_iterator<const char*>(&cb); }
end(const MemberBeginFunctionEnd & v)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;
begin(FunctionBeginMemberEnd & v)368 friend constexpr bidirectional_iterator<int*> begin(FunctionBeginMemberEnd& v) {
369 return bidirectional_iterator<int*>(&v.b);
370 }
endFunctionBeginMemberEnd371 constexpr bidirectional_iterator<int*> end() { return bidirectional_iterator<int*>(&e); }
begin(const FunctionBeginMemberEnd & v)372 friend constexpr bidirectional_iterator<const char*> begin(const FunctionBeginMemberEnd& v) {
373 return bidirectional_iterator<const char*>(&v.cb);
374 }
endFunctionBeginMemberEnd375 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
testBeginEnd()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
main(int,char **)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