[libcxx] r333384 - LWG 2969 "polymorphic_allocator::construct() shouldn't pass resource()"

Eric Fiselier via cfe-commits cfe-commits at lists.llvm.org
Mon May 28 17:08:47 PDT 2018


Author: ericwf
Date: Mon May 28 17:08:47 2018
New Revision: 333384

URL: http://llvm.org/viewvc/llvm-project?rev=333384&view=rev
Log:
LWG 2969 "polymorphic_allocator::construct() shouldn't pass resource()"

Patch from Arthur O'Dwyer.

In the TS, `uses_allocator` construction for `pair` tried to use an allocator
type of `memory_resource*`, which is incorrect because `memory_resource*` is
not an allocator type. LWG 2969 fixed it to use `polymorphic_allocator` as the
allocator type instead.

https://wg21.link/lwg2969

(D47090 included this in `<memory_resource>`; at Eric's request, I've split
this out into its own patch applied to the existing
`<experimental/memory_resource>` instead.)

Reviewed as https://reviews.llvm.org/D47109

Added:
    libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair_evil.pass.cpp
Modified:
    libcxx/trunk/include/experimental/memory_resource
    libcxx/trunk/test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp
    libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_const_lvalue_pair.pass.cpp
    libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_rvalue.pass.cpp
    libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_values.pass.cpp
    libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp
    libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_types.pass.cpp
    libcxx/trunk/test/support/test_memory_resource.hpp

Modified: libcxx/trunk/include/experimental/memory_resource
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/experimental/memory_resource?rev=333384&r1=333383&r2=333384&view=diff
==============================================================================
--- libcxx/trunk/include/experimental/memory_resource (original)
+++ libcxx/trunk/include/experimental/memory_resource Mon May 28 17:08:47 2018
@@ -206,7 +206,7 @@ public:
     void construct(_Tp* __p, _Ts &&... __args)
     {
         _VSTD_LFTS::__lfts_user_alloc_construct(
-            __p, resource(), _VSTD::forward<_Ts>(__args)...
+            __p, *this, _VSTD::forward<_Ts>(__args)...
           );
     }
 
