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

Reply via email to