[PATCH] P0646R1 Improving the Return Value of Erase-Like Algorithms I

Jonathan Wakely jwakely@redhat.com
Wed Jul 4 20:15:00 GMT 2018


In C++2a the remove, remove_if and unique members of std::list and
std::forward_list have been changed to return the number of elements
removed. This is an ABI change for the remove members and the
non-template unique members, so an abi-tag is used to give those symbols
new mangled names in C++2a mode. For the function templates the return
type is part of the mangled name so no abi-tag is needed.

	* include/bits/forward_list.h (__cpp_lib_list_remove_return_type):
	Define.
	(forward_list::__remove_return_type): Define typedef as size_type or
	void, according to __cplusplus value.
	(_GLIBCXX_FWDLIST_REMOVE_RETURN_TYPE_TAG): Define macro as abi-tag or
	empty, according to __cplusplus value.
	(forward_list::remove, forward_list::unique): Use typedef and macro
	to change return type and add abi-tag for C++2a.
	(forward_list::remove_if<Pred>, forward_list::unique<BinPred>): Use
	typedef to change return type for C++2a.
	* include/bits/forward_list.tcc (_GLIBCXX20_ONLY): Define macro.
	(forward_list::remove, forward_list::remove_if<Pred>)
	(forward_list::unique<BinPred>): Return number of removed elements
	for C++2a.
	* include/bits/list.tcc (_GLIBCXX20_ONLY): Define macro.
	(list::remove, list::unique, list::remove_if<Predicate>)
	(list::unique<BinaryPredicate>): Return number of removed elements
	for C++2a.
	* include/bits/stl_list.h (__cpp_lib_list_remove_return_type): Define.
	(list::__remove_return_type): Define typedef as size_type or
	void, according to __cplusplus value.
	(_GLIBCXX_LIST_REMOVE_RETURN_TYPE_TAG): Define macro as abi-tag or
	empty, according to __cplusplus value.
	(list::remove, list::unique): Use typedef and macro to change return
	type and add abi-tag for C++2a.
	(list::remove_if<Predicate>, list::unique<BinaryPredicate>): Use
	typedef to change return type for C++2a.
	* include/std/version (__cpp_lib_list_remove_return_type): Define.
	* testsuite/23_containers/forward_list/operations/
	remove_cxx20_return.cc: New.
	* testsuite/23_containers/forward_list/operations/
	unique_cxx20_return.cc: New.

Tested powerpc64le-linux, committed to trunk.


-------------- next part --------------
commit 438e6398493708d2fb13766c9dff5305ebb98eec
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Jul 4 20:13:34 2018 +0100

    P0646R1 Improving the Return Value of Erase-Like Algorithms I
    
    In C++2a the remove, remove_if and unique members of std::list and
    std::forward_list have been changed to return the number of elements
    removed. This is an ABI change for the remove members and the
    non-template unique members, so an abi-tag is used to give those symbols
    new mangled names in C++2a mode. For the function templates the return
    type is part of the mangled name so no abi-tag is needed.
    
            * include/bits/forward_list.h (__cpp_lib_list_remove_return_type):
            Define.
            (forward_list::__remove_return_type): Define typedef as size_type or
            void, according to __cplusplus value.
            (_GLIBCXX_FWDLIST_REMOVE_RETURN_TYPE_TAG): Define macro as abi-tag or
            empty, according to __cplusplus value.
            (forward_list::remove, forward_list::unique): Use typedef and macro
            to change return type and add abi-tag for C++2a.
            (forward_list::remove_if<Pred>, forward_list::unique<BinPred>): Use
            typedef to change return type for C++2a.
            * include/bits/forward_list.tcc (_GLIBCXX20_ONLY): Define macro.
            (forward_list::remove, forward_list::remove_if<Pred>)
            (forward_list::unique<BinPred>): Return number of removed elements
            for C++2a.
            * include/bits/list.tcc (_GLIBCXX20_ONLY): Define macro.
            (list::remove, list::unique, list::remove_if<Predicate>)
            (list::unique<BinaryPredicate>): Return number of removed elements
            for C++2a.
            * include/bits/stl_list.h (__cpp_lib_list_remove_return_type): Define.
            (list::__remove_return_type): Define typedef as size_type or
            void, according to __cplusplus value.
            (_GLIBCXX_LIST_REMOVE_RETURN_TYPE_TAG): Define macro as abi-tag or
            empty, according to __cplusplus value.
            (list::remove, list::unique): Use typedef and macro to change return
            type and add abi-tag for C++2a.
            (list::remove_if<Predicate>, list::unique<BinaryPredicate>): Use
            typedef to change return type for C++2a.
            * include/std/version (__cpp_lib_list_remove_return_type): Define.
            * testsuite/23_containers/forward_list/operations/
            remove_cxx20_return.cc: New.
            * testsuite/23_containers/forward_list/operations/
            unique_cxx20_return.cc: New.

