[libcxx] r275105 - Always use the allocator to construct/destruct elements of a deque/vector. Fixes PR#28412. Thanks to Jonathan Wakely for the report.

Marshall Clow via cfe-commits cfe-commits at lists.llvm.org
Mon Jul 11 14:38:08 PDT 2016


Author: marshall
Date: Mon Jul 11 16:38:08 2016
New Revision: 275105

URL: http://llvm.org/viewvc/llvm-project?rev=275105&view=rev
Log:
Always use the allocator to construct/destruct elements of a deque/vector. Fixes PR#28412. Thanks to Jonathan Wakely for the report.

Modified:
    libcxx/trunk/include/deque
    libcxx/trunk/include/memory
    libcxx/trunk/include/vector
    libcxx/trunk/test/std/containers/sequences/deque/deque.modifiers/emplace_back.pass.cpp
    libcxx/trunk/test/std/containers/sequences/vector/vector.modifiers/emplace_back.pass.cpp
    libcxx/trunk/test/support/test_allocator.h

Modified: libcxx/trunk/include/deque
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/deque?rev=275105&r1=275104&r2=275105&view=diff
==============================================================================
--- libcxx/trunk/include/deque (original)
+++ libcxx/trunk/include/deque Mon Jul 11 16:38:08 2016
@@ -2026,7 +2026,7 @@ deque<_Tp, _Allocator>::emplace(const_it
         }
         else
         {
-            value_type __tmp(_VSTD::forward<_Args>(__args)...);
+            __temp_value<value_type, _Allocator> __tmp(this->__alloc(), _VSTD::forward<_Args>(__args)...);
             iterator __b = __base::begin();
             iterator __bm1 = _VSTD::prev(__b);
             __alloc_traits::construct(__a, _VSTD::addressof(*__bm1), _VSTD::move(*__b));
@@ -2034,7 +2034,7 @@ deque<_Tp, _Allocator>::emplace(const_it
             ++__base::size();
             if (__pos > 1)
                 __b = _VSTD::move(_VSTD::next(__b), __b + __pos, __b);
-            *__b = _VSTD::move(__tmp);
+            *__b = _VSTD::move(__tmp.get());
         }
     }
     else
@@ -2050,14 +2050,14 @@ deque<_Tp, _Allocator>::emplace(const_it
         }
         else
         {
-            value_type __tmp(_VSTD::forward<_Args>(__args)...);
+            __temp_value<value_type, _Allocator> __tmp(this->__alloc(), _VSTD::forward<_Args>(__args)...);
             iterator __e = __base::end();
             iterator __em1 = _VSTD::prev(__e);
             __alloc_traits::construct(__a, _VSTD::addressof(*__e), _VSTD::move(*__em1));
             ++__base::size();
             if (__de > 1)
                 __e = _VSTD::move_backward(__e - __de, __em1, __e);
-            *--__e = _VSTD::move(__tmp);
+            *--__e = _VSTD::move(__tmp.get());
         }
     }
     return __base::begin() + __pos;

Modified: libcxx/trunk/include/memory
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/memory?rev=275105&r1=275104&r2=275105&view=diff
==============================================================================
--- libcxx/trunk/include/memory (original)
+++ libcxx/trunk/include/memory Mon Jul 11 16:38:08 2016
@@ -5674,6 +5674,26 @@ struct __noexcept_move_assign_container
 #endif
     > {};
 
+
+#ifndef _LIBCPP_HAS_NO_VARIADICS
+template <class _Tp, class _Alloc>
+struct __temp_value {
+    typedef allocator_traits<_Alloc> _Traits;
+    
+    typename aligned_storage<sizeof(_Tp), alignof(_Tp)>::type __v;
+    _Alloc &__a;
+
+    _Tp *__addr() { return reinterpret_cast<_Tp *>(addressof(__v)); }
+    _Tp &   get() { return *__addr(); }
+        
+    template<class... _Args>
+    __temp_value(_Alloc &__alloc, _Args&& ... __args) : __a(__alloc)
+    { _Traits::construct(__a, __addr(), _VSTD::forward<_Args>(__args)...); }
+    
+    ~__temp_value() { _Traits::destroy(__a, __addr()); }
+    };
+#endif
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif  // _LIBCPP_MEMORY

Modified: libcxx/trunk/include/vector
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/vector?rev=275105&r1=275104&r2=275105&view=diff
==============================================================================
--- libcxx/trunk/include/vector (original)
+++ libcxx/trunk/include/vector Mon Jul 11 16:38:08 2016
@@ -1812,9 +1812,9 @@ vector<_Tp, _Allocator>::emplace(const_i
         }
         else
         {
-            value_type __tmp(_VSTD::forward<_Args>(__args)...);
+            __temp_value<value_type, _Allocator> __tmp(this->__alloc(), _VSTD::forward<_Args>(__args)...);
             __move_range(__p, this->__end_, __p + 1);
-            *__p = _VSTD::move(__tmp);
+            *__p = _VSTD::move(__tmp.get());
         }
         __annotator.__done();
     }

Modified: libcxx/trunk/test/std/containers/sequences/deque/deque.modifiers/emplace_back.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/containers/sequences/deque/deque.modifiers/emplace_back.pass.cpp?rev=275105&r1=275104&r2=275105&view=diff
==============================================================================
--- libcxx/trunk/test/std/containers/sequences/deque/deque.modifiers/emplace_back.pass.cpp (original)
+++ libcxx/trunk/test/std/containers/sequences/deque/deque.modifiers/emplace_back.pass.cpp Mon Jul 11 16:38:08 2016
@@ -16,6 +16,7 @@
 
 #include "../../../Emplaceable.h"
 #include "min_allocator.h"
