From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wr1-x444.google.com (mail-wr1-x444.google.com [IPv6:2a00:1450:4864:20::444]) by sourceware.org (Postfix) with ESMTPS id 4ABBA3857C53; Mon, 10 Aug 2020 19:07:15 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 4ABBA3857C53 Received: by mail-wr1-x444.google.com with SMTP id p20so9213170wrf.0; Mon, 10 Aug 2020 12:07:15 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:from:to:references:message-id:date :user-agent:mime-version:in-reply-to:content-language; bh=X38E2AHhW+xwERf1WjHUFVnO0C4XOOg4+qrnprDsaWM=; b=O1CkfojxUUeKi/cCV8mVtU28NC3v/sAnniUgs/6eyO9qPMPpqGaCVYhd+w6/hHnIb4 p7YXshFgykiAcHBIuvNF6LLySDxAxKN9t50sFtGNHuZp2tt96DoLN9SwPLFK4Vy9B75C 8qjd82hf1YhXko3L7wQTqxYPE60XKPeXL0j5lcLfskGpEIZBXTQNag/1xcbta+i/qpZw FqtZV9ocu9iyGcEYuDreOJ1nE2JSQHc8t4+vH6ic60RTceVLtL1eNUVKRa0DVIFW7QzO VXTqCp76CgtjhAItGqGdzwUCaFsOiySigqZcpjdzJHyiiTZiPfEdPxxZEjkP0gwWM0p6 az+w== X-Gm-Message-State: AOAM531mzYuiXLaSRoFKgltlAoAmqvQdNqkKPu2kJfa+/MQYMUNe72Ba kxzsCR2qPGRAsOyaR2ALGhJdxKCk X-Google-Smtp-Source: ABdhPJxR/POsbYBh3WmRcTpEVUvJKpq9s+zjWji6xIAWWMeiDHUunE1HZsQsCNZmq/JrZ0wcF24IMA== X-Received: by 2002:a5d:6748:: with SMTP id l8mr2875600wrw.358.1597086433851; Mon, 10 Aug 2020 12:07:13 -0700 (PDT) Received: from [10.61.4.186] ([109.190.253.14]) by smtp.googlemail.com with ESMTPSA id b77sm1517912wmb.3.2020.08.10.12.07.12 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 10 Aug 2020 12:07:12 -0700 (PDT) Subject: Re: [PATCH] PR libstdc++/91620 Implement DR 526 for std::[forward_]list::remove_if/unique From: =?UTF-8?Q?Fran=c3=a7ois_Dumont?= To: "libstdc++@gcc.gnu.org" , gcc-patches References: <24962b65-4e23-2a3b-ea50-2eef3e9c98a8@gmail.com> Message-ID: Date: Mon, 10 Aug 2020 21:07:10 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.10.0 MIME-Version: 1.0 In-Reply-To: <24962b65-4e23-2a3b-ea50-2eef3e9c98a8@gmail.com> Content-Type: multipart/mixed; boundary="------------8C2BBC9C05F736E8D94CAB67" Content-Language: fr X-Spam-Status: No, score=-9.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, NICE_REPLY_A, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 10 Aug 2020 19:07:18 -0000 This is a multi-part message in MIME format. --------------8C2BBC9C05F736E8D94CAB67 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit Gentle reminder, this time with tests. I've added one for list::remove cause I think there was none, for forward_list we had remove_freed.cc. I added // { dg-options "-g -O0" } in the new tests otherwise it doesn't fail, that's life with UB. I know that it can pass also with those options. If you prefer we can go without it and let Valgrind detect the issue. Whatever, once the patch is in place it doesn't fail anymore. François On 27/12/19 11:57 am, François Dumont wrote: > Here is the patch to extend DR 526 to forward_list and list remove_if > and unique. > > As the adopted pattern is simpler I also applied it to the remove > methods. > >     PR libstdc++/91620 >     * include/bits/forward_list.tcc (forward_list<>::remove): Collect > nodes >     to destroy in an intermediate forward_list. >     (forward_list<>::remove_if, forward_list<>::unique): Likewise. >     * include/bits/list.tcc (list<>::remove, list<>::unique): Likewise. >     (list<>::remove_if): Likewise. >     * include/debug/forward_list (forward_list<>::_M_erase_after): > Remove. >     (forward_list<>::erase_after): Adapt. >     (forward_list<>::remove, forward_list<>::remove_if): Collect nodes to >     destroy in an intermediate forward_list. >     (forward_list<>::unique): Likewise. >     * include/debug/list (list<>::remove, list<>::unique): Likewise. >     (list<>::remove_if): Likewise. > > Tested under Linux x86_64 normal and debug modes. > > Ok to commit ? > > François > --------------8C2BBC9C05F736E8D94CAB67 Content-Type: text/x-patch; charset=UTF-8; name="91620.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="91620.patch" diff --git a/libstdc++-v3/include/bits/forward_list.tcc b/libstdc++-v3/include/bits/forward_list.tcc index c42bdc0fd13..3f94066bd55 100644 --- a/libstdc++-v3/include/bits/forward_list.tcc +++ b/libstdc++-v3/include/bits/forward_list.tcc @@ -290,30 +290,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER remove(const _Tp& __val) -> __remove_return_type { size_type __removed __attribute__((__unused__)) = 0; - _Node_base* __curr = &this->_M_impl._M_head; - _Node_base* __extra = nullptr; + forward_list __to_destroy(get_allocator()); - while (_Node* __tmp = static_cast<_Node*>(__curr->_M_next)) - { - if (*__tmp->_M_valptr() == __val) - { - if (__tmp->_M_valptr() != std::__addressof(__val)) - { - this->_M_erase_after(__curr); - _GLIBCXX20_ONLY( __removed++ ); - continue; - } - else - __extra = __curr; - } - __curr = __curr->_M_next; - } + auto __prev_it = cbefore_begin(); + while (_Node* __tmp = static_cast<_Node*>(__prev_it._M_node->_M_next)) + if (*__tmp->_M_valptr() == __val) + { + __to_destroy.splice_after(__to_destroy.cbefore_begin(), + *this, __prev_it); + _GLIBCXX20_ONLY( __removed++ ); + } + else + ++__prev_it; - if (__extra) - { - this->_M_erase_after(__extra); - _GLIBCXX20_ONLY( __removed++ ); - } return _GLIBCXX20_ONLY( __removed ); } @@ -324,17 +313,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER remove_if(_Pred __pred) -> __remove_return_type { size_type __removed __attribute__((__unused__)) = 0; - _Node_base* __curr = &this->_M_impl._M_head; - while (_Node* __tmp = static_cast<_Node*>(__curr->_M_next)) - { - if (__pred(*__tmp->_M_valptr())) - { - this->_M_erase_after(__curr); - _GLIBCXX20_ONLY( __removed++ ); - } - else - __curr = __curr->_M_next; - } + forward_list __to_destroy(get_allocator()); + + auto __prev_it = cbefore_begin(); + while (_Node* __tmp = static_cast<_Node*>(__prev_it._M_node->_M_next)) + if (__pred(*__tmp->_M_valptr())) + { + __to_destroy.splice_after(__to_destroy.cbefore_begin(), + *this, __prev_it); + _GLIBCXX20_ONLY( __removed++ ); + } + else + ++__prev_it; + return _GLIBCXX20_ONLY( __removed ); } @@ -348,20 +339,24 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER iterator __last = end(); if (__first == __last) return _GLIBCXX20_ONLY(0); + + forward_list __to_destroy(get_allocator()); size_type __removed __attribute__((__unused__)) = 0; iterator __next = __first; while (++__next != __last) { if (__binary_pred(*__first, *__next)) { - erase_after(__first); + __to_destroy.splice_after(__to_destroy.cbefore_begin(), + *this, __first); _GLIBCXX20_ONLY( __removed++ ); } else __first = __next; __next = __first; } - return _GLIBCXX20_ONLY( __removed ); + + return _GLIBCXX20_ONLY( __removed ); } #undef _GLIBCXX20_ONLY diff --git a/libstdc++-v3/include/bits/list.tcc b/libstdc++-v3/include/bits/list.tcc index ce9e983c539..9b664f11454 100644 --- a/libstdc++-v3/include/bits/list.tcc +++ b/libstdc++-v3/include/bits/list.tcc @@ -331,10 +331,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER list<_Tp, _Alloc>:: remove(const value_type& __value) { +#if !_GLIBCXX_USE_CXX11_ABI size_type __removed __attribute__((__unused__)) = 0; +#endif + list __to_destroy(get_allocator()); iterator __first = begin(); iterator __last = end(); - iterator __extra = __last; while (__first != __last) { iterator __next = __first; @@ -344,22 +346,20 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER // _GLIBCXX_RESOLVE_LIB_DEFECTS // 526. Is it undefined if a function in the standard changes // in parameters? - if (std::__addressof(*__first) != std::__addressof(__value)) - { - _M_erase(__first); - _GLIBCXX20_ONLY( __removed++ ); - } - else - __extra = __first; + __to_destroy.splice(__to_destroy.begin(), *this, __first); +#if !_GLIBCXX_USE_CXX11_ABI + _GLIBCXX20_ONLY( __removed++ ); +#endif } + __first = __next; } - if (__extra != __last) - { - _M_erase(__extra); - _GLIBCXX20_ONLY( __removed++ ); - } - return _GLIBCXX20_ONLY( __removed ); + +#if !_GLIBCXX_USE_CXX11_ABI + return _GLIBCXX20_ONLY( __removed ); +#else + return _GLIBCXX20_ONLY( __to_destroy.size() ); +#endif } template @@ -371,20 +371,30 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER iterator __last = end(); if (__first == __last) return _GLIBCXX20_ONLY( 0 ); +#if !_GLIBCXX_USE_CXX11_ABI size_type __removed __attribute__((__unused__)) = 0; +#endif + list __to_destroy(get_allocator()); iterator __next = __first; while (++__next != __last) { if (*__first == *__next) { - _M_erase(__next); + __to_destroy.splice(__to_destroy.begin(), *this, __next); +#if !_GLIBCXX_USE_CXX11_ABI _GLIBCXX20_ONLY( __removed++ ); +#endif } else __first = __next; __next = __first; } + +#if !_GLIBCXX_USE_CXX11_ABI return _GLIBCXX20_ONLY( __removed ); +#else + return _GLIBCXX20_ONLY( __to_destroy.size() ); +#endif } template @@ -533,21 +543,31 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER list<_Tp, _Alloc>:: remove_if(_Predicate __pred) { +#if !_GLIBCXX_USE_CXX11_ABI size_type __removed __attribute__((__unused__)) = 0; - iterator __first = begin(); - iterator __last = end(); - while (__first != __last) +#endif + list __to_destroy(get_allocator()); + iterator __first = begin(); + iterator __last = end(); + while (__first != __last) { iterator __next = __first; ++__next; if (__pred(*__first)) { - _M_erase(__first); + __to_destroy.splice(__to_destroy.begin(), *this, __first); +#if !_GLIBCXX_USE_CXX11_ABI _GLIBCXX20_ONLY( __removed++ ); +#endif } __first = __next; } + +#if !_GLIBCXX_USE_CXX11_ABI return _GLIBCXX20_ONLY( __removed ); +#else + return _GLIBCXX20_ONLY( __to_destroy.size() ); +#endif } template @@ -560,20 +580,30 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER iterator __last = end(); if (__first == __last) return _GLIBCXX20_ONLY(0); +#if !_GLIBCXX_USE_CXX11_ABI size_type __removed __attribute__((__unused__)) = 0; +#endif + list __to_destroy(get_allocator()); iterator __next = __first; while (++__next != __last) { if (__binary_pred(*__first, *__next)) { - _M_erase(__next); + __to_destroy.splice(__to_destroy.begin(), *this, __next); +#if !_GLIBCXX_USE_CXX11_ABI _GLIBCXX20_ONLY( __removed++ ); +#endif } else __first = __next; __next = __first; } + +#if !_GLIBCXX_USE_CXX11_ABI return _GLIBCXX20_ONLY( __removed ); +#else + return _GLIBCXX20_ONLY( __to_destroy.size() ); +#endif } #undef _GLIBCXX20_ONLY diff --git a/libstdc++-v3/include/debug/forward_list b/libstdc++-v3/include/debug/forward_list index fc6bf6359e9..7a00417ccb2 100644 --- a/libstdc++-v3/include/debug/forward_list +++ b/libstdc++-v3/include/debug/forward_list @@ -452,21 +452,15 @@ namespace __debug return { _Base::insert_after(__pos.base(), __il), this }; } - private: - _Base_iterator - _M_erase_after(_Base_const_iterator __pos) - { - _Base_const_iterator __next = std::next(__pos); - this->_M_invalidate_if([__next](_Base_const_iterator __it) - { return __it == __next; }); - return _Base::erase_after(__pos); - } - public: iterator erase_after(const_iterator __pos) { __glibcxx_check_erase_after(__pos); - return { _M_erase_after(__pos.base()), this }; + + _Base_const_iterator __next = std::next(__pos.base()); + this->_M_invalidate_if([__next](_Base_const_iterator __it) + { return __it == __next; }); + return { _Base::erase_after(__pos.base()), this }; } iterator @@ -691,29 +685,23 @@ namespace __debug return _Base::remove(__val); size_type __removed __attribute__((__unused__)) = 0; - _Base_iterator __x = _Base::before_begin(); - _Base_iterator __old = __x++; - _Base_iterator __extra = _Base::end(); - while (__x != _Base::end()) + _Base __to_destroy(get_allocator()); + _Base_const_iterator __x = _Base::cbefore_begin(); + _Base_const_iterator __old = __x++; + while (__x != _Base::cend()) { if (*__x == __val) { - if (std::__addressof(*__x) != std::__addressof(__val)) - { - __x = _M_erase_after(__old); - _GLIBCXX20_ONLY( __removed++ ); - continue; - } - else - __extra = __old; + _Base_const_iterator __next = std::next(__old); + this->_M_invalidate_if([__next](_Base_const_iterator __it) + { return __it == __next; }); + __to_destroy.splice_after(__to_destroy.cbefore_begin(), + _M_base(), __old); + __x = __old; + _GLIBCXX20_ONLY( __removed++ ); } - __old = __x++; - } - if (__extra != _Base::end()) - { - this->_M_erase_after(__extra); - _GLIBCXX20_ONLY( __removed++ ); + __old = __x++; } return _GLIBCXX20_ONLY( __removed ); @@ -727,16 +715,23 @@ namespace __debug return _Base::remove_if(__pred); size_type __removed __attribute__((__unused__)) = 0; + _Base __to_destroy(get_allocator()); _Base_iterator __x = _Base::before_begin(); _Base_iterator __old = __x++; while (__x != _Base::end()) - if (__pred(*__x)) - { - __x = _M_erase_after(__old); - _GLIBCXX20_ONLY( __removed++ ); - } - else + { + if (__pred(*__x)) + { + this->_M_invalidate_if([__x](_Base_const_iterator __it) + { return __it == __x; }); + __to_destroy.splice_after(__to_destroy.cbefore_begin(), + _M_base(), __old); + __x = __old; + _GLIBCXX20_ONLY( __removed++ ); + } + __old = __x++; + } return _GLIBCXX20_ONLY( __removed ); } @@ -753,22 +748,27 @@ namespace __debug if (!this->_M_iterators && !this->_M_const_iterators) return _Base::unique(__binary_pred); - _Base_iterator __first = _Base::begin(); - _Base_iterator __last = _Base::end(); + _Base_const_iterator __first = _Base::cbegin(); + _Base_const_iterator __last = _Base::cend(); if (__first == __last) return _GLIBCXX20_ONLY(0); size_type __removed __attribute__((__unused__)) = 0; - _Base_iterator __next = std::next(__first); + _Base __to_destroy(get_allocator()); + _Base_const_iterator __next = std::next(__first); while (__next != __last) { if (__binary_pred(*__first, *__next)) { - __next = _M_erase_after(__first); + this->_M_invalidate_if([__next](_Base_const_iterator __it) + { return __it == __next; }); + __to_destroy.splice_after(__to_destroy.cbefore_begin(), + _M_base(), __first); + __next = __first; _GLIBCXX20_ONLY( __removed++ ); } - else - __first = __next++; + + __first = __next++; } return _GLIBCXX20_ONLY( __removed ); diff --git a/libstdc++-v3/include/debug/list b/libstdc++-v3/include/debug/list index 8f2a8cb0f01..b5652fd9fdc 100644 --- a/libstdc++-v3/include/debug/list +++ b/libstdc++-v3/include/debug/list @@ -681,36 +681,36 @@ namespace __debug if (!this->_M_iterators && !this->_M_const_iterators) return _Base::remove(__value); +#if !_GLIBCXX_USE_CXX11_ABI size_type __removed __attribute__((__unused__)) = 0; +#endif + _Base __to_destroy(get_allocator()); _Base_iterator __first = _Base::begin(); _Base_iterator __last = _Base::end(); - _Base_iterator __extra = __last; while (__first != __last) { + _Base_iterator __next = __first; + ++__next; if (*__first == __value) - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 526. Is it undefined if a function in the standard changes - // in parameters? - if (std::__addressof(*__first) != std::__addressof(__value)) - { - __first = _M_erase(__first); - _GLIBCXX20_ONLY( __removed++ ); - } - else - { - __extra = __first; - ++__first; - } - else - ++__first; - } + { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 526. Is it undefined if a function in the standard changes + // in parameters? + this->_M_invalidate_if(_Equal(__first)); + __to_destroy.splice(__to_destroy.begin(), _M_base(), __first); +#if !_GLIBCXX_USE_CXX11_ABI + _GLIBCXX20_ONLY( __removed++ ); +#endif + } - if (__extra != __last) - { - _M_erase(__extra); - _GLIBCXX20_ONLY( __removed++ ); + __first = __next; } + +#if !_GLIBCXX_USE_CXX11_ABI return _GLIBCXX20_ONLY( __removed ); +#else + return _GLIBCXX20_ONLY( __to_destroy.size() ); +#endif } template @@ -720,17 +720,31 @@ namespace __debug if (!this->_M_iterators && !this->_M_const_iterators) return _Base::remove_if(__pred); +#if !_GLIBCXX_USE_CXX11_ABI size_type __removed __attribute__((__unused__)) = 0; +#endif + _Base __to_destroy(get_allocator()); for (_Base_iterator __x = _Base::begin(); __x != _Base::end(); ) + { + _Base_iterator __next = __x; + ++__next; if (__pred(*__x)) { - __x = _M_erase(__x); + this->_M_invalidate_if(_Equal(__x)); + __to_destroy.splice(__to_destroy.begin(), _M_base(), __x); +#if !_GLIBCXX_USE_CXX11_ABI _GLIBCXX20_ONLY( __removed++ ); +#endif } - else - ++__x; + __x = __next; + } + +#if !_GLIBCXX_USE_CXX11_ABI return _GLIBCXX20_ONLY( __removed ); +#else + return _GLIBCXX20_ONLY( __to_destroy.size() ); +#endif } _GLIBCXX_LIST_REMOVE_RETURN_TYPE_TAG @@ -743,21 +757,31 @@ namespace __debug if (empty()) return _GLIBCXX20_ONLY(0); +#if !_GLIBCXX_USE_CXX11_ABI size_type __removed __attribute__((__unused__)) = 0; +#endif + _Base __to_destroy(get_allocator()); _Base_iterator __first = _Base::begin(); _Base_iterator __last = _Base::end(); _Base_iterator __next = __first; while (++__next != __last) if (*__first == *__next) { - _M_erase(__next); + this->_M_invalidate_if(_Equal(__next)); + __to_destroy.splice(__to_destroy.begin(), _M_base(), __next); __next = __first; +#if !_GLIBCXX_USE_CXX11_ABI _GLIBCXX20_ONLY( __removed++ ); +#endif } else __first = __next; +#if !_GLIBCXX_USE_CXX11_ABI return _GLIBCXX20_ONLY( __removed ); +#else + return _GLIBCXX20_ONLY( __to_destroy.size() ); +#endif } template @@ -770,21 +794,32 @@ namespace __debug if (empty()) return _GLIBCXX20_ONLY(0); + +#if !_GLIBCXX_USE_CXX11_ABI size_type __removed __attribute__((__unused__)) = 0; +#endif + _Base __to_destroy(get_allocator()); _Base_iterator __first = _Base::begin(); _Base_iterator __last = _Base::end(); - _Base_iterator __next = __first;; + _Base_iterator __next = __first; while (++__next != __last) if (__binary_pred(*__first, *__next)) { - _M_erase(__next); + this->_M_invalidate_if(_Equal(__next)); + __to_destroy.splice(__to_destroy.begin(), _M_base(), __next); __next = __first; +#if !_GLIBCXX_USE_CXX11_ABI _GLIBCXX20_ONLY( __removed++ ); +#endif } else __first = __next; - return _GLIBCXX20_ONLY( __removed ); +#if !_GLIBCXX_USE_CXX11_ABI + return _GLIBCXX20_ONLY( __removed ); +#else + return _GLIBCXX20_ONLY( __to_destroy.size() ); +#endif } #undef _GLIBCXX_LIST_REMOVE_RETURN_TYPE_TAG diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/operations/91620.cc b/libstdc++-v3/testsuite/23_containers/forward_list/operations/91620.cc new file mode 100644 index 00000000000..a3127f6ee68 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/forward_list/operations/91620.cc @@ -0,0 +1,88 @@ +// { dg-do run { target c++11 } } +// { dg-options "-g -O0" } + +// +// Copyright (C) 2020 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +#include +#include +#include + +struct PredLWG526 +{ + PredLWG526(int i) : i_(i) {}; + ~PredLWG526() { i_ = -32767; } + + bool + operator() (const PredLWG526& p) const { return p.i_ == i_; } + + bool + operator==(int i) const { return i == i_; } + + bool + operator() (const PredLWG526& lhs, const PredLWG526& rhs) const + { + VERIFY( i_ != -32767 ); + return lhs.i_ == rhs.i_; + } + + int i_; +}; + +void test01() +{ + int a1[] = {1, 2, 1, 3, 5, 8, 11}; + int a2[] = {2, 3, 5, 8, 11}; + std::forward_list fl(a1, a1 + 7); + + VERIFY( std::distance(fl.begin(), fl.end()) == 7 ); + + fl.remove_if(std::cref(fl.front())); + VERIFY( std::distance(fl.begin(), fl.end()) == 5 ); + for (size_t i = 0; !fl.empty(); ++i) + { + VERIFY( fl.front() == a2[i] ); + fl.pop_front(); + } +} + +void test02() +{ + int a1[] = {1, 1, 1, 2, 3, 5, 8, 11}; + int a2[] = {1, 2, 3, 5, 8, 11}; + std::forward_list fl(a1, a1 + 8); + + VERIFY( std::distance(fl.begin(), fl.end()) == 8 ); + + auto it = fl.begin(); + ++it; + fl.unique(std::cref(*it)); + VERIFY( std::distance(fl.begin(), fl.end()) == 6 ); + for (size_t i = 0; !fl.empty(); ++i) + { + VERIFY( fl.front() == a2[i] ); + fl.pop_front(); + } +} + +int main() +{ + test01(); + test02(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/list/operations/91620.cc b/libstdc++-v3/testsuite/23_containers/list/operations/91620.cc new file mode 100644 index 00000000000..64c0998082d --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/list/operations/91620.cc @@ -0,0 +1,110 @@ +// { dg-do run { target c++11 } } +// { dg-options "-g -O0" } + +// +// Copyright (C) 2020 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +#include +#include +#include + +struct PredLWG526 +{ + PredLWG526(int i) : i_(i) {}; + ~PredLWG526() { i_ = -32767; } + + bool + operator() (const PredLWG526& p) const { return p.i_ == i_; } + + bool + operator==(int i) const { return i == i_; } + + bool + operator()(const PredLWG526& lhs, const PredLWG526& rhs) const + { + VERIFY( i_ != -32767 ); + return lhs.i_ == rhs.i_; + } + + friend bool + operator==(const PredLWG526& lhs, const PredLWG526& rhs) + { return lhs.i_ == rhs.i_; } + + int i_; +}; + +void test01() +{ + int a1[] = {1, 2, 1, 3, 5, 8, 11}; + int a2[] = {2, 3, 5, 8, 11}; + std::list l(a1, a1 + 7); + + VERIFY( std::distance(l.begin(), l.end()) == 7 ); + + l.remove(l.front()); + VERIFY( std::distance(l.begin(), l.end()) == 5 ); + for (size_t i = 0; !l.empty(); ++i) + { + VERIFY( l.front() == a2[i] ); + l.pop_front(); + } +} + +void test02() +{ + int a1[] = {1, 2, 1, 3, 5, 8, 11}; + int a2[] = {2, 3, 5, 8, 11}; + std::list l(a1, a1 + 7); + + VERIFY( std::distance(l.begin(), l.end()) == 7 ); + + l.remove_if(std::cref(l.front())); + VERIFY( std::distance(l.begin(), l.end()) == 5 ); + for (size_t i = 0; !l.empty(); ++i) + { + VERIFY( l.front() == a2[i] ); + l.pop_front(); + } +} + +void test03() +{ + int a1[] = {1, 1, 1, 2, 3, 5, 8, 11}; + int a2[] = {1, 2, 3, 5, 8, 11}; + std::list l(a1, a1 + 8); + + VERIFY( std::distance(l.begin(), l.end()) == 8 ); + + auto it = l.begin(); + ++it; + l.unique(std::cref(*it)); + VERIFY( std::distance(l.begin(), l.end()) == 6 ); + for (size_t i = 0; !l.empty(); ++i) + { + VERIFY( l.front() == a2[i] ); + l.pop_front(); + } +} + +int main() +{ + test01(); + test02(); + test03(); + return 0; +} --------------8C2BBC9C05F736E8D94CAB67--