PR libstdc++/80553 don't allow destroying non-destructible types
authorJonathan Wakely <jwakely@redhat.com>
Fri, 28 Apr 2017 12:56:53 +0000 (13:56 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Fri, 28 Apr 2017 12:56:53 +0000 (13:56 +0100)
PR libstdc++/80553
* include/bits/stl_construct.h (_Destroy, _Destroy_n): Add static
assertions to ensure type is destructible.
(destroy_at, destroy, destroy_n): Move from stl_uninitialized.h.
* include/bits/stl_uninitialized.h (destroy_at, destroy, destroy_n):
Move to stl_construct.h.
* testsuite/20_util/specialized_algorithms/memory_management_tools/
destroy_neg.cc: New test.
* testsuite/23_containers/vector/cons/destructible_neg.cc: New test.

From-SVN: r247379

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/stl_construct.h
libstdc++-v3/include/bits/stl_uninitialized.h
libstdc++-v3/testsuite/20_util/specialized_algorithms/memory_management_tools/destroy_neg.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/vector/cons/destructible_neg.cc [new file with mode: 0644]

index a85a39a055ce6a3a9ee67f939521da083773332a..6d78fcdd7385913d4fcb20ddc38c3817c777fcdb 100644 (file)
@@ -1,5 +1,15 @@
 2017-04-28  Jonathan Wakely  <jwakely@redhat.com>
 
+       PR libstdc++/80553
+       * include/bits/stl_construct.h (_Destroy, _Destroy_n): Add static
+       assertions to ensure type is destructible.
+       (destroy_at, destroy, destroy_n): Move from stl_uninitialized.h.
+       * include/bits/stl_uninitialized.h (destroy_at, destroy, destroy_n):
+       Move to stl_construct.h.
+       * testsuite/20_util/specialized_algorithms/memory_management_tools/
+       destroy_neg.cc: New test.
+       * testsuite/23_containers/vector/cons/destructible_neg.cc: New test.
+
        * testsuite/17_intro/headers/c++1998/stdc++_assert_neg.cc: Remove
        superfluous "" in dg-error.
 
index c1504e9bcbd6bd7bba78d0849f4e7dd772e6cc41..71483b46ab29e1f2ecbb177d055e0d2778cc77d1 100644 (file)
@@ -128,6 +128,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     {
       typedef typename iterator_traits<_ForwardIterator>::value_type
                        _Value_type;
+#if __cplusplus >= 201103L
+      // A deleted destructor is trivial, this ensures we reject such types:
+      static_assert(is_destructible<_Value_type>::value,
+                   "value type is destructible");
+#endif
       std::_Destroy_aux<__has_trivial_destructor(_Value_type)>::
        __destroy(__first, __last);
     }
@@ -151,10 +156,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       template<typename _ForwardIterator, typename _Size>
         static _ForwardIterator
         __destroy_n(_ForwardIterator __first, _Size __count)
-      {
-        std::advance(__first, __count);
-        return __first;
-      }
+       {
+         std::advance(__first, __count);
+         return __first;
+       }
     };
 
   /**
@@ -168,6 +173,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     {
       typedef typename iterator_traits<_ForwardIterator>::value_type
                        _Value_type;
+#if __cplusplus >= 201103L
+      // A deleted destructor is trivial, this ensures we reject such types:
+      static_assert(is_destructible<_Value_type>::value,
+                   "value type is destructible");
+#endif
       return std::_Destroy_n_aux<__has_trivial_destructor(_Value_type)>::
        __destroy_n(__first, __count);
     }
@@ -196,6 +206,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _Destroy(__first, __last);
     }
 
+#if __cplusplus > 201402L
+  template <typename _Tp>
+    inline void
+    destroy_at(_Tp* __location)
+    {
+      std::_Destroy(__location);
+    }
+
+  template <typename _ForwardIterator>
+    inline void
+    destroy(_ForwardIterator __first, _ForwardIterator __last)
+    {
+      std::_Destroy(__first, __last);
+    }
+
+  template <typename _ForwardIterator, typename _Size>
+    inline _ForwardIterator
+    destroy_n(_ForwardIterator __first, _Size __count)
+    {
+      return std::_Destroy_n(__first, __count);
+    }
+#endif
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
index d0e2b2d33e0c3d00fbd49c039d56d7a41c1495de..c2ba863ed984646d04682dd56158c2d0f0a85b6a 100644 (file)
@@ -831,77 +831,54 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     inline void
     uninitialized_default_construct(_ForwardIterator __first,
                                    _ForwardIterator __last)
-  {
-    __uninitialized_default_novalue(__first, __last);
-  }
+    {
+      __uninitialized_default_novalue(__first, __last);
+    }
 
   template <typename _ForwardIterator, typename _Size>
     inline _ForwardIterator
     uninitialized_default_construct_n(_ForwardIterator __first, _Size __count)
-  {
-    return __uninitialized_default_novalue_n(__first, __count);
-  }
+    {
+      return __uninitialized_default_novalue_n(__first, __count);
+    }
 
   template <typename _ForwardIterator>
     inline void
     uninitialized_value_construct(_ForwardIterator __first,
                                  _ForwardIterator __last)
-  {
-    return __uninitialized_default(__first, __last);
-  }
+    {
+      return __uninitialized_default(__first, __last);
+    }
 
   template <typename _ForwardIterator, typename _Size>
     inline _ForwardIterator
     uninitialized_value_construct_n(_ForwardIterator __first, _Size __count)
-  {
-    return __uninitialized_default_n(__first, __count);
-  }
+    {
+      return __uninitialized_default_n(__first, __count);
+    }
 
   template <typename _InputIterator, typename _ForwardIterator>
     inline _ForwardIterator
     uninitialized_move(_InputIterator __first, _InputIterator __last,
                       _ForwardIterator __result)
-  {
-    return std::uninitialized_copy
-      (_GLIBCXX_MAKE_MOVE_ITERATOR(__first),
-       _GLIBCXX_MAKE_MOVE_ITERATOR(__last), __result);
-  }
+    {
+      return std::uninitialized_copy
+       (_GLIBCXX_MAKE_MOVE_ITERATOR(__first),
+        _GLIBCXX_MAKE_MOVE_ITERATOR(__last), __result);
+    }
 
   template <typename _InputIterator, typename _Size, typename _ForwardIterator>
     inline pair<_InputIterator, _ForwardIterator>
     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};
-  }
-
-  template <typename _Tp>
-    inline void
-    destroy_at(_Tp* __location)
-  {
-    std::_Destroy(__location);
-  }
-
-  template <typename _ForwardIterator>
-    inline void
-    destroy(_ForwardIterator __first, _ForwardIterator __last)
-  {
-    std::_Destroy(__first, __last);
-  }
-
-  template <typename _ForwardIterator, typename _Size>
-    inline _ForwardIterator
-    destroy_n(_ForwardIterator __first, _Size __count)
-  {
-    return std::_Destroy_n(__first, __count);
-  }
-
+    {
+      auto __res = std::__uninitialized_copy_n_pair
+       (_GLIBCXX_MAKE_MOVE_ITERATOR(__first),
+        __count, __result);
+      return {__res.first.base(), __res.second};
+    }
 #endif
 
-
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace
 
diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/memory_management_tools/destroy_neg.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/memory_management_tools/destroy_neg.cc
new file mode 100644 (file)
index 0000000..663b2c0
--- /dev/null
@@ -0,0 +1,50 @@
+// 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-options "-std=gnu++17" }
+// { dg-do compile { target c++1z } }
+
+#include <memory>
+
+// This has a trivial destructor, but should not be destructible!
+struct DeletedDtor {
+  ~DeletedDtor() = delete;
+};
+
+void
+test01()
+{
+  alignas(DeletedDtor) unsigned char buf[sizeof(DeletedDtor)];
+  auto p = ::new (buf) DeletedDtor();
+  std::destroy(p, p + 1);      // { dg-error "here" }
+  std::destroy_n(p, 1);                // { dg-error "here" }
+}
+
+class PrivateDtor {
+  ~PrivateDtor() { }
+};
+
+void
+test02()
+{
+  alignas(PrivateDtor) unsigned char buf[sizeof(PrivateDtor)];
+  auto p = ::new (buf) PrivateDtor();
+  std::destroy(p, p + 1);      // { dg-error "here" }
+  std::destroy_n(p, 1);                // { dg-error "here" }
+}
+
+// { dg-error "value type is destructible" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_neg.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/destructible_neg.cc
new file mode 100644 (file)
index 0000000..4898595
--- /dev/null
@@ -0,0 +1,44 @@
+// 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 compile { target c++11 } }
+
+#include <vector>
+
+// PR libstdc++/80553
+
+struct DeletedDtor {
+  ~DeletedDtor() = delete;
+};
+
+class PrivateDtor {
+  ~PrivateDtor() { }
+};
+
+void
+test01()
+{
+  std::vector<DeletedDtor> v; // { dg-error "here" }
+}
+
+void
+test02()
+{
+  std::vector<PrivateDtor> v; // { dg-error "here" }
+}
+
+// { dg-error "value type is destructible" "" { target *-*-* } 0 }