[patch] fix a couple of std::allocator_traits bugs

Jonathan Wakely jwakely@redhat.com
Wed Jan 29 14:59:00 GMT 2014


std::allocator_traits<A>::allocate(a, n, hint) could fail to compile
if the const_void_pointer passed as the hint was a non-trivial type,
because it was passed to a varargs function.

std::vector was not using std::allocator_traits<A> for calls to
A::allocate and A::deallocate.

Also remove some redundant conditions in std::vector and _Rb_tree and
in allocator_traits simplify SFINAE uses and use true_type / false_type
to avoid needing definitions for static const bool members.

I added PointerBase to testsuite_allocator.h to help create custom
pointer types for testing because it's non-trivial to define the whole
thing every time you need one. There's also a new test to verify the
allocator_traits typedefs are correct.

Tested x86_64-linux, committed to trunk.
(I didn't fix up some dg-error line numbers relating to stl_vector.h
because I'm also committing another patch that changes them again, so
I only did it once.)

        * include/bits/alloc_traits.h (allocator_traits::_S_allocate): Do
        not use varargs when argument could be non-POD.
        (__alloctr_rebind_helper): Eliminate static const bool member by
        using true_type and false_type.
        (allocator_traits::__allocate_helper): Likewise.
        (allocator_traits::__construct_helper): Likewise.
        (allocator_traits::__destroy_helper): Likewise.
        (allocator_traits::__maxsize_helper): Likewise.
        (allocator_traits::__select_helper): Likewise.
        * include/bits/ptr_traits.h (__ptrtr_rebind_helper): Likewise.
        * include/bits/stl_tree.h (_Rb_tree::operator=(const _Rb_tree&)):
        Remove redundant condition.
        * include/bits/stl_vector.h (vector::operator=(const vector&)):
        Likewise.
        (_Vector_impl::_M_allocate, _Vector_impl::_M_deallocate): Use
        indirection through __alloc_traits.
        * include/ext/alloc_traits.h (__allocator_always_compares_equal):
        Eliminate static const bool members by using true_type and false_type.
        (__gnu_cxx::__alloc_traits::__is_custom_pointer): Optimize.
        * testsuite/util/testsuite_allocator.h (PointerBase): Define.
        * testsuite/20_util/allocator_traits/members/allocate_hint_nonpod.cc:
        New.
        * testsuite/20_util/allocator_traits/requirements/typedefs2.cc: New.

-------------- next part --------------
commit fa11899fe418aaee495c5fd3ed4215a9df319e33
Author: Jonathan Wakely <jwakely.gcc@gmail.com>
Date:   Tue Apr 16 22:19:59 2013 +0100

    	* include/bits/alloc_traits.h (allocator_traits::_S_allocate): Do
    	not use varargs when argument could be non-POD.
    	(__alloctr_rebind_helper): Eliminate static const bool member by
    	using true_type and false_type.
    	(allocator_traits::__allocate_helper): Likewise.
    	(allocator_traits::__construct_helper): Likewise.
    	(allocator_traits::__destroy_helper): Likewise.
    	(allocator_traits::__maxsize_helper): Likewise.
    	(allocator_traits::__select_helper): Likewise.
    	* include/bits/ptr_traits.h (__ptrtr_rebind_helper): Likewise.
    	* include/bits/stl_tree.h (_Rb_tree::operator=(const _Rb_tree&)):
    	Remove redundant condition.
    	* include/bits/stl_vector.h (vector::operator=(const vector&)):
    	Likewise.
    	(_Vector_impl::_M_allocate, _Vector_impl::_M_deallocate): Use
    	indirection through __alloc_traits.
    	* include/ext/alloc_traits.h (__allocator_always_compares_equal):
    	Eliminate static const bool members by using true_type and false_type.
    	(__gnu_cxx::__alloc_traits::__is_custom_pointer): Optimize.
    	* testsuite/util/testsuite_allocator.h (PointerBase): Define.
    	* testsuite/20_util/allocator_traits/members/allocate_hint_nonpod.cc:
    	New.
    	* testsuite/20_util/allocator_traits/requirements/typedefs2.cc: New.

