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

llvm-svn: 275105
Cr-Mirrored-From: sso://chromium.googlesource.com/_direct/external/github.com/llvm/llvm-project
Cr-Mirrored-Commit: dc3eb83d08d63d41824d87e64c10021faee44c6e
diff --git a/include/deque b/include/deque
index c6fbd51..5765042 100644
--- a/include/deque
+++ b/include/deque
@@ -2026,7 +2026,7 @@
         }
         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 @@
             ++__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 @@
         }
         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;
diff --git a/include/memory b/include/memory
index 50a1f00..7a3281e 100644
--- a/include/memory
+++ b/include/memory
@@ -5674,6 +5674,26 @@
 #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
diff --git a/include/vector b/include/vector
index 81c514e..021bbfb 100644
--- a/include/vector
+++ b/include/vector
@@ -1812,9 +1812,9 @@
         }
         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();
     }
diff --git a/test/std/containers/sequences/deque/deque.modifiers/emplace_back.pass.cpp b/test/std/containers/sequences/deque/deque.modifiers/emplace_back.pass.cpp
index 4859a37..784b3a3 100644
--- a/test/std/containers/sequences/deque/deque.modifiers/emplace_back.pass.cpp
+++ b/test/std/containers/sequences/deque/deque.modifiers/emplace_back.pass.cpp
@@ -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 @@
         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
 }
diff --git a/test/std/containers/sequences/vector/vector.modifiers/emplace_back.pass.cpp b/test/std/containers/sequences/vector/vector.modifiers/emplace_back.pass.cpp
index a58f8f0..61ccade 100644
--- a/test/std/containers/sequences/vector/vector.modifiers/emplace_back.pass.cpp
+++ b/test/std/containers/sequences/vector/vector.modifiers/emplace_back.pass.cpp
@@ -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 @@
         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
 }
diff --git a/test/support/test_allocator.h b/test/support/test_allocator.h
index 5514771..466c7fa 100644
--- a/test/support/test_allocator.h
+++ b/test/support/test_allocator.h
@@ -228,4 +228,82 @@
 
 };
 
+#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