On Tue, 23 Oct 2018, Jonathan Wakely wrote:

+  template<typename _Tp, typename _Up, typename _Allocator>
+    inline void
+    __relocate_a(_Tp* __dest, _Up* __orig, _Allocator& __alloc)

I find it a little surprising that this overload for single objects
using the memmove argument ordering (dest, source) but the range overload
below uses the STL ordering (source_begin, source_end, dest).

But I wouldn't be surprised if we're already doing that somewhere that
I've forgotten about.

WOuld it make sense to either rename this overload, or to use
consistent argument ordering for the two __relocate_a overloads?

The functions were not meant as overloads, it just happened that I arrived at the same name for both, but it would make perfect sense to give them different names. I started from __relocate(dest, source) for one element, and later added an allocator to it. The other one corresponds to __uninitialized_move_a, and naming it __uninitialized_relocate_a would be silly since "uninitialized" is included in the definition of relocate.

Yes, my first thought was to add "uninitialized" and I rejected it for
that same reason.

I think I'd rather rename than change the order. Do you have suggestions? __relocate_range_a?

I was thinking the single object one could be __relocate_1_a with the
_1 being like copy_n, fill_n etc. but that's going to be confusing
with __relocate_a_1 instead!

It seems unfortunate to have to put "range" in the name when no other
algos that work on ranges bother to say that in the name.

Maybe the single object one could be __relocate_single_a? Or
__do_relocate_a? __relocate_obj_a? None of them really makes me happy.

I went with __relocate_object_a, but that's easy to change.

We may want to specialize / overload __relocate_object_a for some specific types in the future, although we would more likely have __relocate_object_a call __relocate_object (no allocator) when it receives the default allocator, and specialize that one. And this should anyway be less common that specializing __is_trivially_relocatable.

I just realized that __reallocate_a and construct don't take the allocator argument in the same position... I can switch if it helps.

Regtested on gcc112.

2018-10-25  Marc Glisse  <marc.gli...@inria.fr>

        PR libstdc++/87106
        * include/bits/alloc_traits.h (_S_construct, _S_destroy, construct,
        destroy): Add noexcept specification.
        * include/bits/allocator.h (construct, destroy): Likewise.
        * include/ext/alloc_traits.h (construct, destroy): Likewise.
        * include/ext/malloc_allocator.h (construct, destroy): Likewise.
        * include/ext/new_allocator.h (construct, destroy): Likewise.
        * include/bits/stl_uninitialized.h (__relocate_object_a, __relocate_a,
        __relocate_a_1): New functions.
        (__is_trivially_relocatable): New class.
        * include/bits/stl_vector.h (__use_relocate): New static member.
        * include/bits/vector.tcc (reserve, _M_realloc_insert,
        _M_default_append): Use __relocate_a.
        (reserve, _M_assign_aux, _M_realloc_insert, _M_fill_insert,
        _M_default_append, _M_range_insert): Move _GLIBCXX_ASAN_ANNOTATE_REINIT
        after _Destroy.
        * testsuite/23_containers/vector/modifiers/push_back/49836.cc:
        Replace CopyConsOnlyType with DelAnyAssign.


--
Marc Glisse
Index: libstdc++-v3/include/bits/alloc_traits.h
===================================================================
--- libstdc++-v3/include/bits/alloc_traits.h	(revision 265451)
+++ libstdc++-v3/include/bits/alloc_traits.h	(working copy)
@@ -233,38 +233,43 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  using type = decltype(__test<_Alloc>(0));
 	};
 
       template<typename _Tp, typename... _Args>
 	using __has_construct
 	  = typename __construct_helper<_Tp, _Args...>::type;
 
       template<typename _Tp, typename... _Args>
 	static _Require<__has_construct<_Tp, _Args...>>
 	_S_construct(_Alloc& __a, _Tp* __p, _Args&&... __args)
+	noexcept(noexcept(__a.construct(__p, std::forward<_Args>(__args)...)))
 	{ __a.construct(__p, std::forward<_Args>(__args)...); }
 
       template<typename _Tp, typename... _Args>
 	static
 	_Require<__and_<__not_<__has_construct<_Tp, _Args...>>,
 			       is_constructible<_Tp, _Args...>>>
 	_S_construct(_Alloc&, _Tp* __p, _Args&&... __args)