diff --git a/libstdc++-v3/include/bits/alloc_traits.h b/libstdc++-v3/include/bits/alloc_traits.h
index 86ed222..23fe8de 100644
--- a/libstdc++-v3/include/bits/alloc_traits.h
+++ b/libstdc++-v3/include/bits/alloc_traits.h
@@ -44,24 +44,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     class __alloctr_rebind_helper
     {
       template<typename _Alloc2, typename _Tp2>
-	static constexpr bool
-       	_S_chk(typename _Alloc2::template rebind<_Tp2>::other*)
-	{ return true; }
+	static constexpr true_type
+	_S_chk(typename _Alloc2::template rebind<_Tp2>::other*);
 
       template<typename, typename>
-        static constexpr bool
-       	_S_chk(...)
-       	{ return false; }
+	static constexpr false_type
+	_S_chk(...);
 
     public:
-      static const bool __value = _S_chk<_Alloc, _Tp>(nullptr);
+      using __type = decltype(_S_chk<_Alloc, _Tp>(nullptr));
     };
 
-  template<typename _Alloc, typename _Tp>
-    const bool __alloctr_rebind_helper<_Alloc, _Tp>::__value;
-
   template<typename _Alloc, typename _Tp,
-           bool = __alloctr_rebind_helper<_Alloc, _Tp>::__value>
+	   bool = __alloctr_rebind_helper<_Alloc, _Tp>::__type::value>
     struct __alloctr_rebind;
 
   template<typename _Alloc, typename _Tp>
@@ -71,7 +66,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     };
 
   template<template<typename, typename...> class _Alloc, typename _Tp,
-            typename _Up, typename... _Args>
+	   typename _Up, typename... _Args>
     struct __alloctr_rebind<_Alloc<_Up, _Args...>, _Tp, false>
     {
       typedef _Alloc<_Tp, _Args...> __type;
@@ -140,7 +135,7 @@ _GLIBCXX_ALLOC_TR_NESTED_TYPE(const_void_pointer,
       typedef __const_void_pointer const_void_pointer;
 
 _GLIBCXX_ALLOC_TR_NESTED_TYPE(difference_type,
-                              typename pointer_traits<pointer>::difference_type)
+			      typename pointer_traits<pointer>::difference_type)
 
       /**
        * @brief   The allocator's difference type
@@ -151,7 +146,7 @@ _GLIBCXX_ALLOC_TR_NESTED_TYPE(difference_type,
       typedef __difference_type difference_type;
 
 _GLIBCXX_ALLOC_TR_NESTED_TYPE(size_type,
-                              typename make_unsigned<difference_type>::type)
+			      typename make_unsigned<difference_type>::type)
 
       /**
        * @brief   The allocator's size type
@@ -162,7 +157,7 @@ _GLIBCXX_ALLOC_TR_NESTED_TYPE(size_type,
       typedef __size_type size_type;
 
 _GLIBCXX_ALLOC_TR_NESTED_TYPE(propagate_on_container_copy_assignment,
-                              false_type)
+			      false_type)
 
       /**
        * @brief   How the allocator is propagated on copy assignment
@@ -171,10 +166,10 @@ _GLIBCXX_ALLOC_TR_NESTED_TYPE(propagate_on_container_copy_assignment,
        * otherwise @c false_type
       */
       typedef __propagate_on_container_copy_assignment
-       	propagate_on_container_copy_assignment;
+	propagate_on_container_copy_assignment;
 
 _GLIBCXX_ALLOC_TR_NESTED_TYPE(propagate_on_container_move_assignment,
-                              false_type)
+			      false_type)
 
       /**
        * @brief   How the allocator is propagated on move assignment
@@ -183,10 +178,10 @@ _GLIBCXX_ALLOC_TR_NESTED_TYPE(propagate_on_container_move_assignment,
        * otherwise @c false_type
       */
       typedef __propagate_on_container_move_assignment