@@ -218,14 +218,14 @@ public:
         ::new ((void*)__p) pair<_T1, _T2>(piecewise_construct
           , __transform_tuple(
               typename __lfts_uses_alloc_ctor<
-                  _T1, memory_resource*, _Args1...
+                  _T1, polymorphic_allocator&, _Args1...
               >::type()
             , _VSTD::move(__x)
             , typename __make_tuple_indices<sizeof...(_Args1)>::type{}
           )
           , __transform_tuple(
               typename __lfts_uses_alloc_ctor<
-                  _T2, memory_resource*, _Args2...
+                  _T2, polymorphic_allocator&, _Args2...
               >::type()
             , _VSTD::move(__y)
             , typename __make_tuple_indices<sizeof...(_Args2)>::type{}
@@ -289,23 +289,23 @@ private:
 
     template <class ..._Args, size_t ..._Idx>
     _LIBCPP_INLINE_VISIBILITY
-    tuple<allocator_arg_t const&, memory_resource*, _Args&&...>
+    tuple<allocator_arg_t const&, polymorphic_allocator&, _Args&&...>
     __transform_tuple(integral_constant<int, 1>, tuple<_Args...> && __t,
-                      __tuple_indices<_Idx...>) const
+                      __tuple_indices<_Idx...>)
     {
-        using _Tup = tuple<allocator_arg_t const&, memory_resource*, _Args&&...>;
-        return _Tup(allocator_arg, resource(),
+        using _Tup = tuple<allocator_arg_t const&, polymorphic_allocator&, _Args&&...>;
+        return _Tup(allocator_arg, *this,
                     _VSTD::get<_Idx>(_VSTD::move(__t))...);
     }
 
     template <class ..._Args, size_t ..._Idx>
     _LIBCPP_INLINE_VISIBILITY
-    tuple<_Args&&..., memory_resource*>
+    tuple<_Args&&..., polymorphic_allocator&>
     __transform_tuple(integral_constant<int, 2>, tuple<_Args...> && __t,
-                      __tuple_indices<_Idx...>) const
+                      __tuple_indices<_Idx...>)
     {
-        using _Tup = tuple<_Args&&..., memory_resource*>;
-        return _Tup(_VSTD::get<_Idx>(_VSTD::move(__t))..., resource());
+        using _Tup = tuple<_Args&&..., polymorphic_allocator&>;
+        return _Tup(_VSTD::get<_Idx>(_VSTD::move(__t))..., *this);
     }
 
     _LIBCPP_INLINE_VISIBILITY

Modified: libcxx/trunk/test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp?rev=333384&r1=333383&r2=333384&view=diff
==============================================================================
--- libcxx/trunk/test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp (original)
+++ libcxx/trunk/test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp Mon May 28 17:08:47 2018
@@ -79,12 +79,12 @@ struct CountCopies {
 };
 
 struct CountCopiesAllocV1 {
-  typedef ex::memory_resource* allocator_type;
-  allocator_type alloc;
+  typedef ex::polymorphic_allocator<char> allocator_type;
+  ex::memory_resource *alloc;
   int count;
   CountCopiesAllocV1() : alloc(nullptr), count(0) {}
   CountCopiesAllocV1(std::allocator_arg_t, allocator_type const& a,
-                     CountCopiesAllocV1 const& o) : alloc(a), count(o.count + 1)
+                     CountCopiesAllocV1 const& o) : alloc(a.resource()), count(o.count + 1)
   {}
 
   CountCopiesAllocV1(CountCopiesAllocV1 const& o) : count(o.count + 1) {}
@@ -92,12 +92,12 @@ struct CountCopiesAllocV1 {
 
 
 struct CountCopiesAllocV2 {
-  typedef ex::memory_resource* allocator_type;
-  allocator_type alloc;
+  typedef ex::polymorphic_allocator<char> allocator_type;
+  ex::memory_resource *alloc;
   int count;
   CountCopiesAllocV2() : alloc(nullptr), count(0) {}
   CountCopiesAllocV2(CountCopiesAllocV2 const& o, allocator_type const& a)
-    : alloc(a), count(o.count + 1)
+    : alloc(a.resource()), count(o.count + 1)
   { }
 
   CountCopiesAllocV2(CountCopiesAllocV2 const& o) : count(o.count + 1) {}

Modified: libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_const_lvalue_pair.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_const_lvalue_pair.pass.cpp?rev=333384&r1=333383&r2=333384&view=diff
==============================================================================
--- libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_const_lvalue_pair.pass.cpp (original)
+++ libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_const_lvalue_pair.pass.cpp Mon May 28 17:08:47 2018
@@ -90,6 +90,32 @@ void test_pmr_uses_allocator(std::pair<T
         assert((doTest<T, U>(UA_AllocArg, UA_None, p)));
     }
 }
+
+template <class Alloc, class TT, class UU>
+void test_pmr_not_uses_allocator(std::pair<TT, UU> const& p)
+{
+    {
+        using T = NotUsesAllocator<Alloc, 1>;
+        using U = NotUsesAllocator<Alloc, 1>;
+        assert((doTest<T, U>(UA_None, UA_None, p)));
+    }
+    {
+        using T = UsesAllocatorV1<Alloc, 1>;
+        using U = UsesAllocatorV2<Alloc, 1>;
+        assert((doTest<T, U>(UA_None, UA_None, p)));
+    }
+    {
+        using T = UsesAllocatorV2<Alloc, 1>;
+        using U = UsesAllocatorV3<Alloc, 1>;
+        assert((doTest<T, U>(UA_None, UA_None, p)));
+    }
+    {
+        using T = UsesAllocatorV3<Alloc, 1>;
+        using U = NotUsesAllocator<Alloc, 1>;
+        assert((doTest<T, U>(UA_None, UA_None, p)));
+    }
+}
+
 template <class Tp>
 struct Print;
 
@@ -103,7 +129,7 @@ int main()
         int y = 42;
         const std::pair<int, int&> p(x, y);
         test_pmr_uses_allocator<ERT>(p);
-        test_pmr_uses_allocator<PMR>(p);
+        test_pmr_not_uses_allocator<PMR>(p);
         test_pmr_uses_allocator<PMA>(p);
     }
     {
@@ -111,7 +137,7 @@ int main()
         int y = 42;
         const std::pair<int&, int&&> p(x, std::move(y));
         test_pmr_uses_allocator<ERT>(p);
-        test_pmr_uses_allocator<PMR>(p);
+        test_pmr_not_uses_allocator<PMR>(p);
         test_pmr_uses_allocator<PMA>(p);
     }
 }

Modified: libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_rvalue.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_rvalue.pass.cpp?rev=333384&r1=333383&r2=333384&view=diff
==============================================================================
--- libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_rvalue.pass.cpp (original)
+++ libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_rvalue.pass.cpp Mon May 28 17:08:47 2018
@@ -90,6 +90,31 @@ void test_pmr_uses_allocator(std::pair<T
     }
 }
 
+template <class Alloc, class TT, class UU>
+void test_pmr_not_uses_allocator(std::pair<TT, UU>&& p)
+{
+    {
+        using T = NotUsesAllocator<Alloc, 1>;
+        using U = NotUsesAllocator<Alloc, 1>;
+        assert((doTest<T, U>(UA_None, UA_None, std::move(p))));
+    }
+    {
+        using T = UsesAllocatorV1<Alloc, 1>;
+        using U = UsesAllocatorV2<Alloc, 1>;
+        assert((doTest<T, U>(UA_None, UA_None, std::move(p))));
+    }
+    {
+        using T = UsesAllocatorV2<Alloc, 1>;
+        using U = UsesAllocatorV3<Alloc, 1>;
+        assert((doTest<T, U>(UA_None, UA_None, std::move(p))));
+    }
+    {
+        using T = UsesAllocatorV3<Alloc, 1>;
+        using U = NotUsesAllocator<Alloc, 1>;
+        assert((doTest<T, U>(UA_None, UA_None, std::move(p))));
+    }
+}
+
 int main()
 {
     using ERT = std::experimental::erased_type;
@@ -100,7 +125,7 @@ int main()
         int y = 42;
         std::pair<int&, int&&> p(x, std::move(y));
         test_pmr_uses_allocator<ERT>(std::move(p));
-        test_pmr_uses_allocator<PMR>(std::move(p));
+        test_pmr_not_uses_allocator<PMR>(std::move(p));
         test_pmr_uses_allocator<PMA>(std::move(p));
     }
     {
@@ -108,7 +133,7 @@ int main()
         int y = 42;
         std::pair<int&&, int&> p(std::move(x), y);
         test_pmr_uses_allocator<ERT>(std::move(p));
-        test_pmr_uses_allocator<PMR>(std::move(p));
+        test_pmr_not_uses_allocator<PMR>(std::move(p));
         test_pmr_uses_allocator<PMA>(std::move(p));
     }
 }

Modified: libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_values.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_values.pass.cpp?rev=333384&r1=333383&r2=333384&view=diff
==============================================================================
--- libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_values.pass.cpp (original)
+++ libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_values.pass.cpp Mon May 28 17:08:47 2018
@@ -93,6 +93,35 @@ void test_pmr_uses_allocator(TT&& t, UU&
     }
 }
 
