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