Always use the allocator to construct/destruct elements of a deque/vector. Fixes PR#28412. Thanks to Jonathan Wakely for the report.
git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@275105 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -2026,7 +2026,7 @@ deque<_Tp, _Allocator>::emplace(const_iterator __p, _Args&&... __args)
|
|||||||
}
|
}
|
||||||
else
|
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 __b = __base::begin();
|
||||||
iterator __bm1 = _VSTD::prev(__b);
|
iterator __bm1 = _VSTD::prev(__b);
|
||||||
__alloc_traits::construct(__a, _VSTD::addressof(*__bm1), _VSTD::move(*__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();
|
++__base::size();
|
||||||
if (__pos > 1)
|
if (__pos > 1)
|
||||||
__b = _VSTD::move(_VSTD::next(__b), __b + __pos, __b);
|
__b = _VSTD::move(_VSTD::next(__b), __b + __pos, __b);
|
||||||
*__b = _VSTD::move(__tmp);
|
*__b = _VSTD::move(__tmp.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -2050,14 +2050,14 @@ deque<_Tp, _Allocator>::emplace(const_iterator __p, _Args&&... __args)
|
|||||||
}
|
}
|
||||||
else
|
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 __e = __base::end();
|
||||||
iterator __em1 = _VSTD::prev(__e);
|
iterator __em1 = _VSTD::prev(__e);
|
||||||
__alloc_traits::construct(__a, _VSTD::addressof(*__e), _VSTD::move(*__em1));
|
__alloc_traits::construct(__a, _VSTD::addressof(*__e), _VSTD::move(*__em1));
|
||||||
++__base::size();
|
++__base::size();
|
||||||
if (__de > 1)
|
if (__de > 1)
|
||||||
__e = _VSTD::move_backward(__e - __de, __em1, __e);
|
__e = _VSTD::move_backward(__e - __de, __em1, __e);
|
||||||
*--__e = _VSTD::move(__tmp);
|
*--__e = _VSTD::move(__tmp.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return __base::begin() + __pos;
|
return __base::begin() + __pos;
|
||||||
|
|||||||
@@ -5674,6 +5674,26 @@ struct __noexcept_move_assign_container : public integral_constant<bool,
|
|||||||
#endif
|
#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
|
_LIBCPP_END_NAMESPACE_STD
|
||||||
|
|
||||||
#endif // _LIBCPP_MEMORY
|
#endif // _LIBCPP_MEMORY
|
||||||
|
|||||||
@@ -1812,9 +1812,9 @@ vector<_Tp, _Allocator>::emplace(const_iterator __position, _Args&&... __args)
|
|||||||
}
|
}
|
||||||
else
|
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);
|
__move_range(__p, this->__end_, __p + 1);
|
||||||
*__p = _VSTD::move(__tmp);
|
*__p = _VSTD::move(__tmp.get());
|
||||||
}
|
}
|
||||||
__annotator.__done();
|
__annotator.__done();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "../../../Emplaceable.h"
|
#include "../../../Emplaceable.h"
|
||||||
#include "min_allocator.h"
|
#include "min_allocator.h"
|
||||||
|
#include "test_allocator.h"
|
||||||
|
|
||||||
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
|
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
|
||||||
|
|
||||||
@@ -82,6 +83,17 @@ int main()
|
|||||||
for (int j = 0; j < N; ++j)
|
for (int j = 0; j < N; ++j)
|
||||||
testN<std::deque<Emplaceable, min_allocator<Emplaceable>> >(rng[i], rng[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
|
||||||
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
|
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include "../../../stack_allocator.h"
|
#include "../../../stack_allocator.h"
|
||||||
#include "min_allocator.h"
|
#include "min_allocator.h"
|
||||||
|
#include "test_allocator.h"
|
||||||
#include "asan_testing.h"
|
#include "asan_testing.h"
|
||||||
|
|
||||||
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
|
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
|
||||||
@@ -102,6 +103,14 @@ int main()
|
|||||||
assert(c.back().getd() == 4.5);
|
assert(c.back().getd() == 4.5);
|
||||||
assert(is_contiguous_container_asan_correct(c));
|
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
|
||||||
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
|
#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
#endif // TEST_ALLOCATOR_H
|
||||||
|
|||||||
Reference in New Issue
Block a user