vsapsai updated this revision to Diff 153430. vsapsai added a comment. Herald added a subscriber: dexonsmith.
- Don't check `!__has_construct` for `__construct_range_forward`. Incompatible types will cause a lack of `construct` but it doesn't mean we should use memcpy instead. And missing `_Alloc::construct` doesn't mean `alloc_traits::construct` will fail, so falling back on memcpy can be premature. https://reviews.llvm.org/D48342 Files: libcxx/include/memory libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter_different_value_type.pass.cpp
Index: libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter_different_value_type.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter_different_value_type.pass.cpp @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +// <vector> + +// template <class InputIter> vector(InputIter first, InputIter last); + +// Initialize a vector with a different value type. Make sure initialization +// is performed with each element value, not with a memory blob. + +#include <vector> +#include <cassert> +#include <cfloat> +#include <cmath> + +int main() +{ + int array[3] = {0, 1, 2}; + std::vector<float> v(array, array + 3); + assert(std::fabs(v[0] - 0.0f) < FLT_EPSILON); + assert(std::fabs(v[1] - 1.0f) < FLT_EPSILON); + assert(std::fabs(v[2] - 2.0f) < FLT_EPSILON); +} Index: libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp =================================================================== --- libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp +++ libcxx/test/std/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp @@ -50,6 +50,26 @@ #endif +template <class T> +struct cpp03_allocator : bare_allocator<T> { + typedef T value_type; + typedef value_type* pointer; + + static bool construct_called; + + void construct(pointer p, const value_type& val) + { + ::new(p) value_type(val); + construct_called = true; + } + + std::size_t max_size() const + { + return UINT_MAX / sizeof(T); + } +}; +template <class T> bool cpp03_allocator<T>::construct_called = false; + void basic_tests() { { int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 1, 0}; @@ -129,9 +149,22 @@ } void test_ctor_under_alloc() { -#if TEST_STD_VER >= 11 int arr1[] = {42}; int arr2[] = {1, 101, 42}; + { + typedef std::vector<int, cpp03_allocator<int> > C; + { + cpp03_allocator<int>::construct_called = false; + C v(arr1, arr1 + 1); + assert(cpp03_allocator<int>::construct_called); + } + { + cpp03_allocator<int>::construct_called = false; + C v(arr2, arr2 + 3); + assert(cpp03_allocator<int>::construct_called); + } + } +#if TEST_STD_VER >= 11 { using C = TCT::vector<>; using T = typename C::value_type; @@ -162,6 +195,17 @@ //C v(It(arr2), It(std::end(arr2)), a); } } + { + using C = std::vector<int, ContainerTestAllocator<int, int> >; + { + ExpectConstructGuard<int&> G(1); + C v(arr1, arr1 + 1); + } + { + ExpectConstructGuard<int&> G(3); + C v(arr2, arr2 + 3); + } + } #endif } Index: libcxx/include/memory =================================================================== --- libcxx/include/memory +++ libcxx/include/memory @@ -1459,24 +1459,102 @@ #else // _LIBCPP_CXX03_LANG -#ifndef _LIBCPP_HAS_NO_VARIADICS +template <class _Alloc, class _Pointer> +struct __has_construct_test_0 +{ +private: + template <class _Xp> static true_type __test(void (_Xp::*)(_Pointer)); + template <class _Xp> static false_type __test(...); -template <class _Alloc, class _Pointer, class ..._Args> -struct __has_construct - : false_type + template <class _Xp> + static decltype(__test(&_Xp::construct)) __test_exist(decltype(&_Xp::construct)); + template <class _Xp> static false_type __test_exist(...); + + typedef decltype(__test_exist<_Alloc>(0)) type; +public: + static const bool value = type::value; +}; + +template <class _Alloc, class _Pointer> +struct __has_construct_0 + : integral_constant<bool, __has_construct_test_0<_Alloc, _Pointer>::value> { }; -#else // _LIBCPP_HAS_NO_VARIADICS +template <class _Alloc, class _Pointer, class _A0> +struct __has_construct_test_1 +{ +private: + template <class _Xp> static true_type __test(void (_Xp::*)(_Pointer, _A0)); + template <class _Xp> static false_type __test(...); + + template <class _Xp> + static decltype(__test(&_Xp::construct)) __test_exist(decltype(&_Xp::construct)); + template <class _Xp> static false_type __test_exist(...); + + typedef decltype(__test_exist<_Alloc>(0)) type; +public: + static const bool value = type::value; +}; + +template <class _Alloc, class _Pointer, class _A0> +struct __has_construct_1 + : integral_constant<bool, __has_construct_test_1<_Alloc, _Pointer, _A0>::value> +{ +}; + +template <class _Alloc, class _Pointer, class _A0, class _A1> +struct __has_construct_test_2 +{ +private: + template <class _Xp> static true_type __test(void (_Xp::*)(_Pointer, _A0, _A1)); + template <class _Xp> static false_type __test(...); + + template <class _Xp> + static decltype(__test(&_Xp::construct)) __test_exist(decltype(&_Xp::construct)); + template <class _Xp> static false_type __test_exist(...); + + typedef decltype(__test_exist<_Alloc>(0)) type; +public: + static const bool value = type::value; +}; + +template <class _Alloc, class _Pointer, class _A0, class _A1> +struct __has_construct_2 + : integral_constant<bool, __has_construct_test_2<_Alloc, _Pointer, _A0, _A1>::value> +{ +}; + +template <class _Alloc, class _Pointer, class _A0, class _A1, class _A2> +struct __has_construct_test_3 +{ +private: + template <class _Xp> static true_type __test(void (_Xp::*)(_Pointer, _A0, _A1, _A2)); + template <class _Xp> static false_type __test(...); + + template <class _Xp> + static decltype(__test(&_Xp::construct)) __test_exist(decltype(&_Xp::construct)); + template <class _Xp> static false_type __test_exist(...); + + typedef decltype(__test_exist<_Alloc>(0)) type; +public: + static const bool value = type::value; +}; + +template <class _Alloc, class _Pointer, class _A0, class _A1, class _A2> +struct __has_construct_3 + : integral_constant<bool, __has_construct_test_3<_Alloc, _Pointer, _A0, _A1, _A2>::value> +{ +}; template <class _Alloc, class _Pointer, class _Args> struct __has_construct - : false_type + : integral_constant<bool, + __has_construct_test_1<_Alloc, _Pointer, _Args>::value + || __has_construct_test_1<_Alloc, _Pointer, const _Args&>::value> { }; -#endif // _LIBCPP_HAS_NO_VARIADICS - template <class _Alloc, class _Pointer> struct __has_destroy : false_type @@ -1564,29 +1642,33 @@ #else // _LIBCPP_HAS_NO_VARIADICS template <class _Tp> _LIBCPP_INLINE_VISIBILITY - static void construct(allocator_type&, _Tp* __p) + static void construct(allocator_type& __a, _Tp* __p) { - ::new ((void*)__p) _Tp(); + __construct(__has_construct_0<allocator_type, _Tp*>(), __a, + __p); } template <class _Tp, class _A0> _LIBCPP_INLINE_VISIBILITY - static void construct(allocator_type&, _Tp* __p, const _A0& __a0) + static void construct(allocator_type& __a, _Tp* __p, const _A0& __a0) { - ::new ((void*)__p) _Tp(__a0); + __construct(__has_construct_1<allocator_type, _Tp*, const _A0&>(), + __a, __p, __a0); } template <class _Tp, class _A0, class _A1> _LIBCPP_INLINE_VISIBILITY - static void construct(allocator_type&, _Tp* __p, const _A0& __a0, + static void construct(allocator_type& __a, _Tp* __p, const _A0& __a0, const _A1& __a1) { - ::new ((void*)__p) _Tp(__a0, __a1); + __construct(__has_construct_2<allocator_type, _Tp*, const _A0&, const _A1&>(), + __a, __p, __a0, __a1); } template <class _Tp, class _A0, class _A1, class _A2> _LIBCPP_INLINE_VISIBILITY - static void construct(allocator_type&, _Tp* __p, const _A0& __a0, + static void construct(allocator_type& __a, _Tp* __p, const _A0& __a0, const _A1& __a1, const _A2& __a2) { - ::new ((void*)__p) _Tp(__a0, __a1, __a2); + __construct(__has_construct_3<allocator_type, _Tp*, const _A0&, const _A1&, const _A2&>(), + __a, __p, __a0, __a1, __a2); } #endif // _LIBCPP_HAS_NO_VARIADICS @@ -1646,23 +1728,23 @@ construct(__a, _VSTD::__to_raw_pointer(__begin2), *__begin1); } - template <class _Tp> + template <class _SourceTp, class _DestTp> _LIBCPP_INLINE_VISIBILITY static typename enable_if < - (is_same<allocator_type, allocator<_Tp> >::value - || !__has_construct<allocator_type, _Tp*, _Tp>::value) && - is_trivially_move_constructible<_Tp>::value, + (is_same<allocator_type, allocator<typename _VSTD::remove_const<_SourceTp>::type> >::value + || is_same<allocator_type, allocator<const _SourceTp> >::value) && + is_trivially_move_constructible<_DestTp>::value, void >::type - __construct_range_forward(allocator_type&, _Tp* __begin1, _Tp* __end1, _Tp*& __begin2) + __construct_range_forward(allocator_type&, _SourceTp* __begin1, _SourceTp* __end1, _DestTp*& __begin2) { - typedef typename remove_const<_Tp>::type _Vp; + typedef typename remove_const<_DestTp>::type _Vp; ptrdiff_t _Np = __end1 - __begin1; if (_Np > 0) { - _VSTD::memcpy(const_cast<_Vp*>(__begin2), __begin1, _Np * sizeof(_Tp)); + _VSTD::memcpy(const_cast<_Vp*>(__begin2), __begin1, _Np * sizeof(_DestTp)); __begin2 += _Np; } } @@ -1720,6 +1802,53 @@ { ::new ((void*)__p) _Tp(_VSTD::forward<_Args>(__args)...); } +#else // _LIBCPP_HAS_NO_VARIADICS + template <class _Tp> + _LIBCPP_INLINE_VISIBILITY + static void __construct(true_type, allocator_type& __a, _Tp* __p) + {__a.construct(__p);} + template <class _Tp> + _LIBCPP_INLINE_VISIBILITY + static void __construct(false_type, allocator_type&, _Tp* __p) + { + ::new ((void*)__p) _Tp(); + } + template <class _Tp, class _A0> + _LIBCPP_INLINE_VISIBILITY + static void __construct(true_type, allocator_type& __a, _Tp* __p, + const _A0& __a0) + {__a.construct(__p, __a0);} + template <class _Tp, class _A0> + _LIBCPP_INLINE_VISIBILITY + static void __construct(false_type, allocator_type&, _Tp* __p, + const _A0& __a0) + { + ::new ((void*)__p) _Tp(__a0); + } + template <class _Tp, class _A0, class _A1> + _LIBCPP_INLINE_VISIBILITY + static void __construct(true_type, allocator_type& __a, _Tp* __p, + const _A0& __a0, const _A1& __a1) + {__a.construct(__p, __a0, __a1);} + template <class _Tp, class _A0, class _A1> + _LIBCPP_INLINE_VISIBILITY + static void __construct(false_type, allocator_type&, _Tp* __p, + const _A0& __a0, const _A1& __a1) + { + ::new ((void*)__p) _Tp(__a0, __a1); + } + template <class _Tp, class _A0, class _A1, class _A2> + _LIBCPP_INLINE_VISIBILITY + static void __construct(true_type, allocator_type& __a, _Tp* __p, + const _A0& __a0, const _A1& __a1, const _A2& __a2) + {__a.construct(__p, __a0, __a1, __a2);} + template <class _Tp, class _A0, class _A1, class _A2> + _LIBCPP_INLINE_VISIBILITY + static void __construct(false_type, allocator_type&, _Tp* __p, + const _A0& __a0, const _A1& __a1, const _A2& __a2) + { + ::new ((void*)__p) _Tp(__a0, __a1, __a2); + } #endif // _LIBCPP_HAS_NO_VARIADICS template <class _Tp>
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits