https://gcc.gnu.org/g:3287a5c617458ab1b79d69d93d755006842f00ad

commit r16-6889-g3287a5c617458ab1b79d69d93d755006842f00ad
Author: François Dumont <[email protected]>
Date:   Wed Dec 10 19:12:58 2025 +0100

    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.
            Guard functions using __cpp_lib_erase_if.
            * include/std/set (std::erase_if<>(std::set<>&, _Pred)): Likewise.
            (std::erase_if<>(std::multiset<>&, _Pred)): Likewise.
            Guard functions using __cpp_lib_erase_if.
            * include/std/unordered_map
            (std::erase_if<>(std::unordered_map<>&, _Pred)): Likewise.
            (std::erase_if<>(std::unordered_multimap<>&, _Pred)): Likewise.
            Guard functions using __cpp_lib_erase_if.
            * include/std/unordered_set
            (std::erase_if<>(std::unordered_set<>&, _Pred)): Likewise.
            (std::erase_if<>(std::unordered_multiset<>&, _Pred)): Likewise.
            Guard functions using __cpp_lib_erase_if.
            * 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.

Diff:
---
 libstdc++-v3/include/bits/erase_if.h               | 22 ++++++++++++++
 libstdc++-v3/include/debug/deque                   | 16 ++--------
 libstdc++-v3/include/debug/forward_list            | 21 +++++++++++++
 libstdc++-v3/include/debug/inplace_vector          | 15 ++--------
 libstdc++-v3/include/debug/list                    | 21 +++++++++++++
 libstdc++-v3/include/debug/map                     | 21 +++++++++++++
 libstdc++-v3/include/debug/set                     | 19 ++++++++++++
 libstdc++-v3/include/debug/string                  | 20 +++++++++++++
 libstdc++-v3/include/debug/unordered_map           | 20 +++++++++++++
 libstdc++-v3/include/debug/unordered_set           | 20 +++++++++++++
 libstdc++-v3/include/debug/vector                  | 14 +--------
 libstdc++-v3/include/std/deque                     | 15 ++--------
 libstdc++-v3/include/std/forward_list              |  8 ++---
 libstdc++-v3/include/std/inplace_vector            | 13 ++-------
 libstdc++-v3/include/std/list                      |  8 ++---
 libstdc++-v3/include/std/map                       | 25 +++++++---------
 libstdc++-v3/include/std/set                       | 24 +++++++--------
 libstdc++-v3/include/std/string                    | 11 ++-----
 libstdc++-v3/include/std/unordered_map             | 29 ++++++++----------
 libstdc++-v3/include/std/unordered_set             | 26 +++++++----------
 libstdc++-v3/include/std/vector                    | 15 ++--------
 .../21_strings/basic_string/debug/erase.cc         | 25 ++++++++++++++++
 .../23_containers/forward_list/debug/erase.cc      | 26 +++++++++++++++++
 .../forward_list/debug/invalidation/erase.cc       | 27 +++++++++++++++++
 .../testsuite/23_containers/list/debug/erase.cc    | 29 ++++++++++++++++++
 .../23_containers/list/debug/invalidation/erase.cc | 30 +++++++++++++++++++
 .../testsuite/23_containers/map/debug/erase_if.cc  | 33 +++++++++++++++++++++
 .../map/debug/invalidation/erase_if.cc             | 34 ++++++++++++++++++++++
 .../23_containers/multimap/debug/erase_if.cc       | 33 +++++++++++++++++++++
 .../multimap/debug/invalidation/erase_if.cc        | 34 ++++++++++++++++++++++
 .../23_containers/multiset/debug/erase_if.cc       | 31 ++++++++++++++++++++
 .../multiset/debug/invalidation/erase_if.cc        | 32 ++++++++++++++++++++
 .../testsuite/23_containers/set/debug/erase_if.cc  | 31 ++++++++++++++++++++
 .../set/debug/invalidation/erase_if.cc             | 32 ++++++++++++++++++++
 .../23_containers/unordered_map/debug/erase_if.cc  | 33 +++++++++++++++++++++
 .../unordered_map/debug/invalidation/erase_if.cc   | 34 ++++++++++++++++++++++
 .../unordered_multimap/debug/erase_if.cc           | 33 +++++++++++++++++++++
 .../debug/invalidation/erase_if.cc                 | 34 ++++++++++++++++++++++
 .../unordered_multiset/debug/erase_if.cc           | 31 ++++++++++++++++++++
 .../debug/invalidation/erase_if.cc                 | 32 ++++++++++++++++++++
 .../23_containers/unordered_set/debug/erase_if.cc  | 31 ++++++++++++++++++++
 .../unordered_set/debug/invalidation/erase_if.cc   | 32 ++++++++++++++++++++
 42 files changed, 886 insertions(+), 154 deletions(-)

diff --git a/libstdc++-v3/include/bits/erase_if.h 
b/libstdc++-v3/include/bits/erase_if.h
index a445a53bcfbf..d5a5278d1282 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 b3e72eb30163..9fba4ffc4997 100644
--- a/libstdc++-v3/include/debug/deque
+++ b/libstdc++-v3/include/debug/deque
@@ -778,19 +778,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     inline typename __debug::deque<_Tp, _Alloc>::size_type
     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, __cont._M_base(), std::move(__pred));
     }
 
   template<typename _Tp, typename _Alloc, typename _Up = _Tp>
@@ -798,7 +786,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 1fe3a4f2830b..7d615978000e 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 c7e301efc621..750b0a7343ca 100644
--- a/libstdc++-v3/include/debug/inplace_vector
+++ b/libstdc++-v3/include/debug/inplace_vector
@@ -566,13 +566,13 @@ namespace __debug
       noexcept( noexcept(__x.swap(__y)) )
       { __x.swap(__y); }
 
-    private:
       constexpr _Base&
       _M_base() noexcept { return *this; }
 
       constexpr const _Base&
       _M_base() const noexcept { return *this; }
 
+    private:
       constexpr void
       _M_invalidate_after_nth(difference_type __n) noexcept
       {
@@ -663,17 +663,8 @@ _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, __cont._M_base(),
+                                     std::move(__pred));
        }
 
       return 0;
diff --git a/libstdc++-v3/include/debug/list b/libstdc++-v3/include/debug/list
index 48ec1966d97e..d06e9e4c2f84 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 360325f03ad2..b07c17f2320e 100644
--- a/libstdc++-v3/include/debug/map
+++ b/libstdc++-v3/include/debug/map
@@ -45,4 +45,25 @@ 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)
+    { return __detail::__erase_nodes_if(__cont, __cont._M_base(), __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)
+    { return __detail::__erase_nodes_if(__cont, __cont._M_base(), __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 6645032c349c..508c0cd05fd2 100644
--- a/libstdc++-v3/include/debug/set
+++ b/libstdc++-v3/include/debug/set
@@ -43,4 +43,23 @@ 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)
+    { return __detail::__erase_nodes_if(__cont, __cont._M_base(), __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)
+    { return __detail::__erase_nodes_if(__cont, __cont._M_base(), __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 6d30d7d036ac..d5ee1d9e1938 100644
--- a/libstdc++-v3/include/debug/string
+++ b/libstdc++-v3/include/debug/string
@@ -1331,6 +1331,26 @@ _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)
+    {
+      return __detail::__erase_if(__cont, __cont._M_base(), 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 8e286b733362..4bde18c917b2 100644
--- a/libstdc++-v3/include/debug/unordered_map
+++ b/libstdc++-v3/include/debug/unordered_map
@@ -1748,6 +1748,26 @@ 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)
+    { return __detail::__erase_nodes_if(__cont, __cont._M_base(), __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)
+    { return __detail::__erase_nodes_if(__cont, __cont._M_base(), __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 8951604f03bf..de999a76890e 100644
--- a/libstdc++-v3/include/debug/unordered_set
+++ b/libstdc++-v3/include/debug/unordered_set
@@ -1597,6 +1597,26 @@ 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)
+    { return __detail::__erase_nodes_if(__cont, __cont._M_base(), __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)
+    { return __detail::__erase_nodes_if(__cont, __cont._M_base(), __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 e652260860a2..61e5ff78a7a4 100644
--- a/libstdc++-v3/include/debug/vector
+++ b/libstdc++-v3/include/debug/vector
@@ -1043,19 +1043,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     constexpr typename __debug::vector<_Tp, _Alloc>::size_type
     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, __cont._M_base(), 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 ea426196ca54..3899b68e7367 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 413fcaf3b4c4..ff0c58455cf5 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 df95c1e5c021..c22a9e1f9b40 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 3feff4d7b8b0..a3e7c81680a9 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 b4d39959f0d1..88e549411afd 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 95b9e26a99fb..af6d3814b4b1 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 3748e64964f9..c2b37391fc7a 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 c49c5c6835f5..9166f569ab1d 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 512d542a0b58..157f72ce32df 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 61c750f94ff2..343483e95191 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 000000000000..b381ad157382
--- /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 000000000000..061dfcbd9e31
--- /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 000000000000..15194173cc34
--- /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 000000000000..d6210daf3446
--- /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 000000000000..57137fd08d62
--- /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 000000000000..dfdfc1340fac
--- /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 000000000000..ee080c31160f
--- /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 000000000000..30b6b65e703c
--- /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 000000000000..c9f740ea4e6f
--- /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 000000000000..e54eaa797f87
--- /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 000000000000..c85b76fc506d
--- /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 000000000000..e8c64628a658
--- /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 000000000000..99dde9bfcf29
--- /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 000000000000..e7ac643c8ec5
--- /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 000000000000..303692838ac4
--- /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 000000000000..e8d98c96e6b6
--- /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 000000000000..375393365051
--- /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 000000000000..8969a9dad5f1
--- /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 000000000000..f5ec00e2c1a6
--- /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 000000000000..c725b94558ab
--- /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 000000000000..61c1cffca222
--- /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;
+}

Reply via email to