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