+#include "test_allocator.h"
 
 #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
 
@@ -82,6 +83,17 @@ int main()
         for (int j = 0; j < N; ++j)
             testN<std::deque<Emplaceable, min_allocator<Emplaceable>> >(rng[i], rng[j]);
     }
+    {
+        std::deque<Tag_X, TaggingAllocator<Tag_X>> c;
+        c.emplace_back();
+        assert(c.size() == 1);
+        c.emplace_back(1, 2, 3);
+        assert(c.size() == 2);
+        c.emplace_front();
+        assert(c.size() == 3);
+        c.emplace_front(1, 2, 3);
+        assert(c.size() == 4);
+    }
 #endif
 #endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
 }

Modified: libcxx/trunk/test/std/containers/sequences/vector/vector.modifiers/emplace_back.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/containers/sequences/vector/vector.modifiers/emplace_back.pass.cpp?rev=275105&r1=275104&r2=275105&view=diff
==============================================================================
--- libcxx/trunk/test/std/containers/sequences/vector/vector.modifiers/emplace_back.pass.cpp (original)
+++ libcxx/trunk/test/std/containers/sequences/vector/vector.modifiers/emplace_back.pass.cpp Mon Jul 11 16:38:08 2016
@@ -15,6 +15,7 @@
 #include <cassert>
 #include "../../../stack_allocator.h"
 #include "min_allocator.h"
+#include "test_allocator.h"
 #include "asan_testing.h"
 
 #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
@@ -102,6 +103,14 @@ int main()
         assert(c.back().getd() == 4.5);
         assert(is_contiguous_container_asan_correct(c));
     }
+    {
+        std::vector<Tag_X, TaggingAllocator<Tag_X>> c;
+        c.emplace_back();
+        assert(c.size() == 1);
+        c.emplace_back(1, 2, 3);
+        assert(c.size() == 2);
+        assert(is_contiguous_container_asan_correct(c));
+    }
 #endif
 #endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
 }

Modified: libcxx/trunk/test/support/test_allocator.h
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/support/test_allocator.h?rev=275105&r1=275104&r2=275105&view=diff
==============================================================================
--- libcxx/trunk/test/support/test_allocator.h (original)
+++ libcxx/trunk/test/support/test_allocator.h Mon Jul 11 16:38:08 2016
@@ -228,4 +228,82 @@ public:
 
 };
 
+#if TEST_STD_VER >= 11
+
+struct Ctor_Tag {};
+
+template <typename T> class TaggingAllocator;
+
+struct Tag_X {
+  // All constructors must be passed the Tag type.
+
+  // DefaultInsertable into vector<X, TaggingAllocator<X>>,
+  Tag_X(Ctor_Tag) {}
+  // CopyInsertable into vector<X, TaggingAllocator<X>>,
+  Tag_X(Ctor_Tag, const Tag_X&) {}
+  // MoveInsertable into vector<X, TaggingAllocator<X>>, and
+  Tag_X(Ctor_Tag, Tag_X&&) {}
+
+  // EmplaceConstructible into vector<X, TaggingAllocator<X>> from args.
+  template<typename... Args>
+  Tag_X(Ctor_Tag, Args&&...) { }
+
+  // not DefaultConstructible, CopyConstructible or MoveConstructible.
+  Tag_X() = delete;
+  Tag_X(const Tag_X&) = delete;
+  Tag_X(Tag_X&&) = delete;
+
+  // CopyAssignable.
+  Tag_X& operator=(const Tag_X&) { return *this; }
+
+  // MoveAssignable.
+  Tag_X& operator=(Tag_X&&) { return *this; }
+
+private:
+  // Not Destructible.
+  ~Tag_X() { }
+
+  // Erasable from vector<X, TaggingAllocator<X>>.
+  friend class TaggingAllocator<Tag_X>;
+};
+
+
+template<typename T>
+class TaggingAllocator {
+public:
+    using value_type = T;
+    TaggingAllocator() = default;
+
+    template<typename U>
+      TaggingAllocator(const TaggingAllocator<U>&) { }
+
+    T* allocate(std::size_t n) { return std::allocator<T>{}.allocate(n); }
+
+    void deallocate(T* p, std::size_t n) { std::allocator<T>{}.deallocate(p, n); }
+
+    template<typename... Args>
+    void construct(Tag_X* p, Args&&... args)
+    { ::new((void*)p) Tag_X(Ctor_Tag{}, std::forward<Args>(args)...); }
+
+    template<typename U, typename... Args>
+    void construct(U* p, Args&&... args)
+    { ::new((void*)p) U(std::forward<Args>(args)...); }
+
+    template<typename U, typename... Args>
+    void destroy(U* p)
+    { p->~U(); }
+};
+
+template<typename T, typename U>
+bool
+operator==(const TaggingAllocator<T>&, const TaggingAllocator<U>&)
+{ return true; }
+
+template<typename T, typename U>
+bool
+operator!=(const TaggingAllocator<T>&, const TaggingAllocator<U>&)
+{ return false; }
+#endif
+
+
 #endif  // TEST_ALLOCATOR_H




More information about the cfe-commits mailing list