-       	propagate_on_container_move_assignment;
+	propagate_on_container_move_assignment;
 
 _GLIBCXX_ALLOC_TR_NESTED_TYPE(propagate_on_container_swap,
-                              false_type)
+			      false_type)
 
       /**
        * @brief   How the allocator is propagated on swap
@@ -199,9 +194,9 @@ _GLIBCXX_ALLOC_TR_NESTED_TYPE(propagate_on_container_swap,
 #undef _GLIBCXX_ALLOC_TR_NESTED_TYPE
 
       template<typename _Tp>
-        using rebind_alloc = typename __alloctr_rebind<_Alloc, _Tp>::__type;
+	using rebind_alloc = typename __alloctr_rebind<_Alloc, _Tp>::__type;
       template<typename _Tp>
-        using rebind_traits = allocator_traits<rebind_alloc<_Tp>>;
+	using rebind_traits = allocator_traits<rebind_alloc<_Tp>>;
 
     private:
       template<typename _Alloc2>
@@ -216,20 +211,22 @@ _GLIBCXX_ALLOC_TR_NESTED_TYPE(propagate_on_container_swap,
 	  template<typename>
 	    static false_type __test(...);
 
-	  typedef decltype(__test<_Alloc>(0)) type;
-	  static const bool value = type::value;
+	  using type = decltype(__test<_Alloc>(0));
 	};
 
       template<typename _Alloc2>
-	static typename
-       	enable_if<__allocate_helper<_Alloc2>::value, pointer>::type
-       	_S_allocate(_Alloc2& __a, size_type __n, const_void_pointer __hint)
+	using __has_allocate = typename __allocate_helper<_Alloc2>::type;
+
+      template<typename _Alloc2,
+	       typename = _Require<__has_allocate<_Alloc2>>>
+	static pointer
+	_S_allocate(_Alloc2& __a, size_type __n, const_void_pointer __hint)
 	{ return __a.allocate(__n, __hint); }
 
-      template<typename _Alloc2>
-	static typename
-       	enable_if<!__allocate_helper<_Alloc2>::value, pointer>::type
-       	_S_allocate(_Alloc2& __a, size_type __n, ...)
+      template<typename _Alloc2, typename _UnusedHint,
+	       typename = _Require<__not_<__has_allocate<_Alloc2>>>>
+	static pointer
+	_S_allocate(_Alloc2& __a, size_type __n, _UnusedHint)
 	{ return __a.allocate(__n); }
 
       template<typename _Tp, typename... _Args>
@@ -243,21 +240,23 @@ _GLIBCXX_ALLOC_TR_NESTED_TYPE(propagate_on_container_swap,
 	  template<typename>
 	    static false_type __test(...);
 
-	  typedef decltype(__test<_Alloc>(0)) type;
-	  static const bool value = type::value;
+	  using type = decltype(__test<_Alloc>(0));
 	};
 
       template<typename _Tp, typename... _Args>
-	static typename
-       	enable_if<__construct_helper<_Tp, _Args...>::value, void>::type
-       	_S_construct(_Alloc& __a, _Tp* __p, _Args&&... __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)
 	{ __a.construct(__p, std::forward<_Args>(__args)...); }
 
       template<typename _Tp, typename... _Args>
-	static typename
-	enable_if<__and_<__not_<__construct_helper<_Tp, _Args...>>,
-			 is_constructible<_Tp, _Args...>>::value, void>::type
-       	_S_construct(_Alloc&, _Tp* __p, _Args&&... __args)
+	static
+	_Require<__and_<__not_<__has_construct<_Tp, _Args...>>,
+			       is_constructible<_Tp, _Args...>>>
+	_S_construct(_Alloc&, _Tp* __p, _Args&&... __args)
 	{ ::new((void*)__p) _Tp(std::forward<_Args>(__args)...); }
 
       template<typename _Tp>
@@ -271,18 +270,20 @@ _GLIBCXX_ALLOC_TR_NESTED_TYPE(propagate_on_container_swap,
 	  template<typename>
 	    static false_type __test(...);
 
-	  typedef decltype(__test<_Alloc>(0)) type;
-	  static const bool value = type::value;
+	  using type = decltype(__test<_Alloc>(0));
 	};
 
       template<typename _Tp>
-	static typename enable_if<__destroy_helper<_Tp>::value, void>::type
-       	_S_destroy(_Alloc& __a, _Tp* __p)
+	using __has_destroy = typename __destroy_helper<_Tp>::type;
+
+      template<typename _Tp>
+	static _Require<__has_destroy<_Tp>>
+	_S_destroy(_Alloc& __a, _Tp* __p)
 	{ __a.destroy(__p); }
 
       template<typename _Tp>
-	static typename enable_if<!__destroy_helper<_Tp>::value, void>::type
-       	_S_destroy(_Alloc&, _Tp* __p)
+	static _Require<__not_<__has_destroy<_Tp>>>
+	_S_destroy(_Alloc&, _Tp* __p)
 	{ __p->~_Tp(); }
 
       template<typename _Alloc2>
@@ -295,20 +296,22 @@ _GLIBCXX_ALLOC_TR_NESTED_TYPE(propagate_on_container_swap,
 	  template<typename>
 	    static false_type __test(...);
 
-	  typedef decltype(__test<_Alloc2>(0)) type;
-	  static const bool value = type::value;
+	  using type = decltype(__test<_Alloc2>(0));
 	};
 
       template<typename _Alloc2>
-	static typename
-       	enable_if<__maxsize_helper<_Alloc2>::value, size_type>::type
-       	_S_max_size(_Alloc2& __a)
+	using __has_max_size = typename __maxsize_helper<_Alloc2>::type;
+
+      template<typename _Alloc2,
+	       typename = _Require<__has_max_size<_Alloc2>>>
+	static size_type
+	_S_max_size(_Alloc2& __a, int)
 	{ return __a.max_size(); }
 
-      template<typename _Alloc2>
-	static typename
-       	enable_if<!__maxsize_helper<_Alloc2>::value, size_type>::type
-	_S_max_size(_Alloc2&)
+      template<typename _Alloc2,
+	       typename = _Require<__not_<__has_max_size<_Alloc2>>>>
+	static size_type
+	_S_max_size(_Alloc2&, ...)
 	{ return __gnu_cxx::__numeric_traits<size_type>::__max; }
 
       template<typename _Alloc2>
@@ -322,19 +325,22 @@ _GLIBCXX_ALLOC_TR_NESTED_TYPE(propagate_on_container_swap,
 	  template<typename>
 	    static false_type __test(...);
 
-	  typedef decltype(__test<_Alloc2>(0)) type;
-	  static const bool value = type::value;
+	  using type = decltype(__test<_Alloc2>(0));
 	};
+
       template<typename _Alloc2>
-	static typename
-       	enable_if<__select_helper<_Alloc2>::value, _Alloc2>::type
-       	_S_select(_Alloc2& __a)
+	using __has_soccc = typename __select_helper<_Alloc2>::type;
+
+      template<typename _Alloc2,
+	       typename = _Require<__has_soccc<_Alloc2>>>
+	static _Alloc2
+	_S_select(_Alloc2& __a, int)
 	{ return __a.select_on_container_copy_construction(); }
 
-      template<typename _Alloc2>
-	static typename
-       	enable_if<!__select_helper<_Alloc2>::value, _Alloc2>::type
-       	_S_select(_Alloc2& __a)
+      template<typename _Alloc2,
+	       typename = _Require<__not_<__has_soccc<_Alloc2>>>>
+	static _Alloc2
+	_S_select(_Alloc2& __a, ...)
 	{ return __a; }
 
     public:
@@ -413,7 +419,7 @@ _GLIBCXX_ALLOC_TR_NESTED_TYPE(propagate_on_container_swap,
        *  otherwise returns @c numeric_limits<size_type>::max()
       */
       static size_type max_size(const _Alloc& __a) noexcept
