[PATCH] Fix std::erase_if and std::erase for debug containers

Jonathan Wakely jwakely@redhat.com
Sat Jan 17 12:02:20 GMT 2026


On Thu, 18 Dec 2025 at 22:33 +0100, François Dumont wrote:
>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)

I keep forgetting why we even need this second overload, but it's for
the case where _GLIBCXX_DEBUG is not defined and __gnu_debug::deque is
used explicitly (instead of being used implicitly because std::deque
resolves to it with _GLIBCXX_DEBUG defined).

Maybe it would help me if this overload was guarded with #ifndef
_GLIBCXX_DEBUG and a comment saying that the existing
std::erase_if(deque, p) overload works fine for debug mode. But we
could add that later if I continue being confused.

>     {
>       _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));

It seems like this would be simpler as just:

       return __detail::__erase_if(__cont, __cont._M_base(), std::move(__pred));

I think we could even implement __erase_if so it doesn't need two
references to the container, by using:

     constexpr bool __is_debug_seq
       = __is_base_of(__gnu_debug::_Safe_sequence_base, _Container);

and then using if-constexpr to decide whether to use __cont._M_base()
and __niter_wrap, or just act on __cont directly.

That might make it a little easier to optimize __erase_if for the
non-debug containers, because it would only have one reference and
would not need to use __niter_wrap. But maybe the compiler can already
optimize the extra code away when the references are the same type
and __niter_wrap is the no-op always_inline overload.

I'll think about this later and maybe check the generated code.

OK for trunk.

>     }
>
>   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

Thanks for changing this.

> 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;
>+}



More information about the Libstdc++ mailing list