+template <class Alloc, class TT, class UU>
+void test_pmr_not_uses_allocator(TT&& t, UU&& u)
+{
+    {
+        using T = NotUsesAllocator<Alloc, 1>;
+        using U = NotUsesAllocator<Alloc, 1>;
+        assert((doTest<T, U>(UA_None, UA_None,
+                             std::forward<TT>(t), std::forward<UU>(u))));
+    }
+    {
+        using T = UsesAllocatorV1<Alloc, 1>;
+        using U = UsesAllocatorV2<Alloc, 1>;
+        assert((doTest<T, U>(UA_None, UA_None,
+                             std::forward<TT>(t), std::forward<UU>(u))));
+    }
+    {
+        using T = UsesAllocatorV2<Alloc, 1>;
+        using U = UsesAllocatorV3<Alloc, 1>;
+        assert((doTest<T, U>(UA_None, UA_None,
+                             std::forward<TT>(t), std::forward<UU>(u))));
+    }
+    {
+        using T = UsesAllocatorV3<Alloc, 1>;
+        using U = NotUsesAllocator<Alloc, 1>;
+        assert((doTest<T, U>(UA_None, UA_None,
+                             std::forward<TT>(t), std::forward<UU>(u))));
+    }
+}
+
 int main()
 {
     using ERT = std::experimental::erased_type;
@@ -102,14 +131,14 @@ int main()
         int x = 42;
         int y = 42;
         test_pmr_uses_allocator<ERT>(x, std::move(y));
-        test_pmr_uses_allocator<PMR>(x, std::move(y));
+        test_pmr_not_uses_allocator<PMR>(x, std::move(y));
         test_pmr_uses_allocator<PMA>(x, std::move(y));
     }
     {
         int x = 42;
         const int y = 42;
         test_pmr_uses_allocator<ERT>(std::move(x), y);
-        test_pmr_uses_allocator<PMR>(std::move(x), y);
+        test_pmr_not_uses_allocator<PMR>(std::move(x), y);
         test_pmr_uses_allocator<PMA>(std::move(x), y);
     }
 }

Modified: libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp?rev=333384&r1=333383&r2=333384&view=diff
==============================================================================
--- libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp (original)
+++ libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp Mon May 28 17:08:47 2018
@@ -83,6 +83,35 @@ void test_pmr_uses_allocator(std::tuple<
     }
 }
 
+template <class Alloc, class ...TTypes, class ...UTypes>
+void test_pmr_not_uses_allocator(std::tuple<TTypes...> ttuple, std::tuple<UTypes...> utuple)
+{
+    {
+        using T = NotUsesAllocator<Alloc, sizeof...(TTypes)>;
+        using U = NotUsesAllocator<Alloc, sizeof...(UTypes)>;
+        assert((doTest<T, U>(UA_None, UA_None,
+                             std::move(ttuple), std::move(utuple))));
+    }
+    {
+        using T = UsesAllocatorV1<Alloc, sizeof...(TTypes)>;
+        using U = UsesAllocatorV2<Alloc, sizeof...(UTypes)>;
+        assert((doTest<T, U>(UA_None, UA_None,
+                             std::move(ttuple), std::move(utuple))));
+    }
+    {
+        using T = UsesAllocatorV2<Alloc, sizeof...(TTypes)>;
+        using U = UsesAllocatorV3<Alloc, sizeof...(UTypes)>;
+        assert((doTest<T, U>(UA_None, UA_None,
+                             std::move(ttuple), std::move(utuple))));
+    }
+    {
+        using T = UsesAllocatorV3<Alloc, sizeof...(TTypes)>;
+        using U = NotUsesAllocator<Alloc, sizeof...(UTypes)>;
+        assert((doTest<T, U>(UA_None, UA_None,
+                             std::move(ttuple), std::move(utuple))));
+    }
+}
+
 int main()
 {
     using ERT = std::experimental::erased_type;
@@ -91,7 +120,7 @@ int main()
     {
         std::tuple<> t1;
         test_pmr_uses_allocator<ERT>(t1, t1);
-        test_pmr_uses_allocator<PMR>(t1, t1);
+        test_pmr_not_uses_allocator<PMR>(t1, t1);
         test_pmr_uses_allocator<PMA>(t1, t1);
     }
     {
@@ -99,8 +128,8 @@ int main()
         std::tuple<> t2;
         test_pmr_uses_allocator<ERT>(t1, t2);
         test_pmr_uses_allocator<ERT>(t2, t1);
-        test_pmr_uses_allocator<PMR>(t1, t2);
-        test_pmr_uses_allocator<PMR>(t2, t1);
+        test_pmr_not_uses_allocator<PMR>(t1, t2);
+        test_pmr_not_uses_allocator<PMR>(t2, t1);
         test_pmr_uses_allocator<PMA>(t1, t2);
         test_pmr_uses_allocator<PMA>(t2, t1);
     }
@@ -111,8 +140,8 @@ int main()
         std::tuple<int&, double&&> t2(x, std::move(dx));
         test_pmr_uses_allocator<ERT>(           t1, std::move(t2));
         test_pmr_uses_allocator<ERT>(std::move(t2),            t1);
-        test_pmr_uses_allocator<PMR>(           t1, std::move(t2));
-        test_pmr_uses_allocator<PMR>(std::move(t2),            t1);
+        test_pmr_not_uses_allocator<PMR>(           t1, std::move(t2));
+        test_pmr_not_uses_allocator<PMR>(std::move(t2),            t1);
         test_pmr_uses_allocator<PMA>(           t1, std::move(t2));
         test_pmr_uses_allocator<PMA>(std::move(t2),            t1);
     }
