diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -422,6 +422,7 @@ __iterator/advance.h __iterator/back_insert_iterator.h __iterator/bounded_iter.h + __iterator/cpp17_iterator_concepts.h __iterator/common_iterator.h __iterator/concepts.h __iterator/counted_iterator.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_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_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_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_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_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_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_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_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_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_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_FORWARD_ITERATOR(_ForwardIterator); + _LIBCPP_REQUIRE_FORWARD_ITERATOR(_ForwardOutIterator); + _LIBCPP_REQUIRE_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_FORWARD_ITERATOR(_ForwardIterator1); + _LIBCPP_REQUIRE_FORWARD_ITERATOR(_ForwardIterator2); + _LIBCPP_REQUIRE_FORWARD_ITERATOR(_ForwardOutIterator); + _LIBCPP_REQUIRE_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,182 @@ +//===----------------------------------------------------------------------===// +// +// 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_INPUT_ITERATOR(iter_t) static_assert(::std::__cpp17_input_iterator); +# define _LIBCPP_REQUIRE_OUTPUT_ITERATOR(iter_t, write_t) \ + static_assert(::std::__cpp17_output_iterator); +# define _LIBCPP_REQUIRE_FORWARD_ITERATOR(iter_t) static_assert(::std::__cpp17_forward_iterator); +# define _LIBCPP_REQUIRE_BIDIRECTIONAL_ITERATOR(iter_t) static_assert(::std::__cpp17_bidirectional_iterator); +# define _LIBCPP_REQUIRE_RANDOM_ACCESS_ITERATOR(iter_t) static_assert(::std::__cpp17_random_access_iterator); +# else +# define _LIBCPP_REQUIRE_INPUT_ITERATOR(iter_t) +# define _LIBCPP_REQUIRE_OUTPUT_ITERATOR(iter_t) +# define _LIBCPP_REQUIRE_FORWARD_ITERATOR(iter_t) +# define _LIBCPP_REQUIRE_BIDIRECTIONAL_ITERATOR(iter_t) +# define _LIBCPP_REQUIRE_RANDOM_ACCESS_ITERATOR(iter_t) +# endif + +#else // _LIBCPP_STD_VER >= 20 + +# define _LIBCPP_REQUIRE_INPUT_ITERATOR(iter_t) +# define _LIBCPP_REQUIRE_OUTPUT_ITERATOR(iter_t) +# define _LIBCPP_REQUIRE_FORWARD_ITERATOR(iter_t) +# define _LIBCPP_REQUIRE_BIDIRECTIONAL_ITERATOR(iter_t) +# define _LIBCPP_REQUIRE_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 @@ -1073,6 +1073,7 @@ export concepts.equality_comparable export type_traits.common_reference } + module check_iterators { private header "__iterator/check_iterators.h" } module counted_iterator { private header "__iterator/counted_iterator.h" } module data { private header "__iterator/data.h" } module default_sentinel { private header "__iterator/default_sentinel.h" } 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,128 @@ +//===----------------------------------------------------------------------===// +// +// 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 __check_*_iterator_requirements catch bad iterators + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// ADDITIONAL_COMPILE_FLAGS: -Wno-private-header + +#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++(); + Derived 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); + +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() { + static_assert(std::__cpp17_input_iterator); // expected-error {{static assertion failed}} + // expected-note@*:* {{'__lhs == __rhs' would be invalid: invalid operands to binary expression}} + + static_assert(std::__cpp17_input_iterator); // expected-error {{static assertion failed}} + // expected-note@*:* {{'__lhs != __rhs' would be invalid: overload resolution selected deleted operator '!='}} +} + +struct not_default_constructible : valid_iterator { + not_default_constructible() = delete; +}; +bool operator==(not_default_constructible, not_default_constructible); +bool operator!=(not_default_constructible, not_default_constructible); + +void check_forward_iterator_requirements() { + static_assert(std::__cpp17_forward_iterator); // expected-error {{static assertion failed}} + // expected-note@*:* {{because 'not_default_constructible' does not satisfy '__cpp17_default_constructible'}} +} diff --git a/libcxx/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp --- a/libcxx/test/libcxx/private_headers.verify.cpp +++ b/libcxx/test/libcxx/private_headers.verify.cpp @@ -458,6 +458,7 @@ #include <__iterator/common_iterator.h> // expected-error@*:* {{use of private header from outside its module: '__iterator/common_iterator.h'}} #include <__iterator/concepts.h> // expected-error@*:* {{use of private header from outside its module: '__iterator/concepts.h'}} #include <__iterator/counted_iterator.h> // expected-error@*:* {{use of private header from outside its module: '__iterator/counted_iterator.h'}} +#include <__iterator/cpp17_iterator_concepts.h> // expected-error@*:* {{use of private header from outside its module: '__iterator/cpp17_iterator_concepts.h'}} #include <__iterator/data.h> // expected-error@*:* {{use of private header from outside its module: '__iterator/data.h'}} #include <__iterator/default_sentinel.h> // expected-error@*:* {{use of private header from outside its module: '__iterator/default_sentinel.h'}} #include <__iterator/distance.h> // expected-error@*:* {{use of private header from outside its module: '__iterator/distance.h'}}