public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
* std::vector default default and move constructors
@ 2017-07-23 17:41 François Dumont
  2017-07-28 16:46 ` François Dumont
  0 siblings, 1 reply; 16+ messages in thread
From: François Dumont @ 2017-07-23 17:41 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 709 bytes --]

Hi

     Is it time now to consider this patch ?

     * include/bits/stl_vector.h
     (_Vector_impl_data): New.
     (_Vector_impl): Inherit from latter.
     (_Vertor_impl(_Vector_impl&&, _Tp_alloc_type&&)): New.
     (_Vector_base(_Vector_base&&, const allocator_type&)): Use latter.
     (_Vector_base()): Default.
     (_Vector_base(size_t)): Delete.
     (_Vector_base(_Tp_alloc_type&&)): Delete.
     (_Vector_base(_Vector_base&&)): Default.
     (vector()): Default.
     (vector(vector&&, const allocator_type&, true_type)): New.
     (vector(vector&&, const allocator_type&, false_type)): New.
     (vector(vector&&, const allocator_type&)): Use latters.

Tested under linux x86_64.

François



[-- Attachment #2: vector.patch --]
[-- Type: text/x-patch, Size: 9811 bytes --]

diff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h
index 69cb803..d1abaf4 100644
--- a/libstdc++-v3/include/bits/stl_vector.h
+++ b/libstdc++-v3/include/bits/stl_vector.h
@@ -85,29 +85,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>::pointer
        	pointer;
 
-      struct _Vector_impl
-      : public _Tp_alloc_type
+      struct _Vector_impl_data
       {
 	pointer _M_start;
 	pointer _M_finish;
 	pointer _M_end_of_storage;
 
-	_Vector_impl()
-	: _Tp_alloc_type(), _M_start(), _M_finish(), _M_end_of_storage()
-	{ }
-
-	_Vector_impl(_Tp_alloc_type const& __a) _GLIBCXX_NOEXCEPT
-	: _Tp_alloc_type(__a), _M_start(), _M_finish(), _M_end_of_storage()
+	_Vector_impl_data() _GLIBCXX_NOEXCEPT
+	: _M_start(), _M_finish(), _M_end_of_storage()
 	{ }
 
 #if __cplusplus >= 201103L
-	_Vector_impl(_Tp_alloc_type&& __a) noexcept
-	: _Tp_alloc_type(std::move(__a)),
-	  _M_start(), _M_finish(), _M_end_of_storage()
-	{ }
+	_Vector_impl_data(_Vector_impl_data&& __x) noexcept
+	: _M_start(__x._M_start), _M_finish(__x._M_finish),
+	  _M_end_of_storage(__x._M_end_of_storage)
+	{ __x._M_start = __x._M_finish = __x._M_end_of_storage = pointer(); }
 #endif
 
-	void _M_swap_data(_Vector_impl& __x) _GLIBCXX_NOEXCEPT
+	void
+	_M_swap_data(_Vector_impl_data& __x) _GLIBCXX_NOEXCEPT
 	{
 	  std::swap(_M_start, __x._M_start);
 	  std::swap(_M_finish, __x._M_finish);
@@ -230,54 +226,64 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 #endif // _GLIBCXX_SANITIZE_STD_ALLOCATOR && _GLIBCXX_SANITIZE_VECTOR
       };
 
+      struct _Vector_impl
+	: public _Tp_alloc_type, public _Vector_impl_data
+      {
+	_Vector_impl() _GLIBCXX_NOEXCEPT_IF( noexcept(_Tp_alloc_type()) )
+	: _Tp_alloc_type()
+	{ }
+
+	_Vector_impl(_Tp_alloc_type const& __a) _GLIBCXX_NOEXCEPT
+	: _Tp_alloc_type(__a)
+	{ }
+
+#if __cplusplus >= 201103L
+	_Vector_impl(_Vector_impl&&) = default;
+
+	_Vector_impl(_Tp_alloc_type&& __a) noexcept
+	  : _Tp_alloc_type(std::move(__a))
+	{ }
+
+	_Vector_impl(_Vector_impl&& __rv, _Tp_alloc_type&& __a) noexcept
+	: _Tp_alloc_type(std::move(__a)), _Vector_impl_data(std::move(__rv))
+	{ }
+#endif
+      };
+
     public:
       typedef _Alloc allocator_type;
 
       _Tp_alloc_type&
       _M_get_Tp_allocator() _GLIBCXX_NOEXCEPT
-      { return *static_cast<_Tp_alloc_type*>(&this->_M_impl); }
+      { return this->_M_impl; }
 
       const _Tp_alloc_type&
       _M_get_Tp_allocator() const _GLIBCXX_NOEXCEPT
-      { return *static_cast<const _Tp_alloc_type*>(&this->_M_impl); }
+      { return this->_M_impl; }
 
       allocator_type
       get_allocator() const _GLIBCXX_NOEXCEPT
       { return allocator_type(_M_get_Tp_allocator()); }
 
-      _Vector_base()
-      : _M_impl() { }
+#if __cplusplus >= 201103L
+      _Vector_base() = default;
+#else
+      _Vector_base() { }
+#endif
 
       _Vector_base(const allocator_type& __a) _GLIBCXX_NOEXCEPT
       : _M_impl(__a) { }
 
-      _Vector_base(size_t __n)
-      : _M_impl()
-      { _M_create_storage(__n); }
-
       _Vector_base(size_t __n, const allocator_type& __a)
       : _M_impl(__a)
       { _M_create_storage(__n); }
 
 #if __cplusplus >= 201103L
-      _Vector_base(_Tp_alloc_type&& __a) noexcept
-      : _M_impl(std::move(__a)) { }
-
-      _Vector_base(_Vector_base&& __x) noexcept
-      : _M_impl(std::move(__x._M_get_Tp_allocator()))
-      { this->_M_impl._M_swap_data(__x._M_impl); }
+      _Vector_base(_Vector_base&&) = default;
 
       _Vector_base(_Vector_base&& __x, const allocator_type& __a)
-      : _M_impl(__a)
-      {
-	if (__x.get_allocator() == __a)
-	  this->_M_impl._M_swap_data(__x._M_impl);
-	else
-	  {
-	    size_t __n = __x._M_impl._M_finish - __x._M_impl._M_start;
-	    _M_create_storage(__n);
-	  }
-      }
+      : _M_impl(std::move(__x._M_impl), _Tp_alloc_type(__a))
+      { }
 #endif
 
       ~_Vector_base() _GLIBCXX_NOEXCEPT
@@ -379,11 +385,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       /**
        *  @brief  Creates a %vector with no elements.
        */
-      vector()
 #if __cplusplus >= 201103L
-      noexcept(is_nothrow_default_constructible<_Alloc>::value)
+      vector() = default;
+#else
+      vector() { }
 #endif
-      : _Base() { }
 
       /**
        *  @brief  Creates a %vector with no elements.
@@ -459,13 +465,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 #if __cplusplus >= 201103L
       /**
        *  @brief  %Vector move constructor.
-       *  @param  __x  A %vector of identical element and allocator types.
        *
-       *  The newly-created %vector contains the exact contents of @a __x.
-       *  The contents of @a __x are a valid, but unspecified %vector.
+       *  The newly-created %vector contains the exact contents of the
+       *  moved instance.
+       *  The contents of the moved instance are a valid, but unspecified
+       *  %vector.
        */
-      vector(vector&& __x) noexcept
-      : _Base(std::move(__x)) { }
+      vector(vector&&) = default;
 
       /// Copy constructor with alternative allocator
       vector(const vector& __x, const allocator_type& __a)
@@ -477,13 +483,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 				      _M_get_Tp_allocator());
       }
 
-      /// Move constructor with alternative allocator
-      vector(vector&& __rv, const allocator_type& __m)
-      noexcept(_Alloc_traits::_S_always_equal())
+    private:
+      vector(vector&& __rv, const allocator_type& __m, std::true_type) noexcept
       : _Base(std::move(__rv), __m)
+      { }
+
+      vector(vector&& __rv, const allocator_type& __m, std::false_type)
+      : _Base(__m)
       {
-	if (__rv.get_allocator() != __m)
+	if (__rv.get_allocator() == __m)
+	  this->_M_impl._M_swap_data(__rv._M_impl);
+	else if (!__rv.empty())
 	  {
+	    this->_M_create_storage(__rv.size());
 	    this->_M_impl._M_finish =
 	      std::__uninitialized_move_a(__rv.begin(), __rv.end(),
 					  this->_M_impl._M_start,
@@ -492,6 +504,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  }
       }
 
+    public:
+      /// Move constructor with alternative allocator
+      vector(vector&& __rv, const allocator_type& __m)
+	noexcept(_Alloc_traits::_S_always_equal())
+      : vector(std::move(__rv), __m, typename _Alloc_traits::is_always_equal{})
+      { }
+
       /**
        *  @brief  Builds a %vector from an initializer list.
        *  @param  __l  An initializer_list.
@@ -534,7 +553,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	vector(_InputIterator __first, _InputIterator __last,
 	       const allocator_type& __a = allocator_type())
 	: _Base(__a)
-	{ _M_initialize_dispatch(__first, __last, __false_type()); }
+	{
+	  _M_range_initialize(__first, __last,
+			      std::__iterator_category(__first));
+	}
 #else
       template<typename _InputIterator>
 	vector(_InputIterator __first, _InputIterator __last,
@@ -1405,6 +1427,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 
       // Called by the range constructor to implement [23.1.1]/9
 
+#if __cplusplus < 201103L
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // 438. Ambiguity in the "do the right thing" clause
       template<typename _Integer>
@@ -1423,10 +1446,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	_M_initialize_dispatch(_InputIterator __first, _InputIterator __last,
 			       __false_type)
 	{
-	  typedef typename std::iterator_traits<_InputIterator>::
-	    iterator_category _IterCategory;
-	  _M_range_initialize(__first, __last, _IterCategory());
+	  _M_range_initialize(__first, __last,
+			      std::__iterator_category(__first));
 	}
+#endif
 
       // Called by the second initialize_dispatch above
       template<typename _InputIterator>
diff --git a/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc b/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc
new file mode 100644
index 0000000..1f0719d
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc
@@ -0,0 +1,67 @@
+// Copyright (C) 2017 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/>.
+
+// { dg-do run { target c++11 } }
+// { dg-options "-O0" }
+// { dg-xfail-run-if "PR c++/65816" { *-*-* } }
+
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+#include <ext/aligned_buffer.h>
+
+using T = int;
+
+using __gnu_test::default_init_allocator;
+
+void test01()
+{
+  typedef default_init_allocator<T> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+
+  __gnu_cxx::__aligned_buffer<test_type> buf;
+  __builtin_memset(buf._M_addr(), ~0, sizeof(test_type));
+
+  test_type *tmp = ::new(buf._M_addr()) test_type;
+
+  VERIFY( tmp->get_allocator().state == 0 );
+
+  tmp->~test_type();
+}
+
+void test02()
+{
+  typedef default_init_allocator<T> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+
+  __gnu_cxx::__aligned_buffer<test_type> buf;
+  __builtin_memset(buf._M_addr(), ~0, sizeof(test_type));
+
+  test_type *tmp = ::new(buf._M_addr()) test_type();
+
+  VERIFY( tmp->get_allocator().state == 0 );
+
+  tmp->~test_type();
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: std::vector default default and move constructors
  2017-07-23 17:41 std::vector default default and move constructors François Dumont
@ 2017-07-28 16:46 ` François Dumont
  2017-08-21 19:16   ` François Dumont
  0 siblings, 1 reply; 16+ messages in thread
From: François Dumont @ 2017-07-28 16:46 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 876 bytes --]

Hi

     There was a little issue in this patch, here is the correct version.

François


On 23/07/2017 19:41, François Dumont wrote:
> Hi
>
>     Is it time now to consider this patch ?
>
>     * include/bits/stl_vector.h
>     (_Vector_impl_data): New.
>     (_Vector_impl): Inherit from latter.
>     (_Vertor_impl(_Vector_impl&&, _Tp_alloc_type&&)): New.
>     (_Vector_base(_Vector_base&&, const allocator_type&)): Use latter.
>     (_Vector_base()): Default.
>     (_Vector_base(size_t)): Delete.
>     (_Vector_base(_Tp_alloc_type&&)): Delete.
>     (_Vector_base(_Vector_base&&)): Default.
>     (vector()): Default.
>     (vector(vector&&, const allocator_type&, true_type)): New.
>     (vector(vector&&, const allocator_type&, false_type)): New.
>     (vector(vector&&, const allocator_type&)): Use latters.
>
> Tested under linux x86_64.
>
> François
>
>


[-- Attachment #2: vector.patch --]
[-- Type: text/x-patch, Size: 10005 bytes --]

diff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h
index 69cb803..1cbfcd9 100644
--- a/libstdc++-v3/include/bits/stl_vector.h
+++ b/libstdc++-v3/include/bits/stl_vector.h
@@ -85,29 +85,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>::pointer
        	pointer;
 
-      struct _Vector_impl
-      : public _Tp_alloc_type
+      struct _Vector_impl_data
       {
 	pointer _M_start;
 	pointer _M_finish;
 	pointer _M_end_of_storage;
 
-	_Vector_impl()
-	: _Tp_alloc_type(), _M_start(), _M_finish(), _M_end_of_storage()
-	{ }
-
-	_Vector_impl(_Tp_alloc_type const& __a) _GLIBCXX_NOEXCEPT
-	: _Tp_alloc_type(__a), _M_start(), _M_finish(), _M_end_of_storage()
+	_Vector_impl_data() _GLIBCXX_NOEXCEPT
+	: _M_start(), _M_finish(), _M_end_of_storage()
 	{ }
 
 #if __cplusplus >= 201103L
-	_Vector_impl(_Tp_alloc_type&& __a) noexcept
-	: _Tp_alloc_type(std::move(__a)),
-	  _M_start(), _M_finish(), _M_end_of_storage()
-	{ }
+	_Vector_impl_data(_Vector_impl_data&& __x) noexcept
+	: _M_start(__x._M_start), _M_finish(__x._M_finish),
+	  _M_end_of_storage(__x._M_end_of_storage)
+	{ __x._M_start = __x._M_finish = __x._M_end_of_storage = pointer(); }
 #endif
 
-	void _M_swap_data(_Vector_impl& __x) _GLIBCXX_NOEXCEPT
+	void
+	_M_swap_data(_Vector_impl_data& __x) _GLIBCXX_NOEXCEPT
 	{
 	  std::swap(_M_start, __x._M_start);
 	  std::swap(_M_finish, __x._M_finish);
@@ -230,54 +226,64 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 #endif // _GLIBCXX_SANITIZE_STD_ALLOCATOR && _GLIBCXX_SANITIZE_VECTOR
       };
 
+      struct _Vector_impl
+	: public _Tp_alloc_type, public _Vector_impl_data
+      {
+	_Vector_impl() _GLIBCXX_NOEXCEPT_IF( noexcept(_Tp_alloc_type()) )
+	: _Tp_alloc_type()
+	{ }
+
+	_Vector_impl(_Tp_alloc_type const& __a) _GLIBCXX_NOEXCEPT
+	: _Tp_alloc_type(__a)
+	{ }
+
+#if __cplusplus >= 201103L
+	_Vector_impl(_Vector_impl&&) = default;
+
+	_Vector_impl(_Tp_alloc_type&& __a) noexcept
+	  : _Tp_alloc_type(std::move(__a))
+	{ }
+
+	_Vector_impl(_Vector_impl&& __rv, _Tp_alloc_type&& __a) noexcept
+	: _Tp_alloc_type(std::move(__a)), _Vector_impl_data(std::move(__rv))
+	{ }
+#endif
+      };
+
     public:
       typedef _Alloc allocator_type;
 
       _Tp_alloc_type&
       _M_get_Tp_allocator() _GLIBCXX_NOEXCEPT
-      { return *static_cast<_Tp_alloc_type*>(&this->_M_impl); }
+      { return this->_M_impl; }
 
       const _Tp_alloc_type&
       _M_get_Tp_allocator() const _GLIBCXX_NOEXCEPT
-      { return *static_cast<const _Tp_alloc_type*>(&this->_M_impl); }
+      { return this->_M_impl; }
 
       allocator_type
       get_allocator() const _GLIBCXX_NOEXCEPT
       { return allocator_type(_M_get_Tp_allocator()); }
 
-      _Vector_base()
-      : _M_impl() { }
+#if __cplusplus >= 201103L
+      _Vector_base() = default;
+#else
+      _Vector_base() { }
+#endif
 
       _Vector_base(const allocator_type& __a) _GLIBCXX_NOEXCEPT
       : _M_impl(__a) { }
 
-      _Vector_base(size_t __n)
-      : _M_impl()
-      { _M_create_storage(__n); }
-
       _Vector_base(size_t __n, const allocator_type& __a)
       : _M_impl(__a)
       { _M_create_storage(__n); }
 
 #if __cplusplus >= 201103L
-      _Vector_base(_Tp_alloc_type&& __a) noexcept
-      : _M_impl(std::move(__a)) { }
-
-      _Vector_base(_Vector_base&& __x) noexcept
-      : _M_impl(std::move(__x._M_get_Tp_allocator()))
-      { this->_M_impl._M_swap_data(__x._M_impl); }
+      _Vector_base(_Vector_base&&) = default;
 
       _Vector_base(_Vector_base&& __x, const allocator_type& __a)
-      : _M_impl(__a)
-      {
-	if (__x.get_allocator() == __a)
-	  this->_M_impl._M_swap_data(__x._M_impl);
-	else
-	  {
-	    size_t __n = __x._M_impl._M_finish - __x._M_impl._M_start;
-	    _M_create_storage(__n);
-	  }
-      }
+      : _M_impl(std::move(__x._M_impl), _Tp_alloc_type(__a))
+      { }
 #endif
 
       ~_Vector_base() _GLIBCXX_NOEXCEPT
@@ -304,7 +310,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  _Tr::deallocate(_M_impl, __p, __n);
       }
 
-    private:
+    protected:
       void
       _M_create_storage(size_t __n)
       {
@@ -379,11 +385,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       /**
        *  @brief  Creates a %vector with no elements.
        */
-      vector()
 #if __cplusplus >= 201103L
-      noexcept(is_nothrow_default_constructible<_Alloc>::value)
+      vector() = default;
+#else
+      vector() { }
 #endif
-      : _Base() { }
 
       /**
        *  @brief  Creates a %vector with no elements.
@@ -459,13 +465,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 #if __cplusplus >= 201103L
       /**
        *  @brief  %Vector move constructor.
-       *  @param  __x  A %vector of identical element and allocator types.
        *
-       *  The newly-created %vector contains the exact contents of @a __x.
-       *  The contents of @a __x are a valid, but unspecified %vector.
+       *  The newly-created %vector contains the exact contents of the
+       *  moved instance.
+       *  The contents of the moved instance are a valid, but unspecified
+       *  %vector.
        */
-      vector(vector&& __x) noexcept
-      : _Base(std::move(__x)) { }
+      vector(vector&&) = default;
 
       /// Copy constructor with alternative allocator
       vector(const vector& __x, const allocator_type& __a)
@@ -477,13 +483,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 				      _M_get_Tp_allocator());
       }
 
-      /// Move constructor with alternative allocator
-      vector(vector&& __rv, const allocator_type& __m)
-      noexcept(_Alloc_traits::_S_always_equal())
+    private:
+      vector(vector&& __rv, const allocator_type& __m, std::true_type) noexcept
       : _Base(std::move(__rv), __m)
+      { }
+
+      vector(vector&& __rv, const allocator_type& __m, std::false_type)
+      : _Base(__m)
       {
-	if (__rv.get_allocator() != __m)
+	if (__rv.get_allocator() == __m)
+	  this->_M_impl._M_swap_data(__rv._M_impl);
+	else if (!__rv.empty())
 	  {
+	    this->_M_create_storage(__rv.size());
 	    this->_M_impl._M_finish =
 	      std::__uninitialized_move_a(__rv.begin(), __rv.end(),
 					  this->_M_impl._M_start,
@@ -492,6 +504,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  }
       }
 
+    public:
+      /// Move constructor with alternative allocator
+      vector(vector&& __rv, const allocator_type& __m)
+	noexcept(_Alloc_traits::_S_always_equal())
+      : vector(std::move(__rv), __m, typename _Alloc_traits::is_always_equal{})
+      { }
+
       /**
        *  @brief  Builds a %vector from an initializer list.
        *  @param  __l  An initializer_list.
@@ -534,7 +553,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	vector(_InputIterator __first, _InputIterator __last,
 	       const allocator_type& __a = allocator_type())
 	: _Base(__a)
-	{ _M_initialize_dispatch(__first, __last, __false_type()); }
+	{
+	  _M_range_initialize(__first, __last,
+			      std::__iterator_category(__first));
+	}
 #else
       template<typename _InputIterator>
 	vector(_InputIterator __first, _InputIterator __last,
@@ -1405,6 +1427,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 
       // Called by the range constructor to implement [23.1.1]/9
 
+#if __cplusplus < 201103L
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // 438. Ambiguity in the "do the right thing" clause
       template<typename _Integer>
@@ -1423,10 +1446,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	_M_initialize_dispatch(_InputIterator __first, _InputIterator __last,
 			       __false_type)
 	{
-	  typedef typename std::iterator_traits<_InputIterator>::
-	    iterator_category _IterCategory;
-	  _M_range_initialize(__first, __last, _IterCategory());
+	  _M_range_initialize(__first, __last,
+			      std::__iterator_category(__first));
 	}
+#endif
 
       // Called by the second initialize_dispatch above
       template<typename _InputIterator>
diff --git a/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc b/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc
new file mode 100644
index 0000000..1f0719d
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc
@@ -0,0 +1,67 @@
+// Copyright (C) 2017 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/>.
+
+// { dg-do run { target c++11 } }
+// { dg-options "-O0" }
+// { dg-xfail-run-if "PR c++/65816" { *-*-* } }
+
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+#include <ext/aligned_buffer.h>
+
+using T = int;
+
+using __gnu_test::default_init_allocator;
+
+void test01()
+{
+  typedef default_init_allocator<T> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+
+  __gnu_cxx::__aligned_buffer<test_type> buf;
+  __builtin_memset(buf._M_addr(), ~0, sizeof(test_type));
+
+  test_type *tmp = ::new(buf._M_addr()) test_type;
+
+  VERIFY( tmp->get_allocator().state == 0 );
+
+  tmp->~test_type();
+}
+
+void test02()
+{
+  typedef default_init_allocator<T> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+
+  __gnu_cxx::__aligned_buffer<test_type> buf;
+  __builtin_memset(buf._M_addr(), ~0, sizeof(test_type));
+
+  test_type *tmp = ::new(buf._M_addr()) test_type();
+
+  VERIFY( tmp->get_allocator().state == 0 );
+
+  tmp->~test_type();
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: std::vector default default and move constructors
  2017-07-28 16:46 ` François Dumont
