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