diff --git a/libstdc++-v3/include/bits/forward_list.h b/libstdc++-v3/include/bits/forward_list.h
index 8c4c074e454..84a4ad4d5dc 100644
--- a/libstdc++-v3/include/bits/forward_list.h
+++ b/libstdc++-v3/include/bits/forward_list.h
@@ -1156,6 +1156,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       { _M_splice_after(__pos, __before, __last); }
       // @}
 
+    private:
+#if __cplusplus > 201703L
+# define __cpp_lib_list_remove_return_type 201806L
+      using __remove_return_type = size_type;
+# define _GLIBCXX_FWDLIST_REMOVE_RETURN_TYPE_TAG \
+      __attribute__((__abi_tag__("__cxx20")))
+#else
+      using __remove_return_type = void;
+# define _GLIBCXX_FWDLIST_REMOVE_RETURN_TYPE_TAG
+#endif
+    public:
+
       /**
        *  @brief  Remove all elements equal to value.
        *  @param  __val  The value to remove.
@@ -1167,7 +1179,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        *  touched in any way.  Managing the pointer is the user's
        *  responsibility.
        */
-      void
+      _GLIBCXX_FWDLIST_REMOVE_RETURN_TYPE_TAG
+      __remove_return_type
       remove(const _Tp& __val);
 
       /**
@@ -1182,7 +1195,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        *  responsibility.
        */
       template<typename _Pred>
-	void
+	__remove_return_type
 	remove_if(_Pred __pred);
 
       /**
@@ -1195,9 +1208,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        *  the pointed-to memory is not touched in any way.  Managing
        *  the pointer is the user's responsibility.
        */
-      void
+      _GLIBCXX_FWDLIST_REMOVE_RETURN_TYPE_TAG
+      __remove_return_type
       unique()
-      { unique(std::equal_to<_Tp>()); }
+      { return unique(std::equal_to<_Tp>()); }
+
+#undef _GLIBCXX_FWDLIST_REMOVE_RETURN_TYPE_TAG
 
       /**
        *  @brief  Remove consecutive elements satisfying a predicate.
@@ -1212,7 +1228,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        *  Managing the pointer is the user's responsibility.
        */
       template<typename _BinPred>