@ 2017-08-21 19:16   ` François Dumont
  2017-09-04 19:47     ` François Dumont
  2018-01-11  6:41     ` François Dumont
  0 siblings, 2 replies; 16+ messages in thread
From: François Dumont @ 2017-08-21 19:16 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1114 bytes --]

Following feedback on std::list patch this one had the same problem of 
unused code being deleted. So here is a new version.

Ok to commit ?

François

On 28/07/2017 18:45, François Dumont wrote:
> Hi
>
>     There was a little issue in this patch, here is the correct version.
>
> François
>
>
> On 23/07/2017 19:41, François Dumont wrote:
>> Hi
>>
>>     Is it time now to consider this patch ?
>>
>>     * include/bits/stl_vector.h
>>     (_Vector_impl_data): New.
>>     (_Vector_impl): Inherit from latter.
>>     (_Vertor_impl(_Vector_impl&&, _Tp_alloc_type&&)): New.
>>     (_Vector_base(_Vector_base&&, const allocator_type&)): Use latter.
>>     (_Vector_base()): Default.
>>     (_Vector_base(size_t)): Delete.
>>     (_Vector_base(_Tp_alloc_type&&)): Delete.
>>     (_Vector_base(_Vector_base&&)): Default.
>>     (vector()): Default.
>>     (vector(vector&&, const allocator_type&, true_type)): New.
>>     (vector(vector&&, const allocator_type&, false_type)): New.
>>     (vector(vector&&, const allocator_type&)): Use latters.
>>
>> Tested under linux x86_64.
>>
>> François
>>
>>
>


[-- Attachment #2: vector.patch --]
[-- Type: text/x-patch, Size: 10123 bytes --]

diff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h
index 69cb803..2fd7e2f 100644
--- a/libstdc++-v3/include/bits/stl_vector.h
+++ b/libstdc++-v3/include/bits/stl_vector.h
@@ -85,34 +85,54 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>::pointer
        	pointer;
 
-      struct _Vector_impl
-      : public _Tp_alloc_type
+      struct _Vector_impl_data
       {
 	pointer _M_start;
 	pointer _M_finish;
 	pointer _M_end_of_storage;
 
-	_Vector_impl()
-	: _Tp_alloc_type(), _M_start(), _M_finish(), _M_end_of_storage()
-	{ }
-
-	_Vector_impl(_Tp_alloc_type const& __a) _GLIBCXX_NOEXCEPT
-	: _Tp_alloc_type(__a), _M_start(), _M_finish(), _M_end_of_storage()
+	_Vector_impl_data() _GLIBCXX_NOEXCEPT
+	: _M_start(), _M_finish(), _M_end_of_storage()
 	{ }
 
 #if __cplusplus >= 201103L
-	_Vector_impl(_Tp_alloc_type&& __a) noexcept
-	: _Tp_alloc_type(std::move(__a)),
-	  _M_start(), _M_finish(), _M_end_of_storage()
-	{ }
+	_Vector_impl_data(_Vector_impl_data&& __x) noexcept
+	: _M_start(__x._M_start), _M_finish(__x._M_finish),
+	  _M_end_of_storage(__x._M_end_of_storage)
+	{ __x._M_start = __x._M_finish = __x._M_end_of_storage = pointer(); }
 #endif
 
-	void _M_swap_data(_Vector_impl& __x) _GLIBCXX_NOEXCEPT
+	void
+	_M_swap_data(_Vector_impl_data& __x) _GLIBCXX_NOEXCEPT
 	{
 	  std::swap(_M_start, __x._M_start);
 	  std::swap(_M_finish, __x._M_finish);
 	  std::swap(_M_end_of_storage, __x._M_end_of_storage);
 	}
+      };
+
+      struct _Vector_impl
+	: public _Tp_alloc_type, public _Vector_impl_data
+      {
+	_Vector_impl() _GLIBCXX_NOEXCEPT_IF( noexcept(_Tp_alloc_type()) )
+	: _Tp_alloc_type()
+	{ }
+
+	_Vector_impl(_Tp_alloc_type const& __a) _GLIBCXX_NOEXCEPT
+	: _Tp_alloc_type(__a)
+	{ }
+
+#if __cplusplus >= 201103L
+	_Vector_impl(_Vector_impl&&) = default;
+
+	_Vector_impl(_Tp_alloc_type&& __a) noexcept
+	  : _Tp_alloc_type(std::move(__a))
+	{ }
+
+	_Vector_impl(_Tp_alloc_type&& __a, _Vector_impl&& __rv) noexcept
+	: _Tp_alloc_type(std::move(__a)), _Vector_impl_data(std::move(__rv))
+	{ }
+#endif
 
 #if _GLIBCXX_SANITIZE_STD_ALLOCATOR && _GLIBCXX_SANITIZE_VECTOR
 	template<typename = _Tp_alloc_type>
@@ -235,38 +255,42 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 
       _Tp_alloc_type&
       _M_get_Tp_allocator() _GLIBCXX_NOEXCEPT
-      { return *static_cast<_Tp_alloc_type*>(&this->_M_impl); }
+      { return this->_M_impl; }
 
       const _Tp_alloc_type&
       _M_get_Tp_allocator() const _GLIBCXX_NOEXCEPT
-      { return *static_cast<const _Tp_alloc_type*>(&this->_M_impl); }
+      { return this->_M_impl; }
 
       allocator_type
       get_allocator() const _GLIBCXX_NOEXCEPT
       { return allocator_type(_M_get_Tp_allocator()); }
 
-      _Vector_base()
-      : _M_impl() { }
+#if __cplusplus >= 201103L
+      _Vector_base() = default;
+#else
+      _Vector_base() { }
+#endif
 
       _Vector_base(const allocator_type& __a) _GLIBCXX_NOEXCEPT
       : _M_impl(__a) { }
 
+#if !_GLIBCXX_INLINE_VERSION
       _Vector_base(size_t __n)
       : _M_impl()
       { _M_create_storage(__n); }
+#endif
 
       _Vector_base(size_t __n, const allocator_type& __a)
       : _M_impl(__a)
       { _M_create_storage(__n); }
 
 #if __cplusplus >= 201103L
+      _Vector_base(_Vector_base&&) = default;
+
+# if !_GLIBCXX_INLINE_VERSION
       _Vector_base(_Tp_alloc_type&& __a) noexcept
       : _M_impl(std::move(__a)) { }
 
-      _Vector_base(_Vector_base&& __x) noexcept
-      : _M_impl(std::move(__x._M_get_Tp_allocator()))
-      { this->_M_impl._M_swap_data(__x._M_impl); }
-
       _Vector_base(_Vector_base&& __x, const allocator_type& __a)
       : _M_impl(__a)
       {
@@ -278,6 +302,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	    _M_create_storage(__n);
 	  }
       }
+# endif
+
+      _Vector_base(const allocator_type& __a, _Vector_base&& __x)
+      : _M_impl(_Tp_alloc_type(__a), std::move(__x._M_impl))
+      { }
 #endif
 
       ~_Vector_base() _GLIBCXX_NOEXCEPT
@@ -304,7 +333,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  _Tr::deallocate(_M_impl, __p, __n);
       }
 
-    private:
+    protected:
       void
       _M_create_storage(size_t __n)
       {
@@ -379,11 +408,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       /**
        *  @brief  Creates a %vector with no elements.
        */
-      vector()
 #if __cplusplus >= 201103L
-      noexcept(is_nothrow_default_constructible<_Alloc>::value)
+      vector() = default;
+#else
+      vector() { }
 #endif
-      : _Base() { }
 
       /**
        *  @brief  Creates a %vector with no elements.
@@ -459,13 +488,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 #if __cplusplus >= 201103L
       /**
        *  @brief  %Vector move constructor.
-       *  @param  __x  A %vector of identical element and allocator types.
        *
-       *  The newly-created %vector contains the exact contents of @a __x.
-       *  The contents of @a __x are a valid, but unspecified %vector.
+       *  The newly-created %vector contains the exact contents of the
+       *  moved instance.
+       *  The contents of the moved instance are a valid, but unspecified
+       *  %vector.
        */
-      vector(vector&& __x) noexcept
-      : _Base(std::move(__x)) { }
+      vector(vector&&) = default;
 
       /// Copy constructor with alternative allocator
       vector(const vector& __x, const allocator_type& __a)
@@ -477,13 +506,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 				      _M_get_Tp_allocator());
       }
 
-      /// Move constructor with alternative allocator
-      vector(vector&& __rv, const allocator_type& __m)
-      noexcept(_Alloc_traits::_S_always_equal())
-      : _Base(std::move(__rv), __m)
+    private:
+      vector(vector&& __rv, const allocator_type& __m, std::true_type) noexcept
+      : _Base(__m, std::move(__rv))
+      { }
+
+      vector(vector&& __rv, const allocator_type& __m, std::false_type)
+      : _Base(__m)
       {
-	if (__rv.get_allocator() != __m)
+	if (__rv.get_allocator() == __m)
+	  this->_M_impl._M_swap_data(__rv._M_impl);
+	else if (!__rv.empty())
 	  {
+	    this->_M_create_storage(__rv.size());
 	    this->_M_impl._M_finish =
 	      std::__uninitialized_move_a(__rv.begin(), __rv.end(),
 					  this->_M_impl._M_start,
@@ -492,6 +527,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  }
       }
 
+    public:
+      /// Move constructor with alternative allocator
+      vector(vector&& __rv, const allocator_type& __m)
+	noexcept(_Alloc_traits::_S_always_equal())
+      : vector(std::move(__rv), __m, typename _Alloc_traits::is_always_equal{})
+      { }
+
       /**
        *  @brief  Builds a %vector from an initializer list.
        *  @param  __l  An initializer_list.
@@ -534,7 +576,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	vector(_InputIterator __first, _InputIterator __last,
 	       const allocator_type& __a = allocator_type())
 	: _Base(__a)
-	{ _M_initialize_dispatch(__first, __last, __false_type()); }
+	{
+	  _M_range_initialize(__first, __last,
+			      std::__iterator_category(__first));
+	}
 #else
       template<typename _InputIterator>
 	vector(_InputIterator __first, _InputIterator __last,
@@ -1405,6 +1450,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 
       // Called by the range constructor to implement [23.1.1]/9
 
+#if __cplusplus < 201103L
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // 438. Ambiguity in the "do the right thing" clause
       template<typename _Integer>
@@ -1423,10 +1469,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	_M_initialize_dispatch(_InputIterator __first, _InputIterator __last,
 			       __false_type)
 	{
-	  typedef typename std::iterator_traits<_InputIterator>::
-	    iterator_category _IterCategory;
-	  _M_range_initialize(__first, __last, _IterCategory());
+	  _M_range_initialize(__first, __last,
+			      std::__iterator_category(__first));
 	}
+#endif
 
       // Called by the second initialize_dispatch above
       template<typename _InputIterator>
diff --git a/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc b/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc
new file mode 100644
index 0000000..1f0719d
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc
@@ -0,0 +1,67 @@
+// Copyright (C) 2017 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/>.
+
+// { dg-do run { target c++11 } }
+// { dg-options "-O0" }
+// { dg-xfail-run-if "PR c++/65816" { *-*-* } }
+
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+#include <ext/aligned_buffer.h>
+
+using T = int;
+
+using __gnu_test::default_init_allocator;
+
+void test01()
+{
+  typedef default_init_allocator<T> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+
+  __gnu_cxx::__aligned_buffer<test_type> buf;
+  __builtin_memset(buf._M_addr(), ~0, sizeof(test_type));
+
+  test_type *tmp = ::new(buf._M_addr()) test_type;
+
+  VERIFY( tmp->get_allocator().state == 0 );
+
+  tmp->~test_type();
+}
+
+void test02()
+{
+  typedef default_init_allocator<T> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+
+  __gnu_cxx::__aligned_buffer<test_type> buf;
+  __builtin_memset(buf._M_addr(), ~0, sizeof(test_type));
+
+  test_type *tmp = ::new(buf._M_addr()) test_type();
+
+  VERIFY( tmp->get_allocator().state == 0 );
+
+  tmp->~test_type();
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: std::vector default default and move constructors
  2017-08-21 19:16   ` François Dumont
