[flang] [libc] [clang] [mlir] [llvm] [libcxx] [libc++][memory] P1132R8: out_ptr - a scalable output pointer abstraction (PR #73618)

Hristo Hristov via cfe-commits cfe-commits at lists.llvm.org
Thu Nov 30 05:30:39 PST 2023


https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/73618

>From 84770c82152f027588dd744bbfb91ed55377e007 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <zingam at outlook.com>
Date: Sun, 30 Apr 2023 13:17:20 +0300
Subject: [PATCH 1/4] [libc++][memory] P1132R8: out_ptr - a scalable output
 pointer abstraction

Differential Revision: https://reviews.llvm.org/D150525
---
 libcxx/docs/FeatureTestMacroTable.rst         |   2 +-
 libcxx/docs/Status/Cxx23Issues.csv            |   4 +-
 libcxx/docs/Status/Cxx23Papers.csv            |   2 +-
 libcxx/include/CMakeLists.txt                 |   2 +
 libcxx/include/__memory/allocator_traits.h    |   1 -
 libcxx/include/__memory/inout_ptr.h           | 100 +++++++++
 libcxx/include/__memory/out_ptr.h             |  97 +++++++++
 libcxx/include/__memory/pointer_traits.h      |  67 +++++-
 libcxx/include/memory                         |  18 ++
 libcxx/include/module.modulemap.in            |   2 +
 libcxx/include/version                        |   2 +-
 libcxx/modules/std/memory.inc                 |  10 +-
 .../memory.version.compile.pass.cpp           |  16 +-
 .../version.version.compile.pass.cpp          |  16 +-
 .../inout.ptr/inout.ptr.compile.pass.cpp      |  35 +++
 .../adapt/inout.ptr/inout.ptr.pass.cpp        | 205 ++++++++++++++++++
 .../inout.ptr/inout.ptr.t.compile.pass.cpp    |  32 +++
 .../adapt/inout.ptr/inout.ptr.t.verify.cpp    |  29 +++
 .../adapt/inout.ptr/inout.ptr.verify.cpp      |  30 +++
 .../adapt/out.ptr/out.ptr.compile.pass.cpp    |  34 +++
 .../smartptr/adapt/out.ptr/out.ptr.pass.cpp   | 163 ++++++++++++++
 .../adapt/out.ptr/out.ptr.t.compile.pass.cpp  |  32 +++
 .../adapt/out.ptr/out.ptr.t.verify.cpp        |  29 +++
 .../smartptr/adapt/out.ptr/out.ptr.verify.cpp |  30 +++
 .../test/std/utilities/smartptr/adapt/types.h |  77 +++++++
 .../generate_feature_test_macro_components.py |   1 -
 26 files changed, 999 insertions(+), 37 deletions(-)
 create mode 100644 libcxx/include/__memory/inout_ptr.h
 create mode 100644 libcxx/include/__memory/out_ptr.h
 create mode 100644 libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.compile.pass.cpp
 create mode 100644 libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.pass.cpp
 create mode 100644 libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.compile.pass.cpp
 create mode 100644 libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.verify.cpp
 create mode 100644 libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.verify.cpp
 create mode 100644 libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.compile.pass.cpp
 create mode 100644 libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.pass.cpp
 create mode 100644 libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.compile.pass.cpp
 create mode 100644 libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.verify.cpp
 create mode 100644 libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.verify.cpp
 create mode 100644 libcxx/test/std/utilities/smartptr/adapt/types.h

diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index d09f65b7cadc0e2..4b2adc70f51740c 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -342,7 +342,7 @@ Status
     --------------------------------------------------- -----------------
     ``__cpp_lib_optional``                              ``202110L``
     --------------------------------------------------- -----------------
-    ``__cpp_lib_out_ptr``                               *unimplemented*
+    ``__cpp_lib_out_ptr``                               ``202106L``
     --------------------------------------------------- -----------------
     ``__cpp_lib_print``                                 *unimplemented*
     --------------------------------------------------- -----------------
diff --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv
index b24ecc5525a1497..e5ad365f9ffb877 100644
--- a/libcxx/docs/Status/Cxx23Issues.csv
+++ b/libcxx/docs/Status/Cxx23Issues.csv
@@ -192,7 +192,7 @@
 "`3515 <https://wg21.link/LWG3515>`__","§[stacktrace.basic.nonmem]: ``operator<<`` should be less templatized", "November 2022","","",""
 "`3545 <https://wg21.link/LWG3545>`__","``std::pointer_traits`` should be SFINAE-friendly", "November 2022","|Complete|","18.0",""
 "`3569 <https://wg21.link/LWG3569>`__","``join_view`` fails to support ranges of ranges with non-default_initializable iterators", "November 2022","","","|ranges|"
-"`3594 <https://wg21.link/LWG3594>`__","``inout_ptr`` — inconsistent ``release()`` in destructor", "November 2022","","",""
+"`3594 <https://wg21.link/LWG3594>`__","``inout_ptr`` — inconsistent ``release()`` in destructor", "November 2022","|Complete|","17.0",""
 "`3597 <https://wg21.link/LWG3597>`__","Unsigned integer types don't model advanceable", "November 2022","","","|ranges|"
 "`3600 <https://wg21.link/LWG3600>`__","Making ``istream_iterator`` copy constructor trivial is an ABI break", "November 2022","","",""
 "`3629 <https://wg21.link/LWG3629>`__","``make_error_code`` and ``make_error_condition`` are customization points","November 2022","|Complete|","16.0",""
@@ -282,7 +282,7 @@
 "`3645 <https://wg21.link/LWG3645>`__","``resize_and_overwrite`` is overspecified to call its callback with lvalues","February 2023","|Complete|","14.0",""
 "`3655 <https://wg21.link/LWG3655>`__","The ``INVOKE`` operation and union types","February 2023","|Complete|","18.0",""
 "`3723 <https://wg21.link/LWG3723>`__","``priority_queue::push_range`` needs to ``append_range``","February 2023","","","|ranges|"
-"`3734 <https://wg21.link/LWG3734>`__","Inconsistency in ``inout_ptr`` and ``out_ptr`` for empty case","February 2023","","",""
+"`3734 <https://wg21.link/LWG3734>`__","Inconsistency in ``inout_ptr`` and ``out_ptr`` for empty case","February 2023","|Complete|","17.0",""
 "`3772 <https://wg21.link/LWG3772>`__","``repeat_view``'s ``piecewise`` constructor is missing Postconditions","February 2023","","","|ranges|"
 "`3786 <https://wg21.link/LWG3786>`__","Flat maps' deduction guide needs to default ``Allocator`` to be useful","February 2023","","",""
 "`3803 <https://wg21.link/LWG3803>`__","``flat_foo`` constructors taking ``KeyContainer`` lack ``KeyCompare`` parameter","February 2023","","",""
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index 5cc9e488297b9f7..198b0ab9d390e33 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -13,7 +13,7 @@
 "","","","","","",""
 "`P0401R6 <https://wg21.link/P0401R6>`__","LWG","Providing size feedback in the Allocator interface","June 2021","|Complete|","15.0"
 "`P0448R4 <https://wg21.link/P0448R4>`__","LWG","A strstream replacement using span<charT> as buffer","June 2021","",""
-"`P1132R8 <https://wg21.link/P1132R8>`__","LWG","out_ptr - a scalable output pointer abstraction","June 2021","",""
+"`P1132R8 <https://wg21.link/P1132R8>`__","LWG","out_ptr - a scalable output pointer abstraction","June 2021","|Complete|","17.0"
 "`P1328R1 <https://wg21.link/P1328R1>`__","LWG","Making std::type_info::operator== constexpr","June 2021","|Complete|","17.0"
 "`P1425R4 <https://wg21.link/P1425R4>`__","LWG","Iterators pair constructors for stack and queue","June 2021","|Complete|","14.0","|ranges|"
 "`P1518R2 <https://wg21.link/P1518R2>`__","LWG","Stop overconstraining allocators in container deduction guides","June 2021","|Complete|","13.0"
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index d8faf6467b79ae2..e5a28734ae34bfb 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -529,6 +529,8 @@ set(files
   __memory/concepts.h
   __memory/construct_at.h
   __memory/destruct_n.h
+  __memory/inout_ptr.h
+  __memory/out_ptr.h
   __memory/pointer_traits.h
   __memory/ranges_construct_at.h
   __memory/ranges_uninitialized_algorithms.h
diff --git a/libcxx/include/__memory/allocator_traits.h b/libcxx/include/__memory/allocator_traits.h
index eea5ee973d37fd7..ed13cf8a3c278c1 100644
--- a/libcxx/include/__memory/allocator_traits.h
+++ b/libcxx/include/__memory/allocator_traits.h
@@ -38,7 +38,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD
     template <class _Tp>               struct NAME<_Tp, __void_t<typename _Tp:: PROPERTY > > : true_type { }
 
 // __pointer
-_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_pointer, pointer);
 template <class _Tp, class _Alloc,
           class _RawAlloc = __libcpp_remove_reference_t<_Alloc>,
           bool = __has_pointer<_RawAlloc>::value>
diff --git a/libcxx/include/__memory/inout_ptr.h b/libcxx/include/__memory/inout_ptr.h
new file mode 100644
index 000000000000000..c2044a4642cf4ee
--- /dev/null
+++ b/libcxx/include/__memory/inout_ptr.h
@@ -0,0 +1,100 @@
+// -*- 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___INOUT_PTR_H
+#define _LIBCPP___INOUT_PTR_H
+
+#include <__config>
+#include <__memory/addressof.h>
+#include <__memory/pointer_traits.h>
+#include <__memory/shared_ptr.h>
+#include <__memory/unique_ptr.h>
+#include <__type_traits/is_same.h>
+#include <__type_traits/is_specialization.h>
+#include <__type_traits/is_void.h>
+#include <tuple>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 23
+
+template <class _Smart, class _Pointer, class... _Args>
+class _LIBCPP_TEMPLATE_VIS inout_ptr_t {
+  static_assert(!__is_specialization_v<_Smart, shared_ptr>, "std::shared_ptr<> is not supported");
+
+public:
+  _LIBCPP_HIDE_FROM_ABI explicit inout_ptr_t(_Smart& __s, _Args... __args)
+      : __s_(__s), __a_(std::forward<_Args>(__args)...), __p_([&__s] {
+          if constexpr (is_pointer_v<_Smart>) {
+            return __s;
+          } else {
+            return __s.get();
+          }
+        }()) {
+    if constexpr (requires { __s.release(); }) {
+      __s.release();
+    } else {
+      __s = _Smart();
+    }
+  }
+
+  _LIBCPP_HIDE_FROM_ABI inout_ptr_t(const inout_ptr_t&) = delete;
+
+  _LIBCPP_HIDE_FROM_ABI ~inout_ptr_t() {
+    if (!__p_) {
+      return;
+    }
+
+    using _SP = __pointer_of_or_t<_Smart, _Pointer>;
+    if constexpr (is_pointer_v<_Smart>) {
+      std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); },
+                 std::move(__a_));
+    } else if constexpr (__resettable_smart_pointer_with_args<_Smart, _Pointer, _Args...>) {
+      std::apply([&](auto&&... __args) { __s_.reset(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); },
+                 std::move(__a_));
+    } else if constexpr (is_constructible_v<_Smart, _SP, _Args...>) {
+      std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); },
+                 std::move(__a_));
+    } else {
+      static_assert(is_pointer_v<_Smart> || __resettable_smart_pointer_with_args<_Smart, _Pointer, _Args...> ||
+                    is_constructible_v<_Smart, _SP, _Args...>);
+    }
+  }
+
+  _LIBCPP_HIDE_FROM_ABI operator _Pointer*() const noexcept { return std::addressof(const_cast<_Pointer&>(__p_)); }
+
+  _LIBCPP_HIDE_FROM_ABI operator void**() const noexcept
+    requires(!is_same_v<_Pointer, void*>)
+  {
+    static_assert(is_pointer_v<_Pointer>);
+
+    return reinterpret_cast<void**>(static_cast<_Pointer*>(*this));
+  }
+
+private:
+  _Smart& __s_;
+  tuple<_Args...> __a_;
+  _Pointer __p_;
+};
+
+template <class _Pointer = void, class _Smart, class... _Args>
+_LIBCPP_HIDE_FROM_ABI auto inout_ptr(_Smart& __s, _Args&&... __args) {
+  using _Ptr = conditional_t<is_void_v<_Pointer>, __pointer_of_t<_Smart>, _Pointer>;
+  return std::inout_ptr_t<_Smart, _Ptr, _Args&&...>{__s, std::forward<_Args>(__args)...};
+}
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___INOUT_PTR_H
diff --git a/libcxx/include/__memory/out_ptr.h b/libcxx/include/__memory/out_ptr.h
new file mode 100644
index 000000000000000..09c77cbafe69e01
--- /dev/null
+++ b/libcxx/include/__memory/out_ptr.h
@@ -0,0 +1,97 @@
+// -*- 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___OUT_PTR_H
+#define _LIBCPP___OUT_PTR_H
+
+#include <__config>
+#include <__memory/addressof.h>
+#include <__memory/pointer_traits.h>
+#include <__memory/shared_ptr.h>
+#include <__memory/unique_ptr.h>
+#include <__type_traits/is_specialization.h>
+#include <__type_traits/is_void.h>
+#include <tuple>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 23
+
+template <class _Tp>
+concept __resettable_adapted_ptr = requires(_Tp __ptr) { __ptr().reset(); };
+
+template <class _Smart, class _Pointer, class... _Args>
+class _LIBCPP_TEMPLATE_VIS out_ptr_t {
+  static_assert(!__is_specialization_v<_Smart, shared_ptr> || sizeof...(_Args) > 0,
+                "Specialization of std::shared_ptr<> requires a deleter.");
+
+public:
+  _LIBCPP_HIDE_FROM_ABI explicit out_ptr_t(_Smart& __s, _Args... __args)
+      : __s_(__s), __a_(std::forward<_Args>(__args)...), __p_() {
+    using _Ptr = decltype(__s);
+    if constexpr (__resettable_smart_pointer<_Ptr>) {
+      __s_.reset();
+    } else if constexpr (is_constructible_v<_Smart>) {
+      __s_ = _Smart();
+    } else {
+      static_assert(__resettable_smart_pointer<_Ptr> || is_constructible_v<_Smart>);
+    }
+  }
+
+  _LIBCPP_HIDE_FROM_ABI out_ptr_t(const out_ptr_t&) = delete;
+
+  _LIBCPP_HIDE_FROM_ABI ~out_ptr_t() {
+    if (!__p_) {
+      return;
+    }
+
+    using _SP = __pointer_of_or_t<_Smart, _Pointer>;
+    if constexpr (__resettable_smart_pointer_with_args<_Smart, _Pointer, _Args...>) {
+      std::apply([&](auto&&... __args) { __s_.reset(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); },
+                 std::move(__a_));
+    } else if constexpr (is_constructible_v<_Smart, _SP, _Args...>) {
+      std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); },
+                 std::move(__a_));
+    } else {
+      static_assert(__resettable_smart_pointer_with_args<_Smart, _Pointer, _Args...> ||
+                    is_constructible_v<_Smart, _SP, _Args...>);
+    }
+  }
+
+  _LIBCPP_HIDE_FROM_ABI operator _Pointer*() const noexcept { return std::addressof(const_cast<_Pointer&>(__p_)); }
+
+  _LIBCPP_HIDE_FROM_ABI operator void**() const noexcept
+    requires(!is_same_v<_Pointer, void*>)
+  {
+    static_assert(is_pointer_v<_Pointer>);
+
+    return reinterpret_cast<void**>(static_cast<_Pointer*>(*this));
+  }
+
+private:
+  _Smart& __s_;
+  tuple<_Args...> __a_;
+  _Pointer __p_ = _Pointer();
+};
+
+template <class _Pointer = void, class _Smart, class... _Args>
+_LIBCPP_HIDE_FROM_ABI auto out_ptr(_Smart& __s, _Args&&... __args) {
+  using _Ptr = conditional_t<is_void_v<_Pointer>, __pointer_of_t<_Smart>, _Pointer>;
+  return std::out_ptr_t<_Smart, _Ptr, _Args&&...>{__s, std::forward<_Args>(__args)...};
+}
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___OUT_PTR_H
diff --git a/libcxx/include/__memory/pointer_traits.h b/libcxx/include/__memory/pointer_traits.h
index 7617948ed76bd66..2be0deb50cb8ed1 100644
--- a/libcxx/include/__memory/pointer_traits.h
+++ b/libcxx/include/__memory/pointer_traits.h
@@ -15,11 +15,14 @@
 #include <__type_traits/conditional.h>
 #include <__type_traits/conjunction.h>
 #include <__type_traits/decay.h>
+#include <__type_traits/enable_if.h>
 #include <__type_traits/is_class.h>
 #include <__type_traits/is_function.h>
 #include <__type_traits/is_void.h>
+#include <__type_traits/negation.h>
 #include <__type_traits/void_t.h>
 #include <__utility/declval.h>
+#include <__utility/forward.h>
 #include <cstddef>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -28,11 +31,16 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-template <class _Tp, class = void>
-struct __has_element_type : false_type {};
+// clang-format off
+#define _LIBCPP_CLASS_TRAITS_HAS_XXX(NAME, PROPERTY)                                                                   \
+  template <class _Tp, class = void>                                                                                   \
+  struct NAME : false_type {};                                                                                         \
+  template <class _Tp>                                                                                                 \
+  struct NAME<_Tp, __void_t<typename _Tp::PROPERTY> > : true_type {}
+// clang-format on
 
-template <class _Tp>
-struct __has_element_type<_Tp, __void_t<typename _Tp::element_type> > : true_type {};
+_LIBCPP_CLASS_TRAITS_HAS_XXX(__has_pointer, pointer);
+_LIBCPP_CLASS_TRAITS_HAS_XXX(__has_element_type, element_type);
 
 template <class _Ptr, bool = __has_element_type<_Ptr>::value>
 struct __pointer_traits_element_type {};
@@ -242,6 +250,57 @@ auto to_address(const _Pointer& __p) noexcept -> decltype(std::__to_address(__p)
 }
 #endif
 
+#if _LIBCPP_STD_VER >= 23
+
+template <class _Tp>
+struct __pointer_of {};
+
+template <class _Tp>
+  requires(__has_pointer<_Tp>::value)
+struct __pointer_of<_Tp> {
+  using type = typename _Tp::pointer;
+};
+
+template <class _Tp>
+  requires(!__has_pointer<_Tp>::value && __has_element_type<_Tp>::value)
+struct __pointer_of<_Tp> {
+  using type = typename _Tp::element_type*;
+};
+
+template <class _Tp>
+  requires(!__has_pointer<_Tp>::value && !__has_element_type<_Tp>::value &&
+           __has_element_type<pointer_traits<_Tp>>::value)
+struct __pointer_of<_Tp> {
+  using type = typename pointer_traits<_Tp>::element_type*;
+};
+
+template <typename _Tp>
+using __pointer_of_t = typename __pointer_of<_Tp>::type;
+
+template <class _Tp, class _Up>
+struct __pointer_of_or {
+  using type _LIBCPP_NODEBUG = _Up;
+};
+
+template <class _Tp, class _Up>
+  requires requires { typename __pointer_of_t<_Tp>; }
+struct __pointer_of_or<_Tp, _Up> {
+  using type _LIBCPP_NODEBUG = __pointer_of_t<_Tp>;
+};
+
+template <typename _Tp, typename _Up>
+using __pointer_of_or_t = typename __pointer_of_or<_Tp, _Up>::type;
+
+template <class _Smart>
+concept __resettable_smart_pointer = requires(_Smart __s) { __s.reset(); };
+
+template <class _Smart, class _Pointer = void, class... _Args>
+concept __resettable_smart_pointer_with_args = requires(_Smart __s, _Pointer __p, _Args... __args) {
+  __s.reset(static_cast<__pointer_of_or_t<_Smart, _Pointer>>(__p), std::forward<_Args>(__args)...);
+};
+
+#endif
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP___MEMORY_POINTER_TRAITS_H
diff --git a/libcxx/include/memory b/libcxx/include/memory
index 24ba82f43ddd309..d3ab5f73bf00aae 100644
--- a/libcxx/include/memory
+++ b/libcxx/include/memory
@@ -910,6 +910,22 @@ void* align(size_t alignment, size_t size, void*& ptr, size_t& space);
 template<size_t N, class T>
 [[nodiscard]] constexpr T* assume_aligned(T* ptr); // since C++20
 
+// [out.ptr.t], class template out_ptr_t
+template<class Smart, class Pointer, class... Args>
+  class out_ptr_t;                                          // since c++23
+
+// [out.ptr], function template out_ptr
+template<class Pointer = void, class Smart, class... Args>
+  auto out_ptr(Smart& s, Args&&... args);                   // since c++23
+
+// [inout.ptr.t], class template inout_ptr_t
+template<class Smart, class Pointer, class... Args>
+  class inout_ptr_t;                                        // since c++23
+
+// [inout.ptr], function template inout_ptr
+template<class Pointer = void, class Smart, class... Args>
+  auto inout_ptr(Smart& s, Args&&... args);                 // since c++23
+
 }  // std
 
 */
@@ -928,6 +944,8 @@ template<size_t N, class T>
 #include <__memory/compressed_pair.h>
 #include <__memory/concepts.h>
 #include <__memory/construct_at.h>
+#include <__memory/inout_ptr.h>
+#include <__memory/out_ptr.h>
 #include <__memory/pointer_traits.h>
 #include <__memory/ranges_construct_at.h>
 #include <__memory/ranges_uninitialized_algorithms.h>
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 90ee7fbb2157c2d..f8a154d2541677d 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1519,6 +1519,8 @@ module std_private_memory_concepts                        [system] {
 }
 module std_private_memory_construct_at                    [system] { header "__memory/construct_at.h" }
 module std_private_memory_destruct_n                      [system] { header "__memory/destruct_n.h" }
+module std_private_memory_inout_ptr                       [system] { header "__memory/inout_ptr.h" }
+module std_private_memory_out_ptr                         [system] { header "__memory/out_ptr.h" }
 module std_private_memory_pointer_traits                  [system] { header "__memory/pointer_traits.h" }
 module std_private_memory_ranges_construct_at             [system] { header "__memory/ranges_construct_at.h" }
 module std_private_memory_ranges_uninitialized_algorithms [system] {
diff --git a/libcxx/include/version b/libcxx/include/version
index e84790b888d3333..2203dfd0e600580 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -455,7 +455,7 @@ __cpp_lib_within_lifetime                               202306L <type_traits>
 // # define __cpp_lib_move_only_function                   202110L
 # undef  __cpp_lib_optional
 # define __cpp_lib_optional                             202110L
-// # define __cpp_lib_out_ptr                              202106L
+# define __cpp_lib_out_ptr                              202106L
 // # define __cpp_lib_print                                202207L
 // # define __cpp_lib_ranges_as_const                      202207L
 # define __cpp_lib_ranges_as_rvalue                     202207L
diff --git a/libcxx/modules/std/memory.inc b/libcxx/modules/std/memory.inc
index fba2461732c1b9d..a02fa2b865f57fa 100644
--- a/libcxx/modules/std/memory.inc
+++ b/libcxx/modules/std/memory.inc
@@ -177,17 +177,19 @@ export namespace std {
   // [util.smartptr.atomic], atomic smart pointers
   // using std::atomic;
 
+#if _LIBCPP_STD_VER >= 23
   // [out.ptr.t], class template out_ptr_t
-  //  using std::out_ptr_t;
+  using std::out_ptr_t;
 
   // [out.ptr], function template out_ptr
-  //  using std::out_ptr;
+  using std::out_ptr;
 
   // [inout.ptr.t], class template inout_ptr_t
-  //  using std::inout_ptr_t;
+  using std::inout_ptr_t;
 
   // [inout.ptr], function template inout_ptr
-  //  using std::inout_ptr;
+  using std::inout_ptr;
+#endif // _LIBCPP_STD_VER >= 23
 
 #ifndef _LIBCPP_HAS_NO_THREADS
   // [depr.util.smartptr.shared.atomic]
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp
index b1f6c76d847398d..c3b37ed35a3ad0e 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp
@@ -485,17 +485,11 @@
 #   error "__cpp_lib_make_unique should have the value 201304L in c++23"
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_out_ptr
-#     error "__cpp_lib_out_ptr should be defined in c++23"
-#   endif
-#   if __cpp_lib_out_ptr != 202106L
-#     error "__cpp_lib_out_ptr should have the value 202106L in c++23"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_out_ptr
-#     error "__cpp_lib_out_ptr should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_out_ptr
+#   error "__cpp_lib_out_ptr should be defined in c++23"
+# endif
+# if __cpp_lib_out_ptr != 202106L
+#   error "__cpp_lib_out_ptr should have the value 202106L in c++23"
 # endif
 
 # ifndef __cpp_lib_ranges
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index a995795e305c49f..413fca0e79fecee 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -5210,17 +5210,11 @@
 #   error "__cpp_lib_optional should have the value 202110L in c++23"
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_out_ptr
-#     error "__cpp_lib_out_ptr should be defined in c++23"
-#   endif
-#   if __cpp_lib_out_ptr != 202106L
-#     error "__cpp_lib_out_ptr should have the value 202106L in c++23"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_out_ptr
-#     error "__cpp_lib_out_ptr should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_out_ptr
+#   error "__cpp_lib_out_ptr should be defined in c++23"
+# endif
+# if __cpp_lib_out_ptr != 202106L
+#   error "__cpp_lib_out_ptr should have the value 202106L in c++23"
 # endif
 
 # if !defined(_LIBCPP_VERSION)
diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.compile.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.compile.pass.cpp
new file mode 100644
index 000000000000000..d2eb8c3a6ac0081
--- /dev/null
+++ b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.compile.pass.cpp
@@ -0,0 +1,35 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++17, c++20
+
+// <memory>
+
+// [inout.ptr], function template inout_ptr
+// template<class Pointer = void, class Smart, class... Args>
+//   auto inout_ptr(Smart& s, Args&&... args);                 // since c++23
+
+#include <memory>
+
+int main(int, char**) {
+  {
+    std::unique_ptr<int> uPtr;
+
+    auto inoutUPtr1 = std::inout_ptr(uPtr);
+    auto inoutUPtr2 = std::inout_ptr<int*>(uPtr);
+  }
+  {
+    auto deleter = [](auto* p) { delete p; };
+    std::unique_ptr<int, decltype(deleter)> uPtr;
+
+    auto inoutUPtr1 = std::inout_ptr(uPtr, deleter);
+    auto inoutUPtr2 = std::inout_ptr<int*>(uPtr, deleter);
+  }
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.pass.cpp
new file mode 100644
index 000000000000000..ece562805342780
--- /dev/null
+++ b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.pass.cpp
@@ -0,0 +1,205 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++17, c++20
+
+// <memory>
+
+// [inout.ptr.t], class template inout_ptr_t
+// template<class Smart, class Pointer, class... Args>
+//   class inout_ptr_t;                                        // since c++23
+
+// [inout.ptr], function template inout_ptr
+// template<class Pointer = void, class Smart, class... Args>
+//   auto inout_ptr(Smart& s, Args&&... args);                 // since c++23
+
+#include <cassert>
+#include <memory>
+
+#include "../types.h"
+
+// Test helpers.
+
+void replace_int_p(int** pp) {
+  assert(**pp == 90);
+  delete *pp;
+  *pp = new int{84};
+}
+
+void replace_int_p_with_nullptr(int** pp) {
+  assert(**pp == 90);
+  delete *pp;
+  *pp = nullptr;
+}
+
+void replace_nullptr_with_int_p(int** pp) {
+  assert(*pp == nullptr);
+  *pp = new int{84};
+}
+
+void replace_int_void_p(void** pp) {
+  assert(*(static_cast<int*>(*pp)) == 90);
+  delete static_cast<int*>(*pp);
+  *pp = new int{84};
+}
+
+void replace_int_void_p_with_nullptr(void** pp) {
+  assert(*(static_cast<int*>(*pp)) == 90);
+  delete static_cast<int*>(*pp);
+  *pp = nullptr;
+}
+
+void replace_nullptr_with_int_void_p(void** pp) {
+  assert(*pp == nullptr);
+  *pp = new int{84};
+}
+
+void replace_SomeInt_p(SomeInt** pp) {
+  auto si = **pp;
+  assert(si.value == 90);
+  delete static_cast<SomeInt*>(*pp);
+  *pp = new SomeInt{9084};
+}
+
+void replace_SomeInt_void_p(void** pp) {
+  assert(reinterpret_cast<SomeInt*>(*pp)->value == 90);
+  delete static_cast<SomeInt*>(*pp);
+  *pp = reinterpret_cast<void*>(new SomeInt{9084});
+}
+
+// Test `std::inout_ptr()` function.
+
+void test_raw_ptr() {
+  {
+    auto rPtr = new int{90};
+
+    replace_int_p(std::inout_ptr<int*>(rPtr));
+    assert(*rPtr == 84);
+
+    delete rPtr;
+  }
+  {
+    auto rPtr = new int{90};
+
+    replace_int_p_with_nullptr(std::inout_ptr<int*>(rPtr));
+    assert(rPtr == nullptr);
+  }
+  {
+    int* rPtr = nullptr;
+
+    replace_nullptr_with_int_p(std::inout_ptr<int*>(rPtr));
+    assert(*rPtr == 84);
+    delete rPtr;
+  }
+  {
+    auto rPtr = new int{90};
+
+    replace_int_void_p(std::inout_ptr<int*>(rPtr));
+    assert(*rPtr == 84);
+    delete rPtr;
+  }
+  {
+    auto rPtr = new int{90};
+
+    replace_int_void_p_with_nullptr(std::inout_ptr<int*>(rPtr));
+    assert(rPtr == nullptr);
+  }
+  {
+    int* rPtr = nullptr;
+
+    replace_nullptr_with_int_void_p(std::inout_ptr<int*>(rPtr));
+    assert(*rPtr == 84);
+    delete rPtr;
+  }
+  {
+    auto* rPtr = new SomeInt{90};
+
+    replace_SomeInt_p(std::inout_ptr(rPtr));
+    assert(rPtr->value == 9084);
+    delete rPtr;
+  }
+  {
+    auto* rPtr = new SomeInt{90};
+
+    replace_SomeInt_void_p(std::inout_ptr<SomeInt*>(rPtr));
+    assert(rPtr->value == 9084);
+    delete rPtr;
+  }
+}
+
+void test_unique_ptr() {
+  {
+    auto uPtr = std::make_unique<int>(90);
+
+    replace_int_p(std::inout_ptr(uPtr));
+    assert(*uPtr == 84);
+  }
+  {
+    std::unique_ptr<int> uPtr;
+
+    replace_nullptr_with_int_p(std::inout_ptr(uPtr));
+    assert(*uPtr == 84);
+  }
+  {
+    auto uPtr = std::make_unique<int>(90);
+
+    replace_int_void_p(std::inout_ptr(uPtr));
+    assert(*uPtr == 84);
+  }
+  {
+    std::unique_ptr<int> uPtr;
+
+    replace_nullptr_with_int_void_p(std::inout_ptr(uPtr));
+    assert(*uPtr == 84);
+  }
+  {
+    auto uPtr = std::make_unique<SomeInt>(90);
+
+    replace_SomeInt_p(std::inout_ptr(uPtr));
+    assert(uPtr->value == 9084);
+  }
+  {
+    auto uPtr = std::make_unique<SomeInt>(90);
+
+    replace_SomeInt_void_p(std::inout_ptr<SomeInt*>(uPtr));
+    assert(uPtr->value == 9084);
+  }
+}
+
+void test_custom_ptr() {
+  // ConstructiblePtr
+  {
+    ConstructiblePtr<int> cPtr(new int{90});
+
+    replace_int_p(std::inout_ptr(cPtr));
+    assert(cPtr == 84);
+  }
+  // ResettablePtr
+  {
+    ResettablePtr<int> rPtr(new int{90});
+
+    replace_int_p(std::inout_ptr(rPtr));
+    assert(rPtr == 84);
+  }
+  // NonConstructiblePtr
+  {
+    NonConstructiblePtr<int> nPtr;
+    nPtr.reset(new int{90});
+
+    replace_int_p(std::inout_ptr(nPtr));
+    assert(nPtr == 84);
+  }
+}
+
+int main(int, char**) {
+  test_raw_ptr();
+  test_unique_ptr();
+  test_custom_ptr();
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.compile.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.compile.pass.cpp
new file mode 100644
index 000000000000000..18979d014dc0137
--- /dev/null
+++ b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.compile.pass.cpp
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++17, c++20
+
+// <memory>
+
+// [inout.ptr.t], class template inout_ptr_t
+// template<class Smart, class Pointer, class... Args>
+//   class inout_ptr_t;                                        // since c++23
+
+#include <memory>
+
+int main(int, char**) {
+  {
+    std::unique_ptr<int> uPtr;
+
+    std::inout_ptr_t<std::unique_ptr<int>, int*>{uPtr};
+  }
+  {
+    std::unique_ptr<int> uPtr;
+
+    std::inout_ptr_t<std::unique_ptr<int>, int*>{uPtr};
+  }
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.verify.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.verify.cpp
new file mode 100644
index 000000000000000..33cc55520bb40f6
--- /dev/null
+++ b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.verify.cpp
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++17, c++20
+
+// <memory>
+
+// [inout.ptr.t], class template inout_ptr_t
+// template<class Smart, class Pointer, class... Args>
+//   class inout_ptr_t;                                        // since c++23
+
+#include <memory>
+
+int main(int, char**) {
+  // `std::inout_ptr<>` does not support `std::shared_ptr<>`.
+  {
+    std::shared_ptr<int> sPtr;
+
+    // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed due to requirement '!__is_specialization_v<std::shared_ptr<int>, std::shared_ptr>'{{.*}}std::shared_ptr<> is not supported}}
+    std::inout_ptr_t<std::shared_ptr<int>, int*>{sPtr};
+  }
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.verify.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.verify.cpp
new file mode 100644
index 000000000000000..3e23e543781206e
--- /dev/null
+++ b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.verify.cpp
@@ -0,0 +1,30 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++17, c++20
+
+// <memory>
+
+// [inout.ptr], function template inout_ptr
+// template<class Pointer = void, class Smart, class... Args>
+//   auto inout_ptr(Smart& s, Args&&... args);                 // since c++23
+
+#include <memory>
+
+int main(int, char**) {
+  // `std::inout_ptr<>` does not support `std::shared_ptr<>`.
+  {
+    std::shared_ptr<int> sPtr;
+
+    // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed due to requirement '!__is_specialization_v<std::shared_ptr<int>, std::shared_ptr>'{{.*}}std::shared_ptr<> is not supported}}
+    auto inoutUPtr1 = std::inout_ptr(sPtr);
+    auto inoutUPtr2 = std::inout_ptr<int*>(sPtr);
+  }
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.compile.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.compile.pass.cpp
new file mode 100644
index 000000000000000..71f78a5bf770a00
--- /dev/null
+++ b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.compile.pass.cpp
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++17, c++20
+
+// <memory>
+
+// [out.ptr], function template out_ptr
+// template<class Pointer = void, class Smart, class... Args>
+//   auto out_ptr(Smart& s, Args&&... args);                   // since c++23
+
+#include <memory>
+
+int main(int, char**) {
+  {
+    std::unique_ptr<int> uPtr;
+
+    auto outUPtr1 = std::out_ptr(uPtr);
+    auto outUPtr2 = std::out_ptr<int*>(uPtr);
+  }
+  {
+    std::shared_ptr<int> sPtr;
+
+    auto outSPtr1 = std::out_ptr(sPtr, [](auto* p) { delete p; });
+    auto outSPtr2 = std::out_ptr<int*>(sPtr, [](auto* p) { delete p; });
+  }
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.pass.cpp
new file mode 100644
index 000000000000000..2ccf48643c3323d
--- /dev/null
+++ b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.pass.cpp
@@ -0,0 +1,163 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++17, c++20
+
+// <memory>
+
+// [out.ptr.t], class template out_ptr_t
+// template<class Smart, class Pointer, class... Args>
+//   class out_ptr_t;                                          // since c++23
+
+// [out.ptr], function template out_ptr
+// template<class Pointer = void, class Smart, class... Args>
+//   auto out_ptr(Smart& s, Args&&... args);                   // since c++23
+
+#include <cassert>
+#include <memory>
+
+#include "../types.h"
+
+// Test helpers.
+
+void get_int_p(int** pp) { *pp = new int{84}; }
+
+void get_int_p_nullptr(int** pp) { *pp = nullptr; }
+
+void get_int_void_p(void** pp) { *(reinterpret_cast<int**>(pp)) = new int{84}; }
+
+void get_int_void_p_nullptr(void** pp) { *pp = nullptr; }
+
+void get_SomeInt_p(SomeInt** pp) { *pp = new SomeInt{84}; }
+
+void get_SomeInt_void_p(void** pp) { *pp = reinterpret_cast<int*>(new int{84}); }
+
+// Test `std::out_ptr()` function.
+
+void test_raw_ptr() {
+  {
+    auto n{90};
+    auto rPtr = &n;
+
+    get_int_p(std::inout_ptr<int*>(rPtr));
+    assert(*rPtr == 84);
+    delete rPtr;
+
+    get_int_p_nullptr(std::out_ptr<int*>(rPtr));
+    assert(rPtr == nullptr);
+
+    get_int_void_p(std::inout_ptr<int*>(rPtr));
+    assert(*rPtr == 84);
+    delete rPtr;
+
+    get_int_void_p_nullptr(std::out_ptr<int*>(rPtr));
+    assert(rPtr == nullptr);
+  }
+  {
+    SomeInt si{90};
+    auto* rPtr = &si;
+
+    get_SomeInt_p(std::out_ptr(rPtr));
+    assert(rPtr->value == 84);
+    delete rPtr;
+  }
+  {
+    SomeInt si{90};
+    auto* rPtr = &si;
+
+    get_SomeInt_void_p(std::out_ptr<SomeInt*>(rPtr));
+    assert(rPtr->value == 84);
+    delete rPtr;
+  }
+}
+
+void test_shared_ptr() {
+  {
+    auto sPtr = std::make_shared<int>(90);
+
+    get_int_p(std::out_ptr(sPtr, [](auto* p) { delete p; }));
+    assert(*sPtr == 84);
+
+    sPtr.reset(new int(90));
+
+    get_int_void_p(std::out_ptr(sPtr, [](auto* p) { delete p; }));
+    assert(*sPtr == 84);
+  }
+  {
+    auto sPtr = std::make_shared<SomeInt>(90);
+
+    get_SomeInt_p(std::out_ptr(sPtr, [](auto* p) { delete p; }));
+    assert(sPtr->value == 84);
+  }
+  {
+    auto sPtr = std::make_shared<SomeInt>(90);
+
+    get_SomeInt_void_p(std::out_ptr<SomeInt*>(sPtr, [](auto* p) { delete p; }));
+    assert(sPtr->value == 84);
+  }
+}
+
+void test_unique_ptr() {
+  {
+    auto uPtr = std::make_unique<int>(90);
+
+    get_int_p(std::out_ptr(uPtr));
+    assert(*uPtr == 84);
+
+    uPtr.reset(new int{90});
+
+    get_int_void_p(std::out_ptr(uPtr));
+    assert(*uPtr == 84);
+  }
+  {
+    auto uPtr = std::make_unique<SomeInt>(90);
+
+    get_SomeInt_p(std::out_ptr(uPtr));
+    assert(uPtr->value == 84);
+  }
+  {
+    auto uPtr = std::make_unique<SomeInt>(90);
+
+    get_SomeInt_void_p(std::out_ptr<SomeInt*>(uPtr));
+    assert(uPtr->value == 84);
+  }
+}
+
+void test_custom_ptr() {
+  // ConstructiblePtr
+  {
+    ConstructiblePtr<int> cPtr(new int{90});
+
+    get_int_p(std::out_ptr(cPtr));
+    assert(cPtr == 84);
+  }
+  // ResettablePtr
+  {
+    ResettablePtr<int> rPtr(new int{90});
+
+    get_int_p(std::out_ptr(rPtr));
+    assert(rPtr == 84);
+  }
+  // NonConstructiblePtr
+  {
+    NonConstructiblePtr<int> nPtr;
+    nPtr.reset(new int{90});
+
+    get_int_p(std::out_ptr(nPtr));
+    assert(nPtr == 84);
+  }
+}
+
+int main(int, char**) {
+  test_raw_ptr();
+  test_shared_ptr();
+  test_unique_ptr();
+  test_custom_ptr();
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.compile.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.compile.pass.cpp
new file mode 100644
index 000000000000000..12ad53ac3811e82
--- /dev/null
+++ b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.compile.pass.cpp
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++17, c++20
+
+// <memory>
+
+// [out.ptr.t], class template out_ptr_t
+// template<class Smart, class Pointer, class... Args>
+//   class out_ptr_t;                                          // since c++23
+
+#include <memory>
+
+int main(int, char**) {
+  {
+    std::unique_ptr<int> uPtr;
+
+    std::out_ptr_t<std::unique_ptr<int>, int*>{uPtr};
+  }
+  {
+    std::unique_ptr<int, std::default_delete<int>> uPtr;
+
+    std::out_ptr_t<decltype(uPtr), int*, std::default_delete<int>>{uPtr, std::default_delete<int>{}};
+  }
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.verify.cpp b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.verify.cpp
new file mode 100644
index 000000000000000..c89007b77ae82f9
--- /dev/null
+++ b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.verify.cpp
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++17, c++20
+
+// <memory>
+
+// [out.ptr.t], class template out_ptr_t
+// template<class Smart, class Pointer, class... Args>
+//   class out_ptr_t;                                          // since c++23
+
+#include <memory>
+
+int main(int, char**) {
+  // `std::out_ptr_t<>` requires `std::shared_ptr<>` with a deleter.
+  {
+    std::shared_ptr<int> sPtr;
+
+    // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed due to requirement '!__is_specialization_v<std::shared_ptr<int>, std::shared_ptr> || sizeof...(_Args) > 0'{{.*}}Specialization of std::shared_ptr<> requires a deleter.}}
+    std::out_ptr_t<std::shared_ptr<int>, int*>{sPtr};
+  }
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.verify.cpp b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.verify.cpp
new file mode 100644
index 000000000000000..f48592059ea0a08
--- /dev/null
+++ b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.verify.cpp
@@ -0,0 +1,30 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++17, c++20
+
+// <memory>
+
+// [out.ptr], function template out_ptr
+// template<class Pointer = void, class Smart, class... Args>
+//   auto out_ptr(Smart& s, Args&&... args);                   // since c++23
+
+#include <memory>
+
+int main(int, char**) {
+  // `std::out_ptr<>` requires `std::shared_ptr<>` with a deleter.
+  {
+    std::shared_ptr<int> sPtr;
+
+    // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed due to requirement '!__is_specialization_v<std::shared_ptr<int>, std::shared_ptr> || sizeof...(_Args) > 0'{{.*}}Specialization of std::shared_ptr<> requires a deleter.}}
+    auto outSPtr1 = std::out_ptr(sPtr);
+    auto outSPtr2 = std::out_ptr<int*>(sPtr);
+  }
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/smartptr/adapt/types.h b/libcxx/test/std/utilities/smartptr/adapt/types.h
new file mode 100644
index 000000000000000..0e2dad400308dc7
--- /dev/null
+++ b/libcxx/test/std/utilities/smartptr/adapt/types.h
@@ -0,0 +1,77 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 TEST_LIBCXX_UTILITIES_SMARTPTR_ADAPT_TYPES_H
+#define TEST_LIBCXX_UTILITIES_SMARTPTR_ADAPT_TYPES_H
+
+#include <type_traits>
+#include <memory>
+
+struct ResetArg {};
+
+// Custom pointer types.
+
+template <typename _Tp>
+struct ConstructiblePtr {
+  using pointer = _Tp*;
+  std::unique_ptr<_Tp> ptr;
+
+  ConstructiblePtr() = default;
+  explicit ConstructiblePtr(_Tp* p) : ptr{p} {}
+
+  auto operator==(_Tp val) { return *ptr == val; }
+
+  auto* get() const { return ptr.get(); }
+
+  void release() { ptr.release(); }
+};
+
+static_assert(std::is_same_v<std::__pointer_of_t< ConstructiblePtr<int>>, int* >);
+static_assert(std::is_constructible_v< ConstructiblePtr<int>, int* >);
+
+template <typename _Tp>
+struct ResettablePtr {
+  using element_type = _Tp;
+  std::unique_ptr<_Tp> ptr;
+
+  explicit ResettablePtr(_Tp* p) : ptr{p} {}
+
+  auto operator*() const { return *ptr; }
+
+  auto operator==(_Tp val) { return *ptr == val; }
+
+  void reset() { ptr.reset(); }
+  void reset(_Tp* p, ResetArg) { ptr.reset(p); }
+
+  auto* get() const { return ptr.get(); }
+
+  void release() { ptr.release(); }
+};
+
+static_assert(std::is_same_v<std::__pointer_of_t< ResettablePtr<int>>, int* >);
+static_assert(std::is_constructible_v< ResettablePtr<int>, int* >);
+
+template <typename _Tp>
+struct NonConstructiblePtr : public ResettablePtr<_Tp> {
+  NonConstructiblePtr() : NonConstructiblePtr::ResettablePtr(nullptr){};
+
+  void reset(_Tp* p) { ResettablePtr<_Tp>::ptr.reset(p); }
+};
+
+static_assert(std::is_same_v<std::__pointer_of_t< NonConstructiblePtr<int>>, int* >);
+static_assert(!std::is_constructible_v< NonConstructiblePtr<int>, int* >);
+
+// Custom types.
+
+struct SomeInt {
+  int value;
+
+  constexpr explicit SomeInt(int val = 0) : value{val} {}
+};
+
+#endif // TEST_LIBCXX_UTILITIES_SMARTPTR_ADAPT_TYPES_H
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 47ee20de0fdc2b2..9910afa15cff66f 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -854,7 +854,6 @@ def add_version_header(tc):
                 "c++26": 202311,  # P2833R2 Freestanding Library: inout expected span
             },
             "headers": ["memory"],
-            "unimplemented": True,
         },
         {
             "name": "__cpp_lib_parallel_algorithm",

>From 4bc779ef33ed55605e502f597b94fff69b9e95f9 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <zingam at outlook.com>
Date: Thu, 30 Nov 2023 09:58:10 +0200
Subject: [PATCH 2/4] [out_ptr] Address review comments + new tests

---
 libcxx/docs/FeatureTestMacroTable.rst         |  2 +-
 libcxx/docs/Status/Cxx23Issues.csv            |  4 +-
 libcxx/docs/Status/Cxx23Papers.csv            |  2 +-
 libcxx/docs/Status/Cxx2cIssues.csv            |  2 +-
 libcxx/include/__memory/inout_ptr.h           |  8 ++--
 libcxx/include/__memory/out_ptr.h             |  2 +-
 libcxx/include/__memory/pointer_traits.h      |  2 -
 libcxx/include/version                        |  2 +-
 .../memory.version.compile.pass.cpp           | 16 +++----
 .../version.version.compile.pass.cpp          | 16 +++----
 ...le.pass.cpp => inout.ptr.general.pass.cpp} |  4 ++
 .../adapt/inout.ptr/inout.ptr.pass.cpp        |  4 --
 .../adapt/inout.ptr/inout.ptr.t.ctor.pass.cpp | 43 +++++++++++++++++++
 ...le.pass.cpp => inout.ptr.t.deref.pass.cpp} |  3 ++
 .../adapt/inout.ptr/inout.ptr.verify.cpp      |  1 +
 ...pile.pass.cpp => out.ptr.general.pass.cpp} |  4 ++
 .../smartptr/adapt/out.ptr/out.ptr.pass.cpp   |  4 --
 .../adapt/out.ptr/out.ptr.t.ctor.pass.cpp     | 41 ++++++++++++++++++
 ...pile.pass.cpp => out.ptr.t.deref.pass.cpp} |  3 ++
 .../smartptr/adapt/out.ptr/out.ptr.verify.cpp |  1 +
 20 files changed, 122 insertions(+), 42 deletions(-)
 rename libcxx/test/std/utilities/smartptr/adapt/inout.ptr/{inout.ptr.compile.pass.cpp => inout.ptr.general.pass.cpp} (92%)
 create mode 100644 libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.ctor.pass.cpp
 rename libcxx/test/std/utilities/smartptr/adapt/inout.ptr/{inout.ptr.t.compile.pass.cpp => inout.ptr.t.deref.pass.cpp} (91%)
 rename libcxx/test/std/utilities/smartptr/adapt/out.ptr/{out.ptr.compile.pass.cpp => out.ptr.general.pass.cpp} (92%)
 create mode 100644 libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.ctor.pass.cpp
 rename libcxx/test/std/utilities/smartptr/adapt/out.ptr/{out.ptr.t.compile.pass.cpp => out.ptr.t.deref.pass.cpp} (92%)

diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 4b2adc70f51740c..eb7957c07e30752 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -426,7 +426,7 @@ Status
     --------------------------------------------------- -----------------
     ``__cpp_lib_linalg``                                *unimplemented*
     --------------------------------------------------- -----------------
-    ``__cpp_lib_out_ptr``                               *unimplemented*
+    ``__cpp_lib_out_ptr``                               ``202311L``
     --------------------------------------------------- -----------------
     ``__cpp_lib_ratio``                                 ``202306L``
     --------------------------------------------------- -----------------
diff --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv
index e5ad365f9ffb877..3e0122706930dab 100644
--- a/libcxx/docs/Status/Cxx23Issues.csv
+++ b/libcxx/docs/Status/Cxx23Issues.csv
@@ -192,7 +192,7 @@
 "`3515 <https://wg21.link/LWG3515>`__","§[stacktrace.basic.nonmem]: ``operator<<`` should be less templatized", "November 2022","","",""
 "`3545 <https://wg21.link/LWG3545>`__","``std::pointer_traits`` should be SFINAE-friendly", "November 2022","|Complete|","18.0",""
 "`3569 <https://wg21.link/LWG3569>`__","``join_view`` fails to support ranges of ranges with non-default_initializable iterators", "November 2022","","","|ranges|"
-"`3594 <https://wg21.link/LWG3594>`__","``inout_ptr`` — inconsistent ``release()`` in destructor", "November 2022","|Complete|","17.0",""
+"`3594 <https://wg21.link/LWG3594>`__","``inout_ptr`` — inconsistent ``release()`` in destructor", "November 2022","|Complete|","18.0",""
 "`3597 <https://wg21.link/LWG3597>`__","Unsigned integer types don't model advanceable", "November 2022","","","|ranges|"
 "`3600 <https://wg21.link/LWG3600>`__","Making ``istream_iterator`` copy constructor trivial is an ABI break", "November 2022","","",""
 "`3629 <https://wg21.link/LWG3629>`__","``make_error_code`` and ``make_error_condition`` are customization points","November 2022","|Complete|","16.0",""
@@ -282,7 +282,7 @@
 "`3645 <https://wg21.link/LWG3645>`__","``resize_and_overwrite`` is overspecified to call its callback with lvalues","February 2023","|Complete|","14.0",""
 "`3655 <https://wg21.link/LWG3655>`__","The ``INVOKE`` operation and union types","February 2023","|Complete|","18.0",""
 "`3723 <https://wg21.link/LWG3723>`__","``priority_queue::push_range`` needs to ``append_range``","February 2023","","","|ranges|"
-"`3734 <https://wg21.link/LWG3734>`__","Inconsistency in ``inout_ptr`` and ``out_ptr`` for empty case","February 2023","|Complete|","17.0",""
+"`3734 <https://wg21.link/LWG3734>`__","Inconsistency in ``inout_ptr`` and ``out_ptr`` for empty case","February 2023","|Complete|","18.0",""
 "`3772 <https://wg21.link/LWG3772>`__","``repeat_view``'s ``piecewise`` constructor is missing Postconditions","February 2023","","","|ranges|"
 "`3786 <https://wg21.link/LWG3786>`__","Flat maps' deduction guide needs to default ``Allocator`` to be useful","February 2023","","",""
 "`3803 <https://wg21.link/LWG3803>`__","``flat_foo`` constructors taking ``KeyContainer`` lack ``KeyCompare`` parameter","February 2023","","",""
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index 198b0ab9d390e33..02352837fa4da8e 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -13,7 +13,7 @@
 "","","","","","",""
 "`P0401R6 <https://wg21.link/P0401R6>`__","LWG","Providing size feedback in the Allocator interface","June 2021","|Complete|","15.0"
 "`P0448R4 <https://wg21.link/P0448R4>`__","LWG","A strstream replacement using span<charT> as buffer","June 2021","",""
-"`P1132R8 <https://wg21.link/P1132R8>`__","LWG","out_ptr - a scalable output pointer abstraction","June 2021","|Complete|","17.0"
+"`P1132R8 <https://wg21.link/P1132R8>`__","LWG","out_ptr - a scalable output pointer abstraction","June 2021","|Complete|","18.0"
 "`P1328R1 <https://wg21.link/P1328R1>`__","LWG","Making std::type_info::operator== constexpr","June 2021","|Complete|","17.0"
 "`P1425R4 <https://wg21.link/P1425R4>`__","LWG","Iterators pair constructors for stack and queue","June 2021","|Complete|","14.0","|ranges|"
 "`P1518R2 <https://wg21.link/P1518R2>`__","LWG","Stop overconstraining allocators in container deduction guides","June 2021","|Complete|","13.0"
diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv
index fe0f13f6e8cb2c2..1f407e322f89134 100644
--- a/libcxx/docs/Status/Cxx2cIssues.csv
+++ b/libcxx/docs/Status/Cxx2cIssues.csv
@@ -24,7 +24,7 @@
 "`3749 <https://wg21.link/LWG3749>`__","``common_iterator`` should handle integer-class difference types","Kona November 2023","","",""
 "`3809 <https://wg21.link/LWG3809>`__","Is ``std::subtract_with_carry_engine<uint16_t>`` supposed to work","Kona November 2023","","",""
 "`3892 <https://wg21.link/LWG3892>`__","Incorrect formatting of nested ranges and tuples","Kona November 2023","|Complete|","17.0","|format|"
-"`3897 <https://wg21.link/LWG3897>`__","``inout_ptr`` will not update raw pointer to 0","Kona November 2023","","",""
+"`3897 <https://wg21.link/LWG3897>`__","``inout_ptr`` will not update raw pointer to 0","Kona November 2023","|Complete|","18.0",""
 "`3946 <https://wg21.link/LWG3946>`__","The definition of ``const_iterator_t`` should be reworked","Kona November 2023","","",""
 "`3947 <https://wg21.link/LWG3947>`__","Unexpected constraints on ``adjacent_transform_view::base()``","Kona November 2023","","","|ranges|"
 "`3948 <https://wg21.link/LWG3948>`__","``possibly-const-range and as-const-pointer`` should be ``noexcept``","Kona November 2023","","","|ranges|"
diff --git a/libcxx/include/__memory/inout_ptr.h b/libcxx/include/__memory/inout_ptr.h
index c2044a4642cf4ee..f91ecd8baff57d1 100644
--- a/libcxx/include/__memory/inout_ptr.h
+++ b/libcxx/include/__memory/inout_ptr.h
@@ -51,8 +51,10 @@ class _LIBCPP_TEMPLATE_VIS inout_ptr_t {
   _LIBCPP_HIDE_FROM_ABI inout_ptr_t(const inout_ptr_t&) = delete;
 
   _LIBCPP_HIDE_FROM_ABI ~inout_ptr_t() {
-    if (!__p_) {
-      return;
+    if constexpr (!is_pointer_v<_Smart>) {
+      if (!__p_) {
+        return;
+      }
     }
 
     using _SP = __pointer_of_or_t<_Smart, _Pointer>;
@@ -90,7 +92,7 @@ class _LIBCPP_TEMPLATE_VIS inout_ptr_t {
 template <class _Pointer = void, class _Smart, class... _Args>
 _LIBCPP_HIDE_FROM_ABI auto inout_ptr(_Smart& __s, _Args&&... __args) {
   using _Ptr = conditional_t<is_void_v<_Pointer>, __pointer_of_t<_Smart>, _Pointer>;
-  return std::inout_ptr_t<_Smart, _Ptr, _Args&&...>{__s, std::forward<_Args>(__args)...};
+  return std::inout_ptr_t<_Smart, _Ptr, _Args&&...>(__s, std::forward<_Args>(__args)...);
 }
 
 #endif // _LIBCPP_STD_VER >= 23
diff --git a/libcxx/include/__memory/out_ptr.h b/libcxx/include/__memory/out_ptr.h
index 09c77cbafe69e01..eebc18c97fdcdb5 100644
--- a/libcxx/include/__memory/out_ptr.h
+++ b/libcxx/include/__memory/out_ptr.h
@@ -87,7 +87,7 @@ class _LIBCPP_TEMPLATE_VIS out_ptr_t {
 template <class _Pointer = void, class _Smart, class... _Args>
 _LIBCPP_HIDE_FROM_ABI auto out_ptr(_Smart& __s, _Args&&... __args) {
   using _Ptr = conditional_t<is_void_v<_Pointer>, __pointer_of_t<_Smart>, _Pointer>;
-  return std::out_ptr_t<_Smart, _Ptr, _Args&&...>{__s, std::forward<_Args>(__args)...};
+  return std::out_ptr_t<_Smart, _Ptr, _Args&&...>(__s, std::forward<_Args>(__args)...);
 }
 
 #endif // _LIBCPP_STD_VER >= 23
diff --git a/libcxx/include/__memory/pointer_traits.h b/libcxx/include/__memory/pointer_traits.h
index 2be0deb50cb8ed1..4e902746e6a35b1 100644
--- a/libcxx/include/__memory/pointer_traits.h
+++ b/libcxx/include/__memory/pointer_traits.h
@@ -15,11 +15,9 @@
 #include <__type_traits/conditional.h>
 #include <__type_traits/conjunction.h>
 #include <__type_traits/decay.h>
-#include <__type_traits/enable_if.h>
 #include <__type_traits/is_class.h>
 #include <__type_traits/is_function.h>
 #include <__type_traits/is_void.h>
-#include <__type_traits/negation.h>
 #include <__type_traits/void_t.h>
 #include <__utility/declval.h>
 #include <__utility/forward.h>
diff --git a/libcxx/include/version b/libcxx/include/version
index 2203dfd0e600580..079e9f346a9172d 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -502,7 +502,7 @@ __cpp_lib_within_lifetime                               202306L <type_traits>
 // # define __cpp_lib_hazard_pointer                       202306L
 // # define __cpp_lib_linalg                               202311L
 # undef  __cpp_lib_out_ptr
-// # define __cpp_lib_out_ptr                              202311L
+# define __cpp_lib_out_ptr                              202311L
 # define __cpp_lib_ratio                                202306L
 // # define __cpp_lib_rcu                                  202306L
 // # define __cpp_lib_saturation_arithmetic                202311L
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp
index c3b37ed35a3ad0e..f50f1788cc497c2 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp
@@ -616,17 +616,11 @@
 #   error "__cpp_lib_make_unique should have the value 201304L in c++26"
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_out_ptr
-#     error "__cpp_lib_out_ptr should be defined in c++26"
-#   endif
-#   if __cpp_lib_out_ptr != 202311L
-#     error "__cpp_lib_out_ptr should have the value 202311L in c++26"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_out_ptr
-#     error "__cpp_lib_out_ptr should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_out_ptr
+#   error "__cpp_lib_out_ptr should be defined in c++26"
+# endif
+# if __cpp_lib_out_ptr != 202311L
+#   error "__cpp_lib_out_ptr should have the value 202311L in c++26"
 # endif
 
 # ifndef __cpp_lib_ranges
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index 413fca0e79fecee..272177da0b444e0 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -6917,17 +6917,11 @@
 #   error "__cpp_lib_optional should have the value 202110L in c++26"
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_out_ptr
-#     error "__cpp_lib_out_ptr should be defined in c++26"
-#   endif
-#   if __cpp_lib_out_ptr != 202311L
-#     error "__cpp_lib_out_ptr should have the value 202311L in c++26"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_out_ptr
-#     error "__cpp_lib_out_ptr should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_out_ptr
+#   error "__cpp_lib_out_ptr should be defined in c++26"
+# endif
+# if __cpp_lib_out_ptr != 202311L
+#   error "__cpp_lib_out_ptr should have the value 202311L in c++26"
 # endif
 
 # if !defined(_LIBCPP_VERSION)
diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.compile.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.general.pass.cpp
similarity index 92%
rename from libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.compile.pass.cpp
rename to libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.general.pass.cpp
index d2eb8c3a6ac0081..1b45d04f7942d7c 100644
--- a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.compile.pass.cpp
+++ b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.general.pass.cpp
@@ -21,14 +21,18 @@ int main(int, char**) {
     std::unique_ptr<int> uPtr;
 
     auto inoutUPtr1 = std::inout_ptr(uPtr);
+    (void)inoutUPtr1;
     auto inoutUPtr2 = std::inout_ptr<int*>(uPtr);
+    (void)inoutUPtr2;
   }
   {
     auto deleter = [](auto* p) { delete p; };
     std::unique_ptr<int, decltype(deleter)> uPtr;
 
     auto inoutUPtr1 = std::inout_ptr(uPtr, deleter);
+    (void)inoutUPtr1;
     auto inoutUPtr2 = std::inout_ptr<int*>(uPtr, deleter);
+    (void)inoutUPtr2;
   }
 
   return 0;
diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.pass.cpp
index ece562805342780..58f09dc3a9ec3b2 100644
--- a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.pass.cpp
+++ b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.pass.cpp
@@ -10,10 +10,6 @@
 
 // <memory>
 
-// [inout.ptr.t], class template inout_ptr_t
-// template<class Smart, class Pointer, class... Args>
-//   class inout_ptr_t;                                        // since c++23
-
 // [inout.ptr], function template inout_ptr
 // template<class Pointer = void, class Smart, class... Args>
 //   auto inout_ptr(Smart& s, Args&&... args);                 // since c++23
diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.ctor.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.ctor.pass.cpp
new file mode 100644
index 000000000000000..0a21a41539e432e
--- /dev/null
+++ b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.ctor.pass.cpp
@@ -0,0 +1,43 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++17, c++20
+
+// <memory>
+
+// [inout.ptr.t], class template inout_ptr_t
+// template<class Smart, class Pointer, class... Args>
+//   class inout_ptr_t;                                        // since c++23
+
+// explicit inout_ptr_t(Smart&, Args...);
+
+#include <memory>
+
+#include "test_convertible.h"
+
+int main(int, char**) {
+  {
+    std::unique_ptr<int> uPtr;
+
+    std::inout_ptr_t<std::unique_ptr<int>, int*>{uPtr};
+
+    static_assert(
+        !test_convertible<std::inout_ptr_t<std::unique_ptr<int>, int*>>(), "This constructor must be explicit");
+  }
+  {
+    auto deleter = [](auto* p) { delete p; };
+    std::unique_ptr<int, decltype(deleter)> uPtr;
+
+    std::inout_ptr_t<std::unique_ptr<int, decltype(deleter)>, int*>{uPtr};
+
+    static_assert(!test_convertible<std::inout_ptr_t<std::unique_ptr<int, decltype(deleter)>, int*>>(),
+                  "This constructor must be explicit");
+  }
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.compile.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.deref.pass.cpp
similarity index 91%
rename from libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.compile.pass.cpp
rename to libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.deref.pass.cpp
index 18979d014dc0137..86a055a7644e255 100644
--- a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.compile.pass.cpp
+++ b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.deref.pass.cpp
@@ -14,6 +14,9 @@
 // template<class Smart, class Pointer, class... Args>
 //   class inout_ptr_t;                                        // since c++23
 
+// operator Pointer*() const noexcept;
+// operator void**() const noexcept;
+
 #include <memory>
 
 int main(int, char**) {
diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.verify.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.verify.cpp
index 3e23e543781206e..eb296767085b74a 100644
--- a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.verify.cpp
+++ b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.verify.cpp
@@ -23,6 +23,7 @@ int main(int, char**) {
 
     // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed due to requirement '!__is_specialization_v<std::shared_ptr<int>, std::shared_ptr>'{{.*}}std::shared_ptr<> is not supported}}
     auto inoutUPtr1 = std::inout_ptr(sPtr);
+    // expected-error@*:* {{no matching conversion for functional-style cast from 'std::shared_ptr<int>' to 'std::inout_ptr_t<shared_ptr<int>, _Ptr>' (aka 'inout_ptr_t<std::shared_ptr<int>, int *>'}}
     auto inoutUPtr2 = std::inout_ptr<int*>(sPtr);
   }
 
diff --git a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.compile.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.general.pass.cpp
similarity index 92%
rename from libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.compile.pass.cpp
rename to libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.general.pass.cpp
index 71f78a5bf770a00..84bea7248e7a6ee 100644
--- a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.compile.pass.cpp
+++ b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.general.pass.cpp
@@ -21,13 +21,17 @@ int main(int, char**) {
     std::unique_ptr<int> uPtr;
 
     auto outUPtr1 = std::out_ptr(uPtr);
+    (void)outUPtr1;
     auto outUPtr2 = std::out_ptr<int*>(uPtr);
+    (void)outUPtr2;
   }
   {
     std::shared_ptr<int> sPtr;
 
     auto outSPtr1 = std::out_ptr(sPtr, [](auto* p) { delete p; });
+    (void)outSPtr1;
     auto outSPtr2 = std::out_ptr<int*>(sPtr, [](auto* p) { delete p; });
+    (void)outSPtr2;
   }
 
   return 0;
diff --git a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.pass.cpp
index 2ccf48643c3323d..a5189717fad6242 100644
--- a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.pass.cpp
+++ b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.pass.cpp
@@ -10,10 +10,6 @@
 
 // <memory>
 
-// [out.ptr.t], class template out_ptr_t
-// template<class Smart, class Pointer, class... Args>
-//   class out_ptr_t;                                          // since c++23
-
 // [out.ptr], function template out_ptr
 // template<class Pointer = void, class Smart, class... Args>
 //   auto out_ptr(Smart& s, Args&&... args);                   // since c++23
diff --git a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.ctor.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.ctor.pass.cpp
new file mode 100644
index 000000000000000..39604247216e817
--- /dev/null
+++ b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.ctor.pass.cpp
@@ -0,0 +1,41 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++17, c++20
+
+// <memory>
+
+// [out.ptr.t], class template out_ptr_t
+// template<class Smart, class Pointer, class... Args>
+//   class out_ptr_t;                                          // since c++23
+
+// explicit out_ptr_t(Smart&, Args...);
+
+#include <memory>
+
+#include "test_convertible.h"
+
+int main(int, char**) {
+  {
+    std::unique_ptr<int> uPtr;
+
+    std::out_ptr_t<std::unique_ptr<int>, int*>{uPtr};
+
+    static_assert(!test_convertible<std::out_ptr_t<std::unique_ptr<int>, int*>>(), "This constructor must be explicit");
+  }
+  {
+    std::unique_ptr<int, std::default_delete<int>> uPtr;
+
+    std::out_ptr_t<decltype(uPtr), int*, std::default_delete<int>>{uPtr, std::default_delete<int>{}};
+
+    static_assert(!test_convertible<std::out_ptr_t<decltype(uPtr), int*, std::default_delete<int>>>(),
+                  "This constructor must be explicit");
+  }
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.compile.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.deref.pass.cpp
similarity index 92%
rename from libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.compile.pass.cpp
rename to libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.deref.pass.cpp
index 12ad53ac3811e82..a0f3af8f87fd748 100644
--- a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.compile.pass.cpp
+++ b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.deref.pass.cpp
@@ -14,6 +14,9 @@
 // template<class Smart, class Pointer, class... Args>
 //   class out_ptr_t;                                          // since c++23
 
+// operator Pointer*() const noexcept;
+// operator void**() const noexcept;
+
 #include <memory>
 
 int main(int, char**) {
diff --git a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.verify.cpp b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.verify.cpp
index f48592059ea0a08..3c51583421e7668 100644
--- a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.verify.cpp
+++ b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.verify.cpp
@@ -23,6 +23,7 @@ int main(int, char**) {
 
     // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed due to requirement '!__is_specialization_v<std::shared_ptr<int>, std::shared_ptr> || sizeof...(_Args) > 0'{{.*}}Specialization of std::shared_ptr<> requires a deleter.}}
     auto outSPtr1 = std::out_ptr(sPtr);
+    // expected-error@*:* {{no matching conversion for functional-style cast from 'std::shared_ptr<int>' to 'std::out_ptr_t<shared_ptr<int>, _Ptr>' (aka 'out_ptr_t<std::shared_ptr<int>, int *>')}}
     auto outSPtr2 = std::out_ptr<int*>(sPtr);
   }
 

>From b23e91a1ca684b8454fe84ff570b7245f52e49d1 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <zingam at outlook.com>
Date: Thu, 30 Nov 2023 15:03:00 +0200
Subject: [PATCH 3/4] [out_ptr] Added tests

---
 .../inout.ptr.compile.pass.cpp}               |  18 +-
 .../inout.ptr/inout.ptr.general.pass.cpp      | 184 +++++++++++++++-
 .../adapt/inout.ptr/inout.ptr.pass.cpp        | 201 ------------------
 ....pass.cpp => inout.ptr.t.convert.pass.cpp} |  20 +-
 ...eral.pass.cpp => out.ptr.compile.pass.cpp} |   4 -
 .../{out.ptr.pass.cpp => out.ptr.general.cpp} |   0
 .../adapt/out.ptr/out.ptr.t.convert.pass.cpp  |  58 +++++
 7 files changed, 256 insertions(+), 229 deletions(-)
 rename libcxx/test/std/utilities/smartptr/adapt/{out.ptr/out.ptr.t.deref.pass.cpp => inout.ptr/inout.ptr.compile.pass.cpp} (54%)
 delete mode 100644 libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.pass.cpp
 rename libcxx/test/std/utilities/smartptr/adapt/inout.ptr/{inout.ptr.t.deref.pass.cpp => inout.ptr.t.convert.pass.cpp} (55%)
 rename libcxx/test/std/utilities/smartptr/adapt/out.ptr/{out.ptr.general.pass.cpp => out.ptr.compile.pass.cpp} (92%)
 rename libcxx/test/std/utilities/smartptr/adapt/out.ptr/{out.ptr.pass.cpp => out.ptr.general.cpp} (100%)
 create mode 100644 libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.convert.pass.cpp

diff --git a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.deref.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.compile.pass.cpp
similarity index 54%
rename from libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.deref.pass.cpp
rename to libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.compile.pass.cpp
index a0f3af8f87fd748..d2eb8c3a6ac0081 100644
--- a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.deref.pass.cpp
+++ b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.compile.pass.cpp
@@ -10,12 +10,9 @@
 
 // <memory>
 
-// [out.ptr.t], class template out_ptr_t
-// template<class Smart, class Pointer, class... Args>
-//   class out_ptr_t;                                          // since c++23
-
-// operator Pointer*() const noexcept;
-// operator void**() const noexcept;
+// [inout.ptr], function template inout_ptr
+// template<class Pointer = void, class Smart, class... Args>
+//   auto inout_ptr(Smart& s, Args&&... args);                 // since c++23
 
 #include <memory>
 
@@ -23,12 +20,15 @@ int main(int, char**) {
   {
     std::unique_ptr<int> uPtr;
 
-    std::out_ptr_t<std::unique_ptr<int>, int*>{uPtr};
+    auto inoutUPtr1 = std::inout_ptr(uPtr);
+    auto inoutUPtr2 = std::inout_ptr<int*>(uPtr);
   }
   {
-    std::unique_ptr<int, std::default_delete<int>> uPtr;
+    auto deleter = [](auto* p) { delete p; };
+    std::unique_ptr<int, decltype(deleter)> uPtr;
 
-    std::out_ptr_t<decltype(uPtr), int*, std::default_delete<int>>{uPtr, std::default_delete<int>{}};
+    auto inoutUPtr1 = std::inout_ptr(uPtr, deleter);
+    auto inoutUPtr2 = std::inout_ptr<int*>(uPtr, deleter);
   }
 
   return 0;
diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.general.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.general.pass.cpp
index 1b45d04f7942d7c..58f09dc3a9ec3b2 100644
--- a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.general.pass.cpp
+++ b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.general.pass.cpp
@@ -14,26 +14,188 @@
 // template<class Pointer = void, class Smart, class... Args>
 //   auto inout_ptr(Smart& s, Args&&... args);                 // since c++23
 
+#include <cassert>
 #include <memory>
 
-int main(int, char**) {
+#include "../types.h"
+
+// Test helpers.
+
+void replace_int_p(int** pp) {
+  assert(**pp == 90);
+  delete *pp;
+  *pp = new int{84};
+}
+
+void replace_int_p_with_nullptr(int** pp) {
+  assert(**pp == 90);
+  delete *pp;
+  *pp = nullptr;
+}
+
+void replace_nullptr_with_int_p(int** pp) {
+  assert(*pp == nullptr);
+  *pp = new int{84};
+}
+
+void replace_int_void_p(void** pp) {
+  assert(*(static_cast<int*>(*pp)) == 90);
+  delete static_cast<int*>(*pp);
+  *pp = new int{84};
+}
+
+void replace_int_void_p_with_nullptr(void** pp) {
+  assert(*(static_cast<int*>(*pp)) == 90);
+  delete static_cast<int*>(*pp);
+  *pp = nullptr;
+}
+
+void replace_nullptr_with_int_void_p(void** pp) {
+  assert(*pp == nullptr);
+  *pp = new int{84};
+}
+
+void replace_SomeInt_p(SomeInt** pp) {
+  auto si = **pp;
+  assert(si.value == 90);
+  delete static_cast<SomeInt*>(*pp);
+  *pp = new SomeInt{9084};
+}
+
+void replace_SomeInt_void_p(void** pp) {
+  assert(reinterpret_cast<SomeInt*>(*pp)->value == 90);
+  delete static_cast<SomeInt*>(*pp);
+  *pp = reinterpret_cast<void*>(new SomeInt{9084});
+}
+
+// Test `std::inout_ptr()` function.
+
+void test_raw_ptr() {
+  {
+    auto rPtr = new int{90};
+
+    replace_int_p(std::inout_ptr<int*>(rPtr));
+    assert(*rPtr == 84);
+
+    delete rPtr;
+  }
+  {
+    auto rPtr = new int{90};
+
+    replace_int_p_with_nullptr(std::inout_ptr<int*>(rPtr));
+    assert(rPtr == nullptr);
+  }
+  {
+    int* rPtr = nullptr;
+
+    replace_nullptr_with_int_p(std::inout_ptr<int*>(rPtr));
+    assert(*rPtr == 84);
+    delete rPtr;
+  }
+  {
+    auto rPtr = new int{90};
+
+    replace_int_void_p(std::inout_ptr<int*>(rPtr));
+    assert(*rPtr == 84);
+    delete rPtr;
+  }
+  {
+    auto rPtr = new int{90};
+
+    replace_int_void_p_with_nullptr(std::inout_ptr<int*>(rPtr));
+    assert(rPtr == nullptr);
+  }
+  {
+    int* rPtr = nullptr;
+
+    replace_nullptr_with_int_void_p(std::inout_ptr<int*>(rPtr));
+    assert(*rPtr == 84);
+    delete rPtr;
+  }
+  {
+    auto* rPtr = new SomeInt{90};
+
+    replace_SomeInt_p(std::inout_ptr(rPtr));
+    assert(rPtr->value == 9084);
+    delete rPtr;
+  }
+  {
+    auto* rPtr = new SomeInt{90};
+
+    replace_SomeInt_void_p(std::inout_ptr<SomeInt*>(rPtr));
+    assert(rPtr->value == 9084);
+    delete rPtr;
+  }
+}
+
+void test_unique_ptr() {
+  {
+    auto uPtr = std::make_unique<int>(90);
+
+    replace_int_p(std::inout_ptr(uPtr));
+    assert(*uPtr == 84);
+  }
   {
     std::unique_ptr<int> uPtr;
 
-    auto inoutUPtr1 = std::inout_ptr(uPtr);
-    (void)inoutUPtr1;
-    auto inoutUPtr2 = std::inout_ptr<int*>(uPtr);
-    (void)inoutUPtr2;
+    replace_nullptr_with_int_p(std::inout_ptr(uPtr));
+    assert(*uPtr == 84);
   }
   {
-    auto deleter = [](auto* p) { delete p; };
-    std::unique_ptr<int, decltype(deleter)> uPtr;
+    auto uPtr = std::make_unique<int>(90);
 
-    auto inoutUPtr1 = std::inout_ptr(uPtr, deleter);
-    (void)inoutUPtr1;
-    auto inoutUPtr2 = std::inout_ptr<int*>(uPtr, deleter);
-    (void)inoutUPtr2;
+    replace_int_void_p(std::inout_ptr(uPtr));
+    assert(*uPtr == 84);
   }
+  {
+    std::unique_ptr<int> uPtr;
+
+    replace_nullptr_with_int_void_p(std::inout_ptr(uPtr));
+    assert(*uPtr == 84);
+  }
+  {
+    auto uPtr = std::make_unique<SomeInt>(90);
+
+    replace_SomeInt_p(std::inout_ptr(uPtr));
+    assert(uPtr->value == 9084);
+  }
+  {
+    auto uPtr = std::make_unique<SomeInt>(90);
+
+    replace_SomeInt_void_p(std::inout_ptr<SomeInt*>(uPtr));
+    assert(uPtr->value == 9084);
+  }
+}
+
+void test_custom_ptr() {
+  // ConstructiblePtr
+  {
+    ConstructiblePtr<int> cPtr(new int{90});
+
+    replace_int_p(std::inout_ptr(cPtr));
+    assert(cPtr == 84);
+  }
+  // ResettablePtr
+  {
+    ResettablePtr<int> rPtr(new int{90});
+
+    replace_int_p(std::inout_ptr(rPtr));
+    assert(rPtr == 84);
+  }
+  // NonConstructiblePtr
+  {
+    NonConstructiblePtr<int> nPtr;
+    nPtr.reset(new int{90});
+
+    replace_int_p(std::inout_ptr(nPtr));
+    assert(nPtr == 84);
+  }
+}
+
+int main(int, char**) {
+  test_raw_ptr();
+  test_unique_ptr();
+  test_custom_ptr();
 
   return 0;
 }
diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.pass.cpp
deleted file mode 100644
index 58f09dc3a9ec3b2..000000000000000
--- a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.pass.cpp
+++ /dev/null
@@ -1,201 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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, c++17, c++20
-
-// <memory>
-
-// [inout.ptr], function template inout_ptr
-// template<class Pointer = void, class Smart, class... Args>
-//   auto inout_ptr(Smart& s, Args&&... args);                 // since c++23
-
-#include <cassert>
-#include <memory>
-
-#include "../types.h"
-
-// Test helpers.
-
-void replace_int_p(int** pp) {
-  assert(**pp == 90);
-  delete *pp;
-  *pp = new int{84};
-}
-
-void replace_int_p_with_nullptr(int** pp) {
-  assert(**pp == 90);
-  delete *pp;
-  *pp = nullptr;
-}
-
-void replace_nullptr_with_int_p(int** pp) {
-  assert(*pp == nullptr);
-  *pp = new int{84};
-}
-
-void replace_int_void_p(void** pp) {
-  assert(*(static_cast<int*>(*pp)) == 90);
-  delete static_cast<int*>(*pp);
-  *pp = new int{84};
-}
-
-void replace_int_void_p_with_nullptr(void** pp) {
-  assert(*(static_cast<int*>(*pp)) == 90);
-  delete static_cast<int*>(*pp);
-  *pp = nullptr;
-}
-
-void replace_nullptr_with_int_void_p(void** pp) {
-  assert(*pp == nullptr);
-  *pp = new int{84};
-}
-
-void replace_SomeInt_p(SomeInt** pp) {
-  auto si = **pp;
-  assert(si.value == 90);
-  delete static_cast<SomeInt*>(*pp);
-  *pp = new SomeInt{9084};
-}
-
-void replace_SomeInt_void_p(void** pp) {
-  assert(reinterpret_cast<SomeInt*>(*pp)->value == 90);
-  delete static_cast<SomeInt*>(*pp);
-  *pp = reinterpret_cast<void*>(new SomeInt{9084});
-}
-
-// Test `std::inout_ptr()` function.
-
-void test_raw_ptr() {
-  {
-    auto rPtr = new int{90};
-
-    replace_int_p(std::inout_ptr<int*>(rPtr));
-    assert(*rPtr == 84);
-
-    delete rPtr;
-  }
-  {
-    auto rPtr = new int{90};
-
-    replace_int_p_with_nullptr(std::inout_ptr<int*>(rPtr));
-    assert(rPtr == nullptr);
-  }
-  {
-    int* rPtr = nullptr;
-
-    replace_nullptr_with_int_p(std::inout_ptr<int*>(rPtr));
-    assert(*rPtr == 84);
-    delete rPtr;
-  }
-  {
-    auto rPtr = new int{90};
-
-    replace_int_void_p(std::inout_ptr<int*>(rPtr));
-    assert(*rPtr == 84);
-    delete rPtr;
-  }
-  {
-    auto rPtr = new int{90};
-
-    replace_int_void_p_with_nullptr(std::inout_ptr<int*>(rPtr));
-    assert(rPtr == nullptr);
-  }
-  {
-    int* rPtr = nullptr;
-
-    replace_nullptr_with_int_void_p(std::inout_ptr<int*>(rPtr));
-    assert(*rPtr == 84);
-    delete rPtr;
-  }
-  {
-    auto* rPtr = new SomeInt{90};
-
-    replace_SomeInt_p(std::inout_ptr(rPtr));
-    assert(rPtr->value == 9084);
-    delete rPtr;
-  }
-  {
-    auto* rPtr = new SomeInt{90};
-
-    replace_SomeInt_void_p(std::inout_ptr<SomeInt*>(rPtr));
-    assert(rPtr->value == 9084);
-    delete rPtr;
-  }
-}
-
-void test_unique_ptr() {
-  {
-    auto uPtr = std::make_unique<int>(90);
-
-    replace_int_p(std::inout_ptr(uPtr));
-    assert(*uPtr == 84);
-  }
-  {
-    std::unique_ptr<int> uPtr;
-
-    replace_nullptr_with_int_p(std::inout_ptr(uPtr));
-    assert(*uPtr == 84);
-  }
-  {
-    auto uPtr = std::make_unique<int>(90);
-
-    replace_int_void_p(std::inout_ptr(uPtr));
-    assert(*uPtr == 84);
-  }
-  {
-    std::unique_ptr<int> uPtr;
-
-    replace_nullptr_with_int_void_p(std::inout_ptr(uPtr));
-    assert(*uPtr == 84);
-  }
-  {
-    auto uPtr = std::make_unique<SomeInt>(90);
-
-    replace_SomeInt_p(std::inout_ptr(uPtr));
-    assert(uPtr->value == 9084);
-  }
-  {
-    auto uPtr = std::make_unique<SomeInt>(90);
-
-    replace_SomeInt_void_p(std::inout_ptr<SomeInt*>(uPtr));
-    assert(uPtr->value == 9084);
-  }
-}
-
-void test_custom_ptr() {
-  // ConstructiblePtr
-  {
-    ConstructiblePtr<int> cPtr(new int{90});
-
-    replace_int_p(std::inout_ptr(cPtr));
-    assert(cPtr == 84);
-  }
-  // ResettablePtr
-  {
-    ResettablePtr<int> rPtr(new int{90});
-
-    replace_int_p(std::inout_ptr(rPtr));
-    assert(rPtr == 84);
-  }
-  // NonConstructiblePtr
-  {
-    NonConstructiblePtr<int> nPtr;
-    nPtr.reset(new int{90});
-
-    replace_int_p(std::inout_ptr(nPtr));
-    assert(nPtr == 84);
-  }
-}
-
-int main(int, char**) {
-  test_raw_ptr();
-  test_unique_ptr();
-  test_custom_ptr();
-
-  return 0;
-}
diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.deref.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.convert.pass.cpp
similarity index 55%
rename from libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.deref.pass.cpp
rename to libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.convert.pass.cpp
index 86a055a7644e255..cee19c11c78c38a 100644
--- a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.deref.pass.cpp
+++ b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.t.convert.pass.cpp
@@ -17,18 +17,30 @@
 // operator Pointer*() const noexcept;
 // operator void**() const noexcept;
 
+#include <cassert>
+#include <concepts>
 #include <memory>
 
 int main(int, char**) {
   {
-    std::unique_ptr<int> uPtr;
+    std::unique_ptr<int> uPtr = std::make_unique<int>(84);
 
-    std::inout_ptr_t<std::unique_ptr<int>, int*>{uPtr};
+    const std::inout_ptr_t<std::unique_ptr<int>, int*> ioPtr{uPtr};
+
+    static_assert(noexcept(ioPtr.operator int**()));
+    std::same_as<int**> decltype(auto) pPtr = ioPtr.operator int**();
+
+    assert(**pPtr == 84);
   }
   {
-    std::unique_ptr<int> uPtr;
+    std::unique_ptr<int> uPtr = std::make_unique<int>(84);
+
+    const std::inout_ptr_t<std::unique_ptr<int>, void*> ioPtr{uPtr};
+
+    static_assert(noexcept(ioPtr.operator void**()));
+    std::same_as<void**> decltype(auto) pPtr = ioPtr.operator void**();
 
-    std::inout_ptr_t<std::unique_ptr<int>, int*>{uPtr};
+    assert(**reinterpret_cast<int**>(pPtr) == 84);
   }
 
   return 0;
diff --git a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.general.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.compile.pass.cpp
similarity index 92%
rename from libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.general.pass.cpp
rename to libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.compile.pass.cpp
index 84bea7248e7a6ee..71f78a5bf770a00 100644
--- a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.general.pass.cpp
+++ b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.compile.pass.cpp
@@ -21,17 +21,13 @@ int main(int, char**) {
     std::unique_ptr<int> uPtr;
 
     auto outUPtr1 = std::out_ptr(uPtr);
-    (void)outUPtr1;
     auto outUPtr2 = std::out_ptr<int*>(uPtr);
-    (void)outUPtr2;
   }
   {
     std::shared_ptr<int> sPtr;
 
     auto outSPtr1 = std::out_ptr(sPtr, [](auto* p) { delete p; });
-    (void)outSPtr1;
     auto outSPtr2 = std::out_ptr<int*>(sPtr, [](auto* p) { delete p; });
-    (void)outSPtr2;
   }
 
   return 0;
diff --git a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.general.cpp
similarity index 100%
rename from libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.pass.cpp
rename to libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.general.cpp
diff --git a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.convert.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.convert.pass.cpp
new file mode 100644
index 000000000000000..1e19d1ee5b4ec02
--- /dev/null
+++ b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.t.convert.pass.cpp
@@ -0,0 +1,58 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++17, c++20
+
+// <memory>
+
+// [out.ptr.t], class template out_ptr_t
+// template<class Smart, class Pointer, class... Args>
+//   class out_ptr_t;                                          // since c++23
+
+// operator Pointer*() const noexcept;
+// operator void**() const noexcept;
+
+#include <cassert>
+#include <concepts>
+#include <memory>
+#include <iostream>
+
+int main(int, char**) {
+  {
+    std::unique_ptr<int> uPtr;
+
+    const std::out_ptr_t<std::unique_ptr<int>, int*> oPtr{uPtr};
+
+    static_assert(noexcept(oPtr.operator int**()));
+    std::same_as<int**> decltype(auto) pPtr = oPtr.operator int**();
+
+    assert(*pPtr == nullptr);
+  }
+  {
+    std::unique_ptr<int, std::default_delete<int>> uPtr;
+
+    const std::out_ptr_t<decltype(uPtr), int*, std::default_delete<int>> oPtr{uPtr, std::default_delete<int>{}};
+
+    static_assert(noexcept(oPtr.operator int**()));
+    std::same_as<int**> decltype(auto) pPtr = oPtr.operator int**();
+
+    assert(*pPtr == nullptr);
+  }
+  {
+    std::unique_ptr<int> uPtr;
+
+    const std::out_ptr_t<std::unique_ptr<int>, void*> oPtr{uPtr};
+
+    static_assert(noexcept(oPtr.operator void**()));
+    std::same_as<void**> decltype(auto) pPtr = oPtr.operator void**();
+
+    assert(*pPtr == nullptr);
+  }
+
+  return 0;
+}

>From cb71ea2e2942a85b85712a877f994b6189efd83b Mon Sep 17 00:00:00 2001
From: Hristo Hristov <zingam at outlook.com>
Date: Thu, 30 Nov 2023 15:04:52 +0200
Subject: [PATCH 4/4] Removed tests files

---
 .../inout.ptr/inout.ptr.compile.pass.cpp      | 35 -------------------
 .../adapt/out.ptr/out.ptr.compile.pass.cpp    | 34 ------------------
 2 files changed, 69 deletions(-)
 delete mode 100644 libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.compile.pass.cpp
 delete mode 100644 libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.compile.pass.cpp

diff --git a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.compile.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.compile.pass.cpp
deleted file mode 100644
index d2eb8c3a6ac0081..000000000000000
--- a/libcxx/test/std/utilities/smartptr/adapt/inout.ptr/inout.ptr.compile.pass.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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, c++17, c++20
-
-// <memory>
-
-// [inout.ptr], function template inout_ptr
-// template<class Pointer = void, class Smart, class... Args>
-//   auto inout_ptr(Smart& s, Args&&... args);                 // since c++23
-
-#include <memory>
-
-int main(int, char**) {
-  {
-    std::unique_ptr<int> uPtr;
-
-    auto inoutUPtr1 = std::inout_ptr(uPtr);
-    auto inoutUPtr2 = std::inout_ptr<int*>(uPtr);
-  }
-  {
-    auto deleter = [](auto* p) { delete p; };
-    std::unique_ptr<int, decltype(deleter)> uPtr;
-
-    auto inoutUPtr1 = std::inout_ptr(uPtr, deleter);
-    auto inoutUPtr2 = std::inout_ptr<int*>(uPtr, deleter);
-  }
-
-  return 0;
-}
diff --git a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.compile.pass.cpp b/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.compile.pass.cpp
deleted file mode 100644
index 71f78a5bf770a00..000000000000000
--- a/libcxx/test/std/utilities/smartptr/adapt/out.ptr/out.ptr.compile.pass.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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, c++17, c++20
-
-// <memory>
-
-// [out.ptr], function template out_ptr
-// template<class Pointer = void, class Smart, class... Args>
-//   auto out_ptr(Smart& s, Args&&... args);                   // since c++23
-
-#include <memory>
-
-int main(int, char**) {
-  {
-    std::unique_ptr<int> uPtr;
-
-    auto outUPtr1 = std::out_ptr(uPtr);
-    auto outUPtr2 = std::out_ptr<int*>(uPtr);
-  }
-  {
-    std::shared_ptr<int> sPtr;
-
-    auto outSPtr1 = std::out_ptr(sPtr, [](auto* p) { delete p; });
-    auto outSPtr2 = std::out_ptr<int*>(sPtr, [](auto* p) { delete p; });
-  }
-
-  return 0;
-}



More information about the cfe-commits mailing list