-      { return _S_max_size(__a); }
+      { return _S_max_size(__a, 0); }
 
       /**
        *  @brief  Obtain an allocator to use when copying a container.
@@ -425,31 +431,10 @@ _GLIBCXX_ALLOC_TR_NESTED_TYPE(propagate_on_container_swap,
       */
       static _Alloc
       select_on_container_copy_construction(const _Alloc& __rhs)
-      { return _S_select(__rhs); }
+      { return _S_select(__rhs, 0); }
     };
 
   template<typename _Alloc>
-  template<typename _Alloc2>
-    const bool allocator_traits<_Alloc>::__allocate_helper<_Alloc2>::value;
-
-  template<typename _Alloc>
-  template<typename _Tp, typename... _Args>
-    const bool
-    allocator_traits<_Alloc>::__construct_helper<_Tp, _Args...>::value;
-
-  template<typename _Alloc>
-  template<typename _Tp>
-    const bool allocator_traits<_Alloc>::__destroy_helper<_Tp>::value;
-
-  template<typename _Alloc>
-  template<typename _Alloc2>
-    const bool allocator_traits<_Alloc>::__maxsize_helper<_Alloc2>::value;
-
-  template<typename _Alloc>
-  template<typename _Alloc2>
-    const bool allocator_traits<_Alloc>::__select_helper<_Alloc2>::value;
-
-  template<typename _Alloc>
     inline void
     __do_alloc_on_copy(_Alloc& __one, const _Alloc& __two, true_type)
     { __one = __two; }