@ 2017-09-04 19:47     ` François Dumont
  2018-01-11  6:41     ` François Dumont
  1 sibling, 0 replies; 16+ messages in thread
From: François Dumont @ 2017-09-04 19:47 UTC (permalink / raw)
  To: libstdc++, gcc-patches

Hi

     Gentle reminder.

Thanks


On 21/08/2017 21:15, François Dumont wrote:
> Following feedback on std::list patch this one had the same problem of 
> unused code being deleted. So here is a new version.
>
> Ok to commit ?
>
> François
>
> On 28/07/2017 18:45, François Dumont wrote:
>> Hi
>>
>>     There was a little issue in this patch, here is the correct version.
>>
>> François
>>
>>
>> On 23/07/2017 19:41, François Dumont wrote:
>>> Hi
>>>
>>>     Is it time now to consider this patch ?
>>>
>>>     * include/bits/stl_vector.h
>>>     (_Vector_impl_data): New.
>>>     (_Vector_impl): Inherit from latter.
>>>     (_Vertor_impl(_Vector_impl&&, _Tp_alloc_type&&)): New.
>>>     (_Vector_base(_Vector_base&&, const allocator_type&)): Use latter.
>>>     (_Vector_base()): Default.
>>>     (_Vector_base(size_t)): Delete.
>>>     (_Vector_base(_Tp_alloc_type&&)): Delete.
>>>     (_Vector_base(_Vector_base&&)): Default.
>>>     (vector()): Default.
>>>     (vector(vector&&, const allocator_type&, true_type)): New.
>>>     (vector(vector&&, const allocator_type&, false_type)): New.
>>>     (vector(vector&&, const allocator_type&)): Use latters.
>>>
>>> Tested under linux x86_64.
>>>
>>> François
>>>
>>>
>>
>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: std::vector default default and move constructors
  2017-08-21 19:16   ` François Dumont
  2017-09-04 19:47     ` François Dumont
@ 2018-01-11  6:41     ` François Dumont
  2018-01-11  6:57       ` Marc Glisse
  1 sibling, 1 reply; 16+ messages in thread
From: François Dumont @ 2018-01-11  6:41 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1474 bytes --]

Hi

     Here is an updated patch.

     Tested under Linux x86_64.

     Ok to commit ?

François


On 21/08/2017 21:15, François Dumont wrote:
> Following feedback on std::list patch this one had the same problem of 
> unused code being deleted. So here is a new version.
>
> Ok to commit ?
>
> François
>
> On 28/07/2017 18:45, François Dumont wrote:
>> Hi
>>
>>     There was a little issue in this patch, here is the correct version.
>>
>> François
>>
>>
>> On 23/07/2017 19:41, François Dumont wrote:
>>> Hi
>>>
>>>     Is it time now to consider this patch ?
>>>
>>>     * include/bits/stl_vector.h
>>>     (_Vector_impl_data): New.
>>>     (_Vector_impl): Inherit from latter.
>>>     (_Vertor_impl(_Vector_impl&&, _Tp_alloc_type&&)): New.
>>>     (_Vector_base(_Vector_base&&, const allocator_type&)): Use latter.
>>>     (_Vector_base()): Default.
>>>     (_Vector_base(size_t)): Delete.
>>>     (_Vector_base(_Tp_alloc_type&&)): Delete.
>>>     (_Vector_base(_Vector_base&&)): Default.
>>>     (vector()): Default.
>>>     (vector(vector&&, const allocator_type&, true_type)): New.
>>>     (vector(vector&&, const allocator_type&, false_type)): New.
>>>     (vector(vector&&, const allocator_type&)): Use latters.
>>>
>>> Tested under linux x86_64.
>>>
>>> François
>>>
>>>
>>
>


[-- Attachment #2: vector.patch --]
[-- Type: text/x-patch, Size: 11067 bytes --]

diff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h
index acec501..3dfb4a6 100644
--- a/libstdc++-v3/include/bits/stl_vector.h
+++ b/libstdc++-v3/include/bits/stl_vector.h
@@ -85,34 +85,54 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>::pointer
        	pointer;
 
-      struct _Vector_impl
-      : public _Tp_alloc_type
+      struct _Vector_impl_data
       {
 	pointer _M_start;
 	pointer _M_finish;
 	pointer _M_end_of_storage;
 
-	_Vector_impl()
-	: _Tp_alloc_type(), _M_start(), _M_finish(), _M_end_of_storage()
-	{ }
-
-	_Vector_impl(_Tp_alloc_type const& __a) _GLIBCXX_NOEXCEPT
-	: _Tp_alloc_type(__a), _M_start(), _M_finish(), _M_end_of_storage()
+	_Vector_impl_data() _GLIBCXX_NOEXCEPT
+	: _M_start(), _M_finish(), _M_end_of_storage()
 	{ }
 
 #if __cplusplus >= 201103L
-	_Vector_impl(_Tp_alloc_type&& __a) noexcept
-	: _Tp_alloc_type(std::move(__a)),
-	  _M_start(), _M_finish(), _M_end_of_storage()
-	{ }
+	_Vector_impl_data(_Vector_impl_data&& __x) noexcept
+	: _M_start(__x._M_start), _M_finish(__x._M_finish),
+	  _M_end_of_storage(__x._M_end_of_storage)
+	{ __x._M_start = __x._M_finish = __x._M_end_of_storage = pointer(); }
 #endif
 
-	void _M_swap_data(_Vector_impl& __x) _GLIBCXX_NOEXCEPT
+	void
+	_M_swap_data(_Vector_impl_data& __x) _GLIBCXX_NOEXCEPT
 	{
 	  std::swap(_M_start, __x._M_start);
 	  std::swap(_M_finish, __x._M_finish);
 	  std::swap(_M_end_of_storage, __x._M_end_of_storage);
 	}
+      };
+
+      struct _Vector_impl
+	: public _Tp_alloc_type, public _Vector_impl_data
+      {
+	_Vector_impl() _GLIBCXX_NOEXCEPT_IF( noexcept(_Tp_alloc_type()) )
+	: _Tp_alloc_type()
+	{ }
+
+	_Vector_impl(_Tp_alloc_type const& __a) _GLIBCXX_NOEXCEPT
+	: _Tp_alloc_type(__a)
+	{ }
+
+#if __cplusplus >= 201103L
+	_Vector_impl(_Vector_impl&&) = default;
+
+	_Vector_impl(_Tp_alloc_type&& __a) noexcept
+	  : _Tp_alloc_type(std::move(__a))
+	{ }
+
+	_Vector_impl(_Tp_alloc_type&& __a, _Vector_impl&& __rv) noexcept
+	: _Tp_alloc_type(std::move(__a)), _Vector_impl_data(std::move(__rv))
+	{ }
+#endif
 
 #if _GLIBCXX_SANITIZE_STD_ALLOCATOR && _GLIBCXX_SANITIZE_VECTOR
 	template<typename = _Tp_alloc_type>
@@ -235,38 +255,42 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 
       _Tp_alloc_type&
       _M_get_Tp_allocator() _GLIBCXX_NOEXCEPT
-      { return *static_cast<_Tp_alloc_type*>(&this->_M_impl); }
+      { return this->_M_impl; }
 
       const _Tp_alloc_type&
       _M_get_Tp_allocator() const _GLIBCXX_NOEXCEPT
-      { return *static_cast<const _Tp_alloc_type*>(&this->_M_impl); }
+      { return this->_M_impl; }
 
       allocator_type
       get_allocator() const _GLIBCXX_NOEXCEPT
       { return allocator_type(_M_get_Tp_allocator()); }
 
-      _Vector_base()
-      : _M_impl() { }
+#if __cplusplus >= 201103L
+      _Vector_base() = default;
+#else
+      _Vector_base() { }
+#endif
 
       _Vector_base(const allocator_type& __a) _GLIBCXX_NOEXCEPT
       : _M_impl(__a) { }
 
+#if !_GLIBCXX_INLINE_VERSION
       _Vector_base(size_t __n)
       : _M_impl()
       { _M_create_storage(__n); }
+#endif
 
       _Vector_base(size_t __n, const allocator_type& __a)
       : _M_impl(__a)
       { _M_create_storage(__n); }
 
 #if __cplusplus >= 201103L
+      _Vector_base(_Vector_base&&) = default;
+
+# if !_GLIBCXX_INLINE_VERSION
       _Vector_base(_Tp_alloc_type&& __a) noexcept
       : _M_impl(std::move(__a)) { }
 
-      _Vector_base(_Vector_base&& __x) noexcept
-      : _M_impl(std::move(__x._M_get_Tp_allocator()))
-      { this->_M_impl._M_swap_data(__x._M_impl); }
-
       _Vector_base(_Vector_base&& __x, const allocator_type& __a)
       : _M_impl(__a)
       {
@@ -278,6 +302,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	    _M_create_storage(__n);
 	  }
       }
+# endif
+
+      _Vector_base(const allocator_type& __a, _Vector_base&& __x)
+      : _M_impl(_Tp_alloc_type(__a), std::move(__x._M_impl))
+      { }
 #endif
 
       ~_Vector_base() _GLIBCXX_NOEXCEPT
@@ -304,7 +333,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  _Tr::deallocate(_M_impl, __p, __n);
       }
 
-    private:
+    protected:
       void
       _M_create_storage(size_t __n)
       {
@@ -388,11 +417,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       /**
        *  @brief  Creates a %vector with no elements.
        */
-      vector()
 #if __cplusplus >= 201103L
-      noexcept(is_nothrow_default_constructible<_Alloc>::value)
+      vector() = default;
+#else
+      vector() { }
 #endif
-      : _Base() { }
 
       /**
        *  @brief  Creates a %vector with no elements.
@@ -468,13 +497,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 #if __cplusplus >= 201103L
       /**
        *  @brief  %Vector move constructor.
-       *  @param  __x  A %vector of identical element and allocator types.
        *
-       *  The newly-created %vector contains the exact contents of @a __x.
-       *  The contents of @a __x are a valid, but unspecified %vector.
+       *  The newly-created %vector contains the exact contents of the
+       *  moved instance.
+       *  The contents of the moved instance are a valid, but unspecified
+       *  %vector.
        */
-      vector(vector&& __x) noexcept
-      : _Base(std::move(__x)) { }
+      vector(vector&&) = default;
 
       /// Copy constructor with alternative allocator
       vector(const vector& __x, const allocator_type& __a)
@@ -486,13 +515,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 				      _M_get_Tp_allocator());
       }
 
