diff --git a/libcxx/benchmarks/vector_operations.bench.cpp b/libcxx/benchmarks/vector_operations.bench.cpp --- a/libcxx/benchmarks/vector_operations.bench.cpp +++ b/libcxx/benchmarks/vector_operations.bench.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -36,5 +37,25 @@ std::vector{}, getRandomStringInputs)->Arg(TestNumInputs); +template +void BM_VectorPushBack(benchmark::State& state) { + T x = {}; + std::vector xs = {}; + for (auto _ : state) { + benchmark::DoNotOptimize(x); + xs.push_back(std::move(x)); + benchmark::DoNotOptimize(xs); + } +} + +// Nontrivial, but trivial for calls --> trivially relocatable. +struct [[clang::trivial_abi]] Nontrivial { + int* x = nullptr; + ~Nontrivial() { benchmark::DoNotOptimize(*this); } +}; + +BENCHMARK_TEMPLATE(BM_VectorPushBack, int*); +BENCHMARK_TEMPLATE(BM_VectorPushBack, std::unique_ptr); +BENCHMARK_TEMPLATE(BM_VectorPushBack, Nontrivial); BENCHMARK_MAIN(); diff --git a/libcxx/include/__memory/allocator_traits.h b/libcxx/include/__memory/allocator_traits.h --- a/libcxx/include/__memory/allocator_traits.h +++ b/libcxx/include/__memory/allocator_traits.h @@ -396,6 +396,17 @@ : __is_cpp17_move_insertable<_Alloc> { }; +// __has_default_allocator_construct +template +struct __has_default_allocator_construct + : integral_constant::value || !__has_construct<_Alloc, _Tp*, _Args...>::value) > {}; + +// __has_default_allocator_destroy +template +struct __has_default_allocator_destroy + : integral_constant::value || !__has_destroy<_Alloc, _Tp*>::value) > {}; + #undef _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/memory b/libcxx/include/memory --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -847,9 +847,13 @@ _LIBCPP_BEGIN_NAMESPACE_STD +// __construct_forward_with_exception_guarantees(__a, __begin1, __end1, __begin2, __use_memcpy) +// +// If __use_memcpy is true_type, this constructs using memcpy. Otherwise, it uses the move constructor. + template _LIBCPP_INLINE_VISIBILITY -void __construct_forward_with_exception_guarantees(_Alloc& __a, _Ptr __begin1, _Ptr __end1, _Ptr& __begin2) { +void __construct_forward_with_exception_guarantees(_Alloc& __a, _Ptr __begin1, _Ptr __end1, _Ptr& __begin2, false_type) { static_assert(__is_cpp17_move_insertable<_Alloc>::value, "The specified type does not meet the requirements of Cpp17MoveInsertable"); typedef allocator_traits<_Alloc> _Traits; @@ -864,15 +868,14 @@ } } -template ::value || !__has_construct<_Alloc, _Tp*, _Tp>::value) && - is_trivially_move_constructible<_Tp>::value ->::type> +template _LIBCPP_INLINE_VISIBILITY -void __construct_forward_with_exception_guarantees(_Alloc&, _Tp* __begin1, _Tp* __end1, _Tp*& __begin2) { +void __construct_forward_with_exception_guarantees(_Alloc&, _Ptr __begin1, _Ptr __end1, _Ptr& __begin2, true_type) { + typedef typename iterator_traits<_Ptr>::value_type _Tp; + typedef typename remove_const<_Tp>::type _Vp; ptrdiff_t _Np = __end1 - __begin1; if (_Np > 0) { - _VSTD::memcpy(__begin2, __begin1, _Np * sizeof(_Tp)); + _VSTD::memcpy(const_cast<_Vp*>(_VSTD::__to_address(__begin2)), _VSTD::__to_address(__begin1), _Np * sizeof(_Tp)); __begin2 += _Np; } } @@ -893,7 +896,7 @@ typename enable_if< is_trivially_copy_constructible<_Dest>::value && is_same<_RawSource, _RawDest>::value && - (__is_default_allocator<_Alloc>::value || !__has_construct<_Alloc, _Dest*, _Source&>::value) + __has_default_allocator_construct<_Alloc, _Dest, _Source>::value >::type> _LIBCPP_INLINE_VISIBILITY void __construct_range_forward(_Alloc&, _Source* __begin1, _Source* __end1, _Dest*& __begin2) { @@ -906,7 +909,7 @@ template _LIBCPP_INLINE_VISIBILITY -void __construct_backward_with_exception_guarantees(_Alloc& __a, _Ptr __begin1, _Ptr __end1, _Ptr& __end2) { +void __construct_backward_with_exception_guarantees(_Alloc& __a, _Ptr __begin1, _Ptr __end1, _Ptr& __end2, false_type) { static_assert(__is_cpp17_move_insertable<_Alloc>::value, "The specified type does not meet the requirements of Cpp17MoveInsertable"); typedef allocator_traits<_Alloc> _Traits; @@ -922,16 +925,15 @@ } } -template ::value || !__has_construct<_Alloc, _Tp*, _Tp>::value) && - is_trivially_move_constructible<_Tp>::value ->::type> +template _LIBCPP_INLINE_VISIBILITY -void __construct_backward_with_exception_guarantees(_Alloc&, _Tp* __begin1, _Tp* __end1, _Tp*& __end2) { +void __construct_backward_with_exception_guarantees(_Alloc&, _Ptr __begin1, _Ptr __end1, _Ptr& __end2, true_type) { + typedef typename iterator_traits<_Ptr>::value_type _Tp; + typedef typename remove_const<_Tp>::type _Vp; ptrdiff_t _Np = __end1 - __begin1; __end2 -= _Np; if (_Np > 0) - _VSTD::memcpy(static_cast(__end2), static_cast(__begin1), _Np * sizeof(_Tp)); + _VSTD::memcpy(const_cast<_Vp*>(_VSTD::__to_address(__end2)), _VSTD::__to_address(__begin1), _Np * sizeof(_Tp)); } struct __destruct_n @@ -1092,7 +1094,6 @@ } }; - _LIBCPP_END_NAMESPACE_STD #if defined(_LIBCPP_HAS_PARALLEL_ALGORITHMS) && _LIBCPP_STD_VER >= 17 diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits --- a/libcxx/include/type_traits +++ b/libcxx/include/type_traits @@ -3109,6 +3109,27 @@ // is_nothrow_constructible + + +// __libcpp_is_trivially_relocatable + +template +struct _LIBCPP_TEMPLATE_VIS __libcpp_is_trivially_relocatable + : public integral_constant::type>::value && + is_trivially_destructible::type>::value +#endif + > {}; + +#if _LIBCPP_STD_VER > 14 +template +inline constexpr bool __libcpp_is_trivially_relocatable_v + = __libcpp_is_trivially_relocatable<_Tp>::value; +#endif + #if __has_keyword(__is_nothrow_constructible) template diff --git a/libcxx/include/vector b/libcxx/include/vector --- a/libcxx/include/vector +++ b/libcxx/include/vector @@ -302,6 +302,23 @@ _LIBCPP_BEGIN_NAMESPACE_STD + +template +struct __vector_move_via_memcpy : integral_constant::value && + __has_default_allocator_construct<_Allocator, _Tp, _Tp&&>::value && + !is_volatile<_Tp>::value +> {}; + +template +struct __vector_relocate_via_memcpy : integral_constant::value && + __has_default_allocator_construct<_Allocator, _Tp, _Tp&&>::value && + __has_default_allocator_destroy<_Allocator, _Tp>::value && + !is_volatile<_Tp>::value +> {}; + + template */> class _LIBCPP_TEMPLATE_VIS vector { @@ -675,6 +692,8 @@ void __swap_out_circular_buffer(__split_buffer& __v); pointer __swap_out_circular_buffer(__split_buffer& __v, pointer __p); void __move_range(pointer __from_s, pointer __from_e, pointer __to); + template + void __relocate_upward_and_insert(pointer __from_s, pointer __from_e, _Up&& __elt); void __move_assign(vector& __c, true_type) _NOEXCEPT_(is_nothrow_move_assignable::value); void __move_assign(vector& __c, false_type) @@ -878,13 +897,21 @@ void vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer& __v) { + typedef integral_constant::value || + __vector_relocate_via_memcpy<_Tp, _Allocator>::value + > __move_via_memcpy; + typedef integral_constant::value + > __destroy_via_noop; __annotate_delete(); - _VSTD::__construct_backward_with_exception_guarantees(this->__alloc(), this->__begin_, this->__end_, __v.__begin_); + _VSTD::__construct_backward_with_exception_guarantees(this->__alloc(), this->__begin_, this->__end_, __v.__begin_, __move_via_memcpy()); _VSTD::swap(this->__begin_, __v.__begin_); _VSTD::swap(this->__end_, __v.__end_); _VSTD::swap(this->__end_cap(), __v.__end_cap()); __v.__first_ = __v.__begin_; + __v.__destruct_at_end(__v.__begin_, __destroy_via_noop()); __annotate_new(size()); __invalidate_all_iterators(); } @@ -893,14 +920,23 @@ typename vector<_Tp, _Allocator>::pointer vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer& __v, pointer __p) { + typedef integral_constant::value || + __vector_relocate_via_memcpy<_Tp, _Allocator>::value + > __move_via_memcpy; + typedef integral_constant::value + > __destroy_via_noop; + __annotate_delete(); pointer __r = __v.__begin_; - _VSTD::__construct_backward_with_exception_guarantees(this->__alloc(), this->__begin_, __p, __v.__begin_); - _VSTD::__construct_forward_with_exception_guarantees(this->__alloc(), __p, this->__end_, __v.__end_); + _VSTD::__construct_backward_with_exception_guarantees(this->__alloc(), this->__begin_, __p, __v.__begin_, __move_via_memcpy()); + _VSTD::__construct_forward_with_exception_guarantees(this->__alloc(), __p, this->__end_, __v.__end_, __move_via_memcpy()); _VSTD::swap(this->__begin_, __v.__begin_); _VSTD::swap(this->__end_, __v.__end_); _VSTD::swap(this->__end_cap(), __v.__end_cap()); __v.__first_ = __v.__begin_; + __v.__destruct_at_end(__v.__begin_, __destroy_via_noop()); __annotate_new(size()); __invalidate_all_iterators(); return __r; @@ -1605,7 +1641,16 @@ "vector::erase(iterator) called with a non-dereferenceable iterator"); difference_type __ps = __position - cbegin(); pointer __p = this->__begin_ + __ps; - this->__destruct_at_end(_VSTD::move(__p + 1, this->__end_, __p)); + if (__vector_relocate_via_memcpy<_Tp, _Allocator>::value) { + _Tp *__rawp = _VSTD::__to_address(__p); + __alloc_traits::destroy(this->__alloc(), __rawp); + --this->__end_; + if (__p != this->__end_) { + _VSTD::memmove(__rawp, __rawp + 1, (this->__end_ - __p) * sizeof(*__rawp)); + } + } else { + this->__destruct_at_end(_VSTD::move(__p + 1, this->__end_, __p)); + } this->__invalidate_iterators_past(__p-1); iterator __r = __make_iter(__p); return __r; @@ -1630,6 +1675,36 @@ return __r; } +#ifdef _LIBCPP_CXX03_LANG +template +struct __is_nothrow_constructible_a : integral_constant {}; +#else +template +struct __is_nothrow_constructible_a : integral_constant::construct(declval<_Allocator&>(), (_Tp*)nullptr, declval<_Up>())) +> {}; +#endif + +template +struct __is_nothrow_constructible_a, _Tp, _Up> : is_nothrow_constructible<_Tp, _Up> {}; + +template +template +void +vector<_Tp, _Allocator>::__relocate_upward_and_insert(pointer __from_s, pointer __from_e, _Up&& __elt) +{ + if (__vector_relocate_via_memcpy<_Tp, _Allocator>::value && __is_nothrow_constructible_a<_Allocator, _Tp, _Up&&>::value) { + _VSTD::memmove(_VSTD::__to_address(__from_s + 1), _VSTD::__to_address(__from_s), (__from_e - __from_s) * sizeof(_Tp)); + ++this->__end_; + __alloc_traits::construct(this->__alloc(), + _VSTD::__to_address(__from_s), + static_cast<_Up&&>(__elt)); + } else { + __move_range(__from_s, __from_e, __from_s + 1); + *__from_s = static_cast<_Up&&>(__elt); + } +} + template void vector<_Tp, _Allocator>::__move_range(pointer __from_s, pointer __from_e, pointer __to) @@ -1664,11 +1739,10 @@ } else { - __move_range(__p, this->__end_, __p + 1); const_pointer __xr = pointer_traits::pointer_to(__x); if (__p <= __xr && __xr < this->__end_) ++__xr; - *__p = *__xr; + __relocate_upward_and_insert(__p, this->__end_, *__xr); } } else @@ -1698,8 +1772,7 @@ } else { - __move_range(__p, this->__end_, __p + 1); - *__p = _VSTD::move(__x); + __relocate_upward_and_insert(__p, this->__end_, _VSTD::move(__x)); } } else @@ -1729,8 +1802,7 @@ else { __temp_value __tmp(this->__alloc(), _VSTD::forward<_Args>(__args)...); - __move_range(__p, this->__end_, __p + 1); - *__p = _VSTD::move(__tmp.get()); + __relocate_upward_and_insert(__p, this->__end_, _VSTD::move(__tmp.get())); } } else diff --git a/libcxx/test/libcxx/containers/sequences/vector/insert_trivially_relocatable.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector/insert_trivially_relocatable.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/containers/sequences/vector/insert_trivially_relocatable.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// void insert(const_iterator it, const value_type& x); + +// UNSUPPORTED: c++98, c++03 + +#include +#include +#include + +static int assignments = 0; + +struct NotTriviallyRelocatable { + ~NotTriviallyRelocatable() {} +}; + +struct TriviallyRelocatable {}; + +// This class is trivial for calls, and therefore __trivially_relocatable, iff TR. +// on compilers +template +struct [[clang::trivial_abi]] MyClass : std::conditional::type { + int value; + explicit MyClass(int i) : value(i) {} + MyClass(const MyClass& rhs) { value = rhs.value; } + MyClass(MyClass&& rhs) noexcept { value = rhs.value; } + MyClass& operator=(const MyClass& rhs) { + ++assignments; + value = rhs.value; + return *this; + } + MyClass& operator=(MyClass&& rhs) { + ++assignments; + value = rhs.value; + return *this; + } + ~MyClass() {} +}; + +static_assert(!std::__libcpp_is_trivially_relocatable>::value, ""); +static_assert(std::__libcpp_is_trivially_relocatable>::value == __has_keyword(__is_trivially_relocatable), + ""); + +template +void test() { + using T = MyClass; + constexpr bool trivially_relocatable = std::__libcpp_is_trivially_relocatable::value; + std::vector vec; + vec.reserve(5); + vec.push_back(T(1)); + vec.push_back(T(2)); + vec.push_back(T(3)); + + assignments = 0; + vec.insert(vec.begin() + 2, T(4)); + if (trivially_relocatable) { + assert(assignments == 0); // relocate upward without assigning + } else { + assert(assignments >= 1); + } + + assignments = 0; + vec.insert(vec.begin() + 2, T(5)); + if (trivially_relocatable) { + assert(assignments == 0); // relocate upward without assigning + } else { + assert(assignments >= 1); + } +} + +int main(int, char**) { + test(); + test(); + return 0; +} diff --git a/libcxx/test/libcxx/type_traits/is_trivially_relocatable.pass.cpp b/libcxx/test/libcxx/type_traits/is_trivially_relocatable.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/type_traits/is_trivially_relocatable.pass.cpp @@ -0,0 +1,230 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// UNSUPPORTED: c++98, c++03, c++11, c++14 +// +// +// +// Test that many standard types are trivially relocatable. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct T { + T(); + T(const T&); + ~T(); +}; +struct R {}; +struct SM { + void lock_shared(); + void unlock_shared(); + ~SM(); +}; + +struct K { + T t; + bool operator==(const K&) const; + bool operator<(const K&) const; +}; +template <> +struct std::hash { + size_t operator()(const K&) const; +}; + +static const bool NotDebug = +#if _LIBCPP_DEBUG_LEVEL >= 2 + false; +#else + true; +#endif + +// Define this name for convenience. +#define is_trivially_relocatable __libcpp_is_trivially_relocatable + +static_assert(std::is_trivially_relocatable::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(std::is_trivially_relocatable::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +//static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(std::is_trivially_relocatable::value, ""); +static_assert(std::is_trivially_relocatable::value, ""); +static_assert(std::is_trivially_relocatable::value, ""); +static_assert(std::is_trivially_relocatable::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +//static_assert(std::is_trivially_relocatable>::value, ""); +//static_assert(std::is_trivially_relocatable>::value, ""); +//static_assert(!std::is_trivially_relocatable>::value, ""); +//static_assert(!std::is_trivially_relocatable>::value, ""); +//static_assert(!std::is_trivially_relocatable>::value, ""); +//static_assert(!std::is_trivially_relocatable>::value, ""); +//static_assert(!std::is_trivially_relocatable>::value, ""); +//static_assert(std::is_trivially_relocatable>::value == NotDebug, ""); +//static_assert(std::is_trivially_relocatable>::value == NotDebug, ""); +//static_assert(std::is_trivially_relocatable>::value == NotDebug, ""); +//static_assert(std::is_trivially_relocatable>::value == NotDebug, ""); +//static_assert(std::is_trivially_relocatable>::value == NotDebug, ""); +//static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable::iterator>::value, ""); +static_assert(std::is_trivially_relocatable::iterator>::value, ""); +static_assert(std::is_trivially_relocatable::iterator>::value, ""); +static_assert(std::is_trivially_relocatable::iterator>::value, ""); +static_assert(std::is_trivially_relocatable::iterator>::value == NotDebug, ""); +static_assert(std::is_trivially_relocatable::iterator>::value, ""); +static_assert(std::is_trivially_relocatable::iterator>::value, ""); +static_assert(std::is_trivially_relocatable::iterator>::value, ""); +static_assert(std::is_trivially_relocatable::iterator>::value, ""); +static_assert(std::is_trivially_relocatable::iterator>::value == NotDebug, ""); +static_assert(std::is_trivially_relocatable::iterator>::value == NotDebug, ""); +static_assert(std::is_trivially_relocatable::iterator>::value == NotDebug, ""); +static_assert(std::is_trivially_relocatable::iterator>::value == NotDebug, ""); +static_assert(std::is_trivially_relocatable::local_iterator>::value == NotDebug, ""); +static_assert(std::is_trivially_relocatable::local_iterator>::value == NotDebug, ""); +static_assert(std::is_trivially_relocatable::local_iterator>::value == NotDebug, ""); +static_assert(std::is_trivially_relocatable::local_iterator>::value == NotDebug, ""); +static_assert(std::is_trivially_relocatable::iterator>::value == NotDebug, ""); +static_assert(std::is_trivially_relocatable::const_iterator>::value == NotDebug, ""); +static_assert(!std::is_trivially_relocatable::iterator>::value, ""); +static_assert(std::is_trivially_relocatable::const_iterator>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>>::value, ""); +static_assert(std::is_trivially_relocatable>>::value, ""); +static_assert(std::is_trivially_relocatable>>::value == NotDebug, ""); +static_assert(!std::is_trivially_relocatable>>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); // because it uses vector internally +static_assert(!std::is_trivially_relocatable::value, ""); // because it uses vector internally +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(std::is_trivially_relocatable::value == NotDebug, ""); +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(std::is_trivially_relocatable::value == NotDebug, ""); +//static_assert(std::is_trivially_relocatable::value == NotDebug, ""); // because it uses vector internally +//static_assert(std::is_trivially_relocatable::value == NotDebug, ""); // because it uses vector internally +//static_assert(std::is_trivially_relocatable::value == NotDebug, ""); +//static_assert(std::is_trivially_relocatable::value == NotDebug, ""); +//static_assert(std::is_trivially_relocatable::value == NotDebug, ""); +//static_assert(std::is_trivially_relocatable::value == NotDebug, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable::value, ""); +static_assert(std::is_trivially_relocatable::value, ""); +static_assert(std::is_trivially_relocatable::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(std::is_trivially_relocatable::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); // contains pointer into self +static_assert(!std::is_trivially_relocatable>::value, ""); // contains pointer into self +static_assert(!std::is_trivially_relocatable>::value, ""); // contains pointer into self +static_assert(!std::is_trivially_relocatable>::value, ""); // contains pointer into self + +// The following types are not move-constructible at all. +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); + +int main(int, char**) { return 0; } diff --git a/libcxx/test/libcxx/utilities/meta/meta.unary.prop/is_trivially_relocatable.pass.cpp b/libcxx/test/libcxx/utilities/meta/meta.unary.prop/is_trivially_relocatable.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/meta/meta.unary.prop/is_trivially_relocatable.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// type_traits + +// __libcpp_is_trivially_relocatable +// __libcpp_is_trivially_relocatable_v + +// UNSUPPORTED: c++98, c++03 +// XFAIL: gcc-4.9 + +#include +#include +#include "test_macros.h" + +class Empty {}; + +class Polymorphic { +public: + virtual ~Polymorphic(); +}; + +union Union {}; + +struct bit_zero { + int : 0; +}; + +class Abstract { +public: + virtual ~Abstract() = 0; +}; + +struct NontrivialCopyOnly { + NontrivialCopyOnly(const NontrivialCopyOnly&); +}; + +struct TrivialCopyOnly { + TrivialCopyOnly(const TrivialCopyOnly&) = default; +}; + +#if TEST_STD_VER >= 11 + +struct NontrivialMoveOnly { + NontrivialMoveOnly(NontrivialMoveOnly&&); +}; + +struct TrivialMoveOnly { + TrivialMoveOnly(TrivialMoveOnly&&) = default; +}; +#endif + +int main(int, char**) { + static_assert(!std::__libcpp_is_trivially_relocatable::value, ""); + static_assert(!std::__libcpp_is_trivially_relocatable::value, ""); + static_assert(!std::__libcpp_is_trivially_relocatable::value, ""); + static_assert(!std::__libcpp_is_trivially_relocatable::value, ""); + static_assert(!std::__libcpp_is_trivially_relocatable::value, ""); + static_assert(!std::__libcpp_is_trivially_relocatable::value, ""); + + static_assert(std::__libcpp_is_trivially_relocatable::value, ""); + static_assert(std::__libcpp_is_trivially_relocatable::value, ""); + static_assert(std::__libcpp_is_trivially_relocatable::value, ""); + static_assert(std::__libcpp_is_trivially_relocatable::value, ""); + static_assert(std::__libcpp_is_trivially_relocatable::value, ""); + static_assert(std::__libcpp_is_trivially_relocatable::value, ""); + static_assert(std::__libcpp_is_trivially_relocatable::value, ""); + static_assert(std::__libcpp_is_trivially_relocatable::value, ""); + + static_assert(std::__libcpp_is_trivially_relocatable::value, ""); + static_assert(std::__libcpp_is_trivially_relocatable::value, ""); + static_assert(std::__libcpp_is_trivially_relocatable::value, ""); + static_assert(std::__libcpp_is_trivially_relocatable::value, ""); + + static_assert(std::__libcpp_is_trivially_relocatable::value, ""); + static_assert(std::__libcpp_is_trivially_relocatable::value, ""); + static_assert(std::__libcpp_is_trivially_relocatable::value, ""); + static_assert(std::__libcpp_is_trivially_relocatable::value, ""); + +#if TEST_STD_VER >= 11 + static_assert(!std::__libcpp_is_trivially_relocatable::value, ""); + static_assert(!std::__libcpp_is_trivially_relocatable::value, ""); + static_assert(std::__libcpp_is_trivially_relocatable::value, ""); + static_assert(!std::__libcpp_is_trivially_relocatable::value, ""); +#endif + + return 0; +} diff --git a/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_exception_safety.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_exception_safety.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_exception_safety.pass.cpp @@ -0,0 +1,119 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// void insert(const_iterator it, const value_type& x); + +#include +#include + +static int countdown = 0; +static int constructions = 0; +static int destructions = 0; + +struct MyError {}; + +struct TriviallyRelocatable {}; + +struct NotTriviallyRelocatable { + ~NotTriviallyRelocatable() {} +}; + +template +struct [[clang::trivial_abi]] MyClass : std::conditional::type { + int value; + explicit MyClass(int i) : value(i) { ++constructions; } + MyClass(const MyClass& rhs) _NOEXCEPT_(!CC) { + value = rhs.value; + countdown_if(); + ++constructions; + } + MyClass(MyClass&& rhs) _NOEXCEPT_(!MC) { + value = rhs.value; + countdown_if(); + ++constructions; + } + MyClass& operator=(const MyClass& rhs) _NOEXCEPT_(!CA) { + value = rhs.value; + countdown_if(); + return *this; + } + MyClass& operator=(MyClass&& rhs) _NOEXCEPT_(!MA) { + value = rhs.value; + countdown_if(); + return *this; + } + ~MyClass() { ++destructions; } + template + void countdown_if() { + if (C && countdown-- == 0) + throw MyError(); + } +}; + +template +void test() { + using T = MyClass; + for (int n = 0; true; ++n) { + { + std::vector vec; + vec.reserve(5); + try { + countdown = n; + vec.push_back(T(1)); + vec.push_back(T(2)); + vec.push_back(T(3)); + vec.insert(vec.begin() + 2, T(4)); + vec.insert(vec.begin() + 2, T(5)); + // if we reach here, no exception was thrown + break; + } catch (const MyError&) { + assert(constructions == destructions + static_cast(vec.size())); + } + } + // destroy the vector and check the invariant again + assert(constructions == destructions); + } +} + +int main(int, char**) { + test<0x00>(); + test<0x01>(); + test<0x02>(); + test<0x03>(); + test<0x04>(); + test<0x05>(); + test<0x06>(); + test<0x07>(); + test<0x08>(); + test<0x09>(); + test<0x0a>(); + test<0x0b>(); + test<0x0c>(); + test<0x0d>(); + test<0x0e>(); + test<0x0f>(); + test<0x10>(); + test<0x11>(); + test<0x12>(); + test<0x13>(); + test<0x14>(); + test<0x15>(); + test<0x16>(); + test<0x17>(); + test<0x18>(); + test<0x19>(); + test<0x1a>(); + test<0x1b>(); + test<0x1c>(); + test<0x1d>(); + test<0x1e>(); + test<0x1f>(); + return 0; +}