-	void
+	__remove_return_type
 	unique(_BinPred __binary_pred);
 
       /**
diff --git a/libstdc++-v3/include/bits/forward_list.tcc b/libstdc++-v3/include/bits/forward_list.tcc
index b41fbbb52f2..8a62a5ee748 100644
--- a/libstdc++-v3/include/bits/forward_list.tcc
+++ b/libstdc++-v3/include/bits/forward_list.tcc
@@ -278,11 +278,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  return iterator(const_cast<_Node_base*>(__pos._M_node));
       }
 
+#if __cplusplus > 201703L
+# define _GLIBCXX20_ONLY(__expr) __expr
+#else
+# define _GLIBCXX20_ONLY(__expr)
+#endif
+
   template<typename _Tp, typename _Alloc>
-    void
+    auto
     forward_list<_Tp, _Alloc>::
-    remove(const _Tp& __val)
+    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;
 
@@ -293,6 +300,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	      if (__tmp->_M_valptr() != std::__addressof(__val))
 		{
 		  this->_M_erase_after(__curr);
+		  _GLIBCXX20_ONLY( __removed++ );
 		  continue;
 		}
 	      else
@@ -302,46 +310,62 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	}
 
       if (__extra)
-	this->_M_erase_after(__extra);
+	{
+	  this->_M_erase_after(__extra);
+	  _GLIBCXX20_ONLY( __removed++ );
+	}
+      return _GLIBCXX20_ONLY( __removed );
     }
 
   template<typename _Tp, typename _Alloc>
     template<typename _Pred>
-      void
+      auto
       forward_list<_Tp, _Alloc>::
-      remove_if(_Pred __pred)
+      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);
+	      {
+		this->_M_erase_after(__curr);
+		_GLIBCXX20_ONLY( __removed++ );
+	      }
 	    else
 	      __curr = __curr->_M_next;
 	  }
+	return _GLIBCXX20_ONLY( __removed );
       }
 
   template<typename _Tp, typename _Alloc>
     template<typename _BinPred>
-      void
+      auto
       forward_list<_Tp, _Alloc>::
-      unique(_BinPred __binary_pred)
+      unique(_BinPred __binary_pred) -> __remove_return_type
       {
 	iterator __first = begin();
 	iterator __last = end();
 	if (__first == __last)
-	  return;
+	  return _GLIBCXX20_ONLY(0);
+	size_type __removed __attribute__((__unused__)) = 0;
 	iterator __next = __first;
 	while (++__next != __last)
 	{
 	  if (__binary_pred(*__first, *__next))
-	    erase_after(__first);
+	    {
+	      erase_after(__first);
+	      _GLIBCXX20_ONLY( __removed++ );
+	    }
 	  else
 	    __first = __next;
 	  __next = __first;
 	}
+        return _GLIBCXX20_ONLY( __removed );
       }
 
+#undef _GLIBCXX20_ONLY
+
   template<typename _Tp, typename _Alloc>
     template<typename _Comp>
       void
diff --git a/libstdc++-v3/include/bits/list.tcc b/libstdc++-v3/include/bits/list.tcc
index e90d9574cd2..cdd95527ef5 100644
--- a/libstdc++-v3/include/bits/list.tcc
+++ b/libstdc++-v3/include/bits/list.tcc
@@ -320,11 +320,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
           insert(__last1, __first2, __last2);
       }
 
+#if __cplusplus > 201703L
+# define _GLIBCXX20_ONLY(__expr) __expr
+#else
+# define _GLIBCXX20_ONLY(__expr)
+#endif
+
   template<typename _Tp, typename _Alloc>
-    void
+    typename list<_Tp, _Alloc>::__remove_return_type
     list<_Tp, _Alloc>::
     remove(const value_type& __value)
     {
+      size_type __removed __attribute__((__unused__)) = 0;
       iterator __first = begin();
       iterator __last = end();
       iterator __extra = __last;
@@ -338,34 +345,46 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	      // 526. Is it undefined if a function in the standard changes
 	      // in parameters?
 	      if (std::__addressof(*__first) != std::__addressof(__value))
-		_M_erase(__first);
+		{
+		  _M_erase(__first);
+		  _GLIBCXX20_ONLY( __removed++ );
+		}
 	      else
 		__extra = __first;
 	    }
 	  __first = __next;
 	}
       if (__extra != __last)
-	_M_erase(__extra);
+	{
+	  _M_erase(__extra);
+	  _GLIBCXX20_ONLY( __removed++ );
+	}
+      return _GLIBCXX20_ONLY( __removed );
     }
 
   template<typename _Tp, typename _Alloc>
-    void
+    typename list<_Tp, _Alloc>::__remove_return_type
     list<_Tp, _Alloc>::
     unique()
     {
       iterator __first = begin();
       iterator __last = end();
       if (__first == __last)
-	return;
+	return _GLIBCXX20_ONLY( 0 );
+      size_type __removed __attribute__((__unused__)) = 0;
       iterator __next = __first;
       while (++__next != __last)
 	{
 	  if (*__first == *__next)
-	    _M_erase(__next);
+	    {
+	      _M_erase(__next);
+	      _GLIBCXX20_ONLY( __removed++ );
+	    }
 	  else
 	    __first = __next;
 	  __next = __first;
 	}
+      return _GLIBCXX20_ONLY( __removed );
     }
 
   template<typename _Tp, typename _Alloc>
@@ -510,10 +529,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 
   template<typename _Tp, typename _Alloc>
     template <typename _Predicate>
-      void
+      typename list<_Tp, _Alloc>::__remove_return_type
       list<_Tp, _Alloc>::
       remove_if(_Predicate __pred)
       {
+	size_type __removed __attribute__((__unused__)) = 0;
         iterator __first = begin();
         iterator __last = end();
         while (__first != __last)
@@ -521,32 +541,43 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	    iterator __next = __first;
 	    ++__next;
 	    if (__pred(*__first))
-	      _M_erase(__first);
+	      {
+		_M_erase(__first);
+		_GLIBCXX20_ONLY( __removed++ );
+	      }
 	    __first = __next;
 	  }
+	return _GLIBCXX20_ONLY( __removed );
       }
 
   template<typename _Tp, typename _Alloc>
     template <typename _BinaryPredicate>
-      void
+      typename list<_Tp, _Alloc>::__remove_return_type
       list<_Tp, _Alloc>::
       unique(_BinaryPredicate __binary_pred)
       {
         iterator __first = begin();
         iterator __last = end();
         if (__first == __last)
-	  return;
+	  return _GLIBCXX20_ONLY(0);
+        size_type __removed __attribute__((__unused__)) = 0;
         iterator __next = __first;
         while (++__next != __last)
 	  {
 	    if (__binary_pred(*__first, *__next))
-	      _M_erase(__next);
+	      {
+		_M_erase(__next);
+		_GLIBCXX20_ONLY( __removed++ );
+	      }
 	    else
 	      __first = __next;
 	    __next = __first;
 	  }
+	return _GLIBCXX20_ONLY( __removed );
       }
 
+#undef _GLIBCXX20_ONLY
+
   template<typename _Tp, typename _Alloc>
     template <typename _StrictWeakOrdering>
       void
diff --git a/libstdc++-v3/include/bits/stl_list.h b/libstdc++-v3/include/bits/stl_list.h
index 59e056df604..47749142e0e 100644
--- a/libstdc++-v3/include/bits/stl_list.h
+++ b/libstdc++-v3/include/bits/stl_list.h
@@ -1673,6 +1673,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       { splice(__position, std::move(__x), __first, __last); }
 #endif
 
+    private:
+#if __cplusplus > 201703L
+# define __cpp_lib_list_remove_return_type 201806L
+      typedef size_type __remove_return_type;
+# define _GLIBCXX_LIST_REMOVE_RETURN_TYPE_TAG \
+      __attribute__((__abi_tag__("__cxx20")))
+#else
+      typedef void __remove_return_type;
+# define _GLIBCXX_LIST_REMOVE_RETURN_TYPE_TAG
+#endif
+    public:
+
       /**
        *  @brief  Remove all elements equal to value.
        *  @param  __value  The value to remove.
@@ -1684,7 +1696,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
        *  touched in any way.  Managing the pointer is the user's
        *  responsibility.
        */
-      void
+      _GLIBCXX_LIST_REMOVE_RETURN_TYPE_TAG
+      __remove_return_type
       remove(const _Tp& __value);
 
       /**
@@ -1699,7 +1712,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
        *  responsibility.
        */
       template<typename _Predicate>
-	void
+	__remove_return_type
 	remove_if(_Predicate);
 
       /**
@@ -1712,7 +1725,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
        *  the pointed-to memory is not touched in any way.  Managing
        *  the pointer is the user's responsibility.
        */
-      void
+      _GLIBCXX_LIST_REMOVE_RETURN_TYPE_TAG
+      __remove_return_type
       unique();
 
       /**
@@ -1728,9 +1742,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
        *  Managing the pointer is the user's responsibility.
        */
       template<typename _BinaryPredicate>
-	void
+	__remove_return_type
 	unique(_BinaryPredicate);
 
+#undef _GLIBCXX_LIST_REMOVE_RETURN_TYPE_TAG
+
       /**
        *  @brief  Merge sorted lists.
        *  @param  __x  Sorted list to merge.
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index 08036ff63f2..a70c73fd12b 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -105,6 +105,7 @@
 #define __cpp_lib_is_swappable 201603
 #define __cpp_lib_launder 201606
 #define __cpp_lib_lcm 201606
+#define __cpp_lib_list_remove_return_type 201806L
 #define __cpp_lib_logical_traits 201510
 #define __cpp_lib_make_from_tuple 201606
 #define __cpp_lib_map_insertion 201411
diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/operations/remove_cxx20_return.cc b/libstdc++-v3/testsuite/23_containers/forward_list/operations/remove_cxx20_return.cc
new file mode 100644
index 00000000000..9b46817078e
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/forward_list/operations/remove_cxx20_return.cc
@@ -0,0 +1,66 @@
+// Copyright (C) 2018 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <forward_list>
+#include <testsuite_hooks.h>
+
+using test_type = std::forward_list<int>;
+
+void
+test01()
+{
+  test_type x{1, 2, 3, 4, 3, 2, 1};
+  static_assert(std::is_same_v<decltype(x.remove(0)), test_type::size_type>);
+  test_type::size_type r = x.remove(0);
+  VERIFY( r == 0 );
+  r = x.remove(1);
+  VERIFY( r == 2 );
+  r = x.remove(1);
+  VERIFY( r == 0 );
+  r = x.remove(4);
+  VERIFY( r == 1 );
+}
+
+void
+test02()
+{
+  int i = 0;
+  auto pred = [&i](int val) { return val == i; };
+  test_type x{1, 2, 3, 4, 3, 2, 1};
+  static_assert(std::is_same_v<decltype(x.remove_if(pred)),
+			       test_type::size_type>);
+  test_type::size_type r = x.remove_if(pred);
+  VERIFY( r == 0 );
+  i = 1;
+  r = x.remove_if(pred);
+  VERIFY( r == 2 );
+  r = x.remove_if(pred);
+  VERIFY( r == 0 );
+  i = 4;
+  r = x.remove_if(pred);
+  VERIFY( r == 1 );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/operations/unique_cxx20_return.cc b/libstdc++-v3/testsuite/23_containers/forward_list/operations/unique_cxx20_return.cc
new file mode 100644
index 00000000000..066330c4148
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/forward_list/operations/unique_cxx20_return.cc
@@ -0,0 +1,55 @@
+// Copyright (C) 2018 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <forward_list>
+#include <testsuite_hooks.h>
+
+using test_type = std::forward_list<int>;
+
+void
+test01()
+{
+  test_type x{1, 2, 2, 4, 4, 2, 1};
+  static_assert(std::is_same_v<decltype(x.unique()), test_type::size_type>);
+  test_type::size_type r = x.unique();
+  VERIFY( r == 2 );
+  r = x.unique();
+  VERIFY( r == 0 );
+}
+
+void
+test02()
+{
+  auto pred = [](int val, int prev) { return val == prev; };
+  test_type x{1, 2, 2, 4, 4, 2, 1};
+  static_assert(std::is_same_v<decltype(x.unique(pred)),
+			       test_type::size_type>);
+  test_type::size_type r = x.unique(pred);
+  VERIFY( r == 2 );
+  r = x.unique(pred);
+  VERIFY( r == 0 );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/list/operations/remove_cxx20_return.cc b/libstdc++-v3/testsuite/23_containers/list/operations/remove_cxx20_return.cc
new file mode 100644
index 00000000000..290646106cf
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/list/operations/remove_cxx20_return.cc
@@ -0,0 +1,66 @@
+// Copyright (C) 2018 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <list>
+#include <testsuite_hooks.h>
+
+using test_type = std::list<int>;
+
+void
+test01()
+{
+  test_type x{1, 2, 3, 4, 3, 2, 1};
+  static_assert(std::is_same_v<decltype(x.remove(0)), test_type::size_type>);
+  test_type::size_type r = x.remove(0);
+  VERIFY( r == 0 );
+  r = x.remove(1);
+  VERIFY( r == 2 );
+  r = x.remove(1);
+  VERIFY( r == 0 );
+  r = x.remove(4);
+  VERIFY( r == 1 );
+}
+
+void
+test02()
+{
+  int i = 0;
+  auto pred = [&i](int val) { return val == i; };
+  test_type x{1, 2, 3, 4, 3, 2, 1};
+  static_assert(std::is_same_v<decltype(x.remove_if(pred)),
+			       test_type::size_type>);
+  test_type::size_type r = x.remove_if(pred);
+  VERIFY( r == 0 );
+  i = 1;
+  r = x.remove_if(pred);
+  VERIFY( r == 2 );
+  r = x.remove_if(pred);
+  VERIFY( r == 0 );
+  i = 4;
+  r = x.remove_if(pred);
+  VERIFY( r == 1 );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/list/operations/unique_cxx20_return.cc b/libstdc++-v3/testsuite/23_containers/list/operations/unique_cxx20_return.cc
new file mode 100644
index 00000000000..90d6dd155ff
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/list/operations/unique_cxx20_return.cc
@@ -0,0 +1,55 @@
+// Copyright (C) 2018 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <list>
+#include <testsuite_hooks.h>
+
+using test_type = std::list<int>;
+
+void
+test01()
+{
+  test_type x{1, 2, 2, 4, 4, 2, 1};
+  static_assert(std::is_same_v<decltype(x.unique()), test_type::size_type>);
+  test_type::size_type r = x.unique();
+  VERIFY( r == 2 );
+  r = x.unique();
+  VERIFY( r == 0 );
+}
+
+void
+test02()
+{
+  auto pred = [](int val, int prev) { return val == prev; };
+  test_type x{1, 2, 2, 4, 4, 2, 1};
+  static_assert(std::is_same_v<decltype(x.unique(pred)),
+			       test_type::size_type>);
+  test_type::size_type r = x.unique(pred);
+  VERIFY( r == 2 );
+  r = x.unique(pred);
+  VERIFY( r == 0 );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}


More information about the Gcc-patches mailing list