@@ -126,8 +155,8 @@ int main()
         std::tuple<int&, double&&, const char*> t2(x, std::move(dx), s);
         test_pmr_uses_allocator<ERT>(           t1, std::move(t2));
         test_pmr_uses_allocator<ERT>(std::move(t2),            t1);
-        test_pmr_uses_allocator<PMR>(           t1, std::move(t2));
-        test_pmr_uses_allocator<PMR>(std::move(t2),            t1);
+        test_pmr_not_uses_allocator<PMR>(           t1, std::move(t2));
+        test_pmr_not_uses_allocator<PMR>(std::move(t2),            t1);
         test_pmr_uses_allocator<PMA>(           t1, std::move(t2));
         test_pmr_uses_allocator<PMA>(std::move(t2),            t1);
     }

Added: libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair_evil.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair_evil.pass.cpp?rev=333384&view=auto
==============================================================================
--- libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair_evil.pass.cpp (added)
+++ libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair_evil.pass.cpp Mon May 28 17:08:47 2018
@@ -0,0 +1,141 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <memory_resource>
+
+// template <class T> class polymorphic_allocator
+
+// template <class U1, class U2, class ...Args1, class ...Args2>
+// void polymorphic_allocator<T>::construct(pair<U1, U2>*, piecewise_construct_t
+//                                          tuple<Args1...>, tuple<Args2...>)
+
+#include <experimental/memory_resource>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+#include <cassert>
+#include <cstdlib>
+
+#include "test_macros.h"
+
+namespace ex = std::experimental::pmr;
+
+template <class T>
+struct EvilAlloc {
+    explicit EvilAlloc() : inner_(ex::null_memory_resource()) {}
+
+    EvilAlloc(ex::polymorphic_allocator<T> & a) : inner_(a) {}
+    EvilAlloc(ex::polymorphic_allocator<T> && a) : inner_(a) {}
+    EvilAlloc(ex::polymorphic_allocator<T> const & a) = delete;
+    EvilAlloc(ex::polymorphic_allocator<T> const && a) = delete;
+
+    using value_type = T;
+    template <class U> EvilAlloc(EvilAlloc<U> const & rhs) : inner_(rhs.inner_) {}
+
+    ex::polymorphic_allocator<T> inner_;
+};
+
+struct WidgetV0 {
+    WidgetV0(int v) : value_(v) {}
+
+    bool holds(int v, const ex::polymorphic_allocator<char>&) const {
+        return value_ == v;
+    }
+private:
+    int value_;
+};
+
+struct WidgetV1 {
+    using allocator_type = EvilAlloc<char>;
+
+    WidgetV1(int v) : value_(v), alloc_() {}
+    WidgetV1(std::allocator_arg_t, EvilAlloc<char> a, int v) : value_(v), alloc_(a) {}
+
+    bool holds(int v, const ex::polymorphic_allocator<char>& a) const {
+        return value_ == v && alloc_.inner_ == a;
+    }
+private:
+    int value_;
+    EvilAlloc<char> alloc_;
+};
+
+struct WidgetV2 {
+    using allocator_type = EvilAlloc<char>;
+
+    WidgetV2(int v) : value_(v), alloc_() {}
+    WidgetV2(int v, EvilAlloc<char> a) : value_(v), alloc_(a) {}
+
+    bool holds(int v, ex::polymorphic_allocator<char> a) const {
+        return value_ == v && alloc_.inner_ == a;
+    }
+private:
+    int value_;
+    EvilAlloc<char> alloc_;
+};
+
+struct WidgetV3 {
+    using allocator_type = EvilAlloc<char>;
+
+    WidgetV3(int v) : value_(v), alloc_() {}
+    WidgetV3(std::allocator_arg_t, EvilAlloc<char> a, int v) : value_(v), alloc_(a) {}
+    WidgetV3(int v, EvilAlloc<char> a) : value_(v), alloc_(a) {}
+
+    bool holds(int v, ex::polymorphic_allocator<char> a) const {
+        return value_ == v && alloc_.inner_ == a;
+    }
+private:
+    int value_;
+    EvilAlloc<char> alloc_;
+};
+
+static_assert(std::uses_allocator<WidgetV1, EvilAlloc<char>>::value, "");
+static_assert(std::uses_allocator<WidgetV2, EvilAlloc<char>>::value, "");
+static_assert(std::uses_allocator<WidgetV3, EvilAlloc<char>>::value, "");
+static_assert(std::uses_allocator<WidgetV1, ex::polymorphic_allocator<char>>::value, "");
+static_assert(std::uses_allocator<WidgetV2, ex::polymorphic_allocator<char>>::value, "");
+static_assert(std::uses_allocator<WidgetV3, ex::polymorphic_allocator<char>>::value, "");
+
+template<class W1, class W2>
+void test_evil()
+{
+    using PMA = ex::polymorphic_allocator<char>;
+    PMA pma(ex::new_delete_resource());
+    {
+        using Pair = std::pair<W1, W2>;
+        void *where = std::malloc(sizeof (Pair));
+        Pair *p = (Pair *)where;
+        pma.construct(p, std::piecewise_construct, std::make_tuple(42), std::make_tuple(42));
+        assert(p->first.holds(42, pma));
+        assert(p->second.holds(42, pma));
+        pma.destroy(p);
+        std::free(where);
+    }
+}
+
+int main()
+{
+    test_evil<WidgetV0, WidgetV0>();
+    test_evil<WidgetV0, WidgetV1>();
+    test_evil<WidgetV0, WidgetV2>();
+    test_evil<WidgetV0, WidgetV3>();
+    test_evil<WidgetV1, WidgetV0>();
+    test_evil<WidgetV1, WidgetV1>();
+    test_evil<WidgetV1, WidgetV2>();
+    test_evil<WidgetV1, WidgetV3>();
+    test_evil<WidgetV2, WidgetV0>();
+    test_evil<WidgetV2, WidgetV1>();
+    test_evil<WidgetV2, WidgetV2>();
+    test_evil<WidgetV2, WidgetV3>();
+    test_evil<WidgetV3, WidgetV0>();
+    test_evil<WidgetV3, WidgetV1>();
+    test_evil<WidgetV3, WidgetV2>();
+    test_evil<WidgetV3, WidgetV3>();
+}

