diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -435,6 +435,7 @@ __iterator/common_iterator.h __iterator/concepts.h __iterator/counted_iterator.h + __iterator/cpp17_iterator_concepts.h __iterator/data.h __iterator/default_sentinel.h __iterator/distance.h diff --git a/libcxx/include/__algorithm/pstl_any_all_none_of.h b/libcxx/include/__algorithm/pstl_any_all_none_of.h --- a/libcxx/include/__algorithm/pstl_any_all_none_of.h +++ b/libcxx/include/__algorithm/pstl_any_all_none_of.h @@ -12,6 +12,7 @@ #include <__algorithm/pstl_find.h> #include <__algorithm/pstl_frontend_dispatch.h> #include <__config> +#include <__iterator/cpp17_iterator_concepts.h> #include <__iterator/iterator_traits.h> #include <__type_traits/enable_if.h> #include <__type_traits/is_execution_policy.h> @@ -36,6 +37,7 @@ enable_if_t, int> = 0> _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool any_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_any_of), [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) { @@ -56,6 +58,7 @@ enable_if_t, int> = 0> _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool all_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred __pred) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_all_of), [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Pred __g_pred) { @@ -78,6 +81,7 @@ enable_if_t, int> = 0> _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI bool none_of(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred __pred) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_none_of), [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Pred __g_pred) { diff --git a/libcxx/include/__algorithm/pstl_fill.h b/libcxx/include/__algorithm/pstl_fill.h --- a/libcxx/include/__algorithm/pstl_fill.h +++ b/libcxx/include/__algorithm/pstl_fill.h @@ -13,6 +13,7 @@ #include <__algorithm/pstl_for_each.h> #include <__algorithm/pstl_frontend_dispatch.h> #include <__config> +#include <__iterator/cpp17_iterator_concepts.h> #include <__iterator/iterator_traits.h> #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> @@ -36,6 +37,7 @@ enable_if_t, int> = 0> _LIBCPP_HIDE_FROM_ABI void fill(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_fill), [&](_ForwardIterator __g_first, _ForwardIterator __g_last, const _Tp& __g_value) { @@ -59,6 +61,7 @@ enable_if_t, int> = 0> _LIBCPP_HIDE_FROM_ABI void fill_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _SizeT __n, const _Tp& __value) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_fill_n), [&](_ForwardIterator __g_first, _SizeT __g_n, const _Tp& __g_value) { diff --git a/libcxx/include/__algorithm/pstl_find.h b/libcxx/include/__algorithm/pstl_find.h --- a/libcxx/include/__algorithm/pstl_find.h +++ b/libcxx/include/__algorithm/pstl_find.h @@ -14,6 +14,7 @@ #include <__algorithm/pstl_backend.h> #include <__algorithm/pstl_frontend_dispatch.h> #include <__config> +#include <__iterator/cpp17_iterator_concepts.h> #include <__iterator/iterator_traits.h> #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> @@ -34,6 +35,7 @@ enable_if_t, int> = 0> _LIBCPP_HIDE_FROM_ABI _ForwardIterator find_if(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); using _Backend = typename __select_backend<_RawPolicy>::type; return std::__pstl_find_if<_RawPolicy>(_Backend{}, std::move(__first), std::move(__last), std::move(__pred)); } @@ -48,6 +50,7 @@ enable_if_t, int> = 0> _LIBCPP_HIDE_FROM_ABI _ForwardIterator find_if_not(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_find_if_not), [&](_ForwardIterator __g_first, _ForwardIterator __g_last, _Predicate __g_pred) { @@ -70,6 +73,7 @@ enable_if_t, int> = 0> _LIBCPP_HIDE_FROM_ABI _ForwardIterator find(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_find), [&](_ForwardIterator __g_first, _ForwardIterator __g_last, const _Tp& __g_value) { diff --git a/libcxx/include/__algorithm/pstl_for_each.h b/libcxx/include/__algorithm/pstl_for_each.h --- a/libcxx/include/__algorithm/pstl_for_each.h +++ b/libcxx/include/__algorithm/pstl_for_each.h @@ -14,6 +14,7 @@ #include <__algorithm/pstl_backend.h> #include <__algorithm/pstl_frontend_dispatch.h> #include <__config> +#include <__iterator/cpp17_iterator_concepts.h> #include <__iterator/iterator_traits.h> #include <__type_traits/is_execution_policy.h> #include <__type_traits/remove_cvref.h> @@ -35,6 +36,7 @@ enable_if_t, int> = 0> _LIBCPP_HIDE_FROM_ABI void for_each(_ExecutionPolicy&&, _ForwardIterator __first, _ForwardIterator __last, _Function __func) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); using _Backend = typename __select_backend<_RawPolicy>::type; std::__pstl_for_each<_RawPolicy>(_Backend{}, std::move(__first), std::move(__last), std::move(__func)); } @@ -50,6 +52,7 @@ enable_if_t, int> = 0> _LIBCPP_HIDE_FROM_ABI void for_each_n(_ExecutionPolicy&& __policy, _ForwardIterator __first, _Size __size, _Function __func) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); return std::__pstl_frontend_dispatch( _LIBCPP_PSTL_CUSTOMIZATION_POINT(__pstl_for_each_n), [&](_ForwardIterator __g_first, _Size __g_size, _Function __g_func) { diff --git a/libcxx/include/__algorithm/pstl_transform.h b/libcxx/include/__algorithm/pstl_transform.h --- a/libcxx/include/__algorithm/pstl_transform.h +++ b/libcxx/include/__algorithm/pstl_transform.h @@ -11,6 +11,7 @@ #include <__algorithm/pstl_backend.h> #include <__config> +#include <__iterator/cpp17_iterator_concepts.h> #include <__iterator/iterator_traits.h> #include <__type_traits/is_execution_policy.h> #include <__utility/terminate_on_exception.h> @@ -35,6 +36,9 @@ _ForwardIterator __last, _ForwardOutIterator __result, _UnaryOperation __op) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator); + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardOutIterator); + _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR(_ForwardOutIterator, decltype(__op(*__first))); using _Backend = typename __select_backend<_RawPolicy>::type; return std::__pstl_transform<_RawPolicy>( _Backend{}, std::move(__first), std::move(__last), std::move(__result), std::move(__op)); @@ -54,6 +58,10 @@ _ForwardIterator2 __first2, _ForwardOutIterator __result, _BinaryOperation __op) { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1); + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2); + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardOutIterator); + _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR(_ForwardOutIterator, decltype(__op(*__first1, *__first2))); using _Backend = typename __select_backend<_RawPolicy>::type; return std::__pstl_transform<_RawPolicy>( _Backend{}, std::move(__first1), std::move(__last1), std::move(__first2), std::move(__result), std::move(__op)); diff --git a/libcxx/include/__iterator/cpp17_iterator_concepts.h b/libcxx/include/__iterator/cpp17_iterator_concepts.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__iterator/cpp17_iterator_concepts.h @@ -0,0 +1,184 @@ +//===----------------------------------------------------------------------===// +// +// 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_CPP17_ITERATOR_CONCEPTS_H +#define _LIBCPP___ITERATOR_CPP17_ITERATOR_CONCEPTS_H + +#include <__concepts/boolean_testable.h> +#include <__concepts/convertible_to.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__type_traits/is_convertible.h> +#include <__type_traits/is_copy_constructible.h> +#include <__type_traits/is_default_constructible.h> +#include <__type_traits/is_move_constructible.h> +#include <__type_traits/is_signed.h> +#include <__type_traits/is_void.h> +#include <__utility/as_const.h> +#include <__utility/forward.h> +#include <__utility/move.h> +#include <__utility/swap.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +concept __cpp17_move_constructible = is_move_constructible_v<_Tp>; + +template +concept __cpp17_copy_constructible = __cpp17_move_constructible<_Tp> && is_copy_constructible_v<_Tp>; + +template +concept __cpp17_move_assignable = requires(_Tp __lhs, _Tp __rhs) { + { __lhs = std::move(__rhs) } -> same_as<_Tp&>; +}; + +template +concept __cpp17_copy_assignable = __cpp17_move_assignable<_Tp> && requires(_Tp __lhs, _Tp __rhs) { + { __lhs = __rhs } -> same_as<_Tp&>; +}; + +template +concept __cpp17_destructible = requires(_Tp __v) { __v.~_Tp(); }; + +template +concept __cpp17_equality_comparable = requires(_Iter __lhs, _Iter __rhs) { + { __lhs == __rhs } -> __boolean_testable; + { std::as_const(__lhs) == __rhs } -> __boolean_testable; + { __lhs == std::as_const(__rhs) } -> __boolean_testable; + { std::as_const(__lhs) == std::as_const(__rhs) } -> __boolean_testable; +}; + +template +concept __cpp17_default_constructible = is_default_constructible_v<_Tp>; + +template +concept __cpp17_iterator = + __cpp17_copy_constructible<_Iter> && __cpp17_copy_assignable<_Iter> && __cpp17_destructible<_Iter> && + (is_signed_v<__iter_diff_t<_Iter>> || is_void_v<__iter_diff_t<_Iter>>)&&requires(_Iter __iter) { + { *__iter }; + { ++__iter } -> same_as<_Iter&>; + }; + +template +concept __cpp17_input_iterator = + __cpp17_iterator<_Iter> && __cpp17_equality_comparable<_Iter> && requires(_Iter __lhs, _Iter __rhs) { + { __lhs != __rhs } -> __boolean_testable; + { std::as_const(__lhs) != __rhs } -> __boolean_testable; + { __lhs != std::as_const(__rhs) } -> __boolean_testable; + { std::as_const(__lhs) != std::as_const(__rhs) } -> __boolean_testable; + + { *__lhs } -> same_as<__iter_reference<_Iter>>; + { *std::as_const(__lhs) } -> same_as<__iter_reference<_Iter>>; + + { ++__lhs } -> same_as<_Iter&>; + { (void)__lhs++ }; + { *__lhs++ }; + }; + +template +concept __cpp17_output_iterator = __cpp17_iterator<_Iter> && requires(_Iter __iter, _WriteTo __write) { + { *__iter = std::forward<_WriteTo>(__write) }; + { ++__iter } -> same_as<_Iter&>; + { __iter++ } -> convertible_to; + { *__iter++ = std::forward<_WriteTo>(__write) }; +}; + +template +concept __cpp17_forward_iterator = + __cpp17_input_iterator<_Iter> && __cpp17_default_constructible<_Iter> && requires(_Iter __iter) { + { __iter++ } -> convertible_to; + { *__iter++ } -> same_as<__iter_reference<_Iter>>; + }; + +template +concept __cpp17_bidirectional_iterator = __cpp17_forward_iterator<_Iter> && requires(_Iter __iter) { + { --__iter } -> same_as<_Iter&>; + { __iter-- } -> convertible_to; + { *__iter-- } -> same_as<__iter_reference<_Iter>>; +}; + +template +concept __cpp17_random_access_iterator = + __cpp17_bidirectional_iterator<_Iter> && requires(_Iter __iter, __iter_diff_t<_Iter> __n) { + { __iter += __n } -> same_as<_Iter&>; + + { __iter + __n } -> same_as<_Iter>; + { __n + __iter } -> same_as<_Iter>; + { std::as_const(__iter) + __n } -> same_as<_Iter>; + { __n + std::as_const(__iter) } -> same_as<_Iter>; + + { __iter -= __n } -> same_as<_Iter&>; + { __iter - __n } -> same_as<_Iter>; + { std::as_const(__iter) - __n } -> same_as<_Iter>; + + { __iter - __iter } -> same_as<__iter_diff_t<_Iter>>; + { std::as_const(__iter) - __iter } -> same_as<__iter_diff_t<_Iter>>; + { __iter - std::as_const(__iter) } -> same_as<__iter_diff_t<_Iter>>; + { std::as_const(__iter) - std::as_const(__iter) } -> same_as<__iter_diff_t<_Iter>>; + + { __iter[__n] } -> convertible_to<__iter_reference<_Iter>>; + { std::as_const(__iter)[__n] } -> convertible_to<__iter_reference<_Iter>>; + + { __iter < __iter } -> __boolean_testable; + { std::as_const(__iter) < __iter } -> __boolean_testable; + { __iter < std::as_const(__iter) } -> __boolean_testable; + { std::as_const(__iter) < std::as_const(__iter) } -> __boolean_testable; + + { __iter > __iter } -> __boolean_testable; + { std::as_const(__iter) > __iter } -> __boolean_testable; + { __iter > std::as_const(__iter) } -> __boolean_testable; + { std::as_const(__iter) > std::as_const(__iter) } -> __boolean_testable; + + { __iter >= __iter } -> __boolean_testable; + { std::as_const(__iter) >= __iter } -> __boolean_testable; + { __iter >= std::as_const(__iter) } -> __boolean_testable; + { std::as_const(__iter) >= std::as_const(__iter) } -> __boolean_testable; + + { __iter <= __iter } -> __boolean_testable; + { std::as_const(__iter) <= __iter } -> __boolean_testable; + { __iter <= std::as_const(__iter) } -> __boolean_testable; + { std::as_const(__iter) <= std::as_const(__iter) } -> __boolean_testable; + }; + +_LIBCPP_END_NAMESPACE_STD + +# ifndef _LIBCPP_DISABLE_ITERATOR_CHECKS +# define _LIBCPP_REQUIRE_CPP17_INPUT_ITERATOR(iter_t) static_assert(::std::__cpp17_input_iterator); +# define _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR(iter_t, write_t) \ + static_assert(::std::__cpp17_output_iterator); +# define _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(iter_t) static_assert(::std::__cpp17_forward_iterator); +# define _LIBCPP_REQUIRE_CPP17_BIDIRECTIONAL_ITERATOR(iter_t) \ + static_assert(::std::__cpp17_bidirectional_iterator); +# define _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(iter_t) \ + static_assert(::std::__cpp17_random_access_iterator); +# else +# define _LIBCPP_REQUIRE_CPP17_INPUT_ITERATOR(iter_t) +# define _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR(iter_t) +# define _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(iter_t) +# define _LIBCPP_REQUIRE_CPP17_BIDIRECTIONAL_ITERATOR(iter_t) +# define _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(iter_t) +# endif + +#else // _LIBCPP_STD_VER >= 20 + +# define _LIBCPP_REQUIRE_CPP17_INPUT_ITERATOR(iter_t) +# define _LIBCPP_REQUIRE_CPP17_OUTPUT_ITERATOR(iter_t) +# define _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(iter_t) +# define _LIBCPP_REQUIRE_CPP17_BIDIRECTIONAL_ITERATOR(iter_t) +# define _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(iter_t) + +#endif // _LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___ITERATOR_CPP17_ITERATOR_CONCEPTS_H diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1076,11 +1076,12 @@ export * module __iterator { - module access { private header "__iterator/access.h" } - module advance { private header "__iterator/advance.h" } - module back_insert_iterator { private header "__iterator/back_insert_iterator.h" } - module bounded_iter { private header "__iterator/bounded_iter.h" } - module common_iterator { private header "__iterator/common_iterator.h" } + module access { private header "__iterator/access.h" } + module advance { private header "__iterator/advance.h" } + module back_insert_iterator { private header "__iterator/back_insert_iterator.h" } + module bounded_iter { private header "__iterator/bounded_iter.h" } + module common_iterator { private header "__iterator/common_iterator.h" } + module cpp17_iterator_concepts { private header "__iterator/cpp17_iterator_concepts.h" } module concepts { private header "__iterator/concepts.h" export concepts.equality_comparable diff --git a/libcxx/test/libcxx/algorithms/cpp17_iterator_concepts.verify.cpp b/libcxx/test/libcxx/algorithms/cpp17_iterator_concepts.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/algorithms/cpp17_iterator_concepts.verify.cpp @@ -0,0 +1,419 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// Check that __cpp17_*_iterator catch bad iterators + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// ADDITIONAL_COMPILE_FLAGS: -Wno-private-header + +#include +#include <__iterator/cpp17_iterator_concepts.h> +#include + +struct missing_deref { + using difference_type = std::ptrdiff_t; + using iterator_category = std::input_iterator_tag; + using value_type = int; + using reference = int&; + + missing_deref& operator++(); +}; + +struct missing_preincrement { + using difference_type = std::ptrdiff_t; + using iterator_category = std::input_iterator_tag; + using value_type = int; + using reference = int&; + + int& operator*(); +}; + +template +struct valid_iterator { + using difference_type = std::ptrdiff_t; + using iterator_category = std::input_iterator_tag; + using value_type = int; + using reference = int&; + + int& operator*() const; + Derived& operator++(); + + struct Proxy { + int operator*(); + }; + + Proxy operator++(int); +}; + +struct not_move_constructible : valid_iterator { + not_move_constructible(const not_move_constructible&) = default; + not_move_constructible(not_move_constructible&&) = delete; + not_move_constructible& operator=(not_move_constructible&&) = default; + not_move_constructible& operator=(const not_move_constructible&) = default; +}; + +struct not_copy_constructible : valid_iterator { + not_copy_constructible(const not_copy_constructible&) = delete; + not_copy_constructible(not_copy_constructible&&) = default; + not_copy_constructible& operator=(not_copy_constructible&&) = default; + not_copy_constructible& operator=(const not_copy_constructible&) = default; +}; + +struct not_move_assignable : valid_iterator { + not_move_assignable(const not_move_assignable&) = default; + not_move_assignable(not_move_assignable&&) = default; + not_move_assignable& operator=(not_move_assignable&&) = delete; + not_move_assignable& operator=(const not_move_assignable&) = default; +}; + +struct not_copy_assignable : valid_iterator { + not_copy_assignable(const not_copy_assignable&) = default; + not_copy_assignable(not_copy_assignable&&) = default; + not_copy_assignable& operator=(not_copy_assignable&&) = default; + not_copy_assignable& operator=(const not_copy_assignable&) = delete; +}; + +struct diff_t_not_signed : valid_iterator { + using difference_type = unsigned; +}; + +void check_iterator_requirements() { + static_assert(std::__cpp17_iterator); // expected-error {{static assertion failed}} + // expected-note@*:* {{indirection requires pointer operand}} + + static_assert(std::__cpp17_iterator); // expected-error {{static assertion failed}} + // expected-note@*:* {{cannot increment value of type 'missing_preincrement'}} + + + static_assert(std::__cpp17_iterator); // expected-error {{static assertion failed}} + // expected-note@*:* {{because 'not_move_constructible' does not satisfy '__cpp17_move_constructible'}} + + static_assert(std::__cpp17_iterator); // expected-error {{static assertion failed}} + // expected-note@*:* {{because 'not_copy_constructible' does not satisfy '__cpp17_copy_constructible'}} + + static_assert(std::__cpp17_iterator); // expected-error {{static assertion failed}} + // expected-note@*:* {{because 'not_move_assignable' does not satisfy '__cpp17_copy_assignable'}} + + static_assert(std::__cpp17_iterator); // expected-error {{static assertion failed}} + // expectted-note@*:* {{because 'not_copy_assignable' does not satisfy '__cpp17_copy_assignable'}} + + static_assert(std::__cpp17_iterator); // expected-error {{static assertion failed}} + // expectted-note@*:* {{'is_signed_v<__iter_diff_t >' evaluated to false}} +} + +struct not_equality_comparable : valid_iterator {}; +bool operator==(not_equality_comparable, not_equality_comparable) = delete; +bool operator!=(not_equality_comparable, not_equality_comparable); + +struct not_unequality_comparable : valid_iterator {}; +bool operator==(not_unequality_comparable, not_unequality_comparable); +bool operator!=(not_unequality_comparable, not_unequality_comparable) = delete; + +void check_input_iterator_requirements() { + _LIBCPP_REQUIRE_CPP17_INPUT_ITERATOR(not_equality_comparable); // expected-error {{static assertion failed}} + // expected-note@*:* {{'__lhs == __rhs' would be invalid: overload resolution selected deleted operator '=='}} + + _LIBCPP_REQUIRE_CPP17_INPUT_ITERATOR(not_unequality_comparable); // expected-error {{static assertion failed}} + // expected-note@*:* {{'__lhs != __rhs' would be invalid: overload resolution selected deleted operator '!='}} +} + +template +struct valid_forward_iterator : valid_iterator { + Derived& operator++(); + Derived operator++(int); + + friend bool operator==(Derived, Derived); +}; + +struct not_default_constructible : valid_forward_iterator { + not_default_constructible() = delete; +}; + +struct postincrement_not_ref : valid_iterator {}; +bool operator==(postincrement_not_ref, postincrement_not_ref); + +void check_forward_iterator_requirements() { + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(not_default_constructible); // expected-error {{static assertion failed}} + // expected-note@*:* {{because 'not_default_constructible' does not satisfy '__cpp17_default_constructible'}} + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(postincrement_not_ref); // expected-error {{static assertion failed}} + // expected-note@*:* {{because type constraint 'convertible_to::Proxy, const postincrement_not_ref &>' was not satisfied}} +} + +struct missing_predecrement : valid_forward_iterator { + missing_deref operator--(int); +}; + +struct missing_postdecrement : valid_forward_iterator { + missing_postdecrement& operator--(); +}; + +struct not_returning_iter_reference : valid_forward_iterator { + + struct Proxy { + operator const not_returning_iter_reference&(); + + int operator*(); + }; + + not_returning_iter_reference& operator--(); + Proxy operator--(int); +}; + +void check_bidirectional_iterator_requirements() { + _LIBCPP_REQUIRE_CPP17_BIDIRECTIONAL_ITERATOR(missing_predecrement); // expected-error {{static assertion failed}} + // expected-note@*:* {{cannot decrement value of type 'missing_predecrement'}} + _LIBCPP_REQUIRE_CPP17_BIDIRECTIONAL_ITERATOR(missing_postdecrement); // expected-error {{static assertion failed}} + // expected-note@*:* {{cannot decrement value of type 'missing_postdecrement'}} + _LIBCPP_REQUIRE_CPP17_BIDIRECTIONAL_ITERATOR(not_returning_iter_reference); // expected-error {{static assertion failed}} + // expected-note@*:* {{because type constraint 'same_as >' was not satisfied}} +} + +template +struct valid_random_access_iterator : valid_forward_iterator { + using Base = valid_forward_iterator; + + Derived& operator--(); + Derived operator--(int); + + Derived& operator+=(Base::difference_type); + Derived& operator-=(Base::difference_type); + + friend Derived operator+(valid_random_access_iterator, Base::difference_type); + friend Derived operator+(Base::difference_type, valid_random_access_iterator); + friend Derived operator-(valid_random_access_iterator, Base::difference_type); + friend Derived operator-(Base::difference_type, valid_random_access_iterator); + friend Base::difference_type operator-(valid_random_access_iterator, valid_random_access_iterator); + + int& operator[](Base::difference_type) const; + + friend std::strong_ordering operator<=>(Derived, Derived); +}; + +struct missing_plus_equals : valid_random_access_iterator { + void operator+=(difference_type) = delete; +}; + +struct missing_minus_equals : valid_random_access_iterator { + void operator-=(difference_type) = delete; +}; + +struct missing_plus_iter_diff : valid_random_access_iterator { + void operator+(difference_type) = delete; +}; + +struct missing_plus_diff_iter : valid_random_access_iterator { + friend missing_plus_diff_iter operator+(difference_type, missing_plus_diff_iter) = delete; +}; + +struct missing_plus_iter_diff_const_mut : valid_random_access_iterator { + friend missing_plus_iter_diff_const_mut operator+(missing_plus_iter_diff_const_mut&, difference_type); + friend missing_plus_iter_diff_const_mut operator+(const missing_plus_iter_diff_const_mut&, difference_type) = delete; +}; + +struct missing_plus_iter_diff_mut_const : valid_random_access_iterator { + friend missing_plus_iter_diff_mut_const operator+(missing_plus_iter_diff_mut_const, difference_type); + friend missing_plus_iter_diff_mut_const operator+(difference_type, missing_plus_iter_diff_mut_const&); + friend missing_plus_iter_diff_mut_const operator+(difference_type, const missing_plus_iter_diff_mut_const&) = delete; +}; + +struct missing_minus_iter_diff_const : valid_random_access_iterator { + friend missing_minus_iter_diff_const operator-(missing_minus_iter_diff_const&, difference_type); + friend missing_minus_iter_diff_const operator-(const missing_minus_iter_diff_const&, difference_type) = delete; +}; + +struct missing_minus_iter_iter : valid_random_access_iterator { + friend missing_minus_iter_iter operator-(missing_minus_iter_iter, missing_minus_iter_iter) = delete; +}; + +struct missing_minus_const_iter_iter : valid_random_access_iterator { + friend difference_type operator-(missing_minus_const_iter_iter&, missing_minus_const_iter_iter); + friend difference_type operator-(const missing_minus_const_iter_iter&, missing_minus_const_iter_iter) = delete; +}; + +struct missing_minus_iter_const_iter : valid_random_access_iterator { + friend difference_type operator-(missing_minus_iter_const_iter, missing_minus_iter_const_iter&); + friend difference_type operator-(missing_minus_iter_const_iter, const missing_minus_iter_const_iter&) = delete; +}; + +struct missing_minus_const_iter_const_iter : valid_random_access_iterator { + friend difference_type operator-(missing_minus_const_iter_const_iter&, missing_minus_const_iter_const_iter&); + friend difference_type operator-(const missing_minus_const_iter_const_iter&, missing_minus_const_iter_const_iter&); + friend difference_type operator-(missing_minus_const_iter_const_iter&, const missing_minus_const_iter_const_iter&); + friend difference_type operator-(const missing_minus_const_iter_const_iter&, const missing_minus_const_iter_const_iter&) = delete; +}; + +struct missing_subscript_operator : valid_random_access_iterator { + int& operator[](difference_type) = delete; +}; + +struct missing_const_subscript_operator : valid_random_access_iterator { + int& operator[](difference_type); + int& operator[](difference_type) const = delete; +}; + +struct missing_less : valid_random_access_iterator { + friend bool operator<(missing_less, missing_less) = delete; +}; + +struct missing_const_mut_less : valid_random_access_iterator { + friend bool operator<(missing_const_mut_less&, missing_const_mut_less&); + friend bool operator<(missing_const_mut_less&, const missing_const_mut_less&); + friend bool operator<(const missing_const_mut_less&, missing_const_mut_less&) = delete; + friend bool operator<(const missing_const_mut_less&, const missing_const_mut_less&); +}; + +struct missing_mut_const_less : valid_random_access_iterator { + friend bool operator<(missing_mut_const_less&, missing_mut_const_less&); + friend bool operator<(missing_mut_const_less&, const missing_mut_const_less&) = delete; + friend bool operator<(const missing_mut_const_less&, missing_mut_const_less&); + friend bool operator<(const missing_mut_const_less&, const missing_mut_const_less&); +}; + +struct missing_const_const_less : valid_random_access_iterator { + friend bool operator<(missing_const_const_less&, missing_const_const_less&); + friend bool operator<(missing_const_const_less&, const missing_const_const_less&); + friend bool operator<(const missing_const_const_less&, missing_const_const_less&); + friend bool operator<(const missing_const_const_less&, const missing_const_const_less&) = delete; +}; + +struct missing_greater : valid_random_access_iterator { + friend bool operator>(missing_greater, missing_greater) = delete; +}; + +struct missing_const_mut_greater : valid_random_access_iterator { + friend bool operator>(missing_const_mut_greater&, missing_const_mut_greater&); + friend bool operator>(missing_const_mut_greater&, const missing_const_mut_greater&); + friend bool operator>(const missing_const_mut_greater&, missing_const_mut_greater&) = delete; + friend bool operator>(const missing_const_mut_greater&, const missing_const_mut_greater&); +}; + +struct missing_mut_const_greater : valid_random_access_iterator { + friend bool operator>(missing_mut_const_greater&, missing_mut_const_greater&); + friend bool operator>(missing_mut_const_greater&, const missing_mut_const_greater&) = delete; + friend bool operator>(const missing_mut_const_greater&, missing_mut_const_greater&); + friend bool operator>(const missing_mut_const_greater&, const missing_mut_const_greater&); +}; + +struct missing_const_const_greater : valid_random_access_iterator { + friend bool operator>(missing_const_const_greater&, missing_const_const_greater&); + friend bool operator>(missing_const_const_greater&, const missing_const_const_greater&); + friend bool operator>(const missing_const_const_greater&, missing_const_const_greater&); + friend bool operator>(const missing_const_const_greater&, const missing_const_const_greater&) = delete; +}; + +struct missing_less_eq : valid_random_access_iterator { + friend bool operator<=(missing_less_eq, missing_less_eq) = delete; +}; + +struct missing_const_mut_less_eq : valid_random_access_iterator { + friend bool operator<=(missing_const_mut_less_eq&, missing_const_mut_less_eq&); + friend bool operator<=(missing_const_mut_less_eq&, const missing_const_mut_less_eq&); + friend bool operator<=(const missing_const_mut_less_eq&, missing_const_mut_less_eq&) = delete; + friend bool operator<=(const missing_const_mut_less_eq&, const missing_const_mut_less_eq&); +}; + +struct missing_mut_const_less_eq : valid_random_access_iterator { + friend bool operator<=(missing_mut_const_less_eq&, missing_mut_const_less_eq&); + friend bool operator<=(missing_mut_const_less_eq&, const missing_mut_const_less_eq&) = delete; + friend bool operator<=(const missing_mut_const_less_eq&, missing_mut_const_less_eq&); + friend bool operator<=(const missing_mut_const_less_eq&, const missing_mut_const_less_eq&); +}; + +struct missing_const_const_less_eq : valid_random_access_iterator { + friend bool operator<=(missing_const_const_less_eq&, missing_const_const_less_eq&); + friend bool operator<=(missing_const_const_less_eq&, const missing_const_const_less_eq&); + friend bool operator<=(const missing_const_const_less_eq&, missing_const_const_less_eq&); + friend bool operator<=(const missing_const_const_less_eq&, const missing_const_const_less_eq&) = delete; +}; + +struct missing_greater_eq : valid_random_access_iterator { + friend bool operator>=(missing_greater_eq, missing_greater_eq) = delete; +}; + +struct missing_const_mut_greater_eq : valid_random_access_iterator { + friend bool operator>=(missing_const_mut_greater_eq&, missing_const_mut_greater_eq&); + friend bool operator>=(missing_const_mut_greater_eq&, const missing_const_mut_greater_eq&); + friend bool operator>=(const missing_const_mut_greater_eq&, missing_const_mut_greater_eq&) = delete; + friend bool operator>=(const missing_const_mut_greater_eq&, const missing_const_mut_greater_eq&); +}; + +struct missing_mut_const_greater_eq : valid_random_access_iterator { + friend bool operator>=(missing_mut_const_greater_eq&, missing_mut_const_greater_eq&); + friend bool operator>=(missing_mut_const_greater_eq&, const missing_mut_const_greater_eq&) = delete; + friend bool operator>=(const missing_mut_const_greater_eq&, missing_mut_const_greater_eq&); + friend bool operator>=(const missing_mut_const_greater_eq&, const missing_mut_const_greater_eq&); +}; + +struct missing_const_const_greater_eq : valid_random_access_iterator { + friend bool operator>=(missing_const_const_greater_eq&, missing_const_const_greater_eq&); + friend bool operator>=(missing_const_const_greater_eq&, const missing_const_const_greater_eq&); + friend bool operator>=(const missing_const_const_greater_eq&, missing_const_const_greater_eq&); + friend bool operator>=(const missing_const_const_greater_eq&, const missing_const_const_greater_eq&) = delete; +}; + +void check_random_access_iterator() { + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_plus_equals); // expected-error {{static assertion failed}} + // expected-note@*:* {{because '__iter += __n' would be invalid: overload resolution selected deleted operator '+='}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_minus_equals); // expected-error {{static assertion failed}} + // expected-note@*:* {{because '__iter -= __n' would be invalid: overload resolution selected deleted operator '-='}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_plus_iter_diff); // expected-error {{static assertion failed}} + // expected-note@*:* {{because '__iter + __n' would be invalid: overload resolution selected deleted operator '+'}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_plus_diff_iter); // expected-error {{static assertion failed}} + // expected-note@*:* {{because '__n + __iter' would be invalid: overload resolution selected deleted operator '+'}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_plus_iter_diff_const_mut); // expected-error {{static assertion failed}} + // expected-note@*:* {{because 'std::as_const(__iter) + __n' would be invalid: overload resolution selected deleted operator '+'}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_plus_iter_diff_mut_const); // expected-error {{static assertion failed}} + // expected-note@*:* {{because '__n + std::as_const(__iter)' would be invalid: overload resolution selected deleted operator '+'}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_minus_iter_diff_const); // expected-error {{static assertion failed}} + // expected-note@*:* {{because 'std::as_const(__iter) - __n' would be invalid: overload resolution selected deleted operator '-'}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_minus_iter_iter); // expected-error {{static assertion failed}} + // expected-note@*:* {{because '__iter - __iter' would be invalid: overload resolution selected deleted operator '-'}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_minus_const_iter_iter); // expected-error {{static assertion failed}} + // expected-note@*:* {{because 'std::as_const(__iter) - __iter' would be invalid: overload resolution selected deleted operator '-'}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_minus_iter_const_iter); // expected-error {{static assertion failed}} + // expected-note@*:* {{because '__iter - std::as_const(__iter)' would be invalid: overload resolution selected deleted operator '-'}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_minus_const_iter_const_iter); // expected-error {{static assertion failed}} + // expected-note@*:* {{because 'std::as_const(__iter) - std::as_const(__iter)' would be invalid: overload resolution selected deleted operator '-'}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_subscript_operator); // expected-error {{static assertion failed}} + // expected-note@*:* {{because '__iter[__n]' would be invalid: overload resolution selected deleted operator '[]'}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_const_subscript_operator); // expected-error {{static assertion failed}} + // expected-note@*:* {{because 'std::as_const(__iter)[__n]' would be invalid: overload resolution selected deleted operator '[]'}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_less); // expected-error {{static assertion failed}} + // expected-note@*:* {{because '__iter < __iter' would be invalid: overload resolution selected deleted operator '<'}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_const_mut_less); // expected-error {{static assertion failed}} + // expected-note@*:* {{because 'std::as_const(__iter) < __iter' would be invalid: overload resolution selected deleted operator '<'}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_mut_const_less); // expected-error {{static assertion failed}} + // expected-note@*:* {{because '__iter < std::as_const(__iter)' would be invalid: overload resolution selected deleted operator '<'}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_const_const_less); // expected-error {{static assertion failed}} + // expected-note@*:* {{because 'std::as_const(__iter) < std::as_const(__iter)' would be invalid: overload resolution selected deleted operator '<'}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_greater); // expected-error {{static assertion failed}} + // expected-note@*:* {{because '__iter > __iter' would be invalid: overload resolution selected deleted operator '>'}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_const_mut_greater); // expected-error {{static assertion failed}} + // expected-note@*:* {{because 'std::as_const(__iter) > __iter' would be invalid: overload resolution selected deleted operator '>'}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_mut_const_greater); // expected-error {{static assertion failed}} + // expected-note@*:* {{because '__iter > std::as_const(__iter)' would be invalid: overload resolution selected deleted operator '>'}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_const_const_greater); // expected-error {{static assertion failed}} + // expected-note@*:* {{because 'std::as_const(__iter) > std::as_const(__iter)' would be invalid: overload resolution selected deleted operator '>'}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_less_eq); // expected-error {{static assertion failed}} + // expected-note@*:* {{because '__iter <= __iter' would be invalid: overload resolution selected deleted operator '<='}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_const_mut_less_eq); // expected-error {{static assertion failed}} + // expected-note@*:* {{because 'std::as_const(__iter) <= __iter' would be invalid: overload resolution selected deleted operator '<='}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_mut_const_less_eq); // expected-error {{static assertion failed}} + // expected-note@*:* {{because '__iter <= std::as_const(__iter)' would be invalid: overload resolution selected deleted operator '<='}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_const_const_less_eq); // expected-error {{static assertion failed}} + // expected-note@*:* {{because 'std::as_const(__iter) <= std::as_const(__iter)' would be invalid: overload resolution selected deleted operator '<='}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_greater_eq); // expected-error {{static assertion failed}} + // expected-note@*:* {{because '__iter >= __iter' would be invalid: overload resolution selected deleted operator '>='}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_const_mut_greater_eq); // expected-error {{static assertion failed}} + // expected-note@*:* {{because 'std::as_const(__iter) >= __iter' would be invalid: overload resolution selected deleted operator '>='}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_mut_const_greater_eq); // expected-error {{static assertion failed}} + // expected-note@*:* {{because '__iter >= std::as_const(__iter)' would be invalid: overload resolution selected deleted operator '>='}} + _LIBCPP_REQUIRE_CPP17_RANDOM_ACCESS_ITERATOR(missing_const_const_greater_eq); // expected-error {{static assertion failed}} + // expected-note@*:* {{because 'std::as_const(__iter) >= std::as_const(__iter)' would be invalid: overload resolution selected deleted operator '>='}} +}