[libcxx] r272747 - [libcxx] [test] In test/support/test_allocator.h, fix construct() to avoid moving immovable types.

Eric Fiselier via cfe-commits cfe-commits at lists.llvm.org
Tue Jun 14 18:53:32 PDT 2016


Author: ericwf
Date: Tue Jun 14 20:53:32 2016
New Revision: 272747

URL: http://llvm.org/viewvc/llvm-project?rev=272747&view=rev
Log:
[libcxx] [test] In test/support/test_allocator.h, fix construct() to avoid moving immovable types.

Summary:
In test/support/test_allocator.h, fix construct() to avoid moving immovable types.

This improves the allocator's conformance, and fixes compiler errors with MSVC's STL. The scenario is when the allocator is asked to construct an object of type X that's immovable (deleted copy/move ctors), but implicitly constructible from an argument type A. When perfectly forwarded, X can be (explicitly) constructed from A, and everything is fine. That's std::allocator's behavior, and the Standard's default when a user allocator's construct() doesn't exist. The previous implementation of construct() here mishandled this scenario. Passing A to this construct() would implicitly construct an X temporary, bound to (non-templated) T&&. Then construct() would attempt to move-construct X from that X temporary, but X is immovable, boom.

Reviewers: mclow.lists, EricWF

Subscribers: cfe-commits

Differential Revision: http://reviews.llvm.org/D21094

Modified:
    libcxx/trunk/test/support/test_allocator.h

Modified: libcxx/trunk/test/support/test_allocator.h
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/support/test_allocator.h?rev=272747&r1=272746&r2=272747&view=diff
==============================================================================
--- libcxx/trunk/test/support/test_allocator.h (original)
+++ libcxx/trunk/test/support/test_allocator.h Tue Jun 14 20:53:32 2016
@@ -80,14 +80,14 @@ public:
         {assert(data_ >= 0); --alloc_count; ::operator delete((void*)p);}
     size_type max_size() const throw()
         {return UINT_MAX / sizeof(T);}
+#if TEST_STD_VER < 11
     void construct(pointer p, const T& val)
-        {::new(p) T(val);}
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
-    void construct(pointer p, T&& val)
-        {::new(p) T(std::move(val));}
-#endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+        {::new(static_cast<void*>(p)) T(val);}
+#else
+    template <class U> void construct(pointer p, U&& val)
+        {::new(static_cast<void*>(p)) T(std::forward<U>(val));}
+#endif
     void destroy(pointer p) {p->~T();}
-
     friend bool operator==(const test_allocator& x, const test_allocator& y)
         {return x.data_ == y.data_;}
     friend bool operator!=(const test_allocator& x, const test_allocator& y)
@@ -140,12 +140,13 @@ public:
         {assert(data_ >= 0); --alloc_count; ::operator delete((void*)p); }
     size_type max_size() const throw()
         {return UINT_MAX / sizeof(T);}
+#if TEST_STD_VER < 11
     void construct(pointer p, const T& val)
-        {::new(p) T(val);}
-#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
-    void construct(pointer p, T&& val)
-        {::new(p) T(std::move(val));}
-#endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+        {::new(static_cast<void*>(p)) T(val);}
+#else
+    template <class U> void construct(pointer p, U&& val)
+        {::new(static_cast<void*>(p)) T(std::forward<U>(val));}
+#endif
     void destroy(pointer p) {p->~T();}
 
     friend bool operator==(const non_default_test_allocator& x, const non_default_test_allocator& y)




More information about the cfe-commits mailing list