Modified: libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_types.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_types.pass.cpp?rev=333384&r1=333383&r2=333384&view=diff
==============================================================================
--- libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_types.pass.cpp (original)
+++ libcxx/trunk/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_types.pass.cpp Mon May 28 17:08:47 2018
@@ -126,6 +126,39 @@ void test_pmr_uses_alloc(Args&&... args)
     }
 }
 
+template <class Alloc, class ...Args>
+void test_pmr_not_uses_alloc(Args&&... args)
+{
+    TestResource R(12435);
+    ex::memory_resource* M = &R;
+    {
+        // NotUsesAllocator provides valid signatures for each uses-allocator
+        // construction but does not supply the required allocator_type typedef.
+        // Test that we can call these constructors manually without
+        // polymorphic_allocator interfering.
+        using T = NotUsesAllocator<Alloc, sizeof...(Args)>;
+        assert(doTestUsesAllocV0<T>(std::forward<Args>(args)...));
+        assert((doTestUsesAllocV1<T>(M, std::forward<Args>(args)...)));
+        assert((doTestUsesAllocV2<T>(M, std::forward<Args>(args)...)));
+    }
+    {
+        // Test T(std::allocator_arg_t, Alloc const&, Args...) construction
+        using T = UsesAllocatorV1<Alloc, sizeof...(Args)>;
+        assert((doTest<T>(UA_None, std::forward<Args>(args)...)));
+    }
+    {
+        // Test T(Args..., Alloc const&) construction
+        using T = UsesAllocatorV2<Alloc, sizeof...(Args)>;
+        assert((doTest<T>(UA_None, std::forward<Args>(args)...)));
+    }
+    {
+        // Test that T(std::allocator_arg_t, Alloc const&, Args...) construction
+        // is preferred when T(Args..., Alloc const&) is also available.
+        using T = UsesAllocatorV3<Alloc, sizeof...(Args)>;
+        assert((doTest<T>(UA_None, std::forward<Args>(args)...)));
+    }
+}
+
 // Test that polymorphic_allocator does not prevent us from manually
 // doing non-pmr uses-allocator construction.
 template <class Alloc, class AllocObj, class ...Args>