+	noexcept(noexcept(::new((void*)__p)
+			  _Tp(std::forward<_Args>(__args)...)))
 	{ ::new((void*)__p) _Tp(std::forward<_Args>(__args)...); }
 
       template<typename _Alloc2, typename _Tp>
 	static auto
 	_S_destroy(_Alloc2& __a, _Tp* __p, int)
+	noexcept(noexcept(__a.destroy(__p)))
 	-> decltype(__a.destroy(__p))
 	{ __a.destroy(__p); }
 
       template<typename _Alloc2, typename _Tp>
 	static void
 	_S_destroy(_Alloc2&, _Tp* __p, ...)
+	noexcept(noexcept(__p->~_Tp()))
 	{ __p->~_Tp(); }
 
       template<typename _Alloc2>
 	static auto
 	_S_max_size(_Alloc2& __a, int)
 	-> decltype(__a.max_size())
 	{ return __a.max_size(); }
 
       template<typename _Alloc2>
 	static size_type
@@ -333,33 +338,36 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *  @param  __p  Pointer to memory of suitable size and alignment for Tp
        *  @param  __args Constructor arguments.
        *
        *  Calls <tt> __a.construct(__p, std::forward<Args>(__args)...) </tt>
        *  if that expression is well-formed, otherwise uses placement-new
        *  to construct an object of type @a _Tp at location @a __p from the
        *  arguments @a __args...
       */
       template<typename _Tp, typename... _Args>
 	static auto construct(_Alloc& __a, _Tp* __p, _Args&&... __args)
+	noexcept(noexcept(_S_construct(__a, __p,
+				       std::forward<_Args>(__args)...)))
 	-> decltype(_S_construct(__a, __p, std::forward<_Args>(__args)...))
 	{ _S_construct(__a, __p, std::forward<_Args>(__args)...); }
 
       /**
        *  @brief  Destroy an object of type @a _Tp
        *  @param  __a  An allocator.
        *  @param  __p  Pointer to the object to destroy
        *
        *  Calls @c __a.destroy(__p) if that expression is well-formed,
        *  otherwise calls @c __p->~_Tp()
       */
       template<typename _Tp>
 	static void destroy(_Alloc& __a, _Tp* __p)
+	noexcept(noexcept(_S_destroy(__a, __p, 0)))
 	{ _S_destroy(__a, __p, 0); }
 
       /**
        *  @brief  The maximum supported allocation size
        *  @param  __a  An allocator.
        *  @return @c __a.max_size() or @c numeric_limits<size_type>::max()
        *
        *  Returns @c __a.max_size() if that expression is well-formed,
        *  otherwise returns @c numeric_limits<size_type>::max()
       */
@@ -465,32 +473,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        *  @brief  Construct an object of type @a _Up
        *  @param  __a  An allocator.
        *  @param  __p  Pointer to memory of suitable size and alignment for Tp
        *  @param  __args Constructor arguments.
        *
        *  Calls <tt> __a.construct(__p, std::forward<Args>(__args)...) </tt>
       */
       template<typename _Up, typename... _Args>
 	static void
 	construct(allocator_type& __a, _Up* __p, _Args&&... __args)
+	noexcept(noexcept(__a.construct(__p, std::forward<_Args>(__args)...)))
 	{ __a.construct(__p, std::forward<_Args>(__args)...); }
 
       /**
        *  @brief  Destroy an object of type @a _Up
        *  @param  __a  An allocator.
        *  @param  __p  Pointer to the object to destroy
        *
        *  Calls @c __a.destroy(__p).
       */
       template<typename _Up>
 	static void
 	destroy(allocator_type& __a, _Up* __p)
+	noexcept(noexcept(__a.destroy(__p)))
 	{ __a.destroy(__p); }
 
       /**
        *  @brief  The maximum supported allocation size
        *  @param  __a  An allocator.
        *  @return @c __a.max_size()
       */
       static size_type
       max_size(const allocator_type& __a) noexcept
       { return __a.max_size(); }
Index: libstdc++-v3/include/bits/allocator.h
===================================================================
--- libstdc++-v3/include/bits/allocator.h	(revision 265451)
+++ libstdc++-v3/include/bits/allocator.h	(working copy)
@@ -81,25 +81,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #if __cplusplus >= 201103L
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // 2103. std::allocator propagate_on_container_move_assignment
       typedef true_type propagate_on_container_move_assignment;
 
       typedef true_type is_always_equal;
 
       template<typename _Up, typename... _Args>
 	void
 	construct(_Up* __p, _Args&&... __args)
