[libcxx-commits] [libcxx] 3e89508 - [libc++][P1115][C++20] Improving the Return Value of Erase-Like Algorithms II: Free erase/erase if.

Marek Kurdej via libcxx-commits libcxx-commits at lists.llvm.org
Sat May 2 05:05:06 PDT 2020


Author: Marek Kurdej
Date: 2020-05-02T14:04:50+02:00
New Revision: 3e895085de0afdd85574b35de48a1bcc6544f2ec

URL: https://github.com/llvm/llvm-project/commit/3e895085de0afdd85574b35de48a1bcc6544f2ec
DIFF: https://github.com/llvm/llvm-project/commit/3e895085de0afdd85574b35de48a1bcc6544f2ec.diff

LOG: [libc++][P1115][C++20] Improving the Return Value of Erase-Like Algorithms II: Free erase/erase if.

Summary:
This patch adds return type to std::erase and std::erase_if functions.

Also:
* Update __cpp_lib_erase_if to 202002L.
* Fix synopsis in unordered_map.
* Fix generate_feature_test_macro_components.py script.

Reviewers: EricWF, mclow.lists, ldionne, #libc

Reviewed By: ldionne, #libc

Subscribers: broadwaylamb, zoecarver, dexonsmith, ldionne, libcxx-commits

Tags: #libc

Differential Revision: https://reviews.llvm.org/D75905

Added: 
    

Modified: 
    libcxx/docs/FeatureTestMacroTable.rst
    libcxx/include/deque
    libcxx/include/forward_list
    libcxx/include/functional
    libcxx/include/list
    libcxx/include/map
    libcxx/include/set
    libcxx/include/string
    libcxx/include/unordered_map
    libcxx/include/unordered_set
    libcxx/include/vector
    libcxx/include/version
    libcxx/test/std/containers/associative/map/map.erasure/erase_if.pass.cpp
    libcxx/test/std/containers/associative/multimap/multimap.erasure/erase_if.pass.cpp
    libcxx/test/std/containers/associative/multiset/multiset.erasure/erase_if.pass.cpp
    libcxx/test/std/containers/associative/set/set.erasure/erase_if.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.erasure/erase.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.erasure/erase_if.pass.cpp
    libcxx/test/std/containers/sequences/forwardlist/forwardlist.erasure/erase.pass.cpp
    libcxx/test/std/containers/sequences/forwardlist/forwardlist.erasure/erase_if.pass.cpp
    libcxx/test/std/containers/sequences/list/list.erasure/erase.pass.cpp
    libcxx/test/std/containers/sequences/list/list.erasure/erase_if.pass.cpp
    libcxx/test/std/containers/sequences/vector/vector.erasure/erase.pass.cpp
    libcxx/test/std/containers/sequences/vector/vector.erasure/erase_if.pass.cpp
    libcxx/test/std/containers/unord/unord.map/erase_if.pass.cpp
    libcxx/test/std/containers/unord/unord.multimap/erase_if.pass.cpp
    libcxx/test/std/containers/unord/unord.multiset/erase_if.pass.cpp
    libcxx/test/std/containers/unord/unord.set/erase_if.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/deque.version.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/forward_list.version.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/list.version.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/map.version.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/set.version.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/string.version.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/unordered_map.version.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/unordered_set.version.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/vector.version.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
    libcxx/test/std/strings/strings.erasure/erase.pass.cpp
    libcxx/test/std/strings/strings.erasure/erase_if.pass.cpp
    libcxx/utils/generate_feature_test_macro_components.py
    libcxx/www/cxx2a_status.html

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 739e5a4c549f..937683d9cc12 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -186,7 +186,7 @@ Status
     ------------------------------------------------- -----------------
     ``__cpp_lib_endian``                              ``201907L``      
     ------------------------------------------------- -----------------
-    ``__cpp_lib_erase_if``                            ``201811L``      
+    ``__cpp_lib_erase_if``                            ``202002L``      
     ------------------------------------------------- -----------------
     ``__cpp_lib_generic_unordered_lookup``            *unimplemented*  
     ------------------------------------------------- -----------------

diff  --git a/libcxx/include/deque b/libcxx/include/deque
index 115b1b642701..c2ea5f2dbe6d 100644
--- a/libcxx/include/deque
+++ b/libcxx/include/deque
@@ -150,9 +150,11 @@ template <class T, class Allocator>
          noexcept(noexcept(x.swap(y)));
 
 template <class T, class Allocator, class U>
-    void erase(deque<T, Allocator>& c, const U& value);       // C++20
+    typename deque<T, Allocator>::size_type
+    erase(deque<T, Allocator>& c, const U& value);       // C++20
 template <class T, class Allocator, class Predicate>
-    void erase_if(deque<T, Allocator>& c, Predicate pred);    // C++20
+    typename deque<T, Allocator>::size_type
+    erase_if(deque<T, Allocator>& c, Predicate pred);    // C++20
 
 }  // std
 
@@ -3021,14 +3023,20 @@ swap(deque<_Tp, _Allocator>& __x, deque<_Tp, _Allocator>& __y)
 
 #if _LIBCPP_STD_VER > 17
 template <class _Tp, class _Allocator, class _Up>
-inline _LIBCPP_INLINE_VISIBILITY
-void erase(deque<_Tp, _Allocator>& __c, const _Up& __v)
-{ __c.erase(_VSTD::remove(__c.begin(), __c.end(), __v), __c.end()); }
+inline _LIBCPP_INLINE_VISIBILITY typename deque<_Tp, _Allocator>::size_type
+erase(deque<_Tp, _Allocator>& __c, const _Up& __v) {
+  auto __old_size = __c.size();
+  __c.erase(_VSTD::remove(__c.begin(), __c.end(), __v), __c.end());
+  return __old_size - __c.size();
+}
 
 template <class _Tp, class _Allocator, class _Predicate>
-inline _LIBCPP_INLINE_VISIBILITY
-void erase_if(deque<_Tp, _Allocator>& __c, _Predicate __pred)
-{ __c.erase(_VSTD::remove_if(__c.begin(), __c.end(), __pred), __c.end()); }
+inline _LIBCPP_INLINE_VISIBILITY typename deque<_Tp, _Allocator>::size_type
+erase_if(deque<_Tp, _Allocator>& __c, _Predicate __pred) {
+  auto __old_size = __c.size();
+  __c.erase(_VSTD::remove_if(__c.begin(), __c.end(), __pred), __c.end());
+  return __old_size - __c.size();
+}
 #endif
 
 

diff  --git a/libcxx/include/forward_list b/libcxx/include/forward_list
index 3905745931fd..3bd8db8b7d4d 100644
--- a/libcxx/include/forward_list
+++ b/libcxx/include/forward_list
@@ -169,9 +169,11 @@ template <class T, class Allocator>
          noexcept(noexcept(x.swap(y)));
 
 template <class T, class Allocator, class U>
-    void erase(forward_list<T, Allocator>& c, const U& value);       // C++20
+    typename forward_list<T, Allocator>::size_type
+    erase(forward_list<T, Allocator>& c, const U& value);       // C++20
 template <class T, class Allocator, class Predicate>
-    void erase_if(forward_list<T, Allocator>& c, Predicate pred);    // C++20
+    typename forward_list<T, Allocator>::size_type
+    erase_if(forward_list<T, Allocator>& c, Predicate pred);    // C++20
 
 }  // std
 
@@ -1765,13 +1767,17 @@ swap(forward_list<_Tp, _Alloc>& __x, forward_list<_Tp, _Alloc>& __y)
 #if _LIBCPP_STD_VER > 17
 template <class _Tp, class _Allocator, class _Predicate>
 inline _LIBCPP_INLINE_VISIBILITY
-void erase_if(forward_list<_Tp, _Allocator>& __c, _Predicate __pred)
-{ __c.remove_if(__pred); }
+    typename forward_list<_Tp, _Allocator>::size_type
+    erase_if(forward_list<_Tp, _Allocator>& __c, _Predicate __pred) {
+  return __c.remove_if(__pred);
+}
 
 template <class _Tp, class _Allocator, class _Up>
 inline _LIBCPP_INLINE_VISIBILITY
-void erase(forward_list<_Tp, _Allocator>& __c, const _Up& __v)
-{ _VSTD::erase_if(__c, [&](auto& __elem) { return __elem == __v; }); }
+    typename forward_list<_Tp, _Allocator>::size_type
+    erase(forward_list<_Tp, _Allocator>& __c, const _Up& __v) {
+  return _VSTD::erase_if(__c, [&](auto& __elem) { return __elem == __v; });
+}
 #endif
 
 _LIBCPP_END_NAMESPACE_STD

diff  --git a/libcxx/include/functional b/libcxx/include/functional
index 62b7d097be63..67be9ee86a64 100644
--- a/libcxx/include/functional
+++ b/libcxx/include/functional
@@ -3163,15 +3163,19 @@ using unwrap_ref_decay_t = typename unwrap_ref_decay<_Tp>::type;
 #endif // > C++17
 
 template <class _Container, class _Predicate>
-inline void __libcpp_erase_if_container( _Container& __c, _Predicate __pred)
-{
-	for (typename _Container::iterator __iter = __c.begin(), __last = __c.end(); __iter != __last;)
-	{
-		if (__pred(*__iter))
-			__iter = __c.erase(__iter);
-		else
-			++__iter;
-	}
+inline typename _Container::size_type
+__libcpp_erase_if_container(_Container& __c, _Predicate __pred) {
+  typename _Container::size_type __old_size = __c.size();
+
+  const typename _Container::iterator __last = __c.end();
+  for (typename _Container::iterator __iter = __c.begin(); __iter != __last;) {
+    if (__pred(*__iter))
+      __iter = __c.erase(__iter);
+    else
+      ++__iter;
+  }
+
+  return __old_size - __c.size();
 }
 
 _LIBCPP_END_NAMESPACE_STD

diff  --git a/libcxx/include/list b/libcxx/include/list
index ae318ead31da..55b45f1a67d4 100644
--- a/libcxx/include/list
+++ b/libcxx/include/list
@@ -170,9 +170,11 @@ template <class T, class Alloc>
          noexcept(noexcept(x.swap(y)));
 
 template <class T, class Allocator, class U>
-    void erase(list<T, Allocator>& c, const U& value);       // C++20
+    typename list<T, Allocator>::size_type
+    erase(list<T, Allocator>& c, const U& value);       // C++20
 template <class T, class Allocator, class Predicate>
-    void erase_if(list<T, Allocator>& c, Predicate pred);    // C++20
+    typename list<T, Allocator>::size_type
+    erase_if(list<T, Allocator>& c, Predicate pred);    // C++20
 
 }  // std
 
@@ -2471,14 +2473,16 @@ swap(list<_Tp, _Alloc>& __x, list<_Tp, _Alloc>& __y)
 
 #if _LIBCPP_STD_VER > 17
 template <class _Tp, class _Allocator, class _Predicate>
-inline _LIBCPP_INLINE_VISIBILITY
-void erase_if(list<_Tp, _Allocator>& __c, _Predicate __pred)
-{ __c.remove_if(__pred); }
+inline _LIBCPP_INLINE_VISIBILITY typename list<_Tp, _Allocator>::size_type
+erase_if(list<_Tp, _Allocator>& __c, _Predicate __pred) {
+  return __c.remove_if(__pred);
+}
 
 template <class _Tp, class _Allocator, class _Up>
-inline _LIBCPP_INLINE_VISIBILITY
-void erase(list<_Tp, _Allocator>& __c, const _Up& __v)
-{ _VSTD::erase_if(__c, [&](auto& __elem) { return __elem == __v; }); }
+inline _LIBCPP_INLINE_VISIBILITY typename list<_Tp, _Allocator>::size_type
+erase(list<_Tp, _Allocator>& __c, const _Up& __v) {
+  return _VSTD::erase_if(__c, [&](auto& __elem) { return __elem == __v; });
+}
 #endif
 
 _LIBCPP_END_NAMESPACE_STD

diff  --git a/libcxx/include/map b/libcxx/include/map
index b6f89bf5ee54..d2b82591368b 100644
--- a/libcxx/include/map
+++ b/libcxx/include/map
@@ -254,7 +254,8 @@ swap(map<Key, T, Compare, Allocator>& x, map<Key, T, Compare, Allocator>& y)
     noexcept(noexcept(x.swap(y)));
 
 template <class Key, class T, class Compare, class Allocator, class Predicate>
-  void erase_if(map<Key, T, Compare, Allocator>& c, Predicate pred);  // C++20
+typename map<Key, T, Compare, Allocator>::size_type
+erase_if(map<Key, T, Compare, Allocator>& c, Predicate pred);  // C++20
 
 
 template <class Key, class T, class Compare = less<Key>,
@@ -469,7 +470,8 @@ swap(multimap<Key, T, Compare, Allocator>& x,
     noexcept(noexcept(x.swap(y)));
 
 template <class Key, class T, class Compare, class Allocator, class Predicate>
-  void erase_if(multimap<Key, T, Compare, Allocator>& c, Predicate pred);  // C++20
+typename multimap<Key, T, Compare, Allocator>::size_type
+erase_if(multimap<Key, T, Compare, Allocator>& c, Predicate pred);  // C++20
 
 }  // std
 
@@ -1653,10 +1655,13 @@ swap(map<_Key, _Tp, _Compare, _Allocator>& __x,
 }
 
 #if _LIBCPP_STD_VER > 17
-template <class _Key, class _Tp, class _Compare, class _Allocator, class _Predicate>
+template <class _Key, class _Tp, class _Compare, class _Allocator,
+          class _Predicate>
 inline _LIBCPP_INLINE_VISIBILITY
-void erase_if(map<_Key, _Tp, _Compare, _Allocator>& __c, _Predicate __pred)
-{ __libcpp_erase_if_container(__c, __pred); }
+    typename map<_Key, _Tp, _Compare, _Allocator>::size_type
+    erase_if(map<_Key, _Tp, _Compare, _Allocator>& __c, _Predicate __pred) {
+  return __libcpp_erase_if_container(__c, __pred);
+}
 #endif
 
 
@@ -2235,10 +2240,14 @@ swap(multimap<_Key, _Tp, _Compare, _Allocator>& __x,
 }
 
 #if _LIBCPP_STD_VER > 17
-template <class _Key, class _Tp, class _Compare, class _Allocator, class _Predicate>
+template <class _Key, class _Tp, class _Compare, class _Allocator,
+          class _Predicate>
 inline _LIBCPP_INLINE_VISIBILITY
-void erase_if(multimap<_Key, _Tp, _Compare, _Allocator>& __c, _Predicate __pred)
-{ __libcpp_erase_if_container(__c, __pred); }
+    typename multimap<_Key, _Tp, _Compare, _Allocator>::size_type
+    erase_if(multimap<_Key, _Tp, _Compare, _Allocator>& __c,
+             _Predicate __pred) {
+  return __libcpp_erase_if_container(__c, __pred);
+}
 #endif
 
 _LIBCPP_END_NAMESPACE_STD