diff --git a/libstdc++-v3/include/bits/ptr_traits.h b/libstdc++-v3/include/bits/ptr_traits.h
index 714db79..94995c8 100644
--- a/libstdc++-v3/include/bits/ptr_traits.h
+++ b/libstdc++-v3/include/bits/ptr_traits.h
@@ -73,24 +73,19 @@ _GLIBCXX_HAS_NESTED_TYPE(difference_type)
     class __ptrtr_rebind_helper
     {
       template<typename _Ptr2, typename _Up2>
-	static constexpr bool
-       	_S_chk(typename _Ptr2::template rebind<_Up2>*)
-       	{ return true; }
+	static constexpr true_type
+	_S_chk(typename _Ptr2::template rebind<_Up2>*);
 
       template<typename, typename>
-        static constexpr bool
-       	_S_chk(...)
-       	{ return false; }
+	static constexpr false_type
+	_S_chk(...);
 
     public:
-      static const bool __value = _S_chk<_Ptr, _Up>(nullptr);
+      using __type = decltype(_S_chk<_Ptr, _Up>(nullptr));
     };
 
-  template<typename _Ptr, typename _Up>
-    const bool __ptrtr_rebind_helper<_Ptr, _Up>::__value;
-
   template<typename _Tp, typename _Up,
-           bool = __ptrtr_rebind_helper<_Tp, _Up>::__value>
+           bool = __ptrtr_rebind_helper<_Tp, _Up>::__type::value>
     struct __ptrtr_rebind;
 
   template<typename _Tp, typename _Up>
diff --git a/libstdc++-v3/include/bits/stl_tree.h b/libstdc++-v3/include/bits/stl_tree.h
index d24b1f7..4bc3c60 100644
--- a/libstdc++-v3/include/bits/stl_tree.h
+++ b/libstdc++-v3/include/bits/stl_tree.h
@@ -1080,9 +1080,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  clear();
 	  if (__x._M_root() != 0)
 	    _M_move_data(__x, std::true_type());
-	  if (_Alloc_traits::_S_propagate_on_move_assign())
-	    std::__alloc_on_move(_M_get_Node_allocator(),
-				 __x._M_get_Node_allocator());
+	  std::__alloc_on_move(_M_get_Node_allocator(),
+			       __x._M_get_Node_allocator());
 	  return true;
 	}
       return false;
diff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h
index f482957..98ac708 100644
--- a/libstdc++-v3/include/bits/stl_vector.h
+++ b/libstdc++-v3/include/bits/stl_vector.h
@@ -165,13 +165,17 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 
       pointer
       _M_allocate(size_t __n)
-      { return __n != 0 ? _M_impl.allocate(__n) : 0; }
+      {
+	typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Tr;
+	return __n != 0 ? _Tr::allocate(_M_impl, __n) : 0;
+      }
 
       void
       _M_deallocate(pointer __p, size_t __n)
       {
+	typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Tr;
 	if (__p)
-	  _M_impl.deallocate(__p, __n);
+	  _Tr::deallocate(_M_impl, __p, __n);
       }
 
     private:
@@ -1446,9 +1450,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
 	vector __tmp(get_allocator());
 	this->_M_impl._M_swap_data(__tmp._M_impl);
 	this->_M_impl._M_swap_data(__x._M_impl);
-	if (_Alloc_traits::_S_propagate_on_move_assign())
-	  std::__alloc_on_move(_M_get_Tp_allocator(),
-			       __x._M_get_Tp_allocator());
+	std::__alloc_on_move(_M_get_Tp_allocator(), __x._M_get_Tp_allocator());
       }
 
       // Do move assignment when it might not be possible to move source
