Add <experimental/memory_resource>

Reviewers: mclow.lists, EricWF

Subscribers: cfe-commits

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

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@268829 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/exception b/include/exception
index 686e4ec..537e4e3 100644
--- a/include/exception
+++ b/include/exception
@@ -80,6 +80,10 @@
 #include <__config>
 #include <cstddef>
 #include <type_traits>
+#if defined(_LIBCPP_HAS_NO_EXCEPTIONS)
+#include <cstdio>
+#include <cstdlib>
+#endif
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
@@ -251,4 +255,19 @@
 
 }  // std
 
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class _Exception>
+_LIBCPP_INLINE_VISIBILITY
+inline void __libcpp_throw(_Exception const& __e) {
+#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
+    throw __e;
+#else
+    _VSTD::fprintf(stderr, "%s\n", __e.what());
+    _VSTD::abort();
+#endif
+}
+
+_LIBCPP_END_NAMESPACE_STD
+
 #endif  // _LIBCPP_EXCEPTION
diff --git a/include/experimental/__config b/include/experimental/__config
index f64a3a9..046a70a 100644
--- a/include/experimental/__config
+++ b/include/experimental/__config
@@ -25,6 +25,10 @@
 #define _LIBCPP_END_NAMESPACE_LFTS  } } }
 #define _VSTD_LFTS _VSTD_EXPERIMENTAL::fundamentals_v1
 
+#define _LIBCPP_BEGIN_NAMESPACE_LFTS_PMR _LIBCPP_BEGIN_NAMESPACE_LFTS namespace pmr {
+#define _LIBCPP_END_NAMESPACE_LFTS_PMR _LIBCPP_END_NAMESPACE_LFTS }
+#define _VSTD_LFTS_PMR _VSTD_LFTS::pmr
+
 #define _LIBCPP_BEGIN_NAMESPACE_CHRONO_LFTS _LIBCPP_BEGIN_NAMESPACE_STD        \
   namespace chrono { namespace experimental { inline namespace fundamentals_v1 {
 #define _LIBCPP_END_NAMESPACE_CHRONO_LFTS _LIBCPP_END_NAMESPACE_STD } } }
diff --git a/include/experimental/__memory b/include/experimental/__memory
new file mode 100644
index 0000000..229fea6
--- /dev/null
+++ b/include/experimental/__memory
@@ -0,0 +1,90 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+//                     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.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP_EXPERIMENTAL___MEMORY
+#define _LIBCPP_EXPERIMENTAL___MEMORY
+
+#include <experimental/__config>
+#include <experimental/utility> // for erased_type
+#include <__functional_base>
+#include <type_traits>
+
+_LIBCPP_BEGIN_NAMESPACE_LFTS
+
+template <
+    class _Tp, class _Alloc
+  , bool = uses_allocator<_Tp, _Alloc>::value
+  , bool = __has_allocator_type<_Tp>::value
+  >
+struct __lfts_uses_allocator : public false_type {};
+
+template <class _Tp, class _Alloc>
+struct __lfts_uses_allocator<_Tp, _Alloc, false, false> : public false_type {};
+
+template <class _Tp, class _Alloc, bool HasAlloc>
+struct __lfts_uses_allocator<_Tp, _Alloc, true, HasAlloc> : public true_type {};
+
+template <class _Tp, class _Alloc>
+struct __lfts_uses_allocator<_Tp, _Alloc, false, true>
+  : public integral_constant<bool
+    , is_convertible<_Alloc, typename _Tp::allocator_type>::value
+      || is_same<erased_type, typename _Tp::allocator_type>::value
+    >
+{};
+
+template <bool _UsesAlloc, class _Tp, class _Alloc, class ..._Args>
+struct __lfts_uses_alloc_ctor_imp
+{
+    static const int value = 0;
+};
+
+template <class _Tp, class _Alloc, class ..._Args>
+struct __lfts_uses_alloc_ctor_imp<true, _Tp, _Alloc, _Args...>
+{
+    static const bool __ic_first
+        = is_constructible<_Tp, allocator_arg_t, _Alloc, _Args...>::value;
+
+    static const bool __ic_second =
+        conditional<
+            __ic_first,
+            false_type,
+            is_constructible<_Tp, _Args..., _Alloc>
+        >::type::value;
+
+    static_assert(__ic_first || __ic_second,
+                  "Request for uses allocator construction is ill-formed");
+
+    static const int value = __ic_first ? 1 : 2;
+};
+
+template <class _Tp, class _Alloc, class ..._Args>
+struct __lfts_uses_alloc_ctor
+  : integral_constant<int,
+        __lfts_uses_alloc_ctor_imp<
+            __lfts_uses_allocator<_Tp, _Alloc>::value
+          , _Tp, _Alloc, _Args...
+        >::value
+    >
+{};
+
+template <class _Tp, class _Alloc, class ..._Args>
+inline _LIBCPP_INLINE_VISIBILITY
+void __lfts_user_alloc_construct(
+    _Tp * __store, const _Alloc & __a, _Args &&... __args)
+{
+    _VSTD::__user_alloc_construct_impl(
+        typename __lfts_uses_alloc_ctor<_Tp, _Alloc, _Args...>::type()
+       , __store, __a, _VSTD::forward<_Args>(__args)...
+       );
+}
+
+_LIBCPP_END_NAMESPACE_LFTS
+
+#endif /* _LIBCPP_EXPERIMENTAL___MEMORY */
diff --git a/include/experimental/memory_resource b/include/experimental/memory_resource
new file mode 100644
index 0000000..f54ef0b
--- /dev/null
+++ b/include/experimental/memory_resource
@@ -0,0 +1,422 @@
+// -*- C++ -*-
+//===------------------------ memory_resource -----------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP_EXPERIMENTAL_MEMORY_RESOURCE
+#define _LIBCPP_EXPERIMENTAL_MEMORY_RESOURCE
+
+/**
+    experimental/memory_resource synopsis
+
+// C++1y
+
+namespace std {
+namespace experimental {
+inline namespace fundamentals_v1 {
+namespace pmr {
+
+  class memory_resource;
+
+  bool operator==(const memory_resource& a,
+                  const memory_resource& b) noexcept;
+  bool operator!=(const memory_resource& a,
+                  const memory_resource& b) noexcept;
+
+  template <class Tp> class polymorphic_allocator;
+
+  template <class T1, class T2>
+  bool operator==(const polymorphic_allocator<T1>& a,
+                  const polymorphic_allocator<T2>& b) noexcept;
+  template <class T1, class T2>
+  bool operator!=(const polymorphic_allocator<T1>& a,
+                  const polymorphic_allocator<T2>& b) noexcept;
+
+  // The name resource_adaptor_imp is for exposition only.
+  template <class Allocator> class resource_adaptor_imp;
+
+  template <class Allocator>
+    using resource_adaptor = resource_adaptor_imp<
+      allocator_traits<Allocator>::rebind_alloc<char>>;
+
+  // Global memory resources
+  memory_resource* new_delete_resource() noexcept;
+  memory_resource* null_memory_resource() noexcept;
+
+  // The default memory resource
+  memory_resource* set_default_resource(memory_resource* r) noexcept;
+  memory_resource* get_default_resource() noexcept;
+
+  // Standard memory resources
+  struct pool_options;
+  class synchronized_pool_resource;
+  class unsynchronized_pool_resource;
+  class monotonic_buffer_resource;
+
+} // namespace pmr
+} // namespace fundamentals_v1
+} // namespace experimental
+} // namespace std
+
+ */
+
+#include <experimental/__config>
+#include <experimental/__memory>
+#include <limits>
+#include <memory>
+#include <new>
+#include <stdexcept>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+#include <cstddef>
+#include <cstdlib>
+#include <__debug>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_LFTS_PMR
+
+// Round __s up to next multiple of __a.
+inline _LIBCPP_INLINE_VISIBILITY
+size_t __aligned_allocation_size(size_t __s, size_t __a) _NOEXCEPT
+{
+    _LIBCPP_ASSERT(__s + __a > __s, "aligned allocation size overflows");
+    return (__s + __a - 1) & ~(__a - 1);
+}
+
+// 8.5, memory.resource
+class _LIBCPP_TYPE_VIS_ONLY memory_resource
+{
+    static const size_t __max_align = alignof(max_align_t);
+
+// 8.5.2, memory.resource.public
+public:
+    virtual ~memory_resource() = default;
+
+    _LIBCPP_INLINE_VISIBILITY
+    void* allocate(size_t __bytes, size_t __align = __max_align)
+        { return do_allocate(__bytes, __align); }
+
+    _LIBCPP_INLINE_VISIBILITY
+    void deallocate(void * __p, size_t __bytes, size_t __align = __max_align)
+        { do_deallocate(__p, __bytes, __align); }
+
+    _LIBCPP_INLINE_VISIBILITY
+    bool is_equal(memory_resource const & __other) const _NOEXCEPT
+        { return do_is_equal(__other); }
+
+// 8.5.3, memory.resource.priv
+protected:
+    virtual void* do_allocate(size_t, size_t) = 0;
+    virtual void do_deallocate(void*, size_t, size_t) = 0;
+    virtual bool do_is_equal(memory_resource const &) const _NOEXCEPT = 0;
+};
+
+// 8.5.4, memory.resource.eq
+inline _LIBCPP_INLINE_VISIBILITY
+bool operator==(memory_resource const & __lhs,
+                memory_resource const & __rhs) _NOEXCEPT
+{
+    return &__lhs == &__rhs || __lhs.is_equal(__rhs);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+bool operator!=(memory_resource const & __lhs,
+                memory_resource const & __rhs) _NOEXCEPT
+{
+    return !(__lhs == __rhs);
+}
+
+_LIBCPP_FUNC_VIS
+memory_resource * new_delete_resource() _NOEXCEPT;
+
+_LIBCPP_FUNC_VIS
+memory_resource * null_memory_resource() _NOEXCEPT;
+
+_LIBCPP_FUNC_VIS
+memory_resource * get_default_resource() _NOEXCEPT;
+
+_LIBCPP_FUNC_VIS
+memory_resource * set_default_resource(memory_resource * __new_res) _NOEXCEPT;
+
+// 8.6, memory.polymorphic.allocator.class
+
+// 8.6.1, memory.polymorphic.allocator.overview
+template <class _ValueType>
+class _LIBCPP_TYPE_VIS_ONLY polymorphic_allocator
+{
+public:
+    typedef _ValueType value_type;
+
+    // 8.6.2, memory.polymorphic.allocator.ctor
+    _LIBCPP_INLINE_VISIBILITY
+    polymorphic_allocator() _NOEXCEPT
+      : __res_(_VSTD_LFTS_PMR::get_default_resource())
+    {}
+
+    _LIBCPP_INLINE_VISIBILITY
+    polymorphic_allocator(memory_resource * __r) _NOEXCEPT
+      : __res_(__r)
+    {}
+
+    polymorphic_allocator(polymorphic_allocator const &) = default;
+
+    template <class _Tp>
+    _LIBCPP_INLINE_VISIBILITY
+    polymorphic_allocator(polymorphic_allocator<_Tp> const & __other) _NOEXCEPT
+      : __res_(__other.resource())
+    {}
+
+    polymorphic_allocator &
+    operator=(polymorphic_allocator const &) = default;
+
+    // 8.6.3, memory.polymorphic.allocator.mem
+    _LIBCPP_INLINE_VISIBILITY
+    _ValueType* allocate(size_t __n) {
+        if (__n > max_size()) {
+            __libcpp_throw(length_error(
+                "std::experimental::pmr::polymorphic_allocator<T>::allocate(size_t n)"
+                " 'n' exceeds maximum supported size"));
+        }
+        return static_cast<_ValueType*>(
+            __res_->allocate(__n * sizeof(_ValueType), alignof(_ValueType))
+        );
+    }
+
+    _LIBCPP_INLINE_VISIBILITY
+    void deallocate(_ValueType * __p, size_t __n) _NOEXCEPT {
+        _LIBCPP_ASSERT(__n <= max_size(),
+                       "deallocate called for size which exceeds max_size()");
+        __res_->deallocate(__p, __n * sizeof(_ValueType), alignof(_ValueType));
+    }
+
+    template <class _Tp, class ..._Ts>
+    _LIBCPP_INLINE_VISIBILITY
+    void construct(_Tp* __p, _Ts &&... __args)
+    {
+        _VSTD_LFTS::__lfts_user_alloc_construct(
+            __p, resource(), _VSTD::forward<_Ts>(__args)...
+          );
+    }
+
+    template <class _T1, class _T2, class ..._Args1, class ..._Args2>
+    _LIBCPP_INLINE_VISIBILITY
+    void construct(pair<_T1, _T2>* __p, piecewise_construct_t,
+                   tuple<_Args1...> __x, tuple<_Args2...> __y)
+    {
+        ::new ((void*)__p) pair<_T1, _T2>(piecewise_construct
+          , __transform_tuple(
+              typename __lfts_uses_alloc_ctor<
+                  _T1, memory_resource*, _Args1...
+              >::type()
+            , _VSTD::move(__x)
+            , typename __make_tuple_indices<sizeof...(_Args1)>::type{}
+          )
+          , __transform_tuple(
+              typename __lfts_uses_alloc_ctor<
+                  _T2, memory_resource*, _Args2...
+              >::type()
+            , _VSTD::move(__y)
+            , typename __make_tuple_indices<sizeof...(_Args2)>::type{}
+          )
+        );
+    }
+
+    template <class _T1, class _T2>
+    _LIBCPP_INLINE_VISIBILITY
+    void construct(pair<_T1, _T2>* __p) {
+        construct(__p, piecewise_construct, tuple<>(), tuple<>());
+    }
+
+    template <class _T1, class _T2, class _Up, class _Vp>
+    _LIBCPP_INLINE_VISIBILITY
+    void construct(pair<_T1, _T2> * __p, _Up && __u, _Vp && __v) {
+        construct(__p, piecewise_construct
+          , _VSTD::forward_as_tuple(_VSTD::forward<_Up>(__u))
+          , _VSTD::forward_as_tuple(_VSTD::forward<_Vp>(__v)));
+    }
+
+    template <class _T1, class _T2, class _U1, class _U2>
+    _LIBCPP_INLINE_VISIBILITY
+    void construct(pair<_T1, _T2> * __p, pair<_U1, _U2> const & __pr) {
+        construct(__p, piecewise_construct
+            , _VSTD::forward_as_tuple(__pr.first)
+            , _VSTD::forward_as_tuple(__pr.second));
+    }
+
+    template <class _T1, class _T2, class _U1, class _U2>
+    _LIBCPP_INLINE_VISIBILITY
+    void construct(pair<_T1, _T2> * __p, pair<_U1, _U2> && __pr){
+        construct(__p, piecewise_construct
+            , _VSTD::forward_as_tuple(_VSTD::forward<_U1>(__pr.first))
+            , _VSTD::forward_as_tuple(_VSTD::forward<_U2>(__pr.second)));
+    }
+
+    template <class _Tp>
+    _LIBCPP_INLINE_VISIBILITY
+    void destroy(_Tp * __p) _NOEXCEPT
+        { __p->~_Tp(); }
+
+    _LIBCPP_INLINE_VISIBILITY
+    size_t max_size() const _NOEXCEPT
+        { return numeric_limits<size_t>::max() / sizeof(value_type); }
+
+    _LIBCPP_INLINE_VISIBILITY
+    polymorphic_allocator
+    select_on_container_copy_construction() const _NOEXCEPT
+        { return polymorphic_allocator(); }
+
+    _LIBCPP_INLINE_VISIBILITY
+    memory_resource * resource() const _NOEXCEPT
+        { return __res_; }
+
+private:
+    template <class ..._Args, size_t ..._Idx>
+    _LIBCPP_INLINE_VISIBILITY
+    tuple<_Args&&...>
+    __transform_tuple(integral_constant<int, 0>, tuple<_Args...>&& __t,
+                      __tuple_indices<_Idx...>) const
+    {
+        return _VSTD::forward_as_tuple(_VSTD::get<_Idx>(_VSTD::move(__t))...);
+    }
+
+    template <class ..._Args, size_t ..._Idx>
+    _LIBCPP_INLINE_VISIBILITY
+    tuple<allocator_arg_t const&, memory_resource*, _Args&&...>
+    __transform_tuple(integral_constant<int, 1>, tuple<_Args...> && __t,
+                      __tuple_indices<_Idx...>) const
+    {
+        using _Tup = tuple<allocator_arg_t const&, memory_resource*, _Args&&...>;
+        return _Tup(allocator_arg, resource(),
+                    _VSTD::get<_Idx>(_VSTD::move(__t))...);
+    }
+
+    template <class ..._Args, size_t ..._Idx>
+    _LIBCPP_INLINE_VISIBILITY
+    tuple<_Args&&..., memory_resource*>
+    __transform_tuple(integral_constant<int, 2>, tuple<_Args...> && __t,
+                      __tuple_indices<_Idx...>) const
+    {
+        using _Tup = tuple<_Args&&..., memory_resource*>;
+        return _Tup(_VSTD::get<_Idx>(_VSTD::move(__t))..., resource());
+    }
+
+    memory_resource * __res_;
+};
+
+// 8.6.4, memory.polymorphic.allocator.eq
+
+template <class _Tp, class _Up>
+inline _LIBCPP_INLINE_VISIBILITY
+bool operator==(polymorphic_allocator<_Tp> const & __lhs,
+                polymorphic_allocator<_Up> const & __rhs) _NOEXCEPT
+{
+    return *__lhs.resource() == *__rhs.resource();
+}
+
+template <class _Tp, class _Up>
+inline _LIBCPP_INLINE_VISIBILITY
+bool operator!=(polymorphic_allocator<_Tp> const & __lhs,
+                polymorphic_allocator<_Up> const & __rhs) _NOEXCEPT
+{
+    return !(__lhs == __rhs);
+}
+
+// 8.7, memory.resource.adaptor
+
+// 8.7.1, memory.resource.adaptor.overview
+template <class _CharAlloc>
+class _LIBCPP_TYPE_VIS_ONLY __resource_adaptor_imp
+  : public memory_resource
+{
+    using _CTraits = allocator_traits<_CharAlloc>;
+    static_assert(is_same<typename _CTraits::value_type, char>::value
+               && is_same<typename _CTraits::pointer, char*>::value
+               && is_same<typename _CTraits::void_pointer, void*>::value, "");
+
+    static const size_t _MaxAlign = alignof(max_align_t);
+
+    using _Alloc = typename _CTraits::template rebind_alloc<
+            typename aligned_storage<_MaxAlign, _MaxAlign>::type
+        >;
+
+    using _ValueType = typename _Alloc::value_type;
+
+    _Alloc __alloc_;
+
+public:
+    typedef _CharAlloc allocator_type;
+
+    __resource_adaptor_imp() = default;
+    __resource_adaptor_imp(__resource_adaptor_imp const &) = default;
+    __resource_adaptor_imp(__resource_adaptor_imp &&) = default;
+
+    // 8.7.2, memory.resource.adaptor.ctor
+
+    _LIBCPP_INLINE_VISIBILITY
+    explicit __resource_adaptor_imp(allocator_type const & __a)
+      : __alloc_(__a)
+    {}
+
+    _LIBCPP_INLINE_VISIBILITY
+    explicit __resource_adaptor_imp(allocator_type && __a)
+      : __alloc_(_VSTD::move(__a))
+    {}
+
+    __resource_adaptor_imp &
+    operator=(__resource_adaptor_imp const &) = default;
+
+    _LIBCPP_INLINE_VISIBILITY
+    allocator_type get_allocator() const
+    { return __alloc_; }
+
+// 8.7.3, memory.resource.adaptor.mem
+protected:
+    virtual void * do_allocate(size_t __bytes, size_t)
+    {
+        if (__bytes > __max_size()) {
+            __libcpp_throw(length_error(
+                "std::experimental::pmr::resource_adaptor<T>::do_allocate(size_t bytes, size_t align)"
+                " 'bytes' exceeds maximum supported size"));
+        }
+        size_t __s = __aligned_allocation_size(__bytes, _MaxAlign) / _MaxAlign;
+        return __alloc_.allocate(__s);
+    }
+
+    virtual void do_deallocate(void * __p, size_t __bytes, size_t)
+    {
+        _LIBCPP_ASSERT(__bytes <= __max_size(),
+            "do_deallocate called for size which exceeds the maximum allocation size");
+        size_t __s = __aligned_allocation_size(__bytes, _MaxAlign) / _MaxAlign;
+        __alloc_.deallocate((_ValueType*)__p, __s);
+    }
+
+    virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT {
+        __resource_adaptor_imp const * __p
+          = dynamic_cast<__resource_adaptor_imp const *>(&__other);
+        return __p  ? __alloc_ == __p->__alloc_ : false;
+    }
+
+private:
+    _LIBCPP_INLINE_VISIBILITY
+    size_t __max_size() const _NOEXCEPT {
+        return numeric_limits<size_t>::max() - _MaxAlign;
+    }
+};
+
+template <class _Alloc>
+using resource_adaptor = __resource_adaptor_imp<
+    typename allocator_traits<_Alloc>::template rebind_alloc<char>
+  >;
+
+_LIBCPP_END_NAMESPACE_LFTS_PMR
+
+#endif /* _LIBCPP_EXPERIMENTAL_MEMORY_RESOURCE */
diff --git a/src/experimental/memory_resource.cpp b/src/experimental/memory_resource.cpp
new file mode 100644
index 0000000..fe338e0
--- /dev/null
+++ b/src/experimental/memory_resource.cpp
@@ -0,0 +1,129 @@
+//===------------------------ memory_resource.cpp -------------------------===//
+//
+//                     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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "experimental/memory_resource"
+
+#ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER
+#include "atomic"
+#else
+#include "mutex"
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_LFTS_PMR
+
+// memory_resource
+
+//memory_resource::~memory_resource() {}
+
+// new_delete_resource()
+
+class _LIBCPP_TYPE_VIS_ONLY __new_delete_memory_resource_imp
+    : public memory_resource
+{
+public:
+    ~__new_delete_memory_resource_imp() = default;
+
+protected:
+    virtual void* do_allocate(size_t __size, size_t __align)
+        { return __allocate(__size); }
+
+    virtual void do_deallocate(void * __p, size_t, size_t)
+        { __deallocate(__p); }
+
+    virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT
+        { return &__other == this; }
+};
+
+// null_memory_resource()
+
+class _LIBCPP_TYPE_VIS_ONLY __null_memory_resource_imp
+    : public memory_resource
+{
+public:
+    ~__null_memory_resource_imp() = default;
+
+protected:
+    virtual void* do_allocate(size_t, size_t) {
+#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
+        throw std::bad_alloc();
+#else
+        abort();
+#endif
+    }
+    virtual void do_deallocate(void *, size_t, size_t) {}
+    virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT
+    { return &__other == this; }
+};
+
+union ResourceInitHelper {
+  struct {
+    __new_delete_memory_resource_imp new_delete_res;
+    __null_memory_resource_imp       null_res;
+  } resources;
+  char dummy;
+  _LIBCPP_CONSTEXPR_AFTER_CXX11 ResourceInitHelper() : resources() {}
+  ~ResourceInitHelper() {}
+};
+// When compiled in C++14 this initialization should be a constant expression.
+// Only in C++11 is "init_priority" needed to ensure initialization order.
+ResourceInitHelper res_init __attribute__((init_priority (101)));
+
+memory_resource * new_delete_resource() _NOEXCEPT {
+    return &res_init.resources.new_delete_res;
+}
+
+memory_resource * null_memory_resource() _NOEXCEPT {
+    return &res_init.resources.null_res;
+}
+
+// default_memory_resource()
+
+static memory_resource *
+__default_memory_resource(bool set = false, memory_resource * new_res = nullptr) _NOEXCEPT
+{
+#ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER
+    static atomic<memory_resource*> __res =
+        ATOMIC_VAR_INIT(&res_init.resources.new_delete_res);
+    if (set) {
+        new_res = new_res ? new_res : new_delete_resource();
+        // TODO: Can a weaker ordering be used?
+        return _VSTD::atomic_exchange_explicit(
+            &__res, new_res, memory_order::memory_order_acq_rel);
+    }
+    else {
+        return _VSTD::atomic_load_explicit(
+            &__res, memory_order::memory_order_acquire);
+    }
+#else
+    static memory_resource * res = &res_init.resources.new_delete_res;
+    static mutex res_lock;
+    if (set) {
+        new_res = new_res ? new_res : new_delete_resource();
+        lock_guard<mutex> guard(res_lock);
+        memory_resource * old_res = res;
+        res = new_res;
+        return old_res;
+    } else {
+        lock_guard<mutex> guard(res_lock);
+        return res;
+    }
+#endif
+}
+
+memory_resource * get_default_resource() _NOEXCEPT
+{
+    return __default_memory_resource();
+}
+
+memory_resource * set_default_resource(memory_resource * __new_res) _NOEXCEPT
+{
+    return __default_memory_resource(true, __new_res);
+}
+
+_LIBCPP_END_NAMESPACE_LFTS_PMR
\ No newline at end of file
diff --git a/test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp b/test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp
new file mode 100644
index 0000000..83b3041
--- /dev/null
+++ b/test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp
@@ -0,0 +1,178 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// template <class T> class polymorphic_allocator
+
+// template <class U1, class U2, class ...Args1, class ...Args2>
+// void polymorphic_allocator<T>::construct(pair<T1, T2>*, piecewise_construct_t
+//                                          tuple<Args1...> x, tuple<Args2...>)
+
+// The stardard specifiers a tranformation to uses-allocator construction as
+// follows:
+//  - If uses_allocator_v<T1,memory_resource*> is false and
+//      is_constructible_v<T,Args1...> is true, then xprime is x.
+//  - Otherwise, if uses_allocator_v<T1,memory_resource*> is true and
+//      is_constructible_v<T1,allocator_arg_t,memory_resource*,Args1...> is true,
+//      then xprime is
+//      tuple_cat(make_tuple(allocator_arg, this->resource()), std::move(x)).
+//  - Otherwise, if uses_allocator_v<T1,memory_resource*> is true and
+//      is_constructible_v<T1,Args1...,memory_resource*> is true, then xprime is
+//      tuple_cat(std::move(x), make_tuple(this->resource())).
+//  - Otherwise the program is ill formed.
+//
+// The use of "xprime = tuple_cat(..., std::move(x), ...)" causes all of the
+// objects in 'x' to be copied into 'xprime'. If 'x' contains any types which
+// are stored by value this causes an unessary copy to occur. To prevent this
+//  libc++ changes this call into
+// "xprime = forward_as_tuple(..., std::get<Idx>(std::move(x))..., ...)".
+// 'xprime' contains references to the values in 'x' instead of copying them.
+
+// This test checks the number of copies incurred to the elements in
+// 'tuple<Args1...>' and 'tuple<Args2...>'.
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <utility>
+#include <tuple>
+#include <cassert>
+#include <cstdlib>
+#include "test_memory_resource.hpp"
+
+namespace ex = std::experimental::pmr;
+
+template <class T>
+struct TestHarness {
+    TestResource R;
+    ex::memory_resource * M = &R;
+    ex::polymorphic_allocator<T> A = M;
+    bool constructed = false;
+    T * ptr;
+
+    TestHarness() : ptr(A.allocate(1)) {}
+
+    template <class ...Args>
+    void construct(Args&&... args) {
+        A.construct(ptr, std::forward<Args>(args)...);
+        constructed = true;
+    }
+
+    ~TestHarness() {
+        if (constructed) A.destroy(ptr);
+        A.deallocate(ptr, 1);
+    }
+};
+
+struct CountCopies {
+  int count;
+  CountCopies() : count(0) {}
+  CountCopies(CountCopies const& o) : count(o.count + 1) {}
+};
+
+struct CountCopiesAllocV1 {
+  typedef ex::memory_resource* allocator_type;
+  allocator_type 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(CountCopiesAllocV1 const& o) : count(o.count + 1) {}
+};
+
+
+struct CountCopiesAllocV2 {
+  typedef ex::memory_resource* allocator_type;
+  allocator_type alloc;
+  int count;
+  CountCopiesAllocV2() : alloc(nullptr), count(0) {}
+  CountCopiesAllocV2(CountCopiesAllocV2 const& o, allocator_type const& a)
+    : alloc(a), count(o.count + 1)
+  { }
+
+  CountCopiesAllocV2(CountCopiesAllocV2 const& o) : count(o.count + 1) {}
+};
+
+
+int main()
+{
+    using PMR = ex::memory_resource*;
+    using PMA = ex::polymorphic_allocator<char>;
+
+    {
+        using T = CountCopies;
+        using U = CountCopiesAllocV1;
+        using P = std::pair<T, U>;
+        using TH = TestHarness<P>;
+
+        std::tuple<T> t1;
+        std::tuple<U> t2;
+
+        TestHarness<P> h;
+        h.construct(std::piecewise_construct, t1, t2);
+        P const& p = *h.ptr;
+        assert(p.first.count == 2);
+        assert(p.second.count == 2);
+        assert(p.second.alloc == h.M);
+    }
+    {
+        using T = CountCopiesAllocV1;
+        using U = CountCopiesAllocV2;
+        using P = std::pair<T, U>;
+        using TH = TestHarness<P>;
+
+        std::tuple<T> t1;
+        std::tuple<U> t2;
+
+        TestHarness<P> h;
+        h.construct(std::piecewise_construct, std::move(t1), std::move(t2));
+        P const& p = *h.ptr;
+        assert(p.first.count == 2);
+        assert(p.first.alloc == h.M);
+        assert(p.second.count == 2);
+        assert(p.second.alloc == h.M);
+    }
+    {
+        using T = CountCopiesAllocV2;
+        using U = CountCopiesAllocV1;
+        using P = std::pair<T, U>;
+        using TH = TestHarness<P>;
+
+        std::tuple<T> t1;
+        std::tuple<U> t2;
+
+        TestHarness<P> h;
+        h.construct(std::piecewise_construct, std::move(t1), std::move(t2));
+        P const& p = *h.ptr;
+        assert(p.first.count == 2);
+        assert(p.first.alloc == h.M);
+        assert(p.second.count == 2);
+        assert(p.second.alloc == h.M);
+    }
+    {
+        using T = CountCopiesAllocV2;
+        using U = CountCopies;
+        using P = std::pair<T, U>;
+        using TH = TestHarness<P>;
+
+        std::tuple<T> t1;
+        std::tuple<U> t2;
+
+        TestHarness<P> h;
+        h.construct(std::piecewise_construct, t1, t2);
+        P const& p = *h.ptr;
+        assert(p.first.count == 2);
+        assert(p.first.alloc == h.M);
+        assert(p.second.count == 2);
+    }
+}
diff --git a/test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/db_deallocate.pass.cpp b/test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/db_deallocate.pass.cpp
new file mode 100644
index 0000000..020133f
--- /dev/null
+++ b/test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/db_deallocate.pass.cpp
@@ -0,0 +1,42 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// template <class T> class polymorphic_allocator
+
+// T* polymorphic_allocator<T>::deallocate(T*, size_t size)
+
+int AssertCount = 0;
+
+#define _LIBCPP_ASSERT(x, m) ((x) ? (void)0 : (void)::AssertCount++)
+#define _LIBCPP_DEBUG 0
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+namespace ex = std::experimental::pmr;
+
+int main()
+{
+    using Alloc = ex::polymorphic_allocator<int>;
+    using Traits = std::allocator_traits<Alloc>;
+    NullResource R;
+    Alloc a(&R);
+    const std::size_t maxSize = Traits::max_size(a);
+
+    a.deallocate(nullptr, maxSize);
+    assert(AssertCount == 0);
+    a.deallocate(nullptr, maxSize + 1);
+    assert(AssertCount == 1);
+}
diff --git a/test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/max_size.pass.cpp b/test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/max_size.pass.cpp
new file mode 100644
index 0000000..001c689
--- /dev/null
+++ b/test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/max_size.pass.cpp
@@ -0,0 +1,64 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// template <class T> class polymorphic_allocator
+
+// EXTENSION
+// std::size_t polymorphic_allocator<T>::max_size() const noexcept
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+namespace ex = std::experimental::pmr;
+
+template <std::size_t S>
+std::size_t getMaxSize() {
+    using T = typename std::aligned_storage<S>::type;
+    static_assert(sizeof(T) == S, "Required for test");
+    return ex::polymorphic_allocator<T>{}.max_size();
+}
+
+template <std::size_t S, std::size_t A>
+std::size_t getMaxSize() {
+    using T = typename std::aligned_storage<S, A>::type;
+    static_assert(sizeof(T) == S, "Required for test");
+    return ex::polymorphic_allocator<T>{}.max_size();
+}
+
+int main()
+{
+    {
+        using Alloc = ex::polymorphic_allocator<int>;
+        using Traits = std::allocator_traits<Alloc>;
+        const Alloc a;
+        static_assert(std::is_same<decltype(a.max_size()), Traits::size_type>::value, "");
+        static_assert(noexcept(a.max_size()), "");
+    }
+    {
+        constexpr std::size_t Max = std::numeric_limits<std::size_t>::max();
+        assert(getMaxSize<1>()    == Max);
+        assert(getMaxSize<2>()    == Max / 2);
+        assert(getMaxSize<4>()    == Max / 4);
+        assert(getMaxSize<8>()    == Max / 8);
+        assert(getMaxSize<16>()   == Max / 16);
+        assert(getMaxSize<32>()   == Max / 32);
+        assert(getMaxSize<64>()   == Max / 64);
+        assert(getMaxSize<1024>() == Max / 1024);
+
+        assert((getMaxSize<6,  2>() == Max / 6));
+        assert((getMaxSize<12, 4>() == Max / 12));
+    }
+}
diff --git a/test/libcxx/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/db_deallocate.pass.cpp b/test/libcxx/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/db_deallocate.pass.cpp
new file mode 100644
index 0000000..ccb9b71
--- /dev/null
+++ b/test/libcxx/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/db_deallocate.pass.cpp
@@ -0,0 +1,45 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// template <class T> class polymorphic_allocator
+
+// T* polymorphic_allocator<T>::deallocate(T*, size_t size)
+
+int AssertCount = 0;
+
+#define _LIBCPP_ASSERT(x, m) ((x) ? (void)0 : (void)::AssertCount++)
+#define _LIBCPP_DEBUG 0
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+namespace ex = std::experimental::pmr;
+
+int main()
+{
+    using Alloc = NullAllocator<char>;
+    using R = ex::resource_adaptor<Alloc>;
+    AllocController P;
+    ex::resource_adaptor<Alloc> r(Alloc{P});
+    ex::memory_resource & m1 = r;
+
+    std::size_t maxSize = std::numeric_limits<std::size_t>::max()
+                            - alignof(std::max_align_t);
+
+    m1.deallocate(nullptr, maxSize);
+    assert(AssertCount == 0);
+    m1.deallocate(nullptr, maxSize + 1);
+    assert(AssertCount >= 1);
+}
diff --git a/test/libcxx/experimental/memory/memory.resource.global/global_memory_resource_lifetime.pass.cpp b/test/libcxx/experimental/memory/memory.resource.global/global_memory_resource_lifetime.pass.cpp
new file mode 100644
index 0000000..6385ee9
--- /dev/null
+++ b/test/libcxx/experimental/memory/memory.resource.global/global_memory_resource_lifetime.pass.cpp
@@ -0,0 +1,60 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// memory_resource * new_delete_resource()
+
+// The lifetime of the value returned by 'new_delete_resource()' should
+// never end, even very late into program termination. This test constructs
+// attempts to use 'new_delete_resource()' very late in program termination
+// to detect lifetime issues.
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+namespace ex = std::experimental::pmr;
+
+struct POSType {
+  ex::memory_resource* res = nullptr;
+  void* ptr = nullptr;
+  int n = 0;
+  POSType() {}
+  POSType(ex::memory_resource* r, void* p, int s) : res(r), ptr(p), n(s) {}
+  ~POSType() {
+      if (ptr) {
+          if (!res) res = ex::get_default_resource();
+          res->deallocate(ptr, n);
+      }
+  }
+};
+
+void swap(POSType & L, POSType & R) {
+    std::swap(L.res, R.res);
+    std::swap(L.ptr, R.ptr);
+    std::swap(L.n, R.n);
+}
+
+POSType constructed_before_resources;
+POSType constructed_before_resources2;
+
+// Constructs resources
+ex::memory_resource* resource = ex::get_default_resource();
+
+POSType constructed_after_resources(resource, resource->allocate(1024), 1024);
+POSType constructed_after_resources2(nullptr, resource->allocate(1024), 1024);
+
+int main()
+{
+    swap(constructed_after_resources, constructed_before_resources);
+    swap(constructed_before_resources2, constructed_after_resources2);
+}
diff --git a/test/libcxx/experimental/memory/memory.resource.global/new_delete_resource_lifetime.pass.cpp b/test/libcxx/experimental/memory/memory.resource.global/new_delete_resource_lifetime.pass.cpp
new file mode 100644
index 0000000..abdfda8
--- /dev/null
+++ b/test/libcxx/experimental/memory/memory.resource.global/new_delete_resource_lifetime.pass.cpp
@@ -0,0 +1,52 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// memory_resource * new_delete_resource()
+
+// The lifetime of the value returned by 'new_delete_resource()' should
+// never end, even very late into program termination. This test constructs
+// attempts to use 'new_delete_resource()' very late in program termination
+// to detect lifetime issues.
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+namespace ex = std::experimental::pmr;
+
+struct POSType {
+  ex::memory_resource* res = nullptr;
+  void* ptr = nullptr;
+  int n = 0;
+  POSType() {res = ex::new_delete_resource(); ptr = res->allocate(42); n = 42; }
+  POSType(ex::memory_resource* r, void* p, int s) : res(r), ptr(p), n(s) {}
+  ~POSType() { if (ptr) res->deallocate(ptr, n); }
+};
+
+void swap(POSType & L, POSType & R) {
+    std::swap(L.res, R.res);
+    std::swap(L.ptr, R.ptr);
+    std::swap(L.n, R.n);
+}
+
+POSType constructed_before_resources;
+
+// Constructs resources
+ex::memory_resource* resource = ex::new_delete_resource();
+
+POSType constructed_after_resources(resource, resource->allocate(1024), 1024);
+
+int main()
+{
+    swap(constructed_after_resources, constructed_before_resources);
+}
diff --git a/test/libcxx/experimental/memory/memory.resource.synop/version.pass.cpp b/test/libcxx/experimental/memory/memory.resource.synop/version.pass.cpp
new file mode 100644
index 0000000..d05575e
--- /dev/null
+++ b/test/libcxx/experimental/memory/memory.resource.synop/version.pass.cpp
@@ -0,0 +1,22 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+#include <experimental/memory_resource>
+
+#ifndef _LIBCPP_VERSION
+#error _LIBCPP_VERSION not defined
+#endif
+
+int main()
+{
+}
diff --git a/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/assign.pass.cpp b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/assign.pass.cpp
new file mode 100644
index 0000000..77ffb51
--- /dev/null
+++ b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/assign.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.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// template <class T> class polymorphic_allocator
+
+// polymorphic_allocator operator=(polymorphic_allocator const &) = delete
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+namespace ex = std::experimental::pmr;
+
+int main()
+{
+    typedef ex::polymorphic_allocator<void> T;
+    static_assert(std::is_copy_assignable<T>::value, "");
+    static_assert(std::is_move_assignable<T>::value, "");
+}
diff --git a/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/copy.pass.cpp b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/copy.pass.cpp
new file mode 100644
index 0000000..ba3710d
--- /dev/null
+++ b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/copy.pass.cpp
@@ -0,0 +1,48 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// template <class T> class polymorphic_allocator
+
+// polymorphic_allocator<T>::polymorphic_allocator(polymorphic_allocator const &);
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+namespace ex = std::experimental::pmr;
+
+int main()
+{
+    typedef ex::polymorphic_allocator<void> A1;
+    {
+        static_assert(
+            std::is_copy_constructible<A1>::value, ""
+          );
+        static_assert(
+            std::is_move_constructible<A1>::value, ""
+          );
+    }
+    // copy
+    {
+        A1 const a((ex::memory_resource*)42);
+        A1 const a2(a);
+        assert(a.resource() == a2.resource());
+    }
+    // move
+    {
+        A1 a((ex::memory_resource*)42);
+        A1 a2(std::move(a));
+        assert(a.resource() == a2.resource());
+        assert(a2.resource() == (ex::memory_resource*)42);
+    }
+}
diff --git a/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/default.pass.cpp b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/default.pass.cpp
new file mode 100644
index 0000000..1007556
--- /dev/null
+++ b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/default.pass.cpp
@@ -0,0 +1,48 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// template <class T> class polymorphic_allocator
+
+// polymorphic_allocator<T>::polymorphic_allocator() noexcept
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+namespace ex = std::experimental::pmr;
+
+int main()
+{
+    {
+        static_assert(
+            std::is_nothrow_default_constructible<ex::polymorphic_allocator<void>>::value
+          , "Must me nothrow default constructible"
+          );
+    }
+    {
+        // test that the allocator gets its resource from get_default_resource
+        TestResource R1(42);
+        ex::set_default_resource(&R1);
+
+        typedef ex::polymorphic_allocator<void> A;
+        A const a;
+        assert(a.resource() == &R1);
+
+        ex::set_default_resource(nullptr);
+        A const a2;
+        assert(a.resource() == &R1);
+        assert(a2.resource() == ex::new_delete_resource());
+    }
+}
diff --git a/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/memory_resource_convert.pass.cpp b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/memory_resource_convert.pass.cpp
new file mode 100644
index 0000000..19d9646
--- /dev/null
+++ b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/memory_resource_convert.pass.cpp
@@ -0,0 +1,45 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// template <class T> class polymorphic_allocator
+
+// polymorphic_allocator<T>::polymorphic_allocator(memory_resource *)
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+namespace ex = std::experimental::pmr;
+
+int main()
+{
+    {
+        typedef ex::polymorphic_allocator<void> A;
+        static_assert(
+            std::is_convertible<decltype(nullptr), A>::value
+          , "Must be convertible"
+          );
+        static_assert(
+            std::is_convertible<ex::memory_resource *, A>::value
+          , "Must be convertible"
+          );
+    }
+    {
+        typedef ex::polymorphic_allocator<void> A;
+        TestResource R;
+        A const a(&R);
+        assert(a.resource() == &R);
+    }
+}
diff --git a/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/other_alloc.pass.cpp b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/other_alloc.pass.cpp
new file mode 100644
index 0000000..aadfbcc
--- /dev/null
+++ b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/other_alloc.pass.cpp
@@ -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.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// template <class T> class polymorphic_allocator
+
+// template <class U>
+// polymorphic_allocator<T>::polymorphic_allocator(polymorphic_allocator<U> const &);
+
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+namespace ex = std::experimental::pmr;
+
+int main()
+{
+    typedef ex::polymorphic_allocator<void> A1;
+    typedef ex::polymorphic_allocator<char> A2;
+    { // Test that the conversion is implicit and noexcept.
+        static_assert(
+            std::is_convertible<A1 const &, A2>::value, ""
+          );
+        static_assert(
+            std::is_convertible<A2 const &, A1>::value, ""
+          );
+        static_assert(
+            std::is_nothrow_constructible<A1, A2 const &>::value, ""
+          );
+        static_assert(
+            std::is_nothrow_constructible<A2, A1 const &>::value, ""
+          );
+    }
+    // copy other type
+    {
+        A1 const a((ex::memory_resource*)42);
+        A2 const a2(a);
+        assert(a.resource() == a2.resource());
+        assert(a2.resource() == (ex::memory_resource*)42);
+    }
+    {
+        A1 a((ex::memory_resource*)42);
+        A2 const a2(std::move(a));
+        assert(a.resource() == a2.resource());
+        assert(a2.resource() == (ex::memory_resource*)42);
+    }
+}
diff --git a/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.eq/equal.pass.cpp b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.eq/equal.pass.cpp
new file mode 100644
index 0000000..d5a3d01
--- /dev/null
+++ b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.eq/equal.pass.cpp
@@ -0,0 +1,133 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// template <class T> class polymorphic_allocator;
+
+// template <class T, class U>
+// bool operator==(
+//      polymorphic_allocator<T> const &
+//    , polymorphic_allocator<U> const &) noexcept
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+namespace ex = std::experimental::pmr;
+
+int main()
+{
+    typedef ex::polymorphic_allocator<void> A1;
+    typedef ex::polymorphic_allocator<int> A2;
+    // check return types
+    {
+        A1 const a1;
+        A2 const a2;
+        static_assert(std::is_same<decltype(a1 == a2), bool>::value, "");
+        static_assert(noexcept(a1 == a2), "");
+    }
+    // equal same type (different resource)
+    {
+        TestResource d1(1);
+        TestResource d2(1);
+        A1 const a1(&d1);
+        A1 const a2(&d2);
+
+        assert(a1 == a2);
+        assert(d1.checkIsEqualCalledEq(1));
+        assert(d2.checkIsEqualCalledEq(0));
+
+        d1.reset();
+
+        assert(a2 == a1);
+        assert(d1.checkIsEqualCalledEq(0));
+        assert(d2.checkIsEqualCalledEq(1));
+    }
+    // equal same type (same resource)
+    {
+        TestResource d1;
+        A1 const a1(&d1);
+        A1 const a2(&d1);
+
+        assert(a1 == a2);
+        assert(d1.checkIsEqualCalledEq(0));
+
+        assert(a2 == a1);
+        assert(d1.checkIsEqualCalledEq(0));
+    }
+    // equal different type (different resource)
+    {
+        TestResource d1(42);
+        TestResource d2(42);
+        A1 const a1(&d1);
+        A2 const a2(&d2);
+
+        assert(a1 == a2);
+        assert(d1.checkIsEqualCalledEq(1));
+        assert(d2.checkIsEqualCalledEq(0));
+
+        assert(a2 == a1);
+        assert(d1.checkIsEqualCalledEq(1));
+        assert(d2.checkIsEqualCalledEq(1));
+
+    }
+    // equal different type (same resource)
+    {
+        TestResource d1(42);
+        A1 const a1(&d1);
+        A2 const a2(&d1);
+
+        assert(a1 == a2);
+        assert(d1.checkIsEqualCalledEq(0));
+
+        assert(a2 == a1);
+        assert(d1.checkIsEqualCalledEq(0));
+
+    }
+    // not equal same type
+    {
+        TestResource d1(1);
+        TestResource d2(2);
+        A1 const a1(&d1);
+        A1 const a2(&d2);
+
+        assert(!(a1 == a2));
+        assert(d1.checkIsEqualCalledEq(1));
+        assert(d2.checkIsEqualCalledEq(0));
+
+        d1.reset();
+
+        assert(!(a2 == a1));
+        assert(d1.checkIsEqualCalledEq(0));
+        assert(d2.checkIsEqualCalledEq(1));
+
+    }
+    // not equal different types
+    {
+        TestResource  d1;
+        TestResource1 d2;
+        A1 const a1(&d1);
+        A2 const a2(&d2);
+
+        assert(!(a1 == a2));
+        assert(d1.checkIsEqualCalledEq(1));
+        assert(d2.checkIsEqualCalledEq(0));
+
+        d1.reset();
+
+        assert(!(a2 == a1));
+        assert(d1.checkIsEqualCalledEq(0));
+        assert(d2.checkIsEqualCalledEq(1));
+    }
+}
diff --git a/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.eq/not_equal.pass.cpp b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.eq/not_equal.pass.cpp
new file mode 100644
index 0000000..e837576
--- /dev/null
+++ b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.eq/not_equal.pass.cpp
@@ -0,0 +1,104 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// template <class T> class polymorphic_allocator;
+
+// template <class T>
+// bool operator!=(
+//      polymorphic_allocator<T> const &
+//    , polymorphic_allocator<T> const &) noexcept
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+namespace ex = std::experimental::pmr;
+
+int main()
+{
+    typedef ex::polymorphic_allocator<void> A1;
+    typedef ex::polymorphic_allocator<int> A2;
+    // check return types
+    {
+        A1 const a1;
+        A2 const a2;
+        static_assert(std::is_same<decltype(a1 != a2), bool>::value, "");
+        static_assert(noexcept(a1 != a2), "");
+    }
+    // not equal same type (different resource)
+    {
+        TestResource d1(1);
+        TestResource d2(2);
+        A1 const a1(&d1);
+        A1 const a2(&d2);
+
+        assert(a1 != a2);
+        assert(d1.checkIsEqualCalledEq(1));
+        assert(d2.checkIsEqualCalledEq(0));
+
+        d1.reset();
+
+        assert(a2 != a1);
+        assert(d1.checkIsEqualCalledEq(0));
+        assert(d2.checkIsEqualCalledEq(1));
+    }
+    // equal same type (same resource)
+    {
+        TestResource d1;
+        A1 const a1(&d1);
+        A1 const a2(&d1);
+
+        assert(!(a1 != a2));
+        assert(d1.checkIsEqualCalledEq(0));
+
+        assert(!(a2 != a1));
+        assert(d1.checkIsEqualCalledEq(0));
+    }
+    // equal same type
+    {
+        TestResource d1(1);
+        TestResource d2(1);
+        A1 const a1(&d1);
+        A1 const a2(&d2);
+
+        assert(!(a1 != a2));
+        assert(d1.checkIsEqualCalledEq(1));
+        assert(d2.checkIsEqualCalledEq(0));
+
+        d1.reset();
+
+        assert(!(a2 != a1));
+        assert(d1.checkIsEqualCalledEq(0));
+        assert(d2.checkIsEqualCalledEq(1));
+
+    }
+    // not equal different types
+    {
+        TestResource  d1;
+        TestResource1 d2;
+        A1 const a1(&d1);
+        A2 const a2(&d2);
+
+        assert(a1 != a2);
+        assert(d1.checkIsEqualCalledEq(1));
+        assert(d2.checkIsEqualCalledEq(0));
+
+        d1.reset();
+
+        assert(a2 != a1);
+        assert(d1.checkIsEqualCalledEq(0));
+        assert(d2.checkIsEqualCalledEq(1));
+    }
+}
diff --git a/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/allocate.pass.cpp b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/allocate.pass.cpp
new file mode 100644
index 0000000..1a6ce87
--- /dev/null
+++ b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/allocate.pass.cpp
@@ -0,0 +1,111 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// template <class T> class polymorphic_allocator
+
+// T* polymorphic_allocator<T>::allocate(size_t n)
+
+#include <experimental/memory_resource>
+#include <limits>
+#include <memory>
+#include <exception>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_memory_resource.hpp"
+
+namespace ex = std::experimental::pmr;
+
+template <size_t S, size_t Align>
+void testForSizeAndAlign() {
+    using T = typename std::aligned_storage<S, Align>::type;
+    TestResource R;
+    ex::polymorphic_allocator<T> a(&R);
+
+    for (int N = 1; N <= 5; ++N) {
+        auto ret = a.allocate(N);
+        assert(R.checkAlloc(ret, N * sizeof(T), alignof(T)));
+
+        a.deallocate(ret, N);
+        R.reset();
+    }
+}
+
+#ifndef TEST_HAS_NO_EXCEPTIONS
+template <size_t S>
+void testAllocForSizeThrows() {
+    using T = typename std::aligned_storage<S>::type;
+    using Alloc = ex::polymorphic_allocator<T>;
+    using Traits = std::allocator_traits<Alloc>;
+    NullResource R;
+    Alloc a(&R);
+
+    // Test that allocating exactly the max size does not throw.
+    size_t maxSize = Traits::max_size(a);
+    try {
+        a.allocate(maxSize);
+    } catch (...) {
+        assert(false);
+    }
+
+    size_t sizeTypeMax = std::numeric_limits<std::size_t>::max();
+    if (maxSize != sizeTypeMax)
+    {
+        // Test that allocating size_t(~0) throws bad alloc.
+        try {
+            a.allocate(sizeTypeMax);
+            assert(false);
+        } catch (std::exception const&) {
+        }
+
+        // Test that allocating even one more than the max size does throw.
+        size_t overSize = maxSize + 1;
+        try {
+            a.allocate(overSize);
+            assert(false);
+        } catch (std::exception const&) {
+        }
+    }
+}
+#endif // TEST_HAS_NO_EXCEPTIONS
+
+int main()
+{
+    {
+        ex::polymorphic_allocator<int> a;
+        static_assert(std::is_same<decltype(a.allocate(0)), int*>::value, "");
+        static_assert(!noexcept(a.allocate(0)), "");
+    }
+    {
+        constexpr std::size_t MA = alignof(std::max_align_t);
+        testForSizeAndAlign<1, 1>();
+        testForSizeAndAlign<1, 2>();
+        testForSizeAndAlign<1, MA>();
+        testForSizeAndAlign<2, 2>();
+        testForSizeAndAlign<73, alignof(void*)>();
+        testForSizeAndAlign<73, MA>();
+        testForSizeAndAlign<13, MA>();
+    }
+#ifndef TEST_HAS_NO_EXCEPTIONS
+    {
+        testAllocForSizeThrows<1>();
+        testAllocForSizeThrows<2>();
+        testAllocForSizeThrows<4>();
+        testAllocForSizeThrows<8>();
+        testAllocForSizeThrows<16>();
+        testAllocForSizeThrows<73>();
+        testAllocForSizeThrows<13>();
+    }
+#endif
+}
diff --git a/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair.pass.cpp b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair.pass.cpp
new file mode 100644
index 0000000..9ce0404
--- /dev/null
+++ b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair.pass.cpp
@@ -0,0 +1,52 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// template <class T> class polymorphic_allocator
+
+// template <class U1, class U2>
+// void polymorphic_allocator<T>::construct(pair<U1, U2>*)
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <utility>
+#include <tuple>
+#include <cassert>
+#include <cstdlib>
+#include "uses_alloc_types.hpp"
+
+namespace ex = std::experimental::pmr;
+
+int constructed = 0;
+
+struct default_constructible
+{
+    default_constructible() : x(42)  { ++constructed; }
+    int x{0};
+};
+
+int main()
+{
+    // pair<default_constructible, default_constructible> as T()
+    {
+        typedef default_constructible T;
+        typedef std::pair<T, T> P;
+        typedef ex::polymorphic_allocator<void> A;
+        P * ptr = (P*)std::malloc(sizeof(P));
+        A a;
+        a.construct(ptr);
+        assert(constructed == 2);
+        assert(ptr->first.x == 42);
+        assert(ptr->second.x == 42);
+        std::free(ptr);
+    }
+}
diff --git a/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_const_lvalue_pair.pass.cpp b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_const_lvalue_pair.pass.cpp
new file mode 100644
index 0000000..6fbe1a3
--- /dev/null
+++ b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_const_lvalue_pair.pass.cpp
@@ -0,0 +1,111 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// template <class T> class polymorphic_allocator
+
+// template <class P1, class P2, class U1, class U2>
+// void polymorphic_allocator<T>::construct(pair<P1, P2>*, pair<U1, U2> const&)
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <utility>
+#include <tuple>
+#include <cassert>
+#include <cstdlib>
+#include "uses_alloc_types.hpp"
+
+namespace ex = std::experimental::pmr;
+
+
+template <class UA1, class UA2, class TT, class UU>
+bool doTest(UsesAllocatorType TExpect, UsesAllocatorType UExpect,
+            std::pair<TT, UU> const& p)
+{
+    using P = std::pair<UA1, UA2>;
+    TestResource R;
+    ex::memory_resource * M = &R;
+    ex::polymorphic_allocator<P> A(M);
+    P * ptr = (P*)std::malloc(sizeof(P));
+    P * ptr2 =  (P*)std::malloc(sizeof(P));
+
+    // UNDER TEST //
+    A.construct(ptr, p);
+
+    A.construct(ptr2, std::piecewise_construct,
+                std::forward_as_tuple(p.first),
+                std::forward_as_tuple(p.second));
+    // ------- //
+
+    bool tres = checkConstruct<decltype((p.first))>(ptr->first, TExpect, M) &&
+                checkConstructionEquiv(ptr->first, ptr2->first);
+
+    bool ures = checkConstruct<decltype((p.second))>(ptr->second, UExpect, M) &&
+                checkConstructionEquiv(ptr->second, ptr2->second);
+
+    A.destroy(ptr);
+    std::free(ptr);
+    A.destroy(ptr2);
+    std::free(ptr2);
+    return tres && ures;
+
+}
+
+template <class Alloc, class TT, class UU>
+void test_pmr_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_AllocArg, UA_AllocLast, p)));
+    }
+    {
+        using T = UsesAllocatorV2<Alloc, 1>;
+        using U = UsesAllocatorV3<Alloc, 1>;
+        assert((doTest<T, U>(UA_AllocLast, UA_AllocArg, p)));
+    }
+    {
+        using T = UsesAllocatorV3<Alloc, 1>;
+        using U = NotUsesAllocator<Alloc, 1>;
+        assert((doTest<T, U>(UA_AllocArg, UA_None, p)));
+    }
+}
+template <class Tp>
+struct Print;
+
+int main()
+{
+    using ERT = std::experimental::erased_type;
+    using PMR = ex::memory_resource*;
+    using PMA = ex::polymorphic_allocator<char>;
+    {
+        int x = 42;
+        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_uses_allocator<PMA>(p);
+    }
+    {
+        int x = 42;
+        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_uses_allocator<PMA>(p);
+    }
+}
diff --git a/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_rvalue.pass.cpp b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_rvalue.pass.cpp
new file mode 100644
index 0000000..67d16bd
--- /dev/null
+++ b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_rvalue.pass.cpp
@@ -0,0 +1,108 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// template <class T> class polymorphic_allocator
+
+// template <class P1, class P2, class U1, class U2>
+// void polymorphic_allocator<T>::construct(pair<P1, P2>*, pair<U1, U2> &&)
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <utility>
+#include <tuple>
+#include <cassert>
+#include <cstdlib>
+#include "uses_alloc_types.hpp"
+
+namespace ex = std::experimental::pmr;
+
+
+
+template <class UA1, class UA2, class TT, class UU>
+bool doTest(UsesAllocatorType TExpect, UsesAllocatorType UExpect,
+            std::pair<TT, UU>&& p)
+{
+    using P = std::pair<UA1, UA2>;
+    TestResource R;
+    ex::memory_resource * M = &R;
+    ex::polymorphic_allocator<P> A(M);
+    P * ptr  = A.allocate(2);
+    P * ptr2 = ptr + 1;
+
+    // UNDER TEST //
+    A.construct(ptr, std::move(p));
+
+    A.construct(ptr2, std::piecewise_construct,
+                std::forward_as_tuple(std::forward<TT>(p.first)),
+                std::forward_as_tuple(std::forward<UU>(p.second)));
+    // ------- //
+
+    bool tres = checkConstruct<TT&&>(ptr->first, TExpect, M) &&
+                checkConstructionEquiv(ptr->first, ptr2->first);
+
+    bool ures = checkConstruct<UU&&>(ptr->second, UExpect, M) &&
+                checkConstructionEquiv(ptr->second, ptr2->second);
+
+    A.destroy(ptr);
+    A.destroy(ptr2);
+    A.deallocate(ptr, 2);
+    return tres && ures;
+}
+
+template <class Alloc, class TT, class UU>
+void test_pmr_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_AllocArg, UA_AllocLast, std::move(p))));
+    }
+    {
+        using T = UsesAllocatorV2<Alloc, 1>;
+        using U = UsesAllocatorV3<Alloc, 1>;
+        assert((doTest<T, U>(UA_AllocLast, UA_AllocArg, std::move(p))));
+    }
+    {
+        using T = UsesAllocatorV3<Alloc, 1>;
+        using U = NotUsesAllocator<Alloc, 1>;
+        assert((doTest<T, U>(UA_AllocArg, UA_None, std::move(p))));
+    }
+}
+
+int main()
+{
+    using ERT = std::experimental::erased_type;
+    using PMR = ex::memory_resource*;
+    using PMA = ex::polymorphic_allocator<char>;
+    {
+        int x = 42;
+        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_uses_allocator<PMA>(std::move(p));
+    }
+    {
+        int x = 42;
+        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_uses_allocator<PMA>(std::move(p));
+    }
+}
diff --git a/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_values.pass.cpp b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_values.pass.cpp
new file mode 100644
index 0000000..d4c8e03
--- /dev/null
+++ b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_values.pass.cpp
@@ -0,0 +1,109 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// template <class T> class polymorphic_allocator
+
+// template <class P1, class P2, class U1, class U2>
+// void polymorphic_allocator<T>::construct(pair<P1, P2>*, U1&&, U2&&)
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <utility>
+#include <tuple>
+#include <cassert>
+#include <cstdlib>
+#include "uses_alloc_types.hpp"
+
+namespace ex = std::experimental::pmr;
+
+
+template <class UA1, class UA2, class TT, class UU>
+bool doTest(UsesAllocatorType TExpect, UsesAllocatorType UExpect,
+            TT&& t, UU&& u)
+{
+    using P = std::pair<UA1, UA2>;
+    TestResource R;
+    ex::memory_resource * M = &R;
+    ex::polymorphic_allocator<P> A(M);
+    P * ptr = (P*)std::malloc(sizeof(P));
+    P * ptr2 = (P*)std::malloc(sizeof(P));
+
+    // UNDER TEST //
+    A.construct(ptr, std::forward<TT>(t), std::forward<UU>(u));
+    A.construct(ptr2, std::piecewise_construct,
+                      std::forward_as_tuple(std::forward<TT>(t)),
+                      std::forward_as_tuple(std::forward<UU>(u)));
+    // ------- //
+
+    bool tres = checkConstruct<TT&&>(ptr->first, TExpect, M) &&
+                checkConstructionEquiv(ptr->first, ptr2->first);
+
+    bool ures = checkConstruct<UU&&>(ptr->second, UExpect, M) &&
+                checkConstructionEquiv(ptr->second, ptr2->second);
+
+    A.destroy(ptr);
+    A.destroy(ptr2);
+    std::free(ptr);
+    std::free(ptr2);
+    return tres && ures;
+}
+
+template <class Alloc, class TT, class UU>
+void test_pmr_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_AllocArg, UA_AllocLast,
+                             std::forward<TT>(t), std::forward<UU>(u))));
+    }
+    {
+        using T = UsesAllocatorV2<Alloc, 1>;
+        using U = UsesAllocatorV3<Alloc, 1>;
+        assert((doTest<T, U>(UA_AllocLast, UA_AllocArg,
+                             std::forward<TT>(t), std::forward<UU>(u))));
+    }
+    {
+        using T = UsesAllocatorV3<Alloc, 1>;
+        using U = NotUsesAllocator<Alloc, 1>;
+        assert((doTest<T, U>(UA_AllocArg, UA_None,
+                             std::forward<TT>(t), std::forward<UU>(u))));
+    }
+}
+
+int main()
+{
+    using ERT = std::experimental::erased_type;
+    using PMR = ex::memory_resource*;
+    using PMA = ex::polymorphic_allocator<char>;
+    {
+        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_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_uses_allocator<PMA>(std::move(x), y);
+    }
+}
diff --git a/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp
new file mode 100644
index 0000000..206bfb0
--- /dev/null
+++ b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp
@@ -0,0 +1,129 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/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 <type_traits>
+#include <utility>
+#include <tuple>
+#include <cassert>
+#include <cstdlib>
+#include "uses_alloc_types.hpp"
+#include "test_allocator.h"
+
+namespace ex = std::experimental::pmr;
+
+template <class T, class U, class ...TTuple, class ...UTuple>
+bool doTest(UsesAllocatorType TExpect, UsesAllocatorType UExpect,
+            std::tuple<TTuple...> ttuple, std::tuple<UTuple...> utuple)
+{
+    using P = std::pair<T, U>;
+    TestResource R;
+    ex::memory_resource * M = &R;
+    ex::polymorphic_allocator<P> A(M);
+    P * ptr = A.allocate(1);
+
+    // UNDER TEST //
+    A.construct(ptr, std::piecewise_construct, std::move(ttuple), std::move(utuple));
+    // ------- //
+    bool tres = checkConstruct<TTuple&&...>(ptr->first, TExpect, M);
+    bool ures = checkConstruct<UTuple&&...>(ptr->second, UExpect, M);
+
+    A.destroy(ptr);
+    A.deallocate(ptr, 1);
+    return tres && ures;
+}
+
+template <class Alloc, class ...TTypes, class ...UTypes>
+void test_pmr_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_AllocArg, UA_AllocLast,
+                             std::move(ttuple), std::move(utuple))));
+    }
+    {
+        using T = UsesAllocatorV2<Alloc, sizeof...(TTypes)>;
+        using U = UsesAllocatorV3<Alloc, sizeof...(UTypes)>;
+        assert((doTest<T, U>(UA_AllocLast, UA_AllocArg,
+                             std::move(ttuple), std::move(utuple))));
+    }
+    {
+        using T = UsesAllocatorV3<Alloc, sizeof...(TTypes)>;
+        using U = NotUsesAllocator<Alloc, sizeof...(UTypes)>;
+        assert((doTest<T, U>(UA_AllocArg, UA_None,
+                             std::move(ttuple), std::move(utuple))));
+    }
+}
+
+int main()
+{
+    using ERT = std::experimental::erased_type;
+    using PMR = ex::memory_resource*;
+    using PMA = ex::polymorphic_allocator<char>;
+    {
+        std::tuple<> t1;
+        test_pmr_uses_allocator<ERT>(t1, t1);
+        test_pmr_uses_allocator<PMR>(t1, t1);
+        test_pmr_uses_allocator<PMA>(t1, t1);
+    }
+    {
+        std::tuple<int> t1(42);
+        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_uses_allocator<PMA>(t1, t2);
+        test_pmr_uses_allocator<PMA>(t2, t1);
+    }
+    {
+        std::tuple<int> t1(42);
+        int x = 55;
+        double dx = 42.42;
+        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_uses_allocator<PMA>(           t1, std::move(t2));
+        test_pmr_uses_allocator<PMA>(std::move(t2),            t1);
+    }
+    {
+        void* xptr = nullptr;
+        long y = 4242;
+        std::tuple<int, long const&, void*&> t1(42, y, xptr);
+        int x = 55;
+        double dx = 42.42;
+        const char* s = "hello World";
+        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_uses_allocator<PMA>(           t1, std::move(t2));
+        test_pmr_uses_allocator<PMA>(std::move(t2),            t1);
+    }
+}
diff --git a/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_types.pass.cpp b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_types.pass.cpp
new file mode 100644
index 0000000..9f515e9
--- /dev/null
+++ b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_types.pass.cpp
@@ -0,0 +1,189 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// template <class T> class polymorphic_allocator
+
+// template <class U, class ...Args>
+// void polymorphic_allocator<T>::construct(U *, Args &&...)
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+#include <cstdlib>
+#include "uses_alloc_types.hpp"
+#include "test_allocator.h"
+
+namespace ex = std::experimental::pmr;
+
+template <class T>
+struct PMATest {
+    TestResource R;
+    ex::polymorphic_allocator<T> A;
+    T* ptr;
+    bool constructed;
+
+    PMATest() : A(&R), ptr(A.allocate(1)), constructed(false) {}
+
+    template <class ...Args>
+    void construct(Args&&... args) {
+        A.construct(ptr, std::forward<Args>(args)...);
+        constructed = true;
+    }
+
+    ~PMATest() {
+        if (constructed) A.destroy(ptr);
+        A.deallocate(ptr, 1);
+    }
+};
+
+template <class T, class ...Args>
+bool doTest(UsesAllocatorType UAExpect, Args&&... args)
+{
+    PMATest<T> TH;
+    // UNDER TEST //
+    TH.construct(std::forward<Args>(args)...);
+    return checkConstruct<Args&&...>(*TH.ptr, UAExpect, &TH.R);
+    // ------- //
+}
+
+
+template <class T, class ...Args>
+bool doTestUsesAllocV0(Args&&... args)
+{
+    PMATest<T> TH;
+    // UNDER TEST //
+    TH.construct(std::forward<Args>(args)...);
+    return checkConstruct<Args&&...>(*TH.ptr, UA_None);
+    // -------- //
+}
+
+
+template <class T, class EAlloc, class ...Args>
+bool doTestUsesAllocV1(EAlloc const& ealloc, Args&&... args)
+{
+    PMATest<T> TH;
+    // UNDER TEST //
+    TH.construct(std::allocator_arg, ealloc, std::forward<Args>(args)...);
+    return checkConstruct<Args&&...>(*TH.ptr, UA_AllocArg, ealloc);
+    // -------- //
+}
+
+template <class T, class EAlloc, class ...Args>
+bool doTestUsesAllocV2(EAlloc const& ealloc, Args&&... args)
+{
+    PMATest<T> TH;
+    // UNDER TEST //
+    TH.construct(std::forward<Args>(args)..., ealloc);
+    return checkConstruct<Args&&...>(*TH.ptr, UA_AllocLast, ealloc);
+    // -------- //
+}
+
+template <class Alloc, class ...Args>
+void test_pmr_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_AllocArg, std::forward<Args>(args)...)));
+    }
+    {
+        // Test T(Args..., Alloc const&) construction
+        using T = UsesAllocatorV2<Alloc, sizeof...(Args)>;
+        assert((doTest<T>(UA_AllocLast, std::forward<Args>(args)...)));
+    }
+    {
+        // Test that T(std::allocator_arg_t, Alloc const&, Args...) construction
+        // is prefered when T(Args..., Alloc const&) is also available.
+        using T = UsesAllocatorV3<Alloc, sizeof...(Args)>;
+        assert((doTest<T>(UA_AllocArg, 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>
+void test_non_pmr_uses_alloc(AllocObj const& A, Args&&... args)
+{
+    {
+        using T = NotUsesAllocator<Alloc, sizeof...(Args)>;
+        assert(doTestUsesAllocV0<T>(std::forward<Args>(args)...));
+        assert((doTestUsesAllocV1<T>(A, std::forward<Args>(args)...)));
+        assert((doTestUsesAllocV2<T>(A, std::forward<Args>(args)...)));
+    }
+    {
+        using T = UsesAllocatorV1<Alloc, sizeof...(Args)>;
+        assert(doTestUsesAllocV0<T>(std::forward<Args>(args)...));
+        assert((doTestUsesAllocV1<T>(A, std::forward<Args>(args)...)));
+    }
+    {
+        using T = UsesAllocatorV2<Alloc, sizeof...(Args)>;
+        assert(doTestUsesAllocV0<T>(std::forward<Args>(args)...));
+        assert((doTestUsesAllocV2<T>(A, std::forward<Args>(args)...)));
+    }
+    {
+        using T = UsesAllocatorV3<Alloc, sizeof...(Args)>;
+        assert(doTestUsesAllocV0<T>(std::forward<Args>(args)...));
+        assert((doTestUsesAllocV1<T>(A, std::forward<Args>(args)...)));
+        assert((doTestUsesAllocV2<T>(A, std::forward<Args>(args)...)));
+    }
+}
+
+int main()
+{
+    using ET = std::experimental::erased_type;
+    using PMR = ex::memory_resource*;
+    using PMA = ex::polymorphic_allocator<void>;
+    using STDA = std::allocator<char>;
+    using TESTA = test_allocator<char>;
+
+    int value = 42;
+    const int cvalue = 43;
+    {
+        test_pmr_uses_alloc<ET>();
+        test_pmr_uses_alloc<PMR>();
+        test_pmr_uses_alloc<PMA>();
+        test_pmr_uses_alloc<ET>(value);
+        test_pmr_uses_alloc<PMR>(value);
+        test_pmr_uses_alloc<PMA>(value);
+        test_pmr_uses_alloc<ET>(cvalue);
+        test_pmr_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_uses_alloc<PMA>(cvalue, std::move(value));
+    }
+    {
+        STDA std_alloc;
+        TESTA test_alloc(42);
+        test_non_pmr_uses_alloc<STDA>(std_alloc);
+        test_non_pmr_uses_alloc<TESTA>(test_alloc);
+        test_non_pmr_uses_alloc<STDA>(std_alloc, value);
+        test_non_pmr_uses_alloc<TESTA>(test_alloc, value);
+        test_non_pmr_uses_alloc<STDA>(std_alloc, cvalue);
+        test_non_pmr_uses_alloc<TESTA>(test_alloc, cvalue);
+        test_non_pmr_uses_alloc<STDA>(std_alloc, cvalue, std::move(value));
+        test_non_pmr_uses_alloc<TESTA>(test_alloc, cvalue, std::move(value));
+    }
+}
diff --git a/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/deallocate.pass.cpp b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/deallocate.pass.cpp
new file mode 100644
index 0000000..b631f6e
--- /dev/null
+++ b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/deallocate.pass.cpp
@@ -0,0 +1,61 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// template <class T> class polymorphic_allocator
+
+// T* polymorphic_allocator<T>::deallocate(T*, size_t size)
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+namespace ex = std::experimental::pmr;
+
+template <size_t S, size_t Align>
+void testForSizeAndAlign() {
+    using T = typename std::aligned_storage<S, Align>::type;
+
+    TestResource R;
+    ex::polymorphic_allocator<T> a(&R);
+
+    for (int N = 1; N <= 5; ++N) {
+        auto ret = a.allocate(N);
+        assert(R.checkAlloc(ret, N * sizeof(T), alignof(T)));
+
+        a.deallocate(ret, N);
+        assert(R.checkDealloc(ret, N * sizeof(T), alignof(T)));
+
+        R.reset();
+    }
+}
+
+int main()
+{
+    {
+        ex::polymorphic_allocator<int> a;
+        static_assert(
+            std::is_same<decltype(a.deallocate(nullptr, 0)), void>::value, "");
+    }
+    {
+        constexpr std::size_t MA = alignof(std::max_align_t);
+        testForSizeAndAlign<1, 1>();
+        testForSizeAndAlign<1, 2>();
+        testForSizeAndAlign<1, MA>();
+        testForSizeAndAlign<2, 2>();
+        testForSizeAndAlign<73, alignof(void*)>();
+        testForSizeAndAlign<73, MA>();
+        testForSizeAndAlign<13, MA>();
+    }
+}
diff --git a/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/destroy.pass.cpp b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/destroy.pass.cpp
new file mode 100644
index 0000000..f117bf0
--- /dev/null
+++ b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/destroy.pass.cpp
@@ -0,0 +1,51 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// template <class T> class polymorphic_allocator
+
+// template <class U>
+// void polymorphic_allocator<T>::destroy(U * ptr);
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <new>
+#include <cassert>
+#include <cstdlib>
+
+namespace ex = std::experimental::pmr;
+
+int count = 0;
+
+struct destroyable
+{
+    destroyable() { ++count; }
+    ~destroyable() { --count; }
+};
+
+int main()
+{
+    typedef ex::polymorphic_allocator<double> A;
+    {
+        A a;
+        static_assert(
+            std::is_same<decltype(a.destroy((destroyable*)nullptr)), void>::value,
+            "");
+    }
+    {
+        destroyable * ptr = ::new (std::malloc(sizeof(destroyable))) destroyable();
+        assert(count == 1);
+        A{}.destroy(ptr);
+        assert(count == 0);
+        std::free(ptr);
+    }
+}
diff --git a/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/resource.pass.cpp b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/resource.pass.cpp
new file mode 100644
index 0000000..5f5411b
--- /dev/null
+++ b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/resource.pass.cpp
@@ -0,0 +1,56 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// template <class T> class polymorphic_allocator
+
+// memory_resource *
+// polymorphic_allocator<T>::resource() const
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+namespace ex = std::experimental::pmr;
+
+int main()
+{
+    typedef ex::polymorphic_allocator<void> A;
+    {
+        A const a;
+        static_assert(
+            std::is_same<decltype(a.resource()), ex::memory_resource*>::value
+          , ""
+          );
+    }
+    {
+        ex::memory_resource * mptr = (ex::memory_resource*)42;
+        A const a(mptr);
+        assert(a.resource() == mptr);
+    }
+    {
+        A const a(nullptr);
+        assert(a.resource() == nullptr);
+        assert(a.resource() == nullptr);
+    }
+    {
+        A const a;
+        assert(a.resource() == ex::get_default_resource());
+    }
+    {
+        ex::memory_resource * mptr = (ex::memory_resource*)42;
+        ex::set_default_resource(mptr);
+        A const a;
+        assert(a.resource() == mptr);
+        assert(a.resource() == ex::get_default_resource());
+    }
+}
diff --git a/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/select_on_container_copy_construction.pass.cpp b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/select_on_container_copy_construction.pass.cpp
new file mode 100644
index 0000000..92933ce
--- /dev/null
+++ b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/select_on_container_copy_construction.pass.cpp
@@ -0,0 +1,52 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// template <class T> class polymorphic_allocator
+
+// polymorphic_allocator
+// polymorphic_allocator<T>::select_on_container_copy_construction() const
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+namespace ex = std::experimental::pmr;
+
+int main()
+{
+    typedef ex::polymorphic_allocator<void> A;
+    {
+        A const a;
+        static_assert(
+            std::is_same<decltype(a.select_on_container_copy_construction()), A>::value,
+            "");
+    }
+    {
+        ex::memory_resource * mptr = (ex::memory_resource*)42;
+        A const a(mptr);
+        assert(a.resource() == mptr);
+        A const other = a.select_on_container_copy_construction();
+        assert(other.resource() == ex::get_default_resource());
+        assert(a.resource() == mptr);
+    }
+    {
+        ex::memory_resource * mptr = (ex::memory_resource*)42;
+        ex::set_default_resource(mptr);
+        A const a(nullptr);
+        assert(a.resource() == nullptr);
+        A const other = a.select_on_container_copy_construction();
+        assert(other.resource() == ex::get_default_resource());
+        assert(other.resource() == mptr);
+        assert(a.resource() == nullptr);
+    }
+}
diff --git a/src/experimental/placeholder.cpp b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.overview/nothing_to_do.pass.cpp
similarity index 64%
copy from src/experimental/placeholder.cpp
copy to test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.overview/nothing_to_do.pass.cpp
index 998330b..86bf8cc 100644
--- a/src/experimental/placeholder.cpp
+++ b/test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.overview/nothing_to_do.pass.cpp
@@ -1,4 +1,4 @@
-//===--------------------------- TODO.cpp ---------------------------------===//
+//===----------------------------------------------------------------------===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -7,8 +7,4 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "experimental/__config"
-
-_LIBCPP_BEGIN_NAMESPACE_LFTS
-
-_LIBCPP_END_NAMESPACE_LFTS
+int main () {}
diff --git a/src/experimental/placeholder.cpp b/test/std/experimental/memory/memory.polymorphic.allocator.class/nothing_to_do.pass.cpp
similarity index 64%
copy from src/experimental/placeholder.cpp
copy to test/std/experimental/memory/memory.polymorphic.allocator.class/nothing_to_do.pass.cpp
index 998330b..86bf8cc 100644
--- a/src/experimental/placeholder.cpp
+++ b/test/std/experimental/memory/memory.polymorphic.allocator.class/nothing_to_do.pass.cpp
@@ -1,4 +1,4 @@
-//===--------------------------- TODO.cpp ---------------------------------===//
+//===----------------------------------------------------------------------===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -7,8 +7,4 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "experimental/__config"
-
-_LIBCPP_BEGIN_NAMESPACE_LFTS
-
-_LIBCPP_END_NAMESPACE_LFTS
+int main () {}
diff --git a/test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.ctor/alloc_copy.pass.cpp b/test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.ctor/alloc_copy.pass.cpp
new file mode 100644
index 0000000..4de30bc
--- /dev/null
+++ b/test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.ctor/alloc_copy.pass.cpp
@@ -0,0 +1,53 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// template <class Alloc> class resource_adaptor_imp;
+
+// resource_adaptor_imp<Alloc>::resource_adaptor_imp(Alloc const &)
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+namespace ex = std::experimental::pmr;
+
+int main()
+{
+    typedef CountingAllocator<char> AllocT;
+    typedef ex::resource_adaptor<AllocT> R;
+    {
+        AllocController P;
+        AllocT const a(P);
+        R const r(a);
+        assert(P.copy_constructed == 1);
+        assert(P.move_constructed == 0);
+        assert(r.get_allocator() == a);
+    }
+    {
+        AllocController P;
+        AllocT a(P);
+        R const r(a);
+        assert(P.copy_constructed == 1);
+        assert(P.move_constructed == 0);
+        assert(r.get_allocator() == a);
+    }
+    {
+        AllocController P;
+        AllocT const a(P);
+        R const r(std::move(a));
+        assert(P.copy_constructed == 1);
+        assert(P.move_constructed == 0);
+        assert(r.get_allocator() == a);
+    }
+}
diff --git a/test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.ctor/alloc_move.pass.cpp b/test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.ctor/alloc_move.pass.cpp
new file mode 100644
index 0000000..f3ecc98
--- /dev/null
+++ b/test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.ctor/alloc_move.pass.cpp
@@ -0,0 +1,44 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// template <class Alloc> class resource_adaptor_imp;
+
+// resource_adaptor_imp<Alloc>::resource_adaptor_imp(Alloc &&)
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+namespace ex = std::experimental::pmr;
+
+int main()
+{
+    typedef CountingAllocator<char> AllocT;
+    typedef ex::resource_adaptor<AllocT> R;
+    {
+        AllocController P;
+        AllocT a(P);
+        R const r(std::move(a));
+        assert(P.copy_constructed == 0);
+        assert(P.move_constructed == 1);
+        assert(r.get_allocator() == a);
+    }
+    {
+        AllocController P;
+        R const r(AllocT{P});
+        assert(P.copy_constructed == 0);
+        assert(P.move_constructed == 1);
+        assert(r.get_allocator() == AllocT{P});
+    }
+}
diff --git a/test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.ctor/default.pass.cpp b/test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.ctor/default.pass.cpp
new file mode 100644
index 0000000..4abc69f
--- /dev/null
+++ b/test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.ctor/default.pass.cpp
@@ -0,0 +1,40 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// template <class Alloc> class resource_adaptor_imp;
+
+// resource_adaptor_imp<Alloc>::resource_adaptor_imp() = default;
+
+#include <experimental/memory_resource>
+#include <memory>
+#include <type_traits>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+namespace ex = std::experimental::pmr;
+
+int main()
+{
+    {
+        typedef CountingAllocator<char> AllocT; // Not default constructible
+        typedef ex::resource_adaptor<AllocT> R;
+        static_assert(!std::is_default_constructible<R>::value, "");
+    }
+    {
+        typedef std::allocator<char> AllocT; // Is default constructible
+        typedef ex::resource_adaptor<AllocT> R;
+        static_assert(std::is_default_constructible<R>::value, "");
+        R r; ((void)r);
+    }
+}
diff --git a/test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/do_allocate_and_deallocate.pass.cpp b/test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/do_allocate_and_deallocate.pass.cpp
new file mode 100644
index 0000000..875c3e0
--- /dev/null
+++ b/test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/do_allocate_and_deallocate.pass.cpp
@@ -0,0 +1,115 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// template <class Alloc> class resource_adaptor_imp;
+
+// void * do_allocate(size_t size, size_t align)
+// void   do_deallocate(void*, size_t, size_t)
+
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <memory>
+#include <exception>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_memory_resource.hpp"
+
+namespace ex = std::experimental::pmr;
+
+template <class Alloc>
+void check_allocate_deallocate()
+{
+    typedef ex::resource_adaptor<Alloc> R1;
+    const std::size_t max_align = alignof(std::max_align_t);
+
+    for (std::size_t s = 0; s < 5012; ++s)
+    {
+        for(std::size_t align_req = 1; align_req <= (max_align * 2); align_req *= 2)
+        {
+            const std::size_t align_exp = align_req > max_align
+                                                    ? max_align : align_req;
+            AllocController P;
+            R1 r{Alloc(P)};
+            ex::memory_resource & m1 = r;
+
+            void * const ret = m1.allocate(s, align_req);
+            assert(P.alive == 1);
+            assert(P.alloc_count == 1);
+            assert(P.checkAllocAtLeast(ret, s, align_exp));
+
+            assert(((std::size_t)ret % align_exp) == 0);
+
+            m1.deallocate(ret, s, align_req);
+            assert(P.alive == 0);
+            assert(P.dealloc_count == 1);
+            assert(P.checkDeallocMatchesAlloc());
+        }
+    }
+}
+
+void check_alloc_max_size() {
+    using Alloc = NullAllocator<char>;
+    using R1 = ex::resource_adaptor<Alloc>;
+    const std::size_t max_align = alignof(std::max_align_t);
+
+    auto check = [=](std::size_t s, std::size_t align_req) {
+        const std::size_t align_exp = align_req > max_align
+                                                ? max_align : align_req;
+        AllocController P;
+        R1 r{Alloc(P)};
+        ex::memory_resource & m1 = r;
+
+        void * const ret = m1.allocate(s, align_req);
+        assert(P.alive == 1);
+        assert(P.alloc_count == 1);
+        assert(P.checkAllocAtLeast(ret, s, align_exp));
+
+        m1.deallocate(ret, s, align_req);
+        assert(P.alive == 0);
+        assert(P.dealloc_count == 1);
+        assert(P.checkDeallocMatchesAlloc());
+    };
+
+    const std::size_t sizeTypeMax = ~0;
+    const std::size_t testSizeStart = sizeTypeMax - (max_align * 3);
+    const std::size_t testSizeEnd = sizeTypeMax - max_align;
+
+    for (std::size_t size = testSizeStart; size <= testSizeEnd; ++size) {
+        for (std::size_t align=1; align <= (max_align * 2); align *= 2) {
+            check(size, align);
+        }
+    }
+
+#ifndef TEST_HAS_NO_EXCEPTIONS
+    for (std::size_t size = sizeTypeMax; size > testSizeEnd; --size) {
+        AllocController P;
+        R1 r{Alloc(P)};
+        ex::memory_resource & m1 = r;
+
+        try {
+            m1.allocate(size);
+            assert(false);
+        } catch (std::exception const&) {
+        }
+    }
+#endif
+}
+
+int main()
+{
+    check_allocate_deallocate<CountingAllocator<char>>();
+    check_allocate_deallocate<MinAlignedAllocator<char>>();
+    check_alloc_max_size();
+}
diff --git a/test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/do_is_equal.pass.cpp b/test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/do_is_equal.pass.cpp
new file mode 100644
index 0000000..ff4b317
--- /dev/null
+++ b/test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/do_is_equal.pass.cpp
@@ -0,0 +1,83 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// template <class Alloc> class resource_adaptor_imp;
+
+// bool do_is_equal(memory_resource const &) const noexcept;
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <memory>
+#include <cassert>
+#include "test_memory_resource.hpp"
+
+using std::size_t;
+namespace ex = std::experimental::pmr;
+
+int main()
+{
+
+    typedef CountingAllocator<char> Alloc1;
+    typedef CountingAllocator<int> RAlloc1;
+    typedef ex::resource_adaptor<Alloc1> R1;
+    typedef ex::resource_adaptor<RAlloc1> RR1;
+    static_assert(std::is_same<R1, RR1>::value, "");
+
+    typedef std::allocator<char> Alloc2;
+    typedef ex::resource_adaptor<Alloc2> R2;
+    static_assert(!std::is_same<R1, R2>::value, "");
+
+    // equal same type
+    {
+        AllocController C;
+        Alloc1 a1(C);
+        R1 const r1(a1);
+        ex::memory_resource const & m1 = r1;
+
+        Alloc1 a2(C);
+        R1 const r2(a2);
+        ex::memory_resource const & m2 = r2;
+
+        assert(m1.is_equal(m2));
+        assert(m2.is_equal(m1));
+    }
+    // not equal same type
+    {
+        AllocController C;
+        Alloc1 a1(C);
+        R1 const r1(a1);
+        ex::memory_resource const & m1 = r1;
+
+        AllocController C2;
+        Alloc1 a2(C2);
+        R1 const r2(a2);
+        ex::memory_resource const & m2 = r2;
+
+        assert(!m1.is_equal(m2));
+        assert(!m2.is_equal(m1));
+    }
+    // different allocator types
+    {
+        AllocController C;
+        Alloc1 a1(C);
+        R1 const r1(a1);
+        ex::memory_resource const & m1 = r1;
+
+        Alloc2 a2;
+        R2 const r2(a2);
+        ex::memory_resource const & m2 = r2;
+
+        assert(!m1.is_equal(m2));
+        assert(!m2.is_equal(m1));
+    }
+}
diff --git a/test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.overview/overview.pass.cpp b/test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.overview/overview.pass.cpp
new file mode 100644
index 0000000..898543f
--- /dev/null
+++ b/test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.overview/overview.pass.cpp
@@ -0,0 +1,39 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// template <class Alloc> class resource_adaptor_imp;
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <memory>
+#include <cassert>
+
+namespace ex = std::experimental::pmr;
+
+int main()
+{
+    typedef ex::resource_adaptor<std::allocator<void>> R;
+    typedef ex::resource_adaptor<std::allocator<long>> R2;
+    static_assert(std::is_same<R, R2>::value, "");
+    {
+        static_assert(std::is_base_of<ex::memory_resource, R>::value, "");
+        static_assert(std::is_same<R::allocator_type, std::allocator<char>>::value, "");
+    }
+    {
+        static_assert(std::is_default_constructible<R>::value, "");
+        static_assert(std::is_copy_constructible<R>::value, "");
+        static_assert(std::is_move_constructible<R>::value, "");
+        static_assert(std::is_copy_assignable<R>::value, "");
+        static_assert(std::is_move_assignable<R>::value, "");
+   }
+}
diff --git a/test/std/experimental/memory/memory.resource.global/default_resource.pass.cpp b/test/std/experimental/memory/memory.resource.global/default_resource.pass.cpp
new file mode 100644
index 0000000..c89c49d
--- /dev/null
+++ b/test/std/experimental/memory/memory.resource.global/default_resource.pass.cpp
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+//-----------------------------------------------------------------------------
+// TESTING memory_resource * get_default_resource() noexcept;
+//         memory_resource * set_default_resource(memory_resource*) noexcept;
+//
+// Concerns:
+//  A) 'get_default_resource()' returns a non-null memory_resource pointer.
+//  B) 'get_default_resource()' returns the value set by the last call to
+//     'set_default_resource(...)' and 'new_delete_resource()' if no call
+//     to 'set_default_resource(...)' has occurred.
+//  C) 'set_default_resource(...)' returns the previous value of the default
+//     resource.
+//  D) 'set_default_resource(T* p)' for a non-null 'p' sets the default resource
+//     to be 'p'.
+//  E) 'set_default_resource(null)' sets the default resource to
+//     'new_delete_resource()'.
+//  F) 'get_default_resource' and 'set_default_resource' are noexcept.
+
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+using namespace std::experimental::pmr;
+
+int main() {
+    TestResource R;
+    { // Test (A) and (B)
+        memory_resource* p = get_default_resource();
+        assert(p != nullptr);
+        assert(p == new_delete_resource());
+        assert(p == get_default_resource());
+    }
+    { // Test (C) and (D)
+        memory_resource *expect = &R;
+        memory_resource *old = set_default_resource(expect);
+        assert(old != nullptr);
+        assert(old == new_delete_resource());
+
+        memory_resource *p = get_default_resource();
+        assert(p != nullptr);
+        assert(p == expect);
+        assert(p == get_default_resource());
+    }
+    { // Test (E)
+        memory_resource* old = set_default_resource(nullptr);
+        assert(old == &R);
+        memory_resource* p = get_default_resource();
+        assert(p != nullptr);
+        assert(p == new_delete_resource());
+        assert(p == get_default_resource());
+    }
+    { // Test (F)
+        static_assert(noexcept(get_default_resource()),
+                      "get_default_resource() must be noexcept");
+
+        static_assert(noexcept(set_default_resource(nullptr)),
+                      "set_default_resource() must be noexcept");
+    }
+}
diff --git a/test/std/experimental/memory/memory.resource.global/new_delete_resource.pass.cpp b/test/std/experimental/memory/memory.resource.global/new_delete_resource.pass.cpp
new file mode 100644
index 0000000..bd8c121
--- /dev/null
+++ b/test/std/experimental/memory/memory.resource.global/new_delete_resource.pass.cpp
@@ -0,0 +1,101 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// memory_resource * new_delete_resource()
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+#include "count_new.hpp"
+
+namespace ex = std::experimental::pmr;
+
+struct assert_on_compare : public ex::memory_resource
+{
+protected:
+    virtual void * do_allocate(size_t, size_t)
+    { assert(false); }
+
+    virtual void do_deallocate(void *, size_t, size_t)
+    { assert(false); }
+
+    virtual bool do_is_equal(ex::memory_resource const &) const noexcept
+    { assert(false); }
+};
+
+void test_return()
+{
+    {
+        static_assert(std::is_same<
+            decltype(ex::new_delete_resource()), ex::memory_resource*
+          >::value, "");
+    }
+    // assert not null
+    {
+        assert(ex::new_delete_resource());
+    }
+    // assert same return value
+    {
+        assert(ex::new_delete_resource() == ex::new_delete_resource());
+    }
+}
+
+void test_equality()
+{
+    // Same object
+    {
+        ex::memory_resource & r1 = *ex::new_delete_resource();
+        ex::memory_resource & r2 = *ex::new_delete_resource();
+        // check both calls returned the same object
+        assert(&r1 == &r2);
+        // check for proper equality semantics
+        assert(r1 == r2);
+        assert(r2 == r1);
+        assert(!(r1 != r2));
+        assert(!(r2 != r1));
+    }
+    // Different types
+    {
+        ex::memory_resource & r1 = *ex::new_delete_resource();
+        assert_on_compare c;
+        ex::memory_resource & r2 = c;
+        assert(r1 != r2);
+        assert(!(r1 == r2));
+    }
+}
+
+void test_allocate_deallocate()
+{
+    ex::memory_resource & r1 = *ex::new_delete_resource();
+
+    globalMemCounter.reset();
+
+    void *ret = r1.allocate(50);
+    assert(ret);
+    assert(globalMemCounter.checkOutstandingNewEq(1));
+    assert(globalMemCounter.checkLastNewSizeEq(50));
+
+    r1.deallocate(ret, 1);
+    assert(globalMemCounter.checkOutstandingNewEq(0));
+    assert(globalMemCounter.checkDeleteCalledEq(1));
+
+}
+
+int main()
+{
+    static_assert(noexcept(ex::new_delete_resource()), "Must be noexcept");
+    test_return();
+    test_equality();
+    test_allocate_deallocate();
+}
diff --git a/test/std/experimental/memory/memory.resource.global/null_memory_resource.pass.cpp b/test/std/experimental/memory/memory.resource.global/null_memory_resource.pass.cpp
new file mode 100644
index 0000000..2be7436
--- /dev/null
+++ b/test/std/experimental/memory/memory.resource.global/null_memory_resource.pass.cpp
@@ -0,0 +1,117 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// memory_resource * null_memory_resource()
+
+#include <experimental/memory_resource>
+#include <new>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "count_new.hpp"
+
+namespace ex = std::experimental::pmr;
+
+struct assert_on_compare : public ex::memory_resource
+{
+protected:
+    virtual void * do_allocate(size_t, size_t)
+    { assert(false); }
+
+    virtual void do_deallocate(void *, size_t, size_t)
+    { assert(false); }
+
+    virtual bool do_is_equal(ex::memory_resource const &) const noexcept
+    { assert(false); }
+};
+
+void test_return()
+{
+    {
+        static_assert(std::is_same<
+            decltype(ex::null_memory_resource()), ex::memory_resource*
+          >::value, "");
+    }
+    // Test that the returned value is not null
+    {
+        assert(ex::null_memory_resource());
+    }
+    // Test the same value is returned by repeated calls.
+    {
+        assert(ex::null_memory_resource() == ex::null_memory_resource());
+    }
+}
+
+void test_equality()
+{
+    // Same object
+    {
+        ex::memory_resource & r1 = *ex::null_memory_resource();
+        ex::memory_resource & r2 = *ex::null_memory_resource();
+        // check both calls returned the same object
+        assert(&r1 == &r2);
+        // check for proper equality semantics
+        assert(r1 == r2);
+        assert(r2 == r1);
+        assert(!(r1 != r2));
+        assert(!(r2 != r1));
+        // check the is_equal method
+        assert(r1.is_equal(r2));
+        assert(r2.is_equal(r1));
+    }
+    // Different types
+    {
+        ex::memory_resource & r1 = *ex::null_memory_resource();
+        assert_on_compare c;
+        ex::memory_resource & r2 = c;
+        assert(r1 != r2);
+        assert(!(r1 == r2));
+        assert(!r1.is_equal(r2));
+    }
+}
+
+void test_allocate()
+{
+#ifndef TEST_HAS_NO_EXCEPTIONS
+    DisableAllocationGuard g; // null_memory_resource shouldn't allocate.
+    try {
+        ex::null_memory_resource()->allocate(1);
+        assert(false);
+    } catch (std::bad_alloc const &) {
+       // do nothing
+    } catch (...) {
+        assert(false);
+    }
+#endif
+}
+
+void test_deallocate()
+{
+    globalMemCounter.reset();
+
+    int x = 42;
+    ex::null_memory_resource()->deallocate(nullptr, 0);
+    ex::null_memory_resource()->deallocate(&x, 0);
+
+    assert(globalMemCounter.checkDeleteCalledEq(0));
+    assert(globalMemCounter.checkDeleteArrayCalledEq(0));
+}
+
+int main()
+{
+    test_return();
+    test_equality();
+    test_allocate();
+    test_deallocate();
+}
diff --git a/src/experimental/placeholder.cpp b/test/std/experimental/memory/memory.resource.synop/nothing_to_do.pass.cpp
similarity index 64%
rename from src/experimental/placeholder.cpp
rename to test/std/experimental/memory/memory.resource.synop/nothing_to_do.pass.cpp
index 998330b..9a59227 100644
--- a/src/experimental/placeholder.cpp
+++ b/test/std/experimental/memory/memory.resource.synop/nothing_to_do.pass.cpp
@@ -1,4 +1,5 @@
-//===--------------------------- TODO.cpp ---------------------------------===//
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -7,8 +8,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "experimental/__config"
-
-_LIBCPP_BEGIN_NAMESPACE_LFTS
-
-_LIBCPP_END_NAMESPACE_LFTS
+int main()
+{
+}
diff --git a/test/std/experimental/memory/memory.resource/construct.fail.cpp b/test/std/experimental/memory/memory.resource/construct.fail.cpp
new file mode 100644
index 0000000..d990714
--- /dev/null
+++ b/test/std/experimental/memory/memory.resource/construct.fail.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// Check that memory_resource is not constructible
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+namespace ex = std::experimental::pmr;
+
+int main()
+{
+    ex::memory_resource m; // expected-error {{variable type 'ex::memory_resource' is an abstract class}}
+}
diff --git a/test/std/experimental/memory/memory.resource/memory.resource.eq/equal.pass.cpp b/test/std/experimental/memory/memory.resource/memory.resource.eq/equal.pass.cpp
new file mode 100644
index 0000000..0ccdeed
--- /dev/null
+++ b/test/std/experimental/memory/memory.resource/memory.resource.eq/equal.pass.cpp
@@ -0,0 +1,76 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// bool operator==(memory_resource const &, memory_resource const &) noexcept;
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_memory_resource.hpp"
+
+namespace ex = std::experimental::pmr;
+
+int main()
+{
+    // check return types
+    {
+        ex::memory_resource const * mr1(nullptr);
+        ex::memory_resource const * mr2(nullptr);
+        static_assert(std::is_same<decltype(*mr1 == *mr2), bool>::value, "");
+        static_assert(noexcept(*mr1 == *mr2), "");
+    }
+    // equal
+    {
+        TestResource r1(1);
+        TestResource r2(1);
+        ex::memory_resource const & mr1 = r1;
+        ex::memory_resource const & mr2 = r2;
+
+        assert(mr1 == mr2);
+        assert(r1.checkIsEqualCalledEq(1));
+        assert(r2.checkIsEqualCalledEq(0));
+
+        assert(mr2 == mr1);
+        assert(r1.checkIsEqualCalledEq(1));
+        assert(r2.checkIsEqualCalledEq(1));
+    }
+    // equal same object
+    {
+        TestResource r1(1);
+        ex::memory_resource const & mr1 = r1;
+        ex::memory_resource const & mr2 = r1;
+
+        assert(mr1 == mr2);
+        assert(r1.checkIsEqualCalledEq(0));
+
+        assert(mr2 == mr1);
+        assert(r1.checkIsEqualCalledEq(0));
+    }
+    // not equal
+    {
+        TestResource r1(1);
+        TestResource r2(2);
+        ex::memory_resource const & mr1 = r1;
+        ex::memory_resource const & mr2 = r2;
+
+        assert(!(mr1 == mr2));
+        assert(r1.checkIsEqualCalledEq(1));
+        assert(r2.checkIsEqualCalledEq(0));
+
+        assert(!(mr2 == mr1));
+        assert(r1.checkIsEqualCalledEq(1));
+        assert(r2.checkIsEqualCalledEq(1));
+    }
+}
diff --git a/test/std/experimental/memory/memory.resource/memory.resource.eq/not_equal.pass.cpp b/test/std/experimental/memory/memory.resource/memory.resource.eq/not_equal.pass.cpp
new file mode 100644
index 0000000..ede1bfd
--- /dev/null
+++ b/test/std/experimental/memory/memory.resource/memory.resource.eq/not_equal.pass.cpp
@@ -0,0 +1,75 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// bool operator!=(memory_resource const &, memory_resource const &) noexcept;
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+namespace ex = std::experimental::pmr;
+
+int main()
+{
+    // check return types
+    {
+        ex::memory_resource const * mr1(nullptr);
+        ex::memory_resource const * mr2(nullptr);
+        static_assert(std::is_same<decltype(*mr1 != *mr2), bool>::value, "");
+        static_assert(noexcept(*mr1 != *mr2), "");
+    }
+    // not equal
+    {
+        TestResource r1(1);
+        TestResource r2(2);
+        ex::memory_resource const & mr1 = r1;
+        ex::memory_resource const & mr2 = r2;
+
+        assert(mr1 != mr2);
+        assert(r1.checkIsEqualCalledEq(1));
+        assert(r2.checkIsEqualCalledEq(0));
+
+        assert(mr2 != mr1);
+        assert(r1.checkIsEqualCalledEq(1));
+        assert(r2.checkIsEqualCalledEq(1));
+    }
+    // equal
+    {
+        TestResource r1(1);
+        TestResource r2(1);
+        ex::memory_resource const & mr1 = r1;
+        ex::memory_resource const & mr2 = r2;
+
+        assert(!(mr1 != mr2));
+        assert(r1.checkIsEqualCalledEq(1));
+        assert(r2.checkIsEqualCalledEq(0));
+
+        assert(!(mr2 != mr1));
+        assert(r1.checkIsEqualCalledEq(1));
+        assert(r2.checkIsEqualCalledEq(1));
+    }
+    // equal same object
+    {
+        TestResource r1(1);
+        ex::memory_resource const & mr1 = r1;
+        ex::memory_resource const & mr2 = r1;
+
+        assert(!(mr1 != mr2));
+        assert(r1.checkIsEqualCalledEq(0));
+
+        assert(!(mr2 != mr1));
+        assert(r1.checkIsEqualCalledEq(0));
+    }
+}
diff --git a/src/experimental/placeholder.cpp b/test/std/experimental/memory/memory.resource/memory.resource.overview/nothing_to_do.pass.cpp
similarity index 64%
copy from src/experimental/placeholder.cpp
copy to test/std/experimental/memory/memory.resource/memory.resource.overview/nothing_to_do.pass.cpp
index 998330b..86bf8cc 100644
--- a/src/experimental/placeholder.cpp
+++ b/test/std/experimental/memory/memory.resource/memory.resource.overview/nothing_to_do.pass.cpp
@@ -1,4 +1,4 @@
-//===--------------------------- TODO.cpp ---------------------------------===//
+//===----------------------------------------------------------------------===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -7,8 +7,4 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "experimental/__config"
-
-_LIBCPP_BEGIN_NAMESPACE_LFTS
-
-_LIBCPP_END_NAMESPACE_LFTS
+int main () {}
diff --git a/test/std/experimental/memory/memory.resource/memory.resource.priv/protected_members.fail.cpp b/test/std/experimental/memory/memory.resource/memory.resource.priv/protected_members.fail.cpp
new file mode 100644
index 0000000..eddfede
--- /dev/null
+++ b/test/std/experimental/memory/memory.resource/memory.resource.priv/protected_members.fail.cpp
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+// memory_resource::do_allocate(size_t, size_t);          /* protected */
+// memory_resource::do_deallocate(void*, size_t, size_t); /* protected */
+// memory_resource::do_is_equal(memory_resource const&);  /* protected */
+
+#include <experimental/memory_resource>
+
+namespace ex = std::experimental::pmr;
+
+int main() {
+    ex::memory_resource *m = ex::new_delete_resource();
+    m->do_allocate(0, 0); // expected-error{{'do_allocate' is a protected member}}
+    m->do_deallocate(nullptr, 0, 0); // expected-error{{'do_deallocate' is a protected member}}
+    m->do_is_equal(*m); // expected-error{{'do_is_equal' is a protected member}}
+}
\ No newline at end of file
diff --git a/test/std/experimental/memory/memory.resource/memory.resource.public/allocate.pass.cpp b/test/std/experimental/memory/memory.resource/memory.resource.public/allocate.pass.cpp
new file mode 100644
index 0000000..26cf903
--- /dev/null
+++ b/test/std/experimental/memory/memory.resource/memory.resource.public/allocate.pass.cpp
@@ -0,0 +1,89 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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.
+//
+//===----------------------------------------------------------------------===//
+
+// <experimental/memory_resource>
+
+// UNSUPPORTED: c++98, c++03
+
+//------------------------------------------------------------------------------
+// TESTING void * memory_resource::allocate(size_t, size_t = max_align)
+//
+// Concerns:
+//  A) 'memory_resource' contains a member 'allocate' with the required
+//     signature, including the default alignment parameter.
+//  B) The return type of 'allocate' is 'void*'.
+//  C) 'allocate' is not marked as 'noexcept'.
+//  D) Invoking 'allocate' invokes 'do_allocate' with the same arguments.
+//  E) If 'do_allocate' throws then 'allocate' propagates that exception.
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cstddef>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_memory_resource.hpp"
+
+using std::experimental::pmr::memory_resource;
+
+int main()
+{
+    TestResource R(42);
+    auto& P = R.getController();
+    memory_resource& M = R;
+    {
+        static_assert(
+            std::is_same<decltype(M.allocate(0, 0)), void*>::value
+          , "Must be void*"
+          );
+        static_assert(
+            std::is_same<decltype(M.allocate(0)), void*>::value
+          , "Must be void*"
+          );
+    }
+    {
+        static_assert(
+            ! noexcept(M.allocate(0, 0))
+          , "Must not be noexcept."
+          );
+        static_assert(
+            ! noexcept(M.allocate(0))
+          , "Must not be noexcept."
+          );
+    }
+    {
+        int s = 42;
+        int a = 64;
+        void* p = M.allocate(s, a);
+        assert(P.alloc_count == 1);
+        assert(P.checkAlloc(p, s, a));
+
+        s = 128;
+        a = MaxAlignV;
+        p = M.allocate(s);
+        assert(P.alloc_count == 2);
+        assert(P.checkAlloc(p, s, a));
+    }
+#ifndef TEST_HAS_NO_EXCEPTIONS
+    {
+        TestResource R2;
+        auto& P = R2.getController();
+        P.throw_on_alloc = true;
+        memory_resource& M2 = R2;
+        try {
+            M2.allocate(42);
+            assert(false);
+        } catch (TestException const&) {
+            // do nothing.
+        } catch (...) {
+            assert(false);
+        }
+    }
+#endif
+}
diff --git a/test/std/experimental/memory/memory.resource/memory.resource.public/deallocate.pass.cpp b/test/std/experimental/memory/memory.resource/memory.resource.public/deallocate.pass.cpp
new file mode 100644
index 0000000..d1a4ab2
--- /dev/null
+++ b/test/std/experimental/memory/memory.resource/memory.resource.public/deallocate.pass.cpp
@@ -0,0 +1,74 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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.
+//
+//===----------------------------------------------------------------------===//
+
+// <experimental/memory_resource>
+
+// UNSUPPORTED: c++98, c++03
+
+//------------------------------------------------------------------------------
+// TESTING void * memory_resource::deallocate(void *, size_t, size_t = max_align)
+//
+// Concerns:
+//  A) 'memory_resource' contains a member 'deallocate' with the required
+//     signature, including the default alignment parameter.
+//  B) The return type of 'deallocate' is 'void'.
+//  C) 'deallocate' is not marked as 'noexcept'.
+//  D) Invoking 'deallocate' invokes 'do_deallocate' with the same arguments.
+
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cstddef>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+using std::experimental::pmr::memory_resource;
+
+int main()
+{
+    NullResource R(42);
+    auto& P = R.getController();
+    memory_resource& M = R;
+    {
+        static_assert(
+            std::is_same<decltype(M.deallocate(nullptr, 0, 0)), void>::value
+          , "Must be void"
+          );
+        static_assert(
+            std::is_same<decltype(M.deallocate(nullptr, 0)), void>::value
+          , "Must be void"
+          );
+    }
+    {
+        static_assert(
+            ! noexcept(M.deallocate(nullptr, 0, 0))
+          , "Must not be noexcept."
+          );
+        static_assert(
+            ! noexcept(M.deallocate(nullptr, 0))
+          , "Must not be noexcept."
+          );
+    }
+    {
+        int s = 100;
+        int a = 64;
+        void* p = reinterpret_cast<void*>(640);
+        M.deallocate(p, s, a);
+        assert(P.dealloc_count == 1);
+        assert(P.checkDealloc(p, s, a));
+
+        s = 128;
+        a = alignof(std::max_align_t);
+        p = reinterpret_cast<void*>(12800);
+        M.deallocate(p, s);
+        assert(P.dealloc_count == 2);
+        assert(P.checkDealloc(p, s, a));
+    }
+}
diff --git a/test/std/experimental/memory/memory.resource/memory.resource.public/dtor.pass.cpp b/test/std/experimental/memory/memory.resource/memory.resource.public/dtor.pass.cpp
new file mode 100644
index 0000000..9e1d286
--- /dev/null
+++ b/test/std/experimental/memory/memory.resource/memory.resource.public/dtor.pass.cpp
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+//------------------------------------------------------------------------------
+// TESTING virtual ~memory_resource()
+//
+// Concerns:
+//  A) 'memory_resource' is destructible.
+//  B) The destructor is implicitly marked noexcept.
+//  C) The destructor is marked virtual.
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+using std::experimental::pmr::memory_resource;
+
+int main()
+{
+    static_assert(
+        std::has_virtual_destructor<memory_resource>::value
+      , "Must have virtual destructor"
+      );
+    static_assert(
+        std::is_nothrow_destructible<memory_resource>::value,
+        "Must be nothrow destructible"
+      );
+    static_assert(
+        std::is_abstract<memory_resource>::value
+      , "Must be abstract"
+      );
+    // Check that the destructor of `TestResource` is called when
+    // it is deleted as a pointer to `memory_resource`
+    {
+        using TR = TestResource;
+        memory_resource* M = new TR(42);
+        assert(TR::resource_alive == 1);
+        assert(TR::resource_constructed == 1);
+        assert(TR::resource_destructed == 0);
+
+        delete M;
+
+        assert(TR::resource_alive == 0);
+        assert(TR::resource_constructed == 1);
+        assert(TR::resource_destructed == 1);
+    }
+}
diff --git a/test/std/experimental/memory/memory.resource/memory.resource.public/is_equal.pass.cpp b/test/std/experimental/memory/memory.resource/memory.resource.public/is_equal.pass.cpp
new file mode 100644
index 0000000..32792cf
--- /dev/null
+++ b/test/std/experimental/memory/memory.resource/memory.resource.public/is_equal.pass.cpp
@@ -0,0 +1,93 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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
+
+// <experimental/memory_resource>
+
+//------------------------------------------------------------------------------
+// TESTING virtual bool is_equal(memory_resource const &) const noexcept
+//
+// Concerns:
+//   A) 'memory_resource' provides a function 'is_equal' with the required
+//      signature.
+//   B) 'is_equal' is noexcept.
+//   C) 'do_is_equal' is called using the same arguments passed to 'is_equal'
+//      and the resulting value is returned.
+//   D) 'do_is_equal' is called on the LHS object and not the RHS object.
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+#include "test_memory_resource.hpp"
+
+using std::experimental::pmr::memory_resource;
+
+int main()
+{
+    {
+        memory_resource const* r1 = nullptr;
+        memory_resource const* r2 = nullptr;
+        static_assert(
+            noexcept(r1->is_equal(*r2))
+          , "is_equal must be noexcept"
+          );
+    }
+    {
+        TestResource1 R1(1);
+        auto& P1 = R1.getController();
+        memory_resource const& M1 = R1;
+
+        TestResource2 R2(1);
+        auto& P2 = R2.getController();
+        memory_resource const& M2 = R2;
+
+        assert(M1.is_equal(M2) == false);
+        assert(P1.checkIsEqualCalledEq(1));
+        assert(P2.checkIsEqualCalledEq(0));
+
+        assert(M2.is_equal(M1) == false);
+        assert(P2.checkIsEqualCalledEq(1));
+        assert(P1.checkIsEqualCalledEq(1));
+    }
+    {
+        TestResource1 R1(1);
+        auto& P1 = R1.getController();
+        memory_resource const& M1 = R1;
+
+        TestResource1 R2(2);
+        auto& P2 = R2.getController();
+        memory_resource const& M2 = R2;
+
+        assert(M1.is_equal(M2) == false);
+        assert(P1.checkIsEqualCalledEq(1));
+        assert(P2.checkIsEqualCalledEq(0));
+
+        assert(M2.is_equal(M1) == false);
+        assert(P2.checkIsEqualCalledEq(1));
+        assert(P1.checkIsEqualCalledEq(1));
+    }
+    {
+        TestResource1 R1(1);
+        auto& P1 = R1.getController();
+        memory_resource const& M1 = R1;
+
+        TestResource1 R2(1);
+        auto& P2 = R2.getController();
+        memory_resource const& M2 = R2;
+
+        assert(M1.is_equal(M2) == true);
+        assert(P1.checkIsEqualCalledEq(1));
+        assert(P2.checkIsEqualCalledEq(0));
+
+        assert(M2.is_equal(M1) == true);
+        assert(P2.checkIsEqualCalledEq(1));
+        assert(P1.checkIsEqualCalledEq(1));
+    }
+}
diff --git a/src/experimental/placeholder.cpp b/test/std/experimental/memory/nothing_to_do.pass.cpp
similarity index 64%
copy from src/experimental/placeholder.cpp
copy to test/std/experimental/memory/nothing_to_do.pass.cpp
index 998330b..9a59227 100644
--- a/src/experimental/placeholder.cpp
+++ b/test/std/experimental/memory/nothing_to_do.pass.cpp
@@ -1,4 +1,5 @@
-//===--------------------------- TODO.cpp ---------------------------------===//
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -7,8 +8,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "experimental/__config"
-
-_LIBCPP_BEGIN_NAMESPACE_LFTS
-
-_LIBCPP_END_NAMESPACE_LFTS
+int main()
+{
+}
diff --git a/test/support/test_memory_resource.hpp b/test/support/test_memory_resource.hpp
new file mode 100644
index 0000000..88fb41d
--- /dev/null
+++ b/test/support/test_memory_resource.hpp
@@ -0,0 +1,506 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SUPPORT_TEST_MEMORY_RESOURCE_HPP
+#define SUPPORT_TEST_MEMORY_RESOURCE_HPP
+
+#include <experimental/memory_resource>
+#include <memory>
+#include <type_traits>
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <cassert>
+#include "test_macros.h"
+
+struct AllocController;
+    // 'AllocController' is a concrete type that instruments and controls the
+    // behavior of of test allocators.
+
+template <class T>
+class CountingAllocator;
+    // 'CountingAllocator' is an basic implementation of the 'Allocator'
+    // requirements that use the 'AllocController' interface.
+
+template <class T>
+class MinAlignAllocator;
+    // 'MinAlignAllocator' is an instrumented test type which implements the
+    // 'Allocator' requirements. 'MinAlignAllocator' ensures that it *never*
+    // returns a pointer to over-aligned storage. For example
+    // 'MinAlignPointer<char>{}.allocate(...)' will never a 2-byte aligned
+    // pointer.
+
+template <class T>
+class NullAllocator;
+    // 'NullAllocator' is an instrumented test type which implements the
+    // 'Allocator' requirements except that 'allocator' and 'deallocate' are
+    // nops.
+
+
+#define DISALLOW_COPY(Type) \
+  Type(Type const&) = delete; \
+  Type& operator=(Type const&) = delete
+
+constexpr std::size_t MaxAlignV = alignof(std::max_align_t);
+
+struct TestException {};
+
+struct AllocController {
+    int copy_constructed = 0;
+    int move_constructed = 0;
+
+    int alive = 0;
+    int alloc_count = 0;
+    int dealloc_count = 0;
+    int is_equal_count = 0;
+
+    std::size_t alive_size;
+    std::size_t allocated_size;
+    std::size_t deallocated_size;
+
+    std::size_t last_size = 0;
+    std::size_t last_align = 0;
+    void * last_pointer = 0;
+
+    std::size_t last_alloc_size = 0;
+    std::size_t last_alloc_align = 0;
+    void * last_alloc_pointer = nullptr;
+
+    std::size_t last_dealloc_size = 0;
+    std::size_t last_dealloc_align = 0;
+    void * last_dealloc_pointer = nullptr;
+
+    bool throw_on_alloc = false;
+
+    AllocController() = default;
+
+    void countAlloc(void* p, size_t s, size_t a) {
+        ++alive;
+        ++alloc_count;
+        alive_size += s;
+        allocated_size += s;
+        last_pointer = last_alloc_pointer = p;
+        last_size = last_alloc_size = s;
+        last_align = last_alloc_align = a;
+    }
+
+    void countDealloc(void* p, size_t s, size_t a) {
+        --alive;
+        ++dealloc_count;
+        alive_size -= s;
+        deallocated_size += s;
+        last_pointer = last_dealloc_pointer = p;
+        last_size = last_dealloc_size = s;
+        last_align = last_dealloc_align = a;
+    }
+
+    void reset() { std::memset(this, 0, sizeof(*this)); }
+
+public:
+    bool checkAlloc(void* p, size_t s, size_t a) const {
+        return p == last_alloc_pointer &&
+               s == last_alloc_size &&
+               a == last_alloc_align;
+    }
+
+    bool checkAlloc(void* p, size_t s) const {
+        return p == last_alloc_pointer &&
+               s == last_alloc_size;
+    }
+
+    bool checkAllocAtLeast(void* p, size_t s, size_t a) const {
+        return p == last_alloc_pointer &&
+               s <= last_alloc_size &&
+               a <= last_alloc_align;
+    }
+
+    bool checkAllocAtLeast(void* p, size_t s) const {
+        return p == last_alloc_pointer &&
+               s <= last_alloc_size;
+    }
+
+    bool checkDealloc(void* p, size_t s, size_t a) const {
+        return p == last_dealloc_pointer &&
+               s == last_dealloc_size &&
+               a == last_dealloc_align;
+    }
+
+    bool checkDealloc(void* p, size_t s) const {
+        return p == last_dealloc_pointer &&
+               s == last_dealloc_size;
+    }
+
+    bool checkDeallocMatchesAlloc() const {
+        return last_dealloc_pointer == last_alloc_pointer &&
+               last_dealloc_size == last_alloc_size &&
+               last_dealloc_align == last_alloc_align;
+    }
+
+    void countIsEqual() {
+        ++is_equal_count;
+    }
+
+    bool checkIsEqualCalledEq(int n) const {
+        return is_equal_count == n;
+    }
+private:
+  DISALLOW_COPY(AllocController);
+};
+
+template <class T>
+class CountingAllocator
+{
+public:
+    typedef T value_type;
+    typedef T* pointer;
+    CountingAllocator() = delete;
+    explicit CountingAllocator(AllocController& PP) : P(&PP) {}
+
+    CountingAllocator(CountingAllocator const& other) : P(other.P) {
+        P->copy_constructed += 1;
+    }
+
+    CountingAllocator(CountingAllocator&& other) : P(other.P) {
+        P->move_constructed += 1;
+    }
+
+    template <class U>
+    CountingAllocator(CountingAllocator<U> const& other) TEST_NOEXCEPT : P(other.P) {
+        P->copy_constructed += 1;
+    }
+
+    template <class U>
+    CountingAllocator(CountingAllocator<U>&& other) TEST_NOEXCEPT : P(other.P) {
+        P->move_constructed += 1;
+    }
+
+    T* allocate(std::size_t n)
+    {
+        void* ret = ::operator new(n*sizeof(T));
+        P->countAlloc(ret, n*sizeof(T), alignof(T));
+        return static_cast<T*>(ret);
+    }
+
+    void deallocate(T* p, std::size_t n)
+    {
+        void* vp = static_cast<void*>(p);
+        P->countDealloc(vp, n*sizeof(T), alignof(T));
+        ::operator delete(vp);
+    }
+
+    AllocController& getController() const { return *P; }
+
+private:
+    template <class Tp> friend class CountingAllocator;
+    AllocController *P;
+};
+
+template <class T, class U>
+inline bool operator==(CountingAllocator<T> const& x,
+                       CountingAllocator<U> const& y) {
+    return &x.getController() == &y.getController();
+}
+
+template <class T, class U>
+inline bool operator!=(CountingAllocator<T> const& x,
+                       CountingAllocator<U> const& y) {
+    return !(x == y);
+}
+
+template <class T>
+class MinAlignedAllocator
+{
+public:
+    typedef T value_type;
+    typedef T* pointer;
+
+    MinAlignedAllocator() = delete;
+
+    explicit MinAlignedAllocator(AllocController& R) : P(&R) {}
+
+    MinAlignedAllocator(MinAlignedAllocator const& other) : P(other.P) {
+        P->copy_constructed += 1;
+    }
+
+    MinAlignedAllocator(MinAlignedAllocator&& other) : P(other.P) {
+        P->move_constructed += 1;
+    }
+
+    template <class U>
+    MinAlignedAllocator(MinAlignedAllocator<U> const& other) TEST_NOEXCEPT : P(other.P) {
+        P->copy_constructed += 1;
+    }
+
+    template <class U>
+    MinAlignedAllocator(MinAlignedAllocator<U>&& other) TEST_NOEXCEPT : P(other.P) {
+        P->move_constructed += 1;
+    }
+
+    T* allocate(std::size_t n) {
+        char* aligned_ptr = (char*)::operator new(alloc_size(n*sizeof(T)));
+        assert(is_max_aligned(aligned_ptr));
+
+        char* unaligned_ptr = aligned_ptr + alignof(T);
+        assert(is_min_aligned(unaligned_ptr));
+
+        P->countAlloc(unaligned_ptr, n * sizeof(T), alignof(T));
+
+        return ((T*)unaligned_ptr);
+    }
+
+    void deallocate(T* p, std::size_t n) {
+        assert(is_min_aligned(p));
+
+        char* aligned_ptr = ((char*)p) - alignof(T);
+        assert(is_max_aligned(aligned_ptr));
+
+        P->countDealloc(p, n*sizeof(T), alignof(T));
+
+        return ::operator delete(static_cast<void*>(aligned_ptr));
+    }
+
+    AllocController& getController() const { return *P; }
+
+private:
+    static const std::size_t BlockSize = alignof(std::max_align_t);
+
+    static std::size_t alloc_size(std::size_t s) {
+        std::size_t bytes = (s + BlockSize - 1) & ~(BlockSize - 1);
+        bytes += BlockSize;
+        assert(bytes % BlockSize == 0);
+        return bytes / BlockSize;
+    }
+
+    static bool is_max_aligned(void* p) {
+        return reinterpret_cast<std::size_t>(p) % BlockSize == 0;
+    }
+
+    static bool is_min_aligned(void* p) {
+        if (alignof(T) == BlockSize) {
+            return is_max_aligned(p);
+        } else {
+            return reinterpret_cast<std::size_t>(p) % BlockSize == alignof(T);
+        }
+    }
+
+    template <class Tp> friend class MinAlignedAllocator;
+    mutable AllocController *P;
+};
+
+
+template <class T, class U>
+inline bool operator==(MinAlignedAllocator<T> const& x,
+                       MinAlignedAllocator<U> const& y) {
+    return &x.getController() == &y.getController();
+}
+
+template <class T, class U>
+inline bool operator!=(MinAlignedAllocator<T> const& x,
+                       MinAlignedAllocator<U> const& y) {
+    return !(x == y);
+}
+
+template <class T>
+class NullAllocator
+{
+public:
+    typedef T value_type;
+    typedef T* pointer;
+    NullAllocator() = delete;
+    explicit NullAllocator(AllocController& PP) : P(&PP) {}
+
+    NullAllocator(NullAllocator const& other) : P(other.P) {
+        P->copy_constructed += 1;
+    }
+
+    NullAllocator(NullAllocator&& other) : P(other.P) {
+        P->move_constructed += 1;
+    }
+
+    template <class U>
+    NullAllocator(NullAllocator<U> const& other) TEST_NOEXCEPT : P(other.P) {
+        P->copy_constructed += 1;
+    }
+
+    template <class U>
+    NullAllocator(NullAllocator<U>&& other) TEST_NOEXCEPT : P(other.P) {
+        P->move_constructed += 1;
+    }
+
+    T* allocate(std::size_t n)
+    {
+        P->countAlloc(nullptr, n*sizeof(T), alignof(T));
+        return nullptr;
+    }
+
+    void deallocate(T* p, std::size_t n)
+    {
+        void* vp = static_cast<void*>(p);
+        P->countDealloc(vp, n*sizeof(T), alignof(T));
+    }
+
+    AllocController& getController() const { return *P; }
+
+private:
+    template <class Tp> friend class NullAllocator;
+    AllocController *P;
+};
+
+template <class T, class U>
+inline bool operator==(NullAllocator<T> const& x,
+                       NullAllocator<U> const& y) {
+    return &x.getController() == &y.getController();
+}
+
+template <class T, class U>
+inline bool operator!=(NullAllocator<T> const& x,
+                       NullAllocator<U> const& y) {
+    return !(x == y);
+}
+
+
+
+template <class ProviderT, int = 0>
+class TestResourceImp : public std::experimental::pmr::memory_resource
+{
+public:
+    static int resource_alive;
+    static int resource_constructed;
+    static int resource_destructed;
+
+    static void resetStatics() {
+        assert(resource_alive == 0);
+        resource_alive = 0;
+        resource_constructed = 0;
+        resource_destructed = 0;
+    }
+
+    using memory_resource = std::experimental::pmr::memory_resource;
+    using Provider = ProviderT;
+
+    int value;
+
+    explicit TestResourceImp(int val = 0) : value(val) {
+        ++resource_alive;
+        ++resource_constructed;
+    }
+
+    ~TestResourceImp() noexcept {
+        --resource_alive;
+        ++resource_destructed;
+    }
+
+    void reset() { C.reset(); P.reset(); }
+    AllocController& getController() { return C; }
+
+    bool checkAlloc(void* p, std::size_t s, std::size_t a) const
+      { return C.checkAlloc(p, s, a); }
+
+    bool checkDealloc(void* p, std::size_t s, std::size_t a) const
+      { return C.checkDealloc(p, s, a); }
+
+    bool checkIsEqualCalledEq(int n) const { return C.checkIsEqualCalledEq(n); }
+
+protected:
+    virtual void * do_allocate(std::size_t s, std::size_t a) {
+        if (C.throw_on_alloc) {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+            throw TestException{};
+#else
+            assert(false);
+#endif
+        }
+        void* ret = P.allocate(s, a);
+        C.countAlloc(ret, s, a);
+        return ret;
+    }
+
+    virtual void do_deallocate(void * p, std::size_t s, std::size_t a) {
+        C.countDealloc(p, s, a);
+        P.deallocate(p, s, a);
+    }
+
+    virtual bool do_is_equal(memory_resource const & other) const noexcept {
+        C.countIsEqual();
+        TestResourceImp const * o = dynamic_cast<TestResourceImp const *>(&other);
+        return o && o->value == value;
+    }
+private:
+    mutable AllocController C;
+    mutable Provider P;
+    DISALLOW_COPY(TestResourceImp);
+};
+
+template <class Provider, int N>
+int TestResourceImp<Provider, N>::resource_alive = 0;
+
+template <class Provider, int N>
+int TestResourceImp<Provider, N>::resource_constructed = 0;
+
+template <class Provider, int N>
+int TestResourceImp<Provider, N>::resource_destructed = 0;
+
+
+struct NullProvider {
+    NullProvider() {}
+    void* allocate(size_t, size_t) { return nullptr; }
+    void deallocate(void*, size_t, size_t) {}
+    void reset() {}
+private:
+    DISALLOW_COPY(NullProvider);
+};
+
+struct NewDeleteProvider {
+    NewDeleteProvider() {}
+    void* allocate(size_t s, size_t) { return ::operator new(s); }
+    void deallocate(void* p, size_t, size_t) { ::operator delete(p); }
+    void reset() {}
+private:
+    DISALLOW_COPY(NewDeleteProvider);
+};
+
+template <size_t Size = 4096 * 10> // 10 pages worth of memory.
+struct BufferProvider {
+    char buffer[Size];
+    void* next = &buffer;
+    size_t space = Size;
+
+    BufferProvider() {}
+
+    void* allocate(size_t s, size_t a) {
+        void* ret = std::align(s, a, next, space);
+        if (ret == nullptr) {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+            throw std::bad_alloc();
+#else
+            assert(false);
+#endif
+        }
+
+        return ret;
+    }
+
+    void deallocate(void*, size_t, size_t) {}
+
+    void reset() {
+        next = &buffer;
+        space = Size;
+    }
+private:
+    DISALLOW_COPY(BufferProvider);
+};
+
+using NullResource = TestResourceImp<NullProvider, 0>;
+using NewDeleteResource = TestResourceImp<NewDeleteProvider, 0>;
+using TestResource  = TestResourceImp<BufferProvider<>, 0>;
+using TestResource1 = TestResourceImp<BufferProvider<>, 1>;
+using TestResource2 = TestResourceImp<BufferProvider<>, 2>;
+
+
+#endif /* SUPPORT_TEST_MEMORY_RESOURCE_HPP */
diff --git a/test/support/type_id.h b/test/support/type_id.h
new file mode 100644
index 0000000..309f088
--- /dev/null
+++ b/test/support/type_id.h
@@ -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.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SUPPORT_TYPE_ID_H
+#define SUPPORT_TYPE_ID_H
+
+#include <functional>
+#include <cassert>
+
+#include "test_macros.h"
+
+#if TEST_STD_VER < 11
+#error This header requires C++11 or greater
+#endif
+
+// TypeID - Represent a unique identifier for a type. TypeID allows equality
+// comparisons between different types.
+struct TypeID {
+  friend bool operator==(TypeID const& LHS, TypeID const& RHS)
+  {return LHS.m_id == RHS.m_id; }
+  friend bool operator!=(TypeID const& LHS, TypeID const& RHS)
+  {return LHS.m_id != RHS.m_id; }
+private:
+  explicit constexpr TypeID(const int* xid) : m_id(xid) {}
+
+  TypeID(const TypeID&) = delete;
+  TypeID& operator=(TypeID const&) = delete;
+
+  const int* const m_id;
+  template <class T> friend TypeID const& makeTypeID();
+
+};
+
+// makeTypeID - Return the TypeID for the specified type 'T'.
+template <class T>
+inline TypeID const& makeTypeID() {
+  static int dummy;
+  static const TypeID id(&dummy);
+  return id;
+}
+
+template <class ...Args>
+struct ArgumentListID {};
+
+// makeArgumentID - Create and return a unique identifier for a given set
+// of arguments.
+template <class ...Args>
+inline  TypeID const& makeArgumentID() {
+  return makeTypeID<ArgumentListID<Args...>>();
+}
+
+#endif // SUPPORT_TYPE_ID_H
diff --git a/test/support/uses_alloc_types.hpp b/test/support/uses_alloc_types.hpp
new file mode 100644
index 0000000..f68b842
--- /dev/null
+++ b/test/support/uses_alloc_types.hpp
@@ -0,0 +1,298 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef USES_ALLOC_TYPES_HPP
+#define USES_ALLOC_TYPES_HPP
+
+# include <experimental/memory_resource>
+# include <experimental/utility>
+# include <memory>
+# include <cassert>
+
+#include "test_memory_resource.hpp"
+#include "type_id.h"
+
+// There are two forms of uses-allocator construction:
+//   (1) UA_AllocArg: 'T(allocator_arg_t, Alloc const&, Args&&...)'
+//   (2) UA_AllocLast: 'T(Args&&..., Alloc const&)'
+// 'UA_None' represents non-uses allocator construction.
+enum class UsesAllocatorType {
+  UA_None = 0,
+  UA_AllocArg = 2,
+  UA_AllocLast = 4
+};
+constexpr UsesAllocatorType UA_None = UsesAllocatorType::UA_None;
+constexpr UsesAllocatorType UA_AllocArg = UsesAllocatorType::UA_AllocArg;
+constexpr UsesAllocatorType UA_AllocLast = UsesAllocatorType::UA_AllocLast;
+
+template <class Alloc, std::size_t N>
+class UsesAllocatorV1;
+    // Implements form (1) of uses-allocator construction from the specified
+    // 'Alloc' type and exactly 'N' additional arguments. It also provides
+    // non-uses allocator construction from 'N' arguments. This test type
+    // blows up when form (2) of uses-allocator is even considered.
+
+template <class Alloc, std::size_t N>
+class UsesAllocatorV2;
+    // Implements form (2) of uses-allocator construction from the specified
+    // 'Alloc' type and exactly 'N' additional arguments. It also provides
+    // non-uses allocator construction from 'N' arguments.
+
+template <class Alloc, std::size_t N>
+class UsesAllocatorV3;
+    // Implements both form (1) and (2) of uses-allocator construction from
+    // the specified 'Alloc' type and exactly 'N' additional arguments. It also
+    // provides non-uses allocator construction from 'N' arguments.
+
+template <class Alloc, std::size_t>
+class NotUsesAllocator;
+    // Implements both form (1) and (2) of uses-allocator construction from
+    // the specified 'Alloc' type and exactly 'N' additional arguments. It also
+    // provides non-uses allocator construction from 'N' arguments. However
+    // 'NotUsesAllocator' never provides a 'allocator_type' typedef so it is
+    // never automatically uses-allocator constructed.
+
+
+template <class ...ArgTypes, class TestType>
+bool checkConstruct(TestType& value, UsesAllocatorType form,
+                    typename TestType::CtorAlloc const& alloc)
+    // Check that 'value' was constructed using the specified 'form' of
+    // construction and with the specified 'ArgTypes...'. Additionally
+    // check that 'value' was constructed using the specified 'alloc'.
+{
+    if (form == UA_None) {
+        return value.template checkConstruct<ArgTypes&&...>(form);
+    } else {
+        return value.template checkConstruct<ArgTypes&&...>(form, alloc);
+    }
+}
+
+
+template <class ...ArgTypes, class TestType>
+bool checkConstruct(TestType& value, UsesAllocatorType form) {
+    return value.template checkConstruct<ArgTypes&&...>(form);
+}
+
+template <class TestType>
+bool checkConstructionEquiv(TestType& T, TestType& U)
+    // check that 'T' and 'U' where initialized in the exact same manner.
+{
+    return T.checkConstructEquiv(U);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+namespace detail {
+
+template <bool IsZero, size_t N, class ArgList, class ...Args>
+struct TakeNImp;
+
+template <class ArgList, class ...Args>
+struct TakeNImp<true, 0, ArgList, Args...> {
+  typedef ArgList type;
+};
+
+template <size_t N, class ...A1, class F, class ...R>
+struct TakeNImp<false, N, ArgumentListID<A1...>, F, R...>
+    : TakeNImp<N-1 == 0, N - 1, ArgumentListID<A1..., F>, R...> {};
+
+template <size_t N, class ...Args>
+struct TakeNArgs : TakeNImp<N == 0, N, ArgumentListID<>, Args...> {};
+
+template <class T>
+struct Identity { typedef T type; };
+
+template <class T>
+using IdentityT = typename Identity<T>::type;
+
+template <bool Value>
+using EnableIfB = typename std::enable_if<Value, bool>::type;
+
+} // end namespace detail
+
+using detail::EnableIfB;
+
+struct AllocLastTag {};
+
+template <class Alloc>
+struct UsesAllocatorTestBase {
+public:
+    using CtorAlloc = typename std::conditional<
+        std::is_same<Alloc, std::experimental::erased_type>::value,
+        std::experimental::pmr::memory_resource*,
+        Alloc
+    >::type;
+
+    template <class ...ArgTypes>
+    bool checkConstruct(UsesAllocatorType expectType) const {
+        return expectType == constructor_called &&
+               makeArgumentID<ArgTypes...>() == *args_id;
+    }
+
+    template <class ...ArgTypes>
+    bool checkConstruct(UsesAllocatorType expectType,
+                        CtorAlloc const& expectAlloc) const {
+        return expectType == constructor_called &&
+               makeArgumentID<ArgTypes...>() == *args_id &&
+               expectAlloc == allocator;
+    }
+
+    bool checkConstructEquiv(UsesAllocatorTestBase& O) const {
+        return constructor_called == O.constructor_called
+            && *args_id == *O.args_id
+            && allocator == O.allocator;
+    }
+
+protected:
+    explicit UsesAllocatorTestBase(const TypeID* aid)
+        : args_id(aid), constructor_called(UA_None), allocator()
+    {}
+
+    template <class ...Args>
+    UsesAllocatorTestBase(std::allocator_arg_t, CtorAlloc const& a, Args&&...)
+        : args_id(&makeArgumentID<Args&&...>()),
+          constructor_called(UA_AllocArg),
+          allocator(a)
+    {}
+
+    template <class ...Args>
+    UsesAllocatorTestBase(AllocLastTag, Args&&... args)
+        : args_id(nullptr),
+          constructor_called(UA_AllocLast)
+    {
+        typedef typename detail::TakeNArgs<sizeof...(Args) - 1, Args&&...>::type
+            ArgIDL;
+        args_id = &makeTypeID<ArgIDL>();
+        getAllocatorFromPack(ArgIDL{}, std::forward<Args>(args)...);
+    }
+
+private:
+    template <class ...LArgs, class ...Args>
+    void getAllocatorFromPack(ArgumentListID<LArgs...>, Args&&... args) {
+        getAllocatorFromPackImp<LArgs const&...>(args...);
+    }
+
+    template <class ...LArgs>
+    void getAllocatorFromPackImp(typename detail::Identity<LArgs>::type..., CtorAlloc const& alloc) {
+        allocator = alloc;
+    }
+
+    const TypeID* args_id;
+    UsesAllocatorType constructor_called = UA_None;
+    CtorAlloc allocator;
+};
+
+template <class Alloc, size_t Arity>
+class UsesAllocatorV1 : public UsesAllocatorTestBase<Alloc>
+{
+public:
+    typedef Alloc allocator_type;
+
+    using Base = UsesAllocatorTestBase<Alloc>;
+    using CtorAlloc = typename Base::CtorAlloc;
+
+    UsesAllocatorV1() : Base(&makeArgumentID<>()) {}
+
+    // Non-Uses Allocator Ctor
+    template <class ...Args, EnableIfB<sizeof...(Args) == Arity> = false>
+    UsesAllocatorV1(Args&&... args) : Base(&makeArgumentID<Args&&...>()) {};
+
+    // Uses Allocator Arg Ctor
+    template <class ...Args>
+    UsesAllocatorV1(std::allocator_arg_t tag, CtorAlloc const & a, Args&&... args)
+        : Base(tag, a, std::forward<Args>(args)...)
+    { }
+
+    // BLOWS UP: Uses Allocator Last Ctor
+    template <class _First, class ...Args, EnableIfB<sizeof...(Args) == Arity> _Dummy = false>
+    constexpr UsesAllocatorV1(_First&& __first, Args&&... args)
+    {
+        static_assert(!std::is_same<_First, _First>::value, "");
+    }
+};
+
+
+template <class Alloc, size_t Arity>
+class UsesAllocatorV2 : public UsesAllocatorTestBase<Alloc>
+{
+public:
+    typedef Alloc allocator_type;
+
+    using Base = UsesAllocatorTestBase<Alloc>;
+    using CtorAlloc = typename Base::CtorAlloc;
+
+    UsesAllocatorV2() : Base(&makeArgumentID<>()) {}
+
+    // Non-Uses Allocator Ctor
+    template <class ...Args, EnableIfB<sizeof...(Args) == Arity> = false>
+    UsesAllocatorV2(Args&&... args) : Base(&makeArgumentID<Args&&...>()) {};
+
+    // Uses Allocator Last Ctor
+    template <class ...Args, EnableIfB<sizeof...(Args) == Arity + 1> = false>
+    UsesAllocatorV2(Args&&... args)
+        : Base(AllocLastTag{}, std::forward<Args>(args)...)
+    {}
+};
+
+template <class Alloc, size_t Arity>
+class UsesAllocatorV3 : public UsesAllocatorTestBase<Alloc>
+{
+public:
+    typedef Alloc allocator_type;
+
+    using Base = UsesAllocatorTestBase<Alloc>;
+    using CtorAlloc = typename Base::CtorAlloc;
+
+    UsesAllocatorV3() : Base(&makeArgumentID<>()) {}
+
+    // Non-Uses Allocator Ctor
+    template <class ...Args, EnableIfB<sizeof...(Args) == Arity> = false>
+    UsesAllocatorV3(Args&&... args) : Base(&makeArgumentID<Args&&...>()) {};
+
+    // Uses Allocator Arg Ctor
+    template <class ...Args>
+    UsesAllocatorV3(std::allocator_arg_t tag, CtorAlloc const& alloc, Args&&... args)
+        : Base(tag, alloc, std::forward<Args>(args)...)
+    {}
+
+    // Uses Allocator Last Ctor
+    template <class ...Args, EnableIfB<sizeof...(Args) == Arity + 1> = false>
+    UsesAllocatorV3(Args&&... args)
+        : Base(AllocLastTag{}, std::forward<Args>(args)...)
+    {}
+};
+
+template <class Alloc, size_t Arity>
+class NotUsesAllocator : public UsesAllocatorTestBase<Alloc>
+{
+public:
+    // no allocator_type typedef provided
+
+    using Base = UsesAllocatorTestBase<Alloc>;
+    using CtorAlloc = typename Base::CtorAlloc;
+
+    NotUsesAllocator() : Base(&makeArgumentID<>()) {}
+
+    // Non-Uses Allocator Ctor
+    template <class ...Args, EnableIfB<sizeof...(Args) == Arity> = false>
+    NotUsesAllocator(Args&&... args) : Base(&makeArgumentID<Args&&...>()) {};
+
+    // Uses Allocator Arg Ctor
+    template <class ...Args>
+    NotUsesAllocator(std::allocator_arg_t tag, CtorAlloc const& alloc, Args&&... args)
+        : Base(tag, alloc, std::forward<Args>(args)...)
+    {}
+
+    // Uses Allocator Last Ctor
+    template <class ...Args, EnableIfB<sizeof...(Args) == Arity + 1> = false>
+    NotUsesAllocator(Args&&... args)
+        : Base(AllocLastTag{}, std::forward<Args>(args)...)
+    {}
+};
+
+#endif /* USES_ALLOC_TYPES_HPP */