This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Re: [libstdc++ PATCH] Implement __is_nothrow_swappable and use it
- From: Jonathan Wakely <jwakely at redhat dot com>
- To: Ville Voutilainen <ville dot voutilainen at gmail dot com>
- Cc: "gcc-patches at gcc dot gnu dot org" <gcc-patches at gcc dot gnu dot org>, libstdc++ at gcc dot gnu dot org
- Date: Fri, 5 Jun 2015 15:44:48 +0100
- Subject: Re: [libstdc++ PATCH] Implement __is_nothrow_swappable and use it
- Authentication-results: sourceware.org; auth=none
- References: <CAFk2RUbHSNQjhhR5YKnVnNcBX3mYFZouXDnrzmnuFgAe+unw4A at mail dot gmail dot com>
On 01/05/15 12:47 +0300, Ville Voutilainen wrote:
This patch partially solves the problem described in N4426, which is
basically LWG
issue 2456, which in turn is caused by CWG DR 1330. Some remarks:
- the __is_swappable and __is_nothrow_swappable are at this time not
meant to be general traits, they make the shortcut of automatically transforming
their template parameter into a reference, which the truly general trait
as described in N4426 wouldn't do.
- swap is now constrained..
- ..which means that everything from bits/move.h moves to type_traits since
swap now needs type_traits. type_traits becomes ok to include in pre-c++14
modes, but only enables the parts that work in pre-c++14 modes.
- this patch does _not_ yet implement N4426.
I've committed this slightly altered patch, which doesn't move swap
into <type_traits> but just declares it there. The definition remains
in <bits/move.h> and including <type_traits> in c++98 mode is still
an error.
Tested powerpc64le-linux, committed to trunk.
commit d485df2eebd2869b3a17a3d67b2a394dbbbedab9
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Fri Jun 5 13:20:53 2015 +0100
2015-06-04 Ville Voutilainen <ville.voutilainen@gmail.com>
Add __is_nothrow_swappable and take it into use.
* include/bits/algorithmfwd.h (swap): Only declare for C++98 mode.
* include/bits/move.h (swap): Add constraints in C++11 and later.
* include/bits/stl_pair.h (swap): Use __is_nothrow_swappable
for the free swap function for pair.
* include/bits/stl_queue.h (swap): Use __is_nothrow_swappable
for the free swap functions for queue and priority_queue.
* include/bits/stl_stack.h (swap): Use __is_nothrow_swappable
for the free swap function for stack.
* include/debug/array (swap): Use __is_nothrow_swappable
for the free swap function for array.
* include/profile/array (swap): Likewise.
* include/std/array (swap): Likewise.
* include/std/tuple (_Tuple_impl::_M_swap): Use __is_nothrow_swappable.
* include/std/type_traits (__is_swappable_impl::__is_swappable,
__is_nothrow_swappable_impl, __is_nothrow_swappable): New.
* testsuite/20_util/is_nothrow_swappable/requirements/
explicit_instantiation.cc: New.
* testsuite/20_util/is_nothrow_swappable/requirements/typedefs.cc:
New.
* testsuite/20_util/is_nothrow_swappable/value.cc: New.
diff --git a/libstdc++-v3/include/bits/algorithmfwd.h b/libstdc++-v3/include/bits/algorithmfwd.h
index 1dfc4ad..c972f33 100644
--- a/libstdc++-v3/include/bits/algorithmfwd.h
+++ b/libstdc++-v3/include/bits/algorithmfwd.h
@@ -566,22 +566,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_BIter
stable_partition(_BIter, _BIter, _Predicate);
- template<typename _Tp>
- void
- swap(_Tp&, _Tp&)
-#if __cplusplus >= 201103L
- noexcept(__and_<is_nothrow_move_constructible<_Tp>,
- is_nothrow_move_assignable<_Tp>>::value)
-#endif
- ;
+#if __cplusplus < 201103L
+ // For C++11 swap() is declared in <type_traits>.
template<typename _Tp, size_t _Nm>
- void
- swap(_Tp (&__a)[_Nm], _Tp (&__b)[_Nm])
-#if __cplusplus >= 201103L
- noexcept(noexcept(swap(*__a, *__b)))
+ inline void
+ swap(_Tp& __a, _Tp& __b);
+
+ template<typename _Tp, size_t _Nm>
+ inline void
+ swap(_Tp (&__a)[_Nm], _Tp (&__b)[_Nm]);
#endif
- ;
template<typename _FIter1, typename _FIter2>
_FIter2
diff --git a/libstdc++-v3/include/bits/move.h b/libstdc++-v3/include/bits/move.h
index 1dfd667..88c4f7b 100644
--- a/libstdc++-v3/include/bits/move.h
+++ b/libstdc++-v3/include/bits/move.h
@@ -172,11 +172,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
* @return Nothing.
*/
template<typename _Tp>
- inline void
- swap(_Tp& __a, _Tp& __b)
+ inline
#if __cplusplus >= 201103L
+ typename enable_if<__and_<is_move_constructible<_Tp>,
+ is_move_assignable<_Tp>>::value>::type
+ swap(_Tp& __a, _Tp& __b)
noexcept(__and_<is_nothrow_move_constructible<_Tp>,
is_nothrow_move_assignable<_Tp>>::value)
+#else
+ void
+ swap(_Tp& __a, _Tp& __b)
#endif
{
// concept requirements
@@ -191,10 +196,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// DR 809. std::swap should be overloaded for array types.
/// Swap the contents of two arrays.
template<typename _Tp, size_t _Nm>
- inline void
- swap(_Tp (&__a)[_Nm], _Tp (&__b)[_Nm])
+ inline
#if __cplusplus >= 201103L
+ typename enable_if<__is_swappable_impl::__is_swappable<_Tp>::value>::type
+ swap(_Tp (&__a)[_Nm], _Tp (&__b)[_Nm])
noexcept(noexcept(swap(*__a, *__b)))
+#else
+ void
+ swap(_Tp (&__a)[_Nm], _Tp (&__b)[_Nm])
#endif
{
for (size_t __n = 0; __n < _Nm; ++__n)
diff --git a/libstdc++-v3/include/bits/stl_pair.h b/libstdc++-v3/include/bits/stl_pair.h
index 3daeb60..490b005 100644
--- a/libstdc++-v3/include/bits/stl_pair.h
+++ b/libstdc++-v3/include/bits/stl_pair.h
@@ -192,8 +192,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
void
swap(pair& __p)
- noexcept(noexcept(swap(first, __p.first))
- && noexcept(swap(second, __p.second)))
+ noexcept(__is_nothrow_swappable<_T1>::value
+ && __is_nothrow_swappable<_T2>::value)
{
using std::swap;
swap(first, __p.first);
diff --git a/libstdc++-v3/include/bits/stl_queue.h b/libstdc++-v3/include/bits/stl_queue.h
index 48e1ee7..5f8e6fb 100644
--- a/libstdc++-v3/include/bits/stl_queue.h
+++ b/libstdc++-v3/include/bits/stl_queue.h
@@ -247,7 +247,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#if __cplusplus >= 201103L
void
swap(queue& __q)
- noexcept(noexcept(swap(c, __q.c)))
+ noexcept(__is_nothrow_swappable<_Tp>::value)
{
using std::swap;
swap(c, __q.c);
@@ -541,7 +541,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#if __cplusplus >= 201103L
void
swap(priority_queue& __pq)
- noexcept(noexcept(swap(c, __pq.c)) && noexcept(swap(comp, __pq.comp)))
+ noexcept(__is_nothrow_swappable<_Tp>::value
+ && __is_nothrow_swappable<_Compare>::value)
{
using std::swap;
swap(c, __pq.c);
diff --git a/libstdc++-v3/include/bits/stl_stack.h b/libstdc++-v3/include/bits/stl_stack.h
index 3ff307f..0ed212e 100644
--- a/libstdc++-v3/include/bits/stl_stack.h
+++ b/libstdc++-v3/include/bits/stl_stack.h
@@ -221,7 +221,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#if __cplusplus >= 201103L
void
swap(stack& __s)
- noexcept(noexcept(swap(c, __s.c)))
+ noexcept(__is_nothrow_swappable<_Tp>::value)
{
using std::swap;
swap(c, __s.c);
diff --git a/libstdc++-v3/include/debug/array b/libstdc++-v3/include/debug/array
index 7bb74c1..34e6281 100644
--- a/libstdc++-v3/include/debug/array
+++ b/libstdc++-v3/include/debug/array
@@ -84,7 +84,7 @@ namespace __debug
void
swap(array& __other)
- noexcept(noexcept(swap(std::declval<_Tp&>(), std::declval<_Tp&>())))
+ noexcept(__is_nothrow_swappable<_Tp>::value)
{ std::swap_ranges(begin(), end(), __other.begin()); }
// Iterators.
diff --git a/libstdc++-v3/include/profile/array b/libstdc++-v3/include/profile/array
index 5198bb3..434ca96 100644
--- a/libstdc++-v3/include/profile/array
+++ b/libstdc++-v3/include/profile/array
@@ -63,7 +63,7 @@ namespace __profile
void
swap(array& __other)
- noexcept(noexcept(swap(std::declval<_Tp&>(), std::declval<_Tp&>())))
+ noexcept(__is_nothrow_swappable<_Tp>::value)
{ std::swap_ranges(begin(), end(), __other.begin()); }
// Iterators.
diff --git a/libstdc++-v3/include/std/array b/libstdc++-v3/include/std/array
index 24be44f..40fbd46 100644
--- a/libstdc++-v3/include/std/array
+++ b/libstdc++-v3/include/std/array
@@ -113,7 +113,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
void
swap(array& __other)
- noexcept(noexcept(swap(std::declval<_Tp&>(), std::declval<_Tp&>())))
+ noexcept(__is_nothrow_swappable<_Tp>::value)
{ std::swap_ranges(begin(), end(), __other.begin()); }
// Iterators.
diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple
index ad132bd..ccea02b 100644
--- a/libstdc++-v3/include/std/tuple
+++ b/libstdc++-v3/include/std/tuple
@@ -324,9 +324,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
protected:
void
_M_swap(_Tuple_impl& __in)
- noexcept(noexcept(swap(std::declval<_Head&>(),
- std::declval<_Head&>()))
- && noexcept(_M_tail(__in)._M_swap(_M_tail(__in))))
+ noexcept(__is_nothrow_swappable<_Head>::value
+ && noexcept(_M_tail(__in)._M_swap(_M_tail(__in))))
{
using std::swap;
swap(_M_head(*this), _M_head(__in));
@@ -451,7 +450,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
protected:
void
_M_swap(_Tuple_impl& __in)
- noexcept(noexcept(swap(std::declval<_Head&>(), std::declval<_Head&>())))
+ noexcept(__is_nothrow_swappable<_Head>::value)
{
using std::swap;
swap(_M_head(*this), _M_head(__in));
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index b8ec61f..2eae61b 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -2427,6 +2427,52 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: true_type \
{ };
+
+ namespace __is_swappable_impl {
+ template <typename _Tp, typename=void>
+ struct __is_swappable : public false_type
+ { };
+ }
+
+ template<typename _Tp>
+ inline
+ typename enable_if<__and_<is_move_constructible<_Tp>,
+ is_move_assignable<_Tp>>::value>::type
+ swap(_Tp&, _Tp&)
+ noexcept(__and_<is_nothrow_move_constructible<_Tp>,
+ is_nothrow_move_assignable<_Tp>>::value);
+
+ template<typename _Tp, size_t _Nm>
+ inline
+ typename enable_if<__is_swappable_impl::__is_swappable<_Tp>::value>::type
+ swap(_Tp (&__a)[_Nm], _Tp (&__b)[_Nm])
+ noexcept(noexcept(swap(*__a, *__b)));
+
+ namespace __is_swappable_impl {
+ using std::swap;
+
+ template <typename _Tp>
+ struct __is_swappable<_Tp, __void_t<decltype(swap(declval<_Tp&>(),
+ declval<_Tp&>()))>>
+ : public true_type
+ { };
+ }
+
+ template <bool, typename _Tp>
+ struct __is_nothrow_swappable_impl
+ : public __bool_constant<noexcept(swap(declval<_Tp&>(), declval<_Tp&>()))>
+ { };
+
+ template <typename _Tp>
+ struct __is_nothrow_swappable_impl<false, _Tp> : public false_type
+ { };
+
+ template <typename _Tp>
+ struct __is_nothrow_swappable
+ : public __is_nothrow_swappable_impl<
+ __is_swappable_impl::__is_swappable<_Tp>::value, _Tp>
+ { };
+
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
diff --git a/libstdc++-v3/testsuite/20_util/is_nothrow_swappable/requirements/explicit_instantiation.cc b/libstdc++-v3/testsuite/20_util/is_nothrow_swappable/requirements/explicit_instantiation.cc
new file mode 100644
index 0000000..93fa94b
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_nothrow_swappable/requirements/explicit_instantiation.cc
@@ -0,0 +1,27 @@
+// { dg-options "-std=gnu++11" }
+// { dg-do compile }
+
+// Copyright (C) 2015 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 <type_traits>
+
+namespace std
+{
+ typedef short test_type;
+ template struct std::__is_nothrow_swappable<test_type>;
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_nothrow_swappable/requirements/typedefs.cc b/libstdc++-v3/testsuite/20_util/is_nothrow_swappable/requirements/typedefs.cc
new file mode 100644
index 0000000..2372349
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_nothrow_swappable/requirements/typedefs.cc
@@ -0,0 +1,32 @@
+// { dg-options "-std=gnu++11" }
+// { dg-do compile }
+
+// Copyright (C) 2015 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 <type_traits>
+
+
+void test01()
+{
+ // Check for required typedefs
+ typedef std::__is_nothrow_swappable<int> test_type;
+ typedef test_type::value_type value_type;
+ typedef test_type::type type;
+ typedef test_type::type::value_type type_value_type;
+ typedef test_type::type::type type_type;
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_nothrow_swappable/value.cc b/libstdc++-v3/testsuite/20_util/is_nothrow_swappable/value.cc
new file mode 100644
index 0000000..bc778b5
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_nothrow_swappable/value.cc
@@ -0,0 +1,72 @@
+// { dg-options "-std=gnu++11" }
+// { dg-do compile }
+
+// Copyright (C) 2015 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 <type_traits>
+#include <testsuite_tr1.h>
+#include <utility>
+#include <array>
+#include <tuple>
+#include <queue>
+#include <stack>
+
+namespace funny {
+ struct F {};
+ void swap(F&, F&) = delete;
+}
+void test01()
+{
+ using std::__is_nothrow_swappable;
+ using std::__is_swappable_impl::__is_swappable;
+ using namespace __gnu_test;
+ // Positive tests.
+ static_assert(test_property<__is_swappable, int>(true), "");
+ static_assert(test_property<__is_nothrow_swappable, int>(true), "");
+ static_assert(test_property<__is_nothrow_swappable, int[1]>(true), "");
+ static_assert(test_property<__is_nothrow_swappable,
+ std::pair<int, int>>(true), "");
+ static_assert(test_property<__is_nothrow_swappable,
+ std::tuple<int>>(true), "");
+ static_assert(test_property<__is_nothrow_swappable,
+ std::array<int, 1>>(true), "");
+ static_assert(test_property<__is_nothrow_swappable,
+ std::queue<int>>(true), "");
+ static_assert(test_property<__is_nothrow_swappable,
+ std::priority_queue<int>>(true), "");
+ static_assert(test_property<__is_nothrow_swappable,
+ std::stack<int>>(true), "");
+ // Negative tests.
+ static_assert(test_property<__is_swappable, construct::DelCopy>(false), "");
+ static_assert(test_property<__is_swappable, funny::F>(false), "");
+ static_assert(test_property<__is_swappable, funny::F[1]>(false), "");
+ static_assert(test_property<__is_nothrow_swappable,
+ ThrowCopyConsClass>(false), "");
+ static_assert(test_property<__is_nothrow_swappable,
+ std::pair<ThrowCopyConsClass, ThrowCopyConsClass>>(false), "");
+ static_assert(test_property<__is_nothrow_swappable,
+ std::tuple<ThrowCopyConsClass>>(false), "");
+ static_assert(test_property<__is_nothrow_swappable,
+ std::array<ThrowCopyConsClass, 1>>(false), "");
+ static_assert(test_property<__is_nothrow_swappable,
+ std::queue<ThrowCopyConsClass>>(false), "");
+ static_assert(test_property<__is_nothrow_swappable,
+ std::priority_queue<ThrowCopyConsClass>>(false), "");
+ static_assert(test_property<__is_nothrow_swappable,
+ std::stack<ThrowCopyConsClass>>(false), "");
+}