[libcxx] Use custom allocator's `construct` in C++03 when available.
authorVolodymyr Sapsai <vsapsai@apple.com>
Wed, 19 Dec 2018 20:08:43 +0000 (20:08 +0000)
committerVolodymyr Sapsai <vsapsai@apple.com>
Wed, 19 Dec 2018 20:08:43 +0000 (20:08 +0000)
Makes libc++ behavior consistent between C++03 and C++11.

Can use `decltype` in C++03 because `include/__config` defines a macro when
`decltype` is not available.

Reviewers: mclow.lists, EricWF, erik.pilkington, ldionne

Reviewed By: ldionne

Subscribers: dexonsmith, cfe-commits, howard.hinnant, ldionne, christof, jkorous, Quuxplusone

Differential Revision: https://reviews.llvm.org/D48753

llvm-svn: 349676

libcxx/include/memory
libcxx/test/libcxx/containers/sequences/vector/vector.cons/construct_iter_iter.pass.cpp [new file with mode: 0644]
libcxx/test/libcxx/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp [new file with mode: 0644]
libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/destroy.pass.cpp
libcxx/test/support/min_allocator.h

index 3e8f593..b012f5b 100644 (file)
@@ -1460,29 +1460,21 @@ struct __has_select_on_container_copy_construction
 
 #else  // _LIBCPP_CXX03_LANG
 
-#ifndef _LIBCPP_HAS_NO_VARIADICS
-
-template <class _Alloc, class _Pointer, class ..._Args>
-struct __has_construct
-    : false_type
-{
-};
+template <class _Alloc, class _Pointer, class _Tp, class = void>
+struct __has_construct : std::false_type {};
 
-#else  // _LIBCPP_HAS_NO_VARIADICS
+template <class _Alloc, class _Pointer, class _Tp>
+struct __has_construct<_Alloc, _Pointer, _Tp, typename __void_t<
+    decltype(_VSTD::declval<_Alloc>().construct(_VSTD::declval<_Pointer>(), _VSTD::declval<_Tp>()))
+>::type> : std::true_type {};
 
-template <class _Alloc, class _Pointer, class _Args>
-struct __has_construct
-    : false_type
-{
-};
-
-#endif  // _LIBCPP_HAS_NO_VARIADICS
+template <class _Alloc, class _Pointer, class = void>
+struct __has_destroy : false_type {};
 
 template <class _Alloc, class _Pointer>
-struct __has_destroy
-    : false_type
-{
-};
+struct __has_destroy<_Alloc, _Pointer, typename __void_t<
+    decltype(_VSTD::declval<_Alloc>().destroy(_VSTD::declval<_Pointer>()))
+>::type> : std::true_type {};
 
 template <class _Alloc>
 struct __has_max_size
@@ -1571,9 +1563,10 @@ struct _LIBCPP_TEMPLATE_VIS allocator_traits
             }
     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<allocator_type, _Tp*, const _A0&>(),
+                            __a, __p, __a0);
             }
     template <class _Tp, class _A0, class _A1>
         _LIBCPP_INLINE_VISIBILITY
@@ -1721,6 +1714,19 @@ private:
             {
                 ::new ((void*)__p) _Tp(_VSTD::forward<_Args>(__args)...);
             }
+#else  // _LIBCPP_HAS_NO_VARIADICS
+    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);
+            }
 #endif  // _LIBCPP_HAS_NO_VARIADICS
 
     template <class _Tp>