diff --git a/libstdc++-v3/include/ext/alloc_traits.h b/libstdc++-v3/include/ext/alloc_traits.h
index 26e457f..14fbc43 100644
--- a/libstdc++-v3/include/ext/alloc_traits.h
+++ b/libstdc++-v3/include/ext/alloc_traits.h
@@ -44,73 +44,47 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 #if __cplusplus >= 201103L
   template<typename _Alloc>
-    struct __allocator_always_compares_equal
-    { static const bool value = false; };
-
-  template<typename _Alloc>
-    const bool __allocator_always_compares_equal<_Alloc>::value;
+    struct __allocator_always_compares_equal : std::false_type { };
 
   template<typename _Tp>
     struct __allocator_always_compares_equal<std::allocator<_Tp>>
-    { static const bool value = true; };
-
-  template<typename _Tp>
-    const bool __allocator_always_compares_equal<std::allocator<_Tp>>::value;
+    : std::true_type { };
 
   template<typename, typename> struct array_allocator;
 
   template<typename _Tp, typename _Array>
     struct __allocator_always_compares_equal<array_allocator<_Tp, _Array>>
-    { static const bool value = true; };
-
-  template<typename _Tp, typename _Array>
-    const bool
-    __allocator_always_compares_equal<array_allocator<_Tp, _Array>>::value;
+    : std::true_type { };
 
   template<typename> struct bitmap_allocator;
 
   template<typename _Tp>
     struct __allocator_always_compares_equal<bitmap_allocator<_Tp>>
-    { static const bool value = true; };
-
-  template<typename _Tp>
-    const bool __allocator_always_compares_equal<bitmap_allocator<_Tp>>::value;
+    : std::true_type { };
 
   template<typename> struct malloc_allocator;
 
   template<typename _Tp>
     struct __allocator_always_compares_equal<malloc_allocator<_Tp>>
-    { static const bool value = true; };
-
-  template<typename _Tp>
-    const bool __allocator_always_compares_equal<malloc_allocator<_Tp>>::value;
+    : std::true_type { };
 
   template<typename> struct mt_allocator;
 
   template<typename _Tp>
     struct __allocator_always_compares_equal<mt_allocator<_Tp>>
-    { static const bool value = true; };
-
-  template<typename _Tp>
-    const bool __allocator_always_compares_equal<mt_allocator<_Tp>>::value;
+    : std::true_type { };
 
   template<typename> struct new_allocator;
 
   template<typename _Tp>
     struct __allocator_always_compares_equal<new_allocator<_Tp>>
-    { static const bool value = true; };
-
-  template<typename _Tp>
-    const bool __allocator_always_compares_equal<new_allocator<_Tp>>::value;
+    : std::true_type { };
 
   template<typename> struct pool_allocator;
 
   template<typename _Tp>
     struct __allocator_always_compares_equal<pool_allocator<_Tp>>
