diff --git a/libcxx/docs/Status/Cxx20Issues.csv b/libcxx/docs/Status/Cxx20Issues.csv --- a/libcxx/docs/Status/Cxx20Issues.csv +++ b/libcxx/docs/Status/Cxx20Issues.csv @@ -205,7 +205,7 @@ "`3238 `__","Insufficiently-defined behavior of ``std::function``\ deduction guides","Prague","","" "`3242 `__","``std::format``\ : missing rules for ``arg-id``\ in ``width``\ and ``precision``\ ","Prague","|Complete|","Clang 14","|format|" "`3243 `__","``std::format``\ and negative zeroes","Prague","|Complete|","14.0","|format|" -"`3247 `__","``ranges::iter_move``\ should perform ADL-only lookup of ``iter_move``\ ","Prague","","","|ranges|" +"`3247 `__","``ranges::iter_move``\ should perform ADL-only lookup of ``iter_move``\ ","Prague","|Complete|","15.0","|ranges|" "`3248 `__","``std::format``\ ``#b``\ , ``#B``\ , ``#o``\ , ``#x``\ , and ``#X``\ presentation types misformat negative numbers","Prague","|Complete|","14.0","|format|" "`3250 `__","``std::format``\ : ``#``\ (alternate form) for NaN and inf","Prague","|Complete|","14.0","|format|" "`3251 `__","Are ``std::format``\ alignment specifiers applied to string arguments?","Prague","|Complete|","14.0","|format|" @@ -228,7 +228,7 @@ "`3294 `__","``zoned_time``\ deduction guides misinterprets ``string``\ /``char*``\ ","Prague","","","|chrono|" "`3296 `__","Inconsistent default argument for ``basic_regex<>::assign``\ ","Prague","|Complete|","" "`3299 `__","Pointers don't need customized iterator behavior","Prague","|Complete|","15.0","|ranges|" -"`3300 `__","Non-array ``ssize``\ overload is underconstrained","Prague","","" +"`3300 `__","Non-array ``ssize``\ overload is underconstrained","Prague","|Nothing To Do|","" "`3301 `__","``transform_view::iterator``\ has incorrect ``iterator_category``\ ","Prague","|Complete|","15.0","|ranges|" "`3302 `__","Range adaptor objects ``keys``\ and ``values``\ are unspecified","Prague","","","|ranges|" "`3303 `__","Bad ""``constexpr``\ "" marker for ``destroy/destroy_n``\ ","Prague","","" @@ -255,7 +255,7 @@ "`3331 `__","Define ``totally_ordered/_with``\ in terms of ``partially-ordered-with``\ ","Prague","|Complete|","13.0" "`3332 `__","Issue in |sect|\ [time.format]","Prague","","","|chrono| |format|" "`3334 `__","``basic_osyncstream``\ move assignment and destruction calls ``basic_syncbuf::emit()``\ twice","Prague","","" -"`3335 `__","Resolve C++20 NB comments US 273 and GB 274","Prague","","","|ranges|" +"`3335 `__","Resolve C++20 NB comments US 273 and GB 274","Prague","|Complete|","15.0","|ranges|" "`3338 `__","Rename ``default_constructible``\ to ``default_initializable``\ ","Prague","|Complete|","13.0" "`3340 `__","Formatting functions should throw on argument/format string mismatch in |sect|\ [format.functions]","Prague","|Complete|","14.0","|format|" "`3346 `__","``pair``\ and ``tuple``\ copy and move constructor have backwards specification","Prague","","" @@ -266,7 +266,7 @@ "`3351 `__","``ranges::enable_safe_range``\ should not be constrained","Prague","|Complete|","15.0","|ranges|" "`3352 `__","``strong_equality``\ isn't a thing","Prague","|Nothing To Do|","","|spaceship|" "`3354 `__","``has_strong_structural_equality``\ has a meaningless definition","Prague","|Nothing To Do|","","|spaceship|" -"`3355 `__","The memory algorithms should support move-only input iterators introduced by P1207","Prague","","","|ranges|" +"`3355 `__","The memory algorithms should support move-only input iterators introduced by P1207","Prague","|Complete|","15.0","|ranges|" "`3356 `__","``__cpp_lib_nothrow_convertible``\ should be ``__cpp_lib_is_nothrow_convertible``\ ","Prague","|Complete|","12.0" "`3358 `__","|sect|\ [span.cons] is mistaken that ``to_address``\ can throw","Prague","","" "`3359 `__","````\ leap second support should allow for negative leap seconds","Prague","","","|chrono|" diff --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv --- a/libcxx/docs/Status/Cxx20Papers.csv +++ b/libcxx/docs/Status/Cxx20Papers.csv @@ -187,7 +187,7 @@ "`P2002R1 `__","CWG","Defaulted comparison specification cleanups","Prague","* *","" "`P2045R1 `__","LWG","Missing Mandates for the standard library","Prague","* *","" "`P2085R0 `__","CWG","Consistent defaulted comparisons","Prague","* *","" -"`P2091R0 `__","LWG","Issues with range access CPOs","Prague","* *","" +"`P2091R0 `__","LWG","Issues with range access CPOs","Prague","|Complete|","15.0" "`P2101R0 `__","LWG","'Models' subsumes 'satisfies' (Wording for US298 and US300)","Prague","* *","" "`P2102R0 `__","LWG","Make 'implicit expression variations' more explicit (Wording for US185)","Prague","* *","" "`P2106R0 `__","LWG","Alternative wording for GB315 and GB316","Prague","* *","" diff --git a/libcxx/docs/Status/RangesIssues.csv b/libcxx/docs/Status/RangesIssues.csv --- a/libcxx/docs/Status/RangesIssues.csv +++ b/libcxx/docs/Status/RangesIssues.csv @@ -20,7 +20,7 @@ `P1970R2 `__,Consistency for size() functions: Add ranges::ssize,|Complete|,15.0 `P1983R0 `__,"Wording for GB301, US296, US292, US291, and US283",|Complete|,15.0 `P1994R1 `__,elements_view Needs Its Own sentinel,, -`P2091R0 `__,Fixing Issues With Range Access CPOs,, +`P2091R0 `__,Fixing Issues With Range Access CPOs,|Complete|,15.0 `P2106R0 `__,Range Algorithm Result Types,, `P2325R3 `__,Views should not be required to be default constructible ,, diff --git a/libcxx/include/__iterator/move_iterator.h b/libcxx/include/__iterator/move_iterator.h --- a/libcxx/include/__iterator/move_iterator.h +++ b/libcxx/include/__iterator/move_iterator.h @@ -93,6 +93,9 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 move_iterator& operator++() { ++__current_; return *this; } + _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 + pointer operator->() const { return __current_; } + #if _LIBCPP_STD_VER > 17 _LIBCPP_HIDE_FROM_ABI constexpr move_iterator() requires is_constructible_v<_Iter> : __current_() {} @@ -156,8 +159,6 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 reference operator*() const { return static_cast(*__current_); } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 - pointer operator->() const { return __current_; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 reference operator[](difference_type __n) const { return static_cast(__current_[__n]); } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 diff --git a/libcxx/include/__ranges/size.h b/libcxx/include/__ranges/size.h --- a/libcxx/include/__ranges/size.h +++ b/libcxx/include/__ranges/size.h @@ -35,68 +35,76 @@ namespace ranges { namespace __size { - void size(auto&) = delete; - void size(const auto&) = delete; - - template - concept __size_enabled = !disable_sized_range>; - - template - concept __member_size = - __size_enabled<_Tp> && - __workaround_52970<_Tp> && - requires(_Tp&& __t) { - { _LIBCPP_AUTO_CAST(__t.size()) } -> __integer_like; - }; - - template - concept __unqualified_size = - __size_enabled<_Tp> && - !__member_size<_Tp> && - __class_or_enum> && - requires(_Tp&& __t) { - { _LIBCPP_AUTO_CAST(size(__t)) } -> __integer_like; - }; - - template - concept __difference = - !__member_size<_Tp> && - !__unqualified_size<_Tp> && - __class_or_enum> && - requires(_Tp&& __t) { - { ranges::begin(__t) } -> forward_iterator; - { ranges::end(__t) } -> sized_sentinel_for()))>; - }; - - struct __fn { - template - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr size_t operator()(_Tp (&&)[_Sz]) const noexcept { - return _Sz; - } - - template - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr size_t operator()(_Tp (&)[_Sz]) const noexcept { - return _Sz; - } - - template <__member_size _Tp> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __integer_like auto operator()(_Tp&& __t) const - noexcept(noexcept(_LIBCPP_AUTO_CAST(__t.size()))) { - return _LIBCPP_AUTO_CAST(__t.size()); - } - - template <__unqualified_size _Tp> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __integer_like auto operator()(_Tp&& __t) const - noexcept(noexcept(_LIBCPP_AUTO_CAST(size(__t)))) { - return _LIBCPP_AUTO_CAST(size(__t)); - } - - template<__difference _Tp> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __integer_like auto operator()(_Tp&& __t) const - noexcept(noexcept(ranges::end(__t) - ranges::begin(__t))) { - return std::__to_unsigned_like(ranges::end(__t) - ranges::begin(__t)); - } +void size(auto&) = delete; +void size(const auto&) = delete; + +template +concept __size_enabled = !disable_sized_range>; + +template +concept __member_size = + __size_enabled<_Tp> && + __workaround_52970<_Tp> && + requires(_Tp&& __t) { + { _LIBCPP_AUTO_CAST(__t.size()) } -> __integer_like; }; + +template +concept __unqualified_size = + __size_enabled<_Tp> && + !__member_size<_Tp> && + __class_or_enum> && + requires(_Tp&& __t) { + { _LIBCPP_AUTO_CAST(size(__t)) } -> __integer_like; + }; + +template +concept __difference = + !__member_size<_Tp> && + !__unqualified_size<_Tp> && + __class_or_enum> && + requires(_Tp&& __t) { + { ranges::begin(__t) } -> forward_iterator; + { ranges::end(__t) } -> sized_sentinel_for()))>; + }; + +struct __fn { + + // `[range.prim.size]`: the array case (for rvalues). + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr size_t operator()(_Tp (&&)[_Sz]) const noexcept { + return _Sz; + } + + // `[range.prim.size]`: the array case (for lvalues). + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr size_t operator()(_Tp (&)[_Sz]) const noexcept { + return _Sz; + } + + // `[range.prim.size]`: `auto(t.size())` is a valid expression. + template <__member_size _Tp> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __integer_like auto operator()(_Tp&& __t) const + noexcept(noexcept(_LIBCPP_AUTO_CAST(__t.size()))) { + return _LIBCPP_AUTO_CAST(__t.size()); + } + + // `[range.prim.size]`: `auto(size(t))` is a valid expression. + template <__unqualified_size _Tp> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __integer_like auto operator()(_Tp&& __t) const + noexcept(noexcept(_LIBCPP_AUTO_CAST(size(__t)))) { + return _LIBCPP_AUTO_CAST(size(__t)); + } + + // [range.prim.size]: the `to-unsigned-like` case. + template <__difference _Tp> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const + noexcept(noexcept(std::__to_unsigned_like(ranges::end(__t) - ranges::begin(__t)))) + -> decltype( std::__to_unsigned_like(ranges::end(__t) - ranges::begin(__t))) + { return std::__to_unsigned_like(ranges::end(__t) - ranges::begin(__t)); + } +}; + } // namespace __size inline namespace __cpo { @@ -108,19 +116,18 @@ namespace ranges { namespace __ssize { - struct __fn { - template - requires requires (_Tp&& __t) { ranges::size(__t); } - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr integral auto operator()(_Tp&& __t) const - noexcept(noexcept(ranges::size(__t))) - { - using _Signed = make_signed_t; - if constexpr (sizeof(ptrdiff_t) > sizeof(_Signed)) - return static_cast(ranges::size(__t)); - else - return static_cast<_Signed>(ranges::size(__t)); - } - }; +struct __fn { + template + requires requires (_Tp&& __t) { ranges::size(__t); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr integral auto operator()(_Tp&& __t) const + noexcept(noexcept(ranges::size(__t))) { + using _Signed = make_signed_t; + if constexpr (sizeof(ptrdiff_t) > sizeof(_Signed)) + return static_cast(ranges::size(__t)); + else + return static_cast<_Signed>(ranges::size(__t)); + } +}; } // namespace __ssize inline namespace __cpo { diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm --- a/libcxx/include/algorithm +++ b/libcxx/include/algorithm @@ -19,12 +19,17 @@ { namespace ranges { + + // [algorithms.results], algorithm result types template struct in_fun_result; // since C++20 template struct in_in_result; // since C++20 + template + struct in_out_result; // since C++20 + template struct in_in_out_result; // since C++20 @@ -53,6 +58,9 @@ indirect_strict_weak_order, Proj>> Comp = ranges::less> constexpr borrowed_iterator_t ranges::max_element(R&& r, Comp comp = {}, Proj proj = {}); // since C++20 + template + using mismatch_result = in_in_result; + template S1, input_iterator I2, sentinel_for<_I2> S2, class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity> requires indirectly_comparable @@ -174,6 +182,9 @@ constexpr range_difference_t count_if(R&& r, Pred pred, Proj proj = {}); // since C++20 + template + using minmax_result = min_max_result; + template> Comp = ranges::less> constexpr ranges::minmax_result @@ -190,6 +201,9 @@ constexpr ranges::minmax_result> minmax(R&& r, Comp comp = {}, Proj proj = {}); // since C++20 + template + using minmax_element_result = min_max_result; + template S, class Proj = identity, indirect_strict_weak_order> Comp = ranges::less> constexpr ranges::minmax_element_result @@ -201,10 +215,10 @@ minmax_element(R&& r, Comp comp = {}, Proj proj = {}); // since C++20 template - using copy_result = in_out_result; // since C++20 + using copy_result = in_out_result; // since C++20 - template - using copy_n_result = in_out_result; // since C++20 + template + using copy_n_result = in_out_result; // since C++20 template using copy_if_result = in_out_result; // since C++20 @@ -638,19 +652,34 @@ copy_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 result); +// [alg.move], move +template + constexpr OutputIterator move(InputIterator first, InputIterator last, + OutputIterator result); + +template + constexpr BidirectionalIterator2 + move_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, + BidirectionalIterator2 result); + template constexpr ForwardIterator2 // constexpr in C++20 swap_ranges(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2); +namespace ranges { + template + using swap_ranges_result = in_in_result; + template S1, input_iterator I2, sentinel_for S2> requires indirectly_swappable constexpr ranges::swap_ranges_result - ranges::swap_ranges(I1 first1, S1 last1, I2 first2, S2 last2); + swap_ranges(I1 first1, S1 last1, I2 first2, S2 last2); template requires indirectly_swappable, iterator_t> constexpr ranges::swap_ranges_result, borrowed_iterator_t> - ranges::swap_ranges(R1&& r1, R2&& r2); + swap_ranges(R1&& r1, R2&& r2); +} template constexpr void // constexpr in C++20 diff --git a/libcxx/include/functional b/libcxx/include/functional --- a/libcxx/include/functional +++ b/libcxx/include/functional @@ -482,6 +482,16 @@ template struct hash; template <> struct hash; // C++17 +namespace ranges { + // [range.cmp], concept-constrained comparisons + struct equal_to; + struct not_equal_to; + struct greater; + struct less; + struct greater_equal; + struct less_equal; +} + } // std POLICY: For non-variadic implementations, the number of arguments is limited diff --git a/libcxx/include/iterator b/libcxx/include/iterator --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -406,7 +406,7 @@ constexpr Iterator base() &&; // From C++20 constexpr reference operator*() const; - constexpr pointer operator->() const; // Removed in C++20 + constexpr pointer operator->() const; // Deprecated in C++20 constexpr move_iterator& operator++(); constexpr auto operator++(int); // Return type was move_iterator until C++20 constexpr move_iterator& operator--(); diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.ref/deprecated.verify.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.ref/deprecated.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.ref/deprecated.verify.cpp @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// move_iterator + +#include + +int main(int, char**) { + (void)std::move_iterator().operator->(); + // expected-warning@-1{{'operator->' is deprecated}} + + return 0; +} diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.ref/op_arrow.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.ref/op_arrow.pass.cpp --- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.ref/op_arrow.pass.cpp +++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.ref/op_arrow.pass.cpp @@ -6,6 +6,8 @@ // //===----------------------------------------------------------------------===// +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS + // // move_iterator @@ -13,32 +15,21 @@ // pointer operator->() const; // // constexpr in C++17 -// removed in C++20 +// deprecated in C++20 #include #include #include "test_macros.h" -#if TEST_STD_VER > 17 -template -concept HasArrow = requires (T t) { - t.operator->(); -}; -static_assert(!HasArrow>); -static_assert(!HasArrow&>); -static_assert(!HasArrow&&>); -#endif // TEST_STD_VER > 17 - TEST_CONSTEXPR_CXX17 bool test() { -#if TEST_STD_VER <= 17 char a[] = "123456789"; std::move_iterator it1 = std::make_move_iterator(a); std::move_iterator it2 = std::make_move_iterator(a + 1); assert(it1.operator->() == a); assert(it2.operator->() == a + 1); -#endif + return true; } diff --git a/libcxx/test/std/ranges/range.access/begin.verify.cpp b/libcxx/test/std/ranges/range.access/begin.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/begin.verify.cpp @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// std::ranges::begin + +#include + +struct NonBorrowedRange { + int* begin() const; + int* end() const; +}; +static_assert(!std::ranges::enable_borrowed_range); + +// Verify that if the expression is an rvalue and `enable_borrowed_range` is false, `ranges::begin` is ill-formed. +void test() { + std::ranges::begin(NonBorrowedRange()); + // expected-error-re@-1 {{{{call to deleted function call operator in type 'const (std::ranges::)?__begin::__fn'}}}} + // expected-error@-2 {{attempt to use a deleted function}} +} diff --git a/libcxx/test/std/ranges/range.access/data.verify.cpp b/libcxx/test/std/ranges/range.access/data.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/data.verify.cpp @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// std::ranges::data + +#include + +struct NonBorrowedRange { + int* begin() const; + int* end() const; +}; +static_assert(!std::ranges::enable_borrowed_range); + +// Verify that if the expression is an rvalue and `enable_borrowed_range` is false, `ranges::data` is ill-formed. +void test() { + std::ranges::data(NonBorrowedRange()); + // expected-error-re@-1 {{{{no matching function for call to object of type 'const (std::ranges::)?__data::__fn'}}}} +} diff --git a/libcxx/test/std/ranges/range.access/empty.verify.cpp b/libcxx/test/std/ranges/range.access/empty.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/empty.verify.cpp @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// std::ranges::empty + +#include + +extern int arr[]; + +// Verify that for an array of unknown bound `ranges::empty` is ill-formed. +void test() { + std::ranges::empty(arr); + // expected-error-re@-1 {{{{no matching function for call to object of type 'const (std::ranges::)?__empty::__fn'}}}} +} diff --git a/libcxx/test/std/ranges/range.access/end.verify.cpp b/libcxx/test/std/ranges/range.access/end.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/end.verify.cpp @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// std::ranges::end + +#include + +struct NonBorrowedRange { + int* begin() const; + int* end() const; +}; +static_assert(!std::ranges::enable_borrowed_range); + +// Verify that if the expression is an rvalue and `enable_borrowed_range` is false, `ranges::end` is ill-formed. +void test() { + std::ranges::end(NonBorrowedRange()); + // expected-error-re@-1 {{{{call to deleted function call operator in type 'const (std::ranges::)?__end::__fn'}}}} + // expected-error@-2 {{attempt to use a deleted function}} +} diff --git a/libcxx/test/std/ranges/range.access/rbegin.verify.cpp b/libcxx/test/std/ranges/range.access/rbegin.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/rbegin.verify.cpp @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// std::ranges::rbegin + +#include + +struct NonBorrowedRange { + int* begin() const; + int* end() const; +}; +static_assert(!std::ranges::enable_borrowed_range); + +// Verify that if the expression is an rvalue and `enable_borrowed_range` is false, `ranges::rbegin` is ill-formed. +void test() { + std::ranges::rbegin(NonBorrowedRange()); + // expected-error-re@-1 {{{{call to deleted function call operator in type 'const (std::ranges::)?__rbegin::__fn'}}}} + // expected-error@-2 {{attempt to use a deleted function}} +} diff --git a/libcxx/test/std/ranges/range.access/rend.verify.cpp b/libcxx/test/std/ranges/range.access/rend.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/rend.verify.cpp @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// std::ranges::rend + +#include + +struct NonBorrowedRange { + int* begin() const; + int* end() const; +}; +static_assert(!std::ranges::enable_borrowed_range); + +// Verify that if the expression is an rvalue and `enable_borrowed_range` is false, `ranges::rend` is ill-formed. +void test() { + std::ranges::rend(NonBorrowedRange()); + // expected-error-re@-1 {{{{call to deleted function call operator in type 'const (std::ranges::)?__rend::__fn'}}}} + // expected-error@-2 {{attempt to use a deleted function}} +} diff --git a/libcxx/test/std/ranges/range.access/size.verify.cpp b/libcxx/test/std/ranges/range.access/size.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/size.verify.cpp @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// std::ranges::size + +#include + +extern int arr[]; + +// Verify that for an array of unknown bound `ranges::size` is ill-formed. +void test() { + std::ranges::size(arr); + // expected-error-re@-1 {{{{no matching function for call to object of type 'const (std::ranges::)?__size::__fn'}}}} +} diff --git a/libcxx/test/std/ranges/range.access/ssize.verify.cpp b/libcxx/test/std/ranges/range.access/ssize.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.access/ssize.verify.cpp @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// std::ranges::size + +#include + +extern int arr[]; + +// Verify that for an array of unknown bound `ranges::ssize` is ill-formed. +void test() { + std::ranges::ssize(arr); + // expected-error-re@-1 {{{{no matching function for call to object of type 'const (std::ranges::)?__ssize::__fn'}}}} +} diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.copy/ranges_uninitialized_copy.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.copy/ranges_uninitialized_copy.pass.cpp --- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.copy/ranges_uninitialized_copy.pass.cpp +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.copy/ranges_uninitialized_copy.pass.cpp @@ -370,5 +370,32 @@ assert(result.out == out.end()); } + // Move-only iterators are supported. + { + using MoveOnlyIter = cpp20_input_iterator; + static_assert(!std::is_copy_constructible_v); + + constexpr int N = 3; + struct MoveOnlyRange { + int buffer[N] = {1, 2, 3}; + auto begin() const { return MoveOnlyIter(buffer); } + auto end() const { return sentinel_wrapper(MoveOnlyIter(buffer)); } + }; + static_assert(std::ranges::input_range); + MoveOnlyRange in; + + // (iter, sentinel) overload. + { + Buffer out; + std::ranges::uninitialized_copy(in.begin(), in.end(), out.begin(), out.end()); + } + + // (range) overload. + { + Buffer out; + std::ranges::uninitialized_copy(in, out); + } + } + return 0; } diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.copy/ranges_uninitialized_copy_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.copy/ranges_uninitialized_copy_n.pass.cpp --- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.copy/ranges_uninitialized_copy_n.pass.cpp +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.copy/ranges_uninitialized_copy_n.pass.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include "../buffer.h" #include "../counted.h" @@ -148,5 +149,18 @@ assert(result.out == out.end()); } + // Move-only iterators are supported. + { + using MoveOnlyIter = cpp20_input_iterator; + static_assert(!std::is_copy_constructible_v); + + constexpr int N = 3; + int buffer[N] = {1, 2, 3}; + + MoveOnlyIter in(buffer); + Buffer out; + std::ranges::uninitialized_copy_n(std::move(in), N, out.begin(), out.end()); + } + return 0; } diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move.pass.cpp --- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move.pass.cpp +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move.pass.cpp @@ -391,5 +391,32 @@ iter_moves = 0; } + // Move-only iterators are supported. + { + using MoveOnlyIter = cpp20_input_iterator; + static_assert(!std::is_copy_constructible_v); + + constexpr int N = 3; + struct MoveOnlyRange { + int buffer[N] = {1, 2, 3}; + auto begin() const { return MoveOnlyIter(buffer); } + auto end() const { return sentinel_wrapper(MoveOnlyIter(buffer)); } + }; + static_assert(std::ranges::input_range); + MoveOnlyRange in; + + // (iter, sentinel) overload. + { + Buffer out; + std::ranges::uninitialized_move(in.begin(), in.end(), out.begin(), out.end()); + } + + // (range) overload. + { + Buffer out; + std::ranges::uninitialized_move(in, out); + } + } + return 0; } diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move_n.pass.cpp --- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move_n.pass.cpp +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move_n.pass.cpp @@ -167,5 +167,18 @@ iter_moves = 0; } + // Move-only iterators are supported. + { + using MoveOnlyIter = cpp20_input_iterator; + static_assert(!std::is_copy_constructible_v); + + constexpr int N = 3; + int buffer[N] = {1, 2, 3}; + + MoveOnlyIter in(buffer); + Buffer out; + std::ranges::uninitialized_move_n(std::move(in), N, out.begin(), out.end()); + } + return 0; }