Re: [PATCH] PR libstdc++/86963 Implement LWG 2729 constraints on tuple assignment

2018-08-20 Thread Jonathan Wakely

On 17/08/18 19:54 +0100, Jonathan Wakely wrote:

On 17/08/18 19:01 +0100, Jonathan Wakely wrote:

On 17/08/18 18:52 +0100, Jonathan Wakely wrote:

+  // The tag parameter ensures that in nested tuples each __tuple_base
+  // is a different type and can use the empty base-class optimisation.
+  template
+class __tuple_base


Specifically, this would fail if __tuple_base was not a class
template:

static_assert(sizeof(tuple>) == sizeof(int), "");

And also:

struct empty {};
static_assert(sizeof(tuple, tuple>) == 2, "");



In fact, it's just occurred to me that we don't really need the
__tuple_base class template at all. We can make _Tuple_impl
non-assignable (adding _M_assign members for the required
functionality). Then we don't need an extra base class.


Which is what this patch does. I think it's cleaner than needing the
__tuple_base base class.

Tested x86_64-linux and committed to trunk.

commit 1af2f8e775e0f742b530912a3e988316f2c74375
Author: Jonathan Wakely 
Date:   Fri Aug 17 20:37:29 2018 +0100

PR libstdc++/86963 Remove use of __tuple_base in std::tuple

The _Tuple_impl base class can be used to disable copy/move assignment,
without requiring an extra base class.

Exception specifications on std::tuple assignment and swap functions can
be defined directly using is_nothrow_swappable, instead of querying the
base classes.

PR libstdc++/86963
* include/std/tuple (_Tuple_impl::operator=): Define as deleted.
(_Tuple_impl::_M_assign): New functions to perform assignment instead
of assignment operators.
(_Tuple_impl::_M_swap): Remove exception specification.
(_Tuple_impl<_Idx, _Head>): Likewise.
(_TC::_NonNestedTuple, _TC::_NotSameTuple): Use __remove_cvref_t.
(__tuple_base): Remove.
(tuple, tuple<_T1, _T2>): Remove inheritance from __tuple_base.
(tuple::operator=, tuple<_T1, _T2>::operator=): Call _M_assign.
(tuple::swap, tuple<_T1, _T2>::swap): Define exception specification
using __is_nothrow_swappable.
(tuple<_T1, _T2>::tuple(_U1&&, _U2&&)): Use __remove_cvref_t.

diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple
index 955b853066f..56b97c25eed 100644
--- a/libstdc++-v3/include/std/tuple
+++ b/libstdc++-v3/include/std/tuple
@@ -219,6 +219,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   constexpr _Tuple_impl(const _Tuple_impl&) = default;
 
+  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+  // 2729. Missing SFINAE on std::pair::operator=
+  _Tuple_impl& operator=(const _Tuple_impl&) = delete;
+
   constexpr
   _Tuple_impl(_Tuple_impl&& __in)
   noexcept(__and_,
@@ -288,49 +292,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 std::forward<_UHead>
 		(_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in))) { }
 
-  _Tuple_impl&
-  operator=(const _Tuple_impl& __in)
-  {
-	_M_head(*this) = _M_head(__in);
-	_M_tail(*this) = _M_tail(__in);
-	return *this;
-  }
-
-  _Tuple_impl&
-  operator=(_Tuple_impl&& __in)
-  noexcept(__and_,
-	  is_nothrow_move_assignable<_Inherited>>::value)
-  {
-	_M_head(*this) = std::forward<_Head>(_M_head(__in));
-	_M_tail(*this) = std::move(_M_tail(__in));
-	return *this;
-  }
-
   template
-_Tuple_impl&
-operator=(const _Tuple_impl<_Idx, _UElements...>& __in)
+void
+_M_assign(const _Tuple_impl<_Idx, _UElements...>& __in)
 {
 	  _M_head(*this) = _Tuple_impl<_Idx, _UElements...>::_M_head(__in);
-	  _M_tail(*this) = _Tuple_impl<_Idx, _UElements...>::_M_tail(__in);
-	  return *this;
+	  _M_tail(*this)._M_assign(
+	  _Tuple_impl<_Idx, _UElements...>::_M_tail(__in));
 	}
 
   template