-      /// Move constructor with alternative allocator
-      vector(vector&& __rv, const allocator_type& __m)
-      noexcept(_Alloc_traits::_S_always_equal())
-      : _Base(std::move(__rv), __m)
+    private:
+      vector(vector&& __rv, const allocator_type& __m, true_type) noexcept
+      : _Base(__m, std::move(__rv))
+      { }
+
+      vector(vector&& __rv, const allocator_type& __m, false_type)
+      : _Base(__m)
       {
-	if (__rv.get_allocator() != __m)
+	if (__rv.get_allocator() == __m)
+	  this->_M_impl._M_swap_data(__rv._M_impl);
+	else if (!__rv.empty())
 	  {
+	    this->_M_create_storage(__rv.size());
 	    this->_M_impl._M_finish =
 	      std::__uninitialized_move_a(__rv.begin(), __rv.end(),
 					  this->_M_impl._M_start,
@@ -501,6 +536,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  }
       }
 
+    public:
+      /// Move constructor with alternative allocator
+      vector(vector&& __rv, const allocator_type& __m)
+	noexcept(_Alloc_traits::_S_always_equal())
+      : vector(std::move(__rv), __m, typename _Alloc_traits::is_always_equal{})
+      { }
+
       /**
        *  @brief  Builds a %vector from an initializer list.
        *  @param  __l  An initializer_list.
@@ -543,7 +585,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	vector(_InputIterator __first, _InputIterator __last,
 	       const allocator_type& __a = allocator_type())
 	: _Base(__a)
-	{ _M_initialize_dispatch(__first, __last, __false_type()); }
+	{
+	  _M_range_initialize(__first, __last,
+			      std::__iterator_category(__first));
+	}
 #else
       template<typename _InputIterator>
 	vector(_InputIterator __first, _InputIterator __last,
@@ -1414,6 +1459,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 
       // Called by the range constructor to implement [23.1.1]/9
 
+#if __cplusplus < 201103L
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // 438. Ambiguity in the "do the right thing" clause
       template<typename _Integer>
@@ -1432,10 +1478,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	_M_initialize_dispatch(_InputIterator __first, _InputIterator __last,
 			       __false_type)
 	{
-	  typedef typename std::iterator_traits<_InputIterator>::
-	    iterator_category _IterCategory;
-	  _M_range_initialize(__first, __last, _IterCategory());
+	  _M_range_initialize(__first, __last,
+			      std::__iterator_category(__first));
 	}
+#endif
 
       // Called by the second initialize_dispatch above
       template<typename _InputIterator>
@@ -1669,7 +1715,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       // moved, either because the source's allocator will move too
       // or because the allocators are equal.
       void
-      _M_move_assign(vector&& __x, std::true_type) noexcept
+      _M_move_assign(vector&& __x, true_type) noexcept
       {
 	vector __tmp(get_allocator());
 	this->_M_impl._M_swap_data(__tmp._M_impl);
@@ -1680,10 +1726,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       // Do move assignment when it might not be possible to move source
       // object's memory, resulting in a linear-time operation.
       void
-      _M_move_assign(vector&& __x, std::false_type)
+      _M_move_assign(vector&& __x, false_type)
       {
 	if (__x._M_get_Tp_allocator() == this->_M_get_Tp_allocator())
-	  _M_move_assign(std::move(__x), std::true_type());
+	  _M_move_assign(std::move(__x), true_type());
 	else
 	  {
 	    // The rvalue's allocator cannot be moved and is not equal,
diff --git a/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc b/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc
new file mode 100644
index 0000000..5981b8f
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc
@@ -0,0 +1,67 @@
+// Copyright (C) 2018 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/>.
+
+// { dg-do run { target c++11 } }
+// { dg-options "-O0" }
+// { dg-xfail-run-if "PR c++/65816" { *-*-* } }
+
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+#include <ext/aligned_buffer.h>
+
+using T = int;
+
+using __gnu_test::default_init_allocator;
+
+void test01()
+{
+  typedef default_init_allocator<T> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+
+  __gnu_cxx::__aligned_buffer<test_type> buf;
+  __builtin_memset(buf._M_addr(), ~0, sizeof(test_type));
+
+  test_type *tmp = ::new(buf._M_addr()) test_type;
+
+  VERIFY( tmp->get_allocator().state == 0 );
+
+  tmp->~test_type();
+}
+
+void test02()
+{
+  typedef default_init_allocator<T> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+
+  __gnu_cxx::__aligned_buffer<test_type> buf;
+  __builtin_memset(buf._M_addr(), ~0, sizeof(test_type));
+
+  test_type *tmp = ::new(buf._M_addr()) test_type();
+
+  VERIFY( tmp->get_allocator().state == 0 );
+
+  tmp->~test_type();
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: std::vector default default and move constructors
  2018-01-11  6:41     ` François Dumont
@ 2018-01-11  6:57       ` Marc Glisse
  2018-01-11  7:03         ` Marc Glisse
  2018-01-14 21:13         ` François Dumont
  0 siblings, 2 replies; 16+ messages in thread
From: Marc Glisse @ 2018-01-11  6:57 UTC (permalink / raw)
  To: François Dumont; +Cc: gcc-patches, libstdc++

On Thu, 11 Jan 2018, François Dumont wrote:

-       void _M_swap_data(_Vector_impl& __x) _GLIBCXX_NOEXCEPT
+       void
+       _M_swap_data(_Vector_impl_data& __x) _GLIBCXX_NOEXCEPT
         {
           std::swap(_M_start, __x._M_start);
           std::swap(_M_finish, __x._M_finish);
           std::swap(_M_end_of_storage, __x._M_end_of_storage);
         }


I don't remember earlier discussions about this patch, but is this piece 
of code still needed? std::swap(*this, __x) looks like it should work.

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: std::vector default default and move constructors
  2018-01-11  6:57       ` Marc Glisse
@ 2018-01-11  7:03         ` Marc Glisse
  2018-01-14 21:13         ` François Dumont
  1 sibling, 0 replies; 16+ messages in thread
From: Marc Glisse @ 2018-01-11  7:03 UTC (permalink / raw)
  To: libstdc++; +Cc: François Dumont, gcc-patches

On Thu, 11 Jan 2018, Marc Glisse wrote:

> On Thu, 11 Jan 2018, François Dumont wrote:
>
> -       void _M_swap_data(_Vector_impl& __x) _GLIBCXX_NOEXCEPT
> +       void
> +       _M_swap_data(_Vector_impl_data& __x) _GLIBCXX_NOEXCEPT
>        {
>          std::swap(_M_start, __x._M_start);
>          std::swap(_M_finish, __x._M_finish);
>          std::swap(_M_end_of_storage, __x._M_end_of_storage);
>        }
>
>
> I don't remember earlier discussions about this patch, but is this piece of 
> code still needed? std::swap(*this, __x) looks like it should work.

Ah, no, there is a non-trivial move constructor, so forget it. I'll still 
need to rewrite that function later :-(

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: std::vector default default and move constructors
  2018-01-11  6:57       ` Marc Glisse
  2018-01-11  7:03         ` Marc Glisse
@ 2018-01-14 21:13         ` François Dumont
  2018-01-15 12:29           ` Jonathan Wakely
  1 sibling, 1 reply; 16+ messages in thread
From: François Dumont @ 2018-01-14 21:13 UTC (permalink / raw)
  To: libstdc++

On 11/01/2018 07:57, Marc Glisse wrote:
> On Thu, 11 Jan 2018, François Dumont wrote:
>
> -       void _M_swap_data(_Vector_impl& __x) _GLIBCXX_NOEXCEPT
> +       void
> +       _M_swap_data(_Vector_impl_data& __x) _GLIBCXX_NOEXCEPT
>         {
>           std::swap(_M_start, __x._M_start);
>           std::swap(_M_finish, __x._M_finish);
>           std::swap(_M_end_of_storage, __x._M_end_of_storage);
>         }
>
>
> I don't remember earlier discussions about this patch, but is this 
> piece of code still needed? std::swap(*this, __x) looks like it should 
> work.
>
This patch has been arround for quite a long time now, initial 
submission was:

https://gcc.gnu.org/ml/libstdc++/2017-07/msg00060.html

even if I sent several updates since then.

François

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: std::vector default default and move constructors
  2018-01-14 21:13         ` François Dumont
@ 2018-01-15 12:29           ` Jonathan Wakely
  2018-01-15 21:33             ` François Dumont
  0 siblings, 1 reply; 16+ messages in thread
From: Jonathan Wakely @ 2018-01-15 12:29 UTC (permalink / raw)
  To: François Dumont; +Cc: libstdc++

On 14/01/18 22:13 +0100, François Dumont wrote:
>On 11/01/2018 07:57, Marc Glisse wrote:
>>On Thu, 11 Jan 2018, François Dumont wrote:
>>
>>-       void _M_swap_data(_Vector_impl& __x) _GLIBCXX_NOEXCEPT
>>+       void
>>+       _M_swap_data(_Vector_impl_data& __x) _GLIBCXX_NOEXCEPT
>>        {
>>          std::swap(_M_start, __x._M_start);
>>          std::swap(_M_finish, __x._M_finish);
>>          std::swap(_M_end_of_storage, __x._M_end_of_storage);
>>        }
>>
>>
>>I don't remember earlier discussions about this patch, but is this 
>>piece of code still needed? std::swap(*this, __x) looks like it 
>>should work.
>>
>This patch has been arround for quite a long time now, initial 
>submission was:
>
>https://gcc.gnu.org/ml/libstdc++/2017-07/msg00060.html
>
>even if I sent several updates since then.

I know, but it doesn't actually fix any bugs so has been low priority
and I've not been able to make time to finish reviewing it.

In fact it introduces a serious regression because of this line:

>-      vector(vector&& __x) noexcept
>-      : _Base(std::move(__x)) { }
>+      vector(vector&&) = default;

Consider what happens if we have an allocator that is not
nothrow-move-constructible, which can happen if the allocator has a
noexcept(false) move constructor, or more likely just has no move
constructor but has a noexcept(false) copy constructor:

#include <vector>

template<typename T> struct Alloc : std::allocator<T> {
  Alloc() { }
  Alloc(const Alloc&) { }
  template<typename U> Alloc(const Alloc<U>&) { }
  template<typename U> struct rebind { using other = Alloc<U>; };
};

int main()
{
  static_assert( std::is_nothrow_move_constructible<std::vector<int, Alloc<int>>>::value, "" );
}

The standard says this program must compile, and with current GCC
trunk it does compile.

After your change it fails, because the vector(vector&&) constructor
is not explicitly noexcept, instead it deduces its exception
specification from its base classes, which includes the allocator.

So we have a patch which moves a load of code around without fixing
any bugs, but violates the requirements of the standard. I know you
want to simplify the code by making some things implicit, but I don't
think that's always better. If the standard says vector(vector&&) MUST
be noexcept, then making it implicit is not an improvement. If we say
things explicitly we can be sure they are correct, and can check them
more easily just by inspecting the code. When everything is implicit
you need to spend more time analysing the code to check it does the
right thing. I had to carefully review every constructor in the class
hierarchy to find this new bug, but the code you want to change
required no effort to check the exception-specification was correct:

>-      vector(vector&& __x) noexcept


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: std::vector default default and move constructors
  2018-01-15 12:29           ` Jonathan Wakely
@ 2018-01-15 21:33             ` François Dumont
  2018-01-16  0:20               ` Jonathan Wakely
  0 siblings, 1 reply; 16+ messages in thread
From: François Dumont @ 2018-01-15 21:33 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++

On 15/01/2018 13:29, Jonathan Wakely wrote:
> On 14/01/18 22:13 +0100, François Dumont wrote:
>> On 11/01/2018 07:57, Marc Glisse wrote:
>>> On Thu, 11 Jan 2018, François Dumont wrote:
>>>
>>> -       void _M_swap_data(_Vector_impl& __x) _GLIBCXX_NOEXCEPT
>>> +       void
>>> +       _M_swap_data(_Vector_impl_data& __x) _GLIBCXX_NOEXCEPT
>>>         {
>>>           std::swap(_M_start, __x._M_start);
>>>           std::swap(_M_finish, __x._M_finish);
>>>           std::swap(_M_end_of_storage, __x._M_end_of_storage);
>>>         }
>>>
>>>
>>> I don't remember earlier discussions about this patch, but is this 
>>> piece of code still needed? std::swap(*this, __x) looks like it 
>>> should work.
>>>
>> This patch has been arround for quite a long time now, initial 
>> submission was:
>>
>> https://gcc.gnu.org/ml/libstdc++/2017-07/msg00060.html
>>
>> even if I sent several updates since then.
>
> I know, but it doesn't actually fix any bugs so has been low priority
> and I've not been able to make time to finish reviewing it.
No problem, it just make the implementation more compiler friendly by 
leaving as much job as possible to it.
>
> In fact it introduces a serious regression because of this line:
>
>> -      vector(vector&& __x) noexcept
>> -      : _Base(std::move(__x)) { }
>> +      vector(vector&&) = default;
>
> Consider what happens if we have an allocator that is not
> nothrow-move-constructible, which can happen if the allocator has a
> noexcept(false) move constructor, or more likely just has no move
> constructor but has a noexcept(false) copy constructor:
>
> #include <vector>
>
> template<typename T> struct Alloc : std::allocator<T> {
>  Alloc() { }
>  Alloc(const Alloc&) { }
>  template<typename U> Alloc(const Alloc<U>&) { }
>  template<typename U> struct rebind { using other = Alloc<U>; };
> };
>
> int main()
> {
>  static_assert( std::is_nothrow_move_constructible<std::vector<int, 
> Alloc<int>>>::value, "" );
> }
>
> The standard says this program must compile, and with current GCC
> trunk it does compile.
>
> After your change it fails, because the vector(vector&&) constructor
> is not explicitly noexcept, instead it deduces its exception
> specification from its base classes, which includes the allocator.

Shouldn't gcc raise a compilation error ? At least if the use 
explicitely qualified its alloc move constructor with noexcept(true).

I should be more careful when the Standard explicitely qualified 
constructor, and I might need an up to date version of the Standard too.

We can still write:

+      vector(vector&&) noexcept = default;

You already pointed to me recently on the istreambuf_iterator copy 
constructor that I needed to keep the noexcept qualification.

It can even be added on the _Vector_impl so that vector(vector&&) 
benefit from it but as you said it is better to make it explicit on the 
vector move constructor.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: std::vector default default and move constructors
  2018-01-15 21:33             ` François Dumont
@ 2018-01-16  0:20               ` Jonathan Wakely
  2018-01-18 21:01                 ` François Dumont
  2018-06-02 12:01                 ` François Dumont
  0 siblings, 2 replies; 16+ messages in thread
From: Jonathan Wakely @ 2018-01-16  0:20 UTC (permalink / raw)
  To: François Dumont; +Cc: libstdc++

On 15/01/18 22:32 +0100, François Dumont wrote:
>On 15/01/2018 13:29, Jonathan Wakely wrote:
>>On 14/01/18 22:13 +0100, François Dumont wrote:
>>>On 11/01/2018 07:57, Marc Glisse wrote:
>>>>On Thu, 11 Jan 2018, François Dumont wrote:
>>>>
>>>>-       void _M_swap_data(_Vector_impl& __x) _GLIBCXX_NOEXCEPT
>>>>+       void
>>>>+       _M_swap_data(_Vector_impl_data& __x) _GLIBCXX_NOEXCEPT
>>>>        {
>>>>          std::swap(_M_start, __x._M_start);
>>>>          std::swap(_M_finish, __x._M_finish);
>>>>          std::swap(_M_end_of_storage, __x._M_end_of_storage);
>>>>        }
>>>>
>>>>
>>>>I don't remember earlier discussions about this patch, but is 
>>>>this piece of code still needed? std::swap(*this, __x) looks 
>>>>like it should work.
>>>>
>>>This patch has been arround for quite a long time now, initial 
>>>submission was:
>>>
>>>https://gcc.gnu.org/ml/libstdc++/2017-07/msg00060.html
>>>
>>>even if I sent several updates since then.
>>
>>I know, but it doesn't actually fix any bugs so has been low priority
>>and I've not been able to make time to finish reviewing it.
>No problem, it just make the implementation more compiler friendly by 
>leaving as much job as possible to it.
>>
>>In fact it introduces a serious regression because of this line:
>>
>>>-      vector(vector&& __x) noexcept
>>>-      : _Base(std::move(__x)) { }
>>>+      vector(vector&&) = default;
>>
>>Consider what happens if we have an allocator that is not
>>nothrow-move-constructible, which can happen if the allocator has a
>>noexcept(false) move constructor, or more likely just has no move
>>constructor but has a noexcept(false) copy constructor:
>>
>>#include <vector>
>>
>>template<typename T> struct Alloc : std::allocator<T> {
>> Alloc() { }
>> Alloc(const Alloc&) { }
>> template<typename U> Alloc(const Alloc<U>&) { }
>> template<typename U> struct rebind { using other = Alloc<U>; };
>>};
>>
>>int main()
>>{
>> static_assert( std::is_nothrow_move_constructible<std::vector<int, 
>>Alloc<int>>>::value, "" );
>>}
>>
>>The standard says this program must compile, and with current GCC
>>trunk it does compile.
>>
>>After your change it fails, because the vector(vector&&) constructor
>>is not explicitly noexcept, instead it deduces its exception
>>specification from its base classes, which includes the allocator.
>
>Shouldn't gcc raise a compilation error ? At least if the use 
>explicitely qualified its alloc move constructor with noexcept(true).
>
>I should be more careful when the Standard explicitely qualified 
>constructor, and I might need an up to date version of the Standard 
>too.


The latest draft is always available from https://isocpp.org (on the
left sidebar).

>We can still write:
>
>+      vector(vector&&) noexcept = default;
>
>You already pointed to me recently on the istreambuf_iterator copy 
>constructor that I needed to keep the noexcept qualification.

That would still be implicitly noexcept(false) because of the base
class, but now you'd get an error because the explicit exception
specification doesn't match the implicit one.

>It can even be added on the _Vector_impl so that vector(vector&&) 
>benefit from it but as you said it is better to make it explicit on 
>the vector move constructor.

One of the move constructors needs to be defined with a function body,
not defaulted, so that it can also be declared noexcept.


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: std::vector default default and move constructors
  2018-01-16  0:20               ` Jonathan Wakely
@ 2018-01-18 21:01                 ` François Dumont
  2018-01-29 13:49                   ` Jonathan Wakely
  2018-06-02 12:01                 ` François Dumont
  1 sibling, 1 reply; 16+ messages in thread
From: François Dumont @ 2018-01-18 21:01 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1110 bytes --]

On 16/01/2018 01:20, Jonathan Wakely wrote:
> On 15/01/18 22:32 +0100, François Dumont wrote:
>> On 15/01/2018 13:29, Jonathan Wakely wrote:
>>> In fact it introduces a serious regression because of this line:
>>>
>>>> -      vector(vector&& __x) noexcept
>>>> -      : _Base(std::move(__x)) { }
>>>> +      vector(vector&&) = default;
>>>
>>> Consider what happens if we have an allocator that is not
>>> nothrow-move-constructible, which can happen if the allocator has a
>>> noexcept(false) move constructor, or more likely just has no move
>>> constructor but has a noexcept(false) copy constructor:
>>>
> One of the move constructors needs to be defined with a function body,
> not defaulted, so that it can also be declared noexcept

Here is an updated patch with this change. Do you also want an explicit 
noexcept on the vector(vector&&) default declaration ? Ok to commit this 
vector patch ?

I was going to propose a similar patch for vector<bool> but checking 
Standard there is not this noexcept qualification on the move constructor.

François


[-- Attachment #2: vector.patch --]
[-- Type: text/x-patch, Size: 12284 bytes --]

diff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h
index acec501..a6282ec 100644
--- a/libstdc++-v3/include/bits/stl_vector.h
+++ b/libstdc++-v3/include/bits/stl_vector.h
@@ -85,34 +85,56 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>::pointer
        	pointer;
 
-      struct _Vector_impl
-      : public _Tp_alloc_type
+      struct _Vector_impl_data
       {
 	pointer _M_start;
 	pointer _M_finish;
 	pointer _M_end_of_storage;
 
-	_Vector_impl()
-	: _Tp_alloc_type(), _M_start(), _M_finish(), _M_end_of_storage()
-	{ }
-
-	_Vector_impl(_Tp_alloc_type const& __a) _GLIBCXX_NOEXCEPT
-	: _Tp_alloc_type(__a), _M_start(), _M_finish(), _M_end_of_storage()
+	_Vector_impl_data() _GLIBCXX_NOEXCEPT
+	: _M_start(), _M_finish(), _M_end_of_storage()
 	{ }
 
 #if __cplusplus >= 201103L
-	_Vector_impl(_Tp_alloc_type&& __a) noexcept
-	: _Tp_alloc_type(std::move(__a)),
-	  _M_start(), _M_finish(), _M_end_of_storage()
-	{ }
+	_Vector_impl_data(_Vector_impl_data&& __x) noexcept
+	: _M_start(__x._M_start), _M_finish(__x._M_finish),
+	  _M_end_of_storage(__x._M_end_of_storage)
+	{ __x._M_start = __x._M_finish = __x._M_end_of_storage = pointer(); }
 #endif
 
-	void _M_swap_data(_Vector_impl& __x) _GLIBCXX_NOEXCEPT
+	void
+	_M_swap_data(_Vector_impl_data& __x) _GLIBCXX_NOEXCEPT
 	{
 	  std::swap(_M_start, __x._M_start);
 	  std::swap(_M_finish, __x._M_finish);
 	  std::swap(_M_end_of_storage, __x._M_end_of_storage);
 	}
+      };
+
+      struct _Vector_impl
+	: public _Tp_alloc_type, public _Vector_impl_data
+      {
+	_Vector_impl() _GLIBCXX_NOEXCEPT_IF( noexcept(_Tp_alloc_type()) )
+	: _Tp_alloc_type()
+	{ }
+
+	_Vector_impl(_Tp_alloc_type const& __a) _GLIBCXX_NOEXCEPT
+	: _Tp_alloc_type(__a)
+	{ }
+
+#if __cplusplus >= 201103L
+	_Vector_impl(_Vector_impl&& __x) noexcept
+	: _Tp_alloc_type(std::move(__x)), _Vector_impl_data(std::move(__x))
+	{ }
+
+	_Vector_impl(_Tp_alloc_type&& __a) noexcept
+	  : _Tp_alloc_type(std::move(__a))
+	{ }
+
+	_Vector_impl(_Tp_alloc_type&& __a, _Vector_impl&& __rv) noexcept
+	: _Tp_alloc_type(std::move(__a)), _Vector_impl_data(std::move(__rv))
+	{ }
+#endif
 
 #if _GLIBCXX_SANITIZE_STD_ALLOCATOR && _GLIBCXX_SANITIZE_VECTOR
 	template<typename = _Tp_alloc_type>
@@ -235,38 +257,42 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 
       _Tp_alloc_type&
       _M_get_Tp_allocator() _GLIBCXX_NOEXCEPT
-      { return *static_cast<_Tp_alloc_type*>(&this->_M_impl); }
+      { return this->_M_impl; }
 
       const _Tp_alloc_type&
       _M_get_Tp_allocator() const _GLIBCXX_NOEXCEPT
-      { return *static_cast<const _Tp_alloc_type*>(&this->_M_impl); }
+      { return this->_M_impl; }
 
       allocator_type
       get_allocator() const _GLIBCXX_NOEXCEPT
       { return allocator_type(_M_get_Tp_allocator()); }
 
-      _Vector_base()
-      : _M_impl() { }
+#if __cplusplus >= 201103L
+      _Vector_base() = default;
+#else
+      _Vector_base() { }
+#endif
 
       _Vector_base(const allocator_type& __a) _GLIBCXX_NOEXCEPT
       : _M_impl(__a) { }
 
+#if !_GLIBCXX_INLINE_VERSION
       _Vector_base(size_t __n)
       : _M_impl()
       { _M_create_storage(__n); }
+#endif
 
       _Vector_base(size_t __n, const allocator_type& __a)
       : _M_impl(__a)
       { _M_create_storage(__n); }
 
 #if __cplusplus >= 201103L
+      _Vector_base(_Vector_base&&) = default;
+
+# if !_GLIBCXX_INLINE_VERSION
       _Vector_base(_Tp_alloc_type&& __a) noexcept
       : _M_impl(std::move(__a)) { }
 
-      _Vector_base(_Vector_base&& __x) noexcept
-      : _M_impl(std::move(__x._M_get_Tp_allocator()))
-      { this->_M_impl._M_swap_data(__x._M_impl); }
-
       _Vector_base(_Vector_base&& __x, const allocator_type& __a)
       : _M_impl(__a)
       {
@@ -278,6 +304,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	    _M_create_storage(__n);
 	  }
       }
+# endif
+
+      _Vector_base(const allocator_type& __a, _Vector_base&& __x)
+      : _M_impl(_Tp_alloc_type(__a), std::move(__x._M_impl))
+      { }
 #endif
 
       ~_Vector_base() _GLIBCXX_NOEXCEPT
@@ -304,7 +335,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  _Tr::deallocate(_M_impl, __p, __n);
       }
 
-    private:
+    protected:
       void
       _M_create_storage(size_t __n)
       {
@@ -388,11 +419,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       /**
        *  @brief  Creates a %vector with no elements.
        */
-      vector()
 #if __cplusplus >= 201103L
-      noexcept(is_nothrow_default_constructible<_Alloc>::value)
+      vector() = default;
+#else
+      vector() { }
 #endif
-      : _Base() { }
 
       /**
        *  @brief  Creates a %vector with no elements.
@@ -468,13 +499,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 #if __cplusplus >= 201103L
       /**
        *  @brief  %Vector move constructor.
-       *  @param  __x  A %vector of identical element and allocator types.
        *
-       *  The newly-created %vector contains the exact contents of @a __x.
-       *  The contents of @a __x are a valid, but unspecified %vector.
+       *  The newly-created %vector contains the exact contents of the
+       *  moved instance.
+       *  The contents of the moved instance are a valid, but unspecified
+       *  %vector.
        */
-      vector(vector&& __x) noexcept
-      : _Base(std::move(__x)) { }
+      vector(vector&&) = default;
 
       /// Copy constructor with alternative allocator
       vector(const vector& __x, const allocator_type& __a)
@@ -486,13 +517,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 				      _M_get_Tp_allocator());
       }
 
