PR libstdc++/70966 make pmr::new_delete_resource() immortal
authorJonathan Wakely <jwakely@redhat.com>
Wed, 20 Jun 2018 19:34:53 +0000 (20:34 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Wed, 20 Jun 2018 19:34:53 +0000 (20:34 +0100)
Construct the program-wide resource objects using placement new. This
means they have dynamic storage duration and won't be destroyed during
termination.

PR libstdc++/70966
* include/experimental/memory_resource (__resource_adaptor_imp): Add
static assertions to enforce requirements on pointer types.
(__resource_adaptor_imp::get_allocator()): Add noexcept.
(new_delete_resource, null_memory_resource): Return address of an
object with dynamic storage duration.
(__null_memory_resource): Remove.
* testsuite/experimental/memory_resource/70966.cc: New.

From-SVN: r261818

libstdc++-v3/ChangeLog
libstdc++-v3/include/experimental/memory_resource
libstdc++-v3/testsuite/experimental/memory_resource/70966.cc [new file with mode: 0644]

index bed558032c9cd2c4ba89c79a833e4ea008f81a43..83bf2b92e0be6d82ee89d7bd057217c158f6b474 100644 (file)
@@ -1,5 +1,14 @@
 2018-06-20  Jonathan Wakely  <jwakely@redhat.com>
 
+       PR libstdc++/70966
+       * include/experimental/memory_resource (__resource_adaptor_imp): Add
+       static assertions to enforce requirements on pointer types.
+       (__resource_adaptor_imp::get_allocator()): Add noexcept.
+       (new_delete_resource, null_memory_resource): Return address of an
+       object with dynamic storage duration.
+       (__null_memory_resource): Remove.
+       * testsuite/experimental/memory_resource/70966.cc: New.
+
        * testsuite/20_util/duration/arithmetic/dr3050.cc: Add new test
        missed from recent commit.
 
index b8480c2a17b622c36fc07aa8e6fe9bde8dc01292..670a2210804a2033187640d664324bc068b6c0d5 100644 (file)
@@ -33,7 +33,6 @@
 #include <new>
 #include <atomic>
 #include <cstddef>
-#include <bits/alloc_traits.h>
 #include <experimental/bits/lfts_config.h>
 
 namespace std {
@@ -258,6 +257,22 @@ namespace pmr {
   template <typename _Alloc>
     class __resource_adaptor_imp : public memory_resource
     {
+      static_assert(is_same<char,
+         typename allocator_traits<_Alloc>::value_type>::value,
+         "Allocator's value_type is char");
+      static_assert(is_same<char*,
+         typename allocator_traits<_Alloc>::pointer>::value,
+         "Allocator's pointer type is value_type*");
+      static_assert(is_same<const char*,
+         typename allocator_traits<_Alloc>::const_pointer>::value,
+         "Allocator's const_pointer type is value_type const*");
+      static_assert(is_same<void*,
+         typename allocator_traits<_Alloc>::void_pointer>::value,
+         "Allocator's void_pointer type is void*");
+      static_assert(is_same<const void*,
+         typename allocator_traits<_Alloc>::const_void_pointer>::value,
+         "Allocator's const_void_pointer type is void const*");
+
     public:
       using allocator_type = _Alloc;
 
@@ -276,7 +291,7 @@ namespace pmr {
       __resource_adaptor_imp&
       operator=(const __resource_adaptor_imp&) = default;
 
-      allocator_type get_allocator() const { return _M_alloc; }
+      allocator_type get_allocator() const noexcept { return _M_alloc; }
 
     protected:
       virtual void*
@@ -311,13 +326,13 @@ namespace pmr {
     private:
       // Calculate Aligned Size
       // Returns a size that is larger than or equal to __size and divisible
-      // by __alignment, where __alignment is required to be the power of 2.
+      // by __alignment, where __alignment is required to be a power of 2.
       static size_t
       _S_aligned_size(size_t __size, size_t __alignment)
       { return ((__size - 1)|(__alignment - 1)) + 1; }
 
       // Determine whether alignment meets one of those preconditions:
-      // 1. Equals to Zero
+      // 1. Equal to Zero
       // 2. Is power of two
       static bool
       _S_supported (size_t __x)
@@ -337,34 +352,33 @@ namespace pmr {
   inline memory_resource*
   new_delete_resource() noexcept
   {
-    static resource_adaptor<std::allocator<char>> __r;
-    return static_cast<memory_resource*>(&__r);
+    using type = resource_adaptor<std::allocator<char>>;
+    alignas(type) static unsigned char __buf[sizeof(type)];
+    static type* __r = new(__buf) type;
+    return __r;
   }
 
-  template <typename _Alloc>
-    class __null_memory_resource : private memory_resource
+  inline memory_resource*
+  null_memory_resource() noexcept
+  {
+    class type final : public memory_resource
     {
-    protected:
       void*
-      do_allocate(size_t, size_t)
+      do_allocate(size_t, size_t) override
       { std::__throw_bad_alloc(); }
 
       void
-      do_deallocate(void*, size_t, size_t) noexcept
+      do_deallocate(void*, size_t, size_t) noexcept override
       { }
 
       bool
-      do_is_equal(const memory_resource& __other) const noexcept
+      do_is_equal(const memory_resource& __other) const noexcept override
       { return this == &__other; }
-
-      friend memory_resource* null_memory_resource() noexcept;
     };
 
-  inline memory_resource*
-  null_memory_resource() noexcept
-  {
-    static __null_memory_resource<void> __r;
-    return static_cast<memory_resource*>(&__r);
+    alignas(type) static unsigned char __buf[sizeof(type)];
+    static type* __r = new(__buf) type;
+    return __r;
   }
 
   // The default memory resource
diff --git a/libstdc++-v3/testsuite/experimental/memory_resource/70966.cc b/libstdc++-v3/testsuite/experimental/memory_resource/70966.cc
new file mode 100644 (file)
index 0000000..c0173ff
--- /dev/null
@@ -0,0 +1,56 @@
+// 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++14 } }
+
+#include <experimental/memory_resource>
+
+namespace pmr = std::experimental::pmr;
+
+struct X
+{
+  pmr::memory_resource* res = nullptr;
+  void* ptr = nullptr;
+  static constexpr std::size_t n = 64;
+
+  constexpr X() { }
+
+  explicit
+  X(pmr::memory_resource* r) : res(r), ptr(r->allocate(n)) { }
+
+  ~X() { if (ptr) res->deallocate(ptr, n); }
+};
+
+void
+swap(X& lhs, X& rhs) {
+    std::swap(lhs.res, rhs.res);
+    std::swap(lhs.ptr, rhs.ptr);
+}
+
+void
+test01()
+{
+  static X x1;
+  X x2(pmr::new_delete_resource());
+  swap(x1, x2);
+  // Now x1 will deallocate the memory during destruction of static objects.
+}
+
+int main()
+{
+  test01();
+}