Patchwork [v3] More noexcept work on <tuple>, etc

login
register
mail settings
Submitter Paolo Carlini
Date May 19, 2011, 5:21 p.m.
Message ID <4DD5519B.1030008@oracle.com>
Download mbox | patch
Permalink /patch/96432/
State New
Headers show

Comments

Paolo Carlini - May 19, 2011, 5:21 p.m.
Hi,

also exploiting the new std::is_nothrow_move_assignable, plus various 
fixes (added 2 testcases). Tested x86_64-linux, committed to mainline.

Paolo.

///////////////////
2011-05-19  Paolo Carlini  <paolo.carlini@oracle.com>

	* include/std/tuple (tuple<>::operator=(tuple&&)): Specify as
        noexcept.
	(__get_helper): Likewise.
	(_Head_base<>::_M_head, _Tuple_impl<>::_M_head, _M_tail): Likewise.
	* include/bits/move.h (swap): Likewise.
	* include/bits/algorithmfwd.h (swap): Adjust.
	* include/bits/stl_pair.h (pair<>::operator=(pair&&)): Spec noexcept.
	* testsuite/util/testsuite_allocator.h (uneq_allocator): In C++0x
	mode, prefer delete to access control to make the type not copy
	assignable.
	* testsuite/util/testsuite_tr1.h: Add test classes.
	* testsuite/20_util/tuple/noexcept_swap.cc: New.
	* testsuite/20_util/tuple/noexcept_move_assign.cc: Likewise.
	* testsuite/25_algorithms/reverse/moveable.cc: Likewise, prefer
	delete to access control.
	* testsuite/25_algorithms/swap_ranges/moveable.cc: Likewise.
	* testsuite/20_util/weak_ptr/comparison/cmp_neg.cc: Adjust dg-warning
	line numbers.

Patch

Index: include/std/tuple
===================================================================
--- include/std/tuple	(revision 173912)
+++ include/std/tuple	(working copy)
@@ -85,8 +85,8 @@ 
         _Head_base(_UHead&& __h)
 	: _Head(std::forward<_UHead>(__h)) { }
 
-      _Head&       _M_head()       { return *this; }
-      const _Head& _M_head() const { return *this; }
+      _Head&       _M_head() noexcept       { return *this; }
+      const _Head& _M_head() const noexcept { return *this; }
     };
 
   template<std::size_t _Idx, typename _Head>
@@ -102,8 +102,8 @@ 
         _Head_base(_UHead&& __h)
 	: _M_head_impl(std::forward<_UHead>(__h)) { }
 
-      _Head&       _M_head()       { return _M_head_impl; }
-      const _Head& _M_head() const { return _M_head_impl; }        
+      _Head&       _M_head() noexcept       { return _M_head_impl; }
+      const _Head& _M_head() const noexcept { return _M_head_impl; }        
 
       _Head _M_head_impl; 
     };
@@ -147,11 +147,11 @@ 
       typedef _Tuple_impl<_Idx + 1, _Tail...> _Inherited;
       typedef _Head_base<_Idx, _Head, std::is_empty<_Head>::value> _Base;
 
-      _Head&            _M_head()       { return _Base::_M_head(); }
-      const _Head&      _M_head() const { return _Base::_M_head(); }
+      _Head&            _M_head() noexcept       { return _Base::_M_head(); }
+      const _Head&      _M_head() const noexcept { return _Base::_M_head(); }
 
-      _Inherited&       _M_tail()       { return *this; }
-      const _Inherited& _M_tail() const { return *this; }
+      _Inherited&       _M_tail() noexcept       { return *this; }
+      const _Inherited& _M_tail() const noexcept { return *this; }
 
       constexpr _Tuple_impl()
       : _Inherited(), _Base() { }
@@ -191,6 +191,8 @@ 
 
       _Tuple_impl&
       operator=(_Tuple_impl&& __in)