@@ -167,16 +200,16 @@ int main()
     const int cvalue = 43;
     {
         test_pmr_uses_alloc<ET>();
-        test_pmr_uses_alloc<PMR>();
+        test_pmr_not_uses_alloc<PMR>();
         test_pmr_uses_alloc<PMA>();
         test_pmr_uses_alloc<ET>(value);
-        test_pmr_uses_alloc<PMR>(value);
+        test_pmr_not_uses_alloc<PMR>(value);
         test_pmr_uses_alloc<PMA>(value);
         test_pmr_uses_alloc<ET>(cvalue);
-        test_pmr_uses_alloc<PMR>(cvalue);
+        test_pmr_not_uses_alloc<PMR>(cvalue);
         test_pmr_uses_alloc<PMA>(cvalue);
         test_pmr_uses_alloc<ET>(cvalue, std::move(value));
-        test_pmr_uses_alloc<PMR>(cvalue, std::move(value));
+        test_pmr_not_uses_alloc<PMR>(cvalue, std::move(value));
         test_pmr_uses_alloc<PMA>(cvalue, std::move(value));
     }
     {

Modified: libcxx/trunk/test/support/test_memory_resource.hpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/support/test_memory_resource.hpp?rev=333384&r1=333383&r2=333384&view=diff
==============================================================================
--- libcxx/trunk/test/support/test_memory_resource.hpp (original)
+++ libcxx/trunk/test/support/test_memory_resource.hpp Mon May 28 17:08:47 2018
@@ -28,7 +28,7 @@
 // because it can't include <experimental/memory_resource>
 template <>
 struct TransformErasedTypeAlloc<std::experimental::erased_type> {
-  using type = std::experimental::pmr::memory_resource*;
+  using type = std::experimental::pmr::polymorphic_allocator<int>;
 };
 
 template <class ProviderT, int = 0>




More information about the cfe-commits mailing list