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(
191 std::is_invocable_v<RangeRBeginT, RBeginFunction&>); // Ill-formed before P2602R2 Poison Pills are Too Toxic
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 {
rbegin(RBeginFunctionByValue)218 friend constexpr int *rbegin(RBeginFunctionByValue) { return globalBuff + 1; }
219 };
220 static_assert(!std::is_invocable_v<RangeCRBeginT, RBeginFunctionByValue>);
221
222 struct RBeginFunctionEnabledBorrowing {
rbegin(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;
rbegin(RBeginFunctionReturnsEmptyPtr const & bf)231 friend constexpr const Empty *rbegin(RBeginFunctionReturnsEmptyPtr const& bf) { return &bf.x; }
232 };
233
234 struct RBeginFunctionWithDataMember {
235 int x;
236 int rbegin;
rbegin(RBeginFunctionWithDataMember const & bf)237 friend constexpr const int *rbegin(RBeginFunctionWithDataMember const& bf) { return &bf.x; }
238 };
239
240 struct RBeginFunctionWithPrivateBeginMember {
241 int y;
rbegin(RBeginFunctionWithPrivateBeginMember const & bf)242 friend constexpr const int *rbegin(RBeginFunctionWithPrivateBeginMember const& bf) { return &bf.y; }
243 private:
244 const int *rbegin() const;
245 };
246
testRBeginFunction()247 constexpr bool testRBeginFunction() {
248 RBeginFunction a{};
249 const RBeginFunction aa{};
250 assert(std::ranges::rbegin(a) == &a.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
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 assert(std::ranges::rbegin(d) == &d.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
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 assert(std::ranges::rbegin(e) == &e.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
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 assert(std::ranges::rbegin(f) == &f.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic
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;
beginMemberBeginEnd297 constexpr bidirectional_iterator<int*> begin() { return bidirectional_iterator<int*>(&b); }
endMemberBeginEnd298 constexpr bidirectional_iterator<int*> end() { return bidirectional_iterator<int*>(&e); }
beginMemberBeginEnd299 constexpr bidirectional_iterator<const char*> begin() const { return bidirectional_iterator<const char*>(&cb); }
endMemberBeginEnd300 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;
begin(FunctionBeginEnd & v)309 friend constexpr bidirectional_iterator<int*> begin(FunctionBeginEnd& v) {
310 return bidirectional_iterator<int*>(&v.b);
311 }
end(FunctionBeginEnd & v)312 friend constexpr bidirectional_iterator<int*> end(FunctionBeginEnd& v) { return bidirectional_iterator<int*>(&v.e); }
begin(const FunctionBeginEnd & v)313 friend constexpr bidirectional_iterator<const char*> begin(const FunctionBeginEnd& v) {
314 return bidirectional_iterator<const char*>(&v.cb);
315 }
end(const FunctionBeginEnd & v)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;
beginMemberBeginFunctionEnd327 constexpr bidirectional_iterator<int*> begin() { return bidirectional_iterator<int*>(&b); }
end(MemberBeginFunctionEnd & v)328 friend constexpr bidirectional_iterator<int*> end(MemberBeginFunctionEnd& v) {
329 return bidirectional_iterator<int*>(&v.e);
330 }
beginMemberBeginFunctionEnd331 constexpr bidirectional_iterator<const char*> begin() const { return bidirectional_iterator<const char*>(&cb); }
end(const MemberBeginFunctionEnd & v)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;
begin(FunctionBeginMemberEnd & v)343 friend constexpr bidirectional_iterator<int*> begin(FunctionBeginMemberEnd& v) {
344 return bidirectional_iterator<int*>(&v.b);
345 }
endFunctionBeginMemberEnd346 constexpr bidirectional_iterator<int*> end() { return bidirectional_iterator<int*>(&e); }
begin(const FunctionBeginMemberEnd & v)347 friend constexpr bidirectional_iterator<const char*> begin(const FunctionBeginMemberEnd& v) {
348 return bidirectional_iterator<const char*>(&v.cb);
349 }
endFunctionBeginMemberEnd350 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
testBeginEnd()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
main(int,char **)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