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: gcc-10
12 // UNSUPPORTED: libcpp-has-no-incomplete-ranges
13 
14 // std::ranges::end
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 EndMember {
33   int x;
beginEndMember34   constexpr const int *begin() const { return nullptr; }
endEndMember35   constexpr const int *end() const { return &x; }
36 };
37 
38 // Ensure that we can't call with rvalues with borrowing disabled.
39 static_assert( std::is_invocable_v<RangeEndT,  EndMember &>);
40 static_assert( std::is_invocable_v<RangeEndT,  EndMember const&>);
41 static_assert(!std::is_invocable_v<RangeEndT,  EndMember &&>);
42 static_assert( std::is_invocable_v<RangeCEndT, EndMember &>);
43 static_assert( std::is_invocable_v<RangeCEndT, EndMember const&>);
44 
testArray()45 constexpr bool testArray() {
46   int a[2];
47   assert(std::ranges::end(a) == a + 2);
48   assert(std::ranges::cend(a) == a + 2);
49 
50   int b[2][2];
51   assert(std::ranges::end(b) == b + 2);
52   assert(std::ranges::cend(b) == b + 2);
53 
54   EndMember c[2];
55   assert(std::ranges::end(c) == c + 2);
56   assert(std::ranges::cend(c) == c + 2);
57 
58   return true;
59 }
60 
61 struct EndMemberFunction {
62   int x;
beginEndMemberFunction63   constexpr const int *begin() const { return nullptr; }
endEndMemberFunction64   constexpr const int *end() const { return &x; }
65   friend constexpr int *end(EndMemberFunction const&);
66 };
67 
68 struct EndMemberReturnsInt {
69   int begin() const;
70   int end() const;
71 };
72 
73 static_assert(!std::is_invocable_v<RangeEndT, EndMemberReturnsInt const&>);
74 
75 struct EndMemberReturnsVoidPtr {
76   const void *begin() const;
77   const void *end() const;
78 };
79 
80 static_assert(!std::is_invocable_v<RangeEndT, EndMemberReturnsVoidPtr const&>);
81 
82 struct Empty { };
83 struct EmptyEndMember {
84   Empty begin() const;
85   Empty end() const;
86 };
87 struct EmptyPtrEndMember {
88   Empty x;
beginEmptyPtrEndMember89   constexpr const Empty *begin() const { return nullptr; }
endEmptyPtrEndMember90   constexpr const Empty *end() const { return &x; }
91 };
92 
93 static_assert(!std::is_invocable_v<RangeEndT, EmptyEndMember const&>);
94 
95 struct PtrConvertible {
96   operator int*() const;
97 };
98 struct PtrConvertibleEndMember {
99   PtrConvertible begin() const;
100   PtrConvertible end() const;
101 };
102 
103 static_assert(!std::is_invocable_v<RangeEndT, PtrConvertibleEndMember const&>);
104 
105 struct NoBeginMember {
106   constexpr const int *end();
107 };
108 
109 static_assert(!std::is_invocable_v<RangeEndT, NoBeginMember const&>);
110 
111 struct NonConstEndMember {
112   int x;
beginNonConstEndMember113   constexpr int *begin() { return nullptr; }
endNonConstEndMember114   constexpr int *end() { return &x; }
115 };
116 
117 static_assert( std::is_invocable_v<RangeEndT,  NonConstEndMember &>);
118 static_assert(!std::is_invocable_v<RangeEndT,  NonConstEndMember const&>);
119 static_assert(!std::is_invocable_v<RangeCEndT, NonConstEndMember &>);
120 static_assert(!std::is_invocable_v<RangeCEndT, NonConstEndMember const&>);
121 
122 struct EnabledBorrowingEndMember {
beginEnabledBorrowingEndMember123   constexpr int *begin() const { return nullptr; }
endEnabledBorrowingEndMember124   constexpr int *end() const { return &globalBuff[0]; }
125 };
126 
127 template<>
128 inline constexpr bool std::ranges::enable_borrowed_range<EnabledBorrowingEndMember> = true;
129 
testEndMember()130 constexpr bool testEndMember() {
131   EndMember a;
132   assert(std::ranges::end(a) == &a.x);
133   assert(std::ranges::cend(a) == &a.x);
134 
135   NonConstEndMember b;
136   assert(std::ranges::end(b) == &b.x);
137 
138   EnabledBorrowingEndMember c;
139   assert(std::ranges::end(std::move(c)) == &globalBuff[0]);
140 
141   EndMemberFunction d;
142   assert(std::ranges::end(d) == &d.x);
143   assert(std::ranges::cend(d) == &d.x);
144 
145   EmptyPtrEndMember e;
146   assert(std::ranges::end(e) == &e.x);
147   assert(std::ranges::cend(e) == &e.x);
148 
149   return true;
150 }
151 
152 struct EndFunction {
153   int x;
begin(EndFunction const &)154   friend constexpr const int *begin(EndFunction const&) { return nullptr; }
end(EndFunction const & bf)155   friend constexpr const int *end(EndFunction const& bf) { return &bf.x; }
156 };
157 
158 static_assert( std::is_invocable_v<RangeEndT, EndFunction const&>);
159 static_assert(!std::is_invocable_v<RangeEndT, EndFunction &&>);
160 
161 static_assert( std::is_invocable_v<RangeEndT,  EndFunction const&>);
162 static_assert(!std::is_invocable_v<RangeEndT,  EndFunction &&>);
163 static_assert(!std::is_invocable_v<RangeEndT,  EndFunction &>);
164 static_assert( std::is_invocable_v<RangeCEndT, EndFunction const&>);
165 static_assert( std::is_invocable_v<RangeCEndT, EndFunction &>);
166 
167 struct EndFunctionWithDataMember {
168   int x;
169   int end;
begin(EndFunctionWithDataMember const &)170   friend constexpr const int *begin(EndFunctionWithDataMember const&) { return nullptr; }
end(EndFunctionWithDataMember const & bf)171   friend constexpr const int *end(EndFunctionWithDataMember const& bf) { return &bf.x; }
172 };
173 
174 struct EndFunctionWithPrivateEndMember : private EndMember {
175   int y;
begin(EndFunctionWithPrivateEndMember const &)176   friend constexpr const int *begin(EndFunctionWithPrivateEndMember const&) { return nullptr; }
end(EndFunctionWithPrivateEndMember const & bf)177   friend constexpr const int *end(EndFunctionWithPrivateEndMember const& bf) { return &bf.y; }
178 };
179 
180 struct EndFunctionReturnsEmptyPtr {
181   Empty x;
begin(EndFunctionReturnsEmptyPtr const &)182   friend constexpr const Empty *begin(EndFunctionReturnsEmptyPtr const&) { return nullptr; }
end(EndFunctionReturnsEmptyPtr const & bf)183   friend constexpr const Empty *end(EndFunctionReturnsEmptyPtr const& bf) { return &bf.x; }
184 };
185 
186 struct EndFunctionByValue {
begin(EndFunctionByValue)187   friend constexpr int *begin(EndFunctionByValue) { return nullptr; }
end(EndFunctionByValue)188   friend constexpr int *end(EndFunctionByValue) { return &globalBuff[1]; }
189 };
190 
191 static_assert(!std::is_invocable_v<RangeCEndT, EndFunctionByValue>);
192 
193 struct EndFunctionEnabledBorrowing {
begin(EndFunctionEnabledBorrowing)194   friend constexpr int *begin(EndFunctionEnabledBorrowing) { return nullptr; }
end(EndFunctionEnabledBorrowing)195   friend constexpr int *end(EndFunctionEnabledBorrowing) { return &globalBuff[2]; }
196 };
197 
198 template<>
199 inline constexpr bool std::ranges::enable_borrowed_range<EndFunctionEnabledBorrowing> = true;
200 
201 struct EndFunctionReturnsInt {
202   friend constexpr int begin(EndFunctionReturnsInt const&);
203   friend constexpr int end(EndFunctionReturnsInt const&);
204 };
205 
206 static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsInt const&>);
207 
208 struct EndFunctionReturnsVoidPtr {
209   friend constexpr void *begin(EndFunctionReturnsVoidPtr const&);
210   friend constexpr void *end(EndFunctionReturnsVoidPtr const&);
211 };
212 
213 static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsVoidPtr const&>);
214 
215 struct EndFunctionReturnsEmpty {
216   friend constexpr Empty begin(EndFunctionReturnsEmpty const&);
217   friend constexpr Empty end(EndFunctionReturnsEmpty const&);
218 };
219 
220 static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsEmpty const&>);
221 
222 struct EndFunctionReturnsPtrConvertible {
223   friend constexpr PtrConvertible begin(EndFunctionReturnsPtrConvertible const&);
224   friend constexpr PtrConvertible end(EndFunctionReturnsPtrConvertible const&);
225 };
226 
227 static_assert(!std::is_invocable_v<RangeEndT, EndFunctionReturnsPtrConvertible const&>);
228 
229 struct NoBeginFunction {
230   friend constexpr const int *end(NoBeginFunction const&);
231 };
232 
233 static_assert(!std::is_invocable_v<RangeEndT, NoBeginFunction const&>);
234 
235 struct BeginMemberEndFunction {
236   int x;
beginBeginMemberEndFunction237   constexpr const int *begin() const { return nullptr; }
end(BeginMemberEndFunction const & bf)238   friend constexpr const int *end(BeginMemberEndFunction const& bf) { return &bf.x; }
239 };
240 
testEndFunction()241 constexpr bool testEndFunction() {
242   const EndFunction a{};
243   assert(std::ranges::end(a) == &a.x);
244   EndFunction aa{};
245   assert(std::ranges::cend(aa) == &aa.x);
246 
247   EndFunctionByValue b;
248   assert(std::ranges::end(b) == &globalBuff[1]);
249   assert(std::ranges::cend(b) == &globalBuff[1]);
250 
251   EndFunctionEnabledBorrowing c;
252   assert(std::ranges::end(std::move(c)) == &globalBuff[2]);
253 
254   const EndFunctionReturnsEmptyPtr d{};
255   assert(std::ranges::end(d) == &d.x);
256   EndFunctionReturnsEmptyPtr dd{};
257   assert(std::ranges::cend(dd) == &dd.x);
258 
259   const EndFunctionWithDataMember e{};
260   assert(std::ranges::end(e) == &e.x);
261   EndFunctionWithDataMember ee{};
262   assert(std::ranges::cend(ee) == &ee.x);
263 
264   const EndFunctionWithPrivateEndMember f{};
265   assert(std::ranges::end(f) == &f.y);
266   EndFunctionWithPrivateEndMember ff{};
267   assert(std::ranges::cend(ff) == &ff.y);
268 
269   const BeginMemberEndFunction g{};
270   assert(std::ranges::end(g) == &g.x);
271   BeginMemberEndFunction gg{};
272   assert(std::ranges::cend(gg) == &gg.x);
273 
274   return true;
275 }
276 
277 
278 ASSERT_NOEXCEPT(std::ranges::end(std::declval<int (&)[10]>()));
279 ASSERT_NOEXCEPT(std::ranges::cend(std::declval<int (&)[10]>()));
280 
281 template<class T>
282 struct NoThrowMemberEnd {
283   T begin() const;
284   T end() const noexcept;
285 };
286 ASSERT_NOEXCEPT(std::ranges::end(std::declval<NoThrowMemberEnd<int*>&>()));
287 ASSERT_NOEXCEPT(std::ranges::cend(std::declval<NoThrowMemberEnd<int*>&>()));
288 ASSERT_NOT_NOEXCEPT(std::ranges::end(std::declval<NoThrowMemberEnd<ThrowingIterator<int>>&>()));
289 ASSERT_NOT_NOEXCEPT(std::ranges::cend(std::declval<NoThrowMemberEnd<ThrowingIterator<int>>&>()));
290 
291 template<class T>
292 struct NoThrowADLEnd {
293   T begin() const;
end(NoThrowADLEnd &)294   friend T end(NoThrowADLEnd&) noexcept { return T{}; }
end(NoThrowADLEnd const &)295   friend T end(NoThrowADLEnd const&) noexcept { return T{}; }
296 };
297 ASSERT_NOEXCEPT(std::ranges::end(std::declval<NoThrowADLEnd<int*>&>()));
298 ASSERT_NOEXCEPT(std::ranges::cend(std::declval<NoThrowADLEnd<int*>&>()));
299 ASSERT_NOT_NOEXCEPT(std::ranges::end(std::declval<NoThrowADLEnd<ThrowingIterator<int>>&>()));
300 ASSERT_NOT_NOEXCEPT(std::ranges::cend(std::declval<NoThrowADLEnd<ThrowingIterator<int>>&>()));
301 
302 
main(int,char **)303 int main(int, char**) {
304   testArray();
305   static_assert(testArray());
306 
307   testEndMember();
308   static_assert(testEndMember());
309 
310   testEndFunction();
311   static_assert(testEndFunction());
312 
313   return 0;
314 }
315