aboutsummaryrefslogtreecommitdiff
path: root/libcxx
diff options
context:
space:
mode:
authorMarshall Clow <mclow.lists@gmail.com>2016-07-11 21:38:08 +0000
committerMarshall Clow <mclow.lists@gmail.com>2016-07-11 21:38:08 +0000
commitdc3eb83d08d63d41824d87e64c10021faee44c6e (patch)
tree817e696bbdaaadc91e760d0e08b2fd7f8f554ae2 /libcxx
parent83a25792c5c2fc658736af63b7fc51172642be01 (diff)
downloadllvm-dc3eb83d08d63d41824d87e64c10021faee44c6e.zip
llvm-dc3eb83d08d63d41824d87e64c10021faee44c6e.tar.gz
llvm-dc3eb83d08d63d41824d87e64c10021faee44c6e.tar.bz2
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
Diffstat (limited to 'libcxx')
-rw-r--r--libcxx/include/deque8
-rw-r--r--libcxx/include/memory20
-rw-r--r--libcxx/include/vector4
-rw-r--r--libcxx/test/std/containers/sequences/deque/deque.modifiers/emplace_back.pass.cpp12
-rw-r--r--libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace_back.pass.cpp9
-rw-r--r--libcxx/test/support/test_allocator.h78
6 files changed, 125 insertions, 6 deletions
diff --git a/libcxx/include/deque b/libcxx/include/deque
index c6fbd51..5765042 100644
--- a/libcxx/include/deque
+++ b/libcxx/include/deque
@@ -2026,7 +2026,7 @@ deque<_Tp, _Allocator>::emplace(const_iterator __p, _Args&&... __args)
}
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_iterator __p, _Args&&... __args)
++__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_iterator __p, _Args&&... __args)
}
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/libcxx/include/memory b/libcxx/include/memory
index 50a1f00..7a3281e 100644
--- a/libcxx/include/memory
+++ b/libcxx/include/memory
@@ -5674,6 +5674,26 @@ struct __noexcept_move_assign_container : public integral_constant<bool,
#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/libcxx/include/vector b/libcxx/include/vector
index 81c514e..021bbfb 100644
--- a/libcxx/include/vector
+++ b/libcxx/include/vector
@@ -1812,9 +1812,9 @@ vector<_Tp, _Allocator>::emplace(const_iterator __position, _Args&&... __args)
}
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/libcxx/test/std/containers/sequences/deque/deque.modifiers/emplace_back.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/emplace_back.pass.cpp
index 4859a37..784b3a3 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/emplace_back.pass.cpp
+++ b/libcxx/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 @@ 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
}
diff --git a/libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace_back.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace_back.pass.cpp
index a58f8f0..61ccade 100644
--- a/libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace_back.pass.cpp
+++ b/libcxx/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 @@ 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
}
diff --git a/libcxx/test/support/test_allocator.h b/libcxx/test/support/test_allocator.h
index 5514771..466c7fa 100644
--- a/libcxx/test/support/test_allocator.h
+++ b/libcxx/test/support/test_allocator.h
@@ -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