]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Call predicate with non-const values in std::erase_if [PR107850]
authorJonathan Wakely <jwakely@redhat.com>
Thu, 24 Nov 2022 21:09:03 +0000 (21:09 +0000)
committerJonathan Wakely <jwakely@redhat.com>
Thu, 27 Apr 2023 16:42:05 +0000 (17:42 +0100)
As specified in the standard, the predicate for std::erase_if has to be
invocable as non-const with a non-const lvalues argument. Restore
support for predicates that only accept non-const arguments.

It's not strictly nevessary to change it for the set and unordered_set
overloads, because they only give const access to the elements anyway.
I've done it for them too just to keep them all consistent.

libstdc++-v3/ChangeLog:

PR libstdc++/107850
* include/bits/erase_if.h (__erase_nodes_if): Use non-const
reference to the container.
* include/experimental/map (erase_if): Likewise.
* include/experimental/set (erase_if): Likewise.
* include/experimental/unordered_map (erase_if): Likewise.
* include/experimental/unordered_set (erase_if): Likewise.
* include/std/map (erase_if): Likewise.
* include/std/set (erase_if): Likewise.
* include/std/unordered_map (erase_if): Likewise.
* include/std/unordered_set (erase_if): Likewise.
* testsuite/23_containers/map/erasure.cc: Check with
const-incorrect predicate.
* testsuite/23_containers/set/erasure.cc: Likewise.
* testsuite/23_containers/unordered_map/erasure.cc: Likewise.
* testsuite/23_containers/unordered_set/erasure.cc: Likewise.
* testsuite/experimental/map/erasure.cc: Likewise.
* testsuite/experimental/set/erasure.cc: Likewise.
* testsuite/experimental/unordered_map/erasure.cc: Likewise.
* testsuite/experimental/unordered_set/erasure.cc: Likewise.

(cherry picked from commit f54ceb2062c7fef294f85ae093914fa6c7ca35b8)

17 files changed:
libstdc++-v3/include/bits/erase_if.h
libstdc++-v3/include/experimental/map
libstdc++-v3/include/experimental/set
libstdc++-v3/include/experimental/unordered_map
libstdc++-v3/include/experimental/unordered_set
libstdc++-v3/include/std/map
libstdc++-v3/include/std/set
libstdc++-v3/include/std/unordered_map
libstdc++-v3/include/std/unordered_set
libstdc++-v3/testsuite/23_containers/map/erasure.cc
libstdc++-v3/testsuite/23_containers/set/erasure.cc
libstdc++-v3/testsuite/23_containers/unordered_map/erasure.cc
libstdc++-v3/testsuite/23_containers/unordered_set/erasure.cc
libstdc++-v3/testsuite/experimental/map/erasure.cc
libstdc++-v3/testsuite/experimental/set/erasure.cc
libstdc++-v3/testsuite/experimental/unordered_map/erasure.cc
libstdc++-v3/testsuite/experimental/unordered_set/erasure.cc

index 397207f4b56804e12c9a384bae48787cedb9826e..b336e263d2d1d7b8b4b44e41692c83d9ae232399 100644 (file)
@@ -49,7 +49,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     template<typename _Container, typename _UnsafeContainer,
             typename _Predicate>
       typename _Container::size_type
-      __erase_nodes_if(_Container& __cont, const _UnsafeContainer& __ucont,
+      __erase_nodes_if(_Container& __cont, _UnsafeContainer& __ucont,
                       _Predicate __pred)
       {
        typename _Container::size_type __num = 0;
index 4936a66018978066541c2cc611a78a19d45e56b8..4e615c7793bbf906bbfbc1c4f06226eba7f4afe8 100644 (file)
@@ -51,8 +51,7 @@ inline namespace fundamentals_v2
     inline void
     erase_if(map<_Key, _Tp, _Compare, _Alloc>& __cont, _Predicate __pred)
     {
-      const _GLIBCXX_STD_C::map<_Key, _Tp, _Compare, _Alloc>&
-       __ucont = __cont;
+      _GLIBCXX_STD_C::map<_Key, _Tp, _Compare, _Alloc>& __ucont = __cont;
       std::__detail::__erase_nodes_if(__cont, __ucont, __pred);
     }
 
@@ -61,8 +60,7 @@ inline namespace fundamentals_v2
     inline void
     erase_if(multimap<_Key, _Tp, _Compare, _Alloc>& __cont, _Predicate __pred)
     {
-      const _GLIBCXX_STD_C::multimap<_Key, _Tp, _Compare, _Alloc>&
-       __ucont = __cont;
+      _GLIBCXX_STD_C::multimap<_Key, _Tp, _Compare, _Alloc>& __ucont = __cont;
       std::__detail::__erase_nodes_if(__cont, __ucont, __pred);
     }
 
index aa43a2b2fc372a81033577aa3682266fc662b75d..3d46a0bff7ce1128917a783e088cf2c5b02383de 100644 (file)
@@ -51,7 +51,7 @@ inline namespace fundamentals_v2
     inline void
     erase_if(set<_Key, _Compare, _Alloc>& __cont, _Predicate __pred)
     {
-      const _GLIBCXX_STD_C::set<_Key, _Compare, _Alloc>& __ucont = __cont;
+      _GLIBCXX_STD_C::set<_Key, _Compare, _Alloc>& __ucont = __cont;
       std::__detail::__erase_nodes_if(__cont, __ucont, __pred);
     }
 
@@ -60,7 +60,7 @@ inline namespace fundamentals_v2
     inline void
     erase_if(multiset<_Key, _Compare, _Alloc>& __cont, _Predicate __pred)
     {
-      const _GLIBCXX_STD_C::multiset<_Key, _Compare, _Alloc>& __ucont = __cont;
+      _GLIBCXX_STD_C::multiset<_Key, _Compare, _Alloc>& __ucont = __cont;
       std::__detail::__erase_nodes_if(__cont, __ucont, __pred);
     }
 
index 1a41687d5933894a2f80bb4d396d25e85253fbc2..26fff83c893af6d7aac92e602f8dac20e0127b39 100644 (file)
@@ -52,7 +52,7 @@ inline namespace fundamentals_v2
     erase_if(unordered_map<_Key, _Tp, _Hash, _CPred, _Alloc>& __cont,
             _Predicate __pred)
     {
-      const _GLIBCXX_STD_C::unordered_map<_Key, _Tp, _Hash, _CPred, _Alloc>&
+      _GLIBCXX_STD_C::unordered_map<_Key, _Tp, _Hash, _CPred, _Alloc>&
        __ucont = __cont;
       std::__detail::__erase_nodes_if(__cont, __ucont, __pred);
     }
@@ -63,7 +63,7 @@ inline namespace fundamentals_v2
     erase_if(unordered_multimap<_Key, _Tp, _Hash, _CPred, _Alloc>& __cont,
             _Predicate __pred)
     {
-      const _GLIBCXX_STD_C::unordered_multimap<_Key, _Tp, _Hash, _CPred, _Alloc>&
+      _GLIBCXX_STD_C::unordered_multimap<_Key, _Tp, _Hash, _CPred, _Alloc>&
        __ucont = __cont;
       std::__detail::__erase_nodes_if(__cont, __ucont, __pred);
     }
index 583c43798a763263d3d79d334e7969f1cf838225..22fe49d8fdf69d9005051bb1a32d1695ca98a888 100644 (file)
@@ -52,7 +52,7 @@ inline namespace fundamentals_v2
     erase_if(unordered_set<_Key, _Hash, _CPred, _Alloc>& __cont,
             _Predicate __pred)
     {
-      const _GLIBCXX_STD_C::unordered_set<_Key, _Hash, _CPred, _Alloc>&
+      _GLIBCXX_STD_C::unordered_set<_Key, _Hash, _CPred, _Alloc>&
        __ucont = __cont;
       std::__detail::__erase_nodes_if(__cont, __ucont, __pred);
     }
@@ -63,7 +63,7 @@ inline namespace fundamentals_v2
     erase_if(unordered_multiset<_Key, _Hash, _CPred, _Alloc>& __cont,
             _Predicate __pred)
     {
-      const _GLIBCXX_STD_C::unordered_multiset<_Key, _Hash, _CPred, _Alloc>&
+      _GLIBCXX_STD_C::unordered_multiset<_Key, _Hash, _CPred, _Alloc>&
        __ucont = __cont;
       std::__detail::__erase_nodes_if(__cont, __ucont, __pred);
     }
index 93c956af916654d68b5df98d7a989c62138cef45..1311d617404b63f68eddd11224e0c274f78eec69 100644 (file)
@@ -96,8 +96,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     inline typename map<_Key, _Tp, _Compare, _Alloc>::size_type
     erase_if(map<_Key, _Tp, _Compare, _Alloc>& __cont, _Predicate __pred)
     {
-      const _GLIBCXX_STD_C::map<_Key, _Tp, _Compare, _Alloc>&
-       __ucont = __cont;
+      _GLIBCXX_STD_C::map<_Key, _Tp, _Compare, _Alloc>& __ucont = __cont;
       return __detail::__erase_nodes_if(__cont, __ucont, __pred);
     }
 
@@ -106,8 +105,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     inline typename multimap<_Key, _Tp, _Compare, _Alloc>::size_type
     erase_if(multimap<_Key, _Tp, _Compare, _Alloc>& __cont, _Predicate __pred)
     {
-      const _GLIBCXX_STD_C::multimap<_Key, _Tp, _Compare, _Alloc>&
-       __ucont = __cont;
+      _GLIBCXX_STD_C::multimap<_Key, _Tp, _Compare, _Alloc>& __ucont = __cont;
       return __detail::__erase_nodes_if(__cont, __ucont, __pred);
     }
 _GLIBCXX_END_NAMESPACE_VERSION
index 45fed14c51e30e95878de793c165d79a69a40af8..751279120a22e54e7fe1f211c2292ed1f5530b6c 100644 (file)
@@ -92,7 +92,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     inline typename set<_Key, _Compare, _Alloc>::size_type
     erase_if(set<_Key, _Compare, _Alloc>& __cont, _Predicate __pred)
     {
-      const _GLIBCXX_STD_C::set<_Key, _Compare, _Alloc>& __ucont = __cont;
+      _GLIBCXX_STD_C::set<_Key, _Compare, _Alloc>& __ucont = __cont;
       return __detail::__erase_nodes_if(__cont, __ucont, __pred);
     }
 
@@ -101,7 +101,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     inline typename multiset<_Key, _Compare, _Alloc>::size_type
     erase_if(multiset<_Key, _Compare, _Alloc>& __cont, _Predicate __pred)
     {
-      const _GLIBCXX_STD_C::multiset<_Key, _Compare, _Alloc>& __ucont = __cont;
+      _GLIBCXX_STD_C::multiset<_Key, _Compare, _Alloc>& __ucont = __cont;
       return __detail::__erase_nodes_if(__cont, __ucont, __pred);
     }
 _GLIBCXX_END_NAMESPACE_VERSION
index bb14ffa7f2e55ab6ee47ddbe88357b454b8763d1..d57e8dd4959fb62eba46279881d4b239b6811a70 100644 (file)
@@ -84,7 +84,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     erase_if(unordered_map<_Key, _Tp, _Hash, _CPred, _Alloc>& __cont,
             _Predicate __pred)
     {
-      const _GLIBCXX_STD_C::unordered_map<_Key, _Tp, _Hash, _CPred, _Alloc>&
+      _GLIBCXX_STD_C::unordered_map<_Key, _Tp, _Hash, _CPred, _Alloc>&
        __ucont = __cont;
       return __detail::__erase_nodes_if(__cont, __ucont, __pred);
     }
@@ -96,7 +96,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     erase_if(unordered_multimap<_Key, _Tp, _Hash, _CPred, _Alloc>& __cont,
             _Predicate __pred)
     {
-      const _GLIBCXX_STD_C::unordered_multimap<_Key, _Tp, _Hash, _CPred, _Alloc>&
+      _GLIBCXX_STD_C::unordered_multimap<_Key, _Tp, _Hash, _CPred, _Alloc>&
        __ucont = __cont;
       return __detail::__erase_nodes_if(__cont, __ucont, __pred);
     }
index 777e3b8111628519bd5afd186e8d9508b00f889a..a86a80c36be81f4480e560734c9c4f1213ebacf5 100644 (file)
@@ -84,7 +84,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     erase_if(unordered_set<_Key, _Hash, _CPred, _Alloc>& __cont,
             _Predicate __pred)
     {
-      const _GLIBCXX_STD_C::unordered_set<_Key, _Hash, _CPred, _Alloc>&
+      _GLIBCXX_STD_C::unordered_set<_Key, _Hash, _CPred, _Alloc>&
        __ucont = __cont;
       return __detail::__erase_nodes_if(__cont, __ucont, __pred);
     }
@@ -95,7 +95,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     erase_if(unordered_multiset<_Key, _Hash, _CPred, _Alloc>& __cont,
             _Predicate __pred)
     {
-      const _GLIBCXX_STD_C::unordered_multiset<_Key, _Hash, _CPred, _Alloc>&
+      _GLIBCXX_STD_C::unordered_multiset<_Key, _Hash, _CPred, _Alloc>&
        __ucont = __cont;
       return __detail::__erase_nodes_if(__cont, __ucont, __pred);
     }
index badf7896df6a675888119087522f1be0f78c10b3..643ad0a3f17fd8f84d6b1ad68619857e92e15e0b 100644 (file)
@@ -61,11 +61,24 @@ test02()
   VERIFY( num == 4 );
 }
 
+void
+test_pr107850()
+{
+  // Predicate only callable as non-const and only accepts non-const argument.
+  struct Pred { bool operator()(std::pair<const int, int>&) { return false; } };
+  const Pred pred; // erase_if parameter is passed by value, so non-const.
+  std::map<int, int> m;
+  std::erase_if(m, pred);
+  std::multimap<int, int> mm;
+  std::erase_if(mm, pred);
+}
+
 int
 main()
 {
   test01();
   test02();
+  test_pr107850();
 
   return 0;
 }
index fe0c4b8766b5180e2b61dd5604d754ce6865d2af..bfa28f2600966e6b09bbc65789e9b0172f685562 100644 (file)
@@ -49,11 +49,24 @@ test02()
   VERIFY( num == 4 );
 }
 
+void
+test_pr107850()
+{
+  // Predicate only callable as non-const.
+  struct Pred { bool operator()(const int&) { return false; } };
+  const Pred pred; // erase_if parameter is passed by value, so non-const.
+  std::set<int> s;
+  std::erase_if(s, pred);
+  std::multiset<int> ms;
+  std::erase_if(ms, pred);
+}
+
 int
 main()
 {
   test01();
   test02();
+  test_pr107850();
 
   return 0;
 }
index e6018186bf28a7bcb2b4d390c9a4a27d10315e5b..8392e538ac7509e53da7afa36a0975c99a663c8b 100644 (file)
@@ -61,11 +61,24 @@ test02()
   VERIFY( num == 4 );
 }
 
+void
+test_pr107850()
+{
+  // Predicate only callable as non-const and only accepts non-const argument.
+  struct Pred { bool operator()(std::pair<const int, int>&) { return false; } };
+  const Pred pred; // erase_if parameter is passed by value, so non-const.
+  std::unordered_map<int, int> m;
+  std::erase_if(m, pred);
+  std::unordered_multimap<int, int> mm;
+  std::erase_if(mm, pred);
+}
+
 int
 main()
 {
   test01();
   test02();
+  test_pr107850();
 
   return 0;
 }
index 4cb80413ff0f7acaaa0441d417c228beb5306d63..768454942893d38e6ff8611b7ba7470f1501d694 100644 (file)
@@ -51,11 +51,24 @@ test02()
   VERIFY( num == 4 );
 }
 
+void
+test_pr107850()
+{
+  // Predicate only callable as non-const.
+  struct Pred { bool operator()(const int&) { return false; } };
+  const Pred pred; // erase_if parameter is passed by value, so non-const.
+  std::unordered_set<int> s;
+  std::erase_if(s, pred);
+  std::unordered_multiset<int> ms;
+  std::erase_if(ms, pred);
+}
+
 int
 main()
 {
   test01();
   test02();
+  test_pr107850();
 
   return 0;
 }
index 8470ab2e99b4da47eae239338bf177f22da30c72..b377926898f9fe21b85d2dd9f53771e9aa26440a 100644 (file)
@@ -52,11 +52,24 @@ test02()
   VERIFY( mm == t );
 }
 
+void
+test_pr107850()
+{
+  // Predicate only callable as non-const and only accepts non-const argument.
+  struct Pred { bool operator()(std::pair<const int, int>&) { return false; } };
+  const Pred pred; // erase_if parameter is passed by value, so non-const.
+  std::map<int, int> m;
+  std::experimental::erase_if(m, pred);
+  std::multimap<int, int> mm;
+  std::experimental::erase_if(mm, pred);
+}
+
 int
 main()
 {
   test01();
   test02();
+  test_pr107850();
 
   return 0;
 }
index 1e04c3461a4c5a40ecd97d464199cc416c7f4a58..b4272282c320c8ecb365d348ee9fd89f7fdc225a 100644 (file)
@@ -40,11 +40,24 @@ test02()
   VERIFY( ms == t );
 }
 
+void
+test_pr107850()
+{
+  // Predicate only callable as non-const.
+  struct Pred { bool operator()(const int&) { return false; } };
+  const Pred pred; // erase_if parameter is passed by value, so non-const.
+  std::set<int> s;
+  std::experimental::erase_if(s, pred);
+  std::multiset<int> ms;
+  std::experimental::erase_if(ms, pred);
+}
+
 int
 main()
 {
   test01();
   test02();
+  test_pr107850();
 
   return 0;
 }
index 022f57583b03a47003d7493c83576ac3918bfd52..cd281bc70dad8bc90815c23f18ad611e025f909b 100644 (file)
@@ -52,11 +52,24 @@ test02()
   VERIFY( umm == t );
 }
 
+void
+test_pr107850()
+{
+  // Predicate only callable as non-const and only accepts non-const argument.
+  struct Pred { bool operator()(std::pair<const int, int>&) { return false; } };
+  const Pred pred; // erase_if parameter is passed by value, so non-const.
+  std::unordered_map<int, int> m;
+  std::experimental::erase_if(m, pred);
+  std::unordered_multimap<int, int> mm;
+  std::experimental::erase_if(mm, pred);
+}
+
 int
 main()
 {
   test01();
   test02();
+  test_pr107850();
 
   return 0;
 }
index d261812d4ec43d0b8dda7d6113d58ca947584657..918f455f5c001658cd6f91d738071b2d6db4b9e3 100644 (file)
@@ -42,11 +42,24 @@ test02()
   VERIFY( ums == t );
 }
 
+void
+test_pr107850()
+{
+  // Predicate only callable as non-const.
+  struct Pred { bool operator()(const int&) { return false; } };
+  const Pred pred; // erase_if parameter is passed by value, so non-const.
+  std::unordered_set<int> s;
+  std::experimental::erase_if(s, pred);
+  std::unordered_multiset<int> ms;
+  std::experimental::erase_if(ms, pred);
+}
+
 int
 main()
 {
   test01();
   test02();
+  test_pr107850();
 
   return 0;
 }