Hi
libstdc++: Fix std::erase_if behavior for std::__debug containers
Complete fix of std::erase_if/std::erase for all std::__debug
containers and
__gnu_debug::basic_string. Make sure that iterators erased by this
function
will be properly detected as such by the debug container and so
considered as
invalid.
Doing so introduce a new std::__detail::__erase_if function
dealing, similarly
to std::__detail::__erase_node_if, with non-node containers.
libstdc++-v3/ChangeLog:
* include/bits/erase_if.h (__detail::__erase_if): New.
* include/debug/deque (std::erase_if<>(__debug::deque<>&,
_Pred): Use latter.
* include/debug/inplace_vector
(std::erase_if<>(__debug::inplace_vector<>&, _Pred)):
Likewise.
* include/debug/vector (std::erase_if<>(__debug::vector<>&,
_Pred)): Likewise.
* include/std/deque: Include erase_if.h.
(std::erase_if<>(std::vector<>&, _Pred)): Adapt to use
__detail::__erase_if.
* include/std/inplace_vector
(std::erase_if<>(std::inplace_vector<>&, _Pred)):
Likewise.
* include/std/string (std::erase_if<>(std::basic_string<>&,
_Pred)): Likewise.
* include/std/vector (std::erase_if<>(std::vector<>&,
_Pred)): Likewise.
* include/debug/forward_list
(std::erase_if<>(__debug::forward_list<>&, _Pred)): New.
(std::erase<>(__debug::forward_list<>&, const _Up&)): New.
* include/debug/list
(std::erase_if<>(__debug::list<>&, _Pred)): New.
(std::erase<>(__debug::list<>&, const _Up&)): New.
* include/debug/map (std::erase_if<>(__debug::map<>&,
_Pred)): New.
(std::erase_if<>(__debug::multimap<>&, _Pred)): New.
* include/debug/set (std::erase_if<>(__debug::set<>&,
_Pred)): New.
(std::erase_if<>(__debug::multiset<>&, _Pred)): New.
* include/debug/string
(std::erase_if<>(__gnu_debug::basic_string<>&, _Pred)): New.
(std::erase<>(__gnu_debug::basic_string<>&, const _Up&)): New.
* include/debug/unordered_map
(std::erase_if<>(__debug::unordered_map<>&, _Pred)): New.
(std::erase_if<>(__debug::unordered_multimap<>&, _Pred)): New.
* include/debug/unordered_set
(std::erase_if<>(__debug::unordered_set<>&, _Pred)): New.
(std::erase_if<>(__debug::unordered_multiset<>&, _Pred)): New.
* include/std/forward_list
(std::erase_if<>(std::forward_list<>&, _Pred)):
Adapt to work exclusively for normal implementation.
(std::erase<>(std::forward_list<>&, const _Up&)): Likewise.
* include/std/list (std::erase_if<>(std::list<>&, _Pred)):
Likewise.
(std::erase<>(std::list<>&, const _Up&)): Likewise.
* include/std/map (std::erase_if<>(std::map<>&, _Pred)):
Likewise.
(std::erase_if<>(std::multimap<>&, _Pred)): Likewise.
* include/debug/set (std::erase_if<>(std::set<>&, _Pred)):
Likewise.
(std::erase_if<>(std::multiset<>&, _Pred)): Likewise.
* include/std/unordered_map
(std::erase_if<>(std::unordered_map<>&, _Pred)): Likewise.
(std::erase_if<>(std::unordered_multimap<>&, _Pred)): Likewise.
* include/std/unordered_set
(std::erase_if<>(std::unordered_set<>&, _Pred)): Likewise.
(std::erase_if<>(std::unordered_multiset<>&, _Pred)): Likewise.
* testsuite/21_strings/basic_string/debug/erase.cc: New
test case.
* testsuite/23_containers/forward_list/debug/erase.cc: New
test case.
*
testsuite/23_containers/forward_list/debug/invalidation/erase.cc: New
test case.
* testsuite/23_containers/list/debug/erase.cc: New test case.
* testsuite/23_containers/list/debug/invalidation/erase.cc:
New test case.
* testsuite/23_containers/map/debug/erase_if.cc: New test case.
*
testsuite/23_containers/map/debug/invalidation/erase_if.cc: New test case.
* testsuite/23_containers/multimap/debug/erase_if.cc: New
test case.
*
testsuite/23_containers/multimap/debug/invalidation/erase_if.cc: New
test case.
* testsuite/23_containers/multiset/debug/erase_if.cc: New
test case.
*
testsuite/23_containers/multiset/debug/invalidation/erase_if.cc: New
test case.
* testsuite/23_containers/set/debug/erase_if.cc: New test case.
*
testsuite/23_containers/set/debug/invalidation/erase_if.cc: New test case.
* testsuite/23_containers/unordered_map/debug/erase_if.cc:
New test case.
*
testsuite/23_containers/unordered_map/debug/invalidation/erase_if.cc:
New test case.
*
testsuite/23_containers/unordered_multimap/debug/erase_if.cc: New test case.
*
testsuite/23_containers/unordered_multimap/debug/invalidation/erase_if.cc:
New test case.
*
testsuite/23_containers/unordered_multiset/debug/erase_if.cc: New test case.
*
testsuite/23_containers/unordered_multiset/debug/invalidation/erase_if.cc:
New test case.
* testsuite/23_containers/unordered_set/debug/erase_if.cc:
New test case.
*
testsuite/23_containers/unordered_set/debug/invalidation/erase_if.cc:
New test case.
All testsuite/23_containers tests run under Linux x64 normal and
_GLIBCXX_DEBUG modes.
https://forge.sourceware.org/gcc/gcc-TEST/pulls/131
Ok to commit ?
François
diff --git a/libstdc++-v3/include/bits/erase_if.h
b/libstdc++-v3/include/bits/erase_if.h
index fc086b56728..ecf4e7fd4d3 100644
--- a/libstdc++-v3/include/bits/erase_if.h
+++ b/libstdc++-v3/include/bits/erase_if.h
@@ -35,6 +35,7 @@
#endif
#include <bits/c++config.h>
+#include <bits/stl_algobase.h>
// Used by C++17 containers and Library Fundamentals v2 headers.
#if __cplusplus >= 201402L
@@ -44,6 +45,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
namespace __detail
{
+ template<typename _Container, typename _UnsafeContainer,
+ typename _Predicate>
+ _GLIBCXX20_CONSTEXPR
+ typename _Container::size_type
+ __erase_if(_Container& __cont, _UnsafeContainer& __ucont,
+ _Predicate __pred)
+ {
+ const auto __osz = __ucont.size();
+ const auto __end = __ucont.end();
+ auto __removed = std::__remove_if(__ucont.begin(), __end,
+ std::move(__pred));
+ if (__removed != __end)
+ {
+ __cont.erase(__niter_wrap(__cont.cbegin(), __removed),
+ __cont.cend());
+ return __osz - __ucont.size();
+ }
+
+ return 0;
+ }
+
template<typename _Container, typename _UnsafeContainer,
typename _Predicate>
typename _Container::size_type
diff --git a/libstdc++-v3/include/debug/deque b/libstdc++-v3/include/debug/deque
index b2e5dd32717..2358070bd0a 100644
--- a/libstdc++-v3/include/debug/deque
+++ b/libstdc++-v3/include/debug/deque
@@ -779,18 +779,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
erase_if(__debug::deque<_Tp, _Alloc>& __cont, _Predicate __pred)
{
_GLIBCXX_STD_C::deque<_Tp, _Alloc>& __unsafe_cont = __cont;
- const auto __osz = __cont.size();
- const auto __end = __unsafe_cont.end();
- auto __removed = std::__remove_if(__unsafe_cont.begin(), __end,
- std::move(__pred));
- if (__removed != __end)
- {
- __cont.erase(__niter_wrap(__cont.begin(), __removed),
- __cont.end());
- return __osz - __cont.size();
- }
-
- return 0;
+ return __detail::__erase_if(__cont, __unsafe_cont, std::move(__pred));
}
template<typename _Tp, typename _Alloc, typename _Up = _Tp>
@@ -798,7 +787,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
erase(__debug::deque<_Tp, _Alloc>& __cont, const _Up& __value)
{ return std::erase_if(__cont, __gnu_cxx::__ops::__equal_to(__value)); }
_GLIBCXX_END_NAMESPACE_VERSION
-#endif // __cpp_lib_erase_if
+#endif // __glibcxx_erase_if
} // namespace std
#endif
diff --git a/libstdc++-v3/include/debug/forward_list
b/libstdc++-v3/include/debug/forward_list
index 9da7dda4503..c84d08770eb 100644
--- a/libstdc++-v3/include/debug/forward_list
+++ b/libstdc++-v3/include/debug/forward_list
@@ -981,6 +981,27 @@ namespace __debug
{ __lx.swap(__ly); }
} // namespace __debug
+
+#ifdef __glibcxx_erase_if // C++ >= 20 && HOSTED
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+ template<typename _Tp, typename _Alloc, typename _Predicate>
+ inline typename __debug::forward_list<_Tp, _Alloc>::size_type
+ erase_if(__debug::forward_list<_Tp, _Alloc>& __cont, _Predicate __pred)
+ { return __cont.remove_if(__pred); }
+
+ template<typename _Tp, typename _Alloc,
+ typename _Up _GLIBCXX26_DEF_VAL_T(_Tp)>
+ inline typename __debug::forward_list<_Tp, _Alloc>::size_type
+ erase(__debug::forward_list<_Tp, _Alloc>& __cont, const _Up& __value)
+ {
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4135. helper lambda of std::erase for list should specify return type
+ return std::erase_if(__cont, [&](const auto& __elem) -> bool {
+ return __elem == __value;
+ });
+ }
+_GLIBCXX_END_NAMESPACE_VERSION
+#endif // __glibcxx_erase_if
} // namespace std
namespace __gnu_debug
diff --git a/libstdc++-v3/include/debug/inplace_vector
b/libstdc++-v3/include/debug/inplace_vector
index c7e301efc62..1d1f930be1b 100644
--- a/libstdc++-v3/include/debug/inplace_vector
+++ b/libstdc++-v3/include/debug/inplace_vector
@@ -664,16 +664,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if constexpr (_Nm != 0)
{
_GLIBCXX_STD_C::inplace_vector<_Tp, _Nm>& __ucont = __cont;
- const auto __osz = __cont.size();
- const auto __end = __ucont.end();
- auto __removed = std::__remove_if(__ucont.begin(), __end,
- std::move(__pred));
- if (__removed != __end)
- {
- __cont.erase(__niter_wrap(__cont.cbegin(), __removed),
- __cont.cend());
- return __osz - __cont.size();
- }
+ return __detail::__erase_if(__cont, __ucont, std::move(__pred));
}
return 0;
diff --git a/libstdc++-v3/include/debug/list b/libstdc++-v3/include/debug/list
index c502c7cb6e2..254ce4d085a 100644
--- a/libstdc++-v3/include/debug/list
+++ b/libstdc++-v3/include/debug/list
@@ -1031,6 +1031,27 @@ namespace __debug
{ __lhs.swap(__rhs); }
} // namespace __debug
+
+#ifdef __glibcxx_erase_if // C++ >= 20 && HOSTED
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+ template<typename _Tp, typename _Alloc, typename _Predicate>
+ inline typename __debug::list<_Tp, _Alloc>::size_type
+ erase_if(__debug::list<_Tp, _Alloc>& __cont, _Predicate __pred)
+ { return __cont.remove_if(__pred); }
+
+ template<typename _Tp, typename _Alloc,
+ typename _Up _GLIBCXX26_DEF_VAL_T(_Tp)>
+ inline typename __debug::list<_Tp, _Alloc>::size_type
+ erase(__debug::list<_Tp, _Alloc>& __cont, const _Up& __value)
+ {
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4135. helper lambda of std::erase for list should specify return type
+ return std::erase_if(__cont, [&](const auto& __elem) -> bool {
+ return __elem == __value;
+ });
+ }
+_GLIBCXX_END_NAMESPACE_VERSION
+#endif // __glibcxx_erase_if
} // namespace std
namespace __gnu_debug
diff --git a/libstdc++-v3/include/debug/map b/libstdc++-v3/include/debug/map
index 1899c0ae918..fdcb507778b 100644
--- a/libstdc++-v3/include/debug/map
+++ b/libstdc++-v3/include/debug/map
@@ -45,4 +45,31 @@ namespace std _GLIBCXX_VISIBILITY(default) { namespace
__debug {
#include <debug/map.h>
#include <debug/multimap.h>
+#ifdef __glibcxx_erase_if // C++ >= 20 && HOSTED
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+ template<typename _Key, typename _Tp, typename _Compare, typename _Alloc,
+ typename _Predicate>
+ inline typename __debug::map<_Key, _Tp, _Compare, _Alloc>::size_type
+ erase_if(__debug::map<_Key, _Tp, _Compare, _Alloc>& __cont,
+ _Predicate __pred)
+ {
+ _GLIBCXX_STD_C::map<_Key, _Tp, _Compare, _Alloc>& __ucont = __cont;
+ return __detail::__erase_nodes_if(__cont, __ucont, __pred);
+ }
+
+ template<typename _Key, typename _Tp, typename _Compare, typename _Alloc,
+ typename _Predicate>
+ inline typename __debug::multimap<_Key, _Tp, _Compare, _Alloc>::size_type
+ erase_if(__debug::multimap<_Key, _Tp, _Compare, _Alloc>& __cont,
+ _Predicate __pred)
+ {
+ _GLIBCXX_STD_C::multimap<_Key, _Tp, _Compare, _Alloc>& __ucont = __cont;
+ return __detail::__erase_nodes_if(__cont, __ucont, __pred);
+ }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // __glibcxx_erase_if
+
#endif
diff --git a/libstdc++-v3/include/debug/set b/libstdc++-v3/include/debug/set
index 29ef057031c..ed12fa4b5dc 100644
--- a/libstdc++-v3/include/debug/set
+++ b/libstdc++-v3/include/debug/set
@@ -43,4 +43,29 @@ namespace std _GLIBCXX_VISIBILITY(default) { namespace
__debug {
#include <debug/set.h>
#include <debug/multiset.h>
+#ifdef __glibcxx_erase_if // C++ >= 20 && HOSTED
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+ template<typename _Key, typename _Compare, typename _Alloc,
+ typename _Predicate>
+ inline typename __debug::set<_Key, _Compare, _Alloc>::size_type
+ erase_if(__debug::set<_Key, _Compare, _Alloc>& __cont, _Predicate __pred)
+ {
+ _GLIBCXX_STD_C::set<_Key, _Compare, _Alloc>& __ucont = __cont;
+ return __detail::__erase_nodes_if(__cont, __ucont, __pred);
+ }
+
+ template<typename _Key, typename _Compare, typename _Alloc,
+ typename _Predicate>
+ inline typename __debug::multiset<_Key, _Compare, _Alloc>::size_type
+ erase_if(__debug::multiset<_Key, _Compare, _Alloc>& __cont, _Predicate
__pred)
+ {
+ _GLIBCXX_STD_C::multiset<_Key, _Compare, _Alloc>& __ucont = __cont;
+ return __detail::__erase_nodes_if(__cont, __ucont, __pred);
+ }
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // __glibcxx_erase_if
+
#endif
diff --git a/libstdc++-v3/include/debug/string
b/libstdc++-v3/include/debug/string
index fa90ebe7bfb..1502e2330fd 100644
--- a/libstdc++-v3/include/debug/string
+++ b/libstdc++-v3/include/debug/string
@@ -1331,6 +1331,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: __is_fast_hash<hash<std::basic_string<_CharT>>>
{ };
+#ifdef __glibcxx_erase_if // C++ >= 20 && HOSTED
+ template<typename _CharT, typename _Traits, typename _Alloc,
+ typename _Predicate>
+ constexpr typename __gnu_debug::basic_string<_CharT,
+ _Traits, _Alloc>::size_type
+ erase_if(__gnu_debug::basic_string<_CharT, _Traits, _Alloc>& __cont,
+ _Predicate __pred)
+ {
+ std::basic_string<_CharT, _Traits, _Alloc>& __ucont = __cont;
+ return __detail::__erase_if(__cont, __ucont, std::move(__pred));
+ }
+
+ template<typename _CharT, typename _Traits, typename _Alloc,
+ typename _Up _GLIBCXX26_DEF_VAL_T(_CharT)>
+ constexpr typename __gnu_debug::basic_string<_CharT,
+ _Traits, _Alloc>::size_type
+ erase(__gnu_debug::basic_string<_CharT, _Traits, _Alloc>& __cont,
+ const _Up& __value)
+ { return std::erase_if(__cont, __gnu_cxx::__ops::__equal_to(__value)); }
+#endif // __glibcxx_erase_if
+
_GLIBCXX_END_NAMESPACE_VERSION
}
#endif /* C++11 */
diff --git a/libstdc++-v3/include/debug/unordered_map
b/libstdc++-v3/include/debug/unordered_map
index c90e44aee45..a12257e9669 100644
--- a/libstdc++-v3/include/debug/unordered_map
+++ b/libstdc++-v3/include/debug/unordered_map
@@ -1748,6 +1748,34 @@ namespace __debug
#endif
} // namespace __debug
+
+#ifdef __glibcxx_erase_if // C++ >= 20 && HOSTED
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+ template<typename _Key, typename _Tp, typename _Hash, typename _CPred,
+ typename _Alloc, typename _Predicate>
+ inline typename __debug::unordered_map<_Key, _Tp, _Hash,
+ _CPred, _Alloc>::size_type
+ erase_if(__debug::unordered_map<_Key, _Tp, _Hash, _CPred, _Alloc>& __cont,
+ _Predicate __pred)
+ {
+ _GLIBCXX_STD_C::unordered_map<_Key, _Tp, _Hash, _CPred, _Alloc>&
+ __ucont = __cont;
+ return __detail::__erase_nodes_if(__cont, __ucont, __pred);
+ }
+
+ template<typename _Key, typename _Tp, typename _Hash, typename _CPred,
+ typename _Alloc, typename _Predicate>
+ inline typename __debug::unordered_multimap<_Key, _Tp, _Hash,
+ _CPred, _Alloc>::size_type
+ erase_if(__debug::unordered_multimap<_Key, _Tp, _Hash, _CPred, _Alloc>&
__cont,
+ _Predicate __pred)
+ {
+ _GLIBCXX_STD_C::unordered_multimap<_Key, _Tp, _Hash, _CPred, _Alloc>&
+ __ucont = __cont;
+ return __detail::__erase_nodes_if(__cont, __ucont, __pred);
+ }
+_GLIBCXX_END_NAMESPACE_VERSION
+#endif // __glibcxx_erase_if
} // namespace std
#endif // C++11
diff --git a/libstdc++-v3/include/debug/unordered_set
b/libstdc++-v3/include/debug/unordered_set
index 7fc4146aeca..1d2a22af6a7 100644
--- a/libstdc++-v3/include/debug/unordered_set
+++ b/libstdc++-v3/include/debug/unordered_set
@@ -1597,6 +1597,34 @@ namespace __debug
#endif
} // namespace __debug
+
+#ifdef __glibcxx_erase_if // C++ >= 20 && HOSTED
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+ template<typename _Key, typename _Hash, typename _CPred, typename _Alloc,
+ typename _Predicate>
+ inline typename __debug::unordered_set<_Key, _Hash,
+ _CPred, _Alloc>::size_type
+ erase_if(__debug::unordered_set<_Key, _Hash, _CPred, _Alloc>& __cont,
+ _Predicate __pred)
+ {
+ _GLIBCXX_STD_C::unordered_set<_Key, _Hash, _CPred, _Alloc>&
+ __ucont = __cont;
+ return __detail::__erase_nodes_if(__cont, __ucont, __pred);
+ }
+
+ template<typename _Key, typename _Hash, typename _CPred, typename _Alloc,
+ typename _Predicate>
+ inline typename __debug::unordered_multiset<_Key, _Hash,
+ _CPred, _Alloc>::size_type
+ erase_if(__debug::unordered_multiset<_Key, _Hash, _CPred, _Alloc>& __cont,
+ _Predicate __pred)
+ {
+ _GLIBCXX_STD_C::unordered_multiset<_Key, _Hash, _CPred, _Alloc>&
+ __ucont = __cont;
+ return __detail::__erase_nodes_if(__cont, __ucont, __pred);
+ }
+_GLIBCXX_END_NAMESPACE_VERSION
+#endif // __glibcxx_erase_if
} // namespace std
#endif // C++11
diff --git a/libstdc++-v3/include/debug/vector
b/libstdc++-v3/include/debug/vector
index f952fe9255b..83d866fa55a 100644
--- a/libstdc++-v3/include/debug/vector
+++ b/libstdc++-v3/include/debug/vector
@@ -1044,18 +1044,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
erase_if(__debug::vector<_Tp, _Alloc>& __cont, _Predicate __pred)
{
_GLIBCXX_STD_C::vector<_Tp, _Alloc>& __unsafe_cont = __cont;
- const auto __osz = __cont.size();
- const auto __end = __unsafe_cont.end();
- auto __removed = std::__remove_if(__unsafe_cont.begin(), __end,
- std::move(__pred));
- if (__removed != __end)
- {
- __cont.erase(__niter_wrap(__cont.begin(), __removed),
- __cont.end());
- return __osz - __cont.size();
- }
-
- return 0;
+ return __detail::__erase_if(__cont, __unsafe_cont, std::move(__pred));
}
template<typename _Tp, typename _Alloc, typename _Up = _Tp>
diff --git a/libstdc++-v3/include/std/deque b/libstdc++-v3/include/std/deque
index 5cd953217f4..f44fca968f8 100644
--- a/libstdc++-v3/include/std/deque
+++ b/libstdc++-v3/include/std/deque
@@ -68,6 +68,7 @@
#include <bits/stl_uninitialized.h>
#include <bits/stl_deque.h>
#include <bits/range_access.h>
+#include <bits/erase_if.h>
#include <bits/deque.tcc>
#define __glibcxx_want_algorithm_default_value_type
@@ -103,19 +104,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp, typename _Alloc, typename _Predicate>
inline typename _GLIBCXX_STD_C::deque<_Tp, _Alloc>::size_type
erase_if(_GLIBCXX_STD_C::deque<_Tp, _Alloc>& __cont, _Predicate __pred)
- {
- const auto __osz = __cont.size();
- const auto __end = __cont.end();
- auto __removed = std::__remove_if(__cont.begin(), __end,
- std::move(__pred));
- if (__removed != __end)
- {
- __cont.erase(__removed, __end);
- return __osz - __cont.size();
- }
-
- return 0;
- }
+ { return __detail::__erase_if(__cont, __cont, std::move(__pred)); }
template<typename _Tp, typename _Alloc,
typename _Up _GLIBCXX26_DEF_VAL_T(_Tp)>
diff --git a/libstdc++-v3/include/std/forward_list
b/libstdc++-v3/include/std/forward_list
index d478851acf9..f3b7a480860 100644
--- a/libstdc++-v3/include/std/forward_list
+++ b/libstdc++-v3/include/std/forward_list
@@ -75,14 +75,14 @@ namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp, typename _Alloc, typename _Predicate>
- inline typename forward_list<_Tp, _Alloc>::size_type
- erase_if(forward_list<_Tp, _Alloc>& __cont, _Predicate __pred)
+ inline typename _GLIBCXX_STD_C::forward_list<_Tp, _Alloc>::size_type
+ erase_if(_GLIBCXX_STD_C::forward_list<_Tp, _Alloc>& __cont, _Predicate
__pred)
{ return __cont.remove_if(__pred); }
template<typename _Tp, typename _Alloc,
typename _Up _GLIBCXX26_DEF_VAL_T(_Tp)>
- inline typename forward_list<_Tp, _Alloc>::size_type
- erase(forward_list<_Tp, _Alloc>& __cont, const _Up& __value)
+ inline typename _GLIBCXX_STD_C::forward_list<_Tp, _Alloc>::size_type
+ erase(_GLIBCXX_STD_C::forward_list<_Tp, _Alloc>& __cont, const _Up&
__value)
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 4135. helper lambda of std::erase for list should specify return type
diff --git a/libstdc++-v3/include/std/inplace_vector
b/libstdc++-v3/include/std/inplace_vector
index df95c1e5c02..c22a9e1f9b4 100644
--- a/libstdc++-v3/include/std/inplace_vector
+++ b/libstdc++-v3/include/std/inplace_vector
@@ -46,6 +46,7 @@
#include <bits/stl_construct.h>
#include <bits/stl_uninitialized.h>
#include <bits/stl_algo.h> // rotate
+#include <bits/erase_if.h>
namespace std _GLIBCXX_VISIBILITY(default)
{
@@ -1339,17 +1340,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
_Predicate __pred)
{
if constexpr (_Nm != 0)
- {
- const auto __osz = __cont.size();
- const auto __end = __cont.end();
- auto __removed = std::__remove_if(__cont.begin(), __end,
- std::move(__pred));
- if (__removed != __end)
- {
- __cont.erase(__removed, __end);
- return __osz - __cont.size();
- }
- }
+ return __detail::__erase_if(__cont, __cont, std::move(__pred));
return 0;
}
diff --git a/libstdc++-v3/include/std/list b/libstdc++-v3/include/std/list
index 2ba0599d33d..34bbedc9a0e 100644
--- a/libstdc++-v3/include/std/list
+++ b/libstdc++-v3/include/std/list
@@ -99,14 +99,14 @@ namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp, typename _Alloc, typename _Predicate>
- inline typename list<_Tp, _Alloc>::size_type
- erase_if(list<_Tp, _Alloc>& __cont, _Predicate __pred)
+ inline typename _GLIBCXX_STD_C::list<_Tp, _Alloc>::size_type
+ erase_if(_GLIBCXX_STD_C::list<_Tp, _Alloc>& __cont, _Predicate __pred)
{ return __cont.remove_if(__pred); }
template<typename _Tp, typename _Alloc,
typename _Up _GLIBCXX26_DEF_VAL_T(_Tp)>
- inline typename list<_Tp, _Alloc>::size_type
- erase(list<_Tp, _Alloc>& __cont, const _Up& __value)
+ inline typename _GLIBCXX_STD_C::list<_Tp, _Alloc>::size_type
+ erase(_GLIBCXX_STD_C::list<_Tp, _Alloc>& __cont, const _Up& __value)
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 4135. helper lambda of std::erase for list should specify return type
diff --git a/libstdc++-v3/include/std/map b/libstdc++-v3/include/std/map
index 6bfb53848ba..761d96229b9 100644
--- a/libstdc++-v3/include/std/map
+++ b/libstdc++-v3/include/std/map
@@ -101,29 +101,26 @@ _GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#endif // C++17
-#if __cplusplus > 201703L
+#ifdef __cpp_lib_erase_if // C++ >= 20 && HOSTED
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Key, typename _Tp, typename _Compare, typename _Alloc,
typename _Predicate>
- inline typename map<_Key, _Tp, _Compare, _Alloc>::size_type
- erase_if(map<_Key, _Tp, _Compare, _Alloc>& __cont, _Predicate __pred)
- {
- _GLIBCXX_STD_C::map<_Key, _Tp, _Compare, _Alloc>& __ucont = __cont;
- return __detail::__erase_nodes_if(__cont, __ucont, __pred);
- }
+ inline typename _GLIBCXX_STD_C::map<_Key, _Tp, _Compare, _Alloc>::size_type
+ erase_if(_GLIBCXX_STD_C::map<_Key, _Tp, _Compare, _Alloc>& __cont,
+ _Predicate __pred)
+ { return __detail::__erase_nodes_if(__cont, __cont, __pred); }
template<typename _Key, typename _Tp, typename _Compare, typename _Alloc,
typename _Predicate>
- inline typename multimap<_Key, _Tp, _Compare, _Alloc>::size_type
- erase_if(multimap<_Key, _Tp, _Compare, _Alloc>& __cont, _Predicate __pred)
- {
- _GLIBCXX_STD_C::multimap<_Key, _Tp, _Compare, _Alloc>& __ucont = __cont;
- return __detail::__erase_nodes_if(__cont, __ucont, __pred);
- }
+ inline typename _GLIBCXX_STD_C::multimap<_Key, _Tp,
+ _Compare, _Alloc>::size_type
+ erase_if(_GLIBCXX_STD_C::multimap<_Key, _Tp, _Compare, _Alloc>& __cont,
+ _Predicate __pred)
+ { return __detail::__erase_nodes_if(__cont, __cont, __pred); }
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
-#endif // C++20
+#endif // __cpp_lib_erase_if
#endif /* _GLIBCXX_MAP */
diff --git a/libstdc++-v3/include/std/set b/libstdc++-v3/include/std/set
index cf7057aa6c6..2dffb9fec87 100644
--- a/libstdc++-v3/include/std/set
+++ b/libstdc++-v3/include/std/set
@@ -95,29 +95,25 @@ _GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#endif // C++17
-#if __cplusplus > 201703L
+#ifdef __cpp_lib_erase_if // C++ >= 20 && HOSTED
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Key, typename _Compare, typename _Alloc,
typename _Predicate>
- inline typename set<_Key, _Compare, _Alloc>::size_type
- erase_if(set<_Key, _Compare, _Alloc>& __cont, _Predicate __pred)
- {
- _GLIBCXX_STD_C::set<_Key, _Compare, _Alloc>& __ucont = __cont;
- return __detail::__erase_nodes_if(__cont, __ucont, __pred);
- }
+ inline typename _GLIBCXX_STD_C::set<_Key, _Compare, _Alloc>::size_type
+ erase_if(_GLIBCXX_STD_C::set<_Key, _Compare, _Alloc>& __cont,
+ _Predicate __pred)
+ { return __detail::__erase_nodes_if(__cont, __cont, __pred); }
template<typename _Key, typename _Compare, typename _Alloc,
typename _Predicate>
- inline typename multiset<_Key, _Compare, _Alloc>::size_type
- erase_if(multiset<_Key, _Compare, _Alloc>& __cont, _Predicate __pred)
- {
- _GLIBCXX_STD_C::multiset<_Key, _Compare, _Alloc>& __ucont = __cont;
- return __detail::__erase_nodes_if(__cont, __ucont, __pred);
- }
+ inline typename _GLIBCXX_STD_C::multiset<_Key, _Compare, _Alloc>::size_type
+ erase_if(_GLIBCXX_STD_C::multiset<_Key, _Compare, _Alloc>& __cont,
+ _Predicate __pred)
+ { return __detail::__erase_nodes_if(__cont, __cont, __pred); }
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
-#endif // C++20
+#endif // __cpp_lib_erase_if
#endif /* _GLIBCXX_SET */
diff --git a/libstdc++-v3/include/std/string b/libstdc++-v3/include/std/string
index 671bad199f5..114ed705fad 100644
--- a/libstdc++-v3/include/std/string
+++ b/libstdc++-v3/include/std/string
@@ -54,6 +54,7 @@
#include <bits/stdexcept_throw.h>
#include <bits/stl_algobase.h>
#include <bits/range_access.h>
+#include <bits/erase_if.h>
#include <bits/basic_string.h>
#include <bits/basic_string.tcc>
#if (_GLIBCXX_HOSTED && __cpp_exceptions && __cplusplus > 202302L \
@@ -108,15 +109,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
typename _Predicate>
constexpr typename basic_string<_CharT, _Traits, _Alloc>::size_type
erase_if(basic_string<_CharT, _Traits, _Alloc>& __cont, _Predicate __pred)
- {
- using namespace __gnu_cxx;
- const auto __osz = __cont.size();
- const auto __end = __cont.end();
- auto __removed = std::__remove_if(__cont.begin(), __end,
- std::move(__pred));
- __cont.erase(__removed, __end);
- return __osz - __cont.size();
- }
+ { return __detail::__erase_if(__cont, __cont, std::move(__pred)); }
template<typename _CharT, typename _Traits, typename _Alloc,
typename _Up _GLIBCXX26_DEF_VAL_T(_CharT)>
diff --git a/libstdc++-v3/include/std/unordered_map
b/libstdc++-v3/include/std/unordered_map
index 3ae25d758ac..4581b128542 100644
--- a/libstdc++-v3/include/std/unordered_map
+++ b/libstdc++-v3/include/std/unordered_map
@@ -80,35 +80,30 @@ _GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#endif // C++17
-#if __cplusplus > 201703L
+#ifdef __cpp_lib_erase_if // C++ >= 20 && HOSTED
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Key, typename _Tp, typename _Hash, typename _CPred,
typename _Alloc, typename _Predicate>
- inline typename unordered_map<_Key, _Tp, _Hash, _CPred, _Alloc>::size_type
- erase_if(unordered_map<_Key, _Tp, _Hash, _CPred, _Alloc>& __cont,
+ inline typename _GLIBCXX_STD_C::unordered_map<_Key, _Tp, _Hash,
+ _CPred, _Alloc>::size_type
+ erase_if(_GLIBCXX_STD_C::unordered_map<_Key, _Tp, _Hash,
+ _CPred, _Alloc>& __cont,
_Predicate __pred)
- {
- _GLIBCXX_STD_C::unordered_map<_Key, _Tp, _Hash, _CPred, _Alloc>&
- __ucont = __cont;
- return __detail::__erase_nodes_if(__cont, __ucont, __pred);
- }
+ { return __detail::__erase_nodes_if(__cont, __cont, __pred); }
template<typename _Key, typename _Tp, typename _Hash, typename _CPred,
typename _Alloc, typename _Predicate>
- inline typename unordered_multimap<_Key, _Tp, _Hash, _CPred, _Alloc>::
- size_type
- erase_if(unordered_multimap<_Key, _Tp, _Hash, _CPred, _Alloc>& __cont,
+ inline typename _GLIBCXX_STD_C::unordered_multimap<_Key, _Tp, _Hash,
+ _CPred, _Alloc>::size_type
+ erase_if(_GLIBCXX_STD_C::unordered_multimap<_Key, _Tp, _Hash,
+ _CPred, _Alloc>& __cont,
_Predicate __pred)
- {
- _GLIBCXX_STD_C::unordered_multimap<_Key, _Tp, _Hash, _CPred, _Alloc>&
- __ucont = __cont;
- return __detail::__erase_nodes_if(__cont, __ucont, __pred);
- }
+ { return __detail::__erase_nodes_if(__cont, __cont, __pred); }
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
-#endif // C++20
+#endif // __cpp_lib_erase_if
#endif // C++11
diff --git a/libstdc++-v3/include/std/unordered_set
b/libstdc++-v3/include/std/unordered_set
index b561163d31d..02e22e40b43 100644
--- a/libstdc++-v3/include/std/unordered_set
+++ b/libstdc++-v3/include/std/unordered_set
@@ -78,34 +78,28 @@ _GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#endif // C++17
-#if __cplusplus > 201703L
+#ifdef __cpp_lib_erase_if // C++ >= 20 && HOSTED
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Key, typename _Hash, typename _CPred, typename _Alloc,
typename _Predicate>
- inline typename unordered_set<_Key, _Hash, _CPred, _Alloc>::size_type
- erase_if(unordered_set<_Key, _Hash, _CPred, _Alloc>& __cont,
+ inline typename _GLIBCXX_STD_C::unordered_set<_Key, _Hash,
+ _CPred, _Alloc>::size_type
+ erase_if(_GLIBCXX_STD_C::unordered_set<_Key, _Hash, _CPred, _Alloc>&
__cont,
_Predicate __pred)
- {
- _GLIBCXX_STD_C::unordered_set<_Key, _Hash, _CPred, _Alloc>&
- __ucont = __cont;
- return __detail::__erase_nodes_if(__cont, __ucont, __pred);
- }
+ { return __detail::__erase_nodes_if(__cont, __cont, __pred); }
template<typename _Key, typename _Hash, typename _CPred, typename _Alloc,
typename _Predicate>
- inline typename unordered_multiset<_Key, _Hash, _CPred, _Alloc>::size_type
- erase_if(unordered_multiset<_Key, _Hash, _CPred, _Alloc>& __cont,
+ inline typename _GLIBCXX_STD_C::unordered_multiset<_Key, _Hash,
+ _CPred, _Alloc>::size_type
+ erase_if(_GLIBCXX_STD_C::unordered_multiset<_Key, _Hash, _CPred, _Alloc>&
__cont,
_Predicate __pred)
- {
- _GLIBCXX_STD_C::unordered_multiset<_Key, _Hash, _CPred, _Alloc>&
- __ucont = __cont;
- return __detail::__erase_nodes_if(__cont, __ucont, __pred);
- }
+ { return __detail::__erase_nodes_if(__cont, __cont, __pred); }
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
-#endif // C++20
+#endif // __cpp_lib_erase_if
#endif // C++11
diff --git a/libstdc++-v3/include/std/vector b/libstdc++-v3/include/std/vector
index 375011fff69..f79fc371af7 100644
--- a/libstdc++-v3/include/std/vector
+++ b/libstdc++-v3/include/std/vector
@@ -68,6 +68,7 @@
#include <bits/stl_vector.h>
#include <bits/stl_bvector.h>
#include <bits/range_access.h>
+#include <bits/erase_if.h>
#ifndef _GLIBCXX_EXPORT_TEMPLATE
# include <bits/vector.tcc>
@@ -114,19 +115,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp, typename _Alloc, typename _Predicate>
constexpr typename _GLIBCXX_STD_C::vector<_Tp, _Alloc>::size_type
erase_if(_GLIBCXX_STD_C::vector<_Tp, _Alloc>& __cont, _Predicate __pred)
- {
- const auto __osz = __cont.size();
- const auto __end = __cont.end();
- auto __removed = std::__remove_if(__cont.begin(), __end,
- std::move(__pred));
- if (__removed != __end)
- {
- __cont.erase(__removed, __end);
- return __osz - __cont.size();
- }
-
- return 0;
- }
+ { return __detail::__erase_if(__cont, __cont, std::move(__pred)); }
template<typename _Tp, typename _Alloc,
typename _Up _GLIBCXX26_DEF_VAL_T(_Tp)>
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/debug/erase.cc
b/libstdc++-v3/testsuite/21_strings/basic_string/debug/erase.cc
new file mode 100644
index 00000000000..b381ad15738
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/debug/erase.cc
@@ -0,0 +1,25 @@
+// { dg-do run { target c++20 } }
+
+#include <debug/string>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::string;
+
+void test01()
+{
+ string str("abcdefghijklmnopqrstuvwxyz");
+
+ auto before = str.begin();
+ auto last = str.end() - 1;
+
+ VERIFY( std::erase(str, 'd') == 1 );
+
+ VERIFY(before._M_singular());
+ VERIFY(last._M_singular());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/debug/erase.cc
b/libstdc++-v3/testsuite/23_containers/forward_list/debug/erase.cc
new file mode 100644
index 00000000000..061dfcbd9e3
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/forward_list/debug/erase.cc
@@ -0,0 +1,26 @@
+// { dg-do run { target c++20 } }
+// { dg-require-debug-mode "" }
+
+#include <forward_list>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ std::forward_list<int> fl({ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });
+
+ auto before = ++fl.begin();
+ auto match = std::next(fl.begin(), 6);
+ auto last = std::next(fl.begin(), 9);
+
+ VERIFY( std::erase(fl, 6) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(match._M_singular());
+ VERIFY(last._M_dereferenceable());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/forward_list/debug/invalidation/erase.cc
b/libstdc++-v3/testsuite/23_containers/forward_list/debug/invalidation/erase.cc
new file mode 100644
index 00000000000..15194173cc3
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/forward_list/debug/invalidation/erase.cc
@@ -0,0 +1,27 @@
+// { dg-do run { target c++20 } }
+
+#include <debug/forward_list>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::forward_list;
+
+void test01()
+{
+ forward_list<int> fl({ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });
+
+ auto before = ++fl.begin();
+ auto match = std::next(fl.begin(), 6);
+ auto last = std::next(fl.begin(), 9);
+
+ VERIFY( std::erase(fl, 6) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(match._M_singular());
+ VERIFY(last._M_dereferenceable());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/list/debug/erase.cc
b/libstdc++-v3/testsuite/23_containers/list/debug/erase.cc
new file mode 100644
index 00000000000..d6210daf344
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/list/debug/erase.cc
@@ -0,0 +1,29 @@
+// { dg-do run { target c++20 } }
+// { dg-require-debug-mode "" }
+
+#include <list>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ std::list<int> l;
+
+ for (int i = 0; i != 10; ++i)
+ l.push_back(i);
+
+ auto before = ++l.begin();
+ auto match = std::next(l.begin(), 6);
+ auto last = --l.end();
+
+ VERIFY( std::erase(l, 6) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(match._M_singular());
+ VERIFY(last._M_dereferenceable());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/list/debug/invalidation/erase.cc
b/libstdc++-v3/testsuite/23_containers/list/debug/invalidation/erase.cc
new file mode 100644
index 00000000000..57137fd08d6
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/list/debug/invalidation/erase.cc
@@ -0,0 +1,30 @@
+// { dg-do run { target c++20 } }
+
+#include <debug/list>
+#include <testsuite_hooks.h>
+
+using __gnu_debug::list;
+
+void test01()
+{
+ list<int> l;
+
+ for (int i = 0; i != 10; ++i)
+ l.push_back(i);
+
+ auto before = ++l.begin();
+ auto match = std::next(l.begin(), 6);
+ auto last = --l.end();
+
+ VERIFY( std::erase(l, 6) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(match._M_singular());
+ VERIFY(last._M_dereferenceable());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/map/debug/erase_if.cc
b/libstdc++-v3/testsuite/23_containers/map/debug/erase_if.cc
new file mode 100644
index 00000000000..dfdfc1340fa
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/map/debug/erase_if.cc
@@ -0,0 +1,33 @@
+// { dg-do run { target c++20 } }
+// { dg-require-debug-mode "" }
+
+#include <map>
+#include <testsuite_hooks.h>
+
+auto is_six_pair = [](const std::pair<const int, int>& p)
+{
+ return p.first == 6;
+};
+
+void test01()
+{
+ std::map<int, int> m;
+ for (int i = 0; i != 10; ++i)
+ m.insert({ i, i });
+
+ auto before = ++m.begin();
+ auto match = std::next(m.begin(), 6);
+ auto last = std::next(m.begin(), 9);
+
+ VERIFY( std::erase_if(m, is_six_pair) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(match._M_singular());
+ VERIFY(last._M_dereferenceable());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/map/debug/invalidation/erase_if.cc
b/libstdc++-v3/testsuite/23_containers/map/debug/invalidation/erase_if.cc
new file mode 100644
index 00000000000..ee080c31160
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/map/debug/invalidation/erase_if.cc
@@ -0,0 +1,34 @@
+// { dg-do run { target c++20 } }
+
+#include <debug/map>
+#include <testsuite_hooks.h>
+
+auto is_six_pair = [](const std::pair<const int, int>& p)
+{
+ return p.first == 6;
+};
+
+using __gnu_debug::map;
+
+void test01()
+{
+ map<int, int> m;
+ for (int i = 0; i != 10; ++i)
+ m.insert({ i, i });
+
+ auto before = ++m.begin();
+ auto match = std::next(m.begin(), 6);
+ auto last = std::next(m.begin(), 9);
+
+ VERIFY( std::erase_if(m, is_six_pair) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(match._M_singular());
+ VERIFY(last._M_dereferenceable());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/multimap/debug/erase_if.cc
b/libstdc++-v3/testsuite/23_containers/multimap/debug/erase_if.cc
new file mode 100644
index 00000000000..30b6b65e703
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/multimap/debug/erase_if.cc
@@ -0,0 +1,33 @@
+// { dg-do run { target c++20 } }
+// { dg-require-debug-mode "" }
+
+#include <map>
+#include <testsuite_hooks.h>
+
+auto is_six_pair = [](const std::pair<const int, int>& p)
+{
+ return p.first == 6;
+};
+
+void test01()
+{
+ std::multimap<int, int> m;
+ for (int i = 0; i != 10; ++i)
+ m.insert({ i, i });
+
+ auto before = ++m.begin();
+ auto match = std::next(m.begin(), 6);
+ auto last = std::next(m.begin(), 9);
+
+ VERIFY( std::erase_if(m, is_six_pair) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(match._M_singular());
+ VERIFY(last._M_dereferenceable());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/multimap/debug/invalidation/erase_if.cc
b/libstdc++-v3/testsuite/23_containers/multimap/debug/invalidation/erase_if.cc
new file mode 100644
index 00000000000..c9f740ea4e6
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/multimap/debug/invalidation/erase_if.cc
@@ -0,0 +1,34 @@
+// { dg-do run { target c++20 } }
+
+#include <debug/map>
+#include <testsuite_hooks.h>
+
+auto is_six_pair = [](const std::pair<const int, int>& p)
+{
+ return p.first == 6;
+};
+
+using __gnu_debug::multimap;
+
+void test01()
+{
+ multimap<int, int> m;
+ for (int i = 0; i != 10; ++i)
+ m.insert({ i, i });
+
+ auto before = ++m.begin();
+ auto match = std::next(m.begin(), 6);
+ auto last = std::next(m.begin(), 9);
+
+ VERIFY( std::erase_if(m, is_six_pair) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(match._M_singular());
+ VERIFY(last._M_dereferenceable());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/multiset/debug/erase_if.cc
b/libstdc++-v3/testsuite/23_containers/multiset/debug/erase_if.cc
new file mode 100644
index 00000000000..e54eaa797f8
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/multiset/debug/erase_if.cc
@@ -0,0 +1,31 @@
+// { dg-do run { target c++20 } }
+// { dg-require-debug-mode "" }
+
+#include <set>
+#include <testsuite_hooks.h>
+
+auto is_six = [](int p)
+{ return p == 6; };
+
+void test01()
+{
+ std::multiset<int> s;
+ for (int i = 0; i != 10; ++i)
+ s.insert(i);
+
+ auto before = ++s.begin();
+ auto match = std::next(s.begin(), 6);
+ auto last = std::next(s.begin(), 9);
+
+ VERIFY( std::erase_if(s, is_six) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(match._M_singular());
+ VERIFY(last._M_dereferenceable());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/multiset/debug/invalidation/erase_if.cc
b/libstdc++-v3/testsuite/23_containers/multiset/debug/invalidation/erase_if.cc
new file mode 100644
index 00000000000..c85b76fc506
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/multiset/debug/invalidation/erase_if.cc
@@ -0,0 +1,32 @@
+// { dg-do run { target c++20 } }
+
+#include <debug/set>
+#include <testsuite_hooks.h>
+
+auto is_six = [](int p)
+{ return p == 6; };
+
+using __gnu_debug::multiset;
+
+void test01()
+{
+ multiset<int> s;
+ for (int i = 0; i != 10; ++i)
+ s.insert(i);
+
+ auto before = ++s.begin();
+ auto match = std::next(s.begin(), 6);
+ auto last = std::next(s.begin(), 9);
+
+ VERIFY( std::erase_if(s, is_six) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(match._M_singular());
+ VERIFY(last._M_dereferenceable());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/set/debug/erase_if.cc
b/libstdc++-v3/testsuite/23_containers/set/debug/erase_if.cc
new file mode 100644
index 00000000000..e8c64628a65
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/set/debug/erase_if.cc
@@ -0,0 +1,31 @@
+// { dg-do run { target c++20 } }
+// { dg-require-debug-mode "" }
+
+#include <set>
+#include <testsuite_hooks.h>
+
+auto is_six = [](int p)
+{ return p == 6; };
+
+void test01()
+{
+ std::set<int> s;
+ for (int i = 0; i != 10; ++i)
+ s.insert(i);
+
+ auto before = ++s.begin();
+ auto match = std::next(s.begin(), 6);
+ auto last = std::next(s.begin(), 9);
+
+ VERIFY( std::erase_if(s, is_six) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(match._M_singular());
+ VERIFY(last._M_dereferenceable());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/set/debug/invalidation/erase_if.cc
b/libstdc++-v3/testsuite/23_containers/set/debug/invalidation/erase_if.cc
new file mode 100644
index 00000000000..99dde9bfcf2
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/set/debug/invalidation/erase_if.cc
@@ -0,0 +1,32 @@
+// { dg-do run { target c++20 } }
+
+#include <debug/set>
+#include <testsuite_hooks.h>
+
+auto is_six = [](int p)
+{ return p == 6; };
+
+using __gnu_debug::set;
+
+void test01()
+{
+ set<int> s;
+ for (int i = 0; i != 10; ++i)
+ s.insert(i);
+
+ auto before = ++s.begin();
+ auto match = std::next(s.begin(), 6);
+ auto last = std::next(s.begin(), 9);
+
+ VERIFY( std::erase_if(s, is_six) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(match._M_singular());
+ VERIFY(last._M_dereferenceable());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/erase_if.cc
b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/erase_if.cc
new file mode 100644
index 00000000000..e7ac643c8ec
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/erase_if.cc
@@ -0,0 +1,33 @@
+// { dg-do run { target c++20 } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_map>
+#include <testsuite_hooks.h>
+
+auto is_six_pair = [](const std::pair<const int, int>& p)
+{
+ return p.first == 6;
+};
+
+void test01()
+{
+ std::unordered_map<int, int> m;
+ for (int i = 0; i != 10; ++i)
+ m.insert({ i, i });
+
+ auto before = m.find(1);
+ auto match = m.find(6);
+ auto last = m.find(9);
+
+ VERIFY( std::erase_if(m, is_six_pair) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(match._M_singular());
+ VERIFY(last._M_dereferenceable());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalidation/erase_if.cc
b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalidation/erase_if.cc
new file mode 100644
index 00000000000..303692838ac
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/unordered_map/debug/invalidation/erase_if.cc
@@ -0,0 +1,34 @@
+// { dg-do run { target c++20 } }
+
+#include <debug/unordered_map>
+#include <testsuite_hooks.h>
+
+auto is_six_pair = [](const std::pair<const int, int>& p)
+{
+ return p.first == 6;
+};
+
+using __gnu_debug::unordered_map;
+
+void test01()
+{
+ unordered_map<int, int> m;
+ for (int i = 0; i != 10; ++i)
+ m.insert({ i, i });
+
+ auto before = m.find(1);
+ auto match = m.find(6);
+ auto last = m.find(9);
+
+ VERIFY( std::erase_if(m, is_six_pair) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(match._M_singular());
+ VERIFY(last._M_dereferenceable());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/erase_if.cc
b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/erase_if.cc
new file mode 100644
index 00000000000..e8d98c96e6b
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/erase_if.cc
@@ -0,0 +1,33 @@
+// { dg-do run { target c++20 } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_map>
+#include <testsuite_hooks.h>
+
+auto is_six_pair = [](const std::pair<const int, int>& p)
+{
+ return p.first == 6;
+};
+
+void test01()
+{
+ std::unordered_multimap<int, int> m;
+ for (int i = 0; i != 10; ++i)
+ m.insert({ i, i });
+
+ auto before = m.find(1);
+ auto match = m.find(6);
+ auto last = m.find(9);
+
+ VERIFY( std::erase_if(m, is_six_pair) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(match._M_singular());
+ VERIFY(last._M_dereferenceable());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalidation/erase_if.cc
b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalidation/erase_if.cc
new file mode 100644
index 00000000000..37539336505
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/unordered_multimap/debug/invalidation/erase_if.cc
@@ -0,0 +1,34 @@
+// { dg-do run { target c++20 } }
+
+#include <debug/unordered_map>
+#include <testsuite_hooks.h>
+
+auto is_six_pair = [](const std::pair<const int, int>& p)
+{
+ return p.first == 6;
+};
+
+using __gnu_debug::unordered_multimap;
+
+void test01()
+{
+ unordered_multimap<int, int> m;
+ for (int i = 0; i != 10; ++i)
+ m.insert({ i, i });
+
+ auto before = m.find(1);
+ auto match = m.find(6);
+ auto last = m.find(9);
+
+ VERIFY( std::erase_if(m, is_six_pair) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(match._M_singular());
+ VERIFY(last._M_dereferenceable());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/erase_if.cc
b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/erase_if.cc
new file mode 100644
index 00000000000..8969a9dad5f
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/erase_if.cc
@@ -0,0 +1,31 @@
+// { dg-do run { target c++20 } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_set>
+#include <testsuite_hooks.h>
+
+auto is_six = [](int p)
+{ return p == 6; };
+
+void test01()
+{
+ std::unordered_multiset<int> s;
+ for (int i = 0; i != 10; ++i)
+ s.insert(i);
+
+ auto before = s.find(1);
+ auto match = s.find(6);
+ auto last = s.find(9);
+
+ VERIFY( std::erase_if(s, is_six) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(match._M_singular());
+ VERIFY(last._M_dereferenceable());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalidation/erase_if.cc
b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalidation/erase_if.cc
new file mode 100644
index 00000000000..f5ec00e2c1a
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/unordered_multiset/debug/invalidation/erase_if.cc
@@ -0,0 +1,32 @@
+// { dg-do run { target c++20 } }
+
+#include <debug/unordered_set>
+#include <testsuite_hooks.h>
+
+auto is_six = [](int p)
+{ return p == 6; };
+
+using __gnu_debug::unordered_multiset;
+
+void test01()
+{
+ unordered_multiset<int> s;
+ for (int i = 0; i != 10; ++i)
+ s.insert(i);
+
+ auto before = s.find(1);
+ auto match = s.find(6);
+ auto last = s.find(9);
+
+ VERIFY( std::erase_if(s, is_six) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(match._M_singular());
+ VERIFY(last._M_dereferenceable());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/unordered_set/debug/erase_if.cc
b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/erase_if.cc
new file mode 100644
index 00000000000..c725b94558a
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/erase_if.cc
@@ -0,0 +1,31 @@
+// { dg-do run { target c++20 } }
+// { dg-require-debug-mode "" }
+
+#include <unordered_set>
+#include <testsuite_hooks.h>
+
+auto is_six = [](int p)
+{ return p == 6; };
+
+void test01()
+{
+ std::unordered_set<int> s;
+ for (int i = 0; i != 10; ++i)
+ s.insert(i);
+
+ auto before = s.find(1);
+ auto match = s.find(6);
+ auto last = s.find(9);
+
+ VERIFY( std::erase_if(s, is_six) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(match._M_singular());
+ VERIFY(last._M_dereferenceable());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git
a/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalidation/erase_if.cc
b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalidation/erase_if.cc
new file mode 100644
index 00000000000..61c1cffca22
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/unordered_set/debug/invalidation/erase_if.cc
@@ -0,0 +1,32 @@
+// { dg-do run { target c++20 } }
+
+#include <debug/unordered_set>
+#include <testsuite_hooks.h>
+
+auto is_six = [](int p)
+{ return p == 6; };
+
+using __gnu_debug::unordered_set;
+
+void test01()
+{
+ unordered_set<int> s;
+ for (int i = 0; i != 10; ++i)
+ s.insert(i);
+
+ auto before = s.find(1);
+ auto match = s.find(6);
+ auto last = s.find(9);
+
+ VERIFY( std::erase_if(s, is_six) == 1 );
+
+ VERIFY(before._M_dereferenceable());
+ VERIFY(match._M_singular());
+ VERIFY(last._M_dereferenceable());
+}
+
+int main()
+{
+ test01();
+ return 0;
+}