Index: libcxx/docs/Status/Cxx2bIssues.csv =================================================================== --- libcxx/docs/Status/Cxx2bIssues.csv +++ libcxx/docs/Status/Cxx2bIssues.csv @@ -104,7 +104,7 @@ `3123 `__,"``duration`` constructor from representation shouldn't be effectively non-throwing","October 2021","","","|chrono|" `3146 `__,"Excessive unwrapping in ``std::ref/cref``","October 2021","|Complete|","14.0" `3152 `__,"``common_type`` and ``common_reference`` have flaws in common","October 2021","","" -`3293 `__,"``move_iterator operator+()`` has incorrect constraints","October 2021","","","|ranges|" +`3293 `__,"``move_iterator operator+()`` has incorrect constraints","October 2021","|Complete|","14.0","|ranges|" `3361 `__,"``safe_range`` case","October 2021","","","|ranges|" `3392 `__,"``ranges::distance()`` cannot be used on a move-only iterator with a sized sentinel","October 2021","","","|ranges|" `3407 `__,"Some problems with the wording changes of P1739R4","October 2021","","","|ranges|" Index: libcxx/include/CMakeLists.txt =================================================================== --- libcxx/include/CMakeLists.txt +++ libcxx/include/CMakeLists.txt @@ -235,6 +235,7 @@ __iterator/iterator.h __iterator/iterator_traits.h __iterator/move_iterator.h + __iterator/move_sentinel.h __iterator/next.h __iterator/ostream_iterator.h __iterator/ostreambuf_iterator.h Index: libcxx/include/__iterator/move_iterator.h =================================================================== --- libcxx/include/__iterator/move_iterator.h +++ libcxx/include/__iterator/move_iterator.h @@ -10,8 +10,19 @@ #ifndef _LIBCPP___ITERATOR_MOVE_ITERATOR_H #define _LIBCPP___ITERATOR_MOVE_ITERATOR_H +#include <__compare/compare_three_way_result.h> +#include <__concepts/assignable.h> +#include <__concepts/convertible_to.h> +#include <__concepts/derived_from.h> +#include <__concepts/same_as.h> #include <__config> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/iter_move.h> +#include <__iterator/iter_swap.h> #include <__iterator/iterator_traits.h> +#include <__iterator/move_sentinel.h> +#include <__iterator/readable_traits.h> #include <__utility/move.h> #include @@ -21,20 +32,48 @@ _LIBCPP_BEGIN_NAMESPACE_STD +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) +template +struct __move_iter_category_base {}; + +template + requires requires { typename iterator_traits<_Iter>::iterator_category; } +struct __move_iter_category_base<_Iter> { + using iterator_category = _If< + derived_from::iterator_category, random_access_iterator_tag>, + random_access_iterator_tag, + typename iterator_traits<_Iter>::iterator_category + >; +}; + +template +concept __move_iter_comparable = requires { + { declval() == declval<_Sent>() } -> convertible_to; +}; +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + template class _LIBCPP_TEMPLATE_VIS move_iterator +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + : public __move_iter_category_base<_Iter> +#endif { public: -#if _LIBCPP_STD_VER > 17 - typedef input_iterator_tag iterator_concept; -#endif - +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + using iterator_type = _Iter; + using iterator_concept = input_iterator_tag; + // iterator_category is inherited and not always present + using value_type = iter_value_t<_Iter>; + using difference_type = iter_difference_t<_Iter>; + using pointer = _Iter; + using reference = iter_rvalue_reference_t<_Iter>; +#else typedef _Iter iterator_type; typedef _If< __is_cpp17_random_access_iterator<_Iter>::value, random_access_iterator_tag, typename iterator_traits<_Iter>::iterator_category - > iterator_category; + > iterator_category; typedef typename iterator_traits::value_type value_type; typedef typename iterator_traits::difference_type difference_type; typedef iterator_type pointer; @@ -50,18 +89,41 @@ typedef typename iterator_traits::reference reference; #endif - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 - move_iterator() : __current_() {} +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 explicit move_iterator(_Iter __i) : __current_(_VSTD::move(__i)) {} +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 + move_iterator() requires is_constructible_v<_Iter> : __current_() {} + + template + requires (!_IsSame<_Up, _Iter>::value) && convertible_to + _LIBCPP_HIDE_FROM_ABI constexpr + move_iterator(const move_iterator<_Up>& __u) : __current_(__u.base()) {} +#else + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 + move_iterator() : __current_() {} + template ::value && is_convertible::value > > _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 move_iterator(const move_iterator<_Up>& __u) : __current_(__u.base()) {} +#endif +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + template + requires (!_IsSame<_Up, _Iter>::value) && + convertible_to && + assignable_from<_Iter&, const _Up&> + _LIBCPP_HIDE_FROM_ABI constexpr + move_iterator& operator=(const move_iterator<_Up>& __u) { + __current_ = __u.base(); + return *this; + } +#else template ::value && is_convertible::value && @@ -72,21 +134,48 @@ __current_ = __u.base(); return *this; } +#endif +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + _LIBCPP_HIDE_FROM_ABI constexpr const _Iter& base() const & noexcept { return __current_; } + _LIBCPP_HIDE_FROM_ABI constexpr _Iter base() && { return _VSTD::move(__current_); } +#else _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 _Iter base() const { return __current_; } +#endif +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + _LIBCPP_HIDE_FROM_ABI constexpr + reference operator*() const { return ranges::iter_move(__current_); } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 + reference operator[](difference_type __n) const { return ranges::iter_move(__current_ + __n); } +#else _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]); } +#endif _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 move_iterator& operator++() { ++__current_; return *this; } + +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + _LIBCPP_HIDE_FROM_ABI constexpr + auto operator++(int) + requires forward_iterator<_Iter> + { + move_iterator __tmp(*this); ++__current_; return __tmp; + } + + _LIBCPP_HIDE_FROM_ABI constexpr + void operator++(int) { ++__current_; } +#else _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 move_iterator operator++(int) { move_iterator __tmp(*this); ++__current_; return __tmp; } +#endif + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 move_iterator& operator--() { --__current_; return *this; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 @@ -100,7 +189,48 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 move_iterator& operator-=(difference_type __n) { __current_ -= __n; return *this; } +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + template _Sent> + friend _LIBCPP_HIDE_FROM_ABI constexpr + bool operator==(const move_iterator& __x, const move_sentinel<_Sent>& __y) + requires __move_iter_comparable<_Iter, _Sent> + { + return __x.base() == __y.base(); + } + + template _Sent> + friend _LIBCPP_HIDE_FROM_ABI constexpr + iter_difference_t<_Iter> operator-(const move_sentinel<_Sent>& __x, const move_iterator& __y) + { + return __x.base() - __y.base(); + } + + template _Sent> + friend _LIBCPP_HIDE_FROM_ABI constexpr + iter_difference_t<_Iter> operator-(const move_iterator& __x, const move_sentinel<_Sent>& __y) + { + return __x.base() - __y.base(); + } + + friend _LIBCPP_HIDE_FROM_ABI constexpr + iter_rvalue_reference_t<_Iter> iter_move(const move_iterator& __i) + noexcept(noexcept(ranges::iter_move(__i.__current_))) + { + return ranges::iter_move(__i.__current_); + } + + template _It2> + friend _LIBCPP_HIDE_FROM_ABI constexpr + void iter_swap(const move_iterator& __x, const move_iterator<_It2>& __y) + noexcept(noexcept(ranges::iter_swap(__x.__current_, __y.__current_))) + { + return ranges::iter_swap(__x.__current_, __y.__current_); + } +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + private: + template friend class move_iterator; + _Iter __current_; }; @@ -111,12 +241,14 @@ return __x.base() == __y.base(); } +#if _LIBCPP_STD_VER <= 17 template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 bool operator!=(const move_iterator<_Iter1>& __x, const move_iterator<_Iter2>& __y) { return __x.base() != __y.base(); } +#endif // _LIBCPP_STD_VER <= 17 template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 @@ -146,6 +278,16 @@ return __x.base() >= __y.base(); } +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) +template +inline _LIBCPP_HIDE_FROM_ABI constexpr +auto operator<=>(const move_iterator<_Iter1>& __x, const move_iterator<_Iter2>& __y) + -> compare_three_way_result_t<_Iter1, _Iter2> +{ + return __x.base() <=> __y.base(); +} +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) + #ifndef _LIBCPP_CXX03_LANG template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 @@ -164,6 +306,15 @@ } #endif +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) +template +inline _LIBCPP_HIDE_FROM_ABI constexpr +move_iterator<_Iter> operator+(iter_difference_t<_Iter> __n, const move_iterator<_Iter>& __x) + requires requires { { __x.base() + __n } -> same_as<_Iter>; } +{ + return __x + __n; +} +#else template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 move_iterator<_Iter> @@ -171,6 +322,7 @@ { return move_iterator<_Iter>(__x.base() + __n); } +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 Index: libcxx/include/__iterator/move_sentinel.h =================================================================== --- /dev/null +++ libcxx/include/__iterator/move_sentinel.h @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ITERATOR_MOVE_SENTINEL_H +#define _LIBCPP___ITERATOR_MOVE_SENTINEL_H + +#include <__concepts/assignable.h> +#include <__concepts/convertible_to.h> +#include <__concepts/semiregular.h> +#include <__config> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS) + +template +class _LIBCPP_TEMPLATE_VIS move_sentinel +{ +public: + _LIBCPP_HIDE_FROM_ABI + move_sentinel() = default; + + _LIBCPP_HIDE_FROM_ABI constexpr + explicit move_sentinel(_Sent __s) : __last_(_VSTD::move(__s)) {} + + template + requires convertible_to + _LIBCPP_HIDE_FROM_ABI constexpr + move_sentinel(const move_sentinel<_S2>& __s) : __last_(__s.base()) {} + + template + requires assignable_from<_Sent&, const _S2&> + _LIBCPP_HIDE_FROM_ABI constexpr + move_sentinel& operator=(const move_sentinel<_S2>& __s) + { __last_ = __s.base(); return *this; } + + constexpr _Sent base() const { return __last_; } + +private: + _Sent __last_ = _Sent(); +}; + +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS) + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_MOVE_SENTINEL_H Index: libcxx/include/iterator =================================================================== --- libcxx/include/iterator +++ libcxx/include/iterator @@ -607,6 +607,7 @@ #include <__iterator/iterator.h> #include <__iterator/iterator_traits.h> #include <__iterator/move_iterator.h> +#include <__iterator/move_sentinel.h> #include <__iterator/next.h> #include <__iterator/ostream_iterator.h> #include <__iterator/ostreambuf_iterator.h> Index: libcxx/include/module.modulemap =================================================================== --- libcxx/include/module.modulemap +++ libcxx/include/module.modulemap @@ -615,6 +615,7 @@ module iterator { private header "__iterator/iterator.h" } module iterator_traits { private header "__iterator/iterator_traits.h" } module move_iterator { private header "__iterator/move_iterator.h" } + module move_sentinel { private header "__iterator/move_sentinel.h" } module next { private header "__iterator/next.h" } module ostream_iterator { private header "__iterator/ostream_iterator.h" } module ostreambuf_iterator { private header "__iterator/ostreambuf_iterator.h" } Index: libcxx/test/libcxx/diagnostics/detail.headers/iterator/move_sentinel.module.verify.cpp =================================================================== --- /dev/null +++ libcxx/test/libcxx/diagnostics/detail.headers/iterator/move_sentinel.module.verify.cpp @@ -0,0 +1,15 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: modules-build + +// WARNING: This test was generated by 'generate_private_header_tests.py' +// and should not be edited manually. + +// expected-error@*:* {{use of private header from outside its module: '__iterator/move_sentinel.h'}} +#include <__iterator/move_sentinel.h> Index: libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_eq.pass.cpp =================================================================== --- libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_eq.pass.cpp +++ libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_eq.pass.cpp @@ -23,40 +23,81 @@ #include "test_macros.h" #include "test_iterators.h" +#if TEST_STD_VER > 17 template -void -test(It l, It r, bool x) +constexpr bool test_sentinel() { - const std::move_iterator r1(l); - const std::move_iterator r2(r); - assert((r1 == r2) == x); + { + char s[] = "1234567890"; + const auto it = std::move_iterator(It(s)); + const auto sent = std::move_sentinel>(sentinel_wrapper(It(s))); + ASSERT_SAME_TYPE(decltype(it == sent), bool); + assert(it == sent); + assert(!(it != sent)); + } + { + char s[] = "1234567890"; + const auto it = std::move_iterator(It(s)); + const auto sent = std::move_sentinel>(sentinel_wrapper(It(s + 1))); + ASSERT_SAME_TYPE(decltype(it == sent), bool); + assert(!(it == sent)); + assert(it != sent); + } + return true; } +#endif -int main(int, char**) +template +TEST_CONSTEXPR_CXX17 bool test() { + { + char s[] = "1234567890"; + const std::move_iterator r1 = std::move_iterator(It(s)); + const std::move_iterator r2 = std::move_iterator(It(s)); + ASSERT_SAME_TYPE(decltype(r1 == r2), bool); + assert(r1 == r2); + assert(!(r1 != r2)); + } + { char s[] = "1234567890"; - test(cpp17_input_iterator(s), cpp17_input_iterator(s), true); - test(cpp17_input_iterator(s), cpp17_input_iterator(s+1), false); - test(forward_iterator(s), forward_iterator(s), true); - test(forward_iterator(s), forward_iterator(s+1), false); - test(bidirectional_iterator(s), bidirectional_iterator(s), true); - test(bidirectional_iterator(s), bidirectional_iterator(s+1), false); - test(random_access_iterator(s), random_access_iterator(s), true); - test(random_access_iterator(s), random_access_iterator(s+1), false); - test(s, s, true); - test(s, s+1, false); + const std::move_iterator r1 = std::move_iterator(It(s)); + const std::move_iterator r2 = std::move_iterator(It(s + 1)); + ASSERT_SAME_TYPE(decltype(r1 == r2), bool); + assert(!(r1 == r2)); + assert(r1 != r2); + } +#if TEST_STD_VER > 17 + test_sentinel(); +#endif + return true; +} + +int main(int, char**) +{ + test>(); + test>(); + test>(); + test>(); + test(); + test(); #if TEST_STD_VER > 14 - { - constexpr const char *p = "123456789"; - typedef std::move_iterator MI; - constexpr MI it1 = std::make_move_iterator(p); - constexpr MI it2 = std::make_move_iterator(p + 5); - constexpr MI it3 = std::make_move_iterator(p); - static_assert(!(it1 == it2), ""); - static_assert( (it1 == it3), ""); - static_assert(!(it2 == it3), ""); - } + static_assert(test>()); + static_assert(test>()); + static_assert(test>()); + static_assert(test>()); + static_assert(test()); + static_assert(test()); +#endif + +#if TEST_STD_VER > 17 + test_sentinel>(); + test>(); + test>(); + + static_assert(test_sentinel>()); + static_assert(test>()); + static_assert(test>()); #endif return 0; Index: libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/iter.pass.cpp =================================================================== --- libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/iter.pass.cpp +++ libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/iter.pass.cpp @@ -16,33 +16,73 @@ #include #include +#include #include "test_macros.h" #include "test_iterators.h" template -void -test(It i) +TEST_CONSTEXPR_CXX17 bool test() { - std::move_iterator r(i); - assert(r.base() == i); + static_assert( std::is_constructible, const It&>::value, ""); + static_assert( std::is_constructible, It&&>::value, ""); + static_assert(!std::is_convertible>::value, ""); + static_assert(!std::is_convertible>::value, ""); + + char s[] = "123"; + { + It it = It(s); + std::move_iterator r(it); + assert(base(r.base()) == s); + } + { + It it = It(s); + std::move_iterator r(std::move(it)); + assert(base(r.base()) == s); + } + return true; +} + +template +TEST_CONSTEXPR_CXX17 bool test_moveonly() +{ + static_assert(!std::is_constructible, const It&>::value, ""); + static_assert( std::is_constructible, It&&>::value, ""); + static_assert(!std::is_convertible>::value, ""); + static_assert(!std::is_convertible>::value, ""); + + char s[] = "123"; + { + It it = It(s); + std::move_iterator r(std::move(it)); + assert(base(r.base()) == s); + } + return true; } int main(int, char**) { - char s[] = "123"; - test(cpp17_input_iterator(s)); - test(forward_iterator(s)); - test(bidirectional_iterator(s)); - test(random_access_iterator(s)); - test(s); + test >(); + test >(); + test >(); + test >(); + test(); + test(); #if TEST_STD_VER > 14 - { - constexpr const char *p = "123456789"; - constexpr std::move_iterator it(p); - static_assert(it.base() == p); - } + static_assert(test>()); + static_assert(test>()); + static_assert(test>()); + static_assert(test>()); + static_assert(test()); + static_assert(test()); +#endif + +#if TEST_STD_VER > 17 + test>(); + test_moveonly>(); + static_assert(test>()); + static_assert(test_moveonly>()); #endif return 0; Index: libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.ref/op_arrow.pass.cpp =================================================================== --- libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.ref/op_arrow.pass.cpp +++ libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.ref/op_arrow.pass.cpp @@ -13,35 +13,41 @@ // pointer operator->() const; // // constexpr in C++17 +// removed in C++20 #include #include #include "test_macros.h" -template -void -test(It i) +#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() { - std::move_iterator r(i); - assert(r.operator->() == i); +#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; } int main(int, char**) { - char s[] = "123"; - test(s); - + test(); #if TEST_STD_VER > 14 - { - constexpr const char *p = "123456789"; - typedef std::move_iterator MI; - constexpr MI it1 = std::make_move_iterator(p); - constexpr MI it2 = std::make_move_iterator(p+1); - static_assert(it1.operator->() == p, ""); - static_assert(it2.operator->() == p + 1, ""); - } + static_assert(test()); #endif - return 0; + return 0; } Index: libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op=/move_iterator.pass.cpp =================================================================== --- libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op=/move_iterator.pass.cpp +++ libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op=/move_iterator.pass.cpp @@ -56,6 +56,7 @@ m_value = src.m_value; return *this; } + char *m_value; reference operator*() const; Index: libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/iterator_concept_conformance.compile.pass.cpp =================================================================== --- libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/iterator_concept_conformance.compile.pass.cpp +++ libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/iterator_concept_conformance.compile.pass.cpp @@ -13,14 +13,100 @@ #include -using iterator = std::move_iterator; - -static_assert(std::input_iterator); -static_assert(!std::forward_iterator); -static_assert(!std::indirectly_writable); -static_assert(std::incrementable); -static_assert(std::sentinel_for); -static_assert(std::sized_sentinel_for); -static_assert(!std::indirectly_movable); -static_assert(!std::indirectly_movable_storable); -static_assert(!std::indirectly_swappable); +#include "test_iterators.h" +#include "test_macros.h" + +void test() +{ + { + using iterator = std::move_iterator>; + + LIBCPP_STATIC_ASSERT(!std::default_initializable); + static_assert( std::copyable); + static_assert( std::input_iterator); + static_assert(!std::forward_iterator); + static_assert(!std::sentinel_for); // not copyable + static_assert(!std::sized_sentinel_for); + static_assert( std::indirectly_readable); + static_assert(!std::indirectly_writable); + static_assert( std::indirectly_swappable); + } + { + using iterator = std::move_iterator>; + + LIBCPP_STATIC_ASSERT(!std::default_initializable); + static_assert(!std::copyable); + static_assert( std::input_iterator); + static_assert(!std::forward_iterator); + static_assert(!std::sentinel_for); // not copyable + static_assert(!std::sized_sentinel_for); + static_assert( std::indirectly_readable); + static_assert(!std::indirectly_writable); + static_assert( std::indirectly_swappable); + } + { + using iterator = std::move_iterator>; + + static_assert( std::default_initializable); + static_assert( std::copyable); + static_assert( std::input_iterator); + static_assert(!std::forward_iterator); + static_assert( std::sentinel_for); + static_assert(!std::sized_sentinel_for); + static_assert( std::indirectly_readable); + static_assert(!std::indirectly_writable); + static_assert( std::indirectly_swappable); + } + { + using iterator = std::move_iterator>; + + static_assert( std::default_initializable); + static_assert( std::copyable); + static_assert( std::input_iterator); + static_assert(!std::forward_iterator); + static_assert( std::sentinel_for); + static_assert(!std::sized_sentinel_for); + static_assert( std::indirectly_readable); + static_assert(!std::indirectly_writable); + static_assert( std::indirectly_swappable); + } + { + using iterator = std::move_iterator>; + + static_assert( std::default_initializable); + static_assert( std::copyable); + static_assert( std::input_iterator); + static_assert(!std::forward_iterator); + static_assert( std::sentinel_for); + static_assert( std::sized_sentinel_for); + static_assert( std::indirectly_readable); + static_assert(!std::indirectly_writable); + static_assert( std::indirectly_swappable); + } + { + using iterator = std::move_iterator>; + + static_assert( std::default_initializable); + static_assert( std::copyable); + static_assert( std::input_iterator); + static_assert(!std::forward_iterator); + static_assert( std::sentinel_for); + static_assert( std::sized_sentinel_for); + static_assert( std::indirectly_readable); + static_assert(!std::indirectly_writable); + static_assert( std::indirectly_swappable); + } + { + using iterator = std::move_iterator; + + static_assert( std::default_initializable); + static_assert( std::copyable); + static_assert( std::input_iterator); + static_assert(!std::forward_iterator); + static_assert( std::sentinel_for); + static_assert( std::sized_sentinel_for); + static_assert( std::indirectly_readable); + static_assert(!std::indirectly_writable); + static_assert( std::indirectly_swappable); + } +} Index: libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/assign.converting.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/assign.converting.pass.cpp @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// +// 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-no-concepts + +// + +// move_sentinel + +// template +// requires assignable_from +// constexpr move_sentinel& operator=(const move_sentinel& s); + +#include +#include +#include + +struct NonAssignable { + NonAssignable& operator=(int i); +}; +static_assert(std::semiregular); +static_assert(std::is_assignable_v); +static_assert(!std::assignable_from); + +constexpr bool test() +{ + { + std::move_sentinel m(42); + std::move_sentinel m2; + m2 = m; + assert(m2.base() == 42L); + } + { + std::move_sentinel m2; + m2 = std::move_sentinel(43); + assert(m2.base() == 43L); + } + { + static_assert( std::is_assignable_v, std::move_sentinel>); + static_assert(!std::is_assignable_v, std::move_sentinel>); + static_assert( std::is_assignable_v, std::move_sentinel>); + static_assert(!std::is_assignable_v, std::move_sentinel>); + } + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + return 0; +} Index: libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/base.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/base.pass.cpp @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// +// 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-no-concepts + +// + +// move_sentinel + +// constexpr S base() const; + +#include +#include + +#include "test_macros.h" + +constexpr bool test() +{ + { + auto m = std::move_sentinel(42); + const auto& cm = m; + assert(m.base() == 42); + assert(cm.base() == 42); + assert(std::move(m).base() == 42); + assert(std::move(cm).base() == 42); + ASSERT_SAME_TYPE(decltype(m.base()), int); + ASSERT_SAME_TYPE(decltype(cm.base()), int); + ASSERT_SAME_TYPE(decltype(std::move(m).base()), int); + ASSERT_SAME_TYPE(decltype(std::move(cm).base()), int); + } + { + int a[] = {1, 2, 3}; + auto m = std::move_sentinel(a); + const auto& cm = m; + assert(m.base() == a); + assert(cm.base() == a); + assert(std::move(m).base() == a); + assert(std::move(cm).base() == a); + ASSERT_SAME_TYPE(decltype(m.base()), const int*); + ASSERT_SAME_TYPE(decltype(cm.base()), const int*); + ASSERT_SAME_TYPE(decltype(std::move(m).base()), const int*); + ASSERT_SAME_TYPE(decltype(std::move(cm).base()), const int*); + } + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + return 0; +} Index: libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/concept_conformance.compile.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/concept_conformance.compile.pass.cpp @@ -0,0 +1,92 @@ +//===----------------------------------------------------------------------===// +// +// 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-no-concepts +// UNSUPPORTED: libcpp-no-incomplete-ranges + +// + +// template +// class move_sentinel; + +#include + +#include "test_iterators.h" + +void test() +{ + { + using It = int*; + static_assert( std::sentinel_for, std::move_iterator>); + static_assert( std::sized_sentinel_for, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert(!std::sized_sentinel_for>, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert( std::sized_sentinel_for>, std::move_iterator>); + } + { + using It = cpp17_input_iterator; + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert(!std::sized_sentinel_for>, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert( std::sized_sentinel_for>, std::move_iterator>); + } + { + using It = cpp20_input_iterator; + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert(!std::sized_sentinel_for>, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert( std::sized_sentinel_for>, std::move_iterator>); + } + { + using It = forward_iterator; + static_assert( std::sentinel_for, std::move_iterator>); + static_assert(!std::sized_sentinel_for, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert(!std::sized_sentinel_for>, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert( std::sized_sentinel_for>, std::move_iterator>); + } + { + using It = bidirectional_iterator; + static_assert( std::sentinel_for, std::move_iterator>); + static_assert(!std::sized_sentinel_for, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert(!std::sized_sentinel_for>, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert( std::sized_sentinel_for>, std::move_iterator>); + } + { + using It = random_access_iterator; + static_assert( std::sentinel_for, std::move_iterator>); + static_assert( std::sized_sentinel_for, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert(!std::sized_sentinel_for>, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert( std::sized_sentinel_for>, std::move_iterator>); + } + { + using It = contiguous_iterator; + static_assert( std::sentinel_for, std::move_iterator>); + static_assert( std::sized_sentinel_for, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert(!std::sized_sentinel_for>, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert( std::sized_sentinel_for>, std::move_iterator>); + } + { + using It = three_way_contiguous_iterator; + static_assert( std::sentinel_for, std::move_iterator>); + static_assert( std::sized_sentinel_for, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert(!std::sized_sentinel_for>, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert( std::sized_sentinel_for>, std::move_iterator>); + } +} Index: libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/constraints.compile.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/constraints.compile.pass.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// 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-no-concepts + +// + +// template +// class move_sentinel; + +#include + +template +concept HasMoveSentinel = requires { + typename std::move_sentinel; +}; + +struct Semiregular {}; + +struct NotSemiregular { + NotSemiregular(int); +}; + +static_assert( HasMoveSentinel); +static_assert( HasMoveSentinel); +static_assert( HasMoveSentinel); +static_assert(!HasMoveSentinel); Index: libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.converting.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.converting.pass.cpp @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// 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-no-concepts + +// + +// move_sentinel + +// template +// requires convertible_to +// constexpr move_sentinel(const move_sentinel& s); + +#include +#include +#include + +struct NonConvertible { + explicit NonConvertible(); + NonConvertible(int i); + explicit NonConvertible(long i) = delete; +}; +static_assert(std::semiregular); +static_assert(std::is_convertible_v); +static_assert(!std::convertible_to); + +constexpr bool test() +{ + { + std::move_sentinel m(42); + std::move_sentinel m2 = m; + assert(m2.base() == 42L); + } + { + std::move_sentinel m2 = std::move_sentinel(43); + assert(m2.base() == 43L); + } + { + static_assert( std::is_convertible_v, std::move_sentinel>); + static_assert( std::is_convertible_v, std::move_sentinel>); + static_assert(!std::is_convertible_v, std::move_sentinel>); + static_assert( std::is_convertible_v, std::move_sentinel>); + static_assert(!std::is_convertible_v, std::move_sentinel>); + } + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + return 0; +} Index: libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.default.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.default.pass.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// 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-no-concepts + +// + +// move_sentinel + +// constexpr move_sentinel(); + +#include +#include + +constexpr bool test() +{ + { + std::move_sentinel m; + assert(m.base() == 0); + } + { + std::move_sentinel m; + assert(m.base() == nullptr); + } + { + struct S { + explicit S() = default; + int i = 3; + }; + std::move_sentinel m; + assert(m.base().i == 3); + } + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + return 0; +} Index: libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.sentinel.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.sentinel.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// 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-no-concepts + +// + +// move_sentinel + +// constexpr explicit move_sentinel(S s); + +#include +#include + +constexpr bool test() +{ + { + static_assert(!std::is_convertible_v>); + std::move_sentinel m(42); + assert(m.base() == 42); + } + { + static_assert(!std::is_convertible_v>); + int i = 42; + std::move_sentinel m(&i); + assert(m.base() == &i); + } + { + struct S { + explicit S() = default; + constexpr explicit S(int j) : i(j) {} + int i = 3; + }; + static_assert(!std::is_convertible_v>); + std::move_sentinel m(S(42)); + assert(m.base().i == 42); + } + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + return 0; +}