-    { static const bool value = true; };
-
-  template<typename _Tp>
-    const bool __allocator_always_compares_equal<pool_allocator<_Tp>>::value;
+    : std::true_type { };
 #endif
 
 /**
@@ -131,7 +105,7 @@ template<typename _Alloc>
     typedef typename _Base_type::const_pointer      const_pointer;
     typedef typename _Base_type::size_type          size_type;
     typedef typename _Base_type::difference_type    difference_type;
-    // C++0x allocators do not define reference or const_reference
+    // C++11 allocators do not define reference or const_reference
     typedef value_type&                             reference;
     typedef const value_type&                       const_reference;
     using _Base_type::allocate;
@@ -142,10 +116,9 @@ template<typename _Alloc>
 
   private:
     template<typename _Ptr>
-      struct __is_custom_pointer
-      : std::integral_constant<bool, std::is_same<pointer, _Ptr>::value
-                                     && !std::is_pointer<_Ptr>::value>
-      { };
+      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
diff --git a/libstdc++-v3/testsuite/20_util/allocator_traits/members/allocate_hint_nonpod.cc b/libstdc++-v3/testsuite/20_util/allocator_traits/members/allocate_hint_nonpod.cc
new file mode 100644
index 0000000..b5883dc
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/allocator_traits/members/allocate_hint_nonpod.cc
@@ -0,0 +1,69 @@
+// { dg-options "-std=gnu++11" }
+
+// Copyright (C) 2014 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <memory>
+#include <testsuite_allocator.h>
+
+// User-defined pointer type with non-trivial destructor.
+template<typename T>
+struct Pointer : __gnu_test::PointerBase<Pointer<T>, T>
+{
+  using __gnu_test::PointerBase<Pointer<T>, T>::PointerBase;
+
+  ~Pointer() { /* non-trivial */ }
+};
+
+// Minimal allocator with user-defined pointer type.
+template<typename T>
+struct Alloc
+{
+  typedef T value_type;
+  typedef Pointer<T> pointer;
+
+  Alloc() = default;
+
+  template<typename U>
+    Alloc(const Alloc<U>&) { }
+
+  pointer allocate(std::size_t n)  // does not take a hint
+  { return pointer(std::allocator<T>().allocate(n)); }
+
+  void deallocate(pointer p, std::size_t n)
+  { std::allocator<T>().deallocate(p.value, n); }
+};
+
+template<typename T>
+bool operator==(Alloc<T> l, Alloc<T> r) { return true; }
+
+template<typename T>
+bool operator!=(Alloc<T> l, Alloc<T> r) { return false; }
+
+void test01()
+{
+  typedef std::allocator_traits<Alloc<int>> traits_type;
+  traits_type::allocator_type a;
+  traits_type::const_void_pointer v;
+  traits_type::pointer p = traits_type::allocate(a, 1, v);
+  traits_type::deallocate(a, p, 1);
+}
+
+int main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/20_util/allocator_traits/requirements/typedefs2.cc b/libstdc++-v3/testsuite/20_util/allocator_traits/requirements/typedefs2.cc
new file mode 100644
index 0000000..04521a2
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/allocator_traits/requirements/typedefs2.cc
@@ -0,0 +1,93 @@
+// { dg-options "-std=gnu++11" }
+//
+// Copyright (C) 2013 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <memory>
+#include <testsuite_allocator.h>
+
+// { dg-do compile }
+
+template<typename T>
+struct ptr
+{
+  ptr() = default;
+  template<typename U>
+    ptr(ptr<U> const& p) { }
+};
+
+// This doesn't meet the allocator requirements, it's only to check
+// that allocator_traits finds the right nested types.
+template<typename T>
+struct alloc
+{
+  typedef T value_type;
+
+  typedef ptr<T> pointer;
+  typedef ptr<const T> const_pointer;
+  typedef ptr<void> void_pointer;
+  typedef ptr<const void> const_void_pointer;
+  typedef int difference_type;
+  typedef int size_type;
+
+  typedef std::false_type propagate_on_container_copy_assignment;
+  typedef std::false_type propagate_on_container_move_assignment;
+  typedef std::false_type propagate_on_container_swap;
+};
+
+typedef alloc<int> alloc_type;
+typedef std::allocator_traits<alloc_type> traits;
+
+using std::is_same;
+
+static_assert( is_same<traits::pointer, alloc_type::pointer>::value,
+               "pointer" );
+
+static_assert( is_same<traits::const_pointer,
+                       alloc_type::const_pointer>::value,
+               "const_pointer" );
+
+static_assert( is_same<traits::void_pointer, alloc_type::void_pointer>::value,
+               "void_pointer" );
+
+static_assert( is_same<traits::const_void_pointer,
+                       alloc_type::const_void_pointer>::value,
+               "const_void_pointer");
+
+static_assert( is_same<traits::difference_type,
+                       alloc_type::difference_type>::value,
+               "difference_type" );
+
+static_assert( is_same<traits::size_type, alloc_type::size_type>::value,
+               "size_type" );
+
+static_assert( is_same<traits::size_type, alloc_type::size_type>::value,
+               "size_type" );
+
+static_assert( is_same<traits::propagate_on_container_copy_assignment,
+                       alloc_type::propagate_on_container_copy_assignment
+                      >::value,
+               "propagate_on_container_copy_assignment" );
+
+static_assert( is_same<traits::propagate_on_container_move_assignment,
+                       alloc_type::propagate_on_container_move_assignment
+                      >::value,
+               "propagate_on_container_move_assignment" );
+
+static_assert( is_same<traits::propagate_on_container_swap,
+                       alloc_type::propagate_on_container_swap>::value,
+               "propagate_on_container_swap" );
diff --git a/libstdc++-v3/testsuite/util/testsuite_allocator.h b/libstdc++-v3/testsuite/util/testsuite_allocator.h
index 748557c..822a025 100644
--- a/libstdc++-v3/testsuite/util/testsuite_allocator.h
+++ b/libstdc++-v3/testsuite/util/testsuite_allocator.h
@@ -517,6 +517,106 @@ namespace __gnu_test
       void deallocate(pointer p, std::size_t n)
       { std::allocator<Tp>::deallocate(std::addressof(*p), n); }
     };
+
+  // Utility for use as CRTP base class of custom pointer types
+  template<typename Derived, typename T>
+    struct PointerBase
+    {
+      typedef T element_type;
+
+      // typedefs for iterator_traits
+      typedef T value_type;
+      typedef std::ptrdiff_t difference_type;
+      typedef std::random_access_iterator_tag iterator_category;
+      typedef Derived pointer;
+      typedef T& reference;
+
+      T* value;
+
+      explicit PointerBase(T* p = nullptr) : value(p) { }
+
+      template<typename D, typename U,
+	       typename = decltype(static_cast<T*>(std::declval<U*>()))>
+	PointerBase(const PointerBase<D, U>& p) : value(p.value) { }
+
+      T& operator*() const { return *value; }
+      T* operator->() const { return value; }
+
+      Derived& operator++() { ++value; return derived(); }
+      Derived operator++(int) { Derived tmp(derived()); ++value; return tmp; }
+      Derived& operator--() { --value; return derived(); }
+      Derived operator--(int) { Derived tmp(derived()); --value; return tmp; }
+
+      Derived& operator+=(difference_type n) { value += n; return derived(); }
+      Derived& operator-=(difference_type n) { value -= n; return derived(); }
+
+      explicit operator bool() const { return value != nullptr; }
+
+      Derived
+      operator+(difference_type n) const
+      {
+	Derived p(derived());
+	return p += n;
+      }
+
+      Derived
+      operator-(difference_type n) const
+      {
+	Derived p(derived());
+	return p -= n;
+      }
+
+    private:
+      Derived& derived() { return static_cast<Derived&>(*this); }
+    };
+
+    template<typename D, typename T>
+    std::ptrdiff_t operator-(PointerBase<D, T> l, PointerBase<D, T> r)
+    { return l.value - r.value; }
+
+    template<typename D, typename T>
+    bool operator==(PointerBase<D, T> l, PointerBase<D, T> r)
+    { return l.value == r.value; }
+
+    template<typename D, typename T>
+    bool operator!=(PointerBase<D, T> l, PointerBase<D, T> r)
+    { return l.value != r.value; }
+
+    // implementation for void specializations
+    template<typename T>
+    struct PointerBase_void
+    {
+      typedef T element_type;
+
+      // typedefs for iterator_traits
+      typedef T value_type;
+      typedef std::ptrdiff_t difference_type;
+      typedef std::random_access_iterator_tag iterator_category;
+
+      T* value;
+
+      explicit PointerBase_void(T* p = nullptr) : value(p) { }
+
+      template<typename D, typename U,
+	       typename = decltype(static_cast<T*>(std::declval<U*>()))>
+	PointerBase_void(const PointerBase<D, U>& p) : value(p.value) { }
+
+      explicit operator bool() const { return value != nullptr; }
+    };
+
+    template<typename Derived>
+    struct PointerBase<Derived, void> : PointerBase_void<void>
+    {
+      using PointerBase_void::PointerBase_void;
+      typedef Derived pointer;
+    };
+
+    template<typename Derived>
+    struct PointerBase<Derived, const void> : PointerBase_void<const void>
+    {
+      using PointerBase_void::PointerBase_void;
+      typedef Derived pointer;
+    };
 #endif
 
 } // namespace __gnu_test


More information about the Gcc-patches mailing list