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