+      noexcept(is_nothrow_move_assignable<_Head>::value
+	       && is_nothrow_move_assignable<_Inherited>::value)
       {
 	_M_head() = std::forward<_Head>(__in._M_head());
 	_M_tail() = std::move(__in._M_tail());
@@ -276,6 +278,7 @@ 
 
       tuple&
       operator=(tuple&& __in)
+      noexcept(is_nothrow_move_assignable<_Inherited>::value)
       {
 	static_cast<_Inherited&>(*this) = std::move(__in);
 	return *this;
@@ -364,7 +367,7 @@ 
 
       tuple&
       operator=(tuple&& __in)
-      // noexcept has to wait is_nothrow_move_assignable
+      noexcept(is_nothrow_move_assignable<_Inherited>::value)
       {
 	static_cast<_Inherited&>(*this) = std::move(__in);
 	return *this;
@@ -397,7 +400,7 @@ 
 
       template<typename _U1, typename _U2>
         tuple&
-        operator=(pair<_U1, _U2>&& __in) noexcept
+        operator=(pair<_U1, _U2>&& __in)
         {
 	  this->_M_head() = std::forward<_U1>(__in.first);
 	  this->_M_tail()._M_head() = std::forward<_U2>(__in.second);
@@ -452,6 +455,7 @@ 
 
       tuple&
       operator=(tuple&& __in)
+      noexcept(is_nothrow_move_assignable<_Inherited>::value)
       {
 	static_cast<_Inherited&>(*this) = std::move(__in);
 	return *this;
@@ -517,12 +521,12 @@ 
 
   template<std::size_t __i, typename _Head, typename... _Tail>
     inline typename __add_ref<_Head>::type
-    __get_helper(_Tuple_impl<__i, _Head, _Tail...>& __t)
+    __get_helper(_Tuple_impl<__i, _Head, _Tail...>& __t) noexcept
     { return __t._M_head(); }
 
   template<std::size_t __i, typename _Head, typename... _Tail>
     inline typename __add_c_ref<_Head>::type
-    __get_helper(const _Tuple_impl<__i, _Head, _Tail...>& __t)
+    __get_helper(const _Tuple_impl<__i, _Head, _Tail...>& __t) noexcept
     { return __t._M_head(); }
 
   // Return a reference (const reference, rvalue reference) to the ith element
Index: include/bits/move.h
===================================================================
--- include/bits/move.h	(revision 173912)
+++ include/bits/move.h	(working copy)
@@ -135,7 +135,10 @@ 
   template<typename _Tp>
     inline void
     swap(_Tp& __a, _Tp& __b)
-    // noexcept has to wait is_nothrow_move_assignable
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+    noexcept(is_nothrow_move_constructible<_Tp>::value
+	     && is_nothrow_move_assignable<_Tp>::value)
+#endif
     {
       // concept requirements
       __glibcxx_function_requires(_SGIAssignableConcept<_Tp>)
Index: include/bits/stl_pair.h
===================================================================
--- include/bits/stl_pair.h	(revision 173912)
+++ include/bits/stl_pair.h	(working copy)
@@ -153,7 +153,8 @@ 
 
       pair&
       operator=(pair&& __p)
-      // noexcept has to wait is_nothrow_move_assignable
+      noexcept(is_nothrow_move_assignable<_T1>::value
+	       && is_nothrow_move_assignable<_T2>::value)
       {
 	first = std::move(__p.first);
 	second = std::move(__p.second);
Index: include/bits/algorithmfwd.h
===================================================================
--- include/bits/algorithmfwd.h	(revision 173912)
+++ include/bits/algorithmfwd.h	(working copy)
@@ -549,7 +549,12 @@ 
 
   template<typename _Tp> 
     void 
-    swap(_Tp&, _Tp&);
+    swap(_Tp&, _Tp&)
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+    noexcept(is_nothrow_move_constructible<_Tp>::value
+	     && is_nothrow_move_assignable<_Tp>::value)
+#endif
+    ;
 
   template<typename _Tp, size_t _Nm>
     void
Index: testsuite/25_algorithms/swap_ranges/moveable.cc
===================================================================
--- testsuite/25_algorithms/swap_ranges/moveable.cc	(revision 173912)
+++ testsuite/25_algorithms/swap_ranges/moveable.cc	(working copy)
@@ -1,7 +1,7 @@ 
 // { dg-do compile }
 // { dg-options "-std=gnu++0x" }
 
-// Copyright (C) 2005, 2007, 2009 Free Software Foundation, Inc.
+// Copyright (C) 2005, 2007, 2009, 2011 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
@@ -27,11 +27,11 @@ 
 
 using __gnu_test::forward_iterator_wrapper;
 
-class X 
+struct X 
 { 
-  X();
-  X(const X&);
-  void operator=(const X&);
+  X() = delete;
+  X(const X&) = delete;
+  void operator=(const X&) = delete;
 };
 
 void
Index: testsuite/25_algorithms/reverse/moveable.cc
===================================================================
--- testsuite/25_algorithms/reverse/moveable.cc	(revision 173912)
+++ testsuite/25_algorithms/reverse/moveable.cc	(working copy)
@@ -1,7 +1,7 @@ 
 // { dg-do compile }
 // { dg-options "-std=gnu++0x" }
 
-// Copyright (C) 2005, 2007, 2009 Free Software Foundation, Inc.
+// Copyright (C) 2005, 2007, 2009, 2011 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
@@ -27,11 +27,11 @@ 
 
 using __gnu_test::bidirectional_iterator_wrapper;
 
-class X 
-{ 
-  X();
-  X(const X&);
-  void operator=(const X&);
+struct X 
+{
+  X() = delete;
+  X(const X&) = delete;
+  void operator=(const X&) = delete;
 };
 
 void
Index: testsuite/util/testsuite_tr1.h
===================================================================
--- testsuite/util/testsuite_tr1.h	(revision 173912)
+++ testsuite/util/testsuite_tr1.h	(working copy)
@@ -240,6 +240,42 @@ 
     DeletedMoveAssignClass&
     operator=(DeletedMoveAssignClass&&) = delete;
   };
+
+  struct NoexceptMoveConsNoexceptMoveAssignClass
+  {
+    NoexceptMoveConsNoexceptMoveAssignClass
+    (NoexceptMoveConsNoexceptMoveAssignClass&&) noexcept(true);
+
+    NoexceptMoveConsNoexceptMoveAssignClass&
+    operator=(NoexceptMoveConsNoexceptMoveAssignClass&&) noexcept(true);
+  };
+
+  struct ExceptMoveConsNoexceptMoveAssignClass
+  {
+    ExceptMoveConsNoexceptMoveAssignClass
+    (ExceptMoveConsNoexceptMoveAssignClass&&) noexcept(false);
+
+    ExceptMoveConsNoexceptMoveAssignClass&
+    operator=(ExceptMoveConsNoexceptMoveAssignClass&&) noexcept(true);
+  };
+
+  struct NoexceptMoveConsExceptMoveAssignClass
+  {
+    NoexceptMoveConsExceptMoveAssignClass
+    (NoexceptMoveConsExceptMoveAssignClass&&) noexcept(true);
+
+    NoexceptMoveConsExceptMoveAssignClass&
+    operator=(NoexceptMoveConsExceptMoveAssignClass&&) noexcept(false);
+  };
+
+  struct ExceptMoveConsExceptMoveAssignClass
+  {
+    ExceptMoveConsExceptMoveAssignClass
+    (ExceptMoveConsExceptMoveAssignClass&&) noexcept(false);
+
+    ExceptMoveConsExceptMoveAssignClass&
+    operator=(ExceptMoveConsExceptMoveAssignClass&&) noexcept(false);
+  };
 #endif
 
   struct NType   // neither trivial nor standard-layout
Index: testsuite/util/testsuite_allocator.h
===================================================================
--- testsuite/util/testsuite_allocator.h	(revision 173912)
+++ testsuite/util/testsuite_allocator.h	(working copy)
@@ -327,10 +327,19 @@ 
       void 
       destroy(pointer p) { p->~Tp(); }
 
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+      // Not copy assignable...
+      uneq_allocator&
+      operator=(const uneq_allocator&) = delete;
+#endif
+
     private:
+
+#ifndef __GXX_EXPERIMENTAL_CXX0X__
       // Not assignable...
       uneq_allocator&
       operator=(const uneq_allocator&);
+#endif
 
       // ... yet swappable!
       friend inline void
Index: testsuite/20_util/tuple/noexcept_swap.cc
===================================================================
--- testsuite/20_util/tuple/noexcept_swap.cc	(revision 0)
+++ testsuite/20_util/tuple/noexcept_swap.cc	(revision 0)
@@ -0,0 +1,116 @@ 
+// { dg-do compile }
+// { dg-options "-std=gnu++0x" }
+
+// 2011-05-19  Paolo Carlini  <paolo.carlini@oracle.com>
+//
+// Copyright (C) 2011 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/>.
+
+#include <tuple>
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+typedef std::tuple<int>                                        tt1;
+typedef std::tuple<int, double>                                tt2;
+typedef std::tuple<short, double, int>                         tt3;
+typedef std::tuple<short, NoexceptMoveAssignClass, double>     tt4;
+typedef std::tuple<ExceptMoveAssignClass>                      tt5;
+typedef std::tuple<ExceptMoveAssignClass, double>              tt6;
+typedef std::tuple<short, double, ExceptMoveAssignClass>       tt7;
+typedef std::tuple<ExceptMoveConsClass>                        tt8;
+typedef std::tuple<int, ExceptMoveConsClass>                   tt9;
+typedef std::tuple<ExceptMoveConsClass, short, double>         tt10;
+typedef std::tuple<short, NoexceptMoveConsClass, double>       tt11;
+typedef std::tuple<NoexceptMoveConsClass>                      tt12;
+typedef std::tuple<NoexceptMoveConsNoexceptMoveAssignClass>    tt13;
+typedef std::tuple<ExceptMoveConsNoexceptMoveAssignClass>      tt14;
+typedef std::tuple<NoexceptMoveConsExceptMoveAssignClass>      tt15;
+typedef std::tuple<ExceptMoveConsExceptMoveAssignClass>        tt16;
+typedef std::tuple<NoexceptMoveConsNoexceptMoveAssignClass,
+		   double>                                     tt17;
+typedef std::tuple<double,
+		   NoexceptMoveConsNoexceptMoveAssignClass,
+		   short>                                      tt18;
+typedef std::tuple<NoexceptMoveConsNoexceptMoveAssignClass,
+		   NoexceptMoveConsNoexceptMoveAssignClass,
+		   char>                                       tt19;
+typedef std::tuple<NoexceptMoveConsNoexceptMoveAssignClass,
+		   NoexceptMoveConsNoexceptMoveAssignClass,
+		   NoexceptMoveConsNoexceptMoveAssignClass>    tt20;
+typedef std::tuple<NoexceptMoveConsNoexceptMoveAssignClass,
+		   ExceptMoveConsNoexceptMoveAssignClass,
+		   NoexceptMoveConsNoexceptMoveAssignClass>    tt21;
+typedef std::tuple<NoexceptMoveConsNoexceptMoveAssignClass,
+		   ExceptMoveConsNoexceptMoveAssignClass,
+		   NoexceptMoveConsExceptMoveAssignClass>      tt22;
+typedef std::tuple<NoexceptMoveConsNoexceptMoveAssignClass,
+		   NoexceptMoveConsNoexceptMoveAssignClass,
+		   ExceptMoveConsExceptMoveAssignClass>        tt23;
+typedef std::tuple<NoexceptMoveConsNoexceptMoveAssignClass,
+		   short, ExceptMoveConsExceptMoveAssignClass> tt24;
+typedef std::tuple<NoexceptMoveConsNoexceptMoveAssignClass,
+		   short, ExceptMoveConsExceptMoveAssignClass> tt25;
+
+static_assert(noexcept(std::declval<tt1&>().swap(std::declval<tt1&>())),
+	      "Error");
+static_assert(noexcept(std::declval<tt2&>().swap(std::declval<tt2&>())),
+	      "Error");
+static_assert(noexcept(std::declval<tt3&>().swap(std::declval<tt3&>())),
+	      "Error");
+static_assert(noexcept(std::declval<tt4&>().swap(std::declval<tt4&>())),
+	      "Error");
+static_assert(!noexcept(std::declval<tt5&>().swap(std::declval<tt5&>())),
+	      "Error");
+static_assert(!noexcept(std::declval<tt6&>().swap(std::declval<tt6&>())),
+	      "Error");
+static_assert(!noexcept(std::declval<tt7&>().swap(std::declval<tt7&>())),
+	      "Error");
+static_assert(!noexcept(std::declval<tt8&>().swap(std::declval<tt8&>())),
+	      "Error");
+static_assert(!noexcept(std::declval<tt9&>().swap(std::declval<tt9&>())),
+	      "Error");
+static_assert(!noexcept(std::declval<tt10&>().swap(std::declval<tt10&>())),
+	      "Error");
+static_assert(noexcept(std::declval<tt11&>().swap(std::declval<tt11&>())),
+	      "Error");
+static_assert(noexcept(std::declval<tt12&>().swap(std::declval<tt12&>())),
+	      "Error");
+static_assert(noexcept(std::declval<tt13&>().swap(std::declval<tt13&>())),
+	      "Error");
+static_assert(!noexcept(std::declval<tt14&>().swap(std::declval<tt14&>())),
+	      "Error");
+static_assert(!noexcept(std::declval<tt15&>().swap(std::declval<tt15&>())),
+	      "Error");
+static_assert(!noexcept(std::declval<tt16&>().swap(std::declval<tt16&>())),
+	      "Error");
+static_assert(noexcept(std::declval<tt17&>().swap(std::declval<tt17&>())),
+	      "Error");
+static_assert(noexcept(std::declval<tt18&>().swap(std::declval<tt18&>())),
+	      "Error");
+static_assert(noexcept(std::declval<tt19&>().swap(std::declval<tt19&>())),
+	      "Error");
+static_assert(noexcept(std::declval<tt20&>().swap(std::declval<tt20&>())),
+	      "Error");
+static_assert(!noexcept(std::declval<tt21&>().swap(std::declval<tt21&>())),
+	      "Error");
+static_assert(!noexcept(std::declval<tt22&>().swap(std::declval<tt22&>())),
+	      "Error");
+static_assert(!noexcept(std::declval<tt23&>().swap(std::declval<tt23&>())),
+	      "Error");
+static_assert(!noexcept(std::declval<tt24&>().swap(std::declval<tt24&>())),
+	      "Error");
Index: testsuite/20_util/tuple/noexcept_move_assign.cc
===================================================================
--- testsuite/20_util/tuple/noexcept_move_assign.cc	(revision 0)
+++ testsuite/20_util/tuple/noexcept_move_assign.cc	(revision 0)
@@ -0,0 +1,59 @@ 
+// { dg-do compile }
+// { dg-options "-std=gnu++0x" }
+
+// 2011-05-19  Paolo Carlini  <paolo.carlini@oracle.com>
+//
+// Copyright (C) 2011 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/>.
+
+#include <tuple>
+#include <testsuite_tr1.h>
+
+using namespace __gnu_test;
+
+typedef std::tuple<int>                                        tt1;
+typedef std::tuple<int, double>                                tt2;
+typedef std::tuple<short, double, int>                         tt3;
+typedef std::tuple<short, NoexceptMoveAssignClass, double>     tt4;
+typedef std::tuple<NoexceptMoveAssignClass,
+		   NoexceptMoveAssignClass, double>            tt5;
+typedef std::tuple<NoexceptMoveAssignClass,
+		   NoexceptMoveAssignClass,
+		   NoexceptMoveAssignClass>                    tt6;
+typedef std::tuple<ExceptMoveAssignClass>                      tt7;
+typedef std::tuple<ExceptMoveAssignClass, double>              tt8;
+typedef std::tuple<short, double, ExceptMoveAssignClass>       tt9;
+typedef std::tuple<ExceptMoveAssignClass, double,
+		   ExceptMoveAssignClass>                      tt10;
+typedef std::tuple<NoexceptMoveAssignClass,
+		   ExceptMoveAssignClass>                      tt11;
+typedef std::tuple<int,
+		   NoexceptMoveAssignClass,
+		   ExceptMoveAssignClass>                      tt12;
+
+static_assert(std::is_nothrow_move_assignable<tt1>::value, "Error");
+static_assert(std::is_nothrow_move_assignable<tt2>::value, "Error");
+static_assert(std::is_nothrow_move_assignable<tt3>::value, "Error");
+static_assert(std::is_nothrow_move_assignable<tt4>::value, "Error");
+static_assert(std::is_nothrow_move_assignable<tt5>::value, "Error");
+static_assert(std::is_nothrow_move_assignable<tt6>::value, "Error");
+static_assert(!std::is_nothrow_move_assignable<tt7>::value, "Error");
+static_assert(!std::is_nothrow_move_assignable<tt8>::value, "Error");
+static_assert(!std::is_nothrow_move_assignable<tt9>::value, "Error");
+static_assert(!std::is_nothrow_move_assignable<tt10>::value, "Error");
+static_assert(!std::is_nothrow_move_assignable<tt11>::value, "Error");
+static_assert(!std::is_nothrow_move_assignable<tt12>::value, "Error");
Index: testsuite/20_util/weak_ptr/comparison/cmp_neg.cc
===================================================================
--- testsuite/20_util/weak_ptr/comparison/cmp_neg.cc	(revision 173912)
+++ testsuite/20_util/weak_ptr/comparison/cmp_neg.cc	(working copy)
@@ -51,9 +51,9 @@ 
 // { dg-warning "note" "" { target *-*-* } 485 }
 // { dg-warning "note" "" { target *-*-* } 479 }
 // { dg-warning "note" "" { target *-*-* } 469 }
-// { dg-warning "note" "" { target *-*-* } 599 }
+// { dg-warning "note" "" { target *-*-* } 603 }
 // { dg-warning "note" "" { target *-*-* } 1056 }
 // { dg-warning "note" "" { target *-*-* } 1050 }
 // { dg-warning "note" "" { target *-*-* } 342 }
 // { dg-warning "note" "" { target *-*-* } 292 }
-// { dg-warning "note" "" { target *-*-* } 211 }
+// { dg-warning "note" "" { target *-*-* } 212 }