Patchwork [v3] add C++11 allocator support to forward_list

login
register
mail settings
Submitter Jonathan Wakely
Date Oct. 18, 2012, 9:06 p.m.
Message ID <CAH6eHdRRvbiRtx_9_CpV-Hi99YWBxrZe8WYrVSGPwa+T_yJA1Q@mail.gmail.com>
Download mbox | patch
Permalink /patch/192468/
State New
Headers show

Comments

Jonathan Wakely - Oct. 18, 2012, 9:06 p.m.
I should get some of the allocator work out of my git tree while we're
in stage 1, this is for forward_list.

        * include/bits/forward_list.h: Add C++11 allocator support.
        * include/bits/forward_list.tcc: Likewise.
        * doc/xml/manual/status_cxx2011.xml: Update.
        * testsuite/23_containers/forward_list/allocator/copy.cc: New.
        * testsuite/23_containers/forward_list/allocator/copy_assign.cc: New.
        * testsuite/23_containers/forward_list/allocator/minimal.cc: New.
        * testsuite/23_containers/forward_list/allocator/move_assign.cc: New.
        * testsuite/23_containers/forward_list/allocator/noexcept.cc: New.
        * testsuite/23_containers/forward_list/allocator/swap.cc: New.

Tested x86_64-linux, committed to trunk.
commit 2c5b344ef08b72cbf9e21f9859f85e54f3e87f26
Author: Jonathan Wakely <jwakely.gcc@gmail.com>
Date:   Mon Mar 12 22:43:34 2012 +0000

    	* include/bits/forward_list.h: Add C++11 allocator support.
    	* include/bits/forward_list.tcc: Likewise.
    	* doc/xml/manual/status_cxx2011.xml: Update.
    	* testsuite/23_containers/forward_list/allocator/copy.cc: New.
    	* testsuite/23_containers/forward_list/allocator/copy_assign.cc: New.
    	* testsuite/23_containers/forward_list/allocator/minimal.cc: New.
    	* testsuite/23_containers/forward_list/allocator/move_assign.cc: New.
    	* testsuite/23_containers/forward_list/allocator/noexcept.cc: New.
    	* testsuite/23_containers/forward_list/allocator/swap.cc: New.

Patch

diff --git a/libstdc++-v3/doc/xml/manual/status_cxx2011.xml b/libstdc++-v3/doc/xml/manual/status_cxx2011.xml
index 1e149f0..ba37e0e 100644
--- a/libstdc++-v3/doc/xml/manual/status_cxx2011.xml
+++ b/libstdc++-v3/doc/xml/manual/status_cxx2011.xml
@@ -1378,7 +1378,8 @@  particular release.
       <entry>23.2.1</entry>
       <entry>General container requirements</entry>
       <entry>Partial</entry>
-      <entry>Only <code>vector</code> meets the requirements
+      <entry>Only <code>vector</code> and <code>forward_list</code>
+             meet the requirements
              relating to allocator use and propagation.</entry>
     </row>
     <row>
diff --git a/libstdc++-v3/include/bits/forward_list.h b/libstdc++-v3/include/bits/forward_list.h
index ce35504..a5c9f43 100644
--- a/libstdc++-v3/include/bits/forward_list.h
+++ b/libstdc++-v3/include/bits/forward_list.h
@@ -266,11 +266,15 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     struct _Fwd_list_base
     {
     protected:
-      typedef typename _Alloc::template rebind<_Tp>::other _Tp_alloc_type;
+      typedef typename __gnu_cxx::__alloc_traits<_Alloc> _Alloc_traits;
+      typedef typename _Alloc_traits::template rebind<_Tp>::other
+        _Tp_alloc_type;
 
-      typedef typename _Alloc::template 
+      typedef typename _Alloc_traits::template
         rebind<_Fwd_list_node<_Tp>>::other _Node_alloc_type;
 
+      typedef __gnu_cxx::__alloc_traits<_Node_alloc_type> _Node_alloc_traits;
+
       struct _Fwd_list_impl 
       : public _Node_alloc_type
       {
@@ -312,12 +316,7 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 
       _Fwd_list_base(const _Fwd_list_base& __lst, const _Node_alloc_type& __a);
 
-      _Fwd_list_base(_Fwd_list_base&& __lst, const _Node_alloc_type& __a)
-      : _M_impl(__a)
-      {
-	this->_M_impl._M_head._M_next = __lst._M_impl._M_head._M_next;
-	__lst._M_impl._M_head._M_next = 0;
-      }
+      _Fwd_list_base(_Fwd_list_base&& __lst, const _Node_alloc_type& __a);
 
       _Fwd_list_base(_Fwd_list_base&& __lst)
       : _M_impl(std::move(__lst._M_get_Node_allocator()))
@@ -333,7 +332,7 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 
       _Node*
       _M_get_node()
-      { return _M_get_Node_allocator().allocate(1); }
+      { return _Node_alloc_traits::allocate(_M_get_Node_allocator(), 1); }
 
       template<typename... _Args>
         _Node*
@@ -342,8 +341,8 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
           _Node* __node = this->_M_get_node();
           __try
             {
-              _M_get_Node_allocator().construct(__node,
-                                              std::forward<_Args>(__args)...);
+              _Node_alloc_traits::construct(_M_get_Node_allocator(), __node,
+                                            std::forward<_Args>(__args)...);
               __node->_M_next = 0;
             }
           __catch(...)
@@ -360,7 +359,7 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 
       void
       _M_put_node(_Node* __p)
-      { _M_get_Node_allocator().deallocate(__p, 1); }
+      { _Node_alloc_traits::deallocate(_M_get_Node_allocator(), __p, 1); }
 
       _Fwd_list_node_base*
       _M_erase_after(_Fwd_list_node_base* __pos);
@@ -413,14 +412,16 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       typedef _Fwd_list_node_base                          _Node_base;
       typedef typename _Base::_Tp_alloc_type               _Tp_alloc_type;
       typedef typename _Base::_Node_alloc_type             _Node_alloc_type;
+      typedef typename _Base::_Node_alloc_traits           _Node_alloc_traits;
+      typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type>    _Alloc_traits;
 
     public:
       // types:
       typedef _Tp                                          value_type;
-      typedef typename _Tp_alloc_type::pointer             pointer;
-      typedef typename _Tp_alloc_type::const_pointer       const_pointer;
-      typedef typename _Tp_alloc_type::reference           reference;
-      typedef typename _Tp_alloc_type::const_reference     const_reference;
+      typedef typename _Alloc_traits::pointer              pointer;
+      typedef typename _Alloc_traits::const_pointer        const_pointer;
+      typedef typename _Alloc_traits::reference            reference;
+      typedef typename _Alloc_traits::const_reference      const_reference;
  
       typedef _Fwd_list_iterator<_Tp>                      iterator;
       typedef _Fwd_list_const_iterator<_Tp>                const_iterator;
@@ -504,12 +505,10 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        *  @brief  The %forward_list copy constructor.
        *  @param  __list  A %forward_list of identical element and allocator
        *                types.
-       *
-       *  The newly-created %forward_list uses a copy of the allocation
-       *  object used by @a __list.
        */
       forward_list(const forward_list& __list)
-      : _Base(__list._M_get_Node_allocator())
+      : _Base(_Node_alloc_traits::_S_select_on_copy(
+                __list._M_get_Node_allocator()))
       { _M_range_initialize(__list.begin(), __list.end()); }
 
       /**
@@ -560,16 +559,18 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        *                types.
        *
        *  The contents of @a __list are moved into this %forward_list
-       *  (without copying). @a __list is a valid, but unspecified
-       *  %forward_list
+       *  (without copying, if the allocators permit it).
+       *  @a __list is a valid, but unspecified %forward_list
        */
       forward_list&
       operator=(forward_list&& __list)
+      noexcept(_Node_alloc_traits::_S_nothrow_move())
       {
-	// NB: DR 1204.
-	// NB: DR 675.
-	this->clear();
-	this->swap(__list);
+        constexpr bool __move_storage =
+          _Node_alloc_traits::_S_propagate_on_move_assign()
+          || _Node_alloc_traits::_S_always_equal();
+        _M_move_assign(std::move(__list),
+                       integral_constant<bool, __move_storage>());
 	return *this;
       }
 
@@ -740,7 +741,7 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        */
       size_type
       max_size() const noexcept
-      { return this->_M_get_Node_allocator().max_size(); }
+      { return _Node_alloc_traits::max_size(this->_M_get_Node_allocator()); }
 
       // 23.2.3.3 element access:
 
@@ -981,8 +982,13 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
        */
       void
       swap(forward_list& __list)
-      { std::swap(this->_M_impl._M_head._M_next,
-		  __list._M_impl._M_head._M_next); }
+      noexcept(_Node_alloc_traits::_S_nothrow_swap())
+      {
+        std::swap(this->_M_impl._M_head._M_next,
+		  __list._M_impl._M_head._M_next);
+	_Node_alloc_traits::_S_on_swap(this->_M_get_Node_allocator(),
+                                       __list._M_get_Node_allocator());
+      }
 
       /**
        *  @brief Resizes the %forward_list to the specified number of
@@ -1239,6 +1245,33 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       // Called by resize(sz).
       void
       _M_default_insert_after(const_iterator __pos, size_type __n);
+
+      // Called by operator=(forward_list&&)
+      void
+      _M_move_assign(forward_list&& __list, std::true_type) noexcept
+      {
+        clear();
+        std::swap(this->_M_impl._M_head._M_next,
+                  __list._M_impl._M_head._M_next);
+        std::__alloc_on_move(this->_M_get_Node_allocator(),
+                             __list._M_get_Node_allocator());
+      }
+
+      // Called by operator=(forward_list&&)
+      void
+      _M_move_assign(forward_list&& __list, std::false_type)
+      {
+        if (__list._M_get_Node_allocator() == this->_M_get_Node_allocator())
+          _M_move_assign(std::move(__list), std::true_type());
+        else
+          {
+            // The rvalue's allocator cannot be moved, or is not equal,
+            // so we need to individually move each element.
+            this->assign(std::__make_move_if_noexcept_iterator(__list.begin()),
+                         std::__make_move_if_noexcept_iterator(__list.end()));
+            __list.clear();
+          }
+      }
     };
 
   /**
diff --git a/libstdc++-v3/include/bits/forward_list.tcc b/libstdc++-v3/include/bits/forward_list.tcc
index 3c9f238..5d18a6e 100644
--- a/libstdc++-v3/include/bits/forward_list.tcc
+++ b/libstdc++-v3/include/bits/forward_list.tcc
@@ -52,6 +52,30 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     }
 
   template<typename _Tp, typename _Alloc>
+    _Fwd_list_base<_Tp, _Alloc>::
+    _Fwd_list_base(_Fwd_list_base&& __lst, const _Node_alloc_type& __a)
+    : _M_impl(__a)
+    {
+      if (__lst._M_get_Node_allocator() == __a)
+        this->_M_impl._M_head._M_next = __lst._M_impl._M_head._M_next;
+      else
+        {
+          this->_M_impl._M_head._M_next = 0;
+          _Fwd_list_node_base* __to = &this->_M_impl._M_head;
+          _Node* __curr = static_cast<_Node*>(__lst._M_impl._M_head._M_next);
+
+          while (__curr)
+            {
+              __to->_M_next =
+                _M_create_node(std::move_if_noexcept(__curr->_M_value));
+              __to = __to->_M_next;
+              __curr = static_cast<_Node*>(__curr->_M_next);
+            }
+        }
+      __lst._M_impl._M_head._M_next = 0;
+    }
+
+  template<typename _Tp, typename _Alloc>
     template<typename... _Args>
       _Fwd_list_node_base*
       _Fwd_list_base<_Tp, _Alloc>::
@@ -72,7 +96,7 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     {
       _Node* __curr = static_cast<_Node*>(__pos->_M_next);
       __pos->_M_next = __curr->_M_next;
-      _M_get_Node_allocator().destroy(__curr);
+      _Node_alloc_traits::destroy(_M_get_Node_allocator(), __curr);
       _M_put_node(__curr);
       return __pos->_M_next;
     }
@@ -88,7 +112,7 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
         {
           _Node* __temp = __curr;
           __curr = static_cast<_Node*>(__curr->_M_next);
-          _M_get_Node_allocator().destroy(__temp);
+          _Node_alloc_traits::destroy(_M_get_Node_allocator(), __temp);
           _M_put_node(__temp);
         }
       __pos->_M_next = __last;
@@ -144,6 +168,18 @@  _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
     {
       if (&__list != this)
         {
+	  if (_Node_alloc_traits::_S_propagate_on_copy_assign())
+	    {
+              auto& __this_alloc = this->_M_get_Node_allocator();
+              auto& __that_alloc = __list._M_get_Node_allocator();
+              if (!_Node_alloc_traits::_S_always_equal()
+	          && __this_alloc != __that_alloc)
+	        {
+		  // replacement allocator cannot free existing storage
+		  clear();
+		}
+	      std::__alloc_on_copy(__this_alloc, __that_alloc);
+            }
           iterator __prev1 = before_begin();
           iterator __curr1 = begin();
           iterator __last1 = end();
diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/allocator/copy.cc b/libstdc++-v3/testsuite/23_containers/forward_list/allocator/copy.cc
new file mode 100644
index 0000000..c388ef3
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/forward_list/allocator/copy.cc
@@ -0,0 +1,55 @@ 
+// Copyright (C) 2012 Free Software Foundation
+//
+// 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++0x" }
+
+#include <forward_list>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, false> alloc_type;
+  typedef std::forward_list<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(v1);
+  VERIFY(1 == v1.get_allocator().get_personality());
+  VERIFY(0 == v2.get_allocator().get_personality());
+}
+
+void test02()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, true> alloc_type;
+  typedef std::forward_list<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(v1);
+  VERIFY(1 == v1.get_allocator().get_personality());
+  VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/allocator/copy_assign.cc b/libstdc++-v3/testsuite/23_containers/forward_list/allocator/copy_assign.cc
new file mode 100644
index 0000000..e78856a
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/forward_list/allocator/copy_assign.cc
@@ -0,0 +1,57 @@ 
+// Copyright (C) 2012 Free Software Foundation
+//
+// 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++0x" }
+
+#include <forward_list>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, false> alloc_type;
+  typedef std::forward_list<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(alloc_type(2));
+  v2 = v1;
+  VERIFY(1 == v1.get_allocator().get_personality());
+  VERIFY(2 == v2.get_allocator().get_personality());
+}
+
+void test02()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, true> alloc_type;
+  typedef std::forward_list<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(alloc_type(2));
+  v2 = v1;
+  VERIFY(1 == v1.get_allocator().get_personality());
+  VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/allocator/minimal.cc b/libstdc++-v3/testsuite/23_containers/forward_list/allocator/minimal.cc
new file mode 100644
index 0000000..51033f1
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/forward_list/allocator/minimal.cc
@@ -0,0 +1,47 @@ 
+// Copyright (C) 2012 Free Software Foundation
+//
+// 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++0x" }
+
+#include <forward_list>
+#include <memory>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+bool operator==(const T& l, const T& r) { return l.i == r.i; }
+bool operator<(const T& l, const T& r) { return l.i < r.i; }
+
+using __gnu_test::SimpleAllocator;
+
+template class std::forward_list<T, SimpleAllocator<T>>;
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+  typedef SimpleAllocator<T> alloc_type;
+  typedef std::allocator_traits<alloc_type> traits_type;
+  typedef std::forward_list<T, alloc_type> test_type;
+  test_type v(alloc_type{});
+  VERIFY( v.max_size() == traits_type::max_size(v.get_allocator()) );
+}
+
+int main()
+{
+  test01();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/allocator/move_assign.cc b/libstdc++-v3/testsuite/23_containers/forward_list/allocator/move_assign.cc
new file mode 100644
index 0000000..18539ff
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/forward_list/allocator/move_assign.cc
@@ -0,0 +1,57 @@ 
+// Copyright (C) 2012 Free Software Foundation
+//
+// 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++0x" }
+
+#include <forward_list>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, false> alloc_type;
+  typedef std::forward_list<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(alloc_type(2));
+  v2 = std::move(v1);
+  VERIFY(1 == v1.get_allocator().get_personality());
+  VERIFY(2 == v2.get_allocator().get_personality());
+}
+
+void test02()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, true> alloc_type;
+  typedef std::forward_list<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(alloc_type(2));
+  v2 = std::move(v1);
+  VERIFY(0 == v1.get_allocator().get_personality());
+  VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/allocator/noexcept.cc b/libstdc++-v3/testsuite/23_containers/forward_list/allocator/noexcept.cc
new file mode 100644
index 0000000..77d2c21
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/forward_list/allocator/noexcept.cc
@@ -0,0 +1,76 @@ 
+// Copyright (C) 2012 Free Software Foundation
+//
+// 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++0x" }
+
+#include <forward_list>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+namespace __gnu_test
+{
+  inline void
+  swap(propagating_allocator<T, true>& l, propagating_allocator<T, true>& r)
+  noexcept(false)
+  {
+    typedef uneq_allocator<T> base_alloc;
+    swap(static_cast<base_alloc&>(l), static_cast<base_alloc&>(r));
+  }
+}
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+  typedef std::allocator<T> alloc_type;
+  typedef std::forward_list<T, alloc_type> test_type;
+  test_type v1;
+  test_type v2;
+  // this is a GNU extension for std::allocator
+  static_assert( noexcept( v1 = std::move(v2) ), "Move assign cannot throw" );
+  static_assert( noexcept( v1.swap(v2) ), "Swap cannot throw" );
+}
+
+void test02()
+{
+  typedef propagating_allocator<T, false> alloc_type;
+  typedef std::forward_list<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(alloc_type(2));
+  static_assert( !noexcept( v1 = std::move(v2) ), "Move assign can throw" );
+  static_assert( noexcept( v1.swap(v2) ), "Swap cannot throw" );
+}
+
+void test03()
+{
+  typedef propagating_allocator<T, true> alloc_type;
+  typedef std::forward_list<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(alloc_type(2));
+  static_assert( noexcept( v1 = std::move(v2) ), "Move assign cannot throw" );
+  // static_assert( !noexcept( v1.swap(v2) ), "Swap can throw" );
+}
+
+int main()
+{
+  test01();
+  test02();
+  test03();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/allocator/swap.cc b/libstdc++-v3/testsuite/23_containers/forward_list/allocator/swap.cc
new file mode 100644
index 0000000..60d83d4
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/forward_list/allocator/swap.cc
@@ -0,0 +1,57 @@ 
+// Copyright (C) 2012 Free Software Foundation
+//
+// 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++0x" }
+
+#include <forward_list>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct T { int i; };
+
+using __gnu_test::propagating_allocator;
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, false> alloc_type;
+  typedef std::forward_list<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(alloc_type(2));
+  std::swap(v1, v2);
+  VERIFY(1 == v1.get_allocator().get_personality());
+  VERIFY(2 == v2.get_allocator().get_personality());
+}
+
+void test02()
+{
+  bool test __attribute__((unused)) = true;
+  typedef propagating_allocator<T, true> alloc_type;
+  typedef std::forward_list<T, alloc_type> test_type;
+  test_type v1(alloc_type(1));
+  test_type v2(alloc_type(2));
+  std::swap(v1, v2);
+  VERIFY(2 == v1.get_allocator().get_personality());
+  VERIFY(1 == v2.get_allocator().get_personality());
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}