+	noexcept(noexcept(::new((void *)__p)
+			    _Up(std::forward<_Args>(__args)...)))
 	{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
 
       template<typename _Up>
 	void
-	destroy(_Up* __p) { __p->~_Up(); }
+	destroy(_Up* __p)
+	noexcept(noexcept(__p->~_Up()))
+	{ __p->~_Up(); }
 #endif
     };
 
   /**
    * @brief  The @a standard allocator, as per [20.4].
    *
    *  See https://gcc.gnu.org/onlinedocs/libstdc++/manual/memory.html#std.util.memory.allocator
    *  for further details.
    *
    *  @tparam  _Tp  Type of allocated object.
Index: libstdc++-v3/include/bits/stl_uninitialized.h
===================================================================
--- libstdc++-v3/include/bits/stl_uninitialized.h	(revision 265451)
+++ libstdc++-v3/include/bits/stl_uninitialized.h	(working copy)
@@ -872,14 +872,76 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     uninitialized_move_n(_InputIterator __first, _Size __count,
 			 _ForwardIterator __result)
     {
       auto __res = std::__uninitialized_copy_n_pair
 	(_GLIBCXX_MAKE_MOVE_ITERATOR(__first),
 	 __count, __result);
       return {__res.first.base(), __res.second};
     }
 #endif
 
+#if __cplusplus >= 201103L
+  template<typename _Tp, typename _Up, typename _Allocator>
+    inline void
+    __relocate_object_a(_Tp* __dest, _Up* __orig, _Allocator& __alloc)
+    noexcept(noexcept(std::allocator_traits<_Allocator>::construct(__alloc,
+			 __dest, std::move(*__orig)))
+	     && noexcept(std::allocator_traits<_Allocator>::destroy(
+			    __alloc, std::__addressof(*__orig))))
+    {
+      typedef std::allocator_traits<_Allocator> __traits;
+      __traits::construct(__alloc, __dest, std::move(*__orig));
+      __traits::destroy(__alloc, std::__addressof(*__orig));
+    }
+
+  // This class may be specialized for specific types.
+  template<typename _Tp>
+    struct __is_trivially_relocatable
+    : is_trivial<_Tp> { };
+
+  template <typename _Tp, typename _Up>
+    inline __enable_if_t<std::__is_trivially_relocatable<_Tp>::value, _Tp*>
+    __relocate_a_1(_Tp* __first, _Tp* __last,
+		   _Tp* __result, allocator<_Up>& __alloc)
+    {
+      ptrdiff_t __count = __last - __first;
+      __builtin_memmove(__result, __first, __count * sizeof(_Tp));
+      return __result + __count;
+    }
+
+  template <typename _InputIterator, typename _ForwardIterator,
+	    typename _Allocator>
+    inline _ForwardIterator
+    __relocate_a_1(_InputIterator __first, _InputIterator __last,
+		   _ForwardIterator __result, _Allocator& __alloc)
+    {
+      typedef typename iterator_traits<_InputIterator>::value_type
+	_ValueType;
+      typedef typename iterator_traits<_ForwardIterator>::value_type
+	_ValueType2;
+      static_assert(std::is_same<_ValueType, _ValueType2>::value);
+      static_assert(noexcept(std::__relocate_object_a(std::addressof(*__result),
+						      std::addressof(*__first),
+						      __alloc)));
+      _ForwardIterator __cur = __result;
+      for (; __first != __last; ++__first, (void)++__cur)
+	std::__relocate_object_a(std::__addressof(*__cur),
+				 std::__addressof(*__first), __alloc);
+      return __cur;
+    }
+
+  template <typename _InputIterator, typename _ForwardIterator,
+	    typename _Allocator>
+    inline _ForwardIterator
+    __relocate_a(_InputIterator __first, _InputIterator __last,
+		 _ForwardIterator __result, _Allocator& __alloc)
+    {
+      return __relocate_a_1(std::__niter_base(__first),
+			    std::__niter_base(__last),
+			    std::__niter_base(__result), __alloc);
+    }
+#endif
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace
 
 #endif /* _STL_UNINITIALIZED_H */