diff --git a/libcxx/test/libcxx/containers/sequences/vector/vector.cons/construct_iter_iter.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector/vector.cons/construct_iter_iter.pass.cpp
new file mode 100644 (file)
index 0000000..998d0b7
--- /dev/null
@@ -0,0 +1,54 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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);
+
+#include <vector>
+#include <cassert>
+
+#include "min_allocator.h"
+
+void test_ctor_under_alloc() {
+  int arr1[] = {42};
+  int arr2[] = {1, 101, 42};
+  {
+    typedef std::vector<int, cpp03_allocator<int> > C;
+    typedef C::allocator_type Alloc;
+    {
+      Alloc::construct_called = false;
+      C v(arr1, arr1 + 1);
+      assert(Alloc::construct_called);
+    }
+    {
+      Alloc::construct_called = false;
+      C v(arr2, arr2 + 3);
+      assert(Alloc::construct_called);
+    }
+  }
+  {
+    typedef std::vector<int, cpp03_overload_allocator<int> > C;
+    typedef C::allocator_type Alloc;
+    {
+      Alloc::construct_called = false;
+      C v(arr1, arr1 + 1);
+      assert(Alloc::construct_called);
+    }
+    {
+      Alloc::construct_called = false;
+      C v(arr2, arr2 + 3);
+      assert(Alloc::construct_called);
+    }
+  }
+}
+
+int main() {
+  test_ctor_under_alloc();
+}
diff --git a/libcxx/test/libcxx/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp
new file mode 100644 (file)
index 0000000..c4950fb
--- /dev/null
@@ -0,0 +1,57 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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,
+//                                   const allocator_type& a);
+
+#include <vector>
+#include <cassert>
+
+#include "min_allocator.h"
+
+void test_ctor_under_alloc() {
+  int arr1[] = {42};
+  int arr2[] = {1, 101, 42};
+  {
+    typedef std::vector<int, cpp03_allocator<int> > C;
+    typedef C::allocator_type Alloc;
+    Alloc a;
+    {
+      Alloc::construct_called = false;
+      C v(arr1, arr1 + 1, a);
+      assert(Alloc::construct_called);
+    }
+    {
+      Alloc::construct_called = false;
+      C v(arr2, arr2 + 3, a);
+      assert(Alloc::construct_called);
+    }
+  }
+  {
+    typedef std::vector<int, cpp03_overload_allocator<int> > C;
+    typedef C::allocator_type Alloc;
+    Alloc a;
+    {
+      Alloc::construct_called = false;
+      C v(arr1, arr1 + 1, a);
+      assert(Alloc::construct_called);
+    }
+    {
+      Alloc::construct_called = false;
+      C v(arr2, arr2 + 3, a);
+      assert(Alloc::construct_called);
+    }
+  }
+}
+
+int main() {
+  test_ctor_under_alloc();
+}
index 1a81287..1060b73 100644 (file)
@@ -73,7 +73,7 @@ int main()
       std::aligned_storage<sizeof(VT)>::type store;
       std::allocator_traits<Alloc>::destroy(a, (VT*)&store);
     }
-#if TEST_STD_VER >= 11
+#if defined(_LIBCPP_VERSION) || TEST_STD_VER >= 11
     {
         A0::count = 0;
         b_destroy = 0;
index a3af9e1..4547493 100644 (file)
@@ -14,6 +14,7 @@
 #include <cstdlib>
 #include <cstddef>
 #include <cassert>
+#include <climits>
 
 #include "test_macros.h"
 
@@ -131,6 +132,59 @@ public:
     friend bool operator!=(malloc_allocator x, malloc_allocator y) {return !(x == y);}
 };
 
+template <class T>
+struct cpp03_allocator : bare_allocator<T>
+{
+    typedef T value_type;
+    typedef value_type* pointer;
+
+    static bool construct_called;
+
+    // Returned value is not used but it's not prohibited.
+    pointer construct(pointer p, const value_type& val)
+    {
+        ::new(p) value_type(val);
+        construct_called = true;
+        return p;
+    }
+
+    std::size_t max_size() const
+    {
+        return UINT_MAX / sizeof(T);
+    }
+};
+template <class T> bool cpp03_allocator<T>::construct_called = false;
+
+template <class T>
+struct cpp03_overload_allocator : bare_allocator<T>
+{
+    typedef T value_type;
+    typedef value_type* pointer;
+
+    static bool construct_called;
+
+    void construct(pointer p, const value_type& val)
+    {
+        construct(p, val, std::is_class<T>());
+    }
+    void construct(pointer p, const value_type& val, std::true_type)
+    {
+        ::new(p) value_type(val);
+        construct_called = true;
+    }
+    void construct(pointer p, const value_type& val, std::false_type)
+    {
+        ::new(p) value_type(val);
+        construct_called = true;
+    }
+
+    std::size_t max_size() const
+    {
+        return UINT_MAX / sizeof(T);
+    }
+};
+template <class T> bool cpp03_overload_allocator<T>::construct_called = false;
+
 
 #if TEST_STD_VER >= 11