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::begin
12 // std::ranges::cbegin
13
14 #include <ranges>
15
16 #include <cassert>
17 #include <utility>
18 #include "test_macros.h"
19 #include "test_iterators.h"
20
21 using RangeBeginT = decltype(std::ranges::begin);
22 using RangeCBeginT = decltype(std::ranges::cbegin);
23
24 static int globalBuff[8];
25
26 static_assert(!std::is_invocable_v<RangeBeginT, int (&&)[10]>);
27 static_assert( std::is_invocable_v<RangeBeginT, int (&)[10]>);
28 static_assert(!std::is_invocable_v<RangeBeginT, int (&&)[]>);
29 static_assert( std::is_invocable_v<RangeBeginT, int (&)[]>);
30 static_assert(!std::is_invocable_v<RangeCBeginT, int (&&)[10]>);
31 static_assert( std::is_invocable_v<RangeCBeginT, int (&)[10]>);
32 static_assert(!std::is_invocable_v<RangeCBeginT, int (&&)[]>);
33 static_assert( std::is_invocable_v<RangeCBeginT, int (&)[]>);
34
35 struct Incomplete;
36 static_assert(!std::is_invocable_v<RangeBeginT, Incomplete(&&)[]>);
37 static_assert(!std::is_invocable_v<RangeBeginT, const Incomplete(&&)[]>);
38 static_assert(!std::is_invocable_v<RangeCBeginT, Incomplete(&&)[]>);
39 static_assert(!std::is_invocable_v<RangeCBeginT, const Incomplete(&&)[]>);
40
41 static_assert(!std::is_invocable_v<RangeBeginT, Incomplete(&&)[10]>);
42 static_assert(!std::is_invocable_v<RangeBeginT, const Incomplete(&&)[10]>);
43 static_assert(!std::is_invocable_v<RangeCBeginT, Incomplete(&&)[10]>);
44 static_assert(!std::is_invocable_v<RangeCBeginT, const Incomplete(&&)[10]>);
45
46 // This case is IFNDR; we handle it SFINAE-friendly.
47 LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeBeginT, Incomplete(&)[]>);
48 LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeBeginT, const Incomplete(&)[]>);
49 LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, Incomplete(&)[]>);
50 LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, const Incomplete(&)[]>);
51
52 // This case is IFNDR; we handle it SFINAE-friendly.
53 LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeBeginT, Incomplete(&)[10]>);
54 LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeBeginT, const Incomplete(&)[10]>);
55 LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, Incomplete(&)[10]>);
56 LIBCPP_STATIC_ASSERT(!std::is_invocable_v<RangeCBeginT, const Incomplete(&)[10]>);
57
58 struct BeginMember {
59 int x;
beginBeginMember60 constexpr const int *begin() const { return &x; }
61 };
62
63 // Ensure that we can't call with rvalues with borrowing disabled.
64 static_assert( std::is_invocable_v<RangeBeginT, BeginMember &>);
65 static_assert(!std::is_invocable_v<RangeBeginT, BeginMember &&>);
66 static_assert( std::is_invocable_v<RangeBeginT, BeginMember const&>);
67 static_assert(!std::is_invocable_v<RangeBeginT, BeginMember const&&>);
68 static_assert( std::is_invocable_v<RangeCBeginT, BeginMember &>);
69 static_assert(!std::is_invocable_v<RangeCBeginT, BeginMember &&>);
70 static_assert( std::is_invocable_v<RangeCBeginT, BeginMember const&>);
71 static_assert(!std::is_invocable_v<RangeCBeginT, BeginMember const&&>);
72
testReturnTypes()73 constexpr bool testReturnTypes() {
74 {
75 int *x[2];
76 ASSERT_SAME_TYPE(decltype(std::ranges::begin(x)), int**);
77 ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(x)), int* const*);
78 }
79 {
80 int x[2][2];
81 ASSERT_SAME_TYPE(decltype(std::ranges::begin(x)), int(*)[2]);
82 ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(x)), const int(*)[2]);
83 }
84 {
85 struct Different {
86 char*& begin();
87 short*& begin() const;
88 } x;
89 ASSERT_SAME_TYPE(decltype(std::ranges::begin(x)), char*);
90 ASSERT_SAME_TYPE(decltype(std::ranges::cbegin(x)), short*);
91 }
92 return true;
93 }
94
testArray()95 constexpr bool testArray() {
96 int a[2];
97 assert(std::ranges::begin(a) == a);
98 assert(std::ranges::cbegin(a) == a);
99
100 int b[2][2];
101 assert(std::ranges::begin(b) == b);
102 assert(std::ranges::cbegin(b) == b);
103
104 BeginMember c[2];
105 assert(std::ranges::begin(c) == c);
106 assert(std::ranges::cbegin(c) == c);
107
108 return true;
109 }
110
111 struct BeginMemberReturnsInt {
112 int begin() const;
113 };
114 static_assert(!std::is_invocable_v<RangeBeginT, BeginMemberReturnsInt const&>);
115
116 struct BeginMemberReturnsVoidPtr {
117 const void *begin() const;
118 };
119 static_assert(!std::is_invocable_v<RangeBeginT, BeginMemberReturnsVoidPtr const&>);
120
121 struct EmptyBeginMember {
122 struct iterator {};
123 iterator begin() const;
124 };
125 static_assert(!std::is_invocable_v<RangeBeginT, EmptyBeginMember const&>);
126
127 struct PtrConvertibleBeginMember {
128 struct iterator { operator int*() const; };
129 iterator begin() const;
130 };
131 static_assert(!std::is_invocable_v<RangeBeginT, PtrConvertibleBeginMember const&>);
132
133 struct NonConstBeginMember {
134 int x;
beginNonConstBeginMember135 constexpr int *begin() { return &x; }
136 };
137 static_assert( std::is_invocable_v<RangeBeginT, NonConstBeginMember &>);
138 static_assert(!std::is_invocable_v<RangeBeginT, NonConstBeginMember const&>);
139 static_assert(!std::is_invocable_v<RangeCBeginT, NonConstBeginMember &>);
140 static_assert(!std::is_invocable_v<RangeCBeginT, NonConstBeginMember const&>);
141
142 struct EnabledBorrowingBeginMember {
beginEnabledBorrowingBeginMember143 constexpr int *begin() const { return &globalBuff[0]; }
144 };
145 template<>
146 inline constexpr bool std::ranges::enable_borrowed_range<EnabledBorrowingBeginMember> = true;
147
148 struct BeginMemberFunction {
149 int x;
beginBeginMemberFunction150 constexpr const int *begin() const { return &x; }
151 friend int *begin(BeginMemberFunction const&);
152 };
153
154 struct EmptyPtrBeginMember {
155 struct Empty {};
156 Empty x;
beginEmptyPtrBeginMember157 constexpr const Empty *begin() const { return &x; }
158 };
159
testBeginMember()160 constexpr bool testBeginMember() {
161 BeginMember a;
162 assert(std::ranges::begin(a) == &a.x);
163 assert(std::ranges::cbegin(a) == &a.x);
164 static_assert(!std::is_invocable_v<RangeBeginT, BeginMember&&>);
165 static_assert(!std::is_invocable_v<RangeCBeginT, BeginMember&&>);
166
167 NonConstBeginMember b;
168 assert(std::ranges::begin(b) == &b.x);
169 static_assert(!std::is_invocable_v<RangeCBeginT, NonConstBeginMember&>);
170
171 EnabledBorrowingBeginMember c;
172 assert(std::ranges::begin(c) == &globalBuff[0]);
173 assert(std::ranges::cbegin(c) == &globalBuff[0]);
174 assert(std::ranges::begin(std::move(c)) == &globalBuff[0]);
175 assert(std::ranges::cbegin(std::move(c)) == &globalBuff[0]);
176
177 BeginMemberFunction d;
178 assert(std::ranges::begin(d) == &d.x);
179 assert(std::ranges::cbegin(d) == &d.x);
180
181 EmptyPtrBeginMember e;
182 assert(std::ranges::begin(e) == &e.x);
183 assert(std::ranges::cbegin(e) == &e.x);
184
185 return true;
186 }
187
188
189 struct BeginFunction {
190 int x;
begin(BeginFunction const & bf)191 friend constexpr const int *begin(BeginFunction const& bf) { return &bf.x; }
192 };
193 static_assert( std::is_invocable_v<RangeBeginT, BeginFunction const&>);
194 static_assert(!std::is_invocable_v<RangeBeginT, BeginFunction &&>);
195 static_assert(std::is_invocable_v<RangeBeginT, BeginFunction&>); // Ill-formed before P2602R2 Poison Pills are Too Toxic
196 static_assert( std::is_invocable_v<RangeCBeginT, BeginFunction const&>);
197 static_assert( std::is_invocable_v<RangeCBeginT, BeginFunction &>);
198
199 struct BeginFunctionReturnsInt {
200 friend int begin(BeginFunctionReturnsInt const&);
201 };
202 static_assert(!std::is_invocable_v<RangeBeginT, BeginFunctionReturnsInt const&>);
203
204 struct BeginFunctionReturnsVoidPtr {
205 friend void *begin(BeginFunctionReturnsVoidPtr const&);
206 };
207 static_assert(!std::is_invocable_v<RangeBeginT, BeginFunctionReturnsVoidPtr const&>);
208
209 struct BeginFunctionReturnsPtrConvertible {
210 struct iterator { operator int*() const; };
211 friend iterator begin(BeginFunctionReturnsPtrConvertible const&);
212 };
213 static_assert(!std::is_invocable_v<RangeBeginT, BeginFunctionReturnsPtrConvertible const&>);
214
215 struct BeginFunctionByValue {
begin(BeginFunctionByValue)216 friend constexpr int *begin(BeginFunctionByValue) { return &globalBuff[1]; }
217 };
218 static_assert(!std::is_invocable_v<RangeCBeginT, BeginFunctionByValue>);
219
220 struct BeginFunctionEnabledBorrowing {
begin(BeginFunctionEnabledBorrowing)221 friend constexpr int *begin(BeginFunctionEnabledBorrowing) { return &globalBuff[2]; }
222 };
223 template<>
224 inline constexpr bool std::ranges::enable_borrowed_range<BeginFunctionEnabledBorrowing> = true;
225
226 struct BeginFunctionReturnsEmptyPtr {
227 struct Empty {};
228 Empty x;
begin(BeginFunctionReturnsEmptyPtr const & bf)229 friend constexpr const Empty *begin(BeginFunctionReturnsEmptyPtr const& bf) { return &bf.x; }
230 };
231
232 struct BeginFunctionWithDataMember {
233 int x;
234 int begin;
begin(BeginFunctionWithDataMember const & bf)235 friend constexpr const int *begin(BeginFunctionWithDataMember const& bf) { return &bf.x; }
236 };
237
238 struct BeginFunctionWithPrivateBeginMember {
239 int y;
begin(BeginFunctionWithPrivateBeginMember const & bf)240 friend constexpr const int *begin(BeginFunctionWithPrivateBeginMember const& bf) { return &bf.y; }
241 private:
242 const int *begin() const;
243 };
244
testBeginFunction()245 constexpr bool testBeginFunction() {
246 BeginFunction a{};
247 const BeginFunction aa{};
248 assert(std::ranges::begin(a) == &a.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
249 assert(std::ranges::cbegin(a) == &a.x);
250 assert(std::ranges::begin(aa) == &aa.x);
251 assert(std::ranges::cbegin(aa) == &aa.x);
252
253 BeginFunctionByValue b{};
254 const BeginFunctionByValue bb{};
255 assert(std::ranges::begin(b) == &globalBuff[1]);
256 assert(std::ranges::cbegin(b) == &globalBuff[1]);
257 assert(std::ranges::begin(bb) == &globalBuff[1]);
258 assert(std::ranges::cbegin(bb) == &globalBuff[1]);
259
260 BeginFunctionEnabledBorrowing c{};
261 const BeginFunctionEnabledBorrowing cc{};
262 assert(std::ranges::begin(std::move(c)) == &globalBuff[2]);
263 assert(std::ranges::cbegin(std::move(c)) == &globalBuff[2]);
264 assert(std::ranges::begin(std::move(cc)) == &globalBuff[2]);
265 assert(std::ranges::cbegin(std::move(cc)) == &globalBuff[2]);
266
267 BeginFunctionReturnsEmptyPtr d{};
268 const BeginFunctionReturnsEmptyPtr dd{};
269 assert(std::ranges::begin(d) == &d.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
270 assert(std::ranges::cbegin(d) == &d.x);
271 assert(std::ranges::begin(dd) == &dd.x);
272 assert(std::ranges::cbegin(dd) == &dd.x);
273
274 BeginFunctionWithDataMember e{};
275 const BeginFunctionWithDataMember ee{};
276 assert(std::ranges::begin(e) == &e.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
277 assert(std::ranges::begin(ee) == &ee.x);
278 assert(std::ranges::cbegin(e) == &e.x);
279 assert(std::ranges::cbegin(ee) == &ee.x);
280
281 BeginFunctionWithPrivateBeginMember f{};
282 const BeginFunctionWithPrivateBeginMember ff{};
283 assert(std::ranges::begin(f) == &f.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic
284 assert(std::ranges::cbegin(f) == &f.y);
285 assert(std::ranges::begin(ff) == &ff.y);
286 assert(std::ranges::cbegin(ff) == &ff.y);
287
288 return true;
289 }
290
291
292 ASSERT_NOEXCEPT(std::ranges::begin(std::declval<int (&)[10]>()));
293 ASSERT_NOEXCEPT(std::ranges::cbegin(std::declval<int (&)[10]>()));
294
295 struct NoThrowMemberBegin {
296 ThrowingIterator<int> begin() const noexcept; // auto(t.begin()) doesn't throw
297 } ntmb;
298 static_assert(noexcept(std::ranges::begin(ntmb)));
299 static_assert(noexcept(std::ranges::cbegin(ntmb)));
300
301 struct NoThrowADLBegin {
302 friend ThrowingIterator<int> begin(NoThrowADLBegin&) noexcept; // auto(begin(t)) doesn't throw
303 friend ThrowingIterator<int> begin(const NoThrowADLBegin&) noexcept;
304 } ntab;
305 static_assert(noexcept(std::ranges::begin(ntab)));
306 static_assert(noexcept(std::ranges::cbegin(ntab)));
307
308 struct NoThrowMemberBeginReturnsRef {
309 ThrowingIterator<int>& begin() const noexcept; // auto(t.begin()) may throw
310 } ntmbrr;
311 static_assert(!noexcept(std::ranges::begin(ntmbrr)));
312 static_assert(!noexcept(std::ranges::cbegin(ntmbrr)));
313
314 struct BeginReturnsArrayRef {
315 auto begin() const noexcept -> int(&)[10];
316 } brar;
317 static_assert(noexcept(std::ranges::begin(brar)));
318 static_assert(noexcept(std::ranges::cbegin(brar)));
319
320 // Test ADL-proofing.
321 struct Incomplete;
322 template<class T> struct Holder { T t; };
323 static_assert(!std::is_invocable_v<RangeBeginT, Holder<Incomplete>*>);
324 static_assert(!std::is_invocable_v<RangeBeginT, Holder<Incomplete>*&>);
325 static_assert(!std::is_invocable_v<RangeCBeginT, Holder<Incomplete>*>);
326 static_assert(!std::is_invocable_v<RangeCBeginT, Holder<Incomplete>*&>);
327
main(int,char **)328 int main(int, char**) {
329 static_assert(testReturnTypes());
330
331 testArray();
332 static_assert(testArray());
333
334 testBeginMember();
335 static_assert(testBeginMember());
336
337 testBeginFunction();
338 static_assert(testBeginFunction());
339
340 return 0;
341 }
342