Re: std::forward_list optim for always equal allocator

2018-01-08 Thread Jonathan Wakely

On 23/11/17 22:22 +0100, François Dumont wrote:

Gentle reminder for this patch.

I looked when the constructor got unused and I think it is back in 
June 2015 in git commit:


commit debb6aabb771ed02cb7256a7719555e5fbd7d3f7
Author: redi 
Date:   Wed Jun 17 17:45:45 2015 +

    * include/bits/forward_list.h
    (_Fwd_list_base(const _Node_alloc_type&)): Change parameter to
    rvalue-reference.


Hmm, I should have put that same change on the gcc-5-branch too.

If you fear abi breaking change I can restore it in a 
!_GLIBCXX_INLINE_VERSION section.


I think if there was a problem here my June 2015 change would already
have caused it (when I changed the _Fwd_list_base constructor
signatures).

So let's assume it's OK to remove the constructor.



@@ -533,15 +560,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER

  /**
   *  @brief  The %forward_list move constructor.
-   *  @param  __list  A %forward_list of identical element and allocator
-   *  types.
+   *  @param  A %forward_list of identical element and allocator types.


This change is wrong, you can't just remove the parameter name,
because now Doxygen will document a parameter called "A" (and complain
that there is no such parameter).

It would be better to leave the name __list there and just get the
warning.

Otherwise the patch is OK for trunk (please ensure to update the
Copyright dates in the test files to 2018).

Thanks.




Re: std::forward_list optim for always equal allocator

2017-11-23 Thread François Dumont

Gentle reminder for this patch.

I looked when the constructor got unused and I think it is back in June 
2015 in git commit:


commit debb6aabb771ed02cb7256a7719555e5fbd7d3f7
Author: redi 
Date:   Wed Jun 17 17:45:45 2015 +

    * include/bits/forward_list.h
    (_Fwd_list_base(const _Node_alloc_type&)): Change parameter to
    rvalue-reference.

If you fear abi breaking change I can restore it in a 
!_GLIBCXX_INLINE_VERSION section.


François


On 28/08/2017 21:09, François Dumont wrote:

Hi

    Any news for this patch ?

    It does remove a constructor:
-    _Fwd_list_impl(const _Node_alloc_type& __a)
-    : _Node_alloc_type(__a), _M_head()

 It was already unused before the patch. Do you think it has ever 
been used and so do I need to restore it ?


    I eventually restore the _M_head() in _Fwd_list_impl constructors 
cause IMO it is the inline init of _M_next in _Fwd_list_node_base 
which should be removed. But I remember Jonathan that you didn't want 
to do so because gcc was not good enough in detecting usage of 
uninitialized variables, is it still true ?


François


On 17/07/2017 22:10, François Dumont wrote:

Hi

    Here is the patch to implement the always equal alloc 
optimization for forward_list. With this version there is no abi issue.


    I also prefer to implement the _Fwd_list_node_base move operator 
for consistency with the move constructor and used it where applicable.



    * include/bits/forward_list.h
    (_Fwd_list_node_base& operator=(_Fwd_list_node_base&&)): Implement.
    (_Fwd_list_impl(_Fwd_list_impl&&, _Node_alloc_type&&)): New.
    (_Fwd_list_base(_Fwd_list_base&&, _Node_alloc_type&&, 
std::true_type)):

    New, use latter.
    (forward_list(forward_list&&, _Node_alloc_type&&, std::false_type)):
    New.
    (forward_list(forward_list&&, _Node_alloc_type&&, std::true_type)):
    New.
    (forward_list(forward_list&&, const _Alloc&)): Adapt to use latters.
    * include/bits/forward_list.tcc
    (_Fwd_list_base(_Fwd_list_base&&, _Node_alloc_type&&)): Adapt to use
    _M_impl._M_head move assignment.
    (forward_list<>::merge(forward_list<>&&, _Comp)): Likewise.

Tested under Linux x86_64, ok to commit ?

François





diff --git a/libstdc++-v3/include/bits/forward_list.h b/libstdc++-v3/include/bits/forward_list.h
index 9d86fcc..772e9a0 100644
--- a/libstdc++-v3/include/bits/forward_list.h
+++ b/libstdc++-v3/include/bits/forward_list.h
@@ -54,6 +54,20 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
   struct _Fwd_list_node_base
   {
 _Fwd_list_node_base() = default;
+_Fwd_list_node_base(_Fwd_list_node_base&& __x) noexcept
+  : _M_next(__x._M_next)
+{ __x._M_next = nullptr; }
+
+_Fwd_list_node_base(const _Fwd_list_node_base&) = delete;
+_Fwd_list_node_base& operator=(const _Fwd_list_node_base&) = delete;
+
+_Fwd_list_node_base&
+operator=(_Fwd_list_node_base&& __x) noexcept
+{
+  _M_next = __x._M_next;
+  __x._M_next = nullptr;
+  return *this;
+}
 
 _Fwd_list_node_base* _M_next = nullptr;
 
@@ -68,7 +82,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  __end->_M_next = _M_next;
 	}
   else
-	__begin->_M_next = 0;
+	__begin->_M_next = nullptr;
   _M_next = __keep;
   return __end;
 }
@@ -173,7 +187,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	if (_M_node)
 	  return _Fwd_list_iterator(_M_node->_M_next);
 	else
-  return _Fwd_list_iterator(0);
+	  return _Fwd_list_iterator(nullptr);
   }
 
   _Fwd_list_node_base* _M_node;
@@ -244,7 +258,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	if (this->_M_node)
 	  return _Fwd_list_const_iterator(_M_node->_M_next);
 	else
-  return _Fwd_list_const_iterator(0);
+	  return _Fwd_list_const_iterator(nullptr);
   }
 
   const _Fwd_list_node_base* _M_node;
@@ -285,11 +299,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	_Fwd_list_node_base _M_head;
 
 	_Fwd_list_impl()
+	  noexcept( noexcept(_Node_alloc_type()) )
 	: _Node_alloc_type(), _M_head()
 	{ }
 
-_Fwd_list_impl(const _Node_alloc_type& __a)
-: _Node_alloc_type(__a), _M_head()
+	_Fwd_list_impl(_Fwd_list_impl&&) = default;
+
+	_Fwd_list_impl(_Fwd_list_impl&& __fl, _Node_alloc_type&& __a)
+	: _Node_alloc_type(std::move(__a)), _M_head(std::move(__fl._M_head))
 	{ }
 
 	_Fwd_list_impl(_Node_alloc_type&& __a)
@@ -312,26 +329,26 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
   _M_get_Node_allocator() const noexcept
   { return this->_M_impl; }
 
-  _Fwd_list_base()
-  : _M_impl() { }
+  _Fwd_list_base() = default;
 
   _Fwd_list_base(_Node_alloc_type&& __a)
   : _M_impl(std::move(__a)) { }
 
+  // When allocators are always equal.
+  _Fwd_list_base(_Fwd_list_base&& __lst, _Node_alloc_type&& __a,
+		 std::true_type)
+  : _M_impl(std::move(__lst._M_impl), std::move(__a))
+  { }
+
+  // When allocators are not always equal.
   _Fwd_list_base(_Fwd_list_base&& __lst, 

Re: std::forward_list optim for always equal allocator

2017-09-12 Thread François Dumont

On 12/09/2017 00:10, Jonathan Wakely wrote:

On 11/09/17 22:39 +0200, Daniel Krügler wrote:

2017-09-11 22:36 GMT+02:00 François Dumont :
[..]

So my remark was rather for the:

  _Fwd_list_iterator() noexcept
  : _M_node() { }

that could simply be

_Fwd_list_iterator() = default;

no ?


Yes, that should be fine.


I'm not sure there's much benefit to that change 

Sure, it would be a minor change.

Which is moreover not part of this patch proposal. Is the patch ok to 
commit ?


François


Re: std::forward_list optim for always equal allocator

2017-09-11 Thread Jonathan Wakely

On 11/09/17 22:39 +0200, Daniel Krügler wrote:

2017-09-11 22:36 GMT+02:00 François Dumont :
[..]

So my remark was rather for the:

  _Fwd_list_iterator() noexcept
  : _M_node() { }

that could simply be

_Fwd_list_iterator() = default;

no ?


Yes, that should be fine.


I'm not sure there's much benefit to that change.




Re: std::forward_list optim for always equal allocator

2017-09-11 Thread Daniel Krügler
2017-09-11 22:36 GMT+02:00 François Dumont :
[..]
> So my remark was rather for the:
>
>   _Fwd_list_iterator() noexcept
>   : _M_node() { }
>
> that could simply be
>
> _Fwd_list_iterator() = default;
>
> no ?

Yes, that should be fine.

- Daniel


Re: std::forward_list optim for always equal allocator

2017-09-11 Thread François Dumont

On 11/09/2017 14:11, Jonathan Wakely wrote:

On 11/09/17 07:44 +0200, Daniel Krügler wrote:

2017-09-11 7:12 GMT+02:00 François Dumont :

When user declare a container iterator like that:

std::forward_list::iterator it;

There is no reason to initialize it with a null node pointer. It is 
just an

uninitialized iterator which is invalid to use except to initialize it.


While that is correct, for every forward iterator (and
std::forward_list::iterator meets these requirements), it is also
required that a value-initialized iterator can be compared against
other initialized iterators, so this reduces the amount of freedom to
define a default constructor for such iterators even when used to
default-initialize. This is not meant as a showstopper argument, since
I have not fully understood of what you are planning, but just a
reminder.


Right, which means that
std::forward_list::iterator it = {};

must initialize the node pointer to nullptr. If we remove the
initialization of _Fwd_list_iterator::_M_node from the default
constructor then it would be left uninitialized.

But I'm confused, François was talking about removing the
initialization of _Fwd_list_node_base::_M_next, what has that got to
do with forward_list::iterator? Thee is no node-base in the
iterator.

So I'm still wondering why the initialization of _M_next should be
removed.


Indeed, the iterator contains a _Fwd_list_node_base*.

So my remark was rather for the:

  _Fwd_list_iterator() noexcept
  : _M_node() { }

that could simply be

_Fwd_list_iterator() = default;

no ?

François



Re: std::forward_list optim for always equal allocator

2017-09-11 Thread Jonathan Wakely

On 11/09/17 07:44 +0200, Daniel Krügler wrote:

2017-09-11 7:12 GMT+02:00 François Dumont :

When user declare a container iterator like that:

std::forward_list::iterator it;

There is no reason to initialize it with a null node pointer. It is just an
uninitialized iterator which is invalid to use except to initialize it.


While that is correct, for every forward iterator (and
std::forward_list::iterator meets these requirements), it is also
required that a value-initialized iterator can be compared against
other initialized iterators, so this reduces the amount of freedom to
define a default constructor for such iterators even when used to
default-initialize. This is not meant as a showstopper argument, since
I have not fully understood of what you are planning, but just a
reminder.


Right, which means that 


std::forward_list::iterator it = {};

must initialize the node pointer to nullptr. If we remove the
initialization of _Fwd_list_iterator::_M_node from the default
constructor then it would be left uninitialized.

But I'm confused, François was talking about removing the
initialization of _Fwd_list_node_base::_M_next, what has that got to
do with forward_list::iterator? Thee is no node-base in the
iterator.

So I'm still wondering why the initialization of _M_next should be
removed.




Re: std::forward_list optim for always equal allocator

2017-09-10 Thread Daniel Krügler
2017-09-11 7:12 GMT+02:00 François Dumont :
> When user declare a container iterator like that:
>
> std::forward_list::iterator it;
>
> There is no reason to initialize it with a null node pointer. It is just an
> uninitialized iterator which is invalid to use except to initialize it.

While that is correct, for every forward iterator (and
std::forward_list::iterator meets these requirements), it is also
required that a value-initialized iterator can be compared against
other initialized iterators, so this reduces the amount of freedom to
define a default constructor for such iterators even when used to
default-initialize. This is not meant as a showstopper argument, since
I have not fully understood of what you are planning, but just a
reminder.

- Daniel


Re: std::forward_list optim for always equal allocator

2017-09-10 Thread François Dumont

On 08/09/2017 18:19, Jonathan Wakely wrote:

On 28/08/17 21:09 +0200, François Dumont wrote:

Hi

   Any news for this patch ?

   It does remove a constructor:
-_Fwd_list_impl(const _Node_alloc_type& __a)
-: _Node_alloc_type(__a), _M_head()

It was already unused before the patch. Do you think it has ever 
been used and so do I need to restore it ?


   I eventually restore the _M_head() in _Fwd_list_impl constructors 
cause IMO it is the inline init of _M_next in _Fwd_list_node_base 
which should be removed. But I remember Jonathan that you didn't want 
to do so because gcc was not good enough in detecting usage of 
uninitialized variables, is it still true ?


Why should it be removed?




When user declare a container iterator like that:

std::forward_list::iterator it;

There is no reason to initialize it with a null node pointer. It is just 
an uninitialized iterator which is invalid to use except to initialize it.


I once proposed to do the same simplification for the unordered 
containers _Hash_node_base. But you said that detection of the usage of 
uninitialized variable is not good enough in gcc to leave variables 
uninitialized this way.





Re: std::forward_list optim for always equal allocator

2017-09-08 Thread Jonathan Wakely

On 28/08/17 21:09 +0200, François Dumont wrote:

Hi

   Any news for this patch ?

   It does remove a constructor:
-_Fwd_list_impl(const _Node_alloc_type& __a)
-: _Node_alloc_type(__a), _M_head()

It was already unused before the patch. Do you think it has ever 
been used and so do I need to restore it ?


   I eventually restore the _M_head() in _Fwd_list_impl constructors 
cause IMO it is the inline init of _M_next in _Fwd_list_node_base 
which should be removed. But I remember Jonathan that you didn't want 
to do so because gcc was not good enough in detecting usage of 
uninitialized variables, is it still true ?


Why should it be removed?




Re: std::forward_list optim for always equal allocator

2017-08-28 Thread François Dumont

Hi

Any news for this patch ?

It does remove a constructor:
-_Fwd_list_impl(const _Node_alloc_type& __a)
-: _Node_alloc_type(__a), _M_head()

 It was already unused before the patch. Do you think it has ever 
been used and so do I need to restore it ?


I eventually restore the _M_head() in _Fwd_list_impl constructors 
cause IMO it is the inline init of _M_next in _Fwd_list_node_base which 
should be removed. But I remember Jonathan that you didn't want to do so 
because gcc was not good enough in detecting usage of uninitialized 
variables, is it still true ?


François


On 17/07/2017 22:10, François Dumont wrote:

Hi

Here is the patch to implement the always equal alloc optimization 
for forward_list. With this version there is no abi issue.


I also prefer to implement the _Fwd_list_node_base move operator 
for consistency with the move constructor and used it where applicable.



* include/bits/forward_list.h
(_Fwd_list_node_base& operator=(_Fwd_list_node_base&&)): Implement.
(_Fwd_list_impl(_Fwd_list_impl&&, _Node_alloc_type&&)): New.
(_Fwd_list_base(_Fwd_list_base&&, _Node_alloc_type&&, 
std::true_type)):

New, use latter.
(forward_list(forward_list&&, _Node_alloc_type&&, std::false_type)):
New.
(forward_list(forward_list&&, _Node_alloc_type&&, std::true_type)):
New.
(forward_list(forward_list&&, const _Alloc&)): Adapt to use latters.
* include/bits/forward_list.tcc
(_Fwd_list_base(_Fwd_list_base&&, _Node_alloc_type&&)): Adapt to use
_M_impl._M_head move assignment.
(forward_list<>::merge(forward_list<>&&, _Comp)): Likewise.

Tested under Linux x86_64, ok to commit ?

François



diff --git a/libstdc++-v3/include/bits/forward_list.h b/libstdc++-v3/include/bits/forward_list.h
index 9d86fcc..772e9a0 100644
--- a/libstdc++-v3/include/bits/forward_list.h
+++ b/libstdc++-v3/include/bits/forward_list.h
@@ -54,6 +54,20 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
   struct _Fwd_list_node_base
   {
 _Fwd_list_node_base() = default;
+_Fwd_list_node_base(_Fwd_list_node_base&& __x) noexcept
+  : _M_next(__x._M_next)
+{ __x._M_next = nullptr; }
+
+_Fwd_list_node_base(const _Fwd_list_node_base&) = delete;
+_Fwd_list_node_base& operator=(const _Fwd_list_node_base&) = delete;
+
+_Fwd_list_node_base&
+operator=(_Fwd_list_node_base&& __x) noexcept
+{
+  _M_next = __x._M_next;
+  __x._M_next = nullptr;
+  return *this;
+}
 
 _Fwd_list_node_base* _M_next = nullptr;
 
@@ -68,7 +82,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  __end->_M_next = _M_next;
 	}
   else
-	__begin->_M_next = 0;
+	__begin->_M_next = nullptr;
   _M_next = __keep;
   return __end;
 }
@@ -173,7 +187,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	if (_M_node)
 	  return _Fwd_list_iterator(_M_node->_M_next);
 	else
-  return _Fwd_list_iterator(0);
+	  return _Fwd_list_iterator(nullptr);
   }
 
   _Fwd_list_node_base* _M_node;
@@ -244,7 +258,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	if (this->_M_node)
 	  return _Fwd_list_const_iterator(_M_node->_M_next);
 	else
-  return _Fwd_list_const_iterator(0);
+	  return _Fwd_list_const_iterator(nullptr);
   }
 
   const _Fwd_list_node_base* _M_node;
@@ -285,11 +299,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	_Fwd_list_node_base _M_head;
 
 	_Fwd_list_impl()
+	  noexcept( noexcept(_Node_alloc_type()) )
 	: _Node_alloc_type(), _M_head()
 	{ }
 
-_Fwd_list_impl(const _Node_alloc_type& __a)
-: _Node_alloc_type(__a), _M_head()
+	_Fwd_list_impl(_Fwd_list_impl&&) = default;
+
+	_Fwd_list_impl(_Fwd_list_impl&& __fl, _Node_alloc_type&& __a)
+	: _Node_alloc_type(std::move(__a)), _M_head(std::move(__fl._M_head))
 	{ }
 
 	_Fwd_list_impl(_Node_alloc_type&& __a)
@@ -312,26 +329,26 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
   _M_get_Node_allocator() const noexcept
   { return this->_M_impl; }
 
-  _Fwd_list_base()
-  : _M_impl() { }
+  _Fwd_list_base() = default;
 
   _Fwd_list_base(_Node_alloc_type&& __a)
   : _M_impl(std::move(__a)) { }
 
+  // When allocators are always equal.
+  _Fwd_list_base(_Fwd_list_base&& __lst, _Node_alloc_type&& __a,
+		 std::true_type)
+  : _M_impl(std::move(__lst._M_impl), std::move(__a))
+  { }
+
+  // When allocators are not always equal.
   _Fwd_list_base(_Fwd_list_base&& __lst, _Node_alloc_type&& __a);
 
-  _Fwd_list_base(_Fwd_list_base&& __lst)
-  : _M_impl(std::move(__lst._M_get_Node_allocator()))
-  {
-	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&&) = default;
 
   ~_Fwd_list_base()
-  { _M_erase_after(&_M_impl._M_head, 0); }
+  { _M_erase_after(&_M_impl._M_head, nullptr); }
 
 protected:
-
   _Node*
   _M_get_node()
   {
@@ -437,10 +454,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
   /**

Re: std::forward_list optim for always equal allocator

2017-07-17 Thread Daniel Krügler
2017-07-17 22:10 GMT+02:00 François Dumont :
> Hi
>
> Here is the patch to implement the always equal alloc optimization for
> forward_list. With this version there is no abi issue.
>
> I also prefer to implement the _Fwd_list_node_base move operator for
> consistency with the move constructor and used it where applicable.
>
>
> * include/bits/forward_list.h
> (_Fwd_list_node_base& operator=(_Fwd_list_node_base&&)): Implement.
> (_Fwd_list_impl(_Fwd_list_impl&&, _Node_alloc_type&&)): New.
> (_Fwd_list_base(_Fwd_list_base&&, _Node_alloc_type&&, std::true_type)):
> New, use latter.
> (forward_list(forward_list&&, _Node_alloc_type&&, std::false_type)):
> New.
> (forward_list(forward_list&&, _Node_alloc_type&&, std::true_type)):
> New.
> (forward_list(forward_list&&, const _Alloc&)): Adapt to use latters.
> * include/bits/forward_list.tcc
> (_Fwd_list_base(_Fwd_list_base&&, _Node_alloc_type&&)): Adapt to use
> _M_impl._M_head move assignment.
> (forward_list<>::merge(forward_list<>&&, _Comp)): Likewise.
>
> Tested under Linux x86_64, ok to commit ?

Out of curiosity: Shouldn't

_Fwd_list_node_base&
operator=(_Fwd_list_node_base&& __x);

be declared noexcept?

Thanks,

- Daniel


std::forward_list optim for always equal allocator

2017-07-17 Thread François Dumont

Hi

Here is the patch to implement the always equal alloc optimization 
for forward_list. With this version there is no abi issue.


I also prefer to implement the _Fwd_list_node_base move operator 
for consistency with the move constructor and used it where applicable.



* include/bits/forward_list.h
(_Fwd_list_node_base& operator=(_Fwd_list_node_base&&)): Implement.
(_Fwd_list_impl(_Fwd_list_impl&&, _Node_alloc_type&&)): New.
(_Fwd_list_base(_Fwd_list_base&&, _Node_alloc_type&&, std::true_type)):
New, use latter.
(forward_list(forward_list&&, _Node_alloc_type&&, std::false_type)):
New.
(forward_list(forward_list&&, _Node_alloc_type&&, std::true_type)):
New.
(forward_list(forward_list&&, const _Alloc&)): Adapt to use latters.
* include/bits/forward_list.tcc
(_Fwd_list_base(_Fwd_list_base&&, _Node_alloc_type&&)): Adapt to use
_M_impl._M_head move assignment.
(forward_list<>::merge(forward_list<>&&, _Comp)): Likewise.

Tested under Linux x86_64, ok to commit ?

François

diff --git a/libstdc++-v3/include/bits/forward_list.h b/libstdc++-v3/include/bits/forward_list.h
index 9ddbcb2..dec91ea 100644
--- a/libstdc++-v3/include/bits/forward_list.h
+++ b/libstdc++-v3/include/bits/forward_list.h
@@ -60,7 +60,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 
 _Fwd_list_node_base(const _Fwd_list_node_base&) = delete;
 _Fwd_list_node_base& operator=(const _Fwd_list_node_base&) = delete;
-_Fwd_list_node_base& operator=(_Fwd_list_node_base&&) = delete;
+
+_Fwd_list_node_base&
+operator=(_Fwd_list_node_base&& __x)
+{
+  _M_next = __x._M_next;
+  __x._M_next = nullptr;
+  return *this;
+}
 
 _Fwd_list_node_base* _M_next = nullptr;
 
@@ -75,7 +82,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  __end->_M_next = _M_next;
 	}
   else
-	__begin->_M_next = 0;
+	__begin->_M_next = nullptr;
   _M_next = __keep;
   return __end;
 }
@@ -180,7 +187,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	if (_M_node)
 	  return _Fwd_list_iterator(_M_node->_M_next);
 	else
-	  return _Fwd_list_iterator(0);
+	  return _Fwd_list_iterator(nullptr);
   }
 
   _Fwd_list_node_base* _M_node;
@@ -251,7 +258,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	if (this->_M_node)
 	  return _Fwd_list_const_iterator(_M_node->_M_next);
 	else
-	  return _Fwd_list_const_iterator(0);
+	  return _Fwd_list_const_iterator(nullptr);
   }
 
   const _Fwd_list_node_base* _M_node;
@@ -298,6 +305,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 
 	_Fwd_list_impl(_Fwd_list_impl&&) = default;
 
+	_Fwd_list_impl(_Fwd_list_impl&& __fl, _Node_alloc_type&& __a)
+	: _Node_alloc_type(std::move(__a)), _M_head(std::move(__fl._M_head))
+	{ }
+
 	_Fwd_list_impl(_Node_alloc_type&& __a)
 	: _Node_alloc_type(std::move(__a))
 	{ }
@@ -323,15 +334,21 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
   _Fwd_list_base(_Node_alloc_type&& __a)
   : _M_impl(std::move(__a)) { }
 
+  // When allocators are always equal.
+  _Fwd_list_base(_Fwd_list_base&& __lst, _Node_alloc_type&& __a,
+		 std::true_type)
+  : _M_impl(std::move(__lst._M_impl), std::move(__a))
+  { }
+
+  // When allocators are not always equal.
   _Fwd_list_base(_Fwd_list_base&& __lst, _Node_alloc_type&& __a);
 
   _Fwd_list_base(_Fwd_list_base&&) = default;
 
   ~_Fwd_list_base()
-  { _M_erase_after(&_M_impl._M_head, 0); }
+  { _M_erase_after(&_M_impl._M_head, nullptr); }
 
 protected:
-
   _Node*
   _M_get_node()
   {
@@ -448,7 +465,6 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
   : _Base(_Node_alloc_type(__al))
   { }
 
-
   /**
*  @brief  Copy constructor with allocator argument.
*  @param  __list  Input list to copy.
@@ -458,14 +474,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
   : _Base(_Node_alloc_type(__al))
   { _M_range_initialize(__list.begin(), __list.end()); }
 
-  /**
-   *  @brief  Move constructor with allocator argument.
-   *  @param  __list  Input list to move.
-   *  @param  __alAn allocator object.
-   */
-  forward_list(forward_list&& __list, const _Alloc& __al)
-  noexcept(_Node_alloc_traits::_S_always_equal())
-  : _Base(std::move(__list), _Node_alloc_type(__al))
+private:
+  forward_list(forward_list&& __list, _Node_alloc_type&& __al,
+		   std::false_type)
+  : _Base(std::move(__list), std::move(__al))
   {
 	// If __list is not empty it means its allocator is not equal to __a,
 	// so we need to move from each element individually.
@@ -474,6 +486,24 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 		 std::__make_move_if_noexcept_iterator(__list.end()));
   }
 
+  forward_list(forward_list&& __list, _Node_alloc_type&& __al,
+		   std::true_type)
+  noexcept
+  : _Base(std::move(__list), _Node_alloc_type(__al), std::true_type{})
+  { }
+
+public:
+  /**
+   *  @brief  Move constructor with allocator argument.
+   *  @param