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