-_Tuple_impl&
-operator=(_Tuple_impl<_Idx, _UHead, _UTails...>&& __in)
+void
+_M_assign(_Tuple_impl<_Idx, _UHead, _UTails...>&& __in)
 {
 	  _M_head(*this) = std::forward<_UHead>
 	(_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in));
-	  _M_tail(*this) = std::move
-	(_Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in));
-	  return *this;
+	  _M_tail(*this)._M_assign(
+	  std::move(_Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in)));
 	}
 
 protected:
   void
   _M_swap(_Tuple_impl& __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));
@@ -367,6 +350,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   constexpr _Tuple_impl(const _Tuple_impl&) = default;
 
+  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+  // 2729. Missing SFINAE on std::pair::operator=
+  _Tuple_impl& operator=(const _Tuple_impl&) = delete;
+
   constexpr
   _Tuple_impl(_Tuple_impl&& __in)
   noexcept(is_nothrow_move_constructible<_Head>::value)
@@ -420,42 +407,24 @@ 

Re: [PATCH] PR libstdc++/86963 Implement LWG 2729 constraints on tuple assignment

2018-08-17 Thread Jonathan Wakely

On 17/08/18 19:01 +0100, Jonathan Wakely wrote:

On 17/08/18 18:52 +0100, Jonathan Wakely wrote:

+  // The tag parameter ensures that in nested tuples each __tuple_base
+  // is a different type and can use the empty base-class optimisation.
+  template
+class __tuple_base


Specifically, this would fail if __tuple_base was not a class
template:

static_assert(sizeof(tuple>) == sizeof(int), "");

And also:

struct empty {};
static_assert(sizeof(tuple, tuple>) == 2, "");



In fact, it's just occurred to me that we don't really need the
__tuple_base class template at all. We can make _Tuple_impl
non-assignable (adding _M_assign members for the required
functionality). Then we don't need an extra base class.




Re: [PATCH] PR libstdc++/86963 Implement LWG 2729 constraints on tuple assignment

2018-08-17 Thread Jonathan Wakely

On 17/08/18 18:52 +0100, Jonathan Wakely wrote:

+  // The tag parameter ensures that in nested tuples each __tuple_base
+  // is a different type and can use the empty base-class optimisation.
+  template
+class __tuple_base


Specifically, this would fail if __tuple_base was not a class
template:

static_assert(sizeof(tuple>) == sizeof(int), "");

And also:

struct empty {};
static_assert(sizeof(tuple, tuple>) == 2, "");



[PATCH] PR libstdc++/86963 Implement LWG 2729 constraints on tuple assignment

2018-08-17 Thread Jonathan Wakely

PR libstdc++/86963
* include/std/tuple (__tuple_base): New class template with deleted
copy assignment operator.
(tuple, tuple<_T1, _T2>): Derive from __tuple_base so that
implicit copy/move assignment operator will be deleted/suppressed.
(tuple::__assignable, tuple<_T1, _T2>::__assignable): New helper
functions for SFINAE constraints on assignment operators.
(tuple::__nothrow_assignable, tuple<_T1, _T2>::__nothrow_assignable):
New helper functions for exception specifications.
(tuple::operator=(const tuple&), tuple::operator=(tuple&&))
(tuple<_T1, _T2>::operator=(const tuple&))
(tuple<_T1, _T2>::operator=(tuple&&)): Change parameter types to
__nonesuch_no_braces when the operator should be defined implicitly.
Use __nothrow_assignable for exception specifications.
(tuple::operator=(const tuple<_UElements...>&))
(tuple::operator=(tuple<_UElements...>&&))
(tuple<_T1, _T2>::operator=(const tuple<_U1, _U2>&))
(tuple<_T1, _T2>::operator=(tuple<_U1, _U2>&&))
(tuple<_T1, _T2>::operator=(const pair<_U1, _U2>&))
(tuple<_T1, _T2>::operator=(pair<_U1, _U2>&&)): Constrain using
__assignable and use __nothrow_assignable for exception
specifications.
* python/libstdcxx/v6/printers.py (is_specialization_of): Accept
gdb.Type as first argument, instead of a string.
(StdTuplePrinter._iterator._is_nonempty_tuple): New method to check
tuple for expected structure.
(StdTuplePrinter._iterator.__init__): Use _is_nonempty_tuple.
* testsuite/20_util/tuple/dr2729.cc: New test.
* testsuite/20_util/tuple/element_access/get_neg.cc: Change dg-error
to dg-prune-output.

