Patchwork [v3] finish allocator support in <future> and std::shared_ptr

login
register
mail settings
Submitter Jonathan Wakely
Date Nov. 8, 2011, 4:54 p.m.
Message ID <CAH6eHdTQ_VxXVfrOG-Jq0KZSOBHrgHnhiV9-WOFR4pz7oWXU=A@mail.gmail.com>
Download mbox | patch
Permalink /patch/124395/
State New
Headers show

Comments

Jonathan Wakely - Nov. 8, 2011, 4:54 p.m.
This is the final version of a patch I've had hanging around for about
6 months, it makes futures and shared_ptr use allocator_traits so they
work with minimal C++11 allocators, such as the testsuite's
SimpleAllocator, and implement the proposed resolution of LWG 2070
(which is still in Open state, but only while wording is tweaked.)  I
also added the 'final' virt-specifier to a few polymorphic classes.

        * include/bits/shared_ptr_base.h (_Sp_counted_ptr): Make 'final'.
        (_Sp_counted_deleter): Make 'final'. Use allocator_traits.
        (_Sp_counted_ptr_inplace): Make 'final'. Use allocator_traits.
        Derive from _Sp_counted_ptr instead of _Sp_counted_deleter to use EBO
        for the allocator.
        (__shared_count, __shared_ptr): Use allocator_traits.
        * include/std/future (__future_base::_Result_alloc): Make 'final'. Use
        allocator traits.
        (__future_base::_Task_state): Make 'final'.
        (__future_base::_Deferred_state): Likewise.
        (__future_base::_Async_state): Likewise.
        * testsuite/20_util/shared_ptr/cons/alloc_min.cc: New.
        * testsuite/20_util/shared_ptr/creation/alloc_min.cc: New.
        * testsuite/20_util/shared_ptr/creation/private.cc: New.
        * testsuite/20_util/shared_ptr/cons/43820_neg.cc: Adjust line numbers.
        * testsuite/30_threads/packaged_task/cons/alloc_min.cc: New.
        * testsuite/30_threads/promise/cons/alloc_min.cc: New.

tested x86_64-linux, committed to trunk

Patch

Index: include/std/future
===================================================================
--- include/std/future	(revision 181170)
+++ include/std/future	(revision 181171)
@@ -264,10 +264,10 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
     /// Result_alloc.
     template<typename _Res, typename _Alloc>
-      struct _Result_alloc : _Result<_Res>, _Alloc
+      struct _Result_alloc final : _Result<_Res>, _Alloc
       {
-        typedef typename _Alloc::template rebind<_Result_alloc>::other
-          __allocator_type;
+        typedef typename allocator_traits<_Alloc>::template
+          rebind_alloc<_Result_alloc> __allocator_type;
 
         explicit
 	_Result_alloc(const _Alloc& __a) : _Result<_Res>(), _Alloc(__a)
@@ -276,9 +276,10 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       private:
 	void _M_destroy()
         {
+	  typedef allocator_traits<__allocator_type> __traits;
           __allocator_type __a(*this);
-          __a.destroy(this);
-          __a.deallocate(this, 1);
+	  __traits::destroy(__a, this);
+	  __traits::deallocate(__a, this, 1);
         }
       };
 
@@ -287,15 +288,17 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _S_allocate_result(const _Allocator& __a)
       {
         typedef _Result_alloc<_Res, _Allocator>	__result_type;
-        typename __result_type::__allocator_type __a2(__a);
-        __result_type* __p = __a2.allocate(1);
+	typedef allocator_traits<typename __result_type::__allocator_type>
+	  __traits;
+        typename __traits::allocator_type __a2(__a);
+        __result_type* __p = __traits::allocate(__a2, 1);
         __try
 	{
-          __a2.construct(__p, __a);
+	  __traits::construct(__a2, __p, __a);
         }
         __catch(...)
         {
-          __a2.deallocate(__p, 1);
+	  __traits::deallocate(__a2, __p, 1);
           __throw_exception_again;
         }
         return _Ptr<__result_type>(__p);
@@ -1239,7 +1242,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     };
 
   template<typename _Res, typename... _Args>
-    struct __future_base::_Task_state<_Res(_Args...)>
+    struct __future_base::_Task_state<_Res(_Args...)> final
     : __future_base::_State_base
     {
       typedef _Res _Res_type;
@@ -1393,7 +1396,8 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 
   template<typename _BoundFn, typename _Res>
-    class __future_base::_Deferred_state : public __future_base::_State_base
+    class __future_base::_Deferred_state final
+    : public __future_base::_State_base
     {
     public:
       explicit
@@ -1415,7 +1419,8 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     };
 
   template<typename _BoundFn, typename _Res>
-    class __future_base::_Async_state : public __future_base::_State_base
+    class __future_base::_Async_state final
+    : public __future_base::_State_base
     {
     public:
       explicit
Index: include/bits/shared_ptr_base.h
===================================================================
--- include/bits/shared_ptr_base.h	(revision 181170)
+++ include/bits/shared_ptr_base.h	(revision 181171)
@@ -281,7 +281,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Counted ptr with no deleter or allocator support
   template<typename _Ptr, _Lock_policy _Lp>
-    class _Sp_counted_ptr : public _Sp_counted_base<_Lp>
+    class _Sp_counted_ptr final : public _Sp_counted_base<_Lp>
     {
     public:
       explicit
@@ -321,20 +321,17 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Support for custom deleter and/or allocator
   template<typename _Ptr, typename _Deleter, typename _Alloc, _Lock_policy _Lp>
-    class _Sp_counted_deleter : public _Sp_counted_base<_Lp>
+    class _Sp_counted_deleter final : public _Sp_counted_base<_Lp>
     {
-      typedef typename _Alloc::template
-	  rebind<_Sp_counted_deleter>::other _My_alloc_type;
-
       // Helper class that stores the Deleter and also acts as an allocator.
       // Used to dispose of the owned pointer and the internal refcount
       // Requires that copies of _Alloc can free each other's memory.
       struct _My_Deleter
-      : public _My_alloc_type    // copy constructor must not throw
+      : public _Alloc           // copy constructor must not throw
       {
-	_Deleter _M_del;         // copy constructor must not throw
+	_Deleter _M_del;        // copy constructor must not throw
 	_My_Deleter(_Deleter __d, const _Alloc& __a)
-	: _My_alloc_type(__a), _M_del(__d) { }
+	: _Alloc(__a), _M_del(__d) { }
       };
 
     public:
@@ -353,9 +350,11 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       virtual void
       _M_destroy() noexcept
       {
-	_My_alloc_type __a(_M_del);
-	this->~_Sp_counted_deleter();
-	__a.deallocate(this, 1);
+	typedef typename allocator_traits<_Alloc>::template
+	  rebind_traits<_Sp_counted_deleter> _Alloc_traits;
+	typename _Alloc_traits::allocator_type __a(_M_del);
+	_Alloc_traits::destroy(__a, this);
+	_Alloc_traits::deallocate(__a, this, 1);
       }
 
       virtual void*
@@ -375,51 +374,46 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // helpers for make_shared / allocate_shared
 
-  template<typename _Tp>
-    struct _Sp_destroy_inplace
-    {
-      void operator()(_Tp* __p) const { if (__p) __p->~_Tp(); }
-    };
-
   struct _Sp_make_shared_tag { };
 
   template<typename _Tp, typename _Alloc, _Lock_policy _Lp>
-    class _Sp_counted_ptr_inplace
-    : public _Sp_counted_deleter<_Tp*, _Sp_destroy_inplace<_Tp>, _Alloc, _Lp>
+    class _Sp_counted_ptr_inplace final : public _Sp_counted_base<_Lp>
     {
-      typedef _Sp_counted_deleter<_Tp*, _Sp_destroy_inplace<_Tp>, _Alloc, _Lp>
-	_Base_type;
+      // Helper class that stores the pointer and also acts as an allocator.
+      // Used to dispose of the owned pointer and the internal refcount
+      // Requires that copies of _Alloc can free each other's memory.
+      struct _Impl
+      : public _Alloc           // copy constructor must not throw
+      {
+	_Impl(_Alloc __a) : _Alloc(__a), _M_ptr() { }
+	_Tp* _M_ptr;
+      };
 
     public:
-      explicit
-      _Sp_counted_ptr_inplace(_Alloc __a)
-      : _Base_type(static_cast<_Tp*>(0), _Sp_destroy_inplace<_Tp>(), __a)
-      , _M_storage()
-      {
-	void* __p = &_M_storage;
-	::new (__p) _Tp();  // might throw
-	_Base_type::_M_ptr = static_cast<_Tp*>(__p);
-      }
-
       template<typename... _Args>
 	_Sp_counted_ptr_inplace(_Alloc __a, _Args&&... __args)
-	: _Base_type(static_cast<_Tp*>(0), _Sp_destroy_inplace<_Tp>(), __a)
-	, _M_storage()
+	: _M_impl(__a), _M_storage()
 	{
-	  void* __p = &_M_storage;
-	  ::new (__p) _Tp(std::forward<_Args>(__args)...);  // might throw
-	  _Base_type::_M_ptr = static_cast<_Tp*>(__p);
+	  _M_impl._M_ptr = static_cast<_Tp*>(static_cast<void*>(&_M_storage));
+	  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+	  // 2070.  allocate_shared should use allocator_traits<A>::construct
+	  allocator_traits<_Alloc>::construct(__a, _M_impl._M_ptr,
+	      std::forward<_Args>(__args)...); // might throw
 	}
 
+      virtual void
+      _M_dispose() noexcept
+      { allocator_traits<_Alloc>::destroy(_M_impl, _M_impl._M_ptr); }
+
       // Override because the allocator needs to know the dynamic type
       virtual void
       _M_destroy() noexcept
       {
-	typedef typename _Alloc::template
-	    rebind<_Sp_counted_ptr_inplace>::other _My_alloc_type;
-	_My_alloc_type __a(_Base_type::_M_del);
-	this->~_Sp_counted_ptr_inplace();
-	__a.deallocate(this, 1);
+	typedef typename allocator_traits<_Alloc>::template
+	  rebind_traits<_Sp_counted_ptr_inplace> _Alloc_traits;
+	typename _Alloc_traits::allocator_type __a(_M_impl);
+	_Alloc_traits::destroy(__a, this);
+	_Alloc_traits::deallocate(__a, this, 1);
       }
 
       // Sneaky trick so __shared_ptr can get the managed pointer
@@ -429,13 +423,14 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifdef __GXX_RTTI
 	return __ti == typeid(_Sp_make_shared_tag)
 	       ? static_cast<void*>(&_M_storage)
-	       : _Base_type::_M_get_deleter(__ti);
+	       : 0;
 #else
         return 0;
 #endif
       }
 
     private:
+      _Impl _M_impl;
       typename aligned_storage<sizeof(_Tp), alignment_of<_Tp>::value>::type
 	_M_storage;
     };
@@ -468,18 +463,21 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  // The allocator's value_type doesn't matter, will rebind it anyway.
 	  typedef std::allocator<int> _Alloc;
 	  typedef _Sp_counted_deleter<_Ptr, _Deleter, _Alloc, _Lp> _Sp_cd_type;
-	  typedef std::allocator<_Sp_cd_type> _Alloc2;
-	  _Alloc2 __a2;
+	  typedef typename allocator_traits<_Alloc>::template
+	    rebind_traits<_Sp_cd_type> _Alloc_traits;
+	  typename _Alloc_traits::allocator_type __a;
+	  _Sp_cd_type* __mem = 0;
 	  __try
 	    {
-	      _M_pi = __a2.allocate(1);
-	      ::new(static_cast<void*>(_M_pi)) _Sp_cd_type(__p, __d);
+	      __mem = _Alloc_traits::allocate(__a, 1);
+	      _Alloc_traits::construct(__a, __mem, __p, std::move(__d));
+	      _M_pi = __mem;
 	    }
 	  __catch(...)
 	    {
 	      __d(__p); // Call _Deleter on __p.
-	      if (_M_pi)
-		__a2.deallocate(static_cast<_Sp_cd_type*>(_M_pi), 1);
+	      if (__mem)
+	        _Alloc_traits::deallocate(__a, __mem, 1);
 	      __throw_exception_again;
 	    }
 	}
@@ -488,18 +486,22 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	__shared_count(_Ptr __p, _Deleter __d, _Alloc __a) : _M_pi(0)
 	{
 	  typedef _Sp_counted_deleter<_Ptr, _Deleter, _Alloc, _Lp> _Sp_cd_type;
-	  typedef typename _Alloc::template rebind<_Sp_cd_type>::other _Alloc2;
-	  _Alloc2 __a2(__a);
+	  typedef typename allocator_traits<_Alloc>::template
+	    rebind_traits<_Sp_cd_type> _Alloc_traits;
+	  typename _Alloc_traits::allocator_type __a2(__a);
+	  _Sp_cd_type* __mem = 0;
 	  __try
 	    {
-	      _M_pi = __a2.allocate(1);
-	      ::new(static_cast<void*>(_M_pi)) _Sp_cd_type(__p, __d, __a);
+	      __mem = _Alloc_traits::allocate(__a2, 1);
+	      _Alloc_traits::construct(__a2, __mem,
+		  __p, std::move(__d), std::move(__a));
+	      _M_pi = __mem;
 	    }
 	  __catch(...)
 	    {
 	      __d(__p); // Call _Deleter on __p.
-	      if (_M_pi)
-		__a2.deallocate(static_cast<_Sp_cd_type*>(_M_pi), 1);
+	      if (__mem)
+	        _Alloc_traits::deallocate(__a2, __mem, 1);
 	      __throw_exception_again;
 	    }
 	}
@@ -510,18 +512,19 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	: _M_pi(0)
 	{
 	  typedef _Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp> _Sp_cp_type;
-	  typedef typename _Alloc::template rebind<_Sp_cp_type>::other _Alloc2;
-	  _Alloc2 __a2(__a);
+	  typedef typename allocator_traits<_Alloc>::template
+	    rebind_traits<_Sp_cp_type> _Alloc_traits;
+	  typename _Alloc_traits::allocator_type __a2(__a);
+	  _Sp_cp_type* __mem = _Alloc_traits::allocate(__a2, 1);
 	  __try
 	    {
-	      _M_pi = __a2.allocate(1);
-	      ::new(static_cast<void*>(_M_pi)) _Sp_cp_type(__a,
+	      _Alloc_traits::construct(__a2, __mem, std::move(__a),
 		    std::forward<_Args>(__args)...);
+	      _M_pi = __mem;
 	    }
 	  __catch(...)
 	    {
-	      if (_M_pi)
-		__a2.deallocate(static_cast<_Sp_cp_type*>(_M_pi), 1);
+	      _Alloc_traits::deallocate(__a2, __mem, 1);
 	      __throw_exception_again;
 	    }
 	}
@@ -1001,8 +1004,9 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
         {
           void operator()(_Tp* __ptr)
           {
-            _M_alloc.destroy(__ptr);
-            _M_alloc.deallocate(__ptr, 1);
+	    typedef allocator_traits<_Alloc> _Alloc_traits;
+	    _Alloc_traits::destroy(_M_alloc, __ptr);
+	    _Alloc_traits::deallocate(_M_alloc, __ptr, 1);
           }
           _Alloc _M_alloc;
         };
@@ -1014,14 +1018,18 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
         {
 	  typedef typename _Alloc::template rebind<_Tp>::other _Alloc2;
           _Deleter<_Alloc2> __del = { _Alloc2(__a) };
-          _M_ptr = __del._M_alloc.allocate(1);
+	  typedef allocator_traits<_Alloc2> __traits;
+          _M_ptr = __traits::allocate(__del._M_alloc, 1);
 	  __try
 	    {
-              __del._M_alloc.construct(_M_ptr, std::forward<_Args>(__args)...);
+	      // _GLIBCXX_RESOLVE_LIB_DEFECTS
+	      // 2070. allocate_shared should use allocator_traits<A>::construct
+	      __traits::construct(__del._M_alloc, _M_ptr,
+		                  std::forward<_Args>(__args)...);
 	    }
 	  __catch(...)
 	    {
-              __del._M_alloc.deallocate(_M_ptr, 1);
+	      __traits::deallocate(__del._M_alloc, _M_ptr, 1);
 	      __throw_exception_again;
 	    }
           __shared_count<_Lp> __count(_M_ptr, __del, __del._M_alloc);
Index: testsuite/20_util/shared_ptr/cons/alloc_min.cc
===================================================================
--- testsuite/20_util/shared_ptr/cons/alloc_min.cc	(revision 0)
+++ testsuite/20_util/shared_ptr/cons/alloc_min.cc	(revision 181171)
@@ -0,0 +1,35 @@ 
+// { dg-options "-std=gnu++0x" }
+// { dg-do compile }
+
+// Copyright (C) 2011 Free Software Foundation
+//
+// 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/>.
+
+// 20.7.2.2 Class template shared_ptr [util.smartptr.shared]
+
+#include <memory>
+#include <testsuite_allocator.h>
+
+struct X { };
+
+// 20.7.2.2.1 shared_ptr constructors [util.smartptr.shared.const]
+
+// test shared_ptr with minimal allocator
+
+__gnu_test::SimpleAllocator<X> alloc;
+auto deleter = [](X* p) { delete p; };
+std::shared_ptr<X> p(new X, deleter, alloc);
+
Index: testsuite/20_util/shared_ptr/creation/alloc_min.cc
===================================================================
--- testsuite/20_util/shared_ptr/creation/alloc_min.cc	(revision 0)
+++ testsuite/20_util/shared_ptr/creation/alloc_min.cc	(revision 181171)
@@ -0,0 +1,34 @@ 
+// { dg-options "-std=gnu++0x" }
+// { dg-do compile }
+
+// Copyright (C) 2011 Free Software Foundation
+//
+// 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/>.
+
+// 20.7.2.2 Class template shared_ptr [util.smartptr.shared]
+
+#include <memory>
+#include <testsuite_allocator.h>
+
+struct X { };
+
+// 20.7.2.2.6 shared_ptr creation [util.smartptr.shared.create]
+
+// test shared_ptr with minimal allocator
+
+__gnu_test::SimpleAllocator<X> alloc;
+auto p = std::allocate_shared<X>(alloc);
+
Index: testsuite/20_util/shared_ptr/creation/private.cc
===================================================================
--- testsuite/20_util/shared_ptr/creation/private.cc	(revision 0)
+++ testsuite/20_util/shared_ptr/creation/private.cc	(revision 181171)
@@ -0,0 +1,52 @@ 
+// { dg-options "-std=gnu++0x" }
+
+// Copyright (C) 2011 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 <new>
+
+// The behaviour tested here relies on the resolution of LWG issue 2070
+
+template<typename T> struct MyAlloc;
+
+class Private
+{
+  Private() = default;
+  Private(const Private&) = default;
+  ~Private() = default;
+
+  friend class MyAlloc<Private>;
+
+public:
+  int get() const { return 0; }
+};
+
+template<typename T>
+struct MyAlloc : std::allocator<Private>
+{
+  void construct(T* p) { ::new((void*)p) T(); }
+  void destroy(T* p) { p->~T(); }
+};
+
+int main()
+{
+  MyAlloc<Private> a;
+  auto p = std::allocate_shared<Private>(a);
+  return p->get();
+}
+
Index: testsuite/20_util/shared_ptr/cons/43820_neg.cc
===================================================================
--- testsuite/20_util/shared_ptr/cons/43820_neg.cc	(revision 181170)
+++ testsuite/20_util/shared_ptr/cons/43820_neg.cc	(revision 181171)
@@ -32,9 +32,9 @@  void test01()
 {
   X* px = 0;
   std::shared_ptr<X> p1(px);   // { dg-error "here" }
-  // { dg-error "incomplete" "" { target *-*-* } 768 }
+  // { dg-error "incomplete" "" { target *-*-* } 771 }
 
   std::shared_ptr<X> p9(ap());  // { dg-error "here" }
-  // { dg-error "incomplete" "" { target *-*-* } 862 }
+  // { dg-error "incomplete" "" { target *-*-* } 865 }
 
 }
Index: testsuite/30_threads/packaged_task/cons/alloc_min.cc
===================================================================
--- testsuite/30_threads/packaged_task/cons/alloc_min.cc	(revision 0)
+++ testsuite/30_threads/packaged_task/cons/alloc_min.cc	(revision 181171)
@@ -0,0 +1,34 @@ 
+// { dg-do compile }
+// { dg-options "-std=gnu++0x" }
+// { dg-require-cstdint "" }
+// { dg-require-gthreads "" }
+// { dg-require-atomic-builtins "" }
+
+// Copyright (C) 2011 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/>.
+
+// Test that packaged_task can use a minimal C++11 allocator
+// and doesn't rely on C++98 allocator interface.
+
+#include <future>
+#include <testsuite_allocator.h>
+
+using std::packaged_task;
+using std::allocator_arg;
+
+__gnu_test::SimpleAllocator<int> a;
+packaged_task<int()> p(allocator_arg, a, []() { return 1; });
Index: testsuite/30_threads/promise/cons/alloc_min.cc
===================================================================
--- testsuite/30_threads/promise/cons/alloc_min.cc	(revision 0)
+++ testsuite/30_threads/promise/cons/alloc_min.cc	(revision 181171)
@@ -0,0 +1,40 @@ 
+// { dg-do compile }
+// { dg-options "-std=gnu++0x" }
+// { dg-require-cstdint "" }
+// { dg-require-gthreads "" }
+// { dg-require-atomic-builtins "" }
+
+// Copyright (C) 2011 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/>.
+
+// Test that promise can use a minimal C++11 allocator
+// and doesn't rely on C++98 allocator interface.
+
+#include <future>
+#include <testsuite_allocator.h>
+
+using std::promise;
+using std::allocator_arg;
+using std::tuple;
+
+typedef promise<int>  p;
+typedef promise<int&> pr;
+typedef promise<void> pv;
+__gnu_test::SimpleAllocator<p> a;
+
+tuple<p, pr, pv> t1{ allocator_arg, a };
+tuple<p, pr, pv> t2{ allocator_arg, a, p{}, pr{}, pv{} };