[libcxx-commits] [libcxx] [libc++] Implement std::move_only_function (P0288R9) (PR #94670)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Mon Nov 24 02:55:37 PST 2025


https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/94670

>From 352fd1b474ab5e82a1b08161901fbb541079a0e4 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Tue, 4 Jun 2024 09:15:57 +0200
Subject: [PATCH] [libc++] Implement P0288R9 (move_only_function)

---
 libcxx/docs/FeatureTestMacroTable.rst         |   2 +-
 libcxx/docs/ReleaseNotes/22.rst               |   2 +
 libcxx/docs/Status/Cxx23Papers.csv            |   2 +-
 libcxx/include/CMakeLists.txt                 |   3 +
 libcxx/include/__configuration/experimental.h |   1 +
 .../include/__functional/move_only_function.h |  67 ++++++
 .../__functional/move_only_function_common.h  |  44 ++++
 .../__functional/move_only_function_impl.h    | 224 ++++++++++++++++++
 libcxx/include/__utility/small_buffer.h       |   7 +-
 libcxx/include/functional                     |   4 +
 libcxx/include/module.modulemap.in            |   3 +
 libcxx/include/version                        |   2 +-
 libcxx/modules/std/functional.inc             |   2 +-
 .../{ => functional}/function.bench.cpp       |   2 +-
 .../functional/move_only_function.bench.cpp   |  54 +++++
 .../func.wrap.move/assert.engaged.cpp         |  23 ++
 .../functional.version.compile.pass.cpp       |  32 +--
 .../version.version.compile.pass.cpp          |  32 +--
 .../assignment/functor.pass.cpp               |  88 +++++++
 .../func.wrap.move/assignment/move.pass.cpp   |  95 ++++++++
 .../assignment/move_other.pass.cpp            |  66 ++++++
 .../assignment/nullptr.pass.cpp               |  77 ++++++
 .../func.wrap.move/call/lvalue.pass.cpp       | 106 +++++++++
 .../func.wrap.move/call/lvalue_const.pass.cpp | 122 ++++++++++
 .../call/lvalue_const_noexcept.pass.cpp       | 117 +++++++++
 .../call/lvalue_noexcept.pass.cpp             | 106 +++++++++
 .../func.wrap.move/call/normal.pass.cpp       | 110 +++++++++
 .../func.wrap.move/call/normal_const.pass.cpp | 116 +++++++++
 .../call/normal_const_noexcept.pass.cpp       | 116 +++++++++
 .../call/normal_noexcept.pass.cpp             | 110 +++++++++
 .../func.wrap.move/call/rvalue.pass.cpp       | 108 +++++++++
 .../func.wrap.move/call/rvalue_const.pass.cpp | 111 +++++++++
 .../call/rvalue_const_noexcept.pass.cpp       | 111 +++++++++
 .../call/rvalue_noexcept.pass.cpp             | 108 +++++++++
 .../func.wrap/func.wrap.move/common.h         |  80 +++++++
 .../func.wrap.move/ctors/default.pass.cpp     |  32 +++
 .../func.wrap.move/ctors/functor.pass.cpp     | 119 ++++++++++
 .../func.wrap.move/ctors/in_place.pass.cpp    |  50 ++++
 .../ctors/in_place_init_list.pass.cpp         |  50 ++++
 .../func.wrap.move/ctors/move.pass.cpp        | 110 +++++++++
 .../func.wrap.move/ctors/move_other.pass.cpp  |  48 ++++
 .../func.wrap.move/ctors/nullptr.pass.cpp     |  32 +++
 .../func.wrap.move/swap.adl.pass.cpp          |  77 ++++++
 .../func.wrap.move/swap.member.pass.cpp       |  77 ++++++
 libcxx/test/support/type_algorithms.h         |  36 +++
 .../generate_feature_test_macro_components.py |   3 +-
 46 files changed, 2836 insertions(+), 51 deletions(-)
 create mode 100644 libcxx/include/__functional/move_only_function.h
 create mode 100644 libcxx/include/__functional/move_only_function_common.h
 create mode 100644 libcxx/include/__functional/move_only_function_impl.h
 rename libcxx/test/benchmarks/{ => functional}/function.bench.cpp (99%)
 create mode 100644 libcxx/test/benchmarks/functional/move_only_function.bench.cpp
 create mode 100644 libcxx/test/libcxx/utilities/function.objects/func.wrap/func.wrap.move/assert.engaged.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/assignment/functor.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/assignment/move.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/assignment/move_other.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/assignment/nullptr.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/lvalue.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/lvalue_const.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/lvalue_const_noexcept.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/lvalue_noexcept.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/normal.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/normal_const.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/normal_const_noexcept.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/normal_noexcept.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/rvalue.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/rvalue_const.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/rvalue_const_noexcept.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/rvalue_noexcept.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/common.h
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/default.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/functor.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/in_place.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/in_place_init_list.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/move.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/move_other.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/nullptr.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/swap.adl.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/swap.member.pass.cpp

diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 756bdf71f8b22..387e59a4d6fe3 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -356,7 +356,7 @@ Status
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_modules``                                      ``202207L``
     ---------------------------------------------------------- -----------------
-    ``__cpp_lib_move_only_function``                           *unimplemented*
+    ``__cpp_lib_move_only_function``                           ``202110L``
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_optional``                                     ``202110L``
     ---------------------------------------------------------- -----------------
diff --git a/libcxx/docs/ReleaseNotes/22.rst b/libcxx/docs/ReleaseNotes/22.rst
index 2c19dfc57a3f8..651eece542f2f 100644
--- a/libcxx/docs/ReleaseNotes/22.rst
+++ b/libcxx/docs/ReleaseNotes/22.rst
@@ -49,6 +49,8 @@ Implemented Papers
 - P2835R7: Expose ``std::atomic_ref``'s object address (`Github <https://llvm.org/PR118377>`__)
 - P2944R3: Comparisons for ``reference_wrapper`` (`Github <https://llvm.org/PR105424>`__)
 - P3168R2: Give ``std::optional`` Range Support (`Github <https://llvm.org/PR105430>`__)
+- P0288R9 - ``move_only_function`` (`Github <https://llvm.org/PR105157>`__) This feature is currently experimental and
+  therefore requires ``-fexperimental-library``.
 
 Improvements and New Features
 -----------------------------
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index b655384bad7f2..1249afe6968ad 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -23,7 +23,7 @@
 "`P2136R3 <https://wg21.link/P2136R3>`__","invoke_r","2021-06 (Virtual)","|Complete|","17","`#105155 <https://github.com/llvm/llvm-project/issues/105155>`__",""
 "`P2166R1 <https://wg21.link/P2166R1>`__","A Proposal to Prohibit std::basic_string and std::basic_string_view construction from nullptr","2021-06 (Virtual)","|Complete|","13","`#105156 <https://github.com/llvm/llvm-project/issues/105156>`__",""
 "","","","","","",""
-"`P0288R9 <https://wg21.link/P0288R9>`__","``any_invocable``","2021-10 (Virtual)","","","`#105157 <https://github.com/llvm/llvm-project/issues/105157>`__",""
+"`P0288R9 <https://wg21.link/P0288R9>`__","``move_only_function``","2021-10 (Virtual)","|Complete|","22","`#105157 <https://github.com/llvm/llvm-project/issues/105157>`__",""
 "`P0798R8 <https://wg21.link/P0798R8>`__","Monadic operations for ``std::optional``","2021-10 (Virtual)","|Complete|","14","`#105158 <https://github.com/llvm/llvm-project/issues/105158>`__",""
 "`P0849R8 <https://wg21.link/P0849R8>`__","``auto(x)``: ``DECAY_COPY`` in the language","2021-10 (Virtual)","|Complete|","14","`#105159 <https://github.com/llvm/llvm-project/issues/105159>`__",""
 "`P1072R10 <https://wg21.link/P1072R10>`__","``basic_string::resize_and_overwrite``","2021-10 (Virtual)","|Complete|","14","`#105160 <https://github.com/llvm/llvm-project/issues/105160>`__",""
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 4b2713191c1c0..39d882c4f8391 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -430,6 +430,9 @@ set(files
   __functional/is_transparent.h
   __functional/mem_fn.h
   __functional/mem_fun_ref.h
+  __functional/move_only_function.h
+  __functional/move_only_function_common.h
+  __functional/move_only_function_impl.h
   __functional/not_fn.h
   __functional/operations.h
   __functional/perfect_forward.h
diff --git a/libcxx/include/__configuration/experimental.h b/libcxx/include/__configuration/experimental.h
index d14df3e5175f3..79096d63f9727 100644
--- a/libcxx/include/__configuration/experimental.h
+++ b/libcxx/include/__configuration/experimental.h
@@ -33,5 +33,6 @@
 #define _LIBCPP_HAS_EXPERIMENTAL_TZDB _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
 #define _LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
 #define _LIBCPP_HAS_EXPERIMENTAL_HARDENING_OBSERVE_SEMANTIC _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
+#define _LIBCPP_HAS_EXPERIMENTAL_MOVE_ONLY_FUNCTION _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
 
 #endif // _LIBCPP___CONFIGURATION_EXPERIMENTAL_H
diff --git a/libcxx/include/__functional/move_only_function.h b/libcxx/include/__functional/move_only_function.h
new file mode 100644
index 0000000000000..34b5e42a497bb
--- /dev/null
+++ b/libcxx/include/__functional/move_only_function.h
@@ -0,0 +1,67 @@
+//===----------------------------------------------------------------------===//
+//
+// 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___FUNCTIONAL_MOVE_ONLY_FUNCTION_H
+#define _LIBCPP___FUNCTIONAL_MOVE_ONLY_FUNCTION_H
+
+#include <__config>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+#if _LIBCPP_STD_VER >= 23 && !defined(_LIBCPP_COMPILER_GCC) && _LIBCPP_HAS_EXPERIMENTAL_MOVE_ONLY_FUNCTION
+
+// move_only_function design:
+//
+// move_only_function has a small buffer with a size of `3 * sizeof(void*)` bytes. This buffer can only be used when the
+// object to be stored is "trivially relocatable" (currently only when it is trivially move constructible and trivially
+// destructible). The vtable entry for the destructor is a null pointer when the stored object is trivially
+// destructible.
+//
+// trivially relocatable: It would also be possible to store nothrow_move_constructible types, but that would mean
+// that move_only_function itself would not be trivially relocatable anymore. The decision to keep move_only_function
+// trivially relocatable was made because we expect move_only_function to be stored persistently most of the time, since
+// std::function_ref can be used for cases where a function object doesn't need to be stored.
+//
+// buffer size: We did a survey of six implementations from various vendors. Three of them had a buffer size of 24 bytes
+// on 64 bit systems. This will also allow storing a function object containing a std::string or std::vector inside the
+// small buffer once there is a language definition of "trivially relocatable".
+//
+// interaction with copyable_function: When converting a copyable_function into a move_only_function we want to avoid
+// wrapping the copyable_function inside the move_only_function to avoid a double indirection. Instead, we copy the
+// small buffer and use copyable_function's vtable.
+
+// NOLINTBEGIN(readability-duplicate-include)
+#  define _LIBCPP_IN_MOVE_ONLY_FUNCTION_H
+
+#  include <__functional/move_only_function_impl.h>
+
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_REF &
+#  include <__functional/move_only_function_impl.h>
+
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_REF &&
+#  include <__functional/move_only_function_impl.h>
+
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_CV const
+#  include <__functional/move_only_function_impl.h>
+
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_CV const
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_REF &
+#  include <__functional/move_only_function_impl.h>
+
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_CV const
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_REF &&
+#  include <__functional/move_only_function_impl.h>
+
+#  undef _LIBCPP_IN_MOVE_ONLY_FUNCTION_H
+// NOLINTEND(readability-duplicate-include)
+
+#endif // _LIBCPP_STD_VER >= 23 && !defined(_LIBCPP_COMPILER_GCC) && _LIBCPP_HAS_EXPERIMENTAL_MOVE_ONLY_FUNCTION
+
+#endif // _LIBCPP___FUNCTIONAL_MOVE_ONLY_FUNCTION_H
diff --git a/libcxx/include/__functional/move_only_function_common.h b/libcxx/include/__functional/move_only_function_common.h
new file mode 100644
index 0000000000000..cbb0545f2e451
--- /dev/null
+++ b/libcxx/include/__functional/move_only_function_common.h
@@ -0,0 +1,44 @@
+//===----------------------------------------------------------------------===//
+//
+// 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___FUNCTIONAL_MOVE_ONLY_FUNCTION_COMMON_H
+#define _LIBCPP___FUNCTIONAL_MOVE_ONLY_FUNCTION_COMMON_H
+
+#include <__config>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+#if _LIBCPP_STD_VER >= 23 && _LIBCPP_HAS_EXPERIMENTAL_MOVE_ONLY_FUNCTION
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class...>
+class move_only_function;
+
+template <class>
+inline constexpr bool __is_move_only_function_v = false;
+
+template <class... _Args>
+inline constexpr bool __is_move_only_function_v<move_only_function<_Args...>> = true;
+
+template <class _BufferT, class _ReturnT, class... _ArgTypes>
+struct _MoveOnlyFunctionVTable {
+  using _CallFunc _LIBCPP_NODEBUG = _ReturnT(_BufferT&, _ArgTypes...);
+  using _DestroyFunc _LIBCPP_NODEBUG = void(_BufferT&) noexcept;
+
+  _CallFunc* __call_;
+  _DestroyFunc* __destroy_;
+};
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 23 && _LIBCPP_HAS_EXPERIMENTAL_MOVE_ONLY_FUNCTION
+
+#endif // _LIBCPP___FUNCTIONAL_MOVE_ONLY_FUNCTION_COMMON_H
diff --git a/libcxx/include/__functional/move_only_function_impl.h b/libcxx/include/__functional/move_only_function_impl.h
new file mode 100644
index 0000000000000..d61c71b4d6ad4
--- /dev/null
+++ b/libcxx/include/__functional/move_only_function_impl.h
@@ -0,0 +1,224 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// This header is unguarded on purpose. This header is an implementation detail of move_only_function.h
+// and generates multiple versions of std::move_only_function
+
+#include <__assert>
+#include <__config>
+#include <__cstddef/nullptr_t.h>
+#include <__cstddef/size_t.h>
+#include <__functional/invoke.h>
+#include <__functional/move_only_function_common.h>
+#include <__memory/addressof.h>
+#include <__memory/construct_at.h>
+#include <__type_traits/decay.h>
+#include <__type_traits/invoke.h>
+#include <__type_traits/is_constructible.h>
+#include <__type_traits/is_function.h>
+#include <__type_traits/is_member_pointer.h>
+#include <__type_traits/is_pointer.h>
+#include <__type_traits/is_same.h>
+#include <__type_traits/is_trivially_destructible.h>
+#include <__type_traits/remove_cvref.h>
+#include <__type_traits/remove_pointer.h>
+#include <__utility/exchange.h>
+#include <__utility/forward.h>
+#include <__utility/in_place.h>
+#include <__utility/move.h>
+#include <__utility/small_buffer.h>
+#include <__utility/swap.h>
+#include <initializer_list>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+#ifndef _LIBCPP_IN_MOVE_ONLY_FUNCTION_H
+#  error This header should only be included from move_only_function.h
+#endif
+
+#ifndef _LIBCPP_MOVE_ONLY_FUNCTION_CV
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_CV
+#endif
+
+#ifndef _LIBCPP_MOVE_ONLY_FUNCTION_REF
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_REF
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_INVOKE_QUALS _LIBCPP_MOVE_ONLY_FUNCTION_CV&
+#else
+#  define _LIBCPP_MOVE_ONLY_FUNCTION_INVOKE_QUALS _LIBCPP_MOVE_ONLY_FUNCTION_CV _LIBCPP_MOVE_ONLY_FUNCTION_REF
+#endif
+
+#define _LIBCPP_MOVE_ONLY_FUNCTION_CVREF _LIBCPP_MOVE_ONLY_FUNCTION_CV _LIBCPP_MOVE_ONLY_FUNCTION_REF
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class...>
+class move_only_function;
+
+template <class _ReturnT, class... _ArgTypes, bool __is_noexcept>
+class [[_Clang::__trivial_abi__]]
+move_only_function<_ReturnT(_ArgTypes...) _LIBCPP_MOVE_ONLY_FUNCTION_CVREF noexcept(__is_noexcept)> {
+private:
+  static constexpr size_t __buffer_size_      = 3 * sizeof(void*);
+  static constexpr size_t __buffer_alignment_ = alignof(void*);
+  using _BufferT _LIBCPP_NODEBUG              = __small_buffer<__buffer_size_, __buffer_alignment_>;
+
+  using _VTable _LIBCPP_NODEBUG = _MoveOnlyFunctionVTable<_BufferT, _ReturnT, _ArgTypes...>;
+
+  template <class _Functor>
+  static constexpr _VTable __vtable_var_ = {
+      .__call_ = [](_BufferT& __buffer, _ArgTypes... __args) noexcept(__is_noexcept) -> _ReturnT {
+        return std::invoke_r<_ReturnT>(
+            static_cast<_Functor _LIBCPP_MOVE_ONLY_FUNCTION_INVOKE_QUALS>(*__buffer.__get<_Functor>()),
+            std::forward<_ArgTypes>(__args)...);
+      },
+      .__destroy_ = (_BufferT::__fits_in_buffer<_Functor> && is_trivially_destructible_v<_Functor>)
+                      ? nullptr
+                      : [](_BufferT& __buffer) noexcept -> void {
+        std::destroy_at(__buffer.__get<_Functor>());
+        __buffer.__dealloc<_Functor>();
+      }};
+
+  template <class _VT>
+  static constexpr bool __is_callable_from = [] {
+    using _DVT = decay_t<_VT>;
+    if constexpr (__is_noexcept) {
+      return is_nothrow_invocable_r_v<_ReturnT, _DVT _LIBCPP_MOVE_ONLY_FUNCTION_CVREF, _ArgTypes...> &&
+             is_nothrow_invocable_r_v<_ReturnT, _DVT _LIBCPP_MOVE_ONLY_FUNCTION_INVOKE_QUALS, _ArgTypes...>;
+    } else {
+      return is_invocable_r_v<_ReturnT, _DVT _LIBCPP_MOVE_ONLY_FUNCTION_CVREF, _ArgTypes...> &&
+             is_invocable_r_v<_ReturnT, _DVT _LIBCPP_MOVE_ONLY_FUNCTION_INVOKE_QUALS, _ArgTypes...>;
+    }
+  }();
+
+  template <class _Func, class... _Args>
+  _LIBCPP_HIDE_FROM_ABI void __construct(_Args&&... __args) {
+    static_assert(is_constructible_v<decay_t<_Func>, _Func>);
+
+    using _StoredFunc = decay_t<_Func>;
+    __vtable_         = std::addressof(__vtable_var_<_StoredFunc>);
+    __buffer_.__construct<_StoredFunc>(std::forward<_Args>(__args)...);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI void __reset() noexcept {
+    if (__vtable_ && __vtable_->__destroy_)
+      __vtable_->__destroy_(__buffer_);
+    __vtable_ = nullptr;
+  }
+
+public:
+  using result_type = _ReturnT;
+
+  // [func.wrap.move.ctor]
+  move_only_function() noexcept = default;
+  _LIBCPP_HIDE_FROM_ABI move_only_function(nullptr_t) noexcept {}
+  _LIBCPP_HIDE_FROM_ABI move_only_function(move_only_function&& __other) noexcept
+      : __vtable_(__other.__vtable_), __buffer_(std::move(__other.__buffer_)) {
+    __other.__vtable_ = nullptr;
+  }
+
+  template <class _Func>
+    requires(!is_same_v<remove_cvref_t<_Func>, move_only_function> && !__is_inplace_type<_Func>::value &&
+             __is_callable_from<_Func>)
+  _LIBCPP_HIDE_FROM_ABI move_only_function(_Func&& __func) noexcept {
+    using _StoredFunc = decay_t<_Func>;
+
+    if constexpr ((is_pointer_v<_StoredFunc> && is_function_v<remove_pointer_t<_StoredFunc>>) ||
+                  is_member_function_pointer_v<_StoredFunc>) {
+      if (__func != nullptr) {
+        __vtable_ = std::addressof(__vtable_var_<_StoredFunc>);
+        static_assert(_BufferT::__fits_in_buffer<_StoredFunc>);
+        __buffer_.__construct<_StoredFunc>(std::forward<_Func>(__func));
+      }
+    } else if constexpr (__is_move_only_function_v<_StoredFunc>) {
+      if (__func) {
+        __vtable_ = std::exchange(__func.__vtable_, nullptr);
+        __buffer_ = std::move(__func.__buffer_);
+      }
+    } else {
+      __construct<_Func>(std::forward<_Func>(__func));
+    }
+  }
+
+  template <class _Func, class... _Args>
+    requires is_constructible_v<decay_t<_Func>, _Args...> && __is_callable_from<_Func>
+  _LIBCPP_HIDE_FROM_ABI explicit move_only_function(in_place_type_t<_Func>, _Args&&... __args) {
+    static_assert(is_same_v<decay_t<_Func>, _Func>);
+    __construct<_Func>(std::forward<_Args>(__args)...);
+  }
+
+  template <class _Func, class _InitListType, class... _Args>
+    requires is_constructible_v<decay_t<_Func>, initializer_list<_InitListType>&, _Args...> && __is_callable_from<_Func>
+  _LIBCPP_HIDE_FROM_ABI explicit move_only_function(
+      in_place_type_t<_Func>, initializer_list<_InitListType> __il, _Args&&... __args) {
+    static_assert(is_same_v<decay_t<_Func>, _Func>);
+    __construct<_Func>(__il, std::forward<_Args>(__args)...);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI move_only_function& operator=(move_only_function&& __other) noexcept {
+    move_only_function(std::move(__other)).swap(*this);
+    return *this;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI move_only_function& operator=(nullptr_t) noexcept {
+    __reset();
+    return *this;
+  }
+
+  template <class _Func>
+    requires(!is_same_v<remove_cvref_t<_Func>, move_only_function> && !__is_inplace_type<_Func>::value &&
+             __is_callable_from<_Func>)
+  _LIBCPP_HIDE_FROM_ABI move_only_function& operator=(_Func&& __func) {
+    move_only_function(std::forward<_Func>(__func)).swap(*this);
+    return *this;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI ~move_only_function() { __reset(); }
+
+  // [func.wrap.move.inv]
+  _LIBCPP_HIDE_FROM_ABI explicit operator bool() const noexcept { return __vtable_; }
+
+  _LIBCPP_HIDE_FROM_ABI _ReturnT operator()(_ArgTypes... __args) _LIBCPP_MOVE_ONLY_FUNCTION_CVREF
+      noexcept(__is_noexcept) {
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(static_cast<bool>(*this), "Tried to call a disengaged move_only_function");
+    const auto __call = static_cast<_ReturnT (*)(_BufferT&, _ArgTypes...)>(__vtable_->__call_);
+    return __call(__buffer_, std::forward<_ArgTypes>(__args)...);
+  }
+
+  // [func.wrap.move.util]
+  _LIBCPP_HIDE_FROM_ABI void swap(move_only_function& __other) noexcept {
+    std::swap(__vtable_, __other.__vtable_);
+    std::swap(__buffer_, __other.__buffer_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend void swap(move_only_function& __lhs, move_only_function& __rhs) noexcept {
+    __lhs.swap(__rhs);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI friend bool operator==(const move_only_function& __func, nullptr_t) noexcept { return !__func; }
+
+private:
+  const _VTable* __vtable_ = nullptr;
+  mutable _BufferT __buffer_;
+
+  template <class...>
+  friend class move_only_function;
+};
+
+#undef _LIBCPP_MOVE_ONLY_FUNCTION_CV
+#undef _LIBCPP_MOVE_ONLY_FUNCTION_REF
+#undef _LIBCPP_MOVE_ONLY_FUNCTION_INVOKE_QUALS
+#undef _LIBCPP_MOVE_ONLY_FUNCTION_CVREF
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
diff --git a/libcxx/include/__utility/small_buffer.h b/libcxx/include/__utility/small_buffer.h
index 132a57f0fefab..41517669bc125 100644
--- a/libcxx/include/__utility/small_buffer.h
+++ b/libcxx/include/__utility/small_buffer.h
@@ -9,6 +9,7 @@
 #ifndef _LIBCPP___UTILITY_SMALL_BUFFER_H
 #define _LIBCPP___UTILITY_SMALL_BUFFER_H
 
+#include <__bit/has_single_bit.h>
 #include <__config>
 #include <__cstddef/byte.h>
 #include <__cstddef/size_t.h>
@@ -38,10 +39,14 @@
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <size_t _BufferSize, size_t _BufferAlignment>
-  requires(_BufferSize > 0 && _BufferAlignment > 0)
 class __small_buffer {
+  static_assert(std::has_single_bit(_BufferAlignment), "Alignment is invalid.");
+  static_assert(_BufferSize >= sizeof(byte*), "Buffer has to be capable of storing a pointer for heap allocations!");
+
 public:
   template <class _Tp, class _Decayed = decay_t<_Tp>>
+  // In theory we require `is_trivially_copyable`, since we're copying the raw object representation. However, we
+  // already assume that the compiler doesn't optimize on this, e.g. in our trivially relocatable optimizations.
   static constexpr bool __fits_in_buffer =
       is_trivially_move_constructible_v<_Decayed> && is_trivially_destructible_v<_Decayed> &&
       sizeof(_Decayed) <= _BufferSize && alignof(_Decayed) <= _BufferAlignment;
diff --git a/libcxx/include/functional b/libcxx/include/functional
index 9ebcd818ec840..3dcc1c25ad9f1 100644
--- a/libcxx/include/functional
+++ b/libcxx/include/functional
@@ -569,6 +569,10 @@ POLICY:  For non-variadic implementations, the number of arguments is limited
 #    include <__type_traits/unwrap_ref.h>
 #  endif
 
+#  if _LIBCPP_STD_VER >= 23
+#    include <__functional/move_only_function.h>
+#  endif
+
 #  include <version>
 
 #  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 57d66cd1ccaef..0c60d95d7e54d 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1419,6 +1419,9 @@ module std [system] {
     module is_transparent               { header "__functional/is_transparent.h" }
     module mem_fn                       { header "__functional/mem_fn.h" }
     module mem_fun_ref                  { header "__functional/mem_fun_ref.h" }
+    module move_only_function           { header "__functional/move_only_function.h" }
+    module move_only_function_common    { header "__functional/move_only_function_common.h" }
+    module move_only_function_impl      { textual header "__functional/move_only_function_impl.h" }
     module not_fn {
       header "__functional/not_fn.h"
       export std.functional.perfect_forward // inherited from and using its operators
diff --git a/libcxx/include/version b/libcxx/include/version
index 05532ea731ff3..57d76d4c16df2 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -511,7 +511,7 @@ __cpp_lib_void_t                                        201411L <type_traits>
 # define __cpp_lib_is_scoped_enum                       202011L
 # define __cpp_lib_mdspan                               202207L
 # define __cpp_lib_modules                              202207L
-// # define __cpp_lib_move_only_function                   202110L
+# define __cpp_lib_move_only_function                   202110L
 # undef  __cpp_lib_optional
 # define __cpp_lib_optional                             202110L
 # define __cpp_lib_out_ptr                              202106L
diff --git a/libcxx/modules/std/functional.inc b/libcxx/modules/std/functional.inc
index 9ef8f584611fc..801572149b324 100644
--- a/libcxx/modules/std/functional.inc
+++ b/libcxx/modules/std/functional.inc
@@ -100,7 +100,7 @@ export namespace std {
   using std::operator==;
 
   // [func.wrap.move], move only wrapper
-  // using std::move_only_function;
+  using std::move_only_function;
 
   // [func.search], searchers
   using std::default_searcher;
diff --git a/libcxx/test/benchmarks/function.bench.cpp b/libcxx/test/benchmarks/functional/function.bench.cpp
similarity index 99%
rename from libcxx/test/benchmarks/function.bench.cpp
rename to libcxx/test/benchmarks/functional/function.bench.cpp
index e607162d23b72..98e9b3dd41626 100644
--- a/libcxx/test/benchmarks/function.bench.cpp
+++ b/libcxx/test/benchmarks/functional/function.bench.cpp
@@ -14,7 +14,7 @@
 #include <string>
 #include <utility>
 
-#include "CartesianBenchmarks.h"
+#include "../CartesianBenchmarks.h"
 #include "benchmark/benchmark.h"
 #include "test_macros.h"
 
diff --git a/libcxx/test/benchmarks/functional/move_only_function.bench.cpp b/libcxx/test/benchmarks/functional/move_only_function.bench.cpp
new file mode 100644
index 0000000000000..c27bebbd1b277
--- /dev/null
+++ b/libcxx/test/benchmarks/functional/move_only_function.bench.cpp
@@ -0,0 +1,54 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+#include <benchmark/benchmark.h>
+#include <functional>
+
+struct LargeFunctor {
+  int arr[10];
+
+  void operator()() {}
+};
+
+struct SmallFunctor {
+  void operator()() {}
+};
+
+template <bool Opaque>
+static void BM_invoke(benchmark::State& state) {
+  std::move_only_function<void()> func = [] {};
+
+  for (auto _ : state) {
+    if constexpr (Opaque)
+      benchmark::DoNotOptimize(func);
+    func();
+  }
+}
+BENCHMARK(BM_invoke<false>)->Name("move_only_function::operator() (transparent)");
+BENCHMARK(BM_invoke<true>)->Name("move_only_function::operator() (opaque)");
+
+template <class Functor>
+static void BM_move_assign(benchmark::State& state) {
+  std::move_only_function<void()> func1 = Functor();
+  std::move_only_function<void()> func2;
+
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(func1);
+    benchmark::DoNotOptimize(func2);
+    func2 = std::move(func1);
+    benchmark::DoNotOptimize(func1);
+    benchmark::DoNotOptimize(func2);
+    func1 = std::move(func2);
+  }
+}
+BENCHMARK(BM_move_assign<SmallFunctor>)->Name("move_only_function::operator=(move_only_function&&) (small buffer)");
+BENCHMARK(BM_move_assign<LargeFunctor>)->Name("move_only_function::operator=(move_only_function&&) (large buffer)");
+
+BENCHMARK_MAIN();
diff --git a/libcxx/test/libcxx/utilities/function.objects/func.wrap/func.wrap.move/assert.engaged.cpp b/libcxx/test/libcxx/utilities/function.objects/func.wrap/func.wrap.move/assert.engaged.cpp
new file mode 100644
index 0000000000000..1713847c1d863
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/function.objects/func.wrap/func.wrap.move/assert.engaged.cpp
@@ -0,0 +1,23 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: has-unix-headers
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// UNSUPPORTED: libcpp-hardening-mode=none
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
+
+#include <functional>
+
+#include "check_assertion.h"
+
+int main(int, char**) {
+  std::move_only_function<void()> func;
+  TEST_LIBCPP_ASSERT_FAILURE(func(), "Tried to call a disengaged move_only_function");
+
+  return 0;
+}
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp
index b7b7d0334830a..89d99307f69c4 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp
@@ -392,17 +392,11 @@
 #    error "__cpp_lib_invoke_r should have the value 202106L in c++23"
 #  endif
 
-#  if !defined(_LIBCPP_VERSION)
-#    ifndef __cpp_lib_move_only_function
-#      error "__cpp_lib_move_only_function should be defined in c++23"
-#    endif
-#    if __cpp_lib_move_only_function != 202110L
-#      error "__cpp_lib_move_only_function should have the value 202110L in c++23"
-#    endif
-#  else
-#    ifdef __cpp_lib_move_only_function
-#      error "__cpp_lib_move_only_function should not be defined because it is unimplemented in libc++!"
-#    endif
+#  ifndef __cpp_lib_move_only_function
+#    error "__cpp_lib_move_only_function should be defined in c++23"
+#  endif
+#  if __cpp_lib_move_only_function != 202110L
+#    error "__cpp_lib_move_only_function should have the value 202110L in c++23"
 #  endif
 
 #  ifndef __cpp_lib_not_fn
@@ -521,17 +515,11 @@
 #    error "__cpp_lib_invoke_r should have the value 202106L in c++26"
 #  endif
 
-#  if !defined(_LIBCPP_VERSION)
-#    ifndef __cpp_lib_move_only_function
-#      error "__cpp_lib_move_only_function should be defined in c++26"
-#    endif
-#    if __cpp_lib_move_only_function != 202110L
-#      error "__cpp_lib_move_only_function should have the value 202110L in c++26"
-#    endif
-#  else
-#    ifdef __cpp_lib_move_only_function
-#      error "__cpp_lib_move_only_function should not be defined because it is unimplemented in libc++!"
-#    endif
+#  ifndef __cpp_lib_move_only_function
+#    error "__cpp_lib_move_only_function should be defined in c++26"
+#  endif
+#  if __cpp_lib_move_only_function != 202110L
+#    error "__cpp_lib_move_only_function should have the value 202110L in c++26"
 #  endif
 
 #  ifndef __cpp_lib_not_fn
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 996ec29dce697..5c48440fbc8ce 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
@@ -5558,17 +5558,11 @@
 #    error "__cpp_lib_move_iterator_concept should have the value 202207L in c++23"
 #  endif
 
-#  if !defined(_LIBCPP_VERSION)
-#    ifndef __cpp_lib_move_only_function
-#      error "__cpp_lib_move_only_function should be defined in c++23"
-#    endif
-#    if __cpp_lib_move_only_function != 202110L
-#      error "__cpp_lib_move_only_function should have the value 202110L in c++23"
-#    endif
-#  else
-#    ifdef __cpp_lib_move_only_function
-#      error "__cpp_lib_move_only_function should not be defined because it is unimplemented in libc++!"
-#    endif
+#  ifndef __cpp_lib_move_only_function
+#    error "__cpp_lib_move_only_function should be defined in c++23"
+#  endif
+#  if __cpp_lib_move_only_function != 202110L
+#    error "__cpp_lib_move_only_function should have the value 202110L in c++23"
 #  endif
 
 #  ifndef __cpp_lib_node_extract
@@ -7465,17 +7459,11 @@
 #    error "__cpp_lib_move_iterator_concept should have the value 202207L in c++26"
 #  endif
 
-#  if !defined(_LIBCPP_VERSION)
-#    ifndef __cpp_lib_move_only_function
-#      error "__cpp_lib_move_only_function should be defined in c++26"
-#    endif
-#    if __cpp_lib_move_only_function != 202110L
-#      error "__cpp_lib_move_only_function should have the value 202110L in c++26"
-#    endif
-#  else
-#    ifdef __cpp_lib_move_only_function
-#      error "__cpp_lib_move_only_function should not be defined because it is unimplemented in libc++!"
-#    endif
+#  ifndef __cpp_lib_move_only_function
+#    error "__cpp_lib_move_only_function should be defined in c++26"
+#  endif
+#  if __cpp_lib_move_only_function != 202110L
+#    error "__cpp_lib_move_only_function should have the value 202110L in c++26"
 #  endif
 
 #  ifndef __cpp_lib_node_extract
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/assignment/functor.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/assignment/functor.pass.cpp
new file mode 100644
index 0000000000000..84c4602f71d74
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/assignment/functor.pass.cpp
@@ -0,0 +1,88 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// GCC doesn't support [[clang::trivial_abi]] currently, which we want to use on
+// move_only_function.
+// UNSUPPORTED: gcc
+
+#include <cassert>
+#include <concepts>
+#include <functional>
+#include <type_traits>
+#include <utility>
+
+#include "type_algorithms.h"
+#include "../common.h"
+
+template <class T>
+void test() {
+  static_assert(!std::is_nothrow_assignable_v<std::move_only_function<T>&, NonTrivial>);
+  {
+    std::move_only_function<T> f;
+    std::same_as<std::move_only_function<T>&> decltype(auto) ret = (f = &call_func);
+    assert(&ret == &f);
+    assert(f);
+  }
+  {
+    std::move_only_function<T> f;
+    decltype(&call_func) ptr                                     = nullptr;
+    std::same_as<std::move_only_function<T>&> decltype(auto) ret = (f = ptr);
+    assert(&ret == &f);
+    assert(!f);
+  }
+  {
+    std::move_only_function<T> f;
+    std::same_as<std::move_only_function<T>&> decltype(auto) ret = (f = TriviallyDestructible{});
+    assert(&ret == &f);
+    assert(f);
+  }
+  {
+    std::move_only_function<T> f;
+    std::same_as<std::move_only_function<T>&> decltype(auto) ret = (f = TriviallyDestructibleTooLarge{});
+    assert(&ret == &f);
+    assert(f);
+  }
+  {
+    std::move_only_function<T> f;
+    std::same_as<std::move_only_function<T>&> decltype(auto) ret = (f = NonTrivial{});
+    assert(&ret == &f);
+    assert(f);
+  }
+}
+
+struct S {
+  void func() noexcept {}
+};
+
+template <class T>
+void test_member_function_pointer() {
+  {
+    std::move_only_function<T> f = &S::func;
+    std::move_only_function<T> f2;
+    f2 = std::move(f);
+    assert(f2);
+  }
+  {
+    decltype(&S::func) ptr       = nullptr;
+    std::move_only_function<T> f = ptr;
+    std::move_only_function<T> f2;
+    f2 = std::move(f);
+    assert(!f2);
+  }
+}
+
+int main(int, char**) {
+  types::for_each(types::function_noexcept_const_ref_qualified<void()>{}, []<class T> { test<T>(); });
+  types::for_each(types::function_noexcept_const_ref_qualified<void(S)>{}, []<class T> {
+    test_member_function_pointer<T>();
+  });
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/assignment/move.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/assignment/move.pass.cpp
new file mode 100644
index 0000000000000..7e57c30e1fb2a
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/assignment/move.pass.cpp
@@ -0,0 +1,95 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// GCC doesn't support [[clang::trivial_abi]] currently, which we want to use on
+// move_only_function.
+// UNSUPPORTED: gcc
+
+#include <cassert>
+#include <functional>
+#include <type_traits>
+#include <utility>
+
+#include "test_macros.h"
+#include "type_algorithms.h"
+#include "../common.h"
+
+template <class T>
+void test() {
+  static_assert(!std::is_assignable_v<std::move_only_function<T>, int>);
+  {
+    std::move_only_function<T> f = &call_func;
+    std::move_only_function<T> f2;
+    f2 = std::move(f);
+    assert(f2);
+    LIBCPP_ASSERT(!f);
+  }
+  {
+    decltype(&call_func) ptr     = nullptr;
+    std::move_only_function<T> f = ptr;
+    std::move_only_function<T> f2;
+    f2 = std::move(f);
+    assert(!f2);
+    LIBCPP_ASSERT(!f);
+  }
+  {
+    std::move_only_function<T> f = TriviallyDestructible{};
+    std::move_only_function<T> f2;
+    f2 = std::move(f);
+    assert(f2);
+    LIBCPP_ASSERT(!f);
+  }
+  {
+    std::move_only_function<T> f = TriviallyDestructibleTooLarge{};
+    std::move_only_function<T> f2;
+    f2 = std::move(f);
+    assert(f2);
+    LIBCPP_ASSERT(!f);
+  }
+  {
+    std::move_only_function<T> f = NonTrivial{};
+    std::move_only_function<T> f2;
+    f2 = std::move(f);
+    assert(f2);
+    LIBCPP_ASSERT(!f);
+  }
+}
+
+struct S {
+  void func() noexcept {}
+};
+
+template <class T>
+void test_member_function_pointer() {
+  {
+    std::move_only_function<T> f = &S::func;
+    std::move_only_function<T> f2;
+    f2 = std::move(f);
+    assert(f2);
+    LIBCPP_ASSERT(!f);
+  }
+  {
+    decltype(&S::func) ptr       = nullptr;
+    std::move_only_function<T> f = ptr;
+    std::move_only_function<T> f2;
+    f2 = std::move(f);
+    assert(!f2);
+    LIBCPP_ASSERT(!f);
+  }
+}
+
+int main(int, char**) {
+  types::for_each(types::function_noexcept_const_ref_qualified<void()>{}, []<class T> { test<T>(); });
+  types::for_each(types::function_noexcept_const_ref_qualified<void(S)>{}, []<class T> {
+    test_member_function_pointer<T>();
+  });
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/assignment/move_other.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/assignment/move_other.pass.cpp
new file mode 100644
index 0000000000000..26faf862cc271
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/assignment/move_other.pass.cpp
@@ -0,0 +1,66 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// GCC doesn't support [[clang::trivial_abi]] currently, which we want to use on
+// move_only_function.
+// UNSUPPORTED: gcc
+
+#include <cassert>
+#include <concepts>
+#include <functional>
+#include <utility>
+
+#include "type_algorithms.h"
+#include "../common.h"
+
+template <class T>
+void test() {
+  {
+    std::move_only_function<void() const noexcept> f1;
+    std::move_only_function<T> f2;
+    std::same_as<std::move_only_function<T>&> decltype(auto) ret = (f2 = std::move(f1));
+    assert(&ret == &f2);
+    assert(!f2);
+  }
+  {
+    std::move_only_function<void() const & noexcept> f1;
+    std::move_only_function<T> f2;
+    std::same_as<std::move_only_function<T>&> decltype(auto) ret = (f2 = std::move(f1));
+    assert(&ret == &f2);
+    assert(!f2);
+  }
+}
+
+template <class T>
+void test2() {
+  {
+    std::move_only_function<int() const noexcept> f1 = [] noexcept { return 109; };
+    std::move_only_function<T> f2;
+    std::same_as<std::move_only_function<T>&> decltype(auto) ret = (f2 = std::move(f1));
+    assert(&ret == &f2);
+    assert(f2);
+    assert(f2() == 109);
+  }
+  {
+    std::move_only_function<int() const& noexcept> f1 = [] noexcept { return 109; };
+    std::move_only_function<T> f2;
+    std::same_as<std::move_only_function<T>&> decltype(auto) ret = (f2 = std::move(f1));
+    assert(&ret == &f2);
+    assert(f2);
+    assert(f2() == 109);
+  }
+}
+
+int main(int, char**) {
+  types::for_each(types::function_noexcept_const_ref_qualified<void()>{}, []<class T> { test<T>(); });
+  types::for_each(types::function_noexcept_const_lvalue_ref_qualified<int()>{}, []<class T> { test2<T>(); });
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/assignment/nullptr.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/assignment/nullptr.pass.cpp
new file mode 100644
index 0000000000000..d6bd39a418b98
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/assignment/nullptr.pass.cpp
@@ -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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// GCC doesn't support [[clang::trivial_abi]] currently, which we want to use on
+// move_only_function.
+// UNSUPPORTED: gcc
+
+#include <cassert>
+#include <functional>
+
+#include "type_algorithms.h"
+#include "../common.h"
+
+template <class T>
+void test() {
+  {
+    std::move_only_function<T> f = &call_func;
+    f                            = nullptr;
+    assert(!f);
+  }
+  {
+    decltype(&call_func) ptr     = nullptr;
+    std::move_only_function<T> f = ptr;
+    f                            = nullptr;
+    assert(!f);
+  }
+  {
+    std::move_only_function<T> f = TriviallyDestructible{};
+    f                            = nullptr;
+    assert(!f);
+  }
+  {
+    std::move_only_function<T> f = TriviallyDestructibleTooLarge{};
+    f                            = nullptr;
+    assert(!f);
+  }
+  {
+    std::move_only_function<T> f = NonTrivial{};
+    f                            = nullptr;
+    assert(!f);
+  }
+}
+
+struct S {
+  void func() noexcept {}
+};
+
+template <class T>
+void test_member_function_pointer() {
+  {
+    std::move_only_function<T> f = &S::func;
+    f                            = nullptr;
+    assert(!f);
+  }
+  {
+    decltype(&S::func) ptr       = nullptr;
+    std::move_only_function<T> f = ptr;
+    f                            = nullptr;
+    assert(!f);
+  }
+}
+
+int main(int, char**) {
+  types::for_each(types::function_noexcept_const_ref_qualified<void()>{}, []<class T> { test<T>(); });
+  types::for_each(types::function_noexcept_const_ref_qualified<void(S)>{}, []<class T> {
+    test_member_function_pointer<T>();
+  });
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/lvalue.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/lvalue.pass.cpp
new file mode 100644
index 0000000000000..1445cbd42f242
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/lvalue.pass.cpp
@@ -0,0 +1,106 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// GCC doesn't support [[clang::trivial_abi]] currently, which we want to use on
+// move_only_function.
+// UNSUPPORTED: gcc
+
+#include <cassert>
+#include <functional>
+
+#include "test_macros.h"
+#include "../common.h"
+
+struct S {
+  void func() & {}
+};
+
+static_assert(std::is_invocable_v<std::move_only_function<void() &>&>);
+static_assert(!std::is_invocable_v<std::move_only_function<void() &>>);
+static_assert(!std::is_invocable_v<std::move_only_function<void() &>&&>);
+static_assert(!std::is_invocable_v<std::move_only_function<void() &> const&>);
+static_assert(!std::is_invocable_v<std::move_only_function<void() &> const >);
+static_assert(!std::is_invocable_v<std::move_only_function<void() &> const&&>);
+
+void test() {
+  {
+    called                             = false;
+    std::move_only_function<void()&> f = &call_func;
+    f();
+    assert(called);
+  }
+  {
+    called                             = false;
+    std::move_only_function<void()&> f = TriviallyDestructible{};
+    f();
+    assert(called);
+  }
+  {
+    called                             = false;
+    std::move_only_function<void()&> f = TriviallyDestructibleTooLarge{};
+    f();
+    assert(called);
+  }
+  {
+    called                             = false;
+    std::move_only_function<void()&> f = NonTrivial{};
+    f();
+    assert(called);
+  }
+  {
+    std::move_only_function<void(S&)> f = &S::func;
+    assert(f);
+  }
+  {
+    decltype(&S::func) ptr              = nullptr;
+    std::move_only_function<void(S&)> f = ptr;
+    assert(!f);
+  }
+  {
+    CallType type;
+    std::move_only_function<void()&> f = CallTypeChecker{&type};
+    f();
+    assert(type == CallType::LValue);
+  }
+}
+
+void test_return() {
+  {
+    called                               = false;
+    std::move_only_function<int(int)&> f = &get_val;
+    assert(f(3) == 3);
+    assert(!called);
+  }
+  {
+    called                               = false;
+    std::move_only_function<int(int)&> f = TriviallyDestructible{};
+    assert(f(3) == 3);
+    assert(!called);
+  }
+  {
+    called                               = false;
+    std::move_only_function<int(int)&> f = TriviallyDestructibleTooLarge{};
+    assert(f(3) == 3);
+    assert(!called);
+  }
+  {
+    called                               = false;
+    std::move_only_function<int(int)&> f = NonTrivial{};
+    assert(f(3) == 3);
+    assert(!called);
+  }
+}
+
+int main(int, char**) {
+  test();
+  test_return();
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/lvalue_const.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/lvalue_const.pass.cpp
new file mode 100644
index 0000000000000..1f53d89eafadf
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/lvalue_const.pass.cpp
@@ -0,0 +1,122 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// GCC doesn't support [[clang::trivial_abi]] currently, which we want to use on
+// move_only_function.
+// UNSUPPORTED: gcc
+
+#include <cassert>
+#include <functional>
+#include <utility>
+
+#include "test_macros.h"
+#include "../common.h"
+
+struct S {
+  void func() const& {}
+};
+
+static_assert(std::is_invocable_v<std::move_only_function<void() const&>&>);
+static_assert(std::is_invocable_v<std::move_only_function<void() const&>>);
+static_assert(std::is_invocable_v<std::move_only_function<void() const&>&&>);
+static_assert(std::is_invocable_v<std::move_only_function<void() const&> const&>);
+static_assert(std::is_invocable_v<std::move_only_function<void() const&> const >);
+static_assert(std::is_invocable_v<std::move_only_function<void() const&> const&&>);
+
+void test() {
+  {
+    called                                   = false;
+    std::move_only_function<void() const&> f = &call_func;
+    f();
+    assert(called);
+  }
+  {
+    called                                   = false;
+    std::move_only_function<void() const&> f = TriviallyDestructible{};
+    f();
+    assert(called);
+  }
+  {
+    called                                   = false;
+    std::move_only_function<void() const&> f = TriviallyDestructibleTooLarge{};
+    f();
+    assert(called);
+  }
+  {
+    called                                   = false;
+    std::move_only_function<void() const&> f = NonTrivial{};
+    f();
+    assert(called);
+  }
+  {
+    std::move_only_function<void(const S&)> f = &S::func;
+    assert(f);
+  }
+  {
+    decltype(&S::func) ptr                    = nullptr;
+    std::move_only_function<void(const S&)> f = ptr;
+    assert(!f);
+  }
+  {
+    CallType type;
+    std::move_only_function<void() const&> f = CallTypeChecker{&type};
+    f();
+    assert(type == CallType::ConstLValue);
+  }
+  {
+    CallType type;
+    std::move_only_function<void() const&> f = CallTypeChecker{&type};
+    f();
+    assert(type == CallType::ConstLValue);
+    type = CallType::None;
+    std::as_const(f)();
+    assert(type == CallType::ConstLValue);
+    type = CallType::None;
+    std::move(f)();
+    assert(type == CallType::ConstLValue);
+    type = CallType::None;
+    std::move(std::as_const(f))();
+    assert(type == CallType::ConstLValue);
+  }
+}
+
+void test_return() {
+  {
+    called                                     = false;
+    std::move_only_function<int(int) const&> f = &get_val;
+    assert(f(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                     = false;
+    std::move_only_function<int(int) const&> f = TriviallyDestructible{};
+    assert(f(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                     = false;
+    std::move_only_function<int(int) const&> f = TriviallyDestructibleTooLarge{};
+    assert(f(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                     = false;
+    std::move_only_function<int(int) const&> f = NonTrivial{};
+    assert(f(3) == 3);
+    assert(!called);
+  }
+}
+
+int main(int, char**) {
+  test();
+  test_return();
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/lvalue_const_noexcept.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/lvalue_const_noexcept.pass.cpp
new file mode 100644
index 0000000000000..6bb18f21a4567
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/lvalue_const_noexcept.pass.cpp
@@ -0,0 +1,117 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// GCC doesn't support [[clang::trivial_abi]] currently, which we want to use on
+// move_only_function.
+// UNSUPPORTED: gcc
+
+#include <cassert>
+#include <functional>
+#include <type_traits>
+#include <utility>
+
+#include "test_macros.h"
+#include "../common.h"
+
+struct S {
+  void func() const& noexcept {}
+};
+
+static_assert(std::is_invocable_v<std::move_only_function<void() const & noexcept>&>);
+static_assert(std::is_invocable_v<std::move_only_function<void() const & noexcept>>);
+static_assert(std::is_invocable_v<std::move_only_function<void() const & noexcept>&&>);
+static_assert(std::is_invocable_v<std::move_only_function<void() const & noexcept> const&>);
+static_assert(std::is_invocable_v<std::move_only_function<void() const & noexcept> const >);
+static_assert(std::is_invocable_v<std::move_only_function<void() const & noexcept> const&&>);
+
+void test() {
+  {
+    called                                            = false;
+    std::move_only_function<void() const& noexcept> f = &call_func;
+    f();
+    assert(called);
+  }
+  {
+    called                                            = false;
+    std::move_only_function<void() const& noexcept> f = TriviallyDestructible{};
+    f();
+    assert(called);
+  }
+  {
+    called                                            = false;
+    std::move_only_function<void() const& noexcept> f = TriviallyDestructibleTooLarge{};
+    f();
+    assert(called);
+  }
+  {
+    called                                            = false;
+    std::move_only_function<void() const& noexcept> f = NonTrivial{};
+    f();
+    assert(called);
+  }
+  {
+    std::move_only_function<void(const S&) noexcept> f = &S::func;
+    assert(f);
+  }
+  {
+    decltype(&S::func) ptr                             = nullptr;
+    std::move_only_function<void(const S&) noexcept> f = ptr;
+    assert(!f);
+  }
+  {
+    CallType type;
+    std::move_only_function<void() const& noexcept> f = CallTypeCheckerNoexcept{&type};
+    f();
+    assert(type == CallType::ConstLValue);
+    type = CallType::None;
+    std::as_const(f)();
+    assert(type == CallType::ConstLValue);
+    type = CallType::None;
+    std::move(f)();
+    assert(type == CallType::ConstLValue);
+    type = CallType::None;
+    std::move(std::as_const(f))();
+    assert(type == CallType::ConstLValue);
+  }
+}
+
+void test_return() {
+  {
+    called                                              = false;
+    std::move_only_function<int(int) const& noexcept> f = &get_val;
+    assert(f(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                              = false;
+    std::move_only_function<int(int) const& noexcept> f = TriviallyDestructible{};
+    assert(f(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                              = false;
+    std::move_only_function<int(int) const& noexcept> f = TriviallyDestructibleTooLarge{};
+    assert(f(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                              = false;
+    std::move_only_function<int(int) const& noexcept> f = NonTrivial{};
+    assert(f(3) == 3);
+    assert(!called);
+  }
+}
+
+int main(int, char**) {
+  test();
+  test_return();
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/lvalue_noexcept.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/lvalue_noexcept.pass.cpp
new file mode 100644
index 0000000000000..2d8ef1a8b0ebd
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/lvalue_noexcept.pass.cpp
@@ -0,0 +1,106 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// GCC doesn't support [[clang::trivial_abi]] currently, which we want to use on
+// move_only_function.
+// UNSUPPORTED: gcc
+
+#include <cassert>
+#include <functional>
+
+#include "test_macros.h"
+#include "../common.h"
+
+struct S {
+  void func() & noexcept {}
+};
+
+static_assert(std::is_invocable_v<std::move_only_function<void() & noexcept>&>);
+static_assert(!std::is_invocable_v<std::move_only_function<void() & noexcept>>);
+static_assert(!std::is_invocable_v<std::move_only_function<void() & noexcept>&&>);
+static_assert(!std::is_invocable_v<std::move_only_function<void() & noexcept> const&>);
+static_assert(!std::is_invocable_v<std::move_only_function<void() & noexcept> const >);
+static_assert(!std::is_invocable_v<std::move_only_function<void() & noexcept> const&&>);
+
+void test() {
+  {
+    called                                      = false;
+    std::move_only_function<void()& noexcept> f = &call_func;
+    f();
+    assert(called);
+  }
+  {
+    called                                      = false;
+    std::move_only_function<void()& noexcept> f = TriviallyDestructible{};
+    f();
+    assert(called);
+  }
+  {
+    called                                      = false;
+    std::move_only_function<void()& noexcept> f = TriviallyDestructibleTooLarge{};
+    f();
+    assert(called);
+  }
+  {
+    called                                      = false;
+    std::move_only_function<void()& noexcept> f = NonTrivial{};
+    f();
+    assert(called);
+  }
+  {
+    std::move_only_function<void(S&) noexcept> f = &S::func;
+    assert(f);
+  }
+  {
+    decltype(&S::func) ptr                       = nullptr;
+    std::move_only_function<void(S&) noexcept> f = ptr;
+    assert(!f);
+  }
+  {
+    CallType type;
+    std::move_only_function<void()& noexcept> f = CallTypeCheckerNoexcept{&type};
+    f();
+    assert(type == CallType::LValue);
+  }
+}
+
+void test_return() {
+  {
+    called                                        = false;
+    std::move_only_function<int(int)& noexcept> f = &get_val;
+    assert(f(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                        = false;
+    std::move_only_function<int(int)& noexcept> f = TriviallyDestructible{};
+    assert(f(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                        = false;
+    std::move_only_function<int(int)& noexcept> f = TriviallyDestructibleTooLarge{};
+    assert(f(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                        = false;
+    std::move_only_function<int(int)& noexcept> f = NonTrivial{};
+    assert(f(3) == 3);
+    assert(!called);
+  }
+}
+
+int main(int, char**) {
+  test();
+  test_return();
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/normal.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/normal.pass.cpp
new file mode 100644
index 0000000000000..bb246bc99331e
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/normal.pass.cpp
@@ -0,0 +1,110 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// GCC doesn't support [[clang::trivial_abi]] currently, which we want to use on
+// move_only_function.
+// UNSUPPORTED: gcc
+
+#include <cassert>
+#include <functional>
+#include <utility>
+
+#include "test_macros.h"
+#include "../common.h"
+
+struct S {
+  void func() {}
+};
+
+static_assert(std::is_invocable_v<std::move_only_function<void()>&>);
+static_assert(std::is_invocable_v<std::move_only_function<void()>>);
+static_assert(std::is_invocable_v<std::move_only_function<void()>&&>);
+static_assert(!std::is_invocable_v<std::move_only_function<void()> const&>);
+static_assert(!std::is_invocable_v<std::move_only_function<void()> const >);
+static_assert(!std::is_invocable_v<std::move_only_function<void()> const&&>);
+
+void test() {
+  {
+    called                            = false;
+    std::move_only_function<void()> f = &call_func;
+    f();
+    assert(called);
+  }
+  {
+    called                            = false;
+    std::move_only_function<void()> f = TriviallyDestructible{};
+    f();
+    assert(called);
+  }
+  {
+    called                            = false;
+    std::move_only_function<void()> f = TriviallyDestructibleTooLarge{};
+    f();
+    assert(called);
+  }
+  {
+    called                            = false;
+    std::move_only_function<void()> f = NonTrivial{};
+    f();
+    assert(called);
+  }
+  {
+    std::move_only_function<void(S)> f = &S::func;
+    assert(f);
+  }
+  {
+    decltype(&S::func) ptr             = nullptr;
+    std::move_only_function<void(S)> f = ptr;
+    assert(!f);
+  }
+  {
+    CallType type;
+    std::move_only_function<void()> f = CallTypeChecker{&type};
+    f();
+    assert(type == CallType::LValue);
+    type = CallType::None;
+    std::move(f)();
+    assert(type == CallType::LValue);
+  }
+}
+
+void test_return() {
+  {
+    called                              = false;
+    std::move_only_function<int(int)> f = &get_val;
+    assert(f(3) == 3);
+    assert(!called);
+  }
+  {
+    called                              = false;
+    std::move_only_function<int(int)> f = TriviallyDestructible{};
+    assert(f(3) == 3);
+    assert(!called);
+  }
+  {
+    called                              = false;
+    std::move_only_function<int(int)> f = TriviallyDestructibleTooLarge{};
+    assert(f(3) == 3);
+    assert(!called);
+  }
+  {
+    called                              = false;
+    std::move_only_function<int(int)> f = NonTrivial{};
+    assert(f(3) == 3);
+    assert(!called);
+  }
+}
+
+int main(int, char**) {
+  test();
+  test_return();
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/normal_const.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/normal_const.pass.cpp
new file mode 100644
index 0000000000000..30fa980609112
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/normal_const.pass.cpp
@@ -0,0 +1,116 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// GCC doesn't support [[clang::trivial_abi]] currently, which we want to use on
+// move_only_function.
+// UNSUPPORTED: gcc
+
+#include <cassert>
+#include <functional>
+#include <utility>
+
+#include "test_macros.h"
+#include "../common.h"
+
+struct S {
+  void func() const noexcept {}
+};
+
+static_assert(std::is_invocable_v<std::move_only_function<void() const>&>);
+static_assert(std::is_invocable_v<std::move_only_function<void() const>>);
+static_assert(std::is_invocable_v<std::move_only_function<void() const>&&>);
+static_assert(std::is_invocable_v<std::move_only_function<void() const> const&>);
+static_assert(std::is_invocable_v<std::move_only_function<void() const> const >);
+static_assert(std::is_invocable_v<std::move_only_function<void() const> const&&>);
+
+void test() {
+  {
+    called                                  = false;
+    std::move_only_function<void() const> f = &call_func;
+    f();
+    assert(called);
+  }
+  {
+    called                                  = false;
+    std::move_only_function<void() const> f = TriviallyDestructible{};
+    f();
+    assert(called);
+  }
+  {
+    called                                  = false;
+    std::move_only_function<void() const> f = TriviallyDestructibleTooLarge{};
+    f();
+    assert(called);
+  }
+  {
+    called                                  = false;
+    std::move_only_function<void() const> f = NonTrivial{};
+    f();
+    assert(called);
+  }
+  {
+    std::move_only_function<void(S) const> f = &S::func;
+    assert(f);
+  }
+  {
+    decltype(&S::func) ptr                   = nullptr;
+    std::move_only_function<void(S) const> f = ptr;
+    assert(!f);
+  }
+  {
+    CallType type;
+    std::move_only_function<void() const> f = CallTypeChecker{&type};
+    f();
+    assert(type == CallType::ConstLValue);
+    type = CallType::None;
+    std::as_const(f)();
+    assert(type == CallType::ConstLValue);
+    type = CallType::None;
+    std::move(f)();
+    assert(type == CallType::ConstLValue);
+    type = CallType::None;
+    std::move(std::as_const(f))();
+    assert(type == CallType::ConstLValue);
+  }
+}
+
+void test_return() {
+  {
+    called                                    = false;
+    std::move_only_function<int(int) const> f = &get_val;
+    assert(f(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                    = false;
+    std::move_only_function<int(int) const> f = TriviallyDestructible{};
+    assert(f(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                    = false;
+    std::move_only_function<int(int) const> f = TriviallyDestructibleTooLarge{};
+    assert(f(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                    = false;
+    std::move_only_function<int(int) const> f = NonTrivial{};
+    assert(f(3) == 3);
+    assert(!called);
+  }
+}
+
+int main(int, char**) {
+  test();
+  test_return();
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/normal_const_noexcept.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/normal_const_noexcept.pass.cpp
new file mode 100644
index 0000000000000..9c4542b8d8352
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/normal_const_noexcept.pass.cpp
@@ -0,0 +1,116 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// GCC doesn't support [[clang::trivial_abi]] currently, which we want to use on
+// move_only_function.
+// UNSUPPORTED: gcc
+
+#include <cassert>
+#include <functional>
+#include <utility>
+
+#include "test_macros.h"
+#include "../common.h"
+
+struct S {
+  void func() const noexcept {}
+};
+
+static_assert(std::is_invocable_v<std::move_only_function<void() const noexcept>&>);
+static_assert(std::is_invocable_v<std::move_only_function<void() const noexcept>>);
+static_assert(std::is_invocable_v<std::move_only_function<void() const noexcept>&&>);
+static_assert(std::is_invocable_v<std::move_only_function<void() const noexcept> const&>);
+static_assert(std::is_invocable_v<std::move_only_function<void() const noexcept> const >);
+static_assert(std::is_invocable_v<std::move_only_function<void() const noexcept> const&&>);
+
+void test() {
+  {
+    called                                           = false;
+    std::move_only_function<void() const noexcept> f = &call_func;
+    f();
+    assert(called);
+  }
+  {
+    called                                           = false;
+    std::move_only_function<void() const noexcept> f = TriviallyDestructible{};
+    f();
+    assert(called);
+  }
+  {
+    called                                           = false;
+    std::move_only_function<void() const noexcept> f = TriviallyDestructibleTooLarge{};
+    f();
+    assert(called);
+  }
+  {
+    called                                           = false;
+    std::move_only_function<void() const noexcept> f = NonTrivial{};
+    f();
+    assert(called);
+  }
+  {
+    std::move_only_function<void(S) const noexcept> f = &S::func;
+    assert(f);
+  }
+  {
+    decltype(&S::func) ptr                            = nullptr;
+    std::move_only_function<void(S) const noexcept> f = ptr;
+    assert(!f);
+  }
+  {
+    CallType type;
+    std::move_only_function<void() const noexcept> f = CallTypeCheckerNoexcept{&type};
+    f();
+    assert(type == CallType::ConstLValue);
+    type = CallType::None;
+    std::as_const(f)();
+    assert(type == CallType::ConstLValue);
+    type = CallType::None;
+    std::move(f)();
+    assert(type == CallType::ConstLValue);
+    type = CallType::None;
+    std::move(std::as_const(f))();
+    assert(type == CallType::ConstLValue);
+  }
+}
+
+void test_return() {
+  {
+    called                                             = false;
+    std::move_only_function<int(int) const noexcept> f = &get_val;
+    assert(f(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                             = false;
+    std::move_only_function<int(int) const noexcept> f = TriviallyDestructible{};
+    assert(f(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                             = false;
+    std::move_only_function<int(int) const noexcept> f = TriviallyDestructibleTooLarge{};
+    assert(f(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                             = false;
+    std::move_only_function<int(int) const noexcept> f = NonTrivial{};
+    assert(f(3) == 3);
+    assert(!called);
+  }
+}
+
+int main(int, char**) {
+  test();
+  test_return();
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/normal_noexcept.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/normal_noexcept.pass.cpp
new file mode 100644
index 0000000000000..825154630777c
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/normal_noexcept.pass.cpp
@@ -0,0 +1,110 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// GCC doesn't support [[clang::trivial_abi]] currently, which we want to use on
+// move_only_function.
+// UNSUPPORTED: gcc
+
+#include <cassert>
+#include <functional>
+#include <utility>
+
+#include "test_macros.h"
+#include "../common.h"
+
+struct S {
+  void func() noexcept {}
+};
+
+static_assert(std::is_invocable_v<std::move_only_function<void() noexcept>&>);
+static_assert(std::is_invocable_v<std::move_only_function<void() noexcept>>);
+static_assert(std::is_invocable_v<std::move_only_function<void() noexcept>&&>);
+static_assert(!std::is_invocable_v<std::move_only_function<void() noexcept> const&>);
+static_assert(!std::is_invocable_v<std::move_only_function<void() noexcept> const >);
+static_assert(!std::is_invocable_v<std::move_only_function<void() noexcept> const&&>);
+
+void test() {
+  {
+    called                                     = false;
+    std::move_only_function<void() noexcept> f = &call_func;
+    f();
+    assert(called);
+  }
+  {
+    called                                     = false;
+    std::move_only_function<void() noexcept> f = TriviallyDestructible{};
+    f();
+    assert(called);
+  }
+  {
+    called                                     = false;
+    std::move_only_function<void() noexcept> f = TriviallyDestructibleTooLarge{};
+    f();
+    assert(called);
+  }
+  {
+    called                                     = false;
+    std::move_only_function<void() noexcept> f = NonTrivial{};
+    f();
+    assert(called);
+  }
+  {
+    std::move_only_function<void(S) noexcept> f = &S::func;
+    assert(f);
+  }
+  {
+    decltype(&S::func) ptr                      = nullptr;
+    std::move_only_function<void(S) noexcept> f = ptr;
+    assert(!f);
+  }
+  {
+    CallType type;
+    std::move_only_function<void() noexcept> f = CallTypeCheckerNoexcept{&type};
+    f();
+    assert(type == CallType::LValue);
+    type = CallType::None;
+    std::move(f)();
+    assert(type == CallType::LValue);
+  }
+}
+
+void test_return() {
+  {
+    called                                       = false;
+    std::move_only_function<int(int) noexcept> f = &get_val;
+    assert(f(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                       = false;
+    std::move_only_function<int(int) noexcept> f = TriviallyDestructible{};
+    assert(f(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                       = false;
+    std::move_only_function<int(int) noexcept> f = TriviallyDestructibleTooLarge{};
+    assert(f(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                       = false;
+    std::move_only_function<int(int) noexcept> f = NonTrivial{};
+    assert(f(3) == 3);
+    assert(!called);
+  }
+}
+
+int main(int, char**) {
+  test();
+  test_return();
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/rvalue.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/rvalue.pass.cpp
new file mode 100644
index 0000000000000..5e3d3d24fd7e1
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/rvalue.pass.cpp
@@ -0,0 +1,108 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// GCC doesn't support [[clang::trivial_abi]] currently, which we want to use on
+// move_only_function.
+// UNSUPPORTED: gcc
+
+#include <cassert>
+#include <functional>
+#include <utility>
+
+#include "test_macros.h"
+#include "../common.h"
+
+struct S {
+  void func() && noexcept {}
+};
+
+static_assert(!std::is_invocable_v<std::move_only_function<void() &&>&>);
+static_assert(std::is_invocable_v<std::move_only_function<void() &&>>);
+static_assert(std::is_invocable_v<std::move_only_function<void() &&>&&>);
+static_assert(!std::is_invocable_v<std::move_only_function<void() &&> const&>);
+static_assert(!std::is_invocable_v<std::move_only_function<void() &&> const >);
+static_assert(!std::is_invocable_v<std::move_only_function<void() &&> const&&>);
+
+void test() {
+  {
+    called                              = false;
+    std::move_only_function<void()&&> f = &call_func;
+    std::move(f)();
+    assert(called);
+  }
+  {
+    called                              = false;
+    std::move_only_function<void()&&> f = TriviallyDestructible{};
+    std::move(f)();
+    assert(called);
+  }
+  {
+    called                              = false;
+    std::move_only_function<void()&&> f = TriviallyDestructibleTooLarge{};
+    std::move(f)();
+    assert(called);
+  }
+  {
+    called                              = false;
+    std::move_only_function<void()&&> f = NonTrivial{};
+    std::move(f)();
+    assert(called);
+  }
+  {
+    std::move_only_function<void(S)&&> f = &S::func;
+    assert(f);
+  }
+  {
+    decltype(&S::func) ptr               = nullptr;
+    std::move_only_function<void(S)&&> f = ptr;
+    assert(!f);
+  }
+  {
+    CallType type;
+    std::move_only_function<void()&&> f = CallTypeChecker{&type};
+    type                                = CallType::None;
+    std::move(f)();
+    assert(type == CallType::RValue);
+  }
+}
+
+void test_return() {
+  {
+    called                                = false;
+    std::move_only_function<int(int)&&> f = &get_val;
+    assert(std::move(f)(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                = false;
+    std::move_only_function<int(int)&&> f = TriviallyDestructible{};
+    assert(std::move(f)(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                = false;
+    std::move_only_function<int(int)&&> f = TriviallyDestructibleTooLarge{};
+    assert(std::move(f)(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                = false;
+    std::move_only_function<int(int)&&> f = NonTrivial{};
+    assert(std::move(f)(3) == 3);
+    assert(!called);
+  }
+}
+
+int main(int, char**) {
+  test();
+  test_return();
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/rvalue_const.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/rvalue_const.pass.cpp
new file mode 100644
index 0000000000000..9ed5d2d6e93c6
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/rvalue_const.pass.cpp
@@ -0,0 +1,111 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// GCC doesn't support [[clang::trivial_abi]] currently, which we want to use on
+// move_only_function.
+// UNSUPPORTED: gcc
+
+#include <cassert>
+#include <functional>
+#include <utility>
+
+#include "test_macros.h"
+#include "../common.h"
+
+struct S {
+  void func() const&& noexcept {}
+};
+
+static_assert(!std::is_invocable_v<std::move_only_function<void() const&&>&>);
+static_assert(std::is_invocable_v<std::move_only_function<void() const&&>>);
+static_assert(std::is_invocable_v<std::move_only_function<void() const&&>&&>);
+static_assert(!std::is_invocable_v<std::move_only_function<void() const&&> const&>);
+static_assert(std::is_invocable_v<std::move_only_function<void() const&&> const >);
+static_assert(std::is_invocable_v<std::move_only_function<void() const&&> const&&>);
+
+void test() {
+  {
+    called                                    = false;
+    std::move_only_function<void() const&&> f = &call_func;
+    std::move(f)();
+    assert(called);
+  }
+  {
+    called                                    = false;
+    std::move_only_function<void() const&&> f = TriviallyDestructible{};
+    std::move(f)();
+    assert(called);
+  }
+  {
+    called                                    = false;
+    std::move_only_function<void() const&&> f = TriviallyDestructibleTooLarge{};
+    std::move(f)();
+    assert(called);
+  }
+  {
+    called                                    = false;
+    std::move_only_function<void() const&&> f = NonTrivial{};
+    std::move(f)();
+    assert(called);
+  }
+  {
+    std::move_only_function<void(S) const&&> f = &S::func;
+    assert(f);
+  }
+  {
+    decltype(&S::func) ptr                     = nullptr;
+    std::move_only_function<void(S) const&&> f = ptr;
+    assert(!f);
+  }
+  {
+    CallType type;
+    std::move_only_function<void() const&&> f = CallTypeChecker{&type};
+    type                                      = CallType::None;
+    std::move(f)();
+    assert(type == CallType::ConstRValue);
+    type = CallType::None;
+    std::move(std::as_const(f))();
+    assert(type == CallType::ConstRValue);
+  }
+}
+
+void test_return() {
+  {
+    called                                      = false;
+    std::move_only_function<int(int) const&&> f = &get_val;
+    assert(std::move(f)(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                      = false;
+    std::move_only_function<int(int) const&&> f = TriviallyDestructible{};
+    assert(std::move(f)(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                      = false;
+    std::move_only_function<int(int) const&&> f = TriviallyDestructibleTooLarge{};
+    assert(std::move(f)(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                      = false;
+    std::move_only_function<int(int) const&&> f = NonTrivial{};
+    assert(std::move(f)(3) == 3);
+    assert(!called);
+  }
+}
+
+int main(int, char**) {
+  test();
+  test_return();
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/rvalue_const_noexcept.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/rvalue_const_noexcept.pass.cpp
new file mode 100644
index 0000000000000..1b06656800407
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/rvalue_const_noexcept.pass.cpp
@@ -0,0 +1,111 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// GCC doesn't support [[clang::trivial_abi]] currently, which we want to use on
+// move_only_function.
+// UNSUPPORTED: gcc
+
+#include <cassert>
+#include <functional>
+#include <utility>
+
+#include "test_macros.h"
+#include "../common.h"
+
+struct S {
+  void func() const&& noexcept {}
+};
+
+static_assert(!std::is_invocable_v<std::move_only_function<void() const && noexcept>&>);
+static_assert(std::is_invocable_v<std::move_only_function<void() const && noexcept>>);
+static_assert(std::is_invocable_v<std::move_only_function<void() const && noexcept>&&>);
+static_assert(!std::is_invocable_v<std::move_only_function<void() const && noexcept> const&>);
+static_assert(std::is_invocable_v<std::move_only_function<void() const && noexcept> const >);
+static_assert(std::is_invocable_v<std::move_only_function<void() const && noexcept> const&&>);
+
+void test() {
+  {
+    called                                             = false;
+    std::move_only_function<void() const&& noexcept> f = &call_func;
+    std::move(f)();
+    assert(called);
+  }
+  {
+    called                                             = false;
+    std::move_only_function<void() const&& noexcept> f = TriviallyDestructible{};
+    std::move(f)();
+    assert(called);
+  }
+  {
+    called                                             = false;
+    std::move_only_function<void() const&& noexcept> f = TriviallyDestructibleTooLarge{};
+    std::move(f)();
+    assert(called);
+  }
+  {
+    called                                             = false;
+    std::move_only_function<void() const&& noexcept> f = NonTrivial{};
+    std::move(f)();
+    assert(called);
+  }
+  {
+    std::move_only_function<void(S) const&& noexcept> f = &S::func;
+    assert(f);
+  }
+  {
+    decltype(&S::func) ptr                              = nullptr;
+    std::move_only_function<void(S) const&& noexcept> f = ptr;
+    assert(!f);
+  }
+  {
+    CallType type;
+    std::move_only_function<void() const&& noexcept> f = CallTypeCheckerNoexcept{&type};
+    type                                               = CallType::None;
+    std::move(f)();
+    assert(type == CallType::ConstRValue);
+    type = CallType::None;
+    std::move(std::as_const(f))();
+    assert(type == CallType::ConstRValue);
+  }
+}
+
+void test_return() {
+  {
+    called                                               = false;
+    std::move_only_function<int(int) const&& noexcept> f = &get_val;
+    assert(std::move(f)(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                               = false;
+    std::move_only_function<int(int) const&& noexcept> f = TriviallyDestructible{};
+    assert(std::move(f)(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                               = false;
+    std::move_only_function<int(int) const&& noexcept> f = TriviallyDestructibleTooLarge{};
+    assert(std::move(f)(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                               = false;
+    std::move_only_function<int(int) const&& noexcept> f = NonTrivial{};
+    assert(std::move(f)(3) == 3);
+    assert(!called);
+  }
+}
+
+int main(int, char**) {
+  test();
+  test_return();
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/rvalue_noexcept.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/rvalue_noexcept.pass.cpp
new file mode 100644
index 0000000000000..6701187460902
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/rvalue_noexcept.pass.cpp
@@ -0,0 +1,108 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// GCC doesn't support [[clang::trivial_abi]] currently, which we want to use on
+// move_only_function.
+// UNSUPPORTED: gcc
+
+#include <cassert>
+#include <functional>
+#include <utility>
+
+#include "test_macros.h"
+#include "../common.h"
+
+struct S {
+  void func() && noexcept {}
+};
+
+static_assert(!std::is_invocable_v<std::move_only_function<void() && noexcept>&>);
+static_assert(std::is_invocable_v<std::move_only_function<void() && noexcept>>);
+static_assert(std::is_invocable_v<std::move_only_function<void() && noexcept>&&>);
+static_assert(!std::is_invocable_v<std::move_only_function<void() && noexcept> const&>);
+static_assert(!std::is_invocable_v<std::move_only_function<void() && noexcept> const >);
+static_assert(!std::is_invocable_v<std::move_only_function<void() && noexcept> const&&>);
+
+void test() {
+  {
+    called                                       = false;
+    std::move_only_function<void()&& noexcept> f = &call_func;
+    std::move(f)();
+    assert(called);
+  }
+  {
+    called                                       = false;
+    std::move_only_function<void()&& noexcept> f = TriviallyDestructible{};
+    std::move(f)();
+    assert(called);
+  }
+  {
+    called                                       = false;
+    std::move_only_function<void()&& noexcept> f = TriviallyDestructibleTooLarge{};
+    std::move(f)();
+    assert(called);
+  }
+  {
+    called                                       = false;
+    std::move_only_function<void()&& noexcept> f = NonTrivial{};
+    std::move(f)();
+    assert(called);
+  }
+  {
+    std::move_only_function<void(S)&& noexcept> f = &S::func;
+    assert(f);
+  }
+  {
+    decltype(&S::func) ptr                        = nullptr;
+    std::move_only_function<void(S)&& noexcept> f = ptr;
+    assert(!f);
+  }
+  {
+    CallType type;
+    std::move_only_function<void()&& noexcept> f = CallTypeCheckerNoexcept{&type};
+    type                                         = CallType::None;
+    std::move(f)();
+    assert(type == CallType::RValue);
+  }
+}
+
+void test_return() {
+  {
+    called                                         = false;
+    std::move_only_function<int(int)&& noexcept> f = &get_val;
+    assert(std::move(f)(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                         = false;
+    std::move_only_function<int(int)&& noexcept> f = TriviallyDestructible{};
+    assert(std::move(f)(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                         = false;
+    std::move_only_function<int(int)&& noexcept> f = TriviallyDestructibleTooLarge{};
+    assert(std::move(f)(3) == 3);
+    assert(!called);
+  }
+  {
+    called                                         = false;
+    std::move_only_function<int(int)&& noexcept> f = NonTrivial{};
+    assert(std::move(f)(3) == 3);
+    assert(!called);
+  }
+}
+
+int main(int, char**) {
+  test();
+  test_return();
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/common.h b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/common.h
new file mode 100644
index 0000000000000..e0d82d9b00499
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/common.h
@@ -0,0 +1,80 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 MOVE_ONLY_FUNCTION_COMMON_H
+#define MOVE_ONLY_FUNCTION_COMMON_H
+
+#include <initializer_list>
+#include <type_traits>
+
+inline bool called;
+inline void call_func() noexcept { called = true; }
+
+struct MoveCounter {
+  int* counter_;
+  MoveCounter(int* counter) : counter_(counter) {}
+  MoveCounter(MoveCounter&& other) : counter_(other.counter_) { ++*counter_; }
+};
+
+struct TriviallyDestructible {
+  TriviallyDestructible() = default;
+  TriviallyDestructible(MoveCounter) {}
+  TriviallyDestructible(std::initializer_list<int>, MoveCounter) {}
+  void operator()() const noexcept { called = true; }
+  int operator()(int i) const noexcept { return i; }
+};
+
+struct TriviallyDestructibleTooLarge {
+  TriviallyDestructibleTooLarge() = default;
+  TriviallyDestructibleTooLarge(MoveCounter) {}
+  TriviallyDestructibleTooLarge(std::initializer_list<int>, MoveCounter) {}
+  void operator()() const noexcept { called = true; }
+  int operator()(int i) const noexcept { return i; }
+  char a[5 * sizeof(void*)];
+};
+
+struct NonTrivial {
+  NonTrivial() = default;
+  NonTrivial(MoveCounter) {}
+  NonTrivial(std::initializer_list<int>&, MoveCounter) {}
+  NonTrivial(NonTrivial&&) noexcept(false) {}
+  ~NonTrivial() {}
+
+  void operator()() const noexcept { called = true; }
+  int operator()(int i) const noexcept { return i; }
+};
+
+inline int get_val(int i) noexcept { return i; }
+
+enum class CallType {
+  None,
+  LValue,
+  RValue,
+  ConstLValue,
+  ConstRValue,
+};
+
+struct CallTypeChecker {
+  CallType* type;
+  using enum CallType;
+  void operator()() & { *type = LValue; }
+  void operator()() && { *type = RValue; }
+  void operator()() const& { *type = ConstLValue; }
+  void operator()() const&& { *type = ConstRValue; }
+};
+
+struct CallTypeCheckerNoexcept {
+  CallType* type;
+  using enum CallType;
+  void operator()() & noexcept { *type = LValue; }
+  void operator()() && noexcept { *type = RValue; }
+  void operator()() const& noexcept { *type = ConstLValue; }
+  void operator()() const&& noexcept { *type = ConstRValue; }
+};
+
+#endif // MOVE_ONLY_FUNCTION_COMMON_H
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/default.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/default.pass.cpp
new file mode 100644
index 0000000000000..b916c46630d3a
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/default.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
+
+// GCC doesn't support [[clang::trivial_abi]] currently, which we want to use on
+// move_only_function.
+// UNSUPPORTED: gcc
+
+#include <cassert>
+#include <functional>
+
+#include "type_algorithms.h"
+
+template <class T>
+void test() {
+  std::move_only_function<T> f;
+  assert(!f);
+}
+
+int main(int, char**) {
+  types::for_each(types::function_noexcept_const_ref_qualified<void()>{}, []<class T> { test<T>(); });
+  types::for_each(types::function_noexcept_const_ref_qualified<int()>{}, []<class T> { test<T>(); });
+  types::for_each(types::function_noexcept_const_ref_qualified<int(int)>{}, []<class T> { test<T>(); });
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/functor.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/functor.pass.cpp
new file mode 100644
index 0000000000000..e0bc98df5a98e
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/functor.pass.cpp
@@ -0,0 +1,119 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// GCC doesn't support [[clang::trivial_abi]] currently, which we want to use on
+// move_only_function.
+// UNSUPPORTED: gcc
+
+#include <cassert>
+#include <functional>
+
+#include "count_new.h"
+#include "test_macros.h"
+#include "type_algorithms.h"
+#include "../common.h"
+
+template <class T>
+void test() {
+  {
+    std::move_only_function<T> f = &call_func;
+    assert(f);
+  }
+  {
+    decltype(&call_func) ptr     = nullptr;
+    std::move_only_function<T> f = ptr;
+    assert(!f);
+  }
+  {
+    std::move_only_function<T> f = TriviallyDestructible{};
+    assert(f);
+  }
+  {
+    std::move_only_function<T> f = TriviallyDestructibleTooLarge{};
+    assert(f);
+  }
+  {
+    std::move_only_function<T> f = NonTrivial{};
+    assert(f);
+  }
+}
+
+struct S {
+  void func() noexcept {}
+};
+
+template <class T>
+void test_member_function_pointer() {
+  {
+    std::move_only_function<T> f = &S::func;
+    assert(f);
+  }
+  {
+    decltype(&S::func) ptr       = nullptr;
+    std::move_only_function<T> f = ptr;
+    assert(!f);
+  }
+}
+
+template <class T>
+void test_value_return_type() {
+  {
+    std::move_only_function<T> f = &get_val;
+    assert(f);
+  }
+  {
+    decltype(&get_val) ptr       = nullptr;
+    std::move_only_function<T> f = ptr;
+    assert(!f);
+  }
+  {
+    std::move_only_function<T> f = TriviallyDestructible{};
+    assert(f);
+  }
+  {
+    std::move_only_function<T> f = TriviallyDestructibleTooLarge{};
+    assert(f);
+  }
+  {
+    std::move_only_function<T> f = NonTrivial{};
+    assert(f);
+  }
+}
+
+template <class T>
+void test_throwing() {
+  struct ThrowingFunctor {
+    ThrowingFunctor() = default;
+    ThrowingFunctor(const ThrowingFunctor&) { throw 1; }
+    void operator()() {}
+  };
+  std::move_only_function<T> func({});
+}
+
+void check_new_delete_called() {
+  assert(globalMemCounter.new_called == globalMemCounter.delete_called);
+  assert(globalMemCounter.new_array_called == globalMemCounter.delete_array_called);
+  assert(globalMemCounter.aligned_new_called == globalMemCounter.aligned_delete_called);
+  assert(globalMemCounter.aligned_new_array_called == globalMemCounter.aligned_delete_array_called);
+}
+
+int main(int, char**) {
+  types::for_each(types::function_noexcept_const_ref_qualified<void()>{}, []<class T> { test<T>(); });
+  types::for_each(types::function_noexcept_const_ref_qualified<void(S)>{}, []<class T> {
+    test_member_function_pointer<T>();
+  });
+  types::for_each(types::function_noexcept_const_ref_qualified<int(int)>{}, []<class T> {
+    test_value_return_type<T>();
+  });
+  types::for_each(types::function_noexcept_const_ref_qualified<void()>{}, []<class T> { test_throwing<T>(); });
+  check_new_delete_called();
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/in_place.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/in_place.pass.cpp
new file mode 100644
index 0000000000000..47f9b76d20279
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/in_place.pass.cpp
@@ -0,0 +1,50 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// GCC doesn't support [[clang::trivial_abi]] currently, which we want to use on
+// move_only_function.
+// UNSUPPORTED: gcc
+
+#include <cassert>
+#include <functional>
+#include <utility>
+
+#include "test_macros.h"
+#include "type_algorithms.h"
+#include "../common.h"
+
+template <class T>
+void test() {
+  {
+    int counter = 0;
+    std::move_only_function<T> f{std::in_place_type<TriviallyDestructible>, MoveCounter{&counter}};
+    assert(f);
+    assert(counter == 1);
+  }
+  {
+    int counter = 0;
+    std::move_only_function<T> f{std::in_place_type<TriviallyDestructibleTooLarge>, MoveCounter{&counter}};
+    assert(f);
+    assert(counter == 1);
+  }
+  {
+    int counter = 0;
+    std::move_only_function<T> f{std::in_place_type<NonTrivial>, MoveCounter{&counter}};
+    assert(f);
+    assert(counter == 1);
+  }
+}
+
+int main(int, char**) {
+  types::for_each(types::function_noexcept_const_ref_qualified<void()>{}, []<class T> { test<T>(); });
+  types::for_each(types::function_noexcept_const_ref_qualified<int(int)>{}, []<class T> { test<T>(); });
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/in_place_init_list.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/in_place_init_list.pass.cpp
new file mode 100644
index 0000000000000..193b0488f2915
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/in_place_init_list.pass.cpp
@@ -0,0 +1,50 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// GCC doesn't support [[clang::trivial_abi]] currently, which we want to use on
+// move_only_function.
+// UNSUPPORTED: gcc
+
+#include <cassert>
+#include <functional>
+#include <utility>
+
+#include "test_macros.h"
+#include "type_algorithms.h"
+#include "../common.h"
+
+template <class T>
+void test() {
+  {
+    int counter = 0;
+    std::move_only_function<T> f{std::in_place_type<TriviallyDestructible>, {1}, MoveCounter{&counter}};
+    assert(f);
+    assert(counter == 1);
+  }
+  {
+    int counter = 0;
+    std::move_only_function<T> f{std::in_place_type<TriviallyDestructibleTooLarge>, {1}, MoveCounter{&counter}};
+    assert(f);
+    assert(counter == 1);
+  }
+  {
+    int counter = 0;
+    std::move_only_function<T> f{std::in_place_type<NonTrivial>, {1}, MoveCounter{&counter}};
+    assert(f);
+    assert(counter == 1);
+  }
+}
+
+int main(int, char**) {
+  types::for_each(types::function_noexcept_const_ref_qualified<void()>{}, []<class T> { test<T>(); });
+  types::for_each(types::function_noexcept_const_ref_qualified<int(int)>{}, []<class T> { test<T>(); });
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/move.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/move.pass.cpp
new file mode 100644
index 0000000000000..c52b4013144bd
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/move.pass.cpp
@@ -0,0 +1,110 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// GCC doesn't support [[clang::trivial_abi]] currently, which we want to use on
+// move_only_function.
+// UNSUPPORTED: gcc
+
+#include <cassert>
+#include <functional>
+#include <utility>
+
+#include "test_macros.h"
+#include "type_algorithms.h"
+#include "../common.h"
+
+template <class T>
+void test() {
+  {
+    std::move_only_function<T> f  = &call_func;
+    std::move_only_function<T> f2 = std::move(f);
+    assert(f2);
+  }
+  {
+    decltype(&call_func) ptr      = nullptr;
+    std::move_only_function<T> f  = ptr;
+    std::move_only_function<T> f2 = std::move(f);
+    assert(!f2);
+  }
+  {
+    std::move_only_function<T> f  = TriviallyDestructible{};
+    std::move_only_function<T> f2 = std::move(f);
+    assert(f2);
+  }
+  {
+    std::move_only_function<T> f  = TriviallyDestructibleTooLarge{};
+    std::move_only_function<T> f2 = std::move(f);
+    assert(f2);
+  }
+  {
+    std::move_only_function<T> f  = NonTrivial{};
+    std::move_only_function<T> f2 = std::move(f);
+    assert(f2);
+  }
+}
+
+struct S {
+  void func() noexcept {}
+};
+
+template <class T>
+void test_member_function_pointer() {
+  {
+    std::move_only_function<T> f  = &S::func;
+    std::move_only_function<T> f2 = std::move(f);
+    assert(f2);
+  }
+  {
+    decltype(&S::func) ptr        = nullptr;
+    std::move_only_function<T> f  = ptr;
+    std::move_only_function<T> f2 = std::move(f);
+    assert(!f2);
+  }
+}
+
+template <class T>
+void test_value() {
+  {
+    std::move_only_function<T> f  = &get_val;
+    std::move_only_function<T> f2 = std::move(f);
+    assert(f2);
+  }
+  {
+    decltype(&get_val) ptr        = nullptr;
+    std::move_only_function<T> f  = ptr;
+    std::move_only_function<T> f2 = std::move(f);
+    assert(!f2);
+  }
+  {
+    std::move_only_function<T> f  = TriviallyDestructible{};
+    std::move_only_function<T> f2 = std::move(f);
+    assert(f2);
+  }
+  {
+    std::move_only_function<T> f  = TriviallyDestructibleTooLarge{};
+    std::move_only_function<T> f2 = std::move(f);
+    assert(f2);
+  }
+  {
+    std::move_only_function<T> f  = NonTrivial{};
+    std::move_only_function<T> f2 = std::move(f);
+    assert(f2);
+  }
+}
+
+int main(int, char**) {
+  types::for_each(types::function_noexcept_const_ref_qualified<void()>{}, []<class T> { test<T>(); });
+  types::for_each(types::function_noexcept_const_ref_qualified<void(S)>{}, []<class T> {
+    test_member_function_pointer<T>();
+  });
+  types::for_each(types::function_noexcept_const_ref_qualified<int(int)>{}, []<class T> { test_value<T>(); });
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/move_other.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/move_other.pass.cpp
new file mode 100644
index 0000000000000..b3d95f58e14b2
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/move_other.pass.cpp
@@ -0,0 +1,48 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// GCC doesn't support [[clang::trivial_abi]] currently, which we want to use on
+// move_only_function.
+// UNSUPPORTED: gcc
+
+#include <cassert>
+#include <functional>
+#include <utility>
+
+#include "type_algorithms.h"
+
+static_assert(!std::is_constructible_v<std::move_only_function<void() const>, std::move_only_function<void()>>);
+static_assert(!std::is_constructible_v<std::move_only_function<void() noexcept>, std::move_only_function<void()>>);
+static_assert(
+    !std::is_constructible_v<std::move_only_function<void() const noexcept>, std::move_only_function<void()>>);
+static_assert(
+    !std::is_constructible_v<std::move_only_function<void() const noexcept>, std::move_only_function<void() const>>);
+static_assert(
+    !std::is_constructible_v<std::move_only_function<void() const noexcept>, std::move_only_function<void() noexcept>>);
+
+template <class T>
+void test() {
+  {
+    std::move_only_function<void() const noexcept> f1;
+    std::move_only_function<T> f2 = std::move(f1);
+    assert(!f2);
+  }
+  {
+    std::move_only_function<void() const & noexcept> f1;
+    std::move_only_function<T> f2 = std::move(f1);
+    assert(!f2);
+  }
+}
+
+int main(int, char**) {
+  types::for_each(types::function_noexcept_const_ref_qualified<void()>{}, []<class T> { test<T>(); });
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/nullptr.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/nullptr.pass.cpp
new file mode 100644
index 0000000000000..54a916224e107
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/nullptr.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
+
+// GCC doesn't support [[clang::trivial_abi]] currently, which we want to use on
+// move_only_function.
+// UNSUPPORTED: gcc
+
+#include <cassert>
+#include <functional>
+
+#include "type_algorithms.h"
+
+template <class T>
+void test() {
+  std::move_only_function<T> f = nullptr;
+  assert(!f);
+}
+
+int main(int, char**) {
+  types::for_each(types::function_noexcept_const_ref_qualified<void()>{}, []<class T> { test<T>(); });
+  types::for_each(types::function_noexcept_const_ref_qualified<int()>{}, []<class T> { test<T>(); });
+  types::for_each(types::function_noexcept_const_ref_qualified<int(int)>{}, []<class T> { test<T>(); });
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/swap.adl.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/swap.adl.pass.cpp
new file mode 100644
index 0000000000000..7996bad3dec2e
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/swap.adl.pass.cpp
@@ -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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// GCC doesn't support [[clang::trivial_abi]] currently, which we want to use on
+// move_only_function.
+// UNSUPPORTED: gcc
+
+#include <cassert>
+#include <functional>
+
+#include "type_algorithms.h"
+#include "common.h"
+
+template <class T>
+void test() {
+  {
+    std::move_only_function<T> f = &call_func;
+    std::move_only_function<T> f2;
+    swap(f, f2);
+  }
+  {
+    decltype(&call_func) ptr     = nullptr;
+    std::move_only_function<T> f = ptr;
+    std::move_only_function<T> f2;
+    swap(f, f2);
+  }
+  {
+    std::move_only_function<T> f = TriviallyDestructible{};
+    std::move_only_function<T> f2;
+    swap(f, f2);
+  }
+  {
+    std::move_only_function<T> f = TriviallyDestructibleTooLarge{};
+    std::move_only_function<T> f2;
+    swap(f, f2);
+  }
+  {
+    std::move_only_function<T> f = NonTrivial{};
+    std::move_only_function<T> f2;
+    swap(f, f2);
+  }
+}
+
+struct S {
+  void func() noexcept {}
+};
+
+template <class T>
+void test_member_function_pointer() {
+  {
+    std::move_only_function<T> f = &S::func;
+    std::move_only_function<T> f2;
+    swap(f, f2);
+  }
+  {
+    decltype(&S::func) ptr       = nullptr;
+    std::move_only_function<T> f = ptr;
+    std::move_only_function<T> f2;
+    swap(f, f2);
+  }
+}
+
+int main(int, char**) {
+  types::for_each(types::function_noexcept_const_ref_qualified<void()>{}, []<class T> { test<T>(); });
+  types::for_each(types::function_noexcept_const_ref_qualified<void(S)>{}, []<class T> {
+    test_member_function_pointer<T>();
+  });
+
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/swap.member.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/swap.member.pass.cpp
new file mode 100644
index 0000000000000..44a7c69b988f5
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/swap.member.pass.cpp
@@ -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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// GCC doesn't support [[clang::trivial_abi]] currently, which we want to use on
+// move_only_function.
+// UNSUPPORTED: gcc
+
+#include <cassert>
+#include <functional>
+
+#include "type_algorithms.h"
+#include "common.h"
+
+template <class T>
+void test() {
+  {
+    std::move_only_function<T> f = &call_func;
+    std::move_only_function<T> f2;
+    f.swap(f2);
+  }
+  {
+    decltype(&call_func) ptr     = nullptr;
+    std::move_only_function<T> f = ptr;
+    std::move_only_function<T> f2;
+    f.swap(f2);
+  }
+  {
+    std::move_only_function<T> f = TriviallyDestructible{};
+    std::move_only_function<T> f2;
+    f.swap(f2);
+  }
+  {
+    std::move_only_function<T> f = TriviallyDestructibleTooLarge{};
+    std::move_only_function<T> f2;
+    f.swap(f2);
+  }
+  {
+    std::move_only_function<T> f = NonTrivial{};
+    std::move_only_function<T> f2;
+    f.swap(f2);
+  }
+}
+
+struct S {
+  void func() noexcept {}
+};
+
+template <class T>
+void test_member_function_pointer() {
+  {
+    std::move_only_function<T> f = &S::func;
+    std::move_only_function<T> f2;
+    f.swap(f2);
+  }
+  {
+    decltype(&S::func) ptr       = nullptr;
+    std::move_only_function<T> f = ptr;
+    std::move_only_function<T> f2;
+    f.swap(f2);
+  }
+}
+
+int main(int, char**) {
+  types::for_each(types::function_noexcept_const_ref_qualified<void()>{}, []<class T> { test<T>(); });
+  types::for_each(types::function_noexcept_const_ref_qualified<void(S)>{}, []<class T> {
+    test_member_function_pointer<T>();
+  });
+
+  return 0;
+}
diff --git a/libcxx/test/support/type_algorithms.h b/libcxx/test/support/type_algorithms.h
index da3d0add4d0c4..b6f65ebb8d716 100644
--- a/libcxx/test/support/type_algorithms.h
+++ b/libcxx/test/support/type_algorithms.h
@@ -144,6 +144,42 @@ struct type_list_as_pointers<type_list<Types...> > {
 
 template <class T>
 using as_pointers = typename type_list_as_pointers<T>::type;
+template <class...>
+struct function_noexcept_const_lvalue_ref_qualified_impl;
+
+template <class ReturnT, class... Args>
+struct function_noexcept_const_lvalue_ref_qualified_impl<ReturnT(Args...)> {
+  using type =
+      type_list<ReturnT(Args...),
+                ReturnT(Args...)&,
+                ReturnT(Args...) noexcept,
+                ReturnT(Args...) & noexcept,
+                ReturnT(Args...) const,
+                ReturnT(Args...) const&,
+                ReturnT(Args...) const noexcept,
+                ReturnT(Args...) const & noexcept>;
+};
+
+template <class Func>
+using function_noexcept_const_lvalue_ref_qualified =
+    typename function_noexcept_const_lvalue_ref_qualified_impl<Func>::type;
+
+template <class...>
+struct function_noexcept_const_ref_qualified_impl;
+
+template <class ReturnT, class... Args>
+struct function_noexcept_const_ref_qualified_impl<ReturnT(Args...)> {
+  using type =
+      concatenate_t<function_noexcept_const_lvalue_ref_qualified<ReturnT(Args...)>,
+                    type_list<ReturnT(Args...)&&,
+                              ReturnT(Args...) && noexcept,
+                              ReturnT(Args...) const&&,
+                              ReturnT(Args...) const && noexcept> >;
+};
+
+template <class Func>
+using function_noexcept_const_ref_qualified = typename function_noexcept_const_ref_qualified_impl<Func>::type;
+
 } // namespace types
 
 #endif // TEST_SUPPORT_TYPE_ALGORITHMS_H
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 0802f865f9406..afa726da72a96 100644
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -973,7 +973,8 @@ def add_version_header(tc):
             "name": "__cpp_lib_move_only_function",
             "values": {"c++23": 202110},
             "headers": ["functional"],
-            "unimplemented": True,
+            "test_suite_guard": "!defined(_LIBCPP_VERSION) || (!defined(TEST_COMPILER_GCC) && defined(_LIBCPP_HAS_EXPERIMENTAL_MOVE_ONLY_FUNCTION))"
+            "libcxx_guard": "!defined(_LIBCPP_COMPILER_GCC) && defined(_LIBCPP_HAS_EXPERIMENTAL_MOVE_ONLY_FUNCTION)"
         },
         {
             "name": "__cpp_lib_node_extract",



More information about the libcxx-commits mailing list