diff  --git a/libcxx/include/set b/libcxx/include/set
index ac3fbbe02fc3..d58455bfe219 100644
--- a/libcxx/include/set
+++ b/libcxx/include/set
@@ -216,7 +216,8 @@ swap(set<Key, Compare, Allocator>& x, set<Key, Compare, Allocator>& y)
     noexcept(noexcept(x.swap(y)));
 
 template <class Key, class Compare, class Allocator, class Predicate>
-  void erase_if(set<Key, Compare, Allocator>& c, Predicate pred);  // C++20
+typename set<Key, Compare, Allocator>::size_type
+erase_if(set<Key, Compare, Allocator>& c, Predicate pred);  // C++20
 
 template <class Key, class Compare = less<Key>,
           class Allocator = allocator<Key>>
@@ -417,7 +418,8 @@ swap(multiset<Key, Compare, Allocator>& x, multiset<Key, Compare, Allocator>& y)
     noexcept(noexcept(x.swap(y)));
 
 template <class Key, class Compare, class Allocator, class Predicate>
-  void erase_if(multiset<Key, Compare, Allocator>& c, Predicate pred);  // C++20
+typename multiset<Key, Compare, Allocator>::size_type
+erase_if(multiset<Key, Compare, Allocator>& c, Predicate pred);  // C++20
 
 }  // std
 
@@ -960,8 +962,10 @@ swap(set<_Key, _Compare, _Allocator>& __x,
 #if _LIBCPP_STD_VER > 17
 template <class _Key, class _Compare, class _Allocator, class _Predicate>
 inline _LIBCPP_INLINE_VISIBILITY
-void erase_if(set<_Key, _Compare, _Allocator>& __c, _Predicate __pred)
-{ __libcpp_erase_if_container(__c, __pred); }
+    typename set<_Key, _Compare, _Allocator>::size_type
+    erase_if(set<_Key, _Compare, _Allocator>& __c, _Predicate __pred) {
+  return __libcpp_erase_if_container(__c, __pred);
+}
 #endif
 
 template <class _Key, class _Compare = less<_Key>,
@@ -1484,8 +1488,10 @@ swap(multiset<_Key, _Compare, _Allocator>& __x,
 #if _LIBCPP_STD_VER > 17
 template <class _Key, class _Compare, class _Allocator, class _Predicate>
 inline _LIBCPP_INLINE_VISIBILITY
-void erase_if(multiset<_Key, _Compare, _Allocator>& __c, _Predicate __pred)
-{ __libcpp_erase_if_container(__c, __pred); }
+    typename multiset<_Key, _Compare, _Allocator>::size_type
+    erase_if(multiset<_Key, _Compare, _Allocator>& __c, _Predicate __pred) {
+  return __libcpp_erase_if_container(__c, __pred);
+}
 #endif
 
 _LIBCPP_END_NAMESPACE_STD

diff  --git a/libcxx/include/string b/libcxx/include/string
index 6938ee48b0f8..179080dbb579 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -437,9 +437,11 @@ basic_istream<charT, traits>&
 getline(basic_istream<charT, traits>& is, basic_string<charT, traits, Allocator>& str);
 
 template<class charT, class traits, class Allocator, class U>
-void erase(basic_string<charT, traits, Allocator>& c, const U& value); // C++20
+typename basic_string<charT, traits, Allocator>::size_type
+erase(basic_string<charT, traits, Allocator>& c, const U& value);    // C++20
 template<class charT, class traits, class Allocator, class Predicate>
-void erase_if(basic_string<charT, traits, Allocator>& c, Predicate pred); // C++20
+typename basic_string<charT, traits, Allocator>::size_type
+erase_if(basic_string<charT, traits, Allocator>& c, Predicate pred); // C++20
 
 typedef basic_string<char>    string;
 typedef basic_string<wchar_t> wstring;
@@ -4379,15 +4381,25 @@ getline(basic_istream<_CharT, _Traits>&& __is,
 #endif  // _LIBCPP_CXX03_LANG
 
 #if _LIBCPP_STD_VER > 17
-template<class _CharT, class _Traits, class _Allocator, class _Up>
+template <class _CharT, class _Traits, class _Allocator, class _Up>
 inline _LIBCPP_INLINE_VISIBILITY
-void erase(basic_string<_CharT, _Traits, _Allocator>& __str, const _Up& __v)
-{ __str.erase(_VSTD::remove(__str.begin(), __str.end(), __v), __str.end()); }
+    typename basic_string<_CharT, _Traits, _Allocator>::size_type
+    erase(basic_string<_CharT, _Traits, _Allocator>& __str, const _Up& __v) {
+  auto __old_size = __str.size();
+  __str.erase(_VSTD::remove(__str.begin(), __str.end(), __v), __str.end());
+  return __old_size - __str.size();
+}
 
-template<class _CharT, class _Traits, class _Allocator, class _Predicate>
+template <class _CharT, class _Traits, class _Allocator, class _Predicate>
 inline _LIBCPP_INLINE_VISIBILITY
-void erase_if(basic_string<_CharT, _Traits, _Allocator>& __str, _Predicate __pred)
-{ __str.erase(_VSTD::remove_if(__str.begin(), __str.end(), __pred), __str.end()); }
+    typename basic_string<_CharT, _Traits, _Allocator>::size_type
+    erase_if(basic_string<_CharT, _Traits, _Allocator>& __str,
+             _Predicate __pred) {
+  auto __old_size = __str.size();
+  __str.erase(_VSTD::remove_if(__str.begin(), __str.end(), __pred),
+              __str.end());
+  return __old_size - __str.size();
+}
 #endif
 
 #if _LIBCPP_DEBUG_LEVEL >= 2

diff  --git a/libcxx/include/unordered_map b/libcxx/include/unordered_map
index ad17f776c938..6156cfddd7bd 100644
--- a/libcxx/include/unordered_map
+++ b/libcxx/include/unordered_map
@@ -386,10 +386,12 @@ template <class Key, class T, class Hash, class Pred, class Alloc>
               noexcept(noexcept(x.swap(y)));
 
 template <class K, class T, class H, class P, class A, class Predicate>
-    void erase_if(unordered_set<K, T, H, P, A>& c, Predicate pred);       // C++20
+    typename unordered_map<K, T, H, P, A>::size_type
+    erase_if(unordered_map<K, T, H, P, A>& c, Predicate pred);       // C++20
 
 template <class K, class T, class H, class P, class A, class Predicate>
-    void erase_if(unordered_multiset<K, T, H, P, A>& c, Predicate pred);  // C++20
+    typename unordered_multimap<K, T, H, P, A>::size_type
+    erase_if(unordered_multimap<K, T, H, P, A>& c, Predicate pred);  // C++20
 
 template <class Key, class T, class Hash, class Pred, class Alloc>
     bool
@@ -1704,10 +1706,14 @@ swap(unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __x,
 }
 
 #if _LIBCPP_STD_VER > 17
-template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc, class _Predicate>
+template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc,
+          class _Predicate>
 inline _LIBCPP_INLINE_VISIBILITY
-void erase_if(unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __c, _Predicate __pred)
-{ __libcpp_erase_if_container(__c, __pred); }
+    typename unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::size_type
+    erase_if(unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __c,
+             _Predicate __pred) {
+  return __libcpp_erase_if_container(__c, __pred);
+}
 #endif
 
 template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
@@ -2402,10 +2408,14 @@ swap(unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>& __x,
 }
 
 #if _LIBCPP_STD_VER > 17
-template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc, class _Predicate>
+template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc,
+          class _Predicate>
 inline _LIBCPP_INLINE_VISIBILITY
-void erase_if(unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>& __c, _Predicate __pred)
-{ __libcpp_erase_if_container(__c, __pred); }
+    typename unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::size_type
+    erase_if(unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>& __c,
+             _Predicate __pred) {
+  return __libcpp_erase_if_container(__c, __pred);
+}
 #endif
 
 template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>

diff  --git a/libcxx/include/unordered_set b/libcxx/include/unordered_set
index 68f777a4ea3e..6c4ad938006f 100644
--- a/libcxx/include/unordered_set
+++ b/libcxx/include/unordered_set
@@ -341,10 +341,12 @@ template <class Value, class Hash, class Pred, class Alloc>
               noexcept(noexcept(x.swap(y)));
 
 template <class K, class T, class H, class P, class A, class Predicate>
-    void erase_if(unordered_set<K, T, H, P, A>& c, Predicate pred);       // C++20
+    typename unordered_set<K, T, H, P, A>::size_type
+    erase_if(unordered_set<K, T, H, P, A>& c, Predicate pred);       // C++20
 
 template <class K, class T, class H, class P, class A, class Predicate>
-    void erase_if(unordered_multiset<K, T, H, P, A>& c, Predicate pred);  // C++20
+    typename unordered_multiset<K, T, H, P, A>::size_type
+    erase_if(unordered_multiset<K, T, H, P, A>& c, Predicate pred);  // C++20
 
 
 template <class Value, class Hash, class Pred, class Alloc>
@@ -1006,10 +1008,14 @@ swap(unordered_set<_Value, _Hash, _Pred, _Alloc>& __x,
 }
 
 #if _LIBCPP_STD_VER > 17
-template <class _Value, class _Hash, class _Pred, class _Alloc, class _Predicate>
+template <class _Value, class _Hash, class _Pred, class _Alloc,
+          class _Predicate>
 inline _LIBCPP_INLINE_VISIBILITY
-void erase_if(unordered_set<_Value, _Hash, _Pred, _Alloc>& __c, _Predicate __pred)
-{ __libcpp_erase_if_container(__c, __pred); }
+    typename unordered_set<_Value, _Hash, _Pred, _Alloc>::size_type
+    erase_if(unordered_set<_Value, _Hash, _Pred, _Alloc>& __c,
+             _Predicate __pred) {
+  return __libcpp_erase_if_container(__c, __pred);
+}
 #endif
 
 template <class _Value, class _Hash, class _Pred, class _Alloc>
@@ -1637,10 +1643,14 @@ swap(unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __x,
 }
 
 #if _LIBCPP_STD_VER > 17
-template <class _Value, class _Hash, class _Pred, class _Alloc, class _Predicate>
+template <class _Value, class _Hash, class _Pred, class _Alloc,
+          class _Predicate>
 inline _LIBCPP_INLINE_VISIBILITY
-void erase_if(unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __c, _Predicate __pred)
-{ __libcpp_erase_if_container(__c, __pred); }
+    typename unordered_multiset<_Value, _Hash, _Pred, _Alloc>::size_type
+    erase_if(unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __c,
+             _Predicate __pred) {
+  return __libcpp_erase_if_container(__c, __pred);
+}
 #endif
 
 template <class _Value, class _Hash, class _Pred, class _Alloc>

diff  --git a/libcxx/include/vector b/libcxx/include/vector
index af96bffb069c..7d0fec87c4fa 100644
--- a/libcxx/include/vector
+++ b/libcxx/include/vector
@@ -261,9 +261,11 @@ void swap(vector<T,Allocator>& x, vector<T,Allocator>& y)
     noexcept(noexcept(x.swap(y)));
 
 template <class T, class Allocator, class U>
-    void erase(vector<T, Allocator>& c, const U& value);       // C++20
+typename vector<T, Allocator>::size_type
+erase(vector<T, Allocator>& c, const U& value);       // C++20
 template <class T, class Allocator, class Predicate>
-    void erase_if(vector<T, Allocator>& c, Predicate pred);    // C++20
+typename vector<T, Allocator>::size_type
+erase_if(vector<T, Allocator>& c, Predicate pred);    // C++20
 
 }  // std
 
@@ -3389,14 +3391,20 @@ swap(vector<_Tp, _Allocator>& __x, vector<_Tp, _Allocator>& __y)
 
 #if _LIBCPP_STD_VER > 17
 template <class _Tp, class _Allocator, class _Up>
-inline _LIBCPP_INLINE_VISIBILITY
-void erase(vector<_Tp, _Allocator>& __c, const _Up& __v)
-{ __c.erase(_VSTD::remove(__c.begin(), __c.end(), __v), __c.end()); }
+inline _LIBCPP_INLINE_VISIBILITY typename vector<_Tp, _Allocator>::size_type
+erase(vector<_Tp, _Allocator>& __c, const _Up& __v) {
+  auto __old_size = __c.size();
+  __c.erase(_VSTD::remove(__c.begin(), __c.end(), __v), __c.end());
+  return __old_size - __c.size();
+}
 
 template <class _Tp, class _Allocator, class _Predicate>
-inline _LIBCPP_INLINE_VISIBILITY
-void erase_if(vector<_Tp, _Allocator>& __c, _Predicate __pred)
-{ __c.erase(_VSTD::remove_if(__c.begin(), __c.end(), __pred), __c.end()); }
+inline _LIBCPP_INLINE_VISIBILITY typename vector<_Tp, _Allocator>::size_type
+erase_if(vector<_Tp, _Allocator>& __c, _Predicate __pred) {
+  auto __old_size = __c.size();
+  __c.erase(_VSTD::remove_if(__c.begin(), __c.end(), __pred), __c.end());
+  return __old_size - __c.size();
+}
 #endif
 
 _LIBCPP_END_NAMESPACE_STD

diff  --git a/libcxx/include/version b/libcxx/include/version
index ab62a853ceb5..c2e99ccd9a90 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -44,7 +44,7 @@ __cpp_lib_constexpr_swap_algorithms                     201806L <algorithm>
 __cpp_lib_destroying_delete                             201806L <new>
 __cpp_lib_enable_shared_from_this                       201603L <memory>
 __cpp_lib_endian                                        201907L <bit>
-__cpp_lib_erase_if                                      201811L <string> <deque> <forward_list>
+__cpp_lib_erase_if                                      202002L <string> <deque> <forward_list>
                                                                 <list> <vector> <map>
                                                                 <set> <unordered_map> <unordered_set>
 __cpp_lib_exchange_function                             201304L <utility>
@@ -226,7 +226,7 @@ __cpp_lib_void_t                                        201411L <type_traits>
 #   define __cpp_lib_destroying_delete                  201806L
 # endif
 # define __cpp_lib_endian                               201907L
-# define __cpp_lib_erase_if                             201811L
+# define __cpp_lib_erase_if                             202002L
 // # define __cpp_lib_generic_unordered_lookup             201811L
 # define __cpp_lib_interpolate                          201902L
 # if !defined(_LIBCPP_HAS_NO_BUILTIN_IS_CONSTANT_EVALUATED)

diff  --git a/libcxx/test/std/containers/associative/map/map.erasure/erase_if.pass.cpp b/libcxx/test/std/containers/associative/map/map.erasure/erase_if.pass.cpp
index af2d35c66ec0..c890936ebd70 100644
--- a/libcxx/test/std/containers/associative/map/map.erasure/erase_if.pass.cpp
+++ b/libcxx/test/std/containers/associative/map/map.erasure/erase_if.pass.cpp
@@ -10,7 +10,8 @@
 // <map>
 
 // template <class Key, class T, class Compare, class Allocator, class Predicate>
-//   void erase_if(map<Key, T, Compare, Allocator>& c, Predicate pred);
+//   typename map<Key, T, Compare, Allocator>::size_type
+//   erase_if(map<Key, T, Compare, Allocator>& c, Predicate pred);
 
 #include <map>
 
@@ -29,13 +30,11 @@ M make (Init vals)
 }
 
 template <typename M, typename Pred>
-void
-test0(Init vals, Pred p, Init expected)
-{
-    M s = make<M> (vals);
-    ASSERT_SAME_TYPE(void, decltype(std::erase_if(s, p)));
-    std::erase_if(s, p);
-    assert(s == make<M>(expected));
+void test0(Init vals, Pred p, Init expected, size_t expected_erased_count) {
+  M s = make<M>(vals);
+  ASSERT_SAME_TYPE(typename M::size_type, decltype(std::erase_if(s, p)));
+  assert(expected_erased_count == std::erase_if(s, p));
+  assert(s == make<M>(expected));
 }
 
 template <typename S>
@@ -48,22 +47,22 @@ void test()
     auto True  = [](auto) { return true; };
     auto False = [](auto) { return false; };
 
-    test0<S>({}, is1, {});
+    test0<S>({}, is1, {}, 0);
 
-    test0<S>({1}, is1, {});
-    test0<S>({1}, is2, {1});
+    test0<S>({1}, is1, {}, 1);
+    test0<S>({1}, is2, {1}, 0);
 
-    test0<S>({1,2}, is1, {2});
-    test0<S>({1,2}, is2, {1});
-    test0<S>({1,2}, is3, {1,2});
+    test0<S>({1, 2}, is1, {2}, 1);
+    test0<S>({1, 2}, is2, {1}, 1);
+    test0<S>({1, 2}, is3, {1, 2}, 0);
 
-    test0<S>({1,2,3}, is1, {2,3});
-    test0<S>({1,2,3}, is2, {1,3});
-    test0<S>({1,2,3}, is3, {1,2});
-    test0<S>({1,2,3}, is4, {1,2,3});
+    test0<S>({1, 2, 3}, is1, {2, 3}, 1);
+    test0<S>({1, 2, 3}, is2, {1, 3}, 1);
+    test0<S>({1, 2, 3}, is3, {1, 2}, 1);
+    test0<S>({1, 2, 3}, is4, {1, 2, 3}, 0);
 
-    test0<S>({1,2,3}, True,  {});
-    test0<S>({1,2,3}, False, {1,2,3});
+    test0<S>({1, 2, 3}, True, {}, 3);
+    test0<S>({1, 2, 3}, False, {1, 2, 3}, 0);
 }
 
 int main(int, char**)

diff  --git a/libcxx/test/std/containers/associative/multimap/multimap.erasure/erase_if.pass.cpp b/libcxx/test/std/containers/associative/multimap/multimap.erasure/erase_if.pass.cpp
index 6f2d56a9730d..d573c2ef3f51 100644
--- a/libcxx/test/std/containers/associative/multimap/multimap.erasure/erase_if.pass.cpp
+++ b/libcxx/test/std/containers/associative/multimap/multimap.erasure/erase_if.pass.cpp
@@ -9,8 +9,9 @@
 
 // <map>
 
-//   template <class Key, class T, class Compare, class Allocator, class Predicate>
-//     void erase_if(multimap<Key, T, Compare, Allocator>& c, Predicate pred);
+// template <class Key, class T, class Compare, class Allocator, class Predicate>
+//   typename multimap<Key, T, Compare, Allocator>::size_type
+//   erase_if(multimap<Key, T, Compare, Allocator>& c, Predicate pred);
 
 #include <map>
 
@@ -29,13 +30,11 @@ M make (Init vals)
 }
 
 template <typename M, typename Pred>
