https://gcc.gnu.org/g:d22bd12554d5c4214da7072aff4d0babaf82b412
commit r14-11486-gd22bd12554d5c4214da7072aff4d0babaf82b412 Author: Jonathan Wakely <jwak...@redhat.com> Date: Thu Mar 6 21:18:21 2025 +0000 libstdc++: Make std::erase for linked lists convert to bool 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. Reviewed-by: Patrick Palka <ppa...@redhat.com> (cherry picked from commit e6e7b477bbdbfb3fee6b44087a59f94fd1e2c7a3) Diff: --- 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 dfd7d48d1219..91dd6745bec4 100644 --- a/libstdc++-v3/include/std/forward_list +++ b/libstdc++-v3/include/std/forward_list @@ -79,8 +79,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 ff632fc1ab2f..d6126e493fa2 100644 --- a/libstdc++-v3/include/std/list +++ b/libstdc++-v3/include/std/list @@ -103,8 +103,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 271cb3a577e8..c5a7013f6b6b 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 c5d041526dca..0df3a8772bdf 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() {