-      /// Move constructor with alternative allocator
-      vector(vector&& __rv, const allocator_type& __m)
-      noexcept(_Alloc_traits::_S_always_equal())
-      : _Base(std::move(__rv), __m)
+    private:
+      vector(vector&& __rv, const allocator_type& __m, true_type) noexcept
+      : _Base(__m, std::move(__rv))
+      { }
+
+      vector(vector&& __rv, const allocator_type& __m, false_type)
+      : _Base(__m)
       {
-	if (__rv.get_allocator() != __m)
+	if (__rv.get_allocator() == __m)
+	  this->_M_impl._M_swap_data(__rv._M_impl);
+	else if (!__rv.empty())
 	  {
+	    this->_M_create_storage(__rv.size());
 	    this->_M_impl._M_finish =
 	      std::__uninitialized_move_a(__rv.begin(), __rv.end(),
 					  this->_M_impl._M_start,
@@ -501,6 +538,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  }
       }
 
+    public:
+      /// Move constructor with alternative allocator
+      vector(vector&& __rv, const allocator_type& __m)
+	noexcept(_Alloc_traits::_S_always_equal())
+      : vector(std::move(__rv), __m, typename _Alloc_traits::is_always_equal{})
+      { }
+
       /**
        *  @brief  Builds a %vector from an initializer list.
        *  @param  __l  An initializer_list.
@@ -543,7 +587,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	vector(_InputIterator __first, _InputIterator __last,
 	       const allocator_type& __a = allocator_type())
 	: _Base(__a)
-	{ _M_initialize_dispatch(__first, __last, __false_type()); }
+	{
+	  _M_range_initialize(__first, __last,
+			      std::__iterator_category(__first));
+	}
 #else
       template<typename _InputIterator>
 	vector(_InputIterator __first, _InputIterator __last,
@@ -1414,6 +1461,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 
       // Called by the range constructor to implement [23.1.1]/9
 
+#if __cplusplus < 201103L
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // 438. Ambiguity in the "do the right thing" clause
       template<typename _Integer>
@@ -1432,10 +1480,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	_M_initialize_dispatch(_InputIterator __first, _InputIterator __last,
 			       __false_type)
 	{
-	  typedef typename std::iterator_traits<_InputIterator>::
-	    iterator_category _IterCategory;
-	  _M_range_initialize(__first, __last, _IterCategory());
+	  _M_range_initialize(__first, __last,
+			      std::__iterator_category(__first));
 	}
+#endif
 
       // Called by the second initialize_dispatch above
       template<typename _InputIterator>
@@ -1669,7 +1717,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       // moved, either because the source's allocator will move too
       // or because the allocators are equal.
       void
-      _M_move_assign(vector&& __x, std::true_type) noexcept
+      _M_move_assign(vector&& __x, true_type) noexcept
       {
 	vector __tmp(get_allocator());
 	this->_M_impl._M_swap_data(__tmp._M_impl);
@@ -1680,10 +1728,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       // Do move assignment when it might not be possible to move source
       // object's memory, resulting in a linear-time operation.
       void
-      _M_move_assign(vector&& __x, std::false_type)
+      _M_move_assign(vector&& __x, false_type)
       {
 	if (__x._M_get_Tp_allocator() == this->_M_get_Tp_allocator())
-	  _M_move_assign(std::move(__x), std::true_type());
+	  _M_move_assign(std::move(__x), true_type());
 	else
 	  {
 	    // The rvalue's allocator cannot be moved and is not equal,
diff --git a/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc b/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc
new file mode 100644
index 0000000..5981b8f
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc
@@ -0,0 +1,67 @@
+// Copyright (C) 2018 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/>.
+
+// { dg-do run { target c++11 } }
+// { dg-options "-O0" }
+// { dg-xfail-run-if "PR c++/65816" { *-*-* } }
+
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+#include <ext/aligned_buffer.h>
+
+using T = int;
+
+using __gnu_test::default_init_allocator;
+
+void test01()
+{
+  typedef default_init_allocator<T> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+
+  __gnu_cxx::__aligned_buffer<test_type> buf;
+  __builtin_memset(buf._M_addr(), ~0, sizeof(test_type));
+
+  test_type *tmp = ::new(buf._M_addr()) test_type;
+
+  VERIFY( tmp->get_allocator().state == 0 );
+
+  tmp->~test_type();
+}
+
+void test02()
+{
+  typedef default_init_allocator<T> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+
+  __gnu_cxx::__aligned_buffer<test_type> buf;
+  __builtin_memset(buf._M_addr(), ~0, sizeof(test_type));
+
+  test_type *tmp = ::new(buf._M_addr()) test_type();
+
+  VERIFY( tmp->get_allocator().state == 0 );
+
+  tmp->~test_type();
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/cons/noexcept_move_construct.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/noexcept_move_construct.cc
index f8f71a5..268a46c 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/cons/noexcept_move_construct.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/cons/noexcept_move_construct.cc
@@ -24,3 +24,22 @@
 typedef std::vector<int> vtype;
 
 static_assert(std::is_nothrow_move_constructible<vtype>::value, "Error");
+
+template<typename Type>
+  class NoExceptMoveConstructorAlloc : public std::allocator<Type>
+  {
+  public:
+    NoExceptMoveConstructorAlloc() = default;
+    NoExceptMoveConstructorAlloc(const NoExceptMoveConstructorAlloc&) = default;
+    NoExceptMoveConstructorAlloc(NoExceptMoveConstructorAlloc&& __x) noexcept(false)
+    : std::allocator<Type>(std::move(__x))
+    { }
+
+    template<typename _Tp1>
+      struct rebind
+      { typedef NoExceptMoveConstructorAlloc<_Tp1> other; };
+  };
+
+typedef std::vector<int, NoExceptMoveConstructorAlloc<int>> vtype2;
+
+static_assert(std::is_nothrow_move_constructible<vtype2>::value, "Error");


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: std::vector default default and move constructors
  2018-01-18 21:01                 ` François Dumont
@ 2018-01-29 13:49                   ` Jonathan Wakely
  0 siblings, 0 replies; 16+ messages in thread
From: Jonathan Wakely @ 2018-01-29 13:49 UTC (permalink / raw)
  To: François Dumont; +Cc: libstdc++, gcc-patches

On 18/01/18 22:01 +0100, François Dumont wrote:
>On 16/01/2018 01:20, Jonathan Wakely wrote:
>>On 15/01/18 22:32 +0100, François Dumont wrote:
>>>On 15/01/2018 13:29, Jonathan Wakely wrote:
>>>>In fact it introduces a serious regression because of this line:
>>>>
>>>>>-      vector(vector&& __x) noexcept
>>>>>-      : _Base(std::move(__x)) { }
>>>>>+      vector(vector&&) = default;
>>>>
>>>>Consider what happens if we have an allocator that is not
>>>>nothrow-move-constructible, which can happen if the allocator has a
>>>>noexcept(false) move constructor, or more likely just has no move
>>>>constructor but has a noexcept(false) copy constructor:
>>>>
>>One of the move constructors needs to be defined with a function body,
>>not defaulted, so that it can also be declared noexcept
>
>Here is an updated patch with this change. Do you also want an 
>explicit noexcept on the vector(vector&&) default declaration ?

Yes please.

>Ok to commit this vector patch ?

Please wait for Stage 1, it's too late for changes that don't fix any
bugs and risk introducing new ones.

>I was going to propose a similar patch for vector<bool> but checking 
>Standard there is not this noexcept qualification on the move 
>constructor.

We can strengthen noexcept guarantees, but we can't weaken them, so
it's OK to add it to vector<bool> if our implementation cannot throw.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: std::vector default default and move constructors
  2018-01-16  0:20               ` Jonathan Wakely
  2018-01-18 21:01                 ` François Dumont
@ 2018-06-02 12:01                 ` François Dumont
  2018-06-26 13:46                   ` Jonathan Wakely
  1 sibling, 1 reply; 16+ messages in thread
From: François Dumont @ 2018-06-02 12:01 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1801 bytes --]

Hi

     Here is this patch again, I consider all your remarks and also made 
some changes considering feedback on rbtree patch.

     * include/bits/stl_vector.h
     (struct _Vector_base<>::_Vector_impl_data): New.
     (struct _Vector_base<>::_Vector_impl): Inherit from latter.
     (_Vector_base<>::_Vector_impl::_M_swap_data): Move...
     (_Vector_base<>::_Vector_impl_data::_M_swap_data): ...here.
     (_Vector_base<>::_Vector_impl()): Add noexcept qualification.
     (_Vector_base<>::_Vector_impl(_Vector_impl&&)): New.
     (_Vector_base<>::_Vector_impl(_Tp_alloc_type&&, _Vector_impl&&)): New.
     (_Vector_base(const allocator_type&, _Vector_base&&)): New, use latter.
     (_Vector_base()): Default.
     (_Vector_base(_Vector_base&&)): Default.
     (_Vector_base(size_t)) [_GLIBCXX_INLINE_VERSION]: Delete.
     (_Vector_base(_Tp_alloc_type&&)) [_GLIBCXX_INLINE_VERSION]: Delete.
     (_Vector_base::_M_create_storage(size_t)): Make protected.
     (vector()): Default.
     (vector(vector&&)): Default.
     (vector(vector&&, const allocator_type&, true_type)): New.
     (vector(vector&&, const allocator_type&, false_type)): New.
     (vector(vector&&, const allocator_type&)): Use latters.
     (vector(_InputIte, _InputIte, const allocator_type&)): Call
     _M_range_initialize directly.
     * testsuite/23_containers/vector/allocator/default_init.cc: New.
     * testsuite/23_containers/vector/cons/noexcept_move_construct.cc: Add
     static assertions.

     Tested under Linux x86_64, normal and debug modes.

Ok to commit ?

François

[-- Attachment #2: vector.patch --]
[-- Type: text/x-patch, Size: 12966 bytes --]

diff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h
index acec501..7531ef4 100644
--- a/libstdc++-v3/include/bits/stl_vector.h
+++ b/libstdc++-v3/include/bits/stl_vector.h
@@ -85,34 +85,58 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>::pointer
        	pointer;
 
-      struct _Vector_impl
-      : public _Tp_alloc_type
+      struct _Vector_impl_data
       {
 	pointer _M_start;
 	pointer _M_finish;
 	pointer _M_end_of_storage;
 
-	_Vector_impl()
-	: _Tp_alloc_type(), _M_start(), _M_finish(), _M_end_of_storage()
-	{ }
-
-	_Vector_impl(_Tp_alloc_type const& __a) _GLIBCXX_NOEXCEPT
-	: _Tp_alloc_type(__a), _M_start(), _M_finish(), _M_end_of_storage()
+	_Vector_impl_data() _GLIBCXX_NOEXCEPT
+	: _M_start(), _M_finish(), _M_end_of_storage()
 	{ }
 
 #if __cplusplus >= 201103L
-	_Vector_impl(_Tp_alloc_type&& __a) noexcept
-	: _Tp_alloc_type(std::move(__a)),
-	  _M_start(), _M_finish(), _M_end_of_storage()
-	{ }
+	_Vector_impl_data(_Vector_impl_data&& __x) noexcept
+	: _M_start(__x._M_start), _M_finish(__x._M_finish),
+	  _M_end_of_storage(__x._M_end_of_storage)
+	{ __x._M_start = __x._M_finish = __x._M_end_of_storage = pointer(); }
 #endif
 
-	void _M_swap_data(_Vector_impl& __x) _GLIBCXX_NOEXCEPT
+	void
+	_M_swap_data(_Vector_impl_data& __x) _GLIBCXX_NOEXCEPT
 	{
 	  std::swap(_M_start, __x._M_start);
 	  std::swap(_M_finish, __x._M_finish);
 	  std::swap(_M_end_of_storage, __x._M_end_of_storage);
 	}
+      };
+
+      struct _Vector_impl
+	: public _Tp_alloc_type, public _Vector_impl_data
+      {
+	_Vector_impl() _GLIBCXX_NOEXCEPT_IF( noexcept(_Tp_alloc_type()) )
+	: _Tp_alloc_type()
+	{ }
+
+	_Vector_impl(_Tp_alloc_type const& __a) _GLIBCXX_NOEXCEPT
+	: _Tp_alloc_type(__a)
+	{ }
+
+#if __cplusplus >= 201103L
+	// Not defaulted to avoid noexcept qualification dependency on the
+	// _Tp_alloc_type move constructor one.
+	_Vector_impl(_Vector_impl&& __x) noexcept
+	: _Tp_alloc_type(std::move(__x)), _Vector_impl_data(std::move(__x))
+	{ }
+
+	_Vector_impl(_Tp_alloc_type&& __a) noexcept
+	: _Tp_alloc_type(std::move(__a))
+	{ }
+
+	_Vector_impl(_Tp_alloc_type&& __a, _Vector_impl&& __rv) noexcept
+	: _Tp_alloc_type(std::move(__a)), _Vector_impl_data(std::move(__rv))
+	{ }
+#endif
 
 #if _GLIBCXX_SANITIZE_STD_ALLOCATOR && _GLIBCXX_SANITIZE_VECTOR
 	template<typename = _Tp_alloc_type>
@@ -235,38 +259,42 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 
       _Tp_alloc_type&
       _M_get_Tp_allocator() _GLIBCXX_NOEXCEPT
-      { return *static_cast<_Tp_alloc_type*>(&this->_M_impl); }
+      { return this->_M_impl; }
 
       const _Tp_alloc_type&
       _M_get_Tp_allocator() const _GLIBCXX_NOEXCEPT
-      { return *static_cast<const _Tp_alloc_type*>(&this->_M_impl); }
+      { return this->_M_impl; }
 
       allocator_type
       get_allocator() const _GLIBCXX_NOEXCEPT
       { return allocator_type(_M_get_Tp_allocator()); }
 
-      _Vector_base()
-      : _M_impl() { }
+#if __cplusplus >= 201103L
+      _Vector_base() = default;
+#else
+      _Vector_base() { }
+#endif
 
       _Vector_base(const allocator_type& __a) _GLIBCXX_NOEXCEPT
       : _M_impl(__a) { }
 
+#if !_GLIBCXX_INLINE_VERSION
       _Vector_base(size_t __n)
       : _M_impl()
       { _M_create_storage(__n); }
+#endif
 
       _Vector_base(size_t __n, const allocator_type& __a)
       : _M_impl(__a)
       { _M_create_storage(__n); }
 
 #if __cplusplus >= 201103L
+      _Vector_base(_Vector_base&&) = default;
+
+# if !_GLIBCXX_INLINE_VERSION
       _Vector_base(_Tp_alloc_type&& __a) noexcept
       : _M_impl(std::move(__a)) { }
 
-      _Vector_base(_Vector_base&& __x) noexcept
-      : _M_impl(std::move(__x._M_get_Tp_allocator()))
-      { this->_M_impl._M_swap_data(__x._M_impl); }
-
       _Vector_base(_Vector_base&& __x, const allocator_type& __a)
       : _M_impl(__a)
       {
@@ -278,6 +306,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	    _M_create_storage(__n);
 	  }
       }
+# endif
+
+      _Vector_base(const allocator_type& __a, _Vector_base&& __x)
+      : _M_impl(_Tp_alloc_type(__a), std::move(__x._M_impl))
+      { }
 #endif
 
       ~_Vector_base() _GLIBCXX_NOEXCEPT
@@ -304,7 +337,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  _Tr::deallocate(_M_impl, __p, __n);
       }
 
-    private:
+    protected:
       void
       _M_create_storage(size_t __n)
       {
@@ -388,11 +421,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       /**
        *  @brief  Creates a %vector with no elements.
        */
-      vector()
 #if __cplusplus >= 201103L
-      noexcept(is_nothrow_default_constructible<_Alloc>::value)
+      vector() = default;
+#else
+      vector() { }
 #endif
-      : _Base() { }
 
       /**
        *  @brief  Creates a %vector with no elements.
@@ -468,13 +501,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 #if __cplusplus >= 201103L
       /**
        *  @brief  %Vector move constructor.
-       *  @param  __x  A %vector of identical element and allocator types.
        *
-       *  The newly-created %vector contains the exact contents of @a __x.
-       *  The contents of @a __x are a valid, but unspecified %vector.
+       *  The newly-created %vector contains the exact contents of the
+       *  moved instance.
+       *  The contents of the moved instance are a valid, but unspecified
+       *  %vector.
        */
-      vector(vector&& __x) noexcept
-      : _Base(std::move(__x)) { }
+      vector(vector&&) noexcept = default;
 
       /// Copy constructor with alternative allocator
       vector(const vector& __x, const allocator_type& __a)
@@ -486,13 +519,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 				      _M_get_Tp_allocator());
       }
 
