[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