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