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 @@ -699,6 +700,7 @@ __type_traits/conjunction.h __type_traits/copy_cv.h __type_traits/copy_cvref.h + __type_traits/datasizeof.h __type_traits/decay.h __type_traits/dependent_type.h __type_traits/disjunction.h diff --git a/libcxx/include/__algorithm/copy_move_common.h b/libcxx/include/__algorithm/copy_move_common.h --- a/libcxx/include/__algorithm/copy_move_common.h +++ b/libcxx/include/__algorithm/copy_move_common.h @@ -15,6 +15,7 @@ #include <__config> #include <__iterator/iterator_traits.h> #include <__memory/pointer_traits.h> +#include <__string/constexpr_c_functions.h> #include <__type_traits/enable_if.h> #include <__type_traits/is_always_bitcastable.h> #include <__type_traits/is_constant_evaluated.h> @@ -61,7 +62,8 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*> __copy_trivial_impl(_In* __first, _In* __last, _Out* __result) { const size_t __n = static_cast(__last - __first); - ::__builtin_memmove(__result, __first, __n * sizeof(_Out)); + + std::__constexpr_memmove(__result, __first, __element_count(__n)); return std::make_pair(__last, __result + __n); } @@ -72,7 +74,7 @@ const size_t __n = static_cast(__last - __first); __result -= __n; - ::__builtin_memmove(__result, __first, __n * sizeof(_Out)); + std::__constexpr_memmove(__result, __first, __element_count(__n)); return std::make_pair(__last, __result); } @@ -119,16 +121,6 @@ return _Algorithm()(std::move(__first), std::move(__last), std::move(__out_first)); } -template -struct __can_copy_without_conversion : false_type {}; - -template -struct __can_copy_without_conversion< - _IterOps, - _InValue, - _OutIter, - __enable_if_t >::value> > : true_type {}; - template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 pair<_InIter, _OutIter> __dispatch_copy_or_move(_InIter __first, _Sent __last, _OutIter __out_first) { -#ifdef _LIBCPP_COMPILER_GCC - // GCC doesn't support `__builtin_memmove` during constant evaluation. - if (__libcpp_is_constant_evaluated()) { - return std::__unwrap_and_dispatch<_NaiveAlgorithm>(std::move(__first), std::move(__last), std::move(__out_first)); - } -#else - // In Clang, `__builtin_memmove` only supports fully trivially copyable types (just having trivial copy assignment is - // insufficient). Also, conversions are not supported. - if (__libcpp_is_constant_evaluated()) { - using _InValue = typename _IterOps<_AlgPolicy>::template __value_type<_InIter>; - if (!is_trivially_copyable<_InValue>::value || - !__can_copy_without_conversion<_IterOps<_AlgPolicy>, _InValue, _OutIter>::value) { - return std::__unwrap_and_dispatch<_NaiveAlgorithm>(std::move(__first), std::move(__last), std::move(__out_first)); - } - } -#endif // _LIBCPP_COMPILER_GCC - using _Algorithm = __overload<_NaiveAlgorithm, _OptimizedAlgorithm>; return std::__unwrap_and_dispatch<_Algorithm>(std::move(__first), std::move(__last), std::move(__out_first)); } 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,185 @@ +//===----------------------------------------------------------------------===// +// +// 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&>; + { __lhs = std::as_const(__rhs) } -> same_as<_Tp&>; +}; + +template +concept __cpp17_destructible = requires(_Tp __v) { __v.~_Tp(); }; + +template +concept __cpp17_equality_comparable = requires(_Tp __lhs, _Tp __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, write_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, write_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/__string/char_traits.h b/libcxx/include/__string/char_traits.h --- a/libcxx/include/__string/char_traits.h +++ b/libcxx/include/__string/char_traits.h @@ -170,25 +170,6 @@ {return int_type(EOF);} }; -template -_LIBCPP_HIDE_FROM_ABI static inline _LIBCPP_CONSTEXPR_SINCE_CXX20 -_CharT* __char_traits_move(_CharT* __dest, const _CharT* __source, size_t __n) _NOEXCEPT -{ -#ifdef _LIBCPP_COMPILER_GCC - if (__libcpp_is_constant_evaluated()) { - if (__n == 0) - return __dest; - _CharT* __allocation = new _CharT[__n]; - std::copy_n(__source, __n, __allocation); - std::copy_n(static_cast(__allocation), __n, __dest); - delete[] __allocation; - return __dest; - } -#endif - ::__builtin_memmove(__dest, __source, __n * sizeof(_CharT)); - return __dest; -} - // char_traits template <> @@ -249,7 +230,7 @@ static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type* move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT { - return std::__char_traits_move(__s1, __s2, __n); + return std::__constexpr_memmove(__s1, __s2, __element_count(__n)); } static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 @@ -320,7 +301,7 @@ static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type* move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT { - return std::__char_traits_move(__s1, __s2, __n); + return std::__constexpr_memmove(__s1, __s2, __element_count(__n)); } static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 @@ -384,7 +365,7 @@ static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 char_type* move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT { - return std::__char_traits_move(__s1, __s2, __n); + return std::__constexpr_memmove(__s1, __s2, __element_count(__n)); } static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 @@ -468,7 +449,7 @@ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 static char_type* move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT { - return std::__char_traits_move(__s1, __s2, __n); + return std::__constexpr_memmove(__s1, __s2, __element_count(__n)); } _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 @@ -562,7 +543,7 @@ _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 static char_type* move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT { - return std::__char_traits_move(__s1, __s2, __n); + return std::__constexpr_memmove(__s1, __s2, __element_count(__n)); } _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 diff --git a/libcxx/include/__string/constexpr_c_functions.h b/libcxx/include/__string/constexpr_c_functions.h --- a/libcxx/include/__string/constexpr_c_functions.h +++ b/libcxx/include/__string/constexpr_c_functions.h @@ -10,11 +10,15 @@ #define _LIBCPP___STRING_CONSTEXPR_C_FUNCTIONS_H #include <__config> +#include <__type_traits/datasizeof.h> +#include <__type_traits/is_always_bitcastable.h> #include <__type_traits/is_constant_evaluated.h> #include <__type_traits/is_equality_comparable.h> #include <__type_traits/is_same.h> +#include <__type_traits/is_trivially_copyable.h> #include <__type_traits/is_trivially_lexicographically_comparable.h> #include <__type_traits/remove_cv.h> +#include <__utility/is_pointer_in_range.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -129,6 +133,30 @@ } } +template ::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp* +__constexpr_memmove(_Tp* __dest, _Up* __src, __element_count __n) { + size_t __count = static_cast(__n); + if (__libcpp_is_constant_evaluated()) { +#ifdef _LIBCPP_COMPILER_CLANG_BASED + if (is_same<__remove_cv_t<_Tp>, __remove_cv_t<_Up> >::value) { + ::__builtin_memmove(__dest, __src, __count * sizeof(_Tp)); + return __dest; + } +#endif + if (std::__is_pointer_in_range(__src, __src + __count, __dest)) { + for (; __count > 0; --__count) + __dest[__count - 1] = __src[__count - 1]; + } else { + for (size_t __i = 0; __i != __count; ++__i) + __dest[__i] = __src[__i]; + } + } else if (__count > 0) { + ::__builtin_memmove(__dest, __src, (__count - 1) * sizeof(_Tp) + __libcpp_datasizeof<_Tp>::value); + } + return __dest; +} + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___STRING_CONSTEXPR_C_FUNCTIONS_H diff --git a/libcxx/include/__type_traits/datasizeof.h b/libcxx/include/__type_traits/datasizeof.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__type_traits/datasizeof.h @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// 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___TYPE_TRAITS_DATASIZEOF_H +#define _LIBCPP___TYPE_TRAITS_DATASIZEOF_H + +#include <__config> +#include <__type_traits/is_class.h> +#include <__type_traits/is_final.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +// This trait provides the size of a type excluding any tail padding. +// +// It is useful in contexts where performing an operation using the full size of the class (including padding) may +// have unintended side effects, such as overwriting a derived class' member when writing the tail padding of a class +// through a pointer-to-base. + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct __libcpp_datasizeof { +#if __has_cpp_attribute(__no_unique_address__) + template + struct _FirstPaddingByte { + [[__no_unique_address__]] _Tp __v_; + char __first_padding_byte_; + }; +#else + template ::value || !is_class<_Tp>::value> + struct _FirstPaddingByte : _Tp { + char __first_padding_byte_; + }; + + template <> + struct _FirstPaddingByte { + _Tp __v_; + char __first_padding_byte_; + }; +#endif + + static const size_t value = offsetof(_FirstPaddingByte<>, __first_padding_byte_); +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___TYPE_TRAITS_DATASIZEOF_H diff --git a/libcxx/include/__utility/is_pointer_in_range.h b/libcxx/include/__utility/is_pointer_in_range.h --- a/libcxx/include/__utility/is_pointer_in_range.h +++ b/libcxx/include/__utility/is_pointer_in_range.h @@ -17,6 +17,7 @@ #include <__type_traits/is_constant_evaluated.h> #include <__type_traits/is_function.h> #include <__type_traits/is_member_pointer.h> +#include <__type_traits/is_trivially_lexicographically_comparable.h> #include <__type_traits/void_t.h> #include <__utility/declval.h> @@ -26,7 +27,14 @@ _LIBCPP_BEGIN_NAMESPACE_STD +template +struct __is_less_than_comparable : false_type {}; + template +struct __is_less_than_comparable<_Tp, _Up, __void_t() < std::declval<_Up>())> > : true_type { +}; + +template ::value, int> = 0> _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_SANITIZE("address") bool __is_pointer_in_range( const _Tp* __begin, const _Tp* __end, const _Up* __ptr) { static_assert(!is_function<_Tp>::value && !is_function<_Up>::value, @@ -47,6 +55,15 @@ return !__less<>()(__ptr, __begin) && __less<>()(__ptr, __end); } +template ::value, int> = 0> +_LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_SANITIZE("address") bool __is_pointer_in_range( + const _Tp* __begin, const _Tp* __end, const _Up* __ptr) { + if (__libcpp_is_constant_evaluated()) + return false; + + return reinterpret_cast(__begin) <= __ptr && __ptr < reinterpret_cast(__end); +} + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___UTILITY_IS_POINTER_IN_RANGE_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 @@ -1571,6 +1572,7 @@ module conjunction { private header "__type_traits/conjunction.h" } module copy_cv { private header "__type_traits/copy_cv.h" } module copy_cvref { private header "__type_traits/copy_cvref.h" } + module datasizeof { private header "__type_traits/datasizeof.h" } module decay { private header "__type_traits/decay.h" } module dependent_type { private header "__type_traits/dependent_type.h" } module disjunction { private header "__type_traits/disjunction.h" } diff --git a/libcxx/include/string b/libcxx/include/string --- a/libcxx/include/string +++ b/libcxx/include/string @@ -663,13 +663,6 @@ struct __uninitialized_size_tag {}; -template -struct __is_less_than_comparable : false_type {}; - -template -struct __is_less_than_comparable<_Tp, _Up, __void_t() < std::declval<_Up>())> > : true_type { -}; - template class basic_string { @@ -1952,25 +1945,11 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __invalidate_iterators_past(size_type); - template < - class _Tp, - __enable_if_t<__is_less_than_comparable*, const value_type*>::value, int> = 0> + template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __addr_in_range(const _Tp& __v) const { return std::__is_pointer_in_range(data(), data() + size() + 1, std::addressof(__v)); } - template < - class _Tp, - __enable_if_t*, const value_type*>::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __addr_in_range(const _Tp& __v) const { - if (__libcpp_is_constant_evaluated()) - return false; - - auto __t_ptr = reinterpret_cast(std::addressof(__v)); - return reinterpret_cast(data()) <= __t_ptr && - __t_ptr < reinterpret_cast(data() + size() + 1); - } - _LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI void __throw_length_error() const { std::__throw_length_error("basic_string"); 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,422 @@ +//===----------------------------------------------------------------------===// +// +// 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 <__iterator/cpp17_iterator_concepts.h> +#include <__iterator/iterator_traits.h> +#include +#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-re {{{{static assertion|static_assert}} failed}} + // expected-note@*:* {{indirection requires pointer operand}} + + static_assert(std::__cpp17_iterator); // expected-error-re {{{{static assertion|static_assert}} failed}} + // expected-note@*:* {{cannot increment value of type 'missing_preincrement'}} + + + static_assert(std::__cpp17_iterator); // expected-error-re {{{{static assertion|static_assert}} failed}} + // expected-note@*:* {{because 'not_move_constructible' does not satisfy '__cpp17_move_constructible'}} + + static_assert(std::__cpp17_iterator); // expected-error-re {{{{static assertion|static_assert}} failed}} + // expected-note@*:* {{because 'not_copy_constructible' does not satisfy '__cpp17_copy_constructible'}} + + static_assert(std::__cpp17_iterator); // expected-error-re {{{{static assertion|static_assert}} failed}} + // expected-note@*:* {{because 'not_move_assignable' does not satisfy '__cpp17_copy_assignable'}} + + static_assert(std::__cpp17_iterator); // expected-error-re {{{{static assertion|static_assert}} failed}} + // expectted-note@*:* {{because 'not_copy_assignable' does not satisfy '__cpp17_copy_assignable'}} + + static_assert(std::__cpp17_iterator); // expected-error-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} failed}} + // expected-note@*:* {{'__lhs == __rhs' would be invalid: overload resolution selected deleted operator '=='}} + + _LIBCPP_REQUIRE_CPP17_INPUT_ITERATOR(not_unequality_comparable); // expected-error-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} failed}} + // expected-note@*:* {{because 'not_default_constructible' does not satisfy '__cpp17_default_constructible'}} + _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(postincrement_not_ref); // expected-error-re {{{{static assertion|static_assert}} failed}} +#ifndef _AIX + // expected-note@*:* {{because type constraint 'convertible_to::Proxy, const postincrement_not_ref &>' was not satisfied}} +#endif +} + +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-re {{{{static assertion|static_assert}} failed}} + // expected-note@*:* {{cannot decrement value of type 'missing_predecrement'}} + _LIBCPP_REQUIRE_CPP17_BIDIRECTIONAL_ITERATOR(missing_postdecrement); // expected-error-re {{{{static assertion|static_assert}} failed}} + // expected-note@*:* {{cannot decrement value of type 'missing_postdecrement'}} + _LIBCPP_REQUIRE_CPP17_BIDIRECTIONAL_ITERATOR(not_returning_iter_reference); // expected-error-re {{{{static assertion|static_assert}} failed}} + // expected-note@*:* {{because type constraint 'same_as >' was not satisfied}} +} + +template +struct valid_random_access_iterator : valid_forward_iterator { + using difference_type = typename valid_forward_iterator::difference_type; + + Derived& operator--(); + Derived operator--(int); + + Derived& operator+=(difference_type); + Derived& operator-=(difference_type); + + friend Derived operator+(valid_random_access_iterator, difference_type); + friend Derived operator+(difference_type, valid_random_access_iterator); + friend Derived operator-(valid_random_access_iterator, difference_type); + friend Derived operator-(difference_type, valid_random_access_iterator); + friend difference_type operator-(valid_random_access_iterator, valid_random_access_iterator); + + int& operator[](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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} 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-re {{{{static assertion|static_assert}} failed}} + // expected-note@*:* {{because 'std::as_const(__iter) >= std::as_const(__iter)' would be invalid: overload resolution selected deleted operator '>='}} +} diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv --- a/libcxx/test/libcxx/transitive_includes/cxx03.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv @@ -42,6 +42,7 @@ array compare array concepts array cstddef +array cstdint array cstdlib array initializer_list array iterator @@ -506,6 +507,7 @@ map compare map concepts map cstddef +map cstdint map cstdlib map functional map initializer_list @@ -732,6 +734,7 @@ set compare set concepts set cstddef +set cstdint set cstdlib set functional set initializer_list diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv --- a/libcxx/test/libcxx/transitive_includes/cxx11.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv @@ -42,6 +42,7 @@ array compare array concepts array cstddef +array cstdint array cstdlib array initializer_list array iterator @@ -506,6 +507,7 @@ map compare map concepts map cstddef +map cstdint map cstdlib map functional map initializer_list @@ -733,6 +735,7 @@ set compare set concepts set cstddef +set cstdint set cstdlib set functional set initializer_list diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv --- a/libcxx/test/libcxx/transitive_includes/cxx14.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv @@ -42,6 +42,7 @@ array compare array concepts array cstddef +array cstdint array cstdlib array initializer_list array iterator @@ -508,6 +509,7 @@ map compare map concepts map cstddef +map cstdint map cstdlib map functional map initializer_list @@ -735,6 +737,7 @@ set compare set concepts set cstddef +set cstdint set cstdlib set functional set initializer_list diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv --- a/libcxx/test/libcxx/transitive_includes/cxx17.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv @@ -42,6 +42,7 @@ array compare array concepts array cstddef +array cstdint array cstdlib array initializer_list array iterator @@ -508,6 +509,7 @@ map compare map concepts map cstddef +map cstdint map cstdlib map functional map initializer_list @@ -735,6 +737,7 @@ set compare set concepts set cstddef +set cstdint set cstdlib set functional set initializer_list diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv --- a/libcxx/test/libcxx/transitive_includes/cxx20.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv @@ -41,6 +41,7 @@ array compare array concepts array cstddef +array cstdint array cstdlib array initializer_list array iterator @@ -514,6 +515,7 @@ map compare map concepts map cstddef +map cstdint map cstdlib map functional map initializer_list @@ -741,6 +743,7 @@ set compare set concepts set cstddef +set cstdint set cstdlib set functional set initializer_list diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv --- a/libcxx/test/libcxx/transitive_includes/cxx23.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv @@ -21,6 +21,7 @@ any version array compare array cstddef +array cstdint array initializer_list array limits array stdexcept @@ -347,6 +348,7 @@ locale version map compare map cstddef +map cstdint map initializer_list map limits map new @@ -500,6 +502,7 @@ semaphore version set compare set cstddef +set cstdint set initializer_list set limits set new diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv --- a/libcxx/test/libcxx/transitive_includes/cxx26.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv @@ -21,6 +21,7 @@ any version array compare array cstddef +array cstdint array initializer_list array limits array stdexcept @@ -347,6 +348,7 @@ locale version map compare map cstddef +map cstdint map initializer_list map limits map new @@ -500,6 +502,7 @@ semaphore version set compare set cstddef +set cstdint set initializer_list set limits set new diff --git a/libcxx/test/libcxx/type_traits/datasizeof.compile.pass.cpp b/libcxx/test/libcxx/type_traits/datasizeof.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/type_traits/datasizeof.compile.pass.cpp @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// ADDITIONAL_COMPILE_FLAGS: -Wno-private-header + +#include <__type_traits/datasizeof.h> +#include + +static_assert(std::__libcpp_datasizeof::value == 1, ""); +static_assert(std::__libcpp_datasizeof::value == 2, ""); +static_assert(std::__libcpp_datasizeof::value == 4, ""); +static_assert(std::__libcpp_datasizeof::value == 8, ""); + +struct OneBytePadding { + OneBytePadding() {} + + std::int16_t a; + std::int8_t b; +}; + +static_assert(std::__libcpp_datasizeof::value == 3, ""); + +struct InBetweenPadding { + InBetweenPadding() {} + + std::int32_t a; + std::int8_t b; + std::int16_t c; +}; + +static_assert(std::__libcpp_datasizeof::value == 8, ""); diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy.pass.cpp --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy.pass.cpp @@ -18,78 +18,76 @@ #include "test_macros.h" #include "test_iterators.h" -template -TEST_CONSTEXPR_CXX20 void -test_copy() -{ - const unsigned N = 1000; - int ia[N] = {}; - for (unsigned i = 0; i < N; ++i) +class PaddedBase { +public: + TEST_CONSTEXPR PaddedBase(std::int16_t a, std::int8_t b) : a_(a), b_(b) {} + + std::int16_t a_; + std::int8_t b_; +}; + +class Derived : public PaddedBase { +public: + TEST_CONSTEXPR Derived(std::int16_t a, std::int8_t b, std::int8_t c) : PaddedBase(a, b), c_(c) {} + + std::int8_t c_; +}; + +template +struct Test { + template + TEST_CONSTEXPR_CXX20 void operator()() { + { + const unsigned N = 1000; + int ia[N] = {}; + for (unsigned i = 0; i < N; ++i) ia[i] = i; - int ib[N] = {0}; + int ib[N] = {0}; - OutIter r = std::copy(InIter(ia), InIter(ia+N), OutIter(ib)); - assert(base(r) == ib+N); - for (unsigned i = 0; i < N; ++i) + OutIter r = std::copy(InIter(ia), InIter(ia + N), OutIter(ib)); + assert(base(r) == ib + N); + for (unsigned i = 0; i < N; ++i) assert(ia[i] == ib[i]); -} - -TEST_CONSTEXPR_CXX20 bool -test() -{ - test_copy, cpp17_output_iterator >(); - test_copy, forward_iterator >(); - test_copy, bidirectional_iterator >(); - test_copy, random_access_iterator >(); - test_copy, int*>(); - - test_copy, cpp17_output_iterator >(); - test_copy, forward_iterator >(); - test_copy, bidirectional_iterator >(); - test_copy, random_access_iterator >(); - test_copy, int*>(); - - test_copy, cpp17_output_iterator >(); - test_copy, forward_iterator >(); - test_copy, bidirectional_iterator >(); - test_copy, random_access_iterator >(); - test_copy, int*>(); - - test_copy, cpp17_output_iterator >(); - test_copy, forward_iterator >(); - test_copy, bidirectional_iterator >(); - test_copy, random_access_iterator >(); - test_copy, int*>(); - - test_copy >(); - test_copy >(); - test_copy >(); - test_copy >(); - test_copy(); - -#if TEST_STD_VER > 17 - test_copy, contiguous_iterator>(); - test_copy, contiguous_iterator>(); - test_copy, contiguous_iterator>(); - test_copy, contiguous_iterator>(); - test_copy>(); - - test_copy, cpp17_output_iterator>(); - test_copy, forward_iterator>(); - test_copy, bidirectional_iterator>(); - test_copy, random_access_iterator>(); - test_copy, int*>(); -#endif + } + + { // Make sure that padding bits aren't copied + Derived src(1, 2, 3); + Derived dst(4, 5, 6); + std::copy(static_cast(&src), static_cast(&src) + 1, static_cast(&dst)); + assert(dst.a_ == 1); + assert(dst.b_ == 2); + assert(dst.c_ == 6); + } + + { // Make sure that overlapping ranges can be copied + int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + std::copy(a + 3, a + 10, a); + int expected[] = {4, 5, 6, 7, 8, 9, 10, 8, 9, 10}; + assert(std::equal(a, a + 10, expected)); + } + } +}; + +struct TestInIters { + template + TEST_CONSTEXPR_CXX20 void operator()() { + types::for_each( + types::concatenate_t, types::type_list>>(), + Test()); + } +}; + +TEST_CONSTEXPR_CXX20 bool test() { + types::for_each(types::cpp17_input_iterator_list(), TestInIters()); return true; } -int main(int, char**) -{ - test(); +int main(int, char**) { + test(); #if TEST_STD_VER > 17 - static_assert(test()); + static_assert(test()); #endif return 0; diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_backward.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_backward.pass.cpp --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_backward.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_backward.pass.cpp @@ -20,10 +20,26 @@ #include "test_iterators.h" #include "user_defined_integral.h" +class PaddedBase { +public: + TEST_CONSTEXPR PaddedBase(std::int16_t a, std::int8_t b) : a_(a), b_(b) {} + + std::int16_t a_; + std::int8_t b_; +}; + +class Derived : public PaddedBase { +public: + TEST_CONSTEXPR Derived(std::int16_t a, std::int8_t b, std::int8_t c) : PaddedBase(a, b), c_(c) {} + + std::int8_t c_; +}; + template TEST_CONSTEXPR_CXX20 void test_copy_backward() { + { const unsigned N = 1000; int ia[N] = {}; for (unsigned i = 0; i < N; ++i) @@ -34,6 +50,24 @@ assert(base(r) == ib); for (unsigned i = 0; i < N; ++i) assert(ia[i] == ib[i]); + } + + { // Make sure that padding bits aren't copied + Derived src(1, 2, 3); + Derived dst(4, 5, 6); + std::copy_backward( + static_cast(&src), static_cast(&src) + 1, static_cast(&dst) + 1); + assert(dst.a_ == 1); + assert(dst.b_ == 2); + assert(dst.c_ == 6); + } + + { // Make sure that overlapping ranges can be copied + int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + std::copy_backward(a, a + 7, a + 10); + int expected[] = {1, 2, 3, 1, 2, 3, 4, 5, 6, 7}; + assert(std::equal(a, a + 10, expected)); + } } TEST_CONSTEXPR_CXX20 bool diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_n.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_n.pass.cpp --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_n.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_n.pass.cpp @@ -21,10 +21,26 @@ typedef UserDefinedIntegral UDI; +class PaddedBase { +public: + TEST_CONSTEXPR PaddedBase(std::int16_t a, std::int8_t b) : a_(a), b_(b) {} + + std::int16_t a_; + std::int8_t b_; +}; + +class Derived : public PaddedBase { +public: + TEST_CONSTEXPR Derived(std::int16_t a, std::int8_t b, std::int8_t c) : PaddedBase(a, b), c_(c) {} + + std::int8_t c_; +}; + template TEST_CONSTEXPR_CXX20 void test_copy_n() { + { const unsigned N = 1000; int ia[N] = {}; for (unsigned i = 0; i < N; ++i) @@ -35,6 +51,23 @@ assert(base(r) == ib+N/2); for (unsigned i = 0; i < N/2; ++i) assert(ia[i] == ib[i]); + } + + { // Make sure that padding bits aren't copied + Derived src(1, 2, 3); + Derived dst(4, 5, 6); + std::copy_n(static_cast(&src), 1, static_cast(&dst)); + assert(dst.a_ == 1); + assert(dst.b_ == 2); + assert(dst.c_ == 6); + } + + { // Make sure that overlapping ranges can be copied + int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + std::copy_n(a + 3, 7, a); + int expected[] = {4, 5, 6, 7, 8, 9, 10, 8, 9, 10}; + assert(std::equal(a, a + 10, expected)); + } } TEST_CONSTEXPR_CXX20 bool diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp @@ -6,6 +6,8 @@ // //===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03 && !stdlib=libc++ + // // template @@ -20,6 +22,21 @@ #include "test_macros.h" #include "test_iterators.h" +class PaddedBase { +public: + TEST_CONSTEXPR PaddedBase(std::int16_t a, std::int8_t b) : a_(a), b_(b) {} + + std::int16_t a_; + std::int8_t b_; +}; + +class Derived : public PaddedBase { +public: + TEST_CONSTEXPR Derived(std::int16_t a, std::int8_t b, std::int8_t c) : PaddedBase(a, b), c_(c) {} + + std::int8_t c_; +}; + template TEST_CONSTEXPR_CXX17 bool test() @@ -35,10 +52,17 @@ for (unsigned i = 0; i < N; ++i) assert(ia[i] == ib[i]); + // Make sure that padding bits aren't copied + Derived src(1, 2, 3); + Derived dst(4, 5, 6); + std::copy(static_cast(&src), static_cast(&src) + 1, static_cast(&dst)); + assert(dst.a_ == 1); + assert(dst.b_ == 2); + assert(dst.c_ == 6); + return true; } -#if TEST_STD_VER >= 11 template void test1() @@ -54,7 +78,6 @@ for (unsigned i = 0; i < N; ++i) assert(*ib[i] == static_cast(i)); } -#endif int main(int, char**) { @@ -88,7 +111,6 @@ test >(); test(); -#if TEST_STD_VER >= 11 test1*>, cpp17_output_iterator*> >(); test1*>, forward_iterator*> >(); test1*>, bidirectional_iterator*> >(); @@ -118,7 +140,6 @@ test1*, bidirectional_iterator*> >(); test1*, random_access_iterator*> >(); test1*, std::unique_ptr*>(); -#endif // TEST_STD_VER >= 11 #if TEST_STD_VER > 17 test, contiguous_iterator>(); diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move_backward.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move_backward.pass.cpp --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move_backward.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move_backward.pass.cpp @@ -20,6 +20,21 @@ #include "test_macros.h" #include "test_iterators.h" +class PaddedBase { +public: + TEST_CONSTEXPR PaddedBase(std::int16_t a, std::int8_t b) : a_(a), b_(b) {} + + std::int16_t a_; + std::int8_t b_; +}; + +class Derived : public PaddedBase { +public: + TEST_CONSTEXPR Derived(std::int16_t a, std::int8_t b, std::int8_t c) : PaddedBase(a, b), c_(c) {} + + std::int8_t c_; +}; + template TEST_CONSTEXPR_CXX17 bool test() @@ -122,5 +137,22 @@ static_assert(test()); #endif // TEST_STD_VER > 17 + { // Make sure that padding bits aren't copied + Derived src(1, 2, 3); + Derived dst(4, 5, 6); + std::move_backward( + static_cast(&src), static_cast(&src) + 1, static_cast(&dst) + 1); + assert(dst.a_ == 1); + assert(dst.b_ == 2); + assert(dst.c_ == 6); + } + + { // Make sure that overlapping ranges can be copied + int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + std::move_backward(a, a + 7, a + 10); + int expected[] = {1, 2, 3, 1, 2, 3, 4, 5, 6, 7}; + assert(std::equal(a, a + 10, expected)); + } + return 0; } diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/move.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/move.pass.cpp --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/move.pass.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/move.pass.cpp @@ -36,6 +36,21 @@ } }; +class PaddedBase { +public: + constexpr PaddedBase(std::int16_t a, std::int8_t b) : a_(a), b_(b) {} + + std::int16_t a_; + std::int8_t b_; +}; + +class Derived : public PaddedBase { +public: + constexpr Derived(std::int16_t a, std::int8_t b, std::int8_t c) : PaddedBase(a, b), c_(c) {} + + std::int8_t c_; +}; + // move_only type which triggers the empty base optimization struct move_only_ebo { move_only_ebo() = default; @@ -80,6 +95,22 @@ static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); } + + { // Make sure that padding bits aren't copied + Derived src(1, 2, 3); + Derived dst(4, 5, 6); + std::move(static_cast(&src), static_cast(&src) + 1, static_cast(&dst)); + assert(dst.a_ == 1); + assert(dst.b_ == 2); + assert(dst.c_ == 6); + } + + { // Make sure that overlapping ranges can be copied + int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + std::move(a + 3, a + 10, a); + int expected[] = {4, 5, 6, 7, 8, 9, 10, 8, 9, 10}; + assert(std::equal(a, a + 10, expected)); + } } int main(int, char**)