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::end
12 // std::ranges::cend
13
14 #include <ranges>
15
16 #include <cassert>
17 #include <utility>
18 #include "test_macros.h"
19 #include "test_iterators.h"
20
21 using RangeEndT = decltype(std::ranges::end);
22 using RangeCEndT = decltype(std::ranges::cend);
23
24 static int globalBuff[8];
25
26 static_assert(!std::is_invocable_v<RangeEndT, int (&&)[]>);
27 static_assert(!std::is_invocable_v<RangeEndT, int (&)[]>);
28 static_assert(!std::is_invocable_v<RangeEndT, int (&&)[10]>);
29 static_assert( std::is_invocable_v<RangeEndT, int (&)[10]>);
30 static_assert(!std::is_invocable_v<RangeCEndT, int (&&)[]>);
31 static_assert(!std::is_invocable_v<RangeCEndT, int (&)[]>);
32 static_assert(!std::is_invocable_v<RangeCEndT, int (&&)[10]>);
33 static_assert( std::is_invocable_v<RangeCEndT, int (&)[10]>);
34
35 struct Incomplete;
36 static_assert(!std::is_invocable_v<RangeEndT, Incomplete(&&)[]>);
37 static_assert(!std::is_invocable_v<RangeEndT, Incomplete(&&)[42]>);
38 static_assert(!std::is_invocable_v<RangeCEndT, Incomplete(&&)[]>);
39 static_assert(!std::is_invocable_v<RangeCEndT, Incomplete(&&)[42]>);
40
41 struct EndMember {
42 int x;
43 const int *begin() const;
endEndMember44 constexpr const int *end() const { return &x; }
45 };
46
47 // Ensure that we can't call with rvalues with borrowing disabled.
48 static_assert( std::is_invocable_v<RangeEndT, EndMember &>);
49 static_assert(!std::is_invocable_v<RangeEndT, EndMember &&>);
50 static_assert( std::is_invocable_v<RangeEndT, EndMember const&>);
51 static_assert(!std::is_invocable_v<RangeEndT, EndMember const&&>);
52 static_assert( std::is_invocable_v<RangeCEndT, EndMember &>);
53 static_assert(!std::is_invocable_v<RangeCEndT, EndMember &&>);
54 static_assert( std::is_invocable_v<RangeCEndT, EndMember const&>);
55 static_assert(!std::is_invocable_v<RangeCEndT, EndMember const&&>);
56
testReturnTypes()57 constexpr bool testReturnTypes() {
58 {
59 int *x[2];
60 ASSERT_SAME_TYPE(decltype(std::ranges::end(x)), int**);
61 ASSERT_SAME_TYPE(decltype(std::ranges::cend(x)), int* const*);
62 }
63 {
64 int x[2][2];
65 ASSERT_SAME_TYPE(decltype(std::ranges::end(x)), int(*)[2]);
66 ASSERT_SAME_TYPE(decltype(std::ranges::cend(x)), const int(*)[2]);
67 }
68 {
69 struct Different {
70 char *begin();
71 sentinel_wrapper<char*>& end();
72 short *begin() const;
73 sentinel_wrapper<short*>& end() const;
74 } x;
75 ASSERT_SAME_TYPE(decltype(std::ranges::end(x)), sentinel_wrapper<char*>);
76 ASSERT_SAME_TYPE(decltype(std::ranges::cend(x)), sentinel_wrapper<short*>);
77 }
78 return true;
79 }
80
testArray()81 constexpr bool testArray() {
82 int a[2];
83 assert(std::ranges::end(a) == a + 2);
84 assert(std::ranges::cend(a) == a + 2);
85
86 int b[2][2];
87 assert(std::ranges::end(b) == b + 2);
88 assert(std::ranges::cend(b) == b + 2);
89
90 EndMember c[2];
91 assert(std::ranges::end(c) == c + 2);
92 assert(std::ranges::cend(c) == c + 2);
93
94 return true;
95 }
96
97 struct EndMemberReturnsInt {
98 int begin() const;
99 int end() const;
100 };
101 static_assert(!std::is_invocable_v<RangeEndT, EndMemberReturnsInt const&>);
102
103 struct EndMemberReturnsVoidPtr {
104 const void *begin() const;
105 const void *end() const;
106 };
107 static_assert(!std::is_invocable_v<RangeEndT, EndMemberReturnsVoidPtr const&>);
108
109 struct PtrConvertible {
110 operator int*() const;
111 };
112 struct PtrConvertibleEndMember {
113 PtrConvertible begin() const;
114 PtrConvertible end() const;
115 };
116 static_assert(!std::is_invocable_v<RangeEndT, PtrConvertibleEndMember const&>);
117
118 struct NoBeginMember {
119 constexpr const int *end();
120 };
121 static_assert(!std::is_invocable_v<RangeEndT, NoBeginMember const&>);
122
123 struct NonConstEndMember {
124 int x;
beginNonConstEndMember125 constexpr int *begin() { return nullptr; }
endNonConstEndMember126 constexpr int *end() { return &x; }
127 };
128 static_assert( std::is_invocable_v<RangeEndT, NonConstEndMember &>);
129 static_assert(!std::is_invocable_v<RangeEndT, NonConstEndMember const&>);
130 static_assert(!std::is_invocable_v<RangeCEndT, NonConstEndMember &>);
131 static_assert(!std::is_invocable_v<RangeCEndT, NonConstEndMember const&>);
132
133 struct EnabledBorrowingEndMember {
beginEnabledBorrowingEndMember134 constexpr int *begin() const { return nullptr; }
endEnabledBorrowingEndMember135 constexpr int *end() const { return &globalBuff[0]; }
136 };
137
138 template<>
139 inline constexpr bool std::ranges::enable_borrowed_range<EnabledBorrowingEndMember> = true;
140
141 struct EndMemberFunction {
142 int x;
beginEndMemberFunction143 constexpr const int *begin() const { return nullptr; }
endEndMemberFunction144 constexpr const int *end() const { return &x; }
145 friend constexpr int *end(EndMemberFunction const&);
146 };
147
148 struct Empty { };
149 struct EmptyEndMember {
150 Empty begin() const;
151 Empty end() const;
152 };
153 static_assert(!std::is_invocable_v<RangeEndT, EmptyEndMember const&>);
154
155 struct EmptyPtrEndMember {
156 Empty x;
beginEmptyPtrEndMember157 constexpr const Empty *begin() const { return nullptr; }
endEmptyPtrEndMember158 constexpr const Empty *end() const { return &x; }
159 };
160
testEndMember()161 constexpr bool testEndMember() {
162 EndMember a;
163 assert(std::ranges::end(a) == &a.x);
164 assert(std::ranges::cend(a) == &a.x);
165
166 NonConstEndMember b;
167 assert(std::ranges::end(b) == &b.x);
168 static_assert(!std::is_invocable_v<RangeCEndT, decltype((b))>);
169
170 EnabledBorrowingEndMember c;
171 assert(std::ranges::end(std::move(c)) == &globalBuff[0]);
172 assert(std::ranges::cend(std::move(c)) == &globalBuff[0]);
173
174 EndMemberFunction d;
175 assert(std::ranges::end(d) == &d.x);
176 assert(std::ranges::cend(d) == &d.x);
177
178 EmptyPtrEndMember e;
179 assert(std::ranges::end(e) == &e.x);
180 assert(std::ranges::cend(e) == &e.x);
181
182 return true;
183 }
184
185 struct EndFunction {
186 int x;
begin(EndFunction const &)187 friend constexpr const int *begin(EndFunction const&) { return nullptr; }
end(EndFunction const & bf)188 friend constexpr const int *end(EndFunction const& bf) { return &bf.x; }
189 };
190
191 static_assert( std::is_invocable_v<RangeEndT, EndFunction const&>);
192 static_assert(!std::is_invocable_v<RangeEndT, EndFunction &&>);
193
194 static_assert( std::is_invocable_v<RangeEndT, EndFunction const&>);
195 static_assert(!std::is_invocable_v<RangeEndT, EndFunction &&>);
196 static_assert(std::is_invocable_v<RangeEndT, EndFunction&>); // Ill-formed before P2602R2 Poison Pills are Too Toxic
197 static_assert( std::is_invocable_v<RangeCEndT, EndFunction const&>);
198 static_assert( std::is_invocable_v<RangeCEndT, EndFunction &>);
199
200 struct EndFunctionReturnsInt {
201 friend constexpr int begin(EndFunctionReturnsInt const&);
202 friend constexpr int end(EndFunctionReturnsInt const&);
203 };
204 static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsInt const&>);
205
206 struct EndFunctionReturnsVoidPtr {
207 friend constexpr void *begin(EndFunctionReturnsVoidPtr const&);
208 friend constexpr void *end(EndFunctionReturnsVoidPtr const&);
209 };
210 static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsVoidPtr const&>);
211
212 struct EndFunctionReturnsEmpty {
213 friend constexpr Empty begin(EndFunctionReturnsEmpty const&);
214 friend constexpr Empty end(EndFunctionReturnsEmpty const&);
215 };
216 static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsEmpty const&>);
217
218 struct EndFunctionReturnsPtrConvertible {
219 friend constexpr PtrConvertible begin(EndFunctionReturnsPtrConvertible const&);
220 friend constexpr PtrConvertible end(EndFunctionReturnsPtrConvertible const&);
221 };
222 static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsPtrConvertible const&>);
223
224 struct NoBeginFunction {
225 friend constexpr const int *end(NoBeginFunction const&);
226 };
227 static_assert(!std::is_invocable_v<RangeEndT, NoBeginFunction const&>);
228
229 struct EndFunctionByValue {
begin(EndFunctionByValue)230 friend constexpr int *begin(EndFunctionByValue) { return nullptr; }
end(EndFunctionByValue)231 friend constexpr int *end(EndFunctionByValue) { return &globalBuff[1]; }
232 };
233 static_assert(!std::is_invocable_v<RangeCEndT, EndFunctionByValue>);
234
235 struct EndFunctionEnabledBorrowing {
begin(EndFunctionEnabledBorrowing)236 friend constexpr int *begin(EndFunctionEnabledBorrowing) { return nullptr; }
end(EndFunctionEnabledBorrowing)237 friend constexpr int *end(EndFunctionEnabledBorrowing) { return &globalBuff[2]; }
238 };
239 template<>
240 inline constexpr bool std::ranges::enable_borrowed_range<EndFunctionEnabledBorrowing> = true;
241
242 struct EndFunctionReturnsEmptyPtr {
243 Empty x;
begin(EndFunctionReturnsEmptyPtr const &)244 friend constexpr const Empty *begin(EndFunctionReturnsEmptyPtr const&) { return nullptr; }
end(EndFunctionReturnsEmptyPtr const & bf)245 friend constexpr const Empty *end(EndFunctionReturnsEmptyPtr const& bf) { return &bf.x; }
246 };
247
248 struct EndFunctionWithDataMember {
249 int x;
250 int end;
begin(EndFunctionWithDataMember const &)251 friend constexpr const int *begin(EndFunctionWithDataMember const&) { return nullptr; }
end(EndFunctionWithDataMember const & bf)252 friend constexpr const int *end(EndFunctionWithDataMember const& bf) { return &bf.x; }
253 };
254
255 struct EndFunctionWithPrivateEndMember {
256 int y;
begin(EndFunctionWithPrivateEndMember const &)257 friend constexpr const int *begin(EndFunctionWithPrivateEndMember const&) { return nullptr; }
end(EndFunctionWithPrivateEndMember const & bf)258 friend constexpr const int *end(EndFunctionWithPrivateEndMember const& bf) { return &bf.y; }
259 private:
260 const int *end() const;
261 };
262
263 struct BeginMemberEndFunction {
264 int x;
beginBeginMemberEndFunction265 constexpr const int *begin() const { return nullptr; }
end(BeginMemberEndFunction const & bf)266 friend constexpr const int *end(BeginMemberEndFunction const& bf) { return &bf.x; }
267 };
268
testEndFunction()269 constexpr bool testEndFunction() {
270 const EndFunction a{};
271 assert(std::ranges::end(a) == &a.x);
272 assert(std::ranges::cend(a) == &a.x);
273 EndFunction aa{};
274 assert(std::ranges::end(aa) == &aa.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
275 assert(std::ranges::cend(aa) == &aa.x);
276
277 EndFunctionByValue b;
278 assert(std::ranges::end(b) == &globalBuff[1]);
279 assert(std::ranges::cend(b) == &globalBuff[1]);
280
281 EndFunctionEnabledBorrowing c;
282 assert(std::ranges::end(std::move(c)) == &globalBuff[2]);
283 assert(std::ranges::cend(std::move(c)) == &globalBuff[2]);
284
285 const EndFunctionReturnsEmptyPtr d{};
286 assert(std::ranges::end(d) == &d.x);
287 assert(std::ranges::cend(d) == &d.x);
288 EndFunctionReturnsEmptyPtr dd{};
289 assert(std::ranges::end(dd) == &dd.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
290 assert(std::ranges::cend(dd) == &dd.x);
291
292 const EndFunctionWithDataMember e{};
293 assert(std::ranges::end(e) == &e.x);
294 assert(std::ranges::cend(e) == &e.x);
295 EndFunctionWithDataMember ee{};
296 assert(std::ranges::end(ee) == &ee.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
297 assert(std::ranges::cend(ee) == &ee.x);
298
299 const EndFunctionWithPrivateEndMember f{};
300 assert(std::ranges::end(f) == &f.y);
301 assert(std::ranges::cend(f) == &f.y);
302 EndFunctionWithPrivateEndMember ff{};
303 assert(std::ranges::end(ff) == &ff.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic
304 assert(std::ranges::cend(ff) == &ff.y);
305
306 const BeginMemberEndFunction g{};
307 assert(std::ranges::end(g) == &g.x);
308 assert(std::ranges::cend(g) == &g.x);
309 BeginMemberEndFunction gg{};
310 assert(std::ranges::end(gg) == &gg.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
311 assert(std::ranges::cend(gg) == &gg.x);
312
313 return true;
314 }
315
316
317 ASSERT_NOEXCEPT(std::ranges::end(std::declval<int (&)[10]>()));
318 ASSERT_NOEXCEPT(std::ranges::cend(std::declval<int (&)[10]>()));
319
320 struct NoThrowMemberEnd {
321 ThrowingIterator<int> begin() const;
322 ThrowingIterator<int> end() const noexcept; // auto(t.end()) doesn't throw
323 } ntme;
324 static_assert(noexcept(std::ranges::end(ntme)));
325 static_assert(noexcept(std::ranges::cend(ntme)));
326
327 struct NoThrowADLEnd {
328 ThrowingIterator<int> begin() const;
329 friend ThrowingIterator<int> end(NoThrowADLEnd&) noexcept; // auto(end(t)) doesn't throw
330 friend ThrowingIterator<int> end(const NoThrowADLEnd&) noexcept;
331 } ntae;
332 static_assert(noexcept(std::ranges::end(ntae)));
333 static_assert(noexcept(std::ranges::cend(ntae)));
334
335 struct NoThrowMemberEndReturnsRef {
336 ThrowingIterator<int> begin() const;
337 ThrowingIterator<int>& end() const noexcept; // auto(t.end()) may throw
338 } ntmerr;
339 static_assert(!noexcept(std::ranges::end(ntmerr)));
340 static_assert(!noexcept(std::ranges::cend(ntmerr)));
341
342 struct EndReturnsArrayRef {
343 auto begin() const noexcept -> int(&)[10];
344 auto end() const noexcept -> int(&)[10];
345 } erar;
346 static_assert(noexcept(std::ranges::end(erar)));
347 static_assert(noexcept(std::ranges::cend(erar)));
348
349 // Test ADL-proofing.
350 struct Incomplete;
351 template<class T> struct Holder { T t; };
352 static_assert(!std::is_invocable_v<RangeEndT, Holder<Incomplete>*>);
353 static_assert(!std::is_invocable_v<RangeEndT, Holder<Incomplete>*&>);
354 static_assert(!std::is_invocable_v<RangeCEndT, Holder<Incomplete>*>);
355 static_assert(!std::is_invocable_v<RangeCEndT, Holder<Incomplete>*&>);
356
main(int,char **)357 int main(int, char**) {
358 static_assert(testReturnTypes());
359
360 testArray();
361 static_assert(testArray());
362
363 testEndMember();
364 static_assert(testEndMember());
365
366 testEndFunction();
367 static_assert(testEndFunction());
368
369 return 0;
370 }
371