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