Tested x86_64-linux, committed to trunk.


commit 6f8a632c16f417ac0e0db1b2a02a27708702279d
Author: Jonathan Wakely 
Date:   Fri Aug 17 16:12:21 2018 +0100

PR libstdc++/86963 Implement LWG 2729 constraints on tuple assignment

PR libstdc++/86963
* include/std/tuple (__tuple_base): New class template with deleted
copy assignment operator.
(tuple, tuple<_T1, _T2>): Derive from __tuple_base so that
implicit copy/move assignment operator will be deleted/suppressed.
(tuple::__assignable, tuple<_T1, _T2>::__assignable): New helper
functions for SFINAE constraints on assignment operators.
(tuple::__nothrow_assignable, tuple<_T1, 
_T2>::__nothrow_assignable):
New helper functions for exception specifications.
(tuple::operator=(const tuple&), tuple::operator=(tuple&&))
(tuple<_T1, _T2>::operator=(const tuple&))
(tuple<_T1, _T2>::operator=(tuple&&)): Change parameter types to
__nonesuch_no_braces when the operator should be defined implicitly.
Use __nothrow_assignable for exception specifications.
(tuple::operator=(const tuple<_UElements...>&))
(tuple::operator=(tuple<_UElements...>&&))
(tuple<_T1, _T2>::operator=(const tuple<_U1, _U2>&))
(tuple<_T1, _T2>::operator=(tuple<_U1, _U2>&&))
(tuple<_T1, _T2>::operator=(const pair<_U1, _U2>&))
(tuple<_T1, _T2>::operator=(pair<_U1, _U2>&&)): Constrain using
__assignable and use __nothrow_assignable for exception
specifications.
* python/libstdcxx/v6/printers.py (is_specialization_of): Accept
gdb.Type as first argument, instead of a string.
(StdTuplePrinter._iterator._is_nonempty_tuple): New method to check
tuple for expected structure.
(StdTuplePrinter._iterator.__init__): Use _is_nonempty_tuple.
* testsuite/20_util/tuple/dr2729.cc: New test.
* testsuite/20_util/tuple/element_access/get_neg.cc: Change dg-error
to dg-prune-output.

diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple
index dd7daf7f1cf..955b853066f 100644
--- a/libstdc++-v3/include/std/tuple
+++ b/libstdc++-v3/include/std/tuple
@@ -551,9 +551,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 }
   };
 
+  // The tag parameter ensures that in nested tuples each __tuple_base
+  // is a different type and can use the empty base-class optimisation.
+  template
+class __tuple_base
+{
+  template friend struct tuple;
+  __tuple_base() = default;
+  ~__tuple_base() = default;
+  __tuple_base(const __tuple_base&) = default;
+  __tuple_base& operator=(const __tuple_base&) = delete;
+};
+
   /// Primary class template, tuple
   template
-class tuple : public _Tuple_impl<0, _Elements...>
+class tuple
+: public _Tuple_impl<0, _Elements...>,
+  private __tuple_base>
 {
   typedef _Tuple_impl<0, _Elements...> _Inherited;
 
@@ -573,6 +587,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 }
   };
 
+  template
+