The Debug Mode overloads of __copy_move_a, __copy_move_backward_a,
__fill_n_a and __equal_aux call _Safe_iterator::_M_can_advance, which
can't be constexpr because it calls _M_singular. So std::copy,
std::move, std::copy_backward, std::move_backward and std::equal with
a plain source and a Debug Mode destination (or second range of
std::equal) fail in a constant expression.
Skip the _M_can_advance check during constant evaluation, as
__can_advance already does.
PR libstdc++/128115
libstdc++-v3/ChangeLog:
* include/debug/safe_iterator.tcc (__copy_move_a)
(__copy_move_backward_a, __fill_n_a, __equal_aux): Do not call
_M_can_advance during constant evaluation.
* testsuite/23_containers/vector/debug/128115-2.cc: New test.
Signed-off-by: Mishmish Dev <[email protected]>
---
Tested on x86_64-pc-linux-gnu: full libstdc++ testsuite with
GLIBCXX_TESTSUITE_STDS=20,23,26, no regressions.
Independent of the other patch in this series.
OK for trunk, gcc-16 and gcc-15? gcc-14 would also need
constexpr __valid_range and __can_advance (as on gcc-15,
for PR119163).
libstdc++-v3/include/debug/safe_iterator.tcc | 13 +++-
.../23_containers/vector/debug/128115-2.cc | 69 +++++++++++++++++++
2 files changed, 79 insertions(+), 3 deletions(-)
create mode 100644
libstdc++-v3/testsuite/23_containers/vector/debug/128115-2.cc
diff --git a/libstdc++-v3/include/debug/safe_iterator.tcc
b/libstdc++-v3/include/debug/safe_iterator.tcc
index 715eceb92f3..aa7720d2116 100644
--- a/libstdc++-v3/include/debug/safe_iterator.tcc
+++ b/libstdc++-v3/include/debug/safe_iterator.tcc
@@ -305,6 +305,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__glibcxx_check_can_increment_dist(__result, __dist, 1);
if (__dist.second > ::__gnu_debug::__dp_sign
+ && !std::__is_constant_evaluated()
&& __result._M_can_advance(__dist.first, true))
return ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>(
std::__copy_move_a<_IsMove>(__first, __last, __result.base()),
@@ -330,6 +331,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (__dist.second > ::__gnu_debug::__dp_equality)
{
if (__dist.second > ::__gnu_debug::__dp_sign
+ && !std::__is_constant_evaluated()
&& __result._M_can_advance(__dist.first, true))
return ::__gnu_debug::_Safe_iterator<_OIte, _OSeq, _OCat>(
std::__copy_move_a<_IsMove>(__first.base(), __last.base(),
@@ -375,6 +377,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__glibcxx_check_can_increment_dist(__result, __dist, -1);
if (__dist.second > ::__gnu_debug::__dp_sign
+ && !std::__is_constant_evaluated()
&& __result._M_can_advance(-__dist.first, true))
return ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>(
std::__copy_move_backward_a<_IsMove>(__first, __last,
@@ -401,6 +404,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (__dist.second > ::__gnu_debug::__dp_equality)
{
if (__dist.second > ::__gnu_debug::__dp_sign
+ && !std::__is_constant_evaluated()
&& __result._M_can_advance(-__dist.first, true))
return ::__gnu_debug::_Safe_iterator<_OIte, _OSeq, _OCat>(
std::__copy_move_backward_a<_IsMove>(__first.base(),
__last.base(),
@@ -446,7 +450,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __first;
__glibcxx_check_can_increment(__first, __n);
- if (__first._M_can_advance(__n, true))
+ if (!std::__is_constant_evaluated()
+ && __first._M_can_advance(__n, true))
return ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>(
std::__fill_n_a(__first.base(), __n, __value, _Cat()),
__first._M_sequence);
@@ -483,6 +488,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__glibcxx_check_can_increment_dist(__first2, __dist, 1);
if (__dist.second > ::__gnu_debug::__dp_sign
+ && !std::__is_constant_evaluated()
&& __first2._M_can_advance(__dist.first, true))
return std::__equal_aux(__first1, __last1, __first2.base());
@@ -504,8 +510,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (__dist.second > ::__gnu_debug::__dp_equality)
{
- if (__dist.second > ::__gnu_debug::__dp_sign &&
- __first2._M_can_advance(__dist.first, true))
+ if (__dist.second > ::__gnu_debug::__dp_sign
+ && !std::__is_constant_evaluated()
+ && __first2._M_can_advance(__dist.first, true))
return std::__equal_aux(__first1.base(), __last1.base(),
__first2.base());
return std::__equal_aux(__first1.base(), __last1.base(), __first2);
diff --git a/libstdc++-v3/testsuite/23_containers/vector/debug/128115-2.cc
b/libstdc++-v3/testsuite/23_containers/vector/debug/128115-2.cc
new file mode 100644
index 00000000000..7252591e66b
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/vector/debug/128115-2.cc
@@ -0,0 +1,69 @@
+// { dg-do compile { target c++20 } }
+// { dg-additional-options "-D_GLIBCXX_DEBUG" }
+
+// PR libstdc++/128115
+// Debug Mode algorithms with a safe iterator as output or second range
+// call _Safe_iterator::_M_can_advance, which is not constexpr.
+
+#include <algorithm>
+#include <vector>
+
+constexpr bool
+test_copy()
+{
+ int s[3]{1, 2, 3};
+ std::vector<int> v(3);
+ auto out = std::copy(s, s + 3, v.begin());
+ return out == v.end() && v[2] == 3
+ && std::copy(s, s, v.begin()) == v.begin();
+}
+static_assert( test_copy() );
+
+constexpr bool
+test_move()
+{
+ int s[3]{1, 2, 3};
+ std::vector<int> v(3);
+ auto out = std::move(s, s + 3, v.begin());
+ return out == v.end() && v[2] == 3;
+}
+static_assert( test_move() );
+
+constexpr bool
+test_copy_backward()
+{
+ int s[3]{1, 2, 3};
+ std::vector<int> v(3);
+ auto out = std::copy_backward(s, s + 3, v.end());
+ return out == v.begin() && v[0] == 1;
+}
+static_assert( test_copy_backward() );
+
+constexpr bool
+test_move_backward()
+{
+ int s[3]{1, 2, 3};
+ std::vector<int> v(3);
+ auto out = std::move_backward(s, s + 3, v.end());
+ return out == v.begin() && v[0] == 1;
+}
+static_assert( test_move_backward() );
+
+constexpr bool
+test_equal()
+{
+ int s[3]{1, 2, 3};
+ std::vector<int> v{1, 2, 3};
+ return std::equal(s, s + 3, v.begin()) && !std::equal(s, s + 3, v.rbegin());
+}
+static_assert( test_equal() );
+
+constexpr bool
+test_safe_to_safe()
+{
+ std::vector<int> a{1, 2, 3}, v(3);
+ std::copy(a.begin(), a.end(), v.begin());
+ std::copy_backward(a.begin(), a.end(), v.end());
+ return std::equal(a.begin(), a.end(), v.begin());
+}
+static_assert( test_safe_to_safe() );
--
2.55.0