-void
-test0(Init vals, Pred p, Init expected)
-{
-    M s = make<M> (vals);
-    ASSERT_SAME_TYPE(void, decltype(std::erase_if(s, p)));
-    std::erase_if(s, p);
-    assert(s == make<M>(expected));
+void test0(Init vals, Pred p, Init expected, size_t expected_erased_count) {
+  M s = make<M>(vals);
+  ASSERT_SAME_TYPE(typename M::size_type, decltype(std::erase_if(s, p)));
+  assert(expected_erased_count == std::erase_if(s, p));
+  assert(s == make<M>(expected));
 }
 
 template <typename S>
@@ -48,33 +47,33 @@ void test()
     auto True  = [](auto) { return true; };
     auto False = [](auto) { return false; };
 
-    test0<S>({}, is1, {});
-
-    test0<S>({1}, is1, {});
-    test0<S>({1}, is2, {1});
-
-    test0<S>({1,2}, is1, {2});
-    test0<S>({1,2}, is2, {1});
-    test0<S>({1,2}, is3, {1,2});
-    test0<S>({1,1}, is1, {});
-    test0<S>({1,1}, is3, {1,1});
-
-    test0<S>({1,2,3}, is1, {2,3});
-    test0<S>({1,2,3}, is2, {1,3});
-    test0<S>({1,2,3}, is3, {1,2});
-    test0<S>({1,2,3}, is4, {1,2,3});
-
-    test0<S>({1,1,1}, is1, {});
-    test0<S>({1,1,1}, is2, {1,1,1});
-    test0<S>({1,1,2}, is1, {2});
-    test0<S>({1,1,2}, is2, {1,1});
-    test0<S>({1,1,2}, is3, {1,1,2});
-    test0<S>({1,2,2}, is1, {2,2});
-    test0<S>({1,2,2}, is2, {1});
-    test0<S>({1,2,2}, is3, {1,2,2});
-
-    test0<S>({1,2,3}, True,  {});
-    test0<S>({1,2,3}, False, {1,2,3});
+    test0<S>({}, is1, {}, 0);
+
+    test0<S>({1}, is1, {}, 1);
+    test0<S>({1}, is2, {1}, 0);
+
+    test0<S>({1, 2}, is1, {2}, 1);
+    test0<S>({1, 2}, is2, {1}, 1);
+    test0<S>({1, 2}, is3, {1, 2}, 0);
+    test0<S>({1, 1}, is1, {}, 2);
+    test0<S>({1, 1}, is3, {1, 1}, 0);
+
+    test0<S>({1, 2, 3}, is1, {2, 3}, 1);
+    test0<S>({1, 2, 3}, is2, {1, 3}, 1);
+    test0<S>({1, 2, 3}, is3, {1, 2}, 1);
+    test0<S>({1, 2, 3}, is4, {1, 2, 3}, 0);
+
+    test0<S>({1, 1, 1}, is1, {}, 3);
+    test0<S>({1, 1, 1}, is2, {1, 1, 1}, 0);
+    test0<S>({1, 1, 2}, is1, {2}, 2);
+    test0<S>({1, 1, 2}, is2, {1, 1}, 1);
+    test0<S>({1, 1, 2}, is3, {1, 1, 2}, 0);
+    test0<S>({1, 2, 2}, is1, {2, 2}, 1);
+    test0<S>({1, 2, 2}, is2, {1}, 2);
+    test0<S>({1, 2, 2}, is3, {1, 2, 2}, 0);
+
+    test0<S>({1, 2, 3}, True, {}, 3);
+    test0<S>({1, 2, 3}, False, {1, 2, 3}, 0);
 }
 
 int main(int, char**)

diff  --git a/libcxx/test/std/containers/associative/multiset/multiset.erasure/erase_if.pass.cpp b/libcxx/test/std/containers/associative/multiset/multiset.erasure/erase_if.pass.cpp
index 1591fa1f2f81..73b451a1314f 100644
--- a/libcxx/test/std/containers/associative/multiset/multiset.erasure/erase_if.pass.cpp
+++ b/libcxx/test/std/containers/associative/multiset/multiset.erasure/erase_if.pass.cpp
@@ -10,7 +10,8 @@
 // <set>
 
 // template <class T, class Compare, class Allocator, class Predicate>
-//   void erase_if(multiset<T, Compare, Allocator>& c, Predicate pred);
+//   typename multiset<T, Compare, Allocator>::size_type
+//   erase_if(multiset<T, Compare, Allocator>& c, Predicate pred);
 
 #include <set>
 
@@ -19,12 +20,10 @@
 #include "min_allocator.h"
 
 template <class S, class Pred>
-void
-test0(S s, Pred p, S expected)
-{
-    ASSERT_SAME_TYPE(void, decltype(std::erase_if(s, p)));
-    std::erase_if(s, p);
-    assert(s == expected);
+void test0(S s, Pred p, S expected, size_t expected_erased_count) {
+  ASSERT_SAME_TYPE(typename S::size_type, decltype(std::erase_if(s, p)));
+  assert(expected_erased_count == std::erase_if(s, p));
+  assert(s == expected);
 }
 
 template <typename S>
@@ -37,33 +36,33 @@ void test()
     auto True  = [](auto) { return true; };
     auto False = [](auto) { return false; };
 
-    test0(S(), is1, S());
+    test0(S(), is1, S(), 0);
 
-    test0(S({1}), is1, S());
-    test0(S({1}), is2, S({1}));
+    test0(S({1}), is1, S(), 1);
+    test0(S({1}), is2, S({1}), 0);
 
-    test0(S({1,2}), is1, S({2}));
-    test0(S({1,2}), is2, S({1}));
-    test0(S({1,2}), is3, S({1,2}));
-    test0(S({1,1}), is1, S());
-    test0(S({1,1}), is3, S({1,1}));
+    test0(S({1, 2}), is1, S({2}), 1);
+    test0(S({1, 2}), is2, S({1}), 1);
+    test0(S({1, 2}), is3, S({1, 2}), 0);
+    test0(S({1, 1}), is1, S(), 2);
+    test0(S({1, 1}), is3, S({1, 1}), 0);
 
-    test0(S({1,2,3}), is1, S({2,3}));
-    test0(S({1,2,3}), is2, S({1,3}));
-    test0(S({1,2,3}), is3, S({1,2}));
-    test0(S({1,2,3}), is4, S({1,2,3}));
+    test0(S({1, 2, 3}), is1, S({2, 3}), 1);
+    test0(S({1, 2, 3}), is2, S({1, 3}), 1);
+    test0(S({1, 2, 3}), is3, S({1, 2}), 1);
+    test0(S({1, 2, 3}), is4, S({1, 2, 3}), 0);
 
-    test0(S({1,1,1}), is1, S());
-    test0(S({1,1,1}), is2, S({1,1,1}));
-    test0(S({1,1,2}), is1, S({2}));
-    test0(S({1,1,2}), is2, S({1,1}));
-    test0(S({1,1,2}), is3, S({1,1,2}));
-    test0(S({1,2,2}), is1, S({2,2}));
-    test0(S({1,2,2}), is2, S({1}));
-    test0(S({1,2,2}), is3, S({1,2,2}));
+    test0(S({1, 1, 1}), is1, S(), 3);
+    test0(S({1, 1, 1}), is2, S({1, 1, 1}), 0);
+    test0(S({1, 1, 2}), is1, S({2}), 2);
+    test0(S({1, 1, 2}), is2, S({1, 1}), 1);
+    test0(S({1, 1, 2}), is3, S({1, 1, 2}), 0);
+    test0(S({1, 2, 2}), is1, S({2, 2}), 1);
+    test0(S({1, 2, 2}), is2, S({1}), 2);
+    test0(S({1, 2, 2}), is3, S({1, 2, 2}), 0);
 
-    test0(S({1,2,3}), True,  S());
-    test0(S({1,2,3}), False, S({1,2,3}));
+    test0(S({1, 2, 3}), True, S(), 3);
+    test0(S({1, 2, 3}), False, S({1, 2, 3}), 0);
 }
 
 int main(int, char**)

diff  --git a/libcxx/test/std/containers/associative/set/set.erasure/erase_if.pass.cpp b/libcxx/test/std/containers/associative/set/set.erasure/erase_if.pass.cpp
index 519db6d6f4a1..933fc4348c0f 100644
--- a/libcxx/test/std/containers/associative/set/set.erasure/erase_if.pass.cpp
+++ b/libcxx/test/std/containers/associative/set/set.erasure/erase_if.pass.cpp
@@ -10,7 +10,8 @@
 // <set>
 
 // template <class T, class Compare, class Allocator, class Predicate>
-//   void erase_if(set<T, Compare, Allocator>& c, Predicate pred);
+//   typename set<T, Compare, Allocator>::size_type
+//   erase_if(set<T, Compare, Allocator>& c, Predicate pred);
 
 #include <set>
 
@@ -19,12 +20,10 @@
 #include "min_allocator.h"
 
 template <class S, class Pred>
-void
-test0(S s, Pred p, S expected)
-{
-    ASSERT_SAME_TYPE(void, decltype(std::erase_if(s, p)));
-    std::erase_if(s, p);
-    assert(s == expected);
+void test0(S s, Pred p, S expected, size_t expected_erased_count) {
+  ASSERT_SAME_TYPE(typename S::size_type, decltype(std::erase_if(s, p)));
+  assert(expected_erased_count == std::erase_if(s, p));
+  assert(s == expected);
 }
 
 template <typename S>
@@ -37,22 +36,22 @@ void test()
     auto True  = [](auto) { return true; };
     auto False = [](auto) { return false; };
 
-    test0(S(), is1, S());
+    test0(S(), is1, S(), 0);
 
-    test0(S({1}), is1, S());
-    test0(S({1}), is2, S({1}));
+    test0(S({1}), is1, S(), 1);
+    test0(S({1}), is2, S({1}), 0);
 
-    test0(S({1,2}), is1, S({2}));
-    test0(S({1,2}), is2, S({1}));
-    test0(S({1,2}), is3, S({1,2}));
+    test0(S({1, 2}), is1, S({2}), 1);
+    test0(S({1, 2}), is2, S({1}), 1);
+    test0(S({1, 2}), is3, S({1, 2}), 0);
 
-    test0(S({1,2,3}), is1, S({2,3}));
-    test0(S({1,2,3}), is2, S({1,3}));
-    test0(S({1,2,3}), is3, S({1,2}));
-    test0(S({1,2,3}), is4, S({1,2,3}));
+    test0(S({1, 2, 3}), is1, S({2, 3}), 1);
+    test0(S({1, 2, 3}), is2, S({1, 3}), 1);
+    test0(S({1, 2, 3}), is3, S({1, 2}), 1);
+    test0(S({1, 2, 3}), is4, S({1, 2, 3}), 0);
 
-    test0(S({1,2,3}), True,  S());
-    test0(S({1,2,3}), False, S({1,2,3}));
+    test0(S({1, 2, 3}), True, S(), 3);
+    test0(S({1, 2, 3}), False, S({1, 2, 3}), 0);
 }
 
 int main(int, char**)

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.erasure/erase.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.erasure/erase.pass.cpp
index 2394c26dcbe0..e10d06174fe2 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.erasure/erase.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.erasure/erase.pass.cpp
@@ -10,8 +10,8 @@
 // <deque>
 
 // template <class T, class Allocator, class U>
-//   void erase(deque<T, Allocator>& c, const U& value);
-
+//   typename deque<T, Allocator>::size_type
+//   erase(deque<T, Allocator>& c, const U& value);
 
 #include <deque>
 #include <optional>
@@ -21,49 +21,46 @@
 #include "min_allocator.h"
 
 template <class S, class U>
-void
-test0(S s,  U val, S expected)
-{
-    ASSERT_SAME_TYPE(void, decltype(std::erase(s, val)));
-    std::erase(s, val);
-    assert(s == expected);
+void test0(S s, U val, S expected, size_t expected_erased_count) {
+  ASSERT_SAME_TYPE(typename S::size_type, decltype(std::erase(s, val)));
+  assert(expected_erased_count == std::erase(s, val));
+  assert(s == expected);
 }
 
 template <class S>
 void test()
 {
-
-    test0(S(), 1, S());
-
-    test0(S({1}), 1, S());
-    test0(S({1}), 2, S({1}));
-
-    test0(S({1,2}), 1, S({2}));
-    test0(S({1,2}), 2, S({1}));
-    test0(S({1,2}), 3, S({1,2}));
-    test0(S({1,1}), 1, S());
-    test0(S({1,1}), 3, S({1,1}));
-
-    test0(S({1,2,3}), 1, S({2,3}));
-    test0(S({1,2,3}), 2, S({1,3}));
-    test0(S({1,2,3}), 3, S({1,2}));
-    test0(S({1,2,3}), 4, S({1,2,3}));
-
-    test0(S({1,1,1}), 1, S());
-    test0(S({1,1,1}), 2, S({1,1,1}));
-    test0(S({1,1,2}), 1, S({2}));
-    test0(S({1,1,2}), 2, S({1,1}));
-    test0(S({1,1,2}), 3, S({1,1,2}));
-    test0(S({1,2,2}), 1, S({2,2}));
-    test0(S({1,2,2}), 2, S({1}));
-    test0(S({1,2,2}), 3, S({1,2,2}));
-
-//  Test cross-type erasure
-    using opt = std::optional<typename S::value_type>;
-    test0(S({1,2,1}), opt(),  S({1,2,1}));
-    test0(S({1,2,1}), opt(1), S({2}));
-    test0(S({1,2,1}), opt(2), S({1,1}));
-    test0(S({1,2,1}), opt(3), S({1,2,1}));
+  test0(S(), 1, S(), 0);
+
+  test0(S({1}), 1, S(), 1);
+  test0(S({1}), 2, S({1}), 0);
+
+  test0(S({1, 2}), 1, S({2}), 1);
+  test0(S({1, 2}), 2, S({1}), 1);
+  test0(S({1, 2}), 3, S({1, 2}), 0);
+  test0(S({1, 1}), 1, S(), 2);
+  test0(S({1, 1}), 3, S({1, 1}), 0);
+
+  test0(S({1, 2, 3}), 1, S({2, 3}), 1);
+  test0(S({1, 2, 3}), 2, S({1, 3}), 1);
+  test0(S({1, 2, 3}), 3, S({1, 2}), 1);
+  test0(S({1, 2, 3}), 4, S({1, 2, 3}), 0);
+
+  test0(S({1, 1, 1}), 1, S(), 3);
+  test0(S({1, 1, 1}), 2, S({1, 1, 1}), 0);
+  test0(S({1, 1, 2}), 1, S({2}), 2);
+  test0(S({1, 1, 2}), 2, S({1, 1}), 1);
+  test0(S({1, 1, 2}), 3, S({1, 1, 2}), 0);
+  test0(S({1, 2, 2}), 1, S({2, 2}), 1);
+  test0(S({1, 2, 2}), 2, S({1}), 2);
+  test0(S({1, 2, 2}), 3, S({1, 2, 2}), 0);
+
+  //  Test cross-type erasure
+  using opt = std::optional<typename S::value_type>;
+  test0(S({1, 2, 1}), opt(), S({1, 2, 1}), 0);
+  test0(S({1, 2, 1}), opt(1), S({2}), 2);
+  test0(S({1, 2, 1}), opt(2), S({1, 1}), 1);
+  test0(S({1, 2, 1}), opt(3), S({1, 2, 1}), 0);
 }
 
 int main(int, char**)

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.erasure/erase_if.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.erasure/erase_if.pass.cpp
index cb54e4e443f5..86e4c68dcfb9 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.erasure/erase_if.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.erasure/erase_if.pass.cpp
@@ -10,7 +10,8 @@
 // <deque>
 
 // template <class T, class Allocator, class Predicate>
-//   void erase_if(deque<T, Allocator>& c, Predicate pred);
+//   typename deque<T, Allocator>::size_type
+//   erase_if(deque<T, Allocator>& c, Predicate pred);
 
 #include <deque>
 
@@ -19,12 +20,10 @@
 #include "min_allocator.h"
 
 template <class S, class Pred>
-void
-test0(S s, Pred p, S expected)
-{
-    ASSERT_SAME_TYPE(void, decltype(std::erase_if(s, p)));
-    std::erase_if(s, p);
-    assert(s == expected);
+void test0(S s, Pred p, S expected, size_t expected_erased_count) {
+  ASSERT_SAME_TYPE(typename S::size_type, decltype(std::erase_if(s, p)));
+  assert(expected_erased_count == std::erase_if(s, p));
+  assert(s == expected);
 }
 
 template <typename S>
@@ -37,33 +36,33 @@ void test()
     auto True  = [](auto) { return true; };
     auto False = [](auto) { return false; };
 
-    test0(S(), is1, S());
+    test0(S(), is1, S(), 0);
 
-    test0(S({1}), is1, S());
-    test0(S({1}), is2, S({1}));
+    test0(S({1}), is1, S(), 1);
+    test0(S({1}), is2, S({1}), 0);
 
-    test0(S({1,2}), is1, S({2}));
-    test0(S({1,2}), is2, S({1}));
-    test0(S({1,2}), is3, S({1,2}));
-    test0(S({1,1}), is1, S());
-    test0(S({1,1}), is3, S({1,1}));
+    test0(S({1, 2}), is1, S({2}), 1);
+    test0(S({1, 2}), is2, S({1}), 1);
+    test0(S({1, 2}), is3, S({1, 2}), 0);
+    test0(S({1, 1}), is1, S(), 2);
+    test0(S({1, 1}), is3, S({1, 1}), 0);
 
-    test0(S({1,2,3}), is1, S({2,3}));
-    test0(S({1,2,3}), is2, S({1,3}));
-    test0(S({1,2,3}), is3, S({1,2}));
-    test0(S({1,2,3}), is4, S({1,2,3}));
+    test0(S({1, 2, 3}), is1, S({2, 3}), 1);
+    test0(S({1, 2, 3}), is2, S({1, 3}), 1);
+    test0(S({1, 2, 3}), is3, S({1, 2}), 1);
+    test0(S({1, 2, 3}), is4, S({1, 2, 3}), 0);
 
-    test0(S({1,1,1}), is1, S());
-    test0(S({1,1,1}), is2, S({1,1,1}));
-    test0(S({1,1,2}), is1, S({2}));
-    test0(S({1,1,2}), is2, S({1,1}));
-    test0(S({1,1,2}), is3, S({1,1,2}));
-    test0(S({1,2,2}), is1, S({2,2}));
-    test0(S({1,2,2}), is2, S({1}));
-    test0(S({1,2,2}), is3, S({1,2,2}));
+    test0(S({1, 1, 1}), is1, S(), 3);
+    test0(S({1, 1, 1}), is2, S({1, 1, 1}), 0);
+    test0(S({1, 1, 2}), is1, S({2}), 2);
+    test0(S({1, 1, 2}), is2, S({1, 1}), 1);
+    test0(S({1, 1, 2}), is3, S({1, 1, 2}), 0);
+    test0(S({1, 2, 2}), is1, S({2, 2}), 1);
+    test0(S({1, 2, 2}), is2, S({1}), 2);
+    test0(S({1, 2, 2}), is3, S({1, 2, 2}), 0);
 
-    test0(S({1,2,3}), True,  S());
-    test0(S({1,2,3}), False, S({1,2,3}));
+    test0(S({1, 2, 3}), True, S(), 3);
+    test0(S({1, 2, 3}), False, S({1, 2, 3}), 0);
 }
 
 int main(int, char**)

diff  --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.erasure/erase.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.erasure/erase.pass.cpp
index 791553548020..26438c60294e 100644
--- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.erasure/erase.pass.cpp
+++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.erasure/erase.pass.cpp
@@ -10,8 +10,8 @@
 // <forward_list>
 
 // template <class T, class Allocator, class U>
-//   void erase(forward_list<T, Allocator>& c, const U& value);
-
+//   typename forward_list<T, Allocator>::size_type
+//   erase(forward_list<T, Allocator>& c, const U& value);
 
 #include <forward_list>
 #include <optional>
@@ -21,49 +21,46 @@
 #include "min_allocator.h"
 
 template <class S, class U>
-void
-test0(S s,  U val, S expected)
-{
-    ASSERT_SAME_TYPE(void, decltype(std::erase(s, val)));
-    std::erase(s, val);
-    assert(s == expected);
+void test0(S s, U val, S expected, size_t expected_erased_count) {
+  ASSERT_SAME_TYPE(typename S::size_type, decltype(std::erase(s, val)));
+  assert(expected_erased_count == std::erase(s, val));
+  assert(s == expected);
 }
 
 template <class S>
 void test()
 {
-
-    test0(S(), 1, S());
-
-    test0(S({1}), 1, S());
-    test0(S({1}), 2, S({1}));
-
-    test0(S({1,2}), 1, S({2}));
-    test0(S({1,2}), 2, S({1}));
-    test0(S({1,2}), 3, S({1,2}));
-    test0(S({1,1}), 1, S());
-    test0(S({1,1}), 3, S({1,1}));
-
-    test0(S({1,2,3}), 1, S({2,3}));
-    test0(S({1,2,3}), 2, S({1,3}));
-    test0(S({1,2,3}), 3, S({1,2}));
-    test0(S({1,2,3}), 4, S({1,2,3}));
-
-    test0(S({1,1,1}), 1, S());
-    test0(S({1,1,1}), 2, S({1,1,1}));
-    test0(S({1,1,2}), 1, S({2}));
-    test0(S({1,1,2}), 2, S({1,1}));
-    test0(S({1,1,2}), 3, S({1,1,2}));
-    test0(S({1,2,2}), 1, S({2,2}));
-    test0(S({1,2,2}), 2, S({1}));
-    test0(S({1,2,2}), 3, S({1,2,2}));
-
-//  Test cross-type erasure
-    using opt = std::optional<typename S::value_type>;
-    test0(S({1,2,1}), opt(),  S({1,2,1}));
-    test0(S({1,2,1}), opt(1), S({2}));
-    test0(S({1,2,1}), opt(2), S({1,1}));
-    test0(S({1,2,1}), opt(3), S({1,2,1}));
+  test0(S(), 1, S(), 0);
+
+  test0(S({1}), 1, S(), 1);
+  test0(S({1}), 2, S({1}), 0);
+
+  test0(S({1, 2}), 1, S({2}), 1);
+  test0(S({1, 2}), 2, S({1}), 1);
+  test0(S({1, 2}), 3, S({1, 2}), 0);
+  test0(S({1, 1}), 1, S(), 2);
+  test0(S({1, 1}), 3, S({1, 1}), 0);
+
+  test0(S({1, 2, 3}), 1, S({2, 3}), 1);
+  test0(S({1, 2, 3}), 2, S({1, 3}), 1);
+  test0(S({1, 2, 3}), 3, S({1, 2}), 1);
+  test0(S({1, 2, 3}), 4, S({1, 2, 3}), 0);
+
+  test0(S({1, 1, 1}), 1, S(), 3);
+  test0(S({1, 1, 1}), 2, S({1, 1, 1}), 0);
+  test0(S({1, 1, 2}), 1, S({2}), 2);
+  test0(S({1, 1, 2}), 2, S({1, 1}), 1);
+  test0(S({1, 1, 2}), 3, S({1, 1, 2}), 0);
+  test0(S({1, 2, 2}), 1, S({2, 2}), 1);
+  test0(S({1, 2, 2}), 2, S({1}), 2);
+  test0(S({1, 2, 2}), 3, S({1, 2, 2}), 0);
+
+  //  Test cross-type erasure
+  using opt = std::optional<typename S::value_type>;
+  test0(S({1, 2, 1}), opt(), S({1, 2, 1}), 0);
+  test0(S({1, 2, 1}), opt(1), S({2}), 2);
+  test0(S({1, 2, 1}), opt(2), S({1, 1}), 1);
+  test0(S({1, 2, 1}), opt(3), S({1, 2, 1}), 0);
 }
 
 int main(int, char**)

diff  --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.erasure/erase_if.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.erasure/erase_if.pass.cpp
index 103645d4b6ec..e1a4a64b29ad 100644
--- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.erasure/erase_if.pass.cpp
+++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.erasure/erase_if.pass.cpp
@@ -10,7 +10,8 @@
 // <forward_list>
 
 // template <class T, class Allocator, class Predicate>
-//   void erase_if(forward_list<T, Allocator>& c, Predicate pred);
+//   typename forward_list<T, Allocator>::size_type
+//   erase_if(forward_list<T, Allocator>& c, Predicate pred);
 
 #include <forward_list>
 
@@ -19,12 +20,10 @@
 #include "min_allocator.h"
 
 template <class S, class Pred>
-void
-test0(S s, Pred p, S expected)
-{
-    ASSERT_SAME_TYPE(void, decltype(std::erase_if(s, p)));
-    std::erase_if(s, p);
-    assert(s == expected);
+void test0(S s, Pred p, S expected, size_t expected_erased_count) {
+  ASSERT_SAME_TYPE(typename S::size_type, decltype(std::erase_if(s, p)));
+  assert(expected_erased_count == std::erase_if(s, p));
+  assert(s == expected);
 }
 
 template <typename S>
@@ -37,33 +36,33 @@ void test()
     auto True  = [](auto) { return true; };
     auto False = [](auto) { return false; };
 
-    test0(S(), is1, S());
+    test0(S(), is1, S(), 0);
 
-    test0(S({1}), is1, S());
-    test0(S({1}), is2, S({1}));
+    test0(S({1}), is1, S(), 1);
+    test0(S({1}), is2, S({1}), 0);
 
-    test0(S({1,2}), is1, S({2}));
-    test0(S({1,2}), is2, S({1}));
-    test0(S({1,2}), is3, S({1,2}));
-    test0(S({1,1}), is1, S());
-    test0(S({1,1}), is3, S({1,1}));
+    test0(S({1, 2}), is1, S({2}), 1);
+    test0(S({1, 2}), is2, S({1}), 1);
+    test0(S({1, 2}), is3, S({1, 2}), 0);
+    test0(S({1, 1}), is1, S(), 2);
+    test0(S({1, 1}), is3, S({1, 1}), 0);
 
-    test0(S({1,2,3}), is1, S({2,3}));
-    test0(S({1,2,3}), is2, S({1,3}));
-    test0(S({1,2,3}), is3, S({1,2}));
-    test0(S({1,2,3}), is4, S({1,2,3}));
+    test0(S({1, 2, 3}), is1, S({2, 3}), 1);
+    test0(S({1, 2, 3}), is2, S({1, 3}), 1);
+    test0(S({1, 2, 3}), is3, S({1, 2}), 1);
+    test0(S({1, 2, 3}), is4, S({1, 2, 3}), 0);
 
-    test0(S({1,1,1}), is1, S());
-    test0(S({1,1,1}), is2, S({1,1,1}));
-    test0(S({1,1,2}), is1, S({2}));
-    test0(S({1,1,2}), is2, S({1,1}));
-    test0(S({1,1,2}), is3, S({1,1,2}));
-    test0(S({1,2,2}), is1, S({2,2}));
-    test0(S({1,2,2}), is2, S({1}));
-    test0(S({1,2,2}), is3, S({1,2,2}));
+    test0(S({1, 1, 1}), is1, S(), 3);
+    test0(S({1, 1, 1}), is2, S({1, 1, 1}), 0);
+    test0(S({1, 1, 2}), is1, S({2}), 2);
+    test0(S({1, 1, 2}), is2, S({1, 1}), 1);
+    test0(S({1, 1, 2}), is3, S({1, 1, 2}), 0);
+    test0(S({1, 2, 2}), is1, S({2, 2}), 1);
+    test0(S({1, 2, 2}), is2, S({1}), 2);
+    test0(S({1, 2, 2}), is3, S({1, 2, 2}), 0);
 
-    test0(S({1,2,3}), True,  S());
-    test0(S({1,2,3}), False, S({1,2,3}));
+    test0(S({1, 2, 3}), True, S(), 3);
+    test0(S({1, 2, 3}), False, S({1, 2, 3}), 0);
 }
 
 int main(int, char**)

diff  --git a/libcxx/test/std/containers/sequences/list/list.erasure/erase.pass.cpp b/libcxx/test/std/containers/sequences/list/list.erasure/erase.pass.cpp
index 298785ca52c8..a8cbbb37671c 100644
--- a/libcxx/test/std/containers/sequences/list/list.erasure/erase.pass.cpp
+++ b/libcxx/test/std/containers/sequences/list/list.erasure/erase.pass.cpp
@@ -10,8 +10,8 @@
 // <list>
 
 // template <class T, class Allocator, class U>
-//   void erase(list<T, Allocator>& c, const U& value);
-
+//   typename list<T, Allocator>::size_type
+//   erase(list<T, Allocator>& c, const U& value);
 
 #include <list>
 #include <optional>
@@ -21,49 +21,46 @@
 #include "min_allocator.h"
 
 template <class S, class U>
-void
-test0(S s,  U val, S expected)
-{
-    ASSERT_SAME_TYPE(void, decltype(std::erase(s, val)));
-    std::erase(s, val);
-    assert(s == expected);
+void test0(S s, U val, S expected, size_t expected_erased_count) {
+  ASSERT_SAME_TYPE(typename S::size_type, decltype(std::erase(s, val)));
+  assert(expected_erased_count == std::erase(s, val));
+  assert(s == expected);
 }
 
 template <class S>
 void test()
 {
-
-    test0(S(), 1, S());
-
-    test0(S({1}), 1, S());
-    test0(S({1}), 2, S({1}));
-
-    test0(S({1,2}), 1, S({2}));
-    test0(S({1,2}), 2, S({1}));
-    test0(S({1,2}), 3, S({1,2}));
-    test0(S({1,1}), 1, S());
-    test0(S({1,1}), 3, S({1,1}));
-
-    test0(S({1,2,3}), 1, S({2,3}));
-    test0(S({1,2,3}), 2, S({1,3}));
-    test0(S({1,2,3}), 3, S({1,2}));
-    test0(S({1,2,3}), 4, S({1,2,3}));
-
-    test0(S({1,1,1}), 1, S());
-    test0(S({1,1,1}), 2, S({1,1,1}));
-    test0(S({1,1,2}), 1, S({2}));
-    test0(S({1,1,2}), 2, S({1,1}));
-    test0(S({1,1,2}), 3, S({1,1,2}));
-    test0(S({1,2,2}), 1, S({2,2}));
-    test0(S({1,2,2}), 2, S({1}));
-    test0(S({1,2,2}), 3, S({1,2,2}));
-
-//  Test cross-type erasure
-    using opt = std::optional<typename S::value_type>;
-    test0(S({1,2,1}), opt(),  S({1,2,1}));
-    test0(S({1,2,1}), opt(1), S({2}));
-    test0(S({1,2,1}), opt(2), S({1,1}));
-    test0(S({1,2,1}), opt(3), S({1,2,1}));
+  test0(S(), 1, S(), 0);
+
+  test0(S({1}), 1, S(), 1);
+  test0(S({1}), 2, S({1}), 0);
+
+  test0(S({1, 2}), 1, S({2}), 1);
+  test0(S({1, 2}), 2, S({1}), 1);
+  test0(S({1, 2}), 3, S({1, 2}), 0);
+  test0(S({1, 1}), 1, S(), 2);
+  test0(S({1, 1}), 3, S({1, 1}), 0);
+
+  test0(S({1, 2, 3}), 1, S({2, 3}), 1);
+  test0(S({1, 2, 3}), 2, S({1, 3}), 1);
+  test0(S({1, 2, 3}), 3, S({1, 2}), 1);
+  test0(S({1, 2, 3}), 4, S({1, 2, 3}), 0);
+
+  test0(S({1, 1, 1}), 1, S(), 3);
+  test0(S({1, 1, 1}), 2, S({1, 1, 1}), 0);
+  test0(S({1, 1, 2}), 1, S({2}), 2);
+  test0(S({1, 1, 2}), 2, S({1, 1}), 1);
+  test0(S({1, 1, 2}), 3, S({1, 1, 2}), 0);
+  test0(S({1, 2, 2}), 1, S({2, 2}), 1);
+  test0(S({1, 2, 2}), 2, S({1}), 2);
+  test0(S({1, 2, 2}), 3, S({1, 2, 2}), 0);
+
+  //  Test cross-type erasure
+  using opt = std::optional<typename S::value_type>;
+  test0(S({1, 2, 1}), opt(), S({1, 2, 1}), 0);
+  test0(S({1, 2, 1}), opt(1), S({2}), 2);
+  test0(S({1, 2, 1}), opt(2), S({1, 1}), 1);
+  test0(S({1, 2, 1}), opt(3), S({1, 2, 1}), 0);
 }
 
 int main(int, char**)

diff  --git a/libcxx/test/std/containers/sequences/list/list.erasure/erase_if.pass.cpp b/libcxx/test/std/containers/sequences/list/list.erasure/erase_if.pass.cpp
index b2889eb67c44..9e6dfb19d624 100644
--- a/libcxx/test/std/containers/sequences/list/list.erasure/erase_if.pass.cpp
+++ b/libcxx/test/std/containers/sequences/list/list.erasure/erase_if.pass.cpp
@@ -10,7 +10,8 @@
 // <list>
 
 // template <class T, class Allocator, class Predicate>
-//   void erase_if(list<T, Allocator>& c, Predicate pred);
+//   typename list<T, Allocator>::size_type
+//   erase_if(list<T, Allocator>& c, Predicate pred);
 
 #include <list>
 
@@ -19,12 +20,10 @@
 #include "min_allocator.h"
 
 template <class S, class Pred>
-void
-test0(S s, Pred p, S expected)
-{
-    ASSERT_SAME_TYPE(void, decltype(std::erase_if(s, p)));
-    std::erase_if(s, p);
-    assert(s == expected);
+void test0(S s, Pred p, S expected, size_t expected_erased_count) {
+  ASSERT_SAME_TYPE(typename S::size_type, decltype(std::erase_if(s, p)));
+  assert(expected_erased_count == std::erase_if(s, p));
+  assert(s == expected);
 }
 
 template <typename S>
@@ -37,33 +36,33 @@ void test()
     auto True  = [](auto) { return true; };
     auto False = [](auto) { return false; };
 
-    test0(S(), is1, S());
+    test0(S(), is1, S(), 0);
 
-    test0(S({1}), is1, S());
-    test0(S({1}), is2, S({1}));
+    test0(S({1}), is1, S(), 1);
+    test0(S({1}), is2, S({1}), 0);
 
-    test0(S({1,2}), is1, S({2}));
-    test0(S({1,2}), is2, S({1}));
-    test0(S({1,2}), is3, S({1,2}));
-    test0(S({1,1}), is1, S());
-    test0(S({1,1}), is3, S({1,1}));
+    test0(S({1, 2}), is1, S({2}), 1);
+    test0(S({1, 2}), is2, S({1}), 1);
+    test0(S({1, 2}), is3, S({1, 2}), 0);
+    test0(S({1, 1}), is1, S(), 2);
+    test0(S({1, 1}), is3, S({1, 1}), 0);
 
-    test0(S({1,2,3}), is1, S({2,3}));
-    test0(S({1,2,3}), is2, S({1,3}));
-    test0(S({1,2,3}), is3, S({1,2}));
-    test0(S({1,2,3}), is4, S({1,2,3}));
+    test0(S({1, 2, 3}), is1, S({2, 3}), 1);
+    test0(S({1, 2, 3}), is2, S({1, 3}), 1);
+    test0(S({1, 2, 3}), is3, S({1, 2}), 1);
+    test0(S({1, 2, 3}), is4, S({1, 2, 3}), 0);
 
-    test0(S({1,1,1}), is1, S());
-    test0(S({1,1,1}), is2, S({1,1,1}));
-    test0(S({1,1,2}), is1, S({2}));
-    test0(S({1,1,2}), is2, S({1,1}));
-    test0(S({1,1,2}), is3, S({1,1,2}));
-    test0(S({1,2,2}), is1, S({2,2}));
-    test0(S({1,2,2}), is2, S({1}));
-    test0(S({1,2,2}), is3, S({1,2,2}));
+    test0(S({1, 1, 1}), is1, S(), 3);
+    test0(S({1, 1, 1}), is2, S({1, 1, 1}), 0);
+    test0(S({1, 1, 2}), is1, S({2}), 2);
+    test0(S({1, 1, 2}), is2, S({1, 1}), 1);
+    test0(S({1, 1, 2}), is3, S({1, 1, 2}), 0);
+    test0(S({1, 2, 2}), is1, S({2, 2}), 1);
+    test0(S({1, 2, 2}), is2, S({1}), 2);
+    test0(S({1, 2, 2}), is3, S({1, 2, 2}), 0);
 
-    test0(S({1,2,3}), True,  S());
-    test0(S({1,2,3}), False, S({1,2,3}));
+    test0(S({1, 2, 3}), True, S(), 3);
+    test0(S({1, 2, 3}), False, S({1, 2, 3}), 0);
 }
 
 int main(int, char**)

diff  --git a/libcxx/test/std/containers/sequences/vector/vector.erasure/erase.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.erasure/erase.pass.cpp
index 687a467e4f7d..d353a88448e0 100644
--- a/libcxx/test/std/containers/sequences/vector/vector.erasure/erase.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector/vector.erasure/erase.pass.cpp
@@ -10,8 +10,8 @@
 // <vector>
 
 // template <class T, class Allocator, class U>
-//   void erase(vector<T, Allocator>& c, const U& value);
-
+//   typename vector<T, Allocator>::size_type
+//   erase(vector<T, Allocator>& c, const U& value);
 
 #include <vector>
 #include <optional>
@@ -21,49 +21,47 @@
 #include "min_allocator.h"
 
 template <class S, class U>
-void
-test0(S s,  U val, S expected)
-{
-    ASSERT_SAME_TYPE(void, decltype(std::erase(s, val)));
-    std::erase(s, val);
-    assert(s == expected);
+void test0(S s, U val, S expected, size_t expected_erased_count) {
+  ASSERT_SAME_TYPE(typename S::size_type, decltype(std::erase(s, val)));
+  assert(expected_erased_count == std::erase(s, val));
+  assert(s == expected);
 }
 
 template <class S>
 void test()
 {
 
-    test0(S(), 1, S());
-
-    test0(S({1}), 1, S());
-    test0(S({1}), 2, S({1}));
-
-    test0(S({1,2}), 1, S({2}));
-    test0(S({1,2}), 2, S({1}));
-    test0(S({1,2}), 3, S({1,2}));
-    test0(S({1,1}), 1, S());
-    test0(S({1,1}), 3, S({1,1}));
-
-    test0(S({1,2,3}), 1, S({2,3}));
-    test0(S({1,2,3}), 2, S({1,3}));
-    test0(S({1,2,3}), 3, S({1,2}));
-    test0(S({1,2,3}), 4, S({1,2,3}));
-
-    test0(S({1,1,1}), 1, S());
-    test0(S({1,1,1}), 2, S({1,1,1}));
-    test0(S({1,1,2}), 1, S({2}));
-    test0(S({1,1,2}), 2, S({1,1}));
-    test0(S({1,1,2}), 3, S({1,1,2}));
-    test0(S({1,2,2}), 1, S({2,2}));
-    test0(S({1,2,2}), 2, S({1}));
-    test0(S({1,2,2}), 3, S({1,2,2}));
-
-//  Test cross-type erasure
-    using opt = std::optional<typename S::value_type>;
-    test0(S({1,2,1}), opt(),  S({1,2,1}));
-    test0(S({1,2,1}), opt(1), S({2}));
-    test0(S({1,2,1}), opt(2), S({1,1}));
-    test0(S({1,2,1}), opt(3), S({1,2,1}));
+  test0(S(), 1, S(), 0);
+
+  test0(S({1}), 1, S(), 1);
+  test0(S({1}), 2, S({1}), 0);
+
+  test0(S({1, 2}), 1, S({2}), 1);
+  test0(S({1, 2}), 2, S({1}), 1);
+  test0(S({1, 2}), 3, S({1, 2}), 0);
+  test0(S({1, 1}), 1, S(), 2);
+  test0(S({1, 1}), 3, S({1, 1}), 0);
+
+  test0(S({1, 2, 3}), 1, S({2, 3}), 1);
+  test0(S({1, 2, 3}), 2, S({1, 3}), 1);
+  test0(S({1, 2, 3}), 3, S({1, 2}), 1);
+  test0(S({1, 2, 3}), 4, S({1, 2, 3}), 0);
+
+  test0(S({1, 1, 1}), 1, S(), 3);
+  test0(S({1, 1, 1}), 2, S({1, 1, 1}), 0);
+  test0(S({1, 1, 2}), 1, S({2}), 2);
+  test0(S({1, 1, 2}), 2, S({1, 1}), 1);
+  test0(S({1, 1, 2}), 3, S({1, 1, 2}), 0);
+  test0(S({1, 2, 2}), 1, S({2, 2}), 1);
+  test0(S({1, 2, 2}), 2, S({1}), 2);
+  test0(S({1, 2, 2}), 3, S({1, 2, 2}), 0);
+
+  //  Test cross-type erasure
+  using opt = std::optional<typename S::value_type>;
+  test0(S({1, 2, 1}), opt(), S({1, 2, 1}), 0);
+  test0(S({1, 2, 1}), opt(1), S({2}), 2);
+  test0(S({1, 2, 1}), opt(2), S({1, 1}), 1);
+  test0(S({1, 2, 1}), opt(3), S({1, 2, 1}), 0);
 }
 
 int main(int, char**)

diff  --git a/libcxx/test/std/containers/sequences/vector/vector.erasure/erase_if.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.erasure/erase_if.pass.cpp
index 49fece4b7650..f72b3c9eab4f 100644
--- a/libcxx/test/std/containers/sequences/vector/vector.erasure/erase_if.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector/vector.erasure/erase_if.pass.cpp
@@ -10,7 +10,8 @@
 // <vector>
 
 // template <class T, class Allocator, class Predicate>
-//   void erase_if(vector<T, Allocator>& c, Predicate pred);
+//   typename vector<T, Allocator>::size_type
+//   erase_if(vector<T, Allocator>& c, Predicate pred);
 
 #include <vector>
 
@@ -19,12 +20,10 @@
 #include "min_allocator.h"
 
 template <class S, class Pred>
-void
-test0(S s, Pred p, S expected)
-{
-    ASSERT_SAME_TYPE(void, decltype(std::erase_if(s, p)));
-    std::erase_if(s, p);
-    assert(s == expected);
+void test0(S s, Pred p, S expected, size_t expected_erased_count) {
+  ASSERT_SAME_TYPE(typename S::size_type, decltype(std::erase_if(s, p)));
+  assert(expected_erased_count == std::erase_if(s, p));
+  assert(s == expected);
 }
 
 template <typename S>
@@ -37,33 +36,33 @@ void test()
     auto True  = [](auto) { return true; };
     auto False = [](auto) { return false; };
 
-    test0(S(), is1, S());
+    test0(S(), is1, S(), 0);
 
-    test0(S({1}), is1, S());
-    test0(S({1}), is2, S({1}));
+    test0(S({1}), is1, S(), 1);
+    test0(S({1}), is2, S({1}), 0);
 
-    test0(S({1,2}), is1, S({2}));
-    test0(S({1,2}), is2, S({1}));
-    test0(S({1,2}), is3, S({1,2}));
-    test0(S({1,1}), is1, S());
-    test0(S({1,1}), is3, S({1,1}));
+    test0(S({1, 2}), is1, S({2}), 1);
+    test0(S({1, 2}), is2, S({1}), 1);
+    test0(S({1, 2}), is3, S({1, 2}), 0);
+    test0(S({1, 1}), is1, S(), 2);
+    test0(S({1, 1}), is3, S({1, 1}), 0);
 
-    test0(S({1,2,3}), is1, S({2,3}));
-    test0(S({1,2,3}), is2, S({1,3}));
-    test0(S({1,2,3}), is3, S({1,2}));
-    test0(S({1,2,3}), is4, S({1,2,3}));
+    test0(S({1, 2, 3}), is1, S({2, 3}), 1);
+    test0(S({1, 2, 3}), is2, S({1, 3}), 1);
+    test0(S({1, 2, 3}), is3, S({1, 2}), 1);
+    test0(S({1, 2, 3}), is4, S({1, 2, 3}), 0);
 
-    test0(S({1,1,1}), is1, S());
-    test0(S({1,1,1}), is2, S({1,1,1}));
-    test0(S({1,1,2}), is1, S({2}));
-    test0(S({1,1,2}), is2, S({1,1}));
-    test0(S({1,1,2}), is3, S({1,1,2}));
-    test0(S({1,2,2}), is1, S({2,2}));
-    test0(S({1,2,2}), is2, S({1}));
-    test0(S({1,2,2}), is3, S({1,2,2}));
+    test0(S({1, 1, 1}), is1, S(), 3);
+    test0(S({1, 1, 1}), is2, S({1, 1, 1}), 0);
+    test0(S({1, 1, 2}), is1, S({2}), 2);
+    test0(S({1, 1, 2}), is2, S({1, 1}), 1);
+    test0(S({1, 1, 2}), is3, S({1, 1, 2}), 0);
+    test0(S({1, 2, 2}), is1, S({2, 2}), 1);
+    test0(S({1, 2, 2}), is2, S({1}), 2);
+    test0(S({1, 2, 2}), is3, S({1, 2, 2}), 0);
 
-    test0(S({1,2,3}), True,  S());
-    test0(S({1,2,3}), False, S({1,2,3}));
+    test0(S({1, 2, 3}), True, S(), 3);
+    test0(S({1, 2, 3}), False, S({1, 2, 3}), 0);
 }
 
 int main(int, char**)

diff  --git a/libcxx/test/std/containers/unord/unord.map/erase_if.pass.cpp b/libcxx/test/std/containers/unord/unord.map/erase_if.pass.cpp
index 2f188655ca81..782fb6bd6f31 100644
--- a/libcxx/test/std/containers/unord/unord.map/erase_if.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.map/erase_if.pass.cpp
@@ -10,7 +10,8 @@
 // <unordered_map>
 
 // template <class Key, class T, class Hash, class Pred, class Allocator, class Predicate>
-//   void erase_if(unordered_map<Key, T, Hash, Pred, Allocator>& c, Predicate pred);
+//   typename unordered_map<Key, T, Hash, Pred, Allocator>::size_type
+//   erase_if(unordered_map<Key, T, Hash, Pred, Allocator>& c, Predicate pred);
 
 #include <unordered_map>
 
@@ -29,14 +30,12 @@ M make (Init vals)
 }
 
 template <typename M, typename Pred>
-void
-test0(Init vals, Pred p, Init expected)
-{
-    M s = make<M> (vals);
-    ASSERT_SAME_TYPE(void, decltype(std::erase_if(s, p)));
-    std::erase_if(s, p);
-    M e = make<M>(expected);
-    assert((std::is_permutation(s.begin(), s.end(), e.begin(), e.end())));
+void test0(Init vals, Pred p, Init expected, size_t expected_erased_count) {
+  M s = make<M>(vals);
+  ASSERT_SAME_TYPE(typename M::size_type, decltype(std::erase_if(s, p)));
+  assert(expected_erased_count == std::erase_if(s, p));
+  M e = make<M>(expected);
+  assert((std::is_permutation(s.begin(), s.end(), e.begin(), e.end())));
 }
 
 template <typename S>
@@ -49,22 +48,22 @@ void test()
     auto True  = [](auto) { return true; };
     auto False = [](auto) { return false; };
 
-    test0<S>({}, is1, {});
+    test0<S>({}, is1, {}, 0);
 
-    test0<S>({1}, is1, {});
-    test0<S>({1}, is2, {1});
+    test0<S>({1}, is1, {}, 1);
+    test0<S>({1}, is2, {1}, 0);
 
-    test0<S>({1,2}, is1, {2});
-    test0<S>({1,2}, is2, {1});
-    test0<S>({1,2}, is3, {1,2});
+    test0<S>({1, 2}, is1, {2}, 1);
+    test0<S>({1, 2}, is2, {1}, 1);
+    test0<S>({1, 2}, is3, {1, 2}, 0);
 
-    test0<S>({1,2,3}, is1, {2,3});
-    test0<S>({1,2,3}, is2, {1,3});
-    test0<S>({1,2,3}, is3, {1,2});
-    test0<S>({1,2,3}, is4, {1,2,3});
+    test0<S>({1, 2, 3}, is1, {2, 3}, 1);
+    test0<S>({1, 2, 3}, is2, {1, 3}, 1);
+    test0<S>({1, 2, 3}, is3, {1, 2}, 1);
+    test0<S>({1, 2, 3}, is4, {1, 2, 3}, 0);
 
-    test0<S>({1,2,3}, True,  {});
-    test0<S>({1,2,3}, False, {1,2,3});
+    test0<S>({1, 2, 3}, True, {}, 3);
+    test0<S>({1, 2, 3}, False, {1, 2, 3}, 0);
 }
 
 int main(int, char**)

diff  --git a/libcxx/test/std/containers/unord/unord.multimap/erase_if.pass.cpp b/libcxx/test/std/containers/unord/unord.multimap/erase_if.pass.cpp
index 23d18872d142..0a79dbc5ae7a 100644
--- a/libcxx/test/std/containers/unord/unord.multimap/erase_if.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.multimap/erase_if.pass.cpp
@@ -10,7 +10,8 @@
 // <unordered_map>
 
 // template <class Key, class T, class Hash, class Pred, class Allocator, class Predicate>
-//   void erase_if(unordered_multimap<Key, T, Hash, Pred, Allocator>& c, Predicate pred);
+//   typename unordered_multimap<Key, T, Hash, Pred, Allocator>::size_type
+//   erase_if(unordered_multimap<Key, T, Hash, Pred, Allocator>& c, Predicate pred);
 
 #include <unordered_map>
 
@@ -29,14 +30,12 @@ M make (Init vals)
 }
 
 template <typename M, typename Pred>
-void
-test0(Init vals, Pred p, Init expected)
-{
-    M s = make<M> (vals);
-    ASSERT_SAME_TYPE(void, decltype(std::erase_if(s, p)));
-    std::erase_if(s, p);
-    M e = make<M>(expected);
-    assert((std::is_permutation(s.begin(), s.end(), e.begin(), e.end())));
+void test0(Init vals, Pred p, Init expected, size_t expected_erased_count) {
+  M s = make<M>(vals);
+  ASSERT_SAME_TYPE(typename M::size_type, decltype(std::erase_if(s, p)));
+  assert(expected_erased_count == std::erase_if(s, p));
+  M e = make<M>(expected);
+  assert((std::is_permutation(s.begin(), s.end(), e.begin(), e.end())));
 }
 
 template <typename S>
@@ -49,33 +48,33 @@ void test()
     auto True  = [](auto) { return true; };
     auto False = [](auto) { return false; };
 
-    test0<S>({}, is1, {});
-
-    test0<S>({1}, is1, {});
-    test0<S>({1}, is2, {1});
-
-    test0<S>({1,2}, is1, {2});
-    test0<S>({1,2}, is2, {1});
-    test0<S>({1,2}, is3, {1,2});
-    test0<S>({1,1}, is1, {});
-    test0<S>({1,1}, is3, {1,1});
-
-    test0<S>({1,2,3}, is1, {2,3});
-    test0<S>({1,2,3}, is2, {1,3});
-    test0<S>({1,2,3}, is3, {1,2});
-    test0<S>({1,2,3}, is4, {1,2,3});
-
-    test0<S>({1,1,1}, is1, {});
-    test0<S>({1,1,1}, is2, {1,1,1});
-    test0<S>({1,1,2}, is1, {2});
-    test0<S>({1,1,2}, is2, {1,1});
-    test0<S>({1,1,2}, is3, {1,1,2});
-    test0<S>({1,2,2}, is1, {2,2});
-    test0<S>({1,2,2}, is2, {1});
-    test0<S>({1,2,2}, is3, {1,2,2});
-
-    test0<S>({1,2,3}, True,  {});
-    test0<S>({1,2,3}, False, {1,2,3});
+    test0<S>({}, is1, {}, 0);
+
+    test0<S>({1}, is1, {}, 1);
+    test0<S>({1}, is2, {1}, 0);
+
+    test0<S>({1, 2}, is1, {2}, 1);
+    test0<S>({1, 2}, is2, {1}, 1);
+    test0<S>({1, 2}, is3, {1, 2}, 0);
+    test0<S>({1, 1}, is1, {}, 2);
+    test0<S>({1, 1}, is3, {1, 1}, 0);
+
+    test0<S>({1, 2, 3}, is1, {2, 3}, 1);
+    test0<S>({1, 2, 3}, is2, {1, 3}, 1);
+    test0<S>({1, 2, 3}, is3, {1, 2}, 1);
+    test0<S>({1, 2, 3}, is4, {1, 2, 3}, 0);
+
+    test0<S>({1, 1, 1}, is1, {}, 3);
+    test0<S>({1, 1, 1}, is2, {1, 1, 1}, 0);
+    test0<S>({1, 1, 2}, is1, {2}, 2);
+    test0<S>({1, 1, 2}, is2, {1, 1}, 1);
+    test0<S>({1, 1, 2}, is3, {1, 1, 2}, 0);
+    test0<S>({1, 2, 2}, is1, {2, 2}, 1);
+    test0<S>({1, 2, 2}, is2, {1}, 2);
+    test0<S>({1, 2, 2}, is3, {1, 2, 2}, 0);
+
+    test0<S>({1, 2, 3}, True, {}, 3);
+    test0<S>({1, 2, 3}, False, {1, 2, 3}, 0);
 }
 
 int main(int, char**)

diff  --git a/libcxx/test/std/containers/unord/unord.multiset/erase_if.pass.cpp b/libcxx/test/std/containers/unord/unord.multiset/erase_if.pass.cpp
index 72e553a734cd..5f7316923c35 100644
--- a/libcxx/test/std/containers/unord/unord.multiset/erase_if.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.multiset/erase_if.pass.cpp
@@ -10,7 +10,8 @@
 // <set>
 
 // template <class T, class Hash, class Compare, class Allocator, class Predicate>
-//   void erase_if(unordered_multiset<T, Hash, Compare, Allocator>& c, Predicate pred);
+//   typename unordered_multiset<T, Hash, Compare, Allocator>::size_type
+//   erase_if(unordered_multiset<T, Hash, Compare, Allocator>& c, Predicate pred);
 
 #include <unordered_set>
 
@@ -30,14 +31,12 @@ M make (Init vals)
 }
 
 template <typename M, typename Pred>
-void
-test0(Init vals, Pred p, Init expected)
-{
-    M s = make<M> (vals);
-    ASSERT_SAME_TYPE(void, decltype(std::erase_if(s, p)));
-    std::erase_if(s, p);
-    M e = make<M>(expected);
-    assert((std::is_permutation(s.begin(), s.end(), e.begin(), e.end())));
+void test0(Init vals, Pred p, Init expected, size_t expected_erased_count) {
+  M s = make<M>(vals);
+  ASSERT_SAME_TYPE(typename M::size_type, decltype(std::erase_if(s, p)));
+  assert(expected_erased_count == std::erase_if(s, p));
+  M e = make<M>(expected);
+  assert((std::is_permutation(s.begin(), s.end(), e.begin(), e.end())));
 }
 
 template <typename S>
@@ -50,33 +49,33 @@ void test()
     auto True  = [](auto) { return true; };
     auto False = [](auto) { return false; };
 
-    test0<S>({}, is1, {});
-
-    test0<S>({1}, is1, {});
-    test0<S>({1}, is2, {1});
-
-    test0<S>({1,2}, is1, {2});
-    test0<S>({1,2}, is2, {1});
-    test0<S>({1,2}, is3, {1,2});
-    test0<S>({1,1}, is1, {});
-    test0<S>({1,1}, is3, {1,1});
-
-    test0<S>({1,2,3}, is1, {2,3});
-    test0<S>({1,2,3}, is2, {1,3});
-    test0<S>({1,2,3}, is3, {1,2});
-    test0<S>({1,2,3}, is4, {1,2,3});
-
-    test0<S>({1,1,1}, is1, {});
-    test0<S>({1,1,1}, is2, {1,1,1});
-    test0<S>({1,1,2}, is1, {2});
-    test0<S>({1,1,2}, is2, {1,1});
-    test0<S>({1,1,2}, is3, {1,1,2});
-    test0<S>({1,2,2}, is1, {2,2});
-    test0<S>({1,2,2}, is2, {1});
-    test0<S>({1,2,2}, is3, {1,2,2});
-
-    test0<S>({1,2,3}, True,  {});
-    test0<S>({1,2,3}, False, {1,2,3});
+    test0<S>({}, is1, {}, 0);
+
+    test0<S>({1}, is1, {}, 1);
+    test0<S>({1}, is2, {1}, 0);
+
+    test0<S>({1, 2}, is1, {2}, 1);
+    test0<S>({1, 2}, is2, {1}, 1);
+    test0<S>({1, 2}, is3, {1, 2}, 0);
+    test0<S>({1, 1}, is1, {}, 2);
+    test0<S>({1, 1}, is3, {1, 1}, 0);
+
+    test0<S>({1, 2, 3}, is1, {2, 3}, 1);
+    test0<S>({1, 2, 3}, is2, {1, 3}, 1);
+    test0<S>({1, 2, 3}, is3, {1, 2}, 1);
+    test0<S>({1, 2, 3}, is4, {1, 2, 3}, 0);
+
+    test0<S>({1, 1, 1}, is1, {}, 3);
+    test0<S>({1, 1, 1}, is2, {1, 1, 1}, 0);
+    test0<S>({1, 1, 2}, is1, {2}, 2);
+    test0<S>({1, 1, 2}, is2, {1, 1}, 1);
+    test0<S>({1, 1, 2}, is3, {1, 1, 2}, 0);
+    test0<S>({1, 2, 2}, is1, {2, 2}, 1);
+    test0<S>({1, 2, 2}, is2, {1}, 2);
+    test0<S>({1, 2, 2}, is3, {1, 2, 2}, 0);
+
+    test0<S>({1, 2, 3}, True, {}, 3);
+    test0<S>({1, 2, 3}, False, {1, 2, 3}, 0);
 }
 
 int main(int, char**)

diff  --git a/libcxx/test/std/containers/unord/unord.set/erase_if.pass.cpp b/libcxx/test/std/containers/unord/unord.set/erase_if.pass.cpp
index 5bc692e8d9cf..cec1041722d6 100644
--- a/libcxx/test/std/containers/unord/unord.set/erase_if.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.set/erase_if.pass.cpp
@@ -10,7 +10,8 @@
 // <unordered_set>
 
 // template <class T, class Hash, class Compare, class Allocator, class Predicate>
-//   void erase_if(unorderd_set<T, Hash, Compare, Allocator>& c, Predicate pred);
+//   typename unordered_set<T, Hash, Compare, Allocator>::size_type
+//   erase_if(unordered_set<T, Hash, Compare, Allocator>& c, Predicate pred);
 
 #include <unordered_set>
 
@@ -30,17 +31,14 @@ M make (Init vals)
 }
 
 template <typename M, typename Pred>
-void
-test0(Init vals, Pred p, Init expected)
-{
-    M s = make<M> (vals);
-    ASSERT_SAME_TYPE(void, decltype(std::erase_if(s, p)));
-    std::erase_if(s, p);
-    M e = make<M>(expected);
-    assert((std::is_permutation(s.begin(), s.end(), e.begin(), e.end())));
+void test0(Init vals, Pred p, Init expected, size_t expected_erased_count) {
+  M s = make<M>(vals);
+  ASSERT_SAME_TYPE(typename M::size_type, decltype(std::erase_if(s, p)));
+  assert(expected_erased_count == std::erase_if(s, p));
+  M e = make<M>(expected);
+  assert((std::is_permutation(s.begin(), s.end(), e.begin(), e.end())));
 }
 
-
 template <typename S>
 void test()
 {
@@ -51,22 +49,22 @@ void test()
     auto True  = [](auto) { return true; };
     auto False = [](auto) { return false; };
 
-    test0<S>({}, is1, {});
+    test0<S>({}, is1, {}, 0);
 
-    test0<S>({1}, is1, {});
-    test0<S>({1}, is2, {1});
+    test0<S>({1}, is1, {}, 1);
+    test0<S>({1}, is2, {1}, 0);
 
-    test0<S>({1,2}, is1, {2});
-    test0<S>({1,2}, is2, {1});
-    test0<S>({1,2}, is3, {1,2});
+    test0<S>({1, 2}, is1, {2}, 1);
+    test0<S>({1, 2}, is2, {1}, 1);
+    test0<S>({1, 2}, is3, {1, 2}, 0);
 
-    test0<S>({1,2,3}, is1, {2,3});
-    test0<S>({1,2,3}, is2, {1,3});
-    test0<S>({1,2,3}, is3, {1,2});
-    test0<S>({1,2,3}, is4, {1,2,3});
+    test0<S>({1, 2, 3}, is1, {2, 3}, 1);
+    test0<S>({1, 2, 3}, is2, {1, 3}, 1);
+    test0<S>({1, 2, 3}, is3, {1, 2}, 1);
+    test0<S>({1, 2, 3}, is4, {1, 2, 3}, 0);
 
-    test0<S>({1,2,3}, True,  {});
-    test0<S>({1,2,3}, False, {1,2,3});
+    test0<S>({1, 2, 3}, True, {}, 3);
+    test0<S>({1, 2, 3}, False, {1, 2, 3}, 0);
 }
 
 int main(int, char**)

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/deque.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/deque.version.pass.cpp
index 9d07dcdd2466..ac6f94ff70f9 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/deque.version.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/deque.version.pass.cpp
@@ -15,7 +15,7 @@
 
 /*  Constant                                      Value
     __cpp_lib_allocator_traits_is_always_equal    201411L [C++17]
-    __cpp_lib_erase_if                            201811L [C++2a]
+    __cpp_lib_erase_if                            202002L [C++2a]
     __cpp_lib_nonmember_container_access          201411L [C++17]
 */
 
@@ -82,8 +82,8 @@
 # ifndef __cpp_lib_erase_if
 #   error "__cpp_lib_erase_if should be defined in c++2a"
 # endif
-# if __cpp_lib_erase_if != 201811L
-#   error "__cpp_lib_erase_if should have the value 201811L in c++2a"
+# if __cpp_lib_erase_if != 202002L
+#   error "__cpp_lib_erase_if should have the value 202002L in c++2a"
 # endif
 
 # ifndef __cpp_lib_nonmember_container_access

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/forward_list.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/forward_list.version.pass.cpp
index 4004e6b70a2a..837abe395404 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/forward_list.version.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/forward_list.version.pass.cpp
@@ -15,7 +15,7 @@
 
 /*  Constant                                      Value
     __cpp_lib_allocator_traits_is_always_equal    201411L [C++17]
-    __cpp_lib_erase_if                            201811L [C++2a]
+    __cpp_lib_erase_if                            202002L [C++2a]
     __cpp_lib_incomplete_container_elements       201505L [C++17]
     __cpp_lib_list_remove_return_type             201806L [C++2a]
     __cpp_lib_nonmember_container_access          201411L [C++17]
@@ -111,8 +111,8 @@
 # ifndef __cpp_lib_erase_if
 #   error "__cpp_lib_erase_if should be defined in c++2a"
 # endif
-# if __cpp_lib_erase_if != 201811L
-#   error "__cpp_lib_erase_if should have the value 201811L in c++2a"
+# if __cpp_lib_erase_if != 202002L
+#   error "__cpp_lib_erase_if should have the value 202002L in c++2a"
 # endif
 
 # ifndef __cpp_lib_incomplete_container_elements

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/list.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/list.version.pass.cpp
index 01570b69a5bb..218510fb65ef 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/list.version.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/list.version.pass.cpp
@@ -15,7 +15,7 @@
 
 /*  Constant                                      Value
     __cpp_lib_allocator_traits_is_always_equal    201411L [C++17]
-    __cpp_lib_erase_if                            201811L [C++2a]
+    __cpp_lib_erase_if                            202002L [C++2a]
     __cpp_lib_incomplete_container_elements       201505L [C++17]
     __cpp_lib_list_remove_return_type             201806L [C++2a]
     __cpp_lib_nonmember_container_access          201411L [C++17]
@@ -111,8 +111,8 @@
 # ifndef __cpp_lib_erase_if
 #   error "__cpp_lib_erase_if should be defined in c++2a"
 # endif
-# if __cpp_lib_erase_if != 201811L
-#   error "__cpp_lib_erase_if should have the value 201811L in c++2a"
+# if __cpp_lib_erase_if != 202002L
+#   error "__cpp_lib_erase_if should have the value 202002L in c++2a"
 # endif
 
 # ifndef __cpp_lib_incomplete_container_elements

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/map.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/map.version.pass.cpp
index a41dd1b8e986..c6ef179249b1 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/map.version.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/map.version.pass.cpp
@@ -15,7 +15,7 @@
 
 /*  Constant                                      Value
     __cpp_lib_allocator_traits_is_always_equal    201411L [C++17]
-    __cpp_lib_erase_if                            201811L [C++2a]
+    __cpp_lib_erase_if                            202002L [C++2a]
     __cpp_lib_generic_associative_lookup          201304L [C++14]
     __cpp_lib_map_try_emplace                     201411L [C++17]
     __cpp_lib_node_extract                        201606L [C++17]
@@ -133,8 +133,8 @@
 # ifndef __cpp_lib_erase_if
 #   error "__cpp_lib_erase_if should be defined in c++2a"
 # endif
-# if __cpp_lib_erase_if != 201811L
-#   error "__cpp_lib_erase_if should have the value 201811L in c++2a"
+# if __cpp_lib_erase_if != 202002L
+#   error "__cpp_lib_erase_if should have the value 202002L in c++2a"
 # endif
 
 # ifndef __cpp_lib_generic_associative_lookup

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/set.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/set.version.pass.cpp
index 80cf9c0af3ca..bc26397d6431 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/set.version.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/set.version.pass.cpp
@@ -15,7 +15,7 @@
 
 /*  Constant                                      Value
     __cpp_lib_allocator_traits_is_always_equal    201411L [C++17]
-    __cpp_lib_erase_if                            201811L [C++2a]
+    __cpp_lib_erase_if                            202002L [C++2a]
     __cpp_lib_generic_associative_lookup          201304L [C++14]
     __cpp_lib_node_extract                        201606L [C++17]
     __cpp_lib_nonmember_container_access          201411L [C++17]
@@ -117,8 +117,8 @@
 # ifndef __cpp_lib_erase_if
 #   error "__cpp_lib_erase_if should be defined in c++2a"
 # endif
-# if __cpp_lib_erase_if != 201811L
-#   error "__cpp_lib_erase_if should have the value 201811L in c++2a"
+# if __cpp_lib_erase_if != 202002L
+#   error "__cpp_lib_erase_if should have the value 202002L in c++2a"
 # endif
 
 # ifndef __cpp_lib_generic_associative_lookup

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.pass.cpp
index bdd517da0de6..eacd5ff1ecbd 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.pass.cpp
@@ -16,7 +16,7 @@
 /*  Constant                                      Value
     __cpp_lib_allocator_traits_is_always_equal    201411L [C++17]
     __cpp_lib_char8_t                             201811L [C++2a]
-    __cpp_lib_erase_if                            201811L [C++2a]
+    __cpp_lib_erase_if                            202002L [C++2a]
     __cpp_lib_nonmember_container_access          201411L [C++17]
     __cpp_lib_string_udls                         201304L [C++14]
     __cpp_lib_string_view                         201606L [C++17]
@@ -143,8 +143,8 @@
 # ifndef __cpp_lib_erase_if
 #   error "__cpp_lib_erase_if should be defined in c++2a"
 # endif
-# if __cpp_lib_erase_if != 201811L
-#   error "__cpp_lib_erase_if should have the value 201811L in c++2a"
+# if __cpp_lib_erase_if != 202002L
+#   error "__cpp_lib_erase_if should have the value 202002L in c++2a"
 # endif
 
 # ifndef __cpp_lib_nonmember_container_access

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_map.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_map.version.pass.cpp
index 07eb1a9bc351..62c974add1ba 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_map.version.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_map.version.pass.cpp
@@ -15,7 +15,7 @@
 
 /*  Constant                                      Value
     __cpp_lib_allocator_traits_is_always_equal    201411L [C++17]
-    __cpp_lib_erase_if                            201811L [C++2a]
+    __cpp_lib_erase_if                            202002L [C++2a]
     __cpp_lib_generic_unordered_lookup            201811L [C++2a]
     __cpp_lib_node_extract                        201606L [C++17]
     __cpp_lib_nonmember_container_access          201411L [C++17]
@@ -127,8 +127,8 @@
 # ifndef __cpp_lib_erase_if
 #   error "__cpp_lib_erase_if should be defined in c++2a"
 # endif
-# if __cpp_lib_erase_if != 201811L
-#   error "__cpp_lib_erase_if should have the value 201811L in c++2a"
+# if __cpp_lib_erase_if != 202002L
+#   error "__cpp_lib_erase_if should have the value 202002L in c++2a"
 # endif
 
 # if !defined(_LIBCPP_VERSION)

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_set.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_set.version.pass.cpp
index 845318a79a5e..6fe59790857b 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_set.version.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_set.version.pass.cpp
@@ -15,7 +15,7 @@
 
 /*  Constant                                      Value
     __cpp_lib_allocator_traits_is_always_equal    201411L [C++17]
-    __cpp_lib_erase_if                            201811L [C++2a]
+    __cpp_lib_erase_if                            202002L [C++2a]
     __cpp_lib_generic_unordered_lookup            201811L [C++2a]
     __cpp_lib_node_extract                        201606L [C++17]
     __cpp_lib_nonmember_container_access          201411L [C++17]
@@ -111,8 +111,8 @@
 # ifndef __cpp_lib_erase_if
 #   error "__cpp_lib_erase_if should be defined in c++2a"
 # endif
-# if __cpp_lib_erase_if != 201811L
-#   error "__cpp_lib_erase_if should have the value 201811L in c++2a"
+# if __cpp_lib_erase_if != 202002L
+#   error "__cpp_lib_erase_if should have the value 202002L in c++2a"
 # endif
 
 # if !defined(_LIBCPP_VERSION)

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/vector.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/vector.version.pass.cpp
index 3ea2a0cf00b1..60bba44446c6 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/vector.version.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/vector.version.pass.cpp
@@ -15,7 +15,7 @@
 
 /*  Constant                                      Value
     __cpp_lib_allocator_traits_is_always_equal    201411L [C++17]
-    __cpp_lib_erase_if                            201811L [C++2a]
+    __cpp_lib_erase_if                            202002L [C++2a]
     __cpp_lib_incomplete_container_elements       201505L [C++17]
     __cpp_lib_nonmember_container_access          201411L [C++17]
 */
@@ -98,8 +98,8 @@
 # ifndef __cpp_lib_erase_if
 #   error "__cpp_lib_erase_if should be defined in c++2a"
 # endif
-# if __cpp_lib_erase_if != 201811L
-#   error "__cpp_lib_erase_if should have the value 201811L in c++2a"
+# if __cpp_lib_erase_if != 202002L
+#   error "__cpp_lib_erase_if should have the value 202002L in c++2a"
 # endif
 
 # ifndef __cpp_lib_incomplete_container_elements

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
index c55c577aa003..081f0fede234 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
@@ -38,7 +38,7 @@
     __cpp_lib_destroying_delete                    201806L [C++2a]
     __cpp_lib_enable_shared_from_this              201603L [C++17]
     __cpp_lib_endian                               201907L [C++2a]
-    __cpp_lib_erase_if                             201811L [C++2a]
+    __cpp_lib_erase_if                             202002L [C++2a]
     __cpp_lib_exchange_function                    201304L [C++14]
     __cpp_lib_execution                            201603L [C++17]
     __cpp_lib_filesystem                           201703L [C++17]
@@ -1718,8 +1718,8 @@
 # ifndef __cpp_lib_erase_if
 #   error "__cpp_lib_erase_if should be defined in c++2a"
 # endif
-# if __cpp_lib_erase_if != 201811L
-#   error "__cpp_lib_erase_if should have the value 201811L in c++2a"
+# if __cpp_lib_erase_if != 202002L
+#   error "__cpp_lib_erase_if should have the value 202002L in c++2a"
 # endif
 
 # ifndef __cpp_lib_exchange_function

diff  --git a/libcxx/test/std/strings/strings.erasure/erase.pass.cpp b/libcxx/test/std/strings/strings.erasure/erase.pass.cpp
index 26d6b8674e87..6614d65b9527 100644
--- a/libcxx/test/std/strings/strings.erasure/erase.pass.cpp
+++ b/libcxx/test/std/strings/strings.erasure/erase.pass.cpp
@@ -10,8 +10,8 @@
 // <string>
 
 // template <class charT, class traits, class Allocator, class U>
-//   void erase(basic_string<charT, traits, Allocator>& c, const U& value);
-
+//   typename basic_string<charT, traits, Allocator>::size_type
+//   erase(basic_string<charT, traits, Allocator>& c, const U& value);
 
 #include <string>
 #include <optional>
@@ -21,50 +21,48 @@
 #include "min_allocator.h"
 
 template <class S, class U>
-void
-test0(S s,  U val, S expected)
-{
-    ASSERT_SAME_TYPE(void, decltype(std::erase(s, val)));
-    std::erase(s, val);
-    LIBCPP_ASSERT(s.__invariants());
-    assert(s == expected);
+void test0(S s, U val, S expected, size_t expected_erased_count) {
+  ASSERT_SAME_TYPE(typename S::size_type, decltype(std::erase(s, val)));
+  assert(expected_erased_count == std::erase(s, val));
+  LIBCPP_ASSERT(s.__invariants());
+  assert(s == expected);
 }
 
 template <class S>
 void test()
 {
 
-    test0(S(""), 'a', S(""));
+  test0(S(""), 'a', S(""), 0);
 
-    test0(S("a"), 'a', S(""));
-    test0(S("a"), 'b', S("a"));
+  test0(S("a"), 'a', S(""), 1);
+  test0(S("a"), 'b', S("a"), 0);
 
-    test0(S("ab"), 'a', S("b"));
-    test0(S("ab"), 'b', S("a"));
-    test0(S("ab"), 'c', S("ab"));
-    test0(S("aa"), 'a', S(""));
-    test0(S("aa"), 'c', S("aa"));
+  test0(S("ab"), 'a', S("b"), 1);
+  test0(S("ab"), 'b', S("a"), 1);
+  test0(S("ab"), 'c', S("ab"), 0);
+  test0(S("aa"), 'a', S(""), 2);
+  test0(S("aa"), 'c', S("aa"), 0);
 
-    test0(S("abc"), 'a', S("bc"));
-    test0(S("abc"), 'b', S("ac"));
-    test0(S("abc"), 'c', S("ab"));
-    test0(S("abc"), 'd', S("abc"));
+  test0(S("abc"), 'a', S("bc"), 1);
+  test0(S("abc"), 'b', S("ac"), 1);
+  test0(S("abc"), 'c', S("ab"), 1);
+  test0(S("abc"), 'd', S("abc"), 0);
 
-    test0(S("aab"), 'a', S("b"));
-    test0(S("aab"), 'b', S("aa"));
-    test0(S("aab"), 'c', S("aab"));
-    test0(S("abb"), 'a', S("bb"));
-    test0(S("abb"), 'b', S("a"));
-    test0(S("abb"), 'c', S("abb"));
-    test0(S("aaa"), 'a', S(""));
-    test0(S("aaa"), 'b', S("aaa"));
+  test0(S("aab"), 'a', S("b"), 2);
+  test0(S("aab"), 'b', S("aa"), 1);
+  test0(S("aab"), 'c', S("aab"), 0);
+  test0(S("abb"), 'a', S("bb"), 1);
+  test0(S("abb"), 'b', S("a"), 2);
+  test0(S("abb"), 'c', S("abb"), 0);
+  test0(S("aaa"), 'a', S(""), 3);
+  test0(S("aaa"), 'b', S("aaa"), 0);
 
-//  Test cross-type erasure
-    using opt = std::optional<typename S::value_type>;
-    test0(S("aba"), opt(),    S("aba"));
-    test0(S("aba"), opt('a'), S("b"));
-    test0(S("aba"), opt('b'), S("aa"));
-    test0(S("aba"), opt('c'), S("aba"));
+  //  Test cross-type erasure
+  using opt = std::optional<typename S::value_type>;
+  test0(S("aba"), opt(), S("aba"), 0);
+  test0(S("aba"), opt('a'), S("b"), 2);
+  test0(S("aba"), opt('b'), S("aa"), 1);
+  test0(S("aba"), opt('c'), S("aba"), 0);
 }
 
 int main(int, char**)

diff  --git a/libcxx/test/std/strings/strings.erasure/erase_if.pass.cpp b/libcxx/test/std/strings/strings.erasure/erase_if.pass.cpp
index 30a58c0e646d..c46a32586805 100644
--- a/libcxx/test/std/strings/strings.erasure/erase_if.pass.cpp
+++ b/libcxx/test/std/strings/strings.erasure/erase_if.pass.cpp
@@ -10,7 +10,8 @@
 // <string>
 
 // template <class charT, class traits, class Allocator, class Predicate>
-//   void erase_if(basic_string<charT, traits, Allocator>& c, Predicate pred);
+//   typename basic_string<charT, traits, Allocator>::size_type
+//   erase_if(basic_string<charT, traits, Allocator>& c, Predicate pred);
 
 #include <string>
 
@@ -19,13 +20,11 @@
 #include "min_allocator.h"
 
 template <class S, class Pred>
-void
-test0(S s, Pred p, S expected)
-{
-    ASSERT_SAME_TYPE(void, decltype(std::erase_if(s, p)));
-    std::erase_if(s, p);
-    LIBCPP_ASSERT(s.__invariants());
-    assert(s == expected);
+void test0(S s, Pred p, S expected, size_t expected_erased_count) {
+  ASSERT_SAME_TYPE(typename S::size_type, decltype(std::erase_if(s, p)));
+  assert(expected_erased_count == std::erase_if(s, p));
+  LIBCPP_ASSERT(s.__invariants());
+  assert(s == expected);
 }
 
 template <typename S>
@@ -38,33 +37,33 @@ void test()
     auto True  = [](auto) { return true; };
     auto False = [](auto) { return false; };
 
-    test0(S(""), isA, S(""));
+    test0(S(""), isA, S(""), 0);
 
-    test0(S("a"), isA, S(""));
-    test0(S("a"), isB, S("a"));
+    test0(S("a"), isA, S(""), 1);
+    test0(S("a"), isB, S("a"), 0);
 
-    test0(S("ab"), isA, S("b"));
-    test0(S("ab"), isB, S("a"));
-    test0(S("ab"), isC, S("ab"));
-    test0(S("aa"), isA, S(""));
-    test0(S("aa"), isC, S("aa"));
+    test0(S("ab"), isA, S("b"), 1);
+    test0(S("ab"), isB, S("a"), 1);
+    test0(S("ab"), isC, S("ab"), 0);
+    test0(S("aa"), isA, S(""), 2);
+    test0(S("aa"), isC, S("aa"), 0);
 
-    test0(S("abc"), isA, S("bc"));
-    test0(S("abc"), isB, S("ac"));
-    test0(S("abc"), isC, S("ab"));
-    test0(S("abc"), isD, S("abc"));
+    test0(S("abc"), isA, S("bc"), 1);
+    test0(S("abc"), isB, S("ac"), 1);
+    test0(S("abc"), isC, S("ab"), 1);
+    test0(S("abc"), isD, S("abc"), 0);
 
-    test0(S("aab"), isA, S("b"));
-    test0(S("aab"), isB, S("aa"));
-    test0(S("aab"), isC, S("aab"));
-    test0(S("abb"), isA, S("bb"));
-    test0(S("abb"), isB, S("a"));
-    test0(S("abb"), isC, S("abb"));
-    test0(S("aaa"), isA, S(""));
-    test0(S("aaa"), isB, S("aaa"));
+    test0(S("aab"), isA, S("b"), 2);
+    test0(S("aab"), isB, S("aa"), 1);
+    test0(S("aab"), isC, S("aab"), 0);
+    test0(S("abb"), isA, S("bb"), 1);
+    test0(S("abb"), isB, S("a"), 2);
+    test0(S("abb"), isC, S("abb"), 0);
+    test0(S("aaa"), isA, S(""), 3);
+    test0(S("aaa"), isB, S("aaa"), 0);
 
-    test0(S("aba"), False,  S("aba"));
-    test0(S("aba"), True,   S(""));
+    test0(S("aba"), False, S("aba"), 0);
+    test0(S("aba"), True, S(""), 3);
 }
 
 int main(int, char**)

diff  --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 8caee5c13ba9..96860c2118c2 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -475,7 +475,7 @@ def add_version_header(tc):
    },
   {"name": "__cpp_lib_erase_if",
    "values": {
-     "c++2a": int(201811),
+     "c++2a": int(202002),
    },
    "headers": ["string", "deque", "forward_list", "list", "vector", "map",
                "set", "unordered_map", "unordered_set"]
@@ -587,7 +587,7 @@ def add_version_header(tc):
    },
   {"name": "__cpp_lib_to_array",
    "values": {
-     "c++2a": 201907L,
+     "c++2a": int(201907),
    },
    "headers": ["array"],
    },

diff  --git a/libcxx/www/cxx2a_status.html b/libcxx/www/cxx2a_status.html
index c8a74b56dafd..9f1ff469be0b 100644
--- a/libcxx/www/cxx2a_status.html
+++ b/libcxx/www/cxx2a_status.html
@@ -227,7 +227,7 @@ <h3>Paper Status</h3>
   	<tr><td></td><td></td><td></td><td></td><td></td><td></td></tr>
 	<tr><td><a href="https://wg21.link/P0586">P0586</a></td><td>LWG</td><td>Safe integral comparisons</td><td>Prague</td><td><i> </i></td><td></td></tr>
 	<tr><td><a href="https://wg21.link/P0593">P0593</a></td><td>CWG</td><td>Implicit creation of objects for low-level object manipulation</td><td>Prague</td><td><i> </i></td><td></td></tr>
-	<tr><td><a href="https://wg21.link/P1115">P1115</a></td><td>LWG</td><td>Improving the Return Value of Erase-Like Algorithms II: Free erase/erase if</td><td>Prague</td><td><i> </i></td><td></td></tr>
+	<tr><td><a href="https://wg21.link/P1115">P1115</a></td><td>LWG</td><td>Improving the Return Value of Erase-Like Algorithms II: Free erase/erase if</td><td>Prague</td><td>Complete</td><td>11.0</td></tr>
 	<tr><td><a href="https://wg21.link/P1243">P1243</a></td><td>LWG</td><td>Rangify New Algorithms</td><td>Prague</td><td><i> </i></td><td></td></tr>
 	<tr><td><a href="https://wg21.link/P1460">P1460</a></td><td>LWG</td><td>Mandating the Standard Library: Clause 20 - Utilities library</td><td>Prague</td><td><i> </i></td><td></td></tr>
 	<tr><td><a href="https://wg21.link/P1739">P1739</a></td><td>LWG</td><td>Avoid template bloat for safe_ranges in combination with "subrange-y" view adaptors</td><td>Prague</td><td><i> </i></td><td></td></tr>


        


More information about the libcxx-commits mailing list