Index: libstdc++-v3/include/bits/stl_vector.h
===================================================================
--- libstdc++-v3/include/bits/stl_vector.h	(revision 265451)
+++ libstdc++-v3/include/bits/stl_vector.h	(working copy)
@@ -414,20 +414,29 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       typedef typename _Alloc_traits::const_reference	const_reference;
       typedef __gnu_cxx::__normal_iterator<pointer, vector> iterator;
       typedef __gnu_cxx::__normal_iterator<const_pointer, vector>
       const_iterator;
       typedef std::reverse_iterator<const_iterator>	const_reverse_iterator;
       typedef std::reverse_iterator<iterator>		reverse_iterator;
       typedef size_t					size_type;
       typedef ptrdiff_t					difference_type;
       typedef _Alloc					allocator_type;
 
+    private:
+#if __cplusplus >= 201103L
+      static constexpr bool __use_relocate =
+	noexcept(std::__relocate_object_a(
+			std::addressof(*std::declval<pointer>()),
+			std::addressof(*std::declval<pointer>()),
+			std::declval<_Tp_alloc_type&>()));
+#endif
+
     protected:
       using _Base::_M_allocate;
       using _Base::_M_deallocate;
       using _Base::_M_impl;
       using _Base::_M_get_Tp_allocator;
 
     public:
       // [23.2.4.1] construct/copy/destroy
       // (assign() and get_allocator() are also listed in this section)
 
Index: libstdc++-v3/include/bits/vector.tcc
===================================================================
--- libstdc++-v3/include/bits/vector.tcc	(revision 265451)
+++ libstdc++-v3/include/bits/vector.tcc	(working copy)
@@ -64,26 +64,39 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
   template<typename _Tp, typename _Alloc>
     void
     vector<_Tp, _Alloc>::
     reserve(size_type __n)
     {
       if (__n > this->max_size())
 	__throw_length_error(__N("vector::reserve"));
       if (this->capacity() < __n)
 	{
 	  const size_type __old_size = size();
-	  pointer __tmp = _M_allocate_and_copy(__n,
-	    _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(this->_M_impl._M_start),
-	    _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(this->_M_impl._M_finish));
+	  pointer __tmp;
+#if __cplusplus >= 201103L
+	  if constexpr (__use_relocate)
+	    {
+	      __tmp = this->_M_allocate(__n);
+	      std::__relocate_a(this->_M_impl._M_start,
+				this->_M_impl._M_finish,
+				__tmp, _M_get_Tp_allocator());
+	    }
+	  else
+#endif
+	    {
+	      __tmp = _M_allocate_and_copy(__n,
+		_GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(this->_M_impl._M_start),
+		_GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(this->_M_impl._M_finish));
+	      std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
+			    _M_get_Tp_allocator());
+	    }
 	  _GLIBCXX_ASAN_ANNOTATE_REINIT;
-	  std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
-			_M_get_Tp_allocator());
 	  _M_deallocate(this->_M_impl._M_start,
 			this->_M_impl._M_end_of_storage
 			- this->_M_impl._M_start);
 	  this->_M_impl._M_start = __tmp;
 	  this->_M_impl._M_finish = __tmp + __old_size;
 	  this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
 	}
     }
 
 #if __cplusplus >= 201103L
@@ -288,23 +301,23 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
       vector<_Tp, _Alloc>::
       _M_assign_aux(_ForwardIterator __first, _ForwardIterator __last,
 		    std::forward_iterator_tag)
       {
 	const size_type __len = std::distance(__first, __last);
 
 	if (__len > capacity())
 	  {
 	    _S_check_init_len(__len, _M_get_Tp_allocator());
 	    pointer __tmp(_M_allocate_and_copy(__len, __first, __last));
-	    _GLIBCXX_ASAN_ANNOTATE_REINIT;
 	    std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
 			  _M_get_Tp_allocator());
+	    _GLIBCXX_ASAN_ANNOTATE_REINIT;
 	    _M_deallocate(this->_M_impl._M_start,
 			  this->_M_impl._M_end_of_storage
 			  - this->_M_impl._M_start);
 	    this->_M_impl._M_start = __tmp;
 	    this->_M_impl._M_finish = this->_M_impl._M_start + __len;
 	    this->_M_impl._M_end_of_storage = this->_M_impl._M_finish;
 	  }
 	else if (size() >= __len)
 	  _M_erase_at_end(std::copy(__first, __last, this->_M_impl._M_start));
 	else
