[libcxx-commits] [libcxx] 7a62bee - [libc++] Implement std::experimental::observer_ptr

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Sun Nov 5 17:01:45 PST 2023


Author: Zoe Carver
Date: 2023-11-05T17:59:04-07:00
New Revision: 7a62bee611f1c451fa026c146b03a3a277a5a1dd

URL: https://github.com/llvm/llvm-project/commit/7a62bee611f1c451fa026c146b03a3a277a5a1dd
DIFF: https://github.com/llvm/llvm-project/commit/7a62bee611f1c451fa026c146b03a3a277a5a1dd.diff

LOG: [libc++] Implement std::experimental::observer_ptr

This patch adds std::experimental::observer_ptr (n4282) and also
fixes LWG2516.

Co-Authored-By: Louis Dionne <ldionne.2 at gmail.com>
Differential Revision: https://reviews.llvm.org/D63230

Added: 
    libcxx/include/experimental/memory
    libcxx/test/std/experimental/memory/memory.observer.ptr/compare.pass.cpp
    libcxx/test/std/experimental/memory/memory.observer.ptr/ctor.convert.pass.cpp
    libcxx/test/std/experimental/memory/memory.observer.ptr/ctor.copy_move.cpp
    libcxx/test/std/experimental/memory/memory.observer.ptr/ctor.default.pass.cpp
    libcxx/test/std/experimental/memory/memory.observer.ptr/ctor.element_type.pass.cpp
    libcxx/test/std/experimental/memory/memory.observer.ptr/ctor.nullptr.pass.cpp
    libcxx/test/std/experimental/memory/memory.observer.ptr/deref.pass.cpp
    libcxx/test/std/experimental/memory/memory.observer.ptr/get.pass.cpp
    libcxx/test/std/experimental/memory/memory.observer.ptr/hash.pass.cpp
    libcxx/test/std/experimental/memory/memory.observer.ptr/make_observer.pass.cpp
    libcxx/test/std/experimental/memory/memory.observer.ptr/operator-bool.pass.cpp
    libcxx/test/std/experimental/memory/memory.observer.ptr/operator-element_type.pass.cpp
    libcxx/test/std/experimental/memory/memory.observer.ptr/release.pass.cpp
    libcxx/test/std/experimental/memory/memory.observer.ptr/reset.pass.cpp
    libcxx/test/std/experimental/memory/memory.observer.ptr/swap.pass.cpp
    libcxx/test/std/experimental/memory/memory.observer.ptr/types.compile.pass.cpp

Modified: 
    libcxx/docs/Status/Cxx17Issues.csv
    libcxx/include/CMakeLists.txt
    libcxx/include/__std_clang_module
    libcxx/include/module.modulemap.in
    libcxx/test/libcxx/transitive_includes/cxx03.csv
    libcxx/test/libcxx/transitive_includes/cxx11.csv
    libcxx/test/libcxx/transitive_includes/cxx14.csv
    libcxx/test/libcxx/transitive_includes/cxx17.csv
    libcxx/test/libcxx/transitive_includes/cxx20.csv
    libcxx/test/libcxx/transitive_includes/cxx23.csv
    libcxx/test/libcxx/transitive_includes/cxx26.csv

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Status/Cxx17Issues.csv b/libcxx/docs/Status/Cxx17Issues.csv
index bc231c8e8a1b42f..ebe59ddc89fa881 100644
--- a/libcxx/docs/Status/Cxx17Issues.csv
+++ b/libcxx/docs/Status/Cxx17Issues.csv
@@ -143,7 +143,7 @@
 "`2441 <https://wg21.link/LWG2441>`__","Exact-width atomic typedefs should be provided","Oulu","|Complete|",""
 "`2451 <https://wg21.link/LWG2451>`__","[fund.ts.v2] optional should 'forward' T's implicit conversions","Oulu","|Nothing To Do|",""
 "`2509 <https://wg21.link/LWG2509>`__","[fund.ts.v2] any_cast doesn't work with rvalue reference targets and cannot move with a value target","Oulu","|Complete|",""
-"`2516 <https://wg21.link/LWG2516>`__","[fund.ts.v2] Public ""exposition only"" members in observer_ptr","Oulu","",""
+"`2516 <https://wg21.link/LWG2516>`__","[fund.ts.v2] Public ""exposition only"" members in observer_ptr","Oulu","|Complete|","18.0"
 "`2542 <https://wg21.link/LWG2542>`__","Missing const requirements for associative containers","Oulu","",""
 "`2549 <https://wg21.link/LWG2549>`__","Tuple EXPLICIT constructor templates that take tuple parameters end up taking references to temporaries and will create dangling references","Oulu","|Complete|",""
 "`2550 <https://wg21.link/LWG2550>`__","Wording of unordered container's clear() method complexity","Oulu","|Complete|",""

diff  --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index b7b14200498a298..5e8c1700ee4cdad 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -925,6 +925,7 @@ set(files
   experimental/iterator
   experimental/list
   experimental/map
+  experimental/memory
   experimental/memory_resource
   experimental/propagate_const
   experimental/regex

diff  --git a/libcxx/include/__std_clang_module b/libcxx/include/__std_clang_module
index e2e9e85ffc7d8d6..c4bfe8259c74a3a 100644
--- a/libcxx/include/__std_clang_module
+++ b/libcxx/include/__std_clang_module
@@ -91,6 +91,7 @@
 #include <experimental/iterator>
 #include <experimental/list>
 #include <experimental/map>
+#include <experimental/memory>
 #include <experimental/memory_resource>
 #include <experimental/propagate_const>
 #if !defined(_LIBCPP_HAS_NO_LOCALIZATION)

diff  --git a/libcxx/include/experimental/memory b/libcxx/include/experimental/memory
new file mode 100644
index 000000000000000..9de57072759c70d
--- /dev/null
+++ b/libcxx/include/experimental/memory
@@ -0,0 +1,194 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP_EXPERIMENTAL_MEMORY
+#define _LIBCPP_EXPERIMENTAL_MEMORY
+
+/*
+    experimental/memory synopsis
+
+namespace std::experimental::inline fundamentals_v2  {
+
+template <class W> class observer_ptr {
+public:
+    using element_type = W;
+    using pointer = add_pointer_t<W>; // exposition-only
+    using reference = add_lvalue_reference_t<W>; // exposition-only
+
+    // default ctor
+    constexpr observer_ptr() noexcept;
+
+    // pointer-accepting ctors
+    constexpr observer_ptr(nullptr_t) noexcept;
+    constexpr explicit observer_ptr(pointer) noexcept;
+
+    // copying ctors (in addition to compiler-generated copy ctor)
+    template <class W2> constexpr observer_ptr(observer_ptr<W2>) noexcept;
+
+    // observers
+    constexpr pointer get() const noexcept;
+    constexpr reference operator*() const;
+    constexpr pointer operator->() const noexcept;
+    constexpr explicit operator bool() const noexcept;
+
+    // conversions
+    constexpr explicit operator pointer() const noexcept;
+
+    // modifiers
+    constexpr pointer release() noexcept;
+    constexpr void reset(pointer = nullptr) noexcept;
+    constexpr void swap(observer_ptr&) noexcept;
+};
+
+}
+*/
+
+#include <__functional/hash.h>
+#include <__functional/operations.h>
+#include <__type_traits/add_lvalue_reference.h>
+#include <__type_traits/add_pointer.h>
+#include <__type_traits/common_type.h>
+#include <__type_traits/enable_if.h>
+#include <__type_traits/is_convertible.h>
+#include <cstddef>
+#include <experimental/__config>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+#ifdef _LIBCPP_ENABLE_EXPERIMENTAL
+
+_LIBCPP_BEGIN_NAMESPACE_LFTS_V2
+
+#  if _LIBCPP_STD_VER >= 17
+
+template <class _Wp>
+class observer_ptr {
+public:
+  using element_type = _Wp;
+
+  // constructors
+  _LIBCPP_HIDE_FROM_ABI constexpr observer_ptr() noexcept : __ptr_(nullptr) {}
+  _LIBCPP_HIDE_FROM_ABI constexpr observer_ptr(nullptr_t) noexcept : __ptr_(nullptr) {}
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit observer_ptr(element_type* __p) noexcept : __ptr_(__p) {}
+
+  template <class _W2, class = __enable_if_t<is_convertible<_W2*, _Wp*>::value>>
+  _LIBCPP_HIDE_FROM_ABI constexpr observer_ptr(observer_ptr<_W2> __other) noexcept : __ptr_(__other.get()) {}
+
+  // observers
+  _LIBCPP_HIDE_FROM_ABI constexpr element_type* get() const noexcept { return __ptr_; }
+  _LIBCPP_HIDE_FROM_ABI constexpr add_lvalue_reference_t<_Wp> operator*() const { return *__ptr_; }
+  _LIBCPP_HIDE_FROM_ABI constexpr element_type* operator->() const noexcept { return __ptr_; }
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return __ptr_ != nullptr; }
+
+  // conversions
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit operator element_type*() const noexcept { return __ptr_; }
+
+  // modifiers
+  _LIBCPP_HIDE_FROM_ABI constexpr void reset(element_type* __p = nullptr) noexcept { __ptr_ = __p; }
+  _LIBCPP_HIDE_FROM_ABI constexpr void swap(observer_ptr& __other) noexcept {
+    observer_ptr __tmp = __other;
+    __other            = *this;
+    *this              = __tmp;
+  }
+  _LIBCPP_HIDE_FROM_ABI constexpr element_type* release() noexcept {
+    observer_ptr __p;
+    __p.swap(*this);
+    return __p.get();
+  }
+
+private:
+  element_type* __ptr_;
+};
+
+// specializations
+
+template <class _Wp>
+_LIBCPP_HIDE_FROM_ABI constexpr void swap(observer_ptr<_Wp>& __a, observer_ptr<_Wp>& __b) noexcept {
+  __a.swap(__b);
+}
+
+template <class _Wp>
+_LIBCPP_HIDE_FROM_ABI observer_ptr<_Wp> make_observer(_Wp* __ptr) noexcept {
+  return observer_ptr<_Wp>{__ptr};
+}
+
+template <class _W1, class _W2>
+_LIBCPP_HIDE_FROM_ABI bool operator==(observer_ptr<_W1> __a, observer_ptr<_W2> __b) {
+  return __a.get() == __b.get();
+}
+
+template <class _W1, class _W2>
+_LIBCPP_HIDE_FROM_ABI bool operator!=(observer_ptr<_W1> __a, observer_ptr<_W2> __b) {
+  return !(__a == __b);
+}
+
+template <class _Wp>
+_LIBCPP_HIDE_FROM_ABI bool operator==(observer_ptr<_Wp> __p, nullptr_t) {
+  return !__p;
+}
+
+template <class _Wp>
+_LIBCPP_HIDE_FROM_ABI bool operator==(nullptr_t, observer_ptr<_Wp> __p) {
+  return !__p;
+}
+
+template <class _Wp>
+_LIBCPP_HIDE_FROM_ABI bool operator!=(observer_ptr<_Wp> __p, nullptr_t) {
+  return (bool)__p;
+}
+
+template <class _Wp>
+_LIBCPP_HIDE_FROM_ABI bool operator!=(nullptr_t, observer_ptr<_Wp> __p) {
+  return (bool)__p;
+}
+
+template <class _W1, class _W2>
+_LIBCPP_HIDE_FROM_ABI bool operator<(observer_ptr<_W1> __a, observer_ptr<_W2> __b) {
+  return std::less<typename std::common_type<_W1*, _W2*>::type>()(__a.get(), __b.get());
+}
+
+template <class _W1, class _W2>
+_LIBCPP_HIDE_FROM_ABI bool operator>(observer_ptr<_W1> __a, observer_ptr<_W2> __b) {
+  return __b < __a;
+}
+
+template <class _W1, class _W2>
+_LIBCPP_HIDE_FROM_ABI bool operator<=(observer_ptr<_W1> __a, observer_ptr<_W2> __b) {
+  return !(__a > __b);
+}
+
+template <class _W1, class _W2>
+_LIBCPP_HIDE_FROM_ABI bool operator>=(observer_ptr<_W1> __a, observer_ptr<_W2> __b) {
+  return !(__a < __b);
+}
+
+#  endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_END_NAMESPACE_LFTS_V2
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+// hash
+
+#  if _LIBCPP_STD_VER >= 17
+template <class _Tp>
+struct hash<experimental::observer_ptr<_Tp>> {
+  _LIBCPP_HIDE_FROM_ABI size_t operator()(const experimental::observer_ptr<_Tp>& __ptr) const noexcept {
+    return hash<_Tp*>()(__ptr.get());
+  }
+};
+#  endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_ENABLE_EXPERIMENTAL
+
+#endif /* _LIBCPP_EXPERIMENTAL_MEMORY */

diff  --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index f447b2fa0a0ce94..17ebe48f329963d 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -533,6 +533,10 @@ module std_experimental [system] {
     header "experimental/map"
     export *
   }
+  module memory {
+    header "experimental/memory"
+    export *
+  }
   module memory_resource {
     header "experimental/memory_resource"
     export *

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv
index e41a3b290cf6ef5..0e7523b5420d43d 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx03.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv
@@ -241,6 +241,10 @@ experimental/list experimental/memory_resource
 experimental/list list
 experimental/map experimental/memory_resource
 experimental/map map
+experimental/memory cstddef
+experimental/memory cstdint
+experimental/memory cstring
+experimental/memory limits
 experimental/memory_resource atomic
 experimental/memory_resource climits
 experimental/memory_resource concepts

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv
index 4ac3dccc50040f8..08e7786d9b19435 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx11.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv
@@ -242,6 +242,10 @@ experimental/list experimental/memory_resource
 experimental/list list
 experimental/map experimental/memory_resource
 experimental/map map
+experimental/memory cstddef
+experimental/memory cstdint
+experimental/memory cstring
+experimental/memory limits
 experimental/memory_resource atomic
 experimental/memory_resource climits
 experimental/memory_resource concepts

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv
index 4f3fdfdd4d2cae5..37a6e5e853d27e7 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx14.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv
@@ -242,6 +242,10 @@ experimental/list experimental/memory_resource
 experimental/list list
 experimental/map experimental/memory_resource
 experimental/map map
+experimental/memory cstddef
+experimental/memory cstdint
+experimental/memory cstring
+experimental/memory limits
 experimental/memory_resource atomic
 experimental/memory_resource climits
 experimental/memory_resource concepts

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv
index 4f3fdfdd4d2cae5..37a6e5e853d27e7 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx17.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv
@@ -242,6 +242,10 @@ experimental/list experimental/memory_resource
 experimental/list list
 experimental/map experimental/memory_resource
 experimental/map map
+experimental/memory cstddef
+experimental/memory cstdint
+experimental/memory cstring
+experimental/memory limits
 experimental/memory_resource atomic
 experimental/memory_resource climits
 experimental/memory_resource concepts

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv
index 590a39e1b28e93f..5c9638fd467f214 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx20.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv
@@ -248,6 +248,10 @@ experimental/list experimental/memory_resource
 experimental/list list
 experimental/map experimental/memory_resource
 experimental/map map
+experimental/memory cstddef
+experimental/memory cstdint
+experimental/memory cstring
+experimental/memory limits
 experimental/memory_resource atomic
 experimental/memory_resource climits
 experimental/memory_resource concepts

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv
index aa6879026c90265..e1d489391c8de6c 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx23.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv
@@ -170,6 +170,10 @@ experimental/list experimental/memory_resource
 experimental/list list
 experimental/map experimental/memory_resource
 experimental/map map
+experimental/memory cstddef
+experimental/memory cstdint
+experimental/memory cstring
+experimental/memory limits
 experimental/memory_resource cstddef
 experimental/memory_resource experimental/utility
 experimental/memory_resource limits

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv
index aa6879026c90265..e1d489391c8de6c 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -170,6 +170,10 @@ experimental/list experimental/memory_resource
 experimental/list list
 experimental/map experimental/memory_resource
 experimental/map map
+experimental/memory cstddef
+experimental/memory cstdint
+experimental/memory cstring
+experimental/memory limits
 experimental/memory_resource cstddef
 experimental/memory_resource experimental/utility
 experimental/memory_resource limits

diff  --git a/libcxx/test/std/experimental/memory/memory.observer.ptr/compare.pass.cpp b/libcxx/test/std/experimental/memory/memory.observer.ptr/compare.pass.cpp
new file mode 100644
index 000000000000000..c6f70f6a2b1d1b3
--- /dev/null
+++ b/libcxx/test/std/experimental/memory/memory.observer.ptr/compare.pass.cpp
@@ -0,0 +1,179 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// REQUIRES: c++experimental
+
+// <experimental/memory>
+
+// observer_ptr
+//
+// template <class W1, class W2>
+// bool operator==(const observer_ptr<W1>& p1, const observer_ptr<W2>& p2);
+//
+// template <class W1, class W2>
+// bool operator!=(const observer_ptr<W1>& p1, const observer_ptr<W2>& p2);
+//
+// template <class W>
+// bool operator==(const observer_ptr<W>& p, std::nullptr_t) noexcept;
+//
+// template <class W>
+// bool operator==(std::nullptr_t, const observer_ptr<W>& p) noexcept;
+//
+// template <class W>
+// bool operator!=(const observer_ptr<W>& p, std::nullptr_t) noexcept;
+//
+// template <class W>
+// bool operator!=(std::nullptr_t, const observer_ptr<W>& p) noexcept;
+//
+// template <class W1, class W2>
+// bool operator<(const observer_ptr<W1>& p1, const observer_ptr<W2>& p2);
+//
+// template <class W1, class W2>
+// bool operator>(const observer_ptr<W1>& p1, const observer_ptr<W2>& p2);
+//
+// template <class W1, class W2>
+// bool operator<=(const observer_ptr<W1>& p1, const observer_ptr<W2>& p2);
+//
+// template <class W1, class W2>
+// bool operator>=(const observer_ptr<W1>& p1, const observer_ptr<W2>& p2);
+
+#include <experimental/memory>
+#include <cassert>
+
+void test() {
+  using T       = int;
+  using Ptr     = std::experimental::observer_ptr<T>;
+  using VoidPtr = std::experimental::observer_ptr<void>;
+
+  // operator==(observer_ptr, observer_ptr)
+  {
+    T obj1, obj2;
+    Ptr ptr1(&obj1), ptr1_x(&obj1);
+    Ptr ptr2(&obj2);
+    VoidPtr ptr3(&obj1);
+
+    assert(!(ptr1 == ptr2));
+    assert(ptr1 == ptr1_x);
+
+    assert(ptr1 == ptr3);
+  }
+
+  // operator!=(observer_ptr, observer_ptr)
+  {
+    T obj1, obj2;
+    Ptr ptr1(&obj1), ptr1_x(&obj1);
+    Ptr ptr2(&obj2);
+    VoidPtr ptr3(&obj1);
+
+    assert(ptr1 != ptr2);
+    assert(!(ptr1 != ptr1_x));
+
+    assert(ptr2 != ptr3);
+  }
+
+  // operator==(observer_ptr, nullptr_t)
+  {
+    T obj1;
+    Ptr ptr1(&obj1);
+    Ptr ptr2(nullptr);
+
+    assert(!(ptr1 == nullptr));
+    assert(ptr2 == nullptr);
+  }
+
+  // operator==(nullptr_t, observer_ptr)
+  {
+    T obj1;
+    Ptr ptr1(&obj1);
+    Ptr ptr2(nullptr);
+
+    assert(!(nullptr == ptr1));
+    assert(nullptr == ptr2);
+  }
+
+  // operator!=(observer_ptr, nullptr_t)
+  {
+    T obj1;
+    Ptr ptr1(&obj1);
+    Ptr ptr2(nullptr);
+
+    assert(ptr1 != nullptr);
+    assert(!(ptr2 != nullptr));
+  }
+
+  // operator!=(nullptr_t, observer_ptr)
+  {
+    T obj1;
+    Ptr ptr1(&obj1);
+    Ptr ptr2(nullptr);
+
+    assert(nullptr != ptr1);
+    assert(!(nullptr != ptr2));
+  }
+
+  // operator<(observer_ptr, observer_ptr)
+  {
+    T obj1, obj2;
+    Ptr ptr1(&obj1);
+    Ptr ptr2(&obj2);
+    VoidPtr ptr3(&obj1);
+
+    assert(!(ptr1 < ptr1));
+    assert((ptr1 < ptr2) == (&obj1 < &obj2));
+
+    assert(!(ptr1 < ptr3));
+  }
+
+  // operator>(observer_ptr, observer_ptr)
+  {
+    T obj1, obj2;
+    Ptr ptr1(&obj1);
+    Ptr ptr2(&obj2);
+    VoidPtr ptr3(&obj1);
+
+    assert(!(ptr1 > ptr1));
+    assert((ptr1 > ptr2) == (&obj1 > &obj2));
+
+    assert(!(ptr1 > ptr3));
+  }
+
+  // operator<=(observer_ptr, observer_ptr)
+  {
+    T obj1, obj2;
+    Ptr ptr1(&obj1);
+    Ptr ptr2(&obj2);
+    VoidPtr ptr3(&obj1);
+
+    assert(ptr1 <= ptr1);
+    assert((ptr1 <= ptr2) == (&obj1 <= &obj2));
+
+    assert(ptr1 <= ptr3);
+  }
+
+  // operator>=(observer_ptr, observer_ptr)
+  {
+    T obj1, obj2;
+    Ptr ptr1(&obj1);
+    Ptr ptr2(&obj2);
+    VoidPtr ptr3(&obj1);
+
+    assert(ptr1 >= ptr1);
+    assert((ptr1 >= ptr2) == (&obj1 >= &obj2));
+
+    assert(ptr1 >= ptr3);
+  }
+}
+
+int main(int, char**) {
+  // Note: this is not constexpr in the spec
+  test();
+
+  return 0;
+}
\ No newline at end of file

diff  --git a/libcxx/test/std/experimental/memory/memory.observer.ptr/ctor.convert.pass.cpp b/libcxx/test/std/experimental/memory/memory.observer.ptr/ctor.convert.pass.cpp
new file mode 100644
index 000000000000000..f0abba095569852
--- /dev/null
+++ b/libcxx/test/std/experimental/memory/memory.observer.ptr/ctor.convert.pass.cpp
@@ -0,0 +1,75 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// REQUIRES: c++experimental
+
+// <experimental/memory>
+
+// observer_ptr
+//
+// template <class W2>
+// constexpr observer_ptr(observer_ptr<W2> other) noexcept;
+
+#include <experimental/memory>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+
+template <class To, class From>
+constexpr void test_converting_ctor() {
+  using ToPtr   = std::experimental::observer_ptr<To>;
+  using FromPtr = std::experimental::observer_ptr<From>;
+  From obj;
+  FromPtr from(&obj);
+  ToPtr to = from;
+
+  assert(from.get() == &obj);
+  assert(to.get() == &obj);
+#if TEST_STD_VER >= 20
+  static_assert(std::is_nothrow_convertible<FromPtr, ToPtr>::value);
+#endif
+}
+
+template <class To, class From>
+constexpr void check_non_constructible() {
+  using ToPtr   = std::experimental::observer_ptr<To>;
+  using FromPtr = std::experimental::observer_ptr<From>;
+  static_assert(!std::is_constructible<ToPtr, FromPtr>::value);
+}
+
+struct Bar {};
+struct Base {};
+struct Derived : Base {};
+
+constexpr bool test() {
+  test_converting_ctor<void, Bar>();
+  test_converting_ctor<void, int>();
+  test_converting_ctor<Base, Derived>();
+
+  check_non_constructible<Derived, Base>();
+  check_non_constructible<int, void>();
+  check_non_constructible<Bar, void>();
+  check_non_constructible<int, long>();
+  check_non_constructible<long, int>();
+
+  // Check const-ness
+  check_non_constructible<Bar, Bar const>();
+  test_converting_ctor<Bar const, Bar>();
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/experimental/memory/memory.observer.ptr/ctor.copy_move.cpp b/libcxx/test/std/experimental/memory/memory.observer.ptr/ctor.copy_move.cpp
new file mode 100644
index 000000000000000..acfa41d0bb1aa7c
--- /dev/null
+++ b/libcxx/test/std/experimental/memory/memory.observer.ptr/ctor.copy_move.cpp
@@ -0,0 +1,60 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// REQUIRES: c++experimental
+
+// <experimental/memory>
+
+// observer_ptr
+//
+// observer_ptr(const observer_ptr& other) = default;
+// observer_ptr(observer_ptr&& other) = default;
+
+#include <experimental/memory>
+#include <cassert>
+#include <type_traits>
+#include <utility>
+
+template <class T, class Object = T>
+constexpr void test_copy_move() {
+  using Ptr = std::experimental::observer_ptr<T>;
+  Object obj;
+  {
+    Ptr ptr(&obj);
+    Ptr copy = ptr;
+    assert(ptr.get() == &obj);
+    assert(copy.get() == &obj);
+    static_assert(std::is_nothrow_copy_constructible<Ptr>::value);
+  }
+  {
+    Ptr ptr(&obj);
+    Ptr copy = std::move(ptr);
+    assert(ptr.get() == &obj);
+    assert(copy.get() == &obj);
+    static_assert(std::is_nothrow_move_constructible<Ptr>::value);
+  }
+}
+
+struct Bar {};
+
+constexpr bool test() {
+  test_copy_move<int>();
+  test_copy_move<Bar>();
+  test_copy_move<void, int>();
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
\ No newline at end of file

diff  --git a/libcxx/test/std/experimental/memory/memory.observer.ptr/ctor.default.pass.cpp b/libcxx/test/std/experimental/memory/memory.observer.ptr/ctor.default.pass.cpp
new file mode 100644
index 000000000000000..6d254418916d30d
--- /dev/null
+++ b/libcxx/test/std/experimental/memory/memory.observer.ptr/ctor.default.pass.cpp
@@ -0,0 +1,50 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// REQUIRES: c++experimental
+
+// <experimental/memory>
+
+// observer_ptr
+//
+// constexpr observer_ptr() noexcept;
+
+#include <experimental/memory>
+#include <type_traits>
+#include <cassert>
+
+template <class T>
+constexpr void test_default_ctor() {
+  using Ptr = std::experimental::observer_ptr<T>;
+  Ptr ptr;
+  assert(ptr.get() == nullptr);
+  static_assert(std::is_nothrow_default_constructible<Ptr>::value);
+}
+
+struct Foo;
+struct Bar {
+  Bar(int) {}
+};
+
+constexpr bool test() {
+  test_default_ctor<Foo>();
+  test_default_ctor<Bar>();
+  test_default_ctor<int>();
+  test_default_ctor<void>();
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/experimental/memory/memory.observer.ptr/ctor.element_type.pass.cpp b/libcxx/test/std/experimental/memory/memory.observer.ptr/ctor.element_type.pass.cpp
new file mode 100644
index 000000000000000..830f3664cae85ea
--- /dev/null
+++ b/libcxx/test/std/experimental/memory/memory.observer.ptr/ctor.element_type.pass.cpp
@@ -0,0 +1,49 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// REQUIRES: c++experimental
+
+// <experimental/memory>
+
+// observer_ptr
+//
+// constexpr explicit observer_ptr(element_type* p) noexcept;
+
+#include <experimental/memory>
+#include <type_traits>
+#include <cassert>
+
+template <class T, class ObjectT = T>
+constexpr void test_element_type_ctor() {
+  using Ptr = std::experimental::observer_ptr<T>;
+  ObjectT obj;
+  T* raw = &obj;
+  Ptr ptr(raw);
+  assert(ptr.get() == raw);
+  static_assert(!std::is_convertible<T*, Ptr>::value);
+  static_assert(std::is_nothrow_constructible<Ptr, T*>::value);
+}
+
+struct Bar {};
+
+constexpr bool test() {
+  test_element_type_ctor<Bar>();
+  test_element_type_ctor<int>();
+  test_element_type_ctor<void, int>();
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/experimental/memory/memory.observer.ptr/ctor.nullptr.pass.cpp b/libcxx/test/std/experimental/memory/memory.observer.ptr/ctor.nullptr.pass.cpp
new file mode 100644
index 000000000000000..8940f1c263004c3
--- /dev/null
+++ b/libcxx/test/std/experimental/memory/memory.observer.ptr/ctor.nullptr.pass.cpp
@@ -0,0 +1,51 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// REQUIRES: c++experimental
+
+// <experimental/memory>
+
+// observer_ptr
+//
+// constexpr observer_ptr(nullptr_t) noexcept;
+
+#include <experimental/memory>
+#include <cassert>
+#include <cstddef>
+#include <type_traits>
+
+template <class T>
+constexpr void test_nullptr_ctor() {
+  using Ptr = std::experimental::observer_ptr<T>;
+  Ptr ptr   = nullptr;
+  assert(ptr.get() == nullptr);
+  static_assert(std::is_nothrow_constructible<Ptr, std::nullptr_t>::value);
+}
+
+struct Foo;
+struct Bar {
+  Bar(int) {}
+};
+
+constexpr bool test() {
+  test_nullptr_ctor<Foo>();
+  test_nullptr_ctor<Bar>();
+  test_nullptr_ctor<int>();
+  test_nullptr_ctor<void>();
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/experimental/memory/memory.observer.ptr/deref.pass.cpp b/libcxx/test/std/experimental/memory/memory.observer.ptr/deref.pass.cpp
new file mode 100644
index 000000000000000..30b13066e4a96ad
--- /dev/null
+++ b/libcxx/test/std/experimental/memory/memory.observer.ptr/deref.pass.cpp
@@ -0,0 +1,65 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// REQUIRES: c++experimental
+
+// <experimental/memory>
+
+// observer_ptr
+//
+// constexpr std::add_lvalue_reference_t<element_type> operator*() const;
+// constexpr element_type* operator->() const noexcept;
+
+#include <experimental/memory>
+#include <type_traits>
+#include <cassert>
+
+template <class T, class Object = T>
+constexpr void test_deref() {
+  using Ptr = std::experimental::observer_ptr<T>;
+  Object obj;
+
+  {
+    Ptr const ptr(&obj);
+    T& r = *ptr;
+    assert(&r == &obj);
+  }
+  {
+    Ptr const ptr(&obj);
+    T* r = ptr.operator->();
+    assert(r == &obj);
+    static_assert(noexcept(ptr.operator->()));
+  }
+}
+
+struct Bar {};
+struct Foo {
+  int member = 42;
+};
+
+constexpr bool test() {
+  test_deref<Bar>();
+  test_deref<int>();
+
+  {
+    Foo foo;
+    std::experimental::observer_ptr<Foo> ptr(&foo);
+    assert(&ptr->member == &foo.member);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/experimental/memory/memory.observer.ptr/get.pass.cpp b/libcxx/test/std/experimental/memory/memory.observer.ptr/get.pass.cpp
new file mode 100644
index 000000000000000..eae5d5180db93db
--- /dev/null
+++ b/libcxx/test/std/experimental/memory/memory.observer.ptr/get.pass.cpp
@@ -0,0 +1,50 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// REQUIRES: c++experimental
+
+// <experimental/memory>
+
+// observer_ptr
+//
+// constexpr element_type* get() const noexcept;
+
+#include <experimental/memory>
+#include <type_traits>
+#include <cassert>
+
+template <class T, class Object = T>
+constexpr void test_get() {
+  using Ptr = std::experimental::observer_ptr<T>;
+  Object obj;
+
+  Ptr const ptr(&obj);
+  assert(ptr.get() == &obj);
+
+  static_assert(noexcept(ptr.get()));
+  static_assert(std::is_same<decltype(ptr.get()), T*>::value);
+}
+
+struct Bar {};
+
+constexpr bool test() {
+  test_get<Bar>();
+  test_get<int>();
+  test_get<void, int>();
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/experimental/memory/memory.observer.ptr/hash.pass.cpp b/libcxx/test/std/experimental/memory/memory.observer.ptr/hash.pass.cpp
new file mode 100644
index 000000000000000..7aa5dc8d5b326cc
--- /dev/null
+++ b/libcxx/test/std/experimental/memory/memory.observer.ptr/hash.pass.cpp
@@ -0,0 +1,52 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// REQUIRES: c++experimental
+
+// <experimental/memory>
+
+// observer_ptr
+//
+// template <class T> struct hash<std::experimental::observer_ptr<T>>;
+
+#include <experimental/memory>
+#include <cassert>
+
+#include "poisoned_hash_helper.h"
+
+template <class T, class Object = T>
+void test_hash() {
+  {
+    using Ptr = std::experimental::observer_ptr<T>;
+    Object obj;
+    Ptr ptr(&obj);
+
+    std::hash<std::experimental::observer_ptr<T>> f;
+    std::size_t h = f(ptr);
+
+    assert(h == std::hash<T*>()(&obj));
+  }
+
+  test_hash_enabled_for_type<std::experimental::observer_ptr<T>>();
+}
+
+struct Bar {};
+
+void test() {
+  test_hash<void, int>();
+  test_hash<int>();
+  test_hash<Bar>();
+}
+
+int main(int, char**) {
+  // Note: This isn't constexpr friendly in the spec!
+  test();
+
+  return 0;
+}

diff  --git a/libcxx/test/std/experimental/memory/memory.observer.ptr/make_observer.pass.cpp b/libcxx/test/std/experimental/memory/memory.observer.ptr/make_observer.pass.cpp
new file mode 100644
index 000000000000000..8a530fb0e0136ad
--- /dev/null
+++ b/libcxx/test/std/experimental/memory/memory.observer.ptr/make_observer.pass.cpp
@@ -0,0 +1,48 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// REQUIRES: c++experimental
+
+// <experimental/memory>
+
+// observer_ptr
+//
+// template <class W>
+// std::experimental::observer_ptr<W> make_observer(W* p) noexcept;
+
+#include <experimental/memory>
+#include <cassert>
+#include <type_traits>
+
+template <class T, class Object = T>
+void test_make_observer() {
+  using Ptr = std::experimental::observer_ptr<T>;
+  Object obj;
+  T* raw = &obj;
+
+  Ptr ptr = std::experimental::make_observer(raw);
+  assert(ptr.get() == raw);
+  static_assert(noexcept(std::experimental::make_observer(raw)));
+  static_assert(std::is_same<decltype(std::experimental::make_observer(raw)), Ptr>::value);
+}
+
+struct Bar {};
+
+void test() {
+  test_make_observer<void, int>();
+  test_make_observer<int>();
+  test_make_observer<Bar>();
+}
+
+int main(int, char**) {
+  // Note: this is not constexpr in the spec
+  test();
+
+  return 0;
+}

diff  --git a/libcxx/test/std/experimental/memory/memory.observer.ptr/operator-bool.pass.cpp b/libcxx/test/std/experimental/memory/memory.observer.ptr/operator-bool.pass.cpp
new file mode 100644
index 000000000000000..b44f7c8bd2ee528
--- /dev/null
+++ b/libcxx/test/std/experimental/memory/memory.observer.ptr/operator-bool.pass.cpp
@@ -0,0 +1,61 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// REQUIRES: c++experimental
+
+// <experimental/memory>
+
+// observer_ptr
+//
+// constexpr explicit operator bool() const noexcept;
+
+#include <experimental/memory>
+#include <type_traits>
+#include <cassert>
+
+template <class T, class Object = T>
+constexpr void test_operator_bool() {
+  using Ptr = std::experimental::observer_ptr<T>;
+  Object obj;
+
+  {
+    Ptr const ptr(&obj);
+    bool b = static_cast<bool>(ptr);
+    assert(b);
+
+    static_assert(noexcept(static_cast<bool>(ptr)));
+  }
+
+  {
+    Ptr const ptr(nullptr);
+    bool b = static_cast<bool>(ptr);
+    assert(!b);
+  }
+
+  static_assert(!std::is_convertible<Ptr const, bool>::value);
+  static_assert(std::is_constructible<bool, Ptr const>::value);
+}
+
+struct Bar {};
+
+constexpr bool test() {
+  test_operator_bool<Bar>();
+  test_operator_bool<int>();
+  test_operator_bool<void, int>();
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/experimental/memory/memory.observer.ptr/operator-element_type.pass.cpp b/libcxx/test/std/experimental/memory/memory.observer.ptr/operator-element_type.pass.cpp
new file mode 100644
index 000000000000000..6e5bcd6aca6e88d
--- /dev/null
+++ b/libcxx/test/std/experimental/memory/memory.observer.ptr/operator-element_type.pass.cpp
@@ -0,0 +1,58 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// REQUIRES: c++experimental
+
+// <experimental/memory>
+
+// observer_ptr
+//
+// constexpr explicit operator element_type*() const noexcept;
+
+#include <experimental/memory>
+#include <type_traits>
+#include <cassert>
+
+template <class T, class Object = T>
+constexpr void test_convertibility() {
+  Object obj;
+  std::experimental::observer_ptr<T> ptr(&obj);
+
+  T* raw = static_cast<T*>(ptr);
+  assert(raw == &obj);
+  static_assert(!std::is_convertible<std::experimental::observer_ptr<T>, T*>::value, "");
+  static_assert(std::is_constructible<T*, std::experimental::observer_ptr<T>>::value, "");
+}
+
+struct Incomplete;
+
+struct Bar {};
+
+constexpr bool test() {
+  test_convertibility<void, int>();
+  test_convertibility<bool>();
+  test_convertibility<int>();
+  test_convertibility<Bar>();
+
+  {
+    std::experimental::observer_ptr<Incomplete> ptr = nullptr;
+    Incomplete* raw                                 = static_cast<Incomplete*>(ptr);
+    assert(raw == nullptr);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/experimental/memory/memory.observer.ptr/release.pass.cpp b/libcxx/test/std/experimental/memory/memory.observer.ptr/release.pass.cpp
new file mode 100644
index 000000000000000..a6000f7cce89852
--- /dev/null
+++ b/libcxx/test/std/experimental/memory/memory.observer.ptr/release.pass.cpp
@@ -0,0 +1,53 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// REQUIRES: c++experimental
+
+// <experimental/memory>
+
+// observer_ptr
+//
+// constexpr element_type* release() noexcept;
+
+#include <experimental/memory>
+#include <type_traits>
+#include <cassert>
+
+template <class T, class Object = T>
+constexpr void test_release() {
+  Object obj;
+  using Ptr = std::experimental::observer_ptr<T>;
+  Ptr ptr(&obj);
+  assert(ptr.get() == &obj);
+
+  decltype(auto) r = ptr.release();
+  assert(r == &obj);
+  assert(ptr.get() == nullptr);
+
+  static_assert(std::is_same<decltype(r), typename Ptr::element_type*>::value);
+  static_assert(noexcept(ptr.release()));
+}
+
+struct Bar {};
+
+constexpr bool test() {
+  test_release<Bar>();
+  test_release<int>();
+  test_release<void, int>();
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/experimental/memory/memory.observer.ptr/reset.pass.cpp b/libcxx/test/std/experimental/memory/memory.observer.ptr/reset.pass.cpp
new file mode 100644
index 000000000000000..0a639d6e000c0c4
--- /dev/null
+++ b/libcxx/test/std/experimental/memory/memory.observer.ptr/reset.pass.cpp
@@ -0,0 +1,61 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// REQUIRES: c++experimental
+
+// <experimental/memory>
+
+// observer_ptr
+//
+// constexpr void reset(element_type* p = nullptr) noexcept;
+
+#include <experimental/memory>
+#include <type_traits>
+#include <cassert>
+
+template <class T, class Object = T>
+constexpr void test_reset() {
+  using Ptr = std::experimental::observer_ptr<T>;
+  Object obj1, obj2;
+
+  {
+    Ptr ptr(&obj1);
+    assert(ptr.get() == &obj1);
+    ptr.reset(&obj2);
+    assert(ptr.get() == &obj2);
+    static_assert(noexcept(ptr.reset(&obj2)));
+    static_assert(std::is_same<decltype(ptr.reset(&obj2)), void>::value);
+  }
+  {
+    Ptr ptr(&obj1);
+    assert(ptr.get() == &obj1);
+    ptr.reset();
+    assert(ptr.get() == nullptr);
+    static_assert(noexcept(ptr.reset()));
+    static_assert(std::is_same<decltype(ptr.reset()), void>::value);
+  }
+}
+
+struct Bar {};
+
+constexpr bool test() {
+  test_reset<Bar>();
+  test_reset<int>();
+  test_reset<void, int>();
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/experimental/memory/memory.observer.ptr/swap.pass.cpp b/libcxx/test/std/experimental/memory/memory.observer.ptr/swap.pass.cpp
new file mode 100644
index 000000000000000..ffd43a750e2ef29
--- /dev/null
+++ b/libcxx/test/std/experimental/memory/memory.observer.ptr/swap.pass.cpp
@@ -0,0 +1,79 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// REQUIRES: c++experimental
+
+// <experimental/memory>
+
+// observer_ptr
+//
+// constexpr void swap(observer_ptr& other) noexcept;
+//
+// template <class W>
+// void swap(observer_ptr<W>& lhs, observer_ptr<W>& rhs) noexcept;
+
+#include <experimental/memory>
+#include <type_traits>
+#include <cassert>
+
+template <class T, class Object = T>
+constexpr void test_swap() {
+  using Ptr = std::experimental::observer_ptr<T>;
+  Object obj1, obj2;
+
+  {
+    Ptr ptr1(&obj1);
+    Ptr ptr2(&obj2);
+
+    assert(ptr1.get() == &obj1);
+    assert(ptr2.get() == &obj2);
+
+    ptr1.swap(ptr2);
+
+    assert(ptr1.get() == &obj2);
+    assert(ptr2.get() == &obj1);
+
+    static_assert(noexcept(ptr1.swap(ptr2)));
+    static_assert(std::is_same<decltype(ptr1.swap(ptr2)), void>::value);
+  }
+
+  {
+    Ptr ptr1(&obj1);
+    Ptr ptr2(&obj2);
+
+    assert(ptr1.get() == &obj1);
+    assert(ptr2.get() == &obj2);
+
+    std::experimental::swap(ptr1, ptr2);
+
+    assert(ptr1.get() == &obj2);
+    assert(ptr2.get() == &obj1);
+
+    static_assert(noexcept(std::experimental::swap(ptr1, ptr2)));
+    static_assert(std::is_same<decltype(std::experimental::swap(ptr1, ptr2)), void>::value);
+  }
+}
+
+struct Bar {};
+
+constexpr bool test() {
+  test_swap<Bar>();
+  test_swap<int>();
+  test_swap<void, int>();
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/std/experimental/memory/memory.observer.ptr/types.compile.pass.cpp b/libcxx/test/std/experimental/memory/memory.observer.ptr/types.compile.pass.cpp
new file mode 100644
index 000000000000000..3d1461ca5a1208d
--- /dev/null
+++ b/libcxx/test/std/experimental/memory/memory.observer.ptr/types.compile.pass.cpp
@@ -0,0 +1,23 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// REQUIRES: c++experimental
+
+// <experimental/memory>
+
+// observer_ptr
+//
+// using element_type = W;
+
+#include <experimental/memory>
+#include <type_traits>
+
+using T = std::experimental::observer_ptr<int>::element_type;
+static_assert(std::is_same<T, int>::value);


        


More information about the libcxx-commits mailing list