From 3ed89b51da38f081fedb57727076262abb81d149 Mon Sep 17 00:00:00 2001 From: zoecarver Date: Mon, 14 Sep 2020 18:11:08 -0400 Subject: [PATCH] [Take 2] [libc++] Make rotate a constexpr. This patch makes `std::rotate` a constexpr. In doing so, this patch also updates the internal `__move` and `__move_backward` funtions to be constexpr. This patch was previously reverted in ed653184ac63 because it was missing some UNSUPPORTED markup for older compilers. This commit adds it. Differential Revision: https://reviews.llvm.org/D65721 --- libcxx/include/algorithm | 68 +++++++++++++------ libcxx/include/iterator | 16 ++--- .../alg.move/move.pass.cpp | 43 +++++++++++- .../alg.move/move_backward.pass.cpp | 24 ++++++- .../alg.rotate/rotate.pass.cpp | 15 +++- .../alg.rotate/rotate_copy.pass.cpp | 4 ++ .../alg.sorting/alg.merge/merge.pass.cpp | 4 ++ .../alg.sorting/alg.merge/merge_comp.pass.cpp | 4 ++ libcxx/www/cxx2a_status.html | 3 +- 9 files changed, 145 insertions(+), 36 deletions(-) diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm index 8c8bc748606d..5d09b6c3c015 100644 --- a/libcxx/include/algorithm +++ b/libcxx/include/algorithm @@ -1631,7 +1631,7 @@ search_n(_ForwardIterator __first, _ForwardIterator __last, _Size __count, const // copy template -inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR _Iter __unwrap_iter(_Iter __i) { @@ -1639,7 +1639,7 @@ __unwrap_iter(_Iter __i) } template -inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR typename enable_if < is_trivially_copy_assignable<_Tp>::value, @@ -1653,7 +1653,7 @@ __unwrap_iter(move_iterator<_Tp*> __i) #if _LIBCPP_DEBUG_LEVEL < 2 template -inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR typename enable_if < is_trivially_copy_assignable<_Tp>::value, @@ -1665,7 +1665,7 @@ __unwrap_iter(__wrap_iter<_Tp*> __i) } template -inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR typename enable_if < is_trivially_copy_assignable<_Tp>::value, @@ -1679,7 +1679,7 @@ __unwrap_iter(__wrap_iter __i) #else template -inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR typename enable_if < is_trivially_copy_assignable<_Tp>::value, @@ -1859,18 +1859,28 @@ copy_n(_InputIterator __first, _Size __orig_n, _OutputIterator __result) // move +// __move_constexpr exists so that __move doesn't call itself when delegating to the constexpr +// version of __move. template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 _OutputIterator -__move(_InputIterator __first, _InputIterator __last, _OutputIterator __result) +__move_constexpr(_InputIterator __first, _InputIterator __last, _OutputIterator __result) { for (; __first != __last; ++__first, (void) ++__result) *__result = _VSTD::move(*__first); return __result; } +template +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 +_OutputIterator +__move(_InputIterator __first, _InputIterator __last, _OutputIterator __result) +{ + return __move_constexpr(__first, __last, __result); +} + template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 typename enable_if < is_same::type, _Up>::value && @@ -1879,6 +1889,8 @@ typename enable_if >::type __move(_Tp* __first, _Tp* __last, _Up* __result) { + if (__libcpp_is_constant_evaluated()) + return __move_constexpr(__first, __last, __result); const size_t __n = static_cast(__last - __first); if (__n > 0) _VSTD::memmove(__result, __first, __n * sizeof(_Up)); @@ -1886,7 +1898,7 @@ __move(_Tp* __first, _Tp* __last, _Up* __result) } template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 _OutputIterator move(_InputIterator __first, _InputIterator __last, _OutputIterator __result) { @@ -1895,18 +1907,28 @@ move(_InputIterator __first, _InputIterator __last, _OutputIterator __result) // move_backward +// __move_backward_constexpr exists so that __move_backward doesn't call itself when delegating to +// the constexpr version of __move_backward. template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 _OutputIterator -__move_backward(_InputIterator __first, _InputIterator __last, _OutputIterator __result) +__move_backward_constexpr(_InputIterator __first, _InputIterator __last, _OutputIterator __result) { while (__first != __last) *--__result = _VSTD::move(*--__last); return __result; } +template +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 +_OutputIterator +__move_backward(_InputIterator __first, _InputIterator __last, _OutputIterator __result) +{ + return __move_backward_constexpr(__first, __last, __result); +} + template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 typename enable_if < is_same::type, _Up>::value && @@ -1915,6 +1937,8 @@ typename enable_if >::type __move_backward(_Tp* __first, _Tp* __last, _Up* __result) { + if (__libcpp_is_constant_evaluated()) + return __move_backward_constexpr(__first, __last, __result); const size_t __n = static_cast(__last - __first); if (__n > 0) { @@ -1925,7 +1949,7 @@ __move_backward(_Tp* __first, _Tp* __last, _Up* __result) } template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 _BidirectionalIterator2 move_backward(_BidirectionalIterator1 __first, _BidirectionalIterator1 __last, _BidirectionalIterator2 __result) @@ -2333,7 +2357,7 @@ reverse_copy(_BidirectionalIterator __first, _BidirectionalIterator __last, _Out // rotate template -_ForwardIterator +_LIBCPP_CONSTEXPR_AFTER_CXX11 _ForwardIterator __rotate_left(_ForwardIterator __first, _ForwardIterator __last) { typedef typename iterator_traits<_ForwardIterator>::value_type value_type; @@ -2344,7 +2368,7 @@ __rotate_left(_ForwardIterator __first, _ForwardIterator __last) } template -_BidirectionalIterator +_LIBCPP_CONSTEXPR_AFTER_CXX11 _BidirectionalIterator __rotate_right(_BidirectionalIterator __first, _BidirectionalIterator __last) { typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type; @@ -2356,7 +2380,7 @@ __rotate_right(_BidirectionalIterator __first, _BidirectionalIterator __last) } template -_ForwardIterator +_LIBCPP_CONSTEXPR_AFTER_CXX14 _ForwardIterator __rotate_forward(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last) { _ForwardIterator __i = __middle; @@ -2392,7 +2416,7 @@ __rotate_forward(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIt template inline _LIBCPP_INLINE_VISIBILITY -_Integral +_LIBCPP_CONSTEXPR_AFTER_CXX14 _Integral __algo_gcd(_Integral __x, _Integral __y) { do @@ -2405,7 +2429,7 @@ __algo_gcd(_Integral __x, _Integral __y) } template -_RandomAccessIterator +_LIBCPP_CONSTEXPR_AFTER_CXX14 _RandomAccessIterator __rotate_gcd(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last) { typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; @@ -2441,7 +2465,7 @@ __rotate_gcd(_RandomAccessIterator __first, _RandomAccessIterator __middle, _Ran template inline _LIBCPP_INLINE_VISIBILITY -_ForwardIterator +_LIBCPP_CONSTEXPR_AFTER_CXX11 _ForwardIterator __rotate(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last, _VSTD::forward_iterator_tag) { @@ -2456,7 +2480,7 @@ __rotate(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator _ template inline _LIBCPP_INLINE_VISIBILITY -_BidirectionalIterator +_LIBCPP_CONSTEXPR_AFTER_CXX11 _BidirectionalIterator __rotate(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last, _VSTD::bidirectional_iterator_tag) { @@ -2473,7 +2497,7 @@ __rotate(_BidirectionalIterator __first, _BidirectionalIterator __middle, _Bidir template inline _LIBCPP_INLINE_VISIBILITY -_RandomAccessIterator +_LIBCPP_CONSTEXPR_AFTER_CXX11 _RandomAccessIterator __rotate(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last, _VSTD::random_access_iterator_tag) { @@ -2491,7 +2515,7 @@ __rotate(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomA template inline _LIBCPP_INLINE_VISIBILITY -_ForwardIterator +_LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator rotate(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last) { if (__first == __middle) diff --git a/libcxx/include/iterator b/libcxx/include/iterator index 36571a50b8bc..45516db24e7c 100644 --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -1393,13 +1393,13 @@ operator+(typename __wrap_iter<_Iter>::difference_type, __wrap_iter<_Iter>) _NOE template _Op _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 copy(_Ip, _Ip, _Op); template _B2 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 copy_backward(_B1, _B1, _B2); -template _Op _LIBCPP_INLINE_VISIBILITY move(_Ip, _Ip, _Op); -template _B2 _LIBCPP_INLINE_VISIBILITY move_backward(_B1, _B1, _B2); +template _Op _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 move(_Ip, _Ip, _Op); +template _B2 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 move_backward(_B1, _B1, _B2); #if _LIBCPP_DEBUG_LEVEL < 2 template -_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR typename enable_if < is_trivially_copy_assignable<_Tp>::value, @@ -1410,7 +1410,7 @@ __unwrap_iter(__wrap_iter<_Tp*>); #else template -inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR typename enable_if < is_trivially_copy_assignable<_Tp>::value, @@ -1604,12 +1604,12 @@ private: template friend _LIBCPP_CONSTEXPR_AFTER_CXX17 _Op copy(_Ip, _Ip, _Op); template friend _LIBCPP_CONSTEXPR_AFTER_CXX17 _B2 copy_backward(_B1, _B1, _B2); - template friend _Op move(_Ip, _Ip, _Op); - template friend _B2 move_backward(_B1, _B1, _B2); + template friend _LIBCPP_CONSTEXPR_AFTER_CXX17 _Op move(_Ip, _Ip, _Op); + template friend _LIBCPP_CONSTEXPR_AFTER_CXX17 _B2 move_backward(_B1, _B1, _B2); #if _LIBCPP_DEBUG_LEVEL < 2 template - _LIBCPP_CONSTEXPR_IF_NODEBUG friend + _LIBCPP_CONSTEXPR friend typename enable_if < is_trivially_copy_assignable<_Tp>::value, @@ -1618,7 +1618,7 @@ private: __unwrap_iter(__wrap_iter<_Tp*>); #else template - inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG + inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR typename enable_if < is_trivially_copy_assignable<_Tp>::value, 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 index cdb126d4942c..7e69c54797c8 100644 --- 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 @@ -13,6 +13,11 @@ // OutIter // move(InIter first, InIter last, OutIter result); +// Older compilers don't support std::is_constant_evaluated +// UNSUPPORTED: clang-4, clang-5, clang-6, clang-7, clang-8 +// UNSUPPORTED: apple-clang-9, apple-clang-10, apple-clang-11 +// UNSUPPORTED: gcc-5, gcc-6, gcc-7, gcc-8 + #include #include #include @@ -21,11 +26,11 @@ #include "test_iterators.h" template -void +_LIBCPP_CONSTEXPR_AFTER_CXX17 bool test() { const unsigned N = 1000; - int ia[N]; + int ia[N] = {}; for (unsigned i = 0; i < N; ++i) ia[i] = i; int ib[N] = {0}; @@ -34,6 +39,8 @@ test() assert(base(r) == ib+N); for (unsigned i = 0; i < N; ++i) assert(ia[i] == ib[i]); + + return true; } #if TEST_STD_VER >= 11 @@ -128,5 +135,37 @@ int main(int, char**) test1*, std::unique_ptr*>(); #endif // TEST_STD_VER >= 11 +#if TEST_STD_VER > 17 + static_assert(test, input_iterator >()); + static_assert(test, forward_iterator >()); + static_assert(test, bidirectional_iterator >()); + static_assert(test, random_access_iterator >()); + static_assert(test, int*>()); + + static_assert(test, input_iterator >()); + static_assert(test, forward_iterator >()); + static_assert(test, bidirectional_iterator >()); + static_assert(test, random_access_iterator >()); + static_assert(test, int*>()); + + static_assert(test, input_iterator >()); + static_assert(test, forward_iterator >()); + static_assert(test, bidirectional_iterator >()); + static_assert(test, random_access_iterator >()); + static_assert(test, int*>()); + + static_assert(test, input_iterator >()); + static_assert(test, forward_iterator >()); + static_assert(test, bidirectional_iterator >()); + static_assert(test, random_access_iterator >()); + static_assert(test, int*>()); + + static_assert(test >()); + static_assert(test >()); + static_assert(test >()); + static_assert(test >()); + static_assert(test()); +#endif // TEST_STD_VER > 17 + return 0; } 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 index 365c1a1158d7..5e1afe857cca 100644 --- 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 @@ -6,6 +6,10 @@ // //===----------------------------------------------------------------------===// +// Older compilers don't support std::is_constant_evaluated +// UNSUPPORTED: clang-4, clang-5, clang-6, clang-7, clang-8 +// UNSUPPORTED: apple-clang-9, apple-clang-10 + // // template @@ -21,11 +25,11 @@ #include "test_iterators.h" template -void +_LIBCPP_CONSTEXPR_AFTER_CXX17 bool test() { const unsigned N = 1000; - int ia[N]; + int ia[N] = {}; for (unsigned i = 0; i < N; ++i) ia[i] = i; int ib[N] = {0}; @@ -34,6 +38,8 @@ test() assert(base(r) == ib); for (unsigned i = 0; i < N; ++i) assert(ia[i] == ib[i]); + + return true; } #if TEST_STD_VER >= 11 @@ -82,5 +88,19 @@ int main(int, char**) test1*, std::unique_ptr*>(); #endif // TEST_STD_VER >= 11 +#if TEST_STD_VER > 17 + static_assert(test, bidirectional_iterator >()); + static_assert(test, random_access_iterator >()); + static_assert(test, int*>()); + + static_assert(test, bidirectional_iterator >()); + static_assert(test, random_access_iterator >()); + static_assert(test, int*>()); + + static_assert(test >()); + static_assert(test >()); + static_assert(test()); +#endif // TEST_STD_VER > 17 + return 0; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.rotate/rotate.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.rotate/rotate.pass.cpp index 007faf685bfc..2617f9a6a126 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.rotate/rotate.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.rotate/rotate.pass.cpp @@ -12,6 +12,10 @@ // Iter // rotate(Iter first, Iter middle, Iter last); +// Older compilers don't support std::is_constant_evaluated +// UNSUPPORTED: clang-4, clang-5, clang-6, clang-7, clang-8 +// UNSUPPORTED: apple-clang-9, apple-clang-10 + #include #include #include @@ -20,7 +24,7 @@ #include "test_iterators.h" template -void +_LIBCPP_CONSTEXPR_AFTER_CXX17 bool test() { int ia[] = {0}; @@ -209,6 +213,8 @@ test() assert(ig[3] == 0); assert(ig[4] == 1); assert(ig[5] == 2); + + return true; } #if TEST_STD_VER >= 11 @@ -435,5 +441,12 @@ int main(int, char**) #endif +#if TEST_STD_VER > 17 + static_assert(test >()); + static_assert(test >()); + static_assert(test >()); + static_assert(test()); +#endif // TEST_STD_VER > 17 + return 0; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.rotate/rotate_copy.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.rotate/rotate_copy.pass.cpp index 8acb1a129e38..d9dca0c6ebf0 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.rotate/rotate_copy.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.rotate/rotate_copy.pass.cpp @@ -12,6 +12,10 @@ // constexpr OutIter // constexpr after C++17 // rotate_copy(InIter first, InIter middle, InIter last, OutIter result); +// Older compilers don't support std::is_constant_evaluated +// UNSUPPORTED: clang-4, clang-5, clang-6, clang-7, clang-8 +// UNSUPPORTED: apple-clang-9, apple-clang-10 + #include #include diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.merge/merge.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.merge/merge.pass.cpp index 167da9aa2ddd..8730ecdbd572 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.merge/merge.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.merge/merge.pass.cpp @@ -8,6 +8,10 @@ // // REQUIRES: long_tests +// Older compilers don't support std::is_constant_evaluated +// UNSUPPORTED: clang-4, clang-5, clang-6, clang-7, clang-8 +// UNSUPPORTED: apple-clang-9, apple-clang-10 + // // template diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.merge/merge_comp.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.merge/merge_comp.pass.cpp index 8d2dbb726858..376ffd0d1d59 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.merge/merge_comp.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.merge/merge_comp.pass.cpp @@ -8,6 +8,10 @@ // // REQUIRES: long_tests +// Older compilers don't support std::is_constant_evaluated +// UNSUPPORTED: clang-4, clang-5, clang-6, clang-7, clang-8 +// UNSUPPORTED: apple-clang-9, apple-clang-10 + // // templateThe missing bits in P0600 are in [mem.res.class], [mem.poly.allocator.class], and [container.node.overview]

-

The missing bits in P0202 are in copy, copy_backwards, move, and move_backwards (and the ones that call them: copy_n, rotate_copy, merge, set_union, set_difference, and set_symmetric_difference). This is because the first four algorithms have specializations that call memmove which is not constexpr. See Bug 25165

+

The missing bits in P0202 are in copy and copy_backwards (and the ones that call them: copy_n, set_union, set_difference, and set_symmetric_difference). This is because the first two algorithms have specializations that call memmove which is not constexpr. See Bug 25165

+

Library Working group Issues Status