@@ -436,44 +449,66 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	  // [res.on.arguments]).
 	  _Alloc_traits::construct(this->_M_impl,
 				   __new_start + __elems_before,
 #if __cplusplus >= 201103L
 				   std::forward<_Args>(__args)...);
 #else
 				   __x);
 #endif
 	  __new_finish = pointer();
 
-	  __new_finish
-	    = std::__uninitialized_move_if_noexcept_a
-	    (__old_start, __position.base(),
-	     __new_start, _M_get_Tp_allocator());
-
-	  ++__new_finish;
-
-	  __new_finish
-	    = std::__uninitialized_move_if_noexcept_a
-	    (__position.base(), __old_finish,
-	     __new_finish, _M_get_Tp_allocator());
+#if __cplusplus >= 201103L
+	  if constexpr (__use_relocate)
+	    {
+	      __new_finish
+		= std::__relocate_a
+		(__old_start, __position.base(),
+		 __new_start, _M_get_Tp_allocator());
+
+	      ++__new_finish;
+
+	      __new_finish
+		= std::__relocate_a
+		(__position.base(), __old_finish,
+		 __new_finish, _M_get_Tp_allocator());
+	    }
+	  else
+#endif
+	    {
+	      __new_finish
+		= std::__uninitialized_move_if_noexcept_a
+		(__old_start, __position.base(),
+		 __new_start, _M_get_Tp_allocator());
+
+	      ++__new_finish;
+
+	      __new_finish
+		= std::__uninitialized_move_if_noexcept_a
+		(__position.base(), __old_finish,
+		 __new_finish, _M_get_Tp_allocator());
+	    }
 	}
       __catch(...)
 	{
 	  if (!__new_finish)
 	    _Alloc_traits::destroy(this->_M_impl,
 				   __new_start + __elems_before);
 	  else
 	    std::_Destroy(__new_start, __new_finish, _M_get_Tp_allocator());
 	  _M_deallocate(__new_start, __len);
 	  __throw_exception_again;
 	}
+#if __cplusplus >= 201103L
+      if constexpr (!__use_relocate)
+#endif
+	std::_Destroy(__old_start, __old_finish, _M_get_Tp_allocator());
       _GLIBCXX_ASAN_ANNOTATE_REINIT;
-      std::_Destroy(__old_start, __old_finish, _M_get_Tp_allocator());
       _M_deallocate(__old_start,
 		    this->_M_impl._M_end_of_storage - __old_start);
       this->_M_impl._M_start = __new_start;
       this->_M_impl._M_finish = __new_finish;
       this->_M_impl._M_end_of_storage = __new_start + __len;
     }
 
   template<typename _Tp, typename _Alloc>
     void
     vector<_Tp, _Alloc>::
@@ -555,23 +590,23 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 		  if (!__new_finish)
 		    std::_Destroy(__new_start + __elems_before,
 				  __new_start + __elems_before + __n,
 				  _M_get_Tp_allocator());
 		  else
 		    std::_Destroy(__new_start, __new_finish,
 				  _M_get_Tp_allocator());
 		  _M_deallocate(__new_start, __len);
 		  __throw_exception_again;
 		}
-	      _GLIBCXX_ASAN_ANNOTATE_REINIT;
 	      std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
 			    _M_get_Tp_allocator());
+	      _GLIBCXX_ASAN_ANNOTATE_REINIT;
 	      _M_deallocate(this->_M_impl._M_start,
 			    this->_M_impl._M_end_of_storage
 			    - this->_M_impl._M_start);
 	      this->_M_impl._M_start = __new_start;
 	      this->_M_impl._M_finish = __new_finish;
 	      this->_M_impl._M_end_of_storage = __new_start + __len;
 	    }
 	}
     }
 