-      /// Move constructor with alternative allocator
-      vector(vector&& __rv, const allocator_type& __m)
-      noexcept(_Alloc_traits::_S_always_equal())
-      : _Base(std::move(__rv), __m)
+    private:
+      vector(vector&& __rv, const allocator_type& __m, true_type) noexcept
+      : _Base(__m, std::move(__rv))
+      { }
+
+      vector(vector&& __rv, const allocator_type& __m, false_type)
+      : _Base(__m)
       {
-	if (__rv.get_allocator() != __m)
+	if (__rv.get_allocator() == __m)
+	  this->_M_impl._M_swap_data(__rv._M_impl);
+	else if (!__rv.empty())
 	  {
+	    this->_M_create_storage(__rv.size());
 	    this->_M_impl._M_finish =
 	      std::__uninitialized_move_a(__rv.begin(), __rv.end(),
 					  this->_M_impl._M_start,
@@ -501,6 +540,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  }
       }
 
+    public:
+      /// Move constructor with alternative allocator
+      vector(vector&& __rv, const allocator_type& __m)
+      noexcept( noexcept(
+	vector(std::declval<vector&&>(), std::declval<const allocator_type&>(),
+	       std::declval<typename _Alloc_traits::is_always_equal>())) )
+      : vector(std::move(__rv), __m, typename _Alloc_traits::is_always_equal{})
+      { }
+
       /**
        *  @brief  Builds a %vector from an initializer list.
        *  @param  __l  An initializer_list.
@@ -543,7 +591,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	vector(_InputIterator __first, _InputIterator __last,
 	       const allocator_type& __a = allocator_type())
 	: _Base(__a)
-	{ _M_initialize_dispatch(__first, __last, __false_type()); }
+	{
+	  _M_range_initialize(__first, __last,
+			      std::__iterator_category(__first));
+	}
 #else
       template<typename _InputIterator>
 	vector(_InputIterator __first, _InputIterator __last,
@@ -1414,6 +1465,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 
       // Called by the range constructor to implement [23.1.1]/9
 
+#if __cplusplus < 201103L
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // 438. Ambiguity in the "do the right thing" clause
       template<typename _Integer>
@@ -1432,10 +1484,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	_M_initialize_dispatch(_InputIterator __first, _InputIterator __last,
 			       __false_type)
 	{
-	  typedef typename std::iterator_traits<_InputIterator>::
-	    iterator_category _IterCategory;
-	  _M_range_initialize(__first, __last, _IterCategory());
+	  _M_range_initialize(__first, __last,
+			      std::__iterator_category(__first));
 	}
+#endif
 
       // Called by the second initialize_dispatch above
       template<typename _InputIterator>
@@ -1669,7 +1721,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       // moved, either because the source's allocator will move too
       // or because the allocators are equal.
       void
-      _M_move_assign(vector&& __x, std::true_type) noexcept
+      _M_move_assign(vector&& __x, true_type) noexcept
       {
 	vector __tmp(get_allocator());
 	this->_M_impl._M_swap_data(__tmp._M_impl);
@@ -1680,10 +1732,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       // Do move assignment when it might not be possible to move source
       // object's memory, resulting in a linear-time operation.
       void
-      _M_move_assign(vector&& __x, std::false_type)
+      _M_move_assign(vector&& __x, false_type)
       {
 	if (__x._M_get_Tp_allocator() == this->_M_get_Tp_allocator())
-	  _M_move_assign(std::move(__x), std::true_type());
+	  _M_move_assign(std::move(__x), true_type());
 	else
 	  {
 	    // The rvalue's allocator cannot be moved and is not equal,
diff --git a/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc b/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc
new file mode 100644
index 0000000..5981b8f
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc
@@ -0,0 +1,67 @@
+// Copyright (C) 2018 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/>.
+
+// { dg-do run { target c++11 } }
+// { dg-options "-O0" }
+// { dg-xfail-run-if "PR c++/65816" { *-*-* } }
+
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+#include <ext/aligned_buffer.h>
+
+using T = int;
+
+using __gnu_test::default_init_allocator;
+
+void test01()
+{
+  typedef default_init_allocator<T> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+
+  __gnu_cxx::__aligned_buffer<test_type> buf;
+  __builtin_memset(buf._M_addr(), ~0, sizeof(test_type));
+
+  test_type *tmp = ::new(buf._M_addr()) test_type;
+
+  VERIFY( tmp->get_allocator().state == 0 );
+
+  tmp->~test_type();
+}
+
+void test02()
+{
+  typedef default_init_allocator<T> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+
+  __gnu_cxx::__aligned_buffer<test_type> buf;
+  __builtin_memset(buf._M_addr(), ~0, sizeof(test_type));
+
+  test_type *tmp = ::new(buf._M_addr()) test_type();
+
+  VERIFY( tmp->get_allocator().state == 0 );
+
+  tmp->~test_type();
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/cons/noexcept_move_construct.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/noexcept_move_construct.cc
index f8f71a5..4d41486 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/cons/noexcept_move_construct.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/cons/noexcept_move_construct.cc
@@ -23,4 +23,34 @@
 
 typedef std::vector<int> vtype;
 
-static_assert(std::is_nothrow_move_constructible<vtype>::value, "Error");
+static_assert( std::is_nothrow_move_constructible<vtype>::value,
+	       "noexcept move constructor" );
+static_assert( std::is_nothrow_constructible<vtype,
+	       vtype&&, const typename vtype::allocator_type&>::value,
+	       "noexcept move constructor with allocator" );
+
+template<typename Type>
+  class not_noexcept_move_constructor_alloc : public std::allocator<Type>
+  {
+  public:
+    not_noexcept_move_constructor_alloc() noexcept { }
+
+    not_noexcept_move_constructor_alloc(
+	const not_noexcept_move_constructor_alloc& x) noexcept
+    : std::allocator<Type>(x)
+    { }
+
+    not_noexcept_move_constructor_alloc(
+	not_noexcept_move_constructor_alloc&& x) noexcept(false)
+    : std::allocator<Type>(std::move(x))
+    { }
+
+    template<typename _Tp1>
+      struct rebind
+      { typedef not_noexcept_move_constructor_alloc<_Tp1> other; };
+  };
+
+typedef std::vector<int, not_noexcept_move_constructor_alloc<int>> vtype2;
+
+static_assert( std::is_nothrow_move_constructible<vtype2>::value,
+	       "noexcept move constructor with not noexcept alloc" );

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: std::vector default default and move constructors
  2018-06-02 12:01                 ` François Dumont
@ 2018-06-26 13:46                   ` Jonathan Wakely
  2018-06-27 20:27                     ` François Dumont
  0 siblings, 1 reply; 16+ messages in thread
From: Jonathan Wakely @ 2018-06-26 13:46 UTC (permalink / raw)
  To: François Dumont; +Cc: libstdc++, gcc-patches

On 02/06/18 14:00 +0200, François Dumont wrote:
>Hi
>
>    Here is this patch again, I consider all your remarks and also 
>made some changes considering feedback on rbtree patch.



>+	_Vector_impl(_Tp_alloc_type const& __a) _GLIBCXX_NOEXCEPT
>+	: _Tp_alloc_type(__a)
>+	{ }
>+
>+#if __cplusplus >= 201103L
>+	// Not defaulted to avoid noexcept qualification dependency on the
>+	// _Tp_alloc_type move constructor one.

Could you please rephrase this comment as:

        // Not defaulted, to enforce noexcept(true) even when
        // !is_nothrow_move_constructible<_Tp_alloc_type>.

I prefer this wording, because most allocators don't have a move
constructor at all (just a copy constructor) so talking about its move
constructor is misleading.

>+	_Vector_impl(_Vector_impl&& __x) noexcept
>+	: _Tp_alloc_type(std::move(__x)), _Vector_impl_data(std::move(__x))
>+	{ }
>+
>+	_Vector_impl(_Tp_alloc_type&& __a) noexcept
>+	: _Tp_alloc_type(std::move(__a))
>+	{ }
>+
>+	_Vector_impl(_Tp_alloc_type&& __a, _Vector_impl&& __rv) noexcept
>+	: _Tp_alloc_type(std::move(__a)), _Vector_impl_data(std::move(__rv))
>+	{ }
>+#endif
> 
> #if _GLIBCXX_SANITIZE_STD_ALLOCATOR && _GLIBCXX_SANITIZE_VECTOR
> 	template<typename = _Tp_alloc_type>
>@@ -235,38 +259,42 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
> 
>       _Tp_alloc_type&
>       _M_get_Tp_allocator() _GLIBCXX_NOEXCEPT
>-      { return *static_cast<_Tp_alloc_type*>(&this->_M_impl); }
>+      { return this->_M_impl; }
> 
>       const _Tp_alloc_type&
>       _M_get_Tp_allocator() const _GLIBCXX_NOEXCEPT
>-      { return *static_cast<const _Tp_alloc_type*>(&this->_M_impl); }
>+      { return this->_M_impl; }
> 
>       allocator_type
>       get_allocator() const _GLIBCXX_NOEXCEPT
>       { return allocator_type(_M_get_Tp_allocator()); }
> 
>-      _Vector_base()
>-      : _M_impl() { }
>+#if __cplusplus >= 201103L
>+      _Vector_base() = default;
>+#else
>+      _Vector_base() { }
>+#endif
> 
>       _Vector_base(const allocator_type& __a) _GLIBCXX_NOEXCEPT
>       : _M_impl(__a) { }

Please add "// Kept for ABI compatibility" before this #if:

>+#if !_GLIBCXX_INLINE_VERSION
>       _Vector_base(size_t __n)
>       : _M_impl()
>       { _M_create_storage(__n); }
>+#endif
> 
>       _Vector_base(size_t __n, const allocator_type& __a)
>       : _M_impl(__a)
>       { _M_create_storage(__n); }
> 
> #if __cplusplus >= 201103L
>+      _Vector_base(_Vector_base&&) = default;
>+

And here too:

>+# if !_GLIBCXX_INLINE_VERSION
>       _Vector_base(_Tp_alloc_type&& __a) noexcept
>       : _M_impl(std::move(__a)) { }


OK for trunk with those three comment changes.

Thanks for your patience waiting for the review.




^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: std::vector default default and move constructors
  2018-06-26 13:46                   ` Jonathan Wakely
@ 2018-06-27 20:27                     ` François Dumont
  0 siblings, 0 replies; 16+ messages in thread
From: François Dumont @ 2018-06-27 20:27 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 5355 bytes --]

Commited attached patch.

It fixes the missing noexcept qualification on a __gnu_debug::vector<> 
constructor.

2018-06-27  François Dumont  <fdumont@gcc.gnu.org>

     * include/bits/stl_vector.h
     (struct _Vector_base<>::_Vector_impl_data): New.
     (struct _Vector_base<>::_Vector_impl): Inherit from latter.
     (_Vector_base<>::_Vector_impl::_M_swap_data): Move...
     (_Vector_base<>::_Vector_impl_data::_M_swap_data): ...here.
     (_Vector_base<>::_Vector_impl()): Add noexcept qualification.
     (_Vector_base<>::_Vector_impl(_Vector_impl&&)): New.
     (_Vector_base<>::_Vector_impl(_Tp_alloc_type&&, _Vector_impl&&)): New.
     (_Vector_base(const allocator_type&, _Vector_base&&)): New, use latter.
     (_Vector_base()): Default.
     (_Vector_base(_Vector_base&&)): Default.
     (_Vector_base(size_t)) [_GLIBCXX_INLINE_VERSION]: Delete.
     (_Vector_base(_Tp_alloc_type&&)) [_GLIBCXX_INLINE_VERSION]: Delete.
     (_Vector_base::_M_create_storage(size_t)): Make protected.
     (vector()): Default.
     (vector(vector&&)): Default.
     (vector(vector&&, const allocator_type&, true_type)): New.
     (vector(vector&&, const allocator_type&, false_type)): New.
     (vector(vector&&, const allocator_type&)): Use latters.
     (vector(_InputIte, _InputIte, const allocator_type&)): Call
     _M_range_initialize directly.
     * include/debug/vector
     (vector(vector&&, const allocator_type&)): Add noexcept qualification.
     * testsuite/23_containers/vector/allocator/default_init.cc: New.
     * testsuite/23_containers/vector/cons/noexcept_move_construct.cc: Add
     static assertions.

On 26/06/2018 15:46, Jonathan Wakely wrote:
> On 02/06/18 14:00 +0200, François Dumont wrote:
>> Hi
>>
>>     Here is this patch again, I consider all your remarks and also 
>> made some changes considering feedback on rbtree patch.
>
>
>
>> +    _Vector_impl(_Tp_alloc_type const& __a) _GLIBCXX_NOEXCEPT
>> +    : _Tp_alloc_type(__a)
>> +    { }
>> +
>> +#if __cplusplus >= 201103L
>> +    // Not defaulted to avoid noexcept qualification dependency on the
>> +    // _Tp_alloc_type move constructor one.
>
> Could you please rephrase this comment as:
>
>        // Not defaulted, to enforce noexcept(true) even when
>        // !is_nothrow_move_constructible<_Tp_alloc_type>.
>
> I prefer this wording, because most allocators don't have a move
> constructor at all (just a copy constructor) so talking about its move
> constructor is misleading.
>
>> +    _Vector_impl(_Vector_impl&& __x) noexcept
>> +    : _Tp_alloc_type(std::move(__x)), _Vector_impl_data(std::move(__x))
>> +    { }
>> +
>> +    _Vector_impl(_Tp_alloc_type&& __a) noexcept
>> +    : _Tp_alloc_type(std::move(__a))
>> +    { }
>> +
>> +    _Vector_impl(_Tp_alloc_type&& __a, _Vector_impl&& __rv) noexcept
>> +    : _Tp_alloc_type(std::move(__a)), 
>> _Vector_impl_data(std::move(__rv))
>> +    { }
>> +#endif
>>
>> #if _GLIBCXX_SANITIZE_STD_ALLOCATOR && _GLIBCXX_SANITIZE_VECTOR
>>     template<typename = _Tp_alloc_type>
>> @@ -235,38 +259,42 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
>>
>>       _Tp_alloc_type&
>>       _M_get_Tp_allocator() _GLIBCXX_NOEXCEPT
>> -      { return *static_cast<_Tp_alloc_type*>(&this->_M_impl); }
>> +      { return this->_M_impl; }
>>
>>       const _Tp_alloc_type&
>>       _M_get_Tp_allocator() const _GLIBCXX_NOEXCEPT
>> -      { return *static_cast<const _Tp_alloc_type*>(&this->_M_impl); }
>> +      { return this->_M_impl; }
>>
>>       allocator_type
>>       get_allocator() const _GLIBCXX_NOEXCEPT
>>       { return allocator_type(_M_get_Tp_allocator()); }
>>
>> -      _Vector_base()
>> -      : _M_impl() { }
>> +#if __cplusplus >= 201103L
>> +      _Vector_base() = default;
>> +#else
>> +      _Vector_base() { }
>> +#endif
>>
>>       _Vector_base(const allocator_type& __a) _GLIBCXX_NOEXCEPT
>>       : _M_impl(__a) { }
>
> Please add "// Kept for ABI compatibility" before this #if:
>
>> +#if !_GLIBCXX_INLINE_VERSION
>>       _Vector_base(size_t __n)
>>       : _M_impl()
>>       { _M_create_storage(__n); }
>> +#endif
>>
>>       _Vector_base(size_t __n, const allocator_type& __a)
>>       : _M_impl(__a)
>>       { _M_create_storage(__n); }
>>
>> #if __cplusplus >= 201103L
>> +      _Vector_base(_Vector_base&&) = default;
>> +
>
> And here too:
>
>> +# if !_GLIBCXX_INLINE_VERSION
>>       _Vector_base(_Tp_alloc_type&& __a) noexcept
>>       : _M_impl(std::move(__a)) { }
>
>
> OK for trunk with those three comment changes.
>
> Thanks for your patience waiting for the review.
>
>
>
>
>


[-- Attachment #2: vector.patch --]
[-- Type: text/x-patch, Size: 13578 bytes --]

diff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h
index acec501..76829fa 100644
--- a/libstdc++-v3/include/bits/stl_vector.h
+++ b/libstdc++-v3/include/bits/stl_vector.h
@@ -85,34 +85,58 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>::pointer
        	pointer;
 
-      struct _Vector_impl
-      : public _Tp_alloc_type
+      struct _Vector_impl_data
       {
 	pointer _M_start;
 	pointer _M_finish;
 	pointer _M_end_of_storage;
 
-	_Vector_impl()
-	: _Tp_alloc_type(), _M_start(), _M_finish(), _M_end_of_storage()
-	{ }
-
-	_Vector_impl(_Tp_alloc_type const& __a) _GLIBCXX_NOEXCEPT
-	: _Tp_alloc_type(__a), _M_start(), _M_finish(), _M_end_of_storage()
+	_Vector_impl_data() _GLIBCXX_NOEXCEPT
+	: _M_start(), _M_finish(), _M_end_of_storage()
 	{ }
 
 #if __cplusplus >= 201103L
-	_Vector_impl(_Tp_alloc_type&& __a) noexcept
-	: _Tp_alloc_type(std::move(__a)),
-	  _M_start(), _M_finish(), _M_end_of_storage()
-	{ }
+	_Vector_impl_data(_Vector_impl_data&& __x) noexcept
+	: _M_start(__x._M_start), _M_finish(__x._M_finish),
+	  _M_end_of_storage(__x._M_end_of_storage)
+	{ __x._M_start = __x._M_finish = __x._M_end_of_storage = pointer(); }
 #endif
 
-	void _M_swap_data(_Vector_impl& __x) _GLIBCXX_NOEXCEPT
+	void
+	_M_swap_data(_Vector_impl_data& __x) _GLIBCXX_NOEXCEPT
 	{
 	  std::swap(_M_start, __x._M_start);
 	  std::swap(_M_finish, __x._M_finish);
 	  std::swap(_M_end_of_storage, __x._M_end_of_storage);
 	}
+      };
+
+      struct _Vector_impl
+	: public _Tp_alloc_type, public _Vector_impl_data
+      {
+	_Vector_impl() _GLIBCXX_NOEXCEPT_IF( noexcept(_Tp_alloc_type()) )
+	: _Tp_alloc_type()
+	{ }
+
+	_Vector_impl(_Tp_alloc_type const& __a) _GLIBCXX_NOEXCEPT
+	: _Tp_alloc_type(__a)
+	{ }
+
+#if __cplusplus >= 201103L
+	// Not defaulted, to enforce noexcept(true) even when
+	// !is_nothrow_move_constructible<_Tp_alloc_type>.
+	_Vector_impl(_Vector_impl&& __x) noexcept
+	: _Tp_alloc_type(std::move(__x)), _Vector_impl_data(std::move(__x))
+	{ }
+
+	_Vector_impl(_Tp_alloc_type&& __a) noexcept
+	: _Tp_alloc_type(std::move(__a))
+	{ }
+
+	_Vector_impl(_Tp_alloc_type&& __a, _Vector_impl&& __rv) noexcept
+	: _Tp_alloc_type(std::move(__a)), _Vector_impl_data(std::move(__rv))
+	{ }
+#endif
 
 #if _GLIBCXX_SANITIZE_STD_ALLOCATOR && _GLIBCXX_SANITIZE_VECTOR
 	template<typename = _Tp_alloc_type>
@@ -235,38 +259,44 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 
       _Tp_alloc_type&
       _M_get_Tp_allocator() _GLIBCXX_NOEXCEPT
-      { return *static_cast<_Tp_alloc_type*>(&this->_M_impl); }
+      { return this->_M_impl; }
 
       const _Tp_alloc_type&
       _M_get_Tp_allocator() const _GLIBCXX_NOEXCEPT
-      { return *static_cast<const _Tp_alloc_type*>(&this->_M_impl); }
+      { return this->_M_impl; }
 
       allocator_type
       get_allocator() const _GLIBCXX_NOEXCEPT
       { return allocator_type(_M_get_Tp_allocator()); }
 
-      _Vector_base()
-      : _M_impl() { }
+#if __cplusplus >= 201103L
+      _Vector_base() = default;
+#else
+      _Vector_base() { }
+#endif
 
       _Vector_base(const allocator_type& __a) _GLIBCXX_NOEXCEPT
       : _M_impl(__a) { }
 
+      // Kept for ABI compatibility.
+#if !_GLIBCXX_INLINE_VERSION
       _Vector_base(size_t __n)
       : _M_impl()
       { _M_create_storage(__n); }
+#endif
 
       _Vector_base(size_t __n, const allocator_type& __a)
       : _M_impl(__a)
       { _M_create_storage(__n); }
 
 #if __cplusplus >= 201103L
+      _Vector_base(_Vector_base&&) = default;
+
+      // Kept for ABI compatibility.
+# if !_GLIBCXX_INLINE_VERSION
       _Vector_base(_Tp_alloc_type&& __a) noexcept
       : _M_impl(std::move(__a)) { }
 
-      _Vector_base(_Vector_base&& __x) noexcept
-      : _M_impl(std::move(__x._M_get_Tp_allocator()))
-      { this->_M_impl._M_swap_data(__x._M_impl); }
-
       _Vector_base(_Vector_base&& __x, const allocator_type& __a)
       : _M_impl(__a)
       {
@@ -278,6 +308,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	    _M_create_storage(__n);
 	  }
       }
+# endif
+
+      _Vector_base(const allocator_type& __a, _Vector_base&& __x)
+      : _M_impl(_Tp_alloc_type(__a), std::move(__x._M_impl))
+      { }
 #endif
 
       ~_Vector_base() _GLIBCXX_NOEXCEPT
@@ -304,7 +339,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  _Tr::deallocate(_M_impl, __p, __n);
       }
 
-    private:
+    protected:
       void
       _M_create_storage(size_t __n)
       {
@@ -388,11 +423,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       /**
        *  @brief  Creates a %vector with no elements.
        */
-      vector()
 #if __cplusplus >= 201103L
-      noexcept(is_nothrow_default_constructible<_Alloc>::value)
+      vector() = default;
+#else
+      vector() { }
 #endif
-      : _Base() { }
 
       /**
        *  @brief  Creates a %vector with no elements.
@@ -468,13 +503,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 #if __cplusplus >= 201103L
       /**
        *  @brief  %Vector move constructor.
-       *  @param  __x  A %vector of identical element and allocator types.
        *
-       *  The newly-created %vector contains the exact contents of @a __x.
-       *  The contents of @a __x are a valid, but unspecified %vector.
+       *  The newly-created %vector contains the exact contents of the
+       *  moved instance.
+       *  The contents of the moved instance are a valid, but unspecified
+       *  %vector.
        */
-      vector(vector&& __x) noexcept
-      : _Base(std::move(__x)) { }
+      vector(vector&&) noexcept = default;
 
       /// Copy constructor with alternative allocator
       vector(const vector& __x, const allocator_type& __a)
@@ -486,13 +521,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 				      _M_get_Tp_allocator());
       }
 
-      /// Move constructor with alternative allocator
-      vector(vector&& __rv, const allocator_type& __m)
-      noexcept(_Alloc_traits::_S_always_equal())
-      : _Base(std::move(__rv), __m)
+    private:
+      vector(vector&& __rv, const allocator_type& __m, true_type) noexcept
+      : _Base(__m, std::move(__rv))
+      { }
+
+      vector(vector&& __rv, const allocator_type& __m, false_type)
+      : _Base(__m)
       {
-	if (__rv.get_allocator() != __m)
+	if (__rv.get_allocator() == __m)
+	  this->_M_impl._M_swap_data(__rv._M_impl);
+	else if (!__rv.empty())
 	  {
+	    this->_M_create_storage(__rv.size());
 	    this->_M_impl._M_finish =
 	      std::__uninitialized_move_a(__rv.begin(), __rv.end(),
 					  this->_M_impl._M_start,
@@ -501,6 +542,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  }
       }
 
+    public:
+      /// Move constructor with alternative allocator
+      vector(vector&& __rv, const allocator_type& __m)
+      noexcept( noexcept(
+	vector(std::declval<vector&&>(), std::declval<const allocator_type&>(),
+	       std::declval<typename _Alloc_traits::is_always_equal>())) )
+      : vector(std::move(__rv), __m, typename _Alloc_traits::is_always_equal{})
+      { }
+
       /**
        *  @brief  Builds a %vector from an initializer list.
        *  @param  __l  An initializer_list.
@@ -543,7 +593,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	vector(_InputIterator __first, _InputIterator __last,
 	       const allocator_type& __a = allocator_type())
 	: _Base(__a)
-	{ _M_initialize_dispatch(__first, __last, __false_type()); }
+	{
+	  _M_range_initialize(__first, __last,
+			      std::__iterator_category(__first));
+	}
 #else
       template<typename _InputIterator>
 	vector(_InputIterator __first, _InputIterator __last,
@@ -1414,6 +1467,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 
       // Called by the range constructor to implement [23.1.1]/9
 
+#if __cplusplus < 201103L
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // 438. Ambiguity in the "do the right thing" clause
       template<typename _Integer>
@@ -1432,10 +1486,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	_M_initialize_dispatch(_InputIterator __first, _InputIterator __last,
 			       __false_type)
 	{
-	  typedef typename std::iterator_traits<_InputIterator>::
-	    iterator_category _IterCategory;
-	  _M_range_initialize(__first, __last, _IterCategory());
+	  _M_range_initialize(__first, __last,
+			      std::__iterator_category(__first));
 	}
+#endif
 
       // Called by the second initialize_dispatch above
       template<typename _InputIterator>
@@ -1669,7 +1723,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       // moved, either because the source's allocator will move too
       // or because the allocators are equal.
       void
-      _M_move_assign(vector&& __x, std::true_type) noexcept
+      _M_move_assign(vector&& __x, true_type) noexcept
       {
 	vector __tmp(get_allocator());
 	this->_M_impl._M_swap_data(__tmp._M_impl);
@@ -1680,10 +1734,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       // Do move assignment when it might not be possible to move source
       // object's memory, resulting in a linear-time operation.
       void
-      _M_move_assign(vector&& __x, std::false_type)
+      _M_move_assign(vector&& __x, false_type)
       {
 	if (__x._M_get_Tp_allocator() == this->_M_get_Tp_allocator())
-	  _M_move_assign(std::move(__x), std::true_type());
+	  _M_move_assign(std::move(__x), true_type());
 	else
 	  {
 	    // The rvalue's allocator cannot be moved and is not equal,
diff --git a/libstdc++-v3/include/debug/vector b/libstdc++-v3/include/debug/vector
index 8d60da3..802f4fd 100644
--- a/libstdc++-v3/include/debug/vector
+++ b/libstdc++-v3/include/debug/vector
@@ -199,6 +199,8 @@ namespace __debug
       : _Base(__x, __a) { }
 
       vector(vector&& __x, const allocator_type& __a)
+	noexcept( noexcept(
+	  _Base(std::declval<_Base&&>()), std::declval<const allocator_type&>()) )
       : _Safe(std::move(__x._M_safe()), __a),
 	_Base(std::move(__x._M_base()), __a),
 	_Safe_vector(std::move(__x)) { }
diff --git a/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc b/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc
new file mode 100644
index 0000000..5981b8f
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/vector/allocator/default_init.cc
@@ -0,0 +1,67 @@
+// Copyright (C) 2018 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/>.
+
+// { dg-do run { target c++11 } }
+// { dg-options "-O0" }
+// { dg-xfail-run-if "PR c++/65816" { *-*-* } }
+
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+#include <ext/aligned_buffer.h>
+
+using T = int;
+
+using __gnu_test::default_init_allocator;
+
+void test01()
+{
+  typedef default_init_allocator<T> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+
+  __gnu_cxx::__aligned_buffer<test_type> buf;
+  __builtin_memset(buf._M_addr(), ~0, sizeof(test_type));
+
+  test_type *tmp = ::new(buf._M_addr()) test_type;
+
+  VERIFY( tmp->get_allocator().state == 0 );
+
+  tmp->~test_type();
+}
+
+void test02()
+{
+  typedef default_init_allocator<T> alloc_type;
+  typedef std::vector<T, alloc_type> test_type;
+
+  __gnu_cxx::__aligned_buffer<test_type> buf;
+  __builtin_memset(buf._M_addr(), ~0, sizeof(test_type));
+
+  test_type *tmp = ::new(buf._M_addr()) test_type();
+
+  VERIFY( tmp->get_allocator().state == 0 );
+
+  tmp->~test_type();
+}
+
+int main()
+{
+  test01();
+  test02();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/cons/noexcept_move_construct.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/noexcept_move_construct.cc
index f8f71a5..4d41486 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/cons/noexcept_move_construct.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/cons/noexcept_move_construct.cc
@@ -23,4 +23,34 @@
 
 typedef std::vector<int> vtype;
 
-static_assert(std::is_nothrow_move_constructible<vtype>::value, "Error");
+static_assert( std::is_nothrow_move_constructible<vtype>::value,
+	       "noexcept move constructor" );
+static_assert( std::is_nothrow_constructible<vtype,
+	       vtype&&, const typename vtype::allocator_type&>::value,
+	       "noexcept move constructor with allocator" );
+
+template<typename Type>
+  class not_noexcept_move_constructor_alloc : public std::allocator<Type>
+  {
+  public:
+    not_noexcept_move_constructor_alloc() noexcept { }
+
+    not_noexcept_move_constructor_alloc(
+	const not_noexcept_move_constructor_alloc& x) noexcept
+    : std::allocator<Type>(x)
+    { }
+
+    not_noexcept_move_constructor_alloc(
+	not_noexcept_move_constructor_alloc&& x) noexcept(false)
+    : std::allocator<Type>(std::move(x))
+    { }
+
+    template<typename _Tp1>
+      struct rebind
+      { typedef not_noexcept_move_constructor_alloc<_Tp1> other; };
+  };
+
+typedef std::vector<int, not_noexcept_move_constructor_alloc<int>> vtype2;
+
+static_assert( std::is_nothrow_move_constructible<vtype2>::value,
+	       "noexcept move constructor with not noexcept alloc" );

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2018-06-27 20:27 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-07-23 17:41 std::vector default default and move constructors François Dumont
2017-07-28 16:46 ` François Dumont
2017-08-21 19:16   ` François Dumont
2017-09-04 19:47     ` François Dumont
2018-01-11  6:41     ` François Dumont
2018-01-11  6:57       ` Marc Glisse
2018-01-11  7:03         ` Marc Glisse
2018-01-14 21:13         ` François Dumont
2018-01-15 12:29           ` Jonathan Wakely
2018-01-15 21:33             ` François Dumont
2018-01-16  0:20               ` Jonathan Wakely
2018-01-18 21:01                 ` François Dumont
2018-01-29 13:49                   ` Jonathan Wakely
2018-06-02 12:01                 ` François Dumont
2018-06-26 13:46                   ` Jonathan Wakely
2018-06-27 20:27                     ` François Dumont

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).