Fix an exception-safety bug in <deque>. Reference: PR#22650. Not closing the bug...
authorMarshall Clow <mclow.lists@gmail.com>
Mon, 9 Mar 2015 17:08:51 +0000 (17:08 +0000)
committerMarshall Clow <mclow.lists@gmail.com>
Mon, 9 Mar 2015 17:08:51 +0000 (17:08 +0000)
llvm-svn: 231672

libcxx/include/deque
libcxx/test/std/containers/sequences/deque/deque.modifiers/push_back_exception_safety.pass.cpp
libcxx/test/std/containers/sequences/deque/deque.modifiers/push_front_exception_safety.pass.cpp

index 6b419c5..8d0d2a8 100644 (file)
@@ -2288,19 +2288,14 @@ deque<_Tp, _Allocator>::__add_front_capacity()
         __split_buffer<pointer, typename __base::__pointer_allocator&>
             __buf(max<size_type>(2 * __base::__map_.capacity(), 1),
                   0, __base::__map_.__alloc());
-#ifndef _LIBCPP_NO_EXCEPTIONS
-        try
-        {
-#endif  // _LIBCPP_NO_EXCEPTIONS
-            __buf.push_back(__alloc_traits::allocate(__a, __base::__block_size));
-#ifndef _LIBCPP_NO_EXCEPTIONS
-        }
-        catch (...)
-        {
-            __alloc_traits::deallocate(__a, __buf.front(), __base::__block_size);
-            throw;
-        }
-#endif  // _LIBCPP_NO_EXCEPTIONS
+
+               typedef __allocator_destructor<_Allocator> _Dp;
+               unique_ptr<pointer, _Dp> __hold(
+                       __alloc_traits::allocate(__a, __base::__block_size),
+                               _Dp(__a, __base::__block_size));
+               __buf.push_back(__hold.get());
+               __hold.release();
+       
         for (typename __base::__map_pointer __i = __base::__map_.begin();
                 __i != __base::__map_.end(); ++__i)
             __buf.push_back(*__i);
@@ -2436,19 +2431,14 @@ deque<_Tp, _Allocator>::__add_back_capacity()
             __buf(max<size_type>(2* __base::__map_.capacity(), 1),
                   __base::__map_.size(),
                   __base::__map_.__alloc());
-#ifndef _LIBCPP_NO_EXCEPTIONS
-        try
-        {
-#endif  // _LIBCPP_NO_EXCEPTIONS
-            __buf.push_back(__alloc_traits::allocate(__a, __base::__block_size));
-#ifndef _LIBCPP_NO_EXCEPTIONS
-        }
-        catch (...)
-        {
-            __alloc_traits::deallocate(__a, __buf.back(), __base::__block_size);
-            throw;
-        }
-#endif  // _LIBCPP_NO_EXCEPTIONS
+
+               typedef __allocator_destructor<_Allocator> _Dp;
+               unique_ptr<pointer, _Dp> __hold(
+                       __alloc_traits::allocate(__a, __base::__block_size),
+                               _Dp(__a, __base::__block_size));
+               __buf.push_back(__hold.get());
+               __hold.release();
+
         for (typename __base::__map_pointer __i = __base::__map_.end();
                 __i != __base::__map_.begin();)
             __buf.push_front(*--__i);
index 3e62879..8ad6b53 100644 (file)
 // void push_back(const value_type& x);
 
 #include <deque>
+#include "test_allocator.h"
 #include <cassert>
 
 // Flag that makes the copy constructor for CMyClass throw an exception
 static bool gCopyConstructorShouldThow = false;
 
-
 class CMyClass {
     public: CMyClass(int tag);
     public: CMyClass(const CMyClass& iOther);
@@ -25,6 +25,7 @@ class CMyClass {
 
     bool equal(const CMyClass &rhs) const
         { return fTag == rhs.fTag && fMagicValue == rhs.fMagicValue; }
+        
     private:
         int fMagicValue;
         int fTag;
@@ -66,6 +67,7 @@ bool operator==(const CMyClass &lhs, const CMyClass &rhs) { return lhs.equal(rhs
 int main()
 {
     CMyClass instance(42);
+    {
     std::deque<CMyClass> vec;
 
     vec.push_back(instance);
@@ -74,8 +76,26 @@ int main()
     gCopyConstructorShouldThow = true;
     try {
         vec.push_back(instance);
+        assert(false);
+    }
+    catch (...) {
+           gCopyConstructorShouldThow = false;
+        assert(vec==vec2);
+    }
+       }
+       
+       {
+       typedef std::deque<CMyClass, test_allocator<CMyClass> > C;
+    C vec;
+    C vec2(vec);
+
+       C::allocator_type::throw_after = 1;
+    try {
+        vec.push_back(instance);
+        assert(false);
     }
     catch (...) {
         assert(vec==vec2);
     }
+    }
 }
index 6ae06db..e01b2a2 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <deque>
 #include <cassert>
+#include "test_allocator.h"
 
 // Flag that makes the copy constructor for CMyClass throw an exception
 static bool gCopyConstructorShouldThow = false;
@@ -66,6 +67,7 @@ bool operator==(const CMyClass &lhs, const CMyClass &rhs) { return lhs.equal(rhs
 int main()
 {
     CMyClass instance(42);
+    {
     std::deque<CMyClass> vec;
 
     vec.push_front(instance);
@@ -74,8 +76,26 @@ int main()
     gCopyConstructorShouldThow = true;
     try {
         vec.push_front(instance);
+        assert(false);
     }
     catch (...) {
+           gCopyConstructorShouldThow = false;
         assert(vec==vec2);
     }
+       }
+       
+       {
+       typedef std::deque<CMyClass, test_allocator<CMyClass> > C;
+    C vec;
+    C vec2(vec);
+
+       C::allocator_type::throw_after = 1;
+    try {
+        vec.push_front(instance);
+        assert(false);
+    }
+    catch (...) {
+        assert(vec==vec2);
+    }
+    }
 }