@@ -596,41 +631,62 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	      this->_M_impl._M_finish =
 		std::__uninitialized_default_n_a(this->_M_impl._M_finish,
 						 __n, _M_get_Tp_allocator());
 	      _GLIBCXX_ASAN_ANNOTATE_GREW(__n);
 	    }
 	  else
 	    {
 	      const size_type __len =
 		_M_check_len(__n, "vector::_M_default_append");
 	      pointer __new_start(this->_M_allocate(__len));
-	      pointer __destroy_from = pointer();
-	      __try
+#if __cplusplus >= 201103L
+	      if constexpr (__use_relocate)
 		{
-		  std::__uninitialized_default_n_a(__new_start + __size,
-						   __n, _M_get_Tp_allocator());
-		  __destroy_from = __new_start + __size;
-		  std::__uninitialized_move_if_noexcept_a(
-		      this->_M_impl._M_start, this->_M_impl._M_finish,
-		      __new_start, _M_get_Tp_allocator());
+		  __try
+		    {
+		      std::__uninitialized_default_n_a(__new_start + __size,
+			      __n, _M_get_Tp_allocator());
+		    }
+		  __catch(...)
+		    {
+		      _M_deallocate(__new_start, __len);
+		      __throw_exception_again;
+		    }
+		  std::__relocate_a(this->_M_impl._M_start,
+				    this->_M_impl._M_finish,
+				    __new_start, _M_get_Tp_allocator());
 		}
-	      __catch(...)
+	      else
+#endif
 		{
-		  if (__destroy_from)
-		    std::_Destroy(__destroy_from, __destroy_from + __n,
-				  _M_get_Tp_allocator());
-		  _M_deallocate(__new_start, __len);
-		  __throw_exception_again;
+		  pointer __destroy_from = pointer();
+		  __try
+		    {
+		      std::__uninitialized_default_n_a(__new_start + __size,
+			      __n, _M_get_Tp_allocator());
+		      __destroy_from = __new_start + __size;
+		      std::__uninitialized_move_if_noexcept_a(
+			      this->_M_impl._M_start, this->_M_impl._M_finish,
+			      __new_start, _M_get_Tp_allocator());
+		    }
+		  __catch(...)
+		    {
+		      if (__destroy_from)
+			std::_Destroy(__destroy_from, __destroy_from + __n,
+				      _M_get_Tp_allocator());
+		      _M_deallocate(__new_start, __len);
+		      __throw_exception_again;
+		    }
+		  std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
+				_M_get_Tp_allocator());
 		}
 	      _GLIBCXX_ASAN_ANNOTATE_REINIT;
-	      std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
-			    _M_get_Tp_allocator());
 	      _M_deallocate(this->_M_impl._M_start,
 			    this->_M_impl._M_end_of_storage
 			    - this->_M_impl._M_start);
 	      this->_M_impl._M_start = __new_start;
 	      this->_M_impl._M_finish = __new_start + __size + __n;
 	      this->_M_impl._M_end_of_storage = __new_start + __len;
 	    }
 	}
     }
 
@@ -735,23 +791,23 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 		      (__position.base(), this->_M_impl._M_finish,
 		       __new_finish, _M_get_Tp_allocator());
 		  }
 		__catch(...)
 		  {
 		    std::_Destroy(__new_start, __new_finish,
 				  _M_get_Tp_allocator());
 		    _M_deallocate(__new_start, __len);
 		    __throw_exception_again;
 		  }
-		_GLIBCXX_ASAN_ANNOTATE_REINIT;
 		std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
 			      _M_get_Tp_allocator());
+		_GLIBCXX_ASAN_ANNOTATE_REINIT;
 		_M_deallocate(this->_M_impl._M_start,
 			      this->_M_impl._M_end_of_storage
 			      - this->_M_impl._M_start);
 		this->_M_impl._M_start = __new_start;
 		this->_M_impl._M_finish = __new_finish;
 		this->_M_impl._M_end_of_storage = __new_start + __len;
 	      }
 	  }
       }
 
Index: libstdc++-v3/include/ext/alloc_traits.h
===================================================================
--- libstdc++-v3/include/ext/alloc_traits.h	(revision 265451)
+++ libstdc++-v3/include/ext/alloc_traits.h	(working copy)
@@ -73,29 +73,32 @@ template<typename _Alloc, typename = typ
     template<typename _Ptr>
       using __is_custom_pointer
 	= std::__and_<std::is_same<pointer, _Ptr>,
 		      std::__not_<std::is_pointer<_Ptr>>>;
 
   public:
     // overload construct for non-standard pointer types
     template<typename _Ptr, typename... _Args>
       static typename std::enable_if<__is_custom_pointer<_Ptr>::value>::type
       construct(_Alloc& __a, _Ptr __p, _Args&&... __args)
+      noexcept(noexcept(_Base_type::construct(__a, std::__to_address(__p),
+					      std::forward<_Args>(__args)...)))
       {
 	_Base_type::construct(__a, std::__to_address(__p),
 			      std::forward<_Args>(__args)...);
       }
 
     // overload destroy for non-standard pointer types
     template<typename _Ptr>
       static typename std::enable_if<__is_custom_pointer<_Ptr>::value>::type
       destroy(_Alloc& __a, _Ptr __p)
+      noexcept(noexcept(_Base_type::destroy(__a, std::__to_address(__p))))
       { _Base_type::destroy(__a, std::__to_address(__p)); }
 
     static _Alloc _S_select_on_copy(const _Alloc& __a)
     { return _Base_type::select_on_container_copy_construction(__a); }
 
     static void _S_on_swap(_Alloc& __a, _Alloc& __b)
     { std::__alloc_on_swap(__a, __b); }
 
     static constexpr bool _S_propagate_on_copy_assign()
     { return _Base_type::propagate_on_container_copy_assignment::value; }
Index: libstdc++-v3/include/ext/malloc_allocator.h
===================================================================
--- libstdc++-v3/include/ext/malloc_allocator.h	(revision 265451)
+++ libstdc++-v3/include/ext/malloc_allocator.h	(working copy)
@@ -144,25 +144,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return size_t(__PTRDIFF_MAX__) / sizeof(_Tp);
 #else
 	return size_t(-1) / sizeof(_Tp);
 #endif
       }
 
 #if __cplusplus >= 201103L
       template<typename _Up, typename... _Args>
         void
         construct(_Up* __p, _Args&&... __args)
+	noexcept(noexcept(::new((void *)__p)
+			  _Up(std::forward<_Args>(__args)...)))
 	{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
 
       template<typename _Up>
         void 
-        destroy(_Up* __p) { __p->~_Up(); }
+        destroy(_Up* __p)
+	noexcept(noexcept(__p->~_Up()))
+	{ __p->~_Up(); }
 #else
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // 402. wrong new expression in [some_] allocator::construct
       void 
       construct(pointer __p, const _Tp& __val) 
       { ::new((void *)__p) value_type(__val); }
 
       void 
       destroy(pointer __p) { __p->~_Tp(); }
 #endif
Index: libstdc++-v3/include/ext/new_allocator.h
===================================================================
--- libstdc++-v3/include/ext/new_allocator.h	(revision 265451)
+++ libstdc++-v3/include/ext/new_allocator.h	(working copy)
@@ -135,25 +135,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return size_t(__PTRDIFF_MAX__) / sizeof(_Tp);
 #else
 	return size_t(-1) / sizeof(_Tp);
 #endif
       }
 
 #if __cplusplus >= 201103L
       template<typename _Up, typename... _Args>
 	void
 	construct(_Up* __p, _Args&&... __args)
+	noexcept(noexcept(::new((void *)__p)
+			    _Up(std::forward<_Args>(__args)...)))
 	{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
 
       template<typename _Up>
 	void
-	destroy(_Up* __p) { __p->~_Up(); }
+	destroy(_Up* __p)
+	noexcept(noexcept( __p->~_Up()))
+	{ __p->~_Up(); }
 #else
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // 402. wrong new expression in [some_] allocator::construct
       void
       construct(pointer __p, const _Tp& __val)
       { ::new((void *)__p) _Tp(__val); }
 
       void
       destroy(pointer __p) { __p->~_Tp(); }
 #endif
Index: libstdc++-v3/testsuite/23_containers/vector/modifiers/push_back/49836.cc
===================================================================
--- libstdc++-v3/testsuite/23_containers/vector/modifiers/push_back/49836.cc	(revision 265451)
+++ libstdc++-v3/testsuite/23_containers/vector/modifiers/push_back/49836.cc	(working copy)
@@ -17,25 +17,25 @@
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
 #include <vector>
 #include <testsuite_hooks.h>
 #include <testsuite_tr1.h>
 
 // libstdc++/49836
 void test01()
 {
-  using __gnu_test::CopyConsOnlyType;
+  using __gnu_test::assign::DelAnyAssign;
   using __gnu_test::MoveConsOnlyType;
 
-  std::vector<CopyConsOnlyType> v1;
-  CopyConsOnlyType t1(1);
+  std::vector<DelAnyAssign> v1;
+  DelAnyAssign t1;
   v1.push_back(t1);
   v1.push_back(t1);
   v1.push_back(t1);
   VERIFY( v1.size() == 3 );
 
   std::vector<MoveConsOnlyType> v2;
   MoveConsOnlyType t2(1);
   v2.push_back(std::move(t2));
   v2.push_back(std::move(t2));
   v2.push_back(std::move(t2));

Reply via email to