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