LWG 4135 (approved in Wrocław, November 2024) fixes the lambda
expressions used by std::erase for std::list and std::forward_list.
Previously they attempted to copy something that isn't required to be
copyable. Instead they should convert it to bool right away.

The issue resolution also changes the lambda's parameter to be const, so
that it can't modify the elements while comparing them.

libstdc++-v3/ChangeLog:

        * include/std/forward_list (erase): Change lambda to have
        explicit return type and const parameter type.
        * include/std/list (erase): Likewise.
        * testsuite/23_containers/forward_list/erasure.cc: Check lambda
        is correct.
        * testsuite/23_containers/list/erasure.cc: Likewise.
---

Tested x86_64-linux.

Also available at
https://forge.sourceware.org/gcc/gcc-TEST/pulls/39

 libstdc++-v3/include/std/forward_list         |  5 +++--
 libstdc++-v3/include/std/list                 |  5 +++--
 .../23_containers/forward_list/erasure.cc     | 22 +++++++++++++++++++
 .../testsuite/23_containers/list/erasure.cc   | 22 +++++++++++++++++++
 4 files changed, 50 insertions(+), 4 deletions(-)

diff --git a/libstdc++-v3/include/std/forward_list 
b/libstdc++-v3/include/std/forward_list
index 6c5ad1195db..166fdb04242 100644
--- a/libstdc++-v3/include/std/forward_list
+++ b/libstdc++-v3/include/std/forward_list
@@ -83,8 +83,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     inline typename forward_list<_Tp, _Alloc>::size_type
     erase(forward_list<_Tp, _Alloc>& __cont, const _Up& __value)
     {
-      using __elem_type = typename forward_list<_Tp, _Alloc>::value_type;
-      return std::erase_if(__cont, [&](__elem_type& __elem) {
+      // _GLIBCXX_RESOLVE_LIB_DEFECTS
+      // 4135. helper lambda of std::erase for list should specify return type
+      return std::erase_if(__cont, [&](const auto& __elem) -> bool {
          return __elem == __value;
       });
     }
diff --git a/libstdc++-v3/include/std/list b/libstdc++-v3/include/std/list
index 51f1bc079cc..170499d65f7 100644
--- a/libstdc++-v3/include/std/list
+++ b/libstdc++-v3/include/std/list
@@ -107,8 +107,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     inline typename list<_Tp, _Alloc>::size_type
     erase(list<_Tp, _Alloc>& __cont, const _Up& __value)
     {
-      using __elem_type = typename list<_Tp, _Alloc>::value_type;
-      return std::erase_if(__cont, [&](__elem_type& __elem) {
+      // _GLIBCXX_RESOLVE_LIB_DEFECTS
+      // 4135. helper lambda of std::erase for list should specify return type
+      return std::erase_if(__cont, [&](const auto& __elem) -> bool {
          return __elem == __value;
       });
     }
diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/erasure.cc 
b/libstdc++-v3/testsuite/23_containers/forward_list/erasure.cc
index 37e50203959..1ec11de6e36 100644
--- a/libstdc++-v3/testsuite/23_containers/forward_list/erasure.cc
+++ b/libstdc++-v3/testsuite/23_containers/forward_list/erasure.cc
@@ -53,6 +53,28 @@ test02()
   VERIFY( num == 0 );
 }
 
+// LWG 4135.
+// The helper lambda of std::erase for list should specify return type as bool
+void
+test_lwg4135()
+{
+  struct Bool {
+    Bool() = default;
+    Bool(const Bool&) = delete;
+    operator bool() const { return false; }
+  };
+
+  static Bool b;
+
+  struct Int {
+    Bool& operator==(Int) const { return b; }
+    void operator==(Int) = delete;
+  };
+
+  std::forward_list<Int> l;
+  std::erase(l, Int{});
+}
+
 int
 main()
 {
diff --git a/libstdc++-v3/testsuite/23_containers/list/erasure.cc 
b/libstdc++-v3/testsuite/23_containers/list/erasure.cc
index 1a33eca77c2..9f4f8536fe6 100644
--- a/libstdc++-v3/testsuite/23_containers/list/erasure.cc
+++ b/libstdc++-v3/testsuite/23_containers/list/erasure.cc
@@ -52,6 +52,28 @@ test02()
   VERIFY( num == 0 );
 }
 
+// LWG 4135.
+// The helper lambda of std::erase for list should specify return type as bool
+void
+test_lwg4135()
+{
+  struct Bool {
+    Bool() = default;
+    Bool(const Bool&) = delete;
+    operator bool() const { return false; }
+  };
+
+  static Bool b;
+
+  struct Int {
+    Bool& operator==(Int) const { return b; }
+    void operator==(Int) = delete;
+  };
+
+  std::list<Int> l;
+  std::erase(l, Int{});
+}
+
 int
 main()
 {
-- 
2.48.1

Reply via email to