diff --git a/libcxx/.clang-format b/libcxx/.clang-format --- a/libcxx/.clang-format +++ b/libcxx/.clang-format @@ -68,7 +68,7 @@ NamespaceIndentation: Inner PackConstructorInitializers: NextLine -PenaltyIndentedWhitespace: 61 +PenaltyIndentedWhitespace: 2 Language: Cpp Standard: c++20 diff --git a/libcxx/docs/Status/Cxx2bPapers.csv b/libcxx/docs/Status/Cxx2bPapers.csv --- a/libcxx/docs/Status/Cxx2bPapers.csv +++ b/libcxx/docs/Status/Cxx2bPapers.csv @@ -23,7 +23,7 @@ "`P2136R3 `__","LWG","invoke_r","June 2021","","" "`P2166R1 `__","LWG","A Proposal to Prohibit std::basic_string and std::basic_string_view construction from nullptr","June 2021","|Complete|","13.0" "","","","","","" -"`P0288R9 `__","LWG","``any_invocable``","October 2021","","" +"`P0288R9 `__","LWG","``move_only_function``","October 2021","|Complete|","16.0" "`P0798R8 `__","LWG","Monadic operations for ``std::optional``","October 2021","|Complete|","14.0" "`P0849R8 `__","LWG","``auto(x)``: ``DECAY_COPY`` in the language","October 2021","|Complete|","14.0" "`P1072R10 `__","LWG","``basic_string::resize_and_overwrite``","October 2021","|Complete|","14.0" diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -313,6 +313,8 @@ __functional/is_transparent.h __functional/mem_fn.h __functional/mem_fun_ref.h + __functional/move_only_function.h + __functional/move_only_function_impl.h __functional/not_fn.h __functional/operations.h __functional/perfect_forward.h @@ -588,6 +590,7 @@ __type_traits/is_trivially_destructible.h __type_traits/is_trivially_move_assignable.h __type_traits/is_trivially_move_constructible.h + __type_traits/is_trivially_relocatable.h __type_traits/is_unbounded_array.h __type_traits/is_union.h __type_traits/is_unsigned.h diff --git a/libcxx/include/__config b/libcxx/include/__config --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -124,6 +124,8 @@ // The implementation moved to the header, but we still export the symbols from // the dylib for backwards compatibility. # define _LIBCPP_ABI_DO_NOT_EXPORT_TO_CHARS_BASE_10 +// Enable clang::trivial_abi for std::move_only_function +# define _LIBCPP_ABI_MOVE_ONLY_FUNCTION_TRIVIAL_ABI # elif _LIBCPP_ABI_VERSION == 1 # if !(defined(_LIBCPP_OBJECT_FORMAT_COFF) || defined(_LIBCPP_OBJECT_FORMAT_XCOFF)) // Enable compiling copies of now inline methods into the dylib to support diff --git a/libcxx/include/__functional/move_only_function.h b/libcxx/include/__functional/move_only_function.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__functional/move_only_function.h @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// +// 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 > 20 + +// 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> + +# define _LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT true +# include <__functional/move_only_function_impl.h> + +# define _LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT true +# define _LIBCPP_MOVE_ONLY_FUNCTION_REF & +# include <__functional/move_only_function_impl.h> + +# define _LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT true +# define _LIBCPP_MOVE_ONLY_FUNCTION_REF && +# include <__functional/move_only_function_impl.h> + +# define _LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT true +# define _LIBCPP_MOVE_ONLY_FUNCTION_CV const +# include <__functional/move_only_function_impl.h> + +# define _LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT true +# 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_NOEXCEPT true +# 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 + +#endif // _LIBCPP___FUNCTIONAL_MOVE_ONLY_FUNCTION_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 --- /dev/null +++ b/libcxx/include/__functional/move_only_function_impl.h @@ -0,0 +1,400 @@ +//===----------------------------------------------------------------------===// +// +// 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 only partially guarded on purpose. This header is an implementation detail of move_only_function.h +// and generates multiple versions of std::move_only_function + +#include <__bit/bit_cast.h> +#include <__config> +#include <__functional/invoke.h> +#include <__memory/construct_at.h> +#include <__memory/unique_ptr.h> +#include <__type_traits/is_trivially_relocatable.h> +#include <__utility/forward.h> +#include <__utility/in_place.h> +#include <__utility/move.h> +#include +#include +#include +#include +#include + +#include + +#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___FUNCTIONAL_MOVE_ONLY_FUNCTION_IMPL_H +# define _LIBCPP___FUNCTIONAL_MOVE_ONLY_FUNCTION_IMPL_H + +_LIBCPP_BEGIN_NAMESPACE_STD + +// The storage for move_only_functions may be one of 3 things: +// - A pointer to a heap object +// - A trivially relocatable object +// - A trivially relocatable object that also has a trivial destructor +// +// If the object is too large or not trivially relocatable it is stored on the heap. +// (on 64-bit platforms) an object fits into the small buffer if +// - it is trivially relocatable and has a size of less than 32 bytes and an alignment of no more than 8 bytes, or +// - it is trivially destructible and has a size of less than 40 bytes and an alignment of no more than 8 bytes. +// +// "size of" in this case doesn't mean "sizeof". Objects which have padding bytes at the end may also be put into +// the small buffer if the padding byte can be detected by [[no_unique_address]]. For example +// +// class [[clang::trivial_abi]] A { +// int* begin; +// int* end; +// int* cap; +// int flags; +// public: +// A(A&&); +// ~A(); +// void operator()() {} +// }; +// +// is put into the small buffer, even though sizeof(A) == 32. + +union __move_only_function_storage { + using _DestroyFn = void(void*); + using _CallFn = void; + + static constexpr auto __target_size = 6 * sizeof(void*); + + enum class _Status : uint8_t { + _NotEngaged, + _TriviallyRelocatable, + _TriviallyDestructible, + _Heap, + }; + + struct _HeapObject { + _CallFn* __call_; + _DestroyFn* __destroy_; + std::byte* __heap_; + std::byte __padding_[__target_size - 3 * sizeof(void*) - 1]; + _Status __status_; + } __large_; + static_assert(sizeof(_HeapObject) == __target_size); + static_assert(offsetof(_HeapObject, __status_) == __target_size - 1); + + struct _TriviallyRelocatableObject { + _CallFn* __call_; + _DestroyFn* __destroy_; + alignas(void*) std::byte __data_[__target_size - 2 * sizeof(void*) - 1]; + _Status __status_; + } __trivially_relocatable_; + static_assert(sizeof(_TriviallyRelocatableObject) == __target_size); + static_assert(offsetof(_TriviallyRelocatableObject, __status_) == __target_size - 1); + + struct _TriviallyDestructibleObject { + _CallFn* __call_; + alignas(void*) std::byte __data_[__target_size - 1 * sizeof(void*) - 1]; + _Status __status_; + } __trivially_destructible_; + static_assert(sizeof(_TriviallyDestructibleObject) == __target_size); + static_assert(offsetof(_TriviallyDestructibleObject, __status_) == __target_size - 1); + +private: + // try to squeeze in another char to see if we can use the last byte for our own purposes + template + struct _Compact { + _LIBCPP_NO_UNIQUE_ADDRESS _Func __func; + char __c; + }; + + template + static constexpr bool __fits_in_buffer = + sizeof(_Compact<_Func>) <= _BufferSize + 1 && alignof(_Func) <= BufferAlignment; + + template + static constexpr bool __fits_in_trivially_relocatable_buffer_impl = + __libcpp_is_trivially_relocatable_v<_Func> && + __fits_in_buffer<_Func, + sizeof(_TriviallyRelocatableObject::__data_), + alignof(_TriviallyRelocatableObject::__data_)>; + + template + static constexpr bool __fits_in_trivially_destructible_buffer_impl = + __libcpp_is_trivially_relocatable_v<_Func> && is_trivially_destructible_v<_Func> && + __fits_in_buffer<_Func, + sizeof(_TriviallyDestructibleObject::__data_), + alignof(_TriviallyDestructibleObject::__data_)>; + +public: + template + static constexpr bool __fits_in_trivially_relocatable_buffer = + __fits_in_trivially_relocatable_buffer_impl>; + + template + static constexpr bool __fits_in_trivially_destructible_buffer = + __fits_in_trivially_destructible_buffer_impl>; +}; + +static_assert(alignof(__move_only_function_storage) == alignof(void*)); +static_assert(sizeof(__move_only_function_storage) == __move_only_function_storage::__target_size); + +template +class move_only_function; + +template +struct __is_move_only_function : false_type {}; + +template +struct __is_move_only_function> : true_type {}; + +_LIBCPP_END_NAMESPACE_STD + +// This header is only partially guarded on purpose. This header is an implementation detail of move_only_function.h +// and generates multiple versions of std::move_only_function +#endif // _LIBCPP___FUNCTIONAL_MOVE_ONLY_FUNCTION_IMPL_H + +#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_INV_QUALS _LIBCPP_MOVE_ONLY_FUNCTION_CV& +#else +# define _LIBCPP_MOVE_ONLY_FUNCTION_INV_QUALS _LIBCPP_MOVE_ONLY_FUNCTION_CV _LIBCPP_MOVE_ONLY_FUNCTION_REF +#endif + +#ifndef _LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT +# define _LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT false +#endif + +#define _LIBCPP_MOVE_ONLY_FUNCTION_CV_REF _LIBCPP_MOVE_ONLY_FUNCTION_CV _LIBCPP_MOVE_ONLY_FUNCTION_REF + +_LIBCPP_BEGIN_NAMESPACE_STD + +#ifdef _LIBCPP_ABI_MOVE_ONLY_FUNCTION_TRIVIAL_ABI +# define _LIBCPP_MOVE_ONLY_FUNCTION_TRIVIAL_ABI [[_Clang::__trivial_abi__]] +#else +# define _LIBCPP_MOVE_ONLY_FUNCTION_TRIVIAL_ABI +#endif + +template +class _LIBCPP_MOVE_ONLY_FUNCTION_TRIVIAL_ABI move_only_function<_ReturnT( + _ArgTypes...) _LIBCPP_MOVE_ONLY_FUNCTION_CV_REF noexcept(_LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT)> { + using _Store = __move_only_function_storage; + + template + struct __function_wrappers_impl { + __function_wrappers_impl() = delete; + __function_wrappers_impl(const __function_wrappers_impl&) = delete; + __function_wrappers_impl(__function_wrappers_impl&&) = delete; + + _LIBCPP_HIDE_FROM_ABI static void __destroy(void* __store) noexcept { + std::destroy_at(static_cast<_Functor*>(__store)); + } + + _LIBCPP_HIDE_FROM_ABI static _ReturnT + __call(void* __functor, _ArgTypes&&... __args) noexcept(_LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT) { + return std::invoke(static_cast<_Functor _LIBCPP_MOVE_ONLY_FUNCTION_INV_QUALS>(*static_cast<_Functor*>(__functor)), + std::forward<_ArgTypes>(__args)...); + } + }; + + template + using __function_wrappers = __function_wrappers_impl>; + + template + consteval static bool __is_callable_from_impl() { + if (_LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT) { + return is_nothrow_invocable_r_v< _ReturnT, _VT _LIBCPP_MOVE_ONLY_FUNCTION_CV_REF, _ArgTypes...> && + is_nothrow_invocable_r_v<_ReturnT, _VT _LIBCPP_MOVE_ONLY_FUNCTION_INV_QUALS, _ArgTypes...>; + } else { + return is_invocable_r_v<_ReturnT, _VT _LIBCPP_MOVE_ONLY_FUNCTION_CV_REF, _ArgTypes...> && + is_invocable_r_v<_ReturnT, _VT _LIBCPP_MOVE_ONLY_FUNCTION_INV_QUALS, _ArgTypes...>; + } + return false; + } + + template + static constexpr bool __is_callable_from = __is_callable_from_impl>(); + + template + _LIBCPP_HIDE_FROM_ABI void __construct(_Args&&... __args) { + static_assert(is_constructible_v, _Func>); + + using _FuncWraps = __function_wrappers<_Func>; + using _UnRefFunc = remove_reference_t<_Func>; + + if constexpr (_Store::__fits_in_trivially_destructible_buffer<_Func>) { + auto& __data = __storage_.__trivially_destructible_; + __data.__call_ = std::bit_cast(&_FuncWraps::__call); + std::construct_at(reinterpret_cast<_UnRefFunc*>(__data.__data_), std::forward<_Args>(__args)...); + __data.__status_ = _Store::_Status::_TriviallyDestructible; + } else if constexpr (_Store::__fits_in_trivially_relocatable_buffer<_Func>) { + auto& __data = __storage_.__trivially_relocatable_; + __data.__call_ = std::bit_cast(&_FuncWraps::__call); + __data.__destroy_ = &_FuncWraps::__destroy; + std::construct_at(reinterpret_cast<_UnRefFunc*>(__data.__data_), std::forward<_Args>(__args)...); + __data.__status_ = _Store::_Status::_TriviallyRelocatable; + } else { + auto& __data = __storage_.__large_; + __data.__call_ = std::bit_cast(&_FuncWraps::__call); + __data.__destroy_ = &_FuncWraps::__destroy; + __data.__heap_ = static_cast(::operator new(sizeof(_Func), std::align_val_t(alignof(_Func)))); + std::construct_at(reinterpret_cast<_UnRefFunc*>(__data.__heap_), std::forward<_Args>(__args)...); + __data.__status_ = _Store::_Status::_Heap; + } + } + + _LIBCPP_HIDE_FROM_ABI void __reset() { + using enum _Store::_Status; + switch (__storage_.__large_.__status_) { + case _NotEngaged: + case _TriviallyDestructible: + break; + + case _TriviallyRelocatable: + __storage_.__trivially_relocatable_.__destroy_(&__storage_.__trivially_relocatable_.__data_); + break; + case _Heap: + __storage_.__large_.__destroy_(__storage_.__large_.__heap_); + ::operator delete(__storage_.__large_.__heap_); + break; + } + __storage_.__large_.__status_ = _NotEngaged; + } + +public: + using result_type = _ReturnT; + + // [func.wrap.move.ctor] + move_only_function() noexcept = default; + _LIBCPP_HIDE_FROM_ABI move_only_function(nullptr_t) noexcept : __storage_({}) {} + _LIBCPP_HIDE_FROM_ABI move_only_function(move_only_function&& __other) noexcept : __storage_(__other.__storage_) { + __other.__storage_ = {}; + } + + template + requires(!is_same_v, move_only_function> && !__is_inplace_type<_Func>::value && + __is_callable_from<_Func>) + _LIBCPP_HIDE_FROM_ABI move_only_function(_Func&& __func) noexcept { + using _FuncWraps = __function_wrappers<_Func>; + using _UnRefFunc = remove_reference_t<_Func>; + + if constexpr ((is_pointer_v<_UnRefFunc> && is_function_v>) || + is_member_function_pointer_v<_UnRefFunc>) { + if (__func == nullptr) { + __storage_ = {}; + return; + } else { + auto& __data = __storage_.__trivially_destructible_; + __data.__call_ = std::bit_cast(&_FuncWraps::__call); + std::construct_at(reinterpret_cast<_UnRefFunc*>(__data.__data_), std::forward<_Func>(__func)); + __data.__status_ = _Store::_Status::_TriviallyDestructible; + } + } else if constexpr (__is_move_only_function>::value) { + if (!__func) { + __storage_ = {}; + } else { + auto& __data = __storage_.__large_; + __data.__call_ = std::bit_cast(&_FuncWraps::__call); + __data.__destroy_ = &_FuncWraps::__destroy; + __data.__heap_ = static_cast(::operator new(sizeof(_Func), std::align_val_t(alignof(_Func)))); + std::construct_at(reinterpret_cast<_UnRefFunc*>(__data.__heap_), std::forward<_Func>(__func)); + __data.__status_ = _Store::_Status::_Heap; + } + } else { + __construct<_Func>(std::forward<_Func>(__func)); + } + } + + _LIBCPP_HIDE_FROM_ABI _Store::_Status __get_status() noexcept { return __storage_.__large_.__status_; } + + template + requires is_constructible_v, _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, _Func>); + __construct<_Func>(std::forward<_Args>(__args)...); + } + + template + requires is_constructible_v, 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) { + __construct<_Func>(__il, std::forward<_Args>(__args)...); + } + + // TODO: Do we want to make this `noexcept` as an extensions? + _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; + } + + // TODO: Do we want to make this `noexcept` as an extensions? + template + _LIBCPP_HIDE_FROM_ABI move_only_function& operator=(_Func&& __func) noexcept { + move_only_function(std::forward<_Func>(__func)).swap(*this); + } + + _LIBCPP_HIDE_FROM_ABI ~move_only_function() { __reset(); } + + // [func.wrap.move.inv] + _LIBCPP_HIDE_FROM_ABI explicit operator bool() const noexcept { + return __storage_.__large_.__status_ != _Store::_Status::_NotEngaged; + } + + _LIBCPP_HIDE_FROM_ABI _ReturnT operator()(_ArgTypes... __args) _LIBCPP_MOVE_ONLY_FUNCTION_CV_REF + noexcept(_LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT) { + auto __call = [&](auto&& __callable, auto&& __data) { + return std::bit_cast(__callable)( + __data, std::forward<_ArgTypes>(__args)...); + }; + + using enum _Store::_Status; + switch (__storage_.__large_.__status_) { + case _NotEngaged: + _LIBCPP_ASSERT(false, "Tried to call move_only_function which doesn't hold a callable object"); + case _TriviallyDestructible: + return __call(__storage_.__trivially_destructible_.__call_, &__storage_.__trivially_destructible_.__data_); + case _TriviallyRelocatable: + return __call(__storage_.__trivially_relocatable_.__call_, &__storage_.__trivially_relocatable_.__data_); + case _Heap: + return __call(__storage_.__large_.__call_, &__storage_.__large_.__heap_); + } + } + + // [func.wrap.move.util] + _LIBCPP_HIDE_FROM_ABI void swap(move_only_function& __other) noexcept { std::swap(__storage_, __other.__storage_); } + + _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: + _Store __storage_ = {}; +}; + +template +struct __libcpp_is_trivially_relocatable> : true_type {}; + +#undef _LIBCPP_MOVE_ONLY_FUNCTION_CV +#undef _LIBCPP_MOVE_ONLY_FUNCTION_REF +#undef _LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT +#undef _LIBCPP_MOVE_ONLY_FUNCTION_INV_QUALS +#undef _LIBCPP_MOVE_ONLY_FUNCTION_CV_REF + +_LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__type_traits/is_trivially_relocatable.h b/libcxx/include/__type_traits/is_trivially_relocatable.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__type_traits/is_trivially_relocatable.h @@ -0,0 +1,51 @@ +//===----------------------------------------------------------------------===// +// +// 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___TYPE_TRAITS_IS_TRIVIALLY_RELOCATABLE_H +#define _LIBCPP___TYPE_TRAITS_IS_TRIVIALLY_RELOCATABLE_H + +#include <__config> +#include <__type_traits/is_trivially_destructible.h> +#include <__type_traits/is_trivially_move_constructible.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +//------------------------------------------------------WARNING-------------------------------------------------------// +// +// This type trait should only be used where ABI stability isn't relevant or can be assured by other means, +// like in function bodies or where the difference can be detected at runtime. If this trait is used in ABI-sensitive +// environments it has to be ensured that Clang and GCC can interpret the data produced by each other. If you are not +// certain that this is the case DO NOT USE THIS TYPE TRAIT +// +//--------------------------------------------------------------------------------------------------------------------// + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if __has_builtin(__is_trivially_relocatable) + +template +struct __libcpp_is_trivially_relocatable : integral_constant {}; + +#else + +template +using __libcpp_is_trivially_relocatable = + integral_constant::value && is_trivially_destructible_v<_Type>::value>; + +#endif // __has_builtin(__is_trivially_relocatable) + +#if _LIBCPP_STD_VER > 14 +template +constexpr bool __libcpp_is_trivially_relocatable_v = __libcpp_is_trivially_relocatable<_Type>::value; +#endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___TYPE_TRAITS_IS_TRIVIALLY_RELOCATABLE_H diff --git a/libcxx/include/functional b/libcxx/include/functional --- a/libcxx/include/functional +++ b/libcxx/include/functional @@ -521,6 +521,7 @@ #include <__functional/invoke.h> #include <__functional/mem_fn.h> // TODO: deprecate #include <__functional/mem_fun_ref.h> +#include <__functional/move_only_function.h> #include <__functional/not_fn.h> #include <__functional/operations.h> #include <__functional/pointer_to_binary_function.h> 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/assignment/move.pass.cpp @@ -0,0 +1,124 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +#include "test_macros.h" +#include "../common.h" + +template +void test() { + { + std::move_only_function f = &call_func; + std::move_only_function f2; + f2 = std::move(f); + assert(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + decltype(&call_func) ptr = nullptr; + std::move_only_function f = ptr; + std::move_only_function f2; + f2 = std::move(f); + assert(!f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + } + { + std::move_only_function f = TriviallyDestructible{}; + std::move_only_function f2; + f2 = std::move(f); + assert(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + std::move_only_function f = TriviallyDestructibleSqueezeFit{}; + std::move_only_function f2; + f2 = std::move(f); + assert(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + std::move_only_function f = TriviallyDestructibleTooLarge{}; + std::move_only_function f2; + f2 = std::move(f); + assert(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_Heap); + } +#ifdef TEST_COMPILER_CLANG + { + std::move_only_function f = TriviallyRelocatable{}; + std::move_only_function f2; + f2 = std::move(f); + assert(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_TriviallyRelocatable); + } + { + std::move_only_function f = TriviallyRelocatableSqueezeFit{}; + std::move_only_function f2; + f2 = std::move(f); + assert(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_TriviallyRelocatable); + } + { + std::move_only_function f = TriviallyRelocatableTooLarge{}; + std::move_only_function f2; + f2 = std::move(f); + assert(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_Heap); + } +#endif + { + std::move_only_function f = NonTrivial{}; + std::move_only_function f2; + f2 = std::move(f); + assert(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_Heap); + } +} + +struct S { + void func() noexcept {} +}; + +template +void test_member_function_pointer() { + { + std::move_only_function f = &S::func; + std::move_only_function f2; + f2 = std::move(f); + assert(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + std::move_only_function f2; + f2 = std::move(f); + assert(!f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + } +} + +int main(int, char**) { + call_test([] { test(); }); + call_test([] { test_member_function_pointer(); }); +} 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/assignment/nullptr.pass.cpp @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +#include "test_macros.h" +#include "../common.h" + +template +void test() { + { + std::move_only_function f = &call_func; + f = nullptr; + assert(!f); + } + { + decltype(&call_func) ptr = nullptr; + std::move_only_function f = ptr; + f = nullptr; + assert(!f); + } + { + std::move_only_function f = TriviallyDestructible{}; + f = nullptr; + assert(!f); + } + { + std::move_only_function f = TriviallyDestructibleSqueezeFit{}; + f = nullptr; + assert(!f); + } + { + std::move_only_function f = TriviallyDestructibleTooLarge{}; + f = nullptr; + assert(!f); + } +#ifdef TEST_COMPILER_CLANG + { + std::move_only_function f = TriviallyRelocatable{}; + f = nullptr; + assert(!f); + } + { + std::move_only_function f = TriviallyRelocatableSqueezeFit{}; + f = nullptr; + assert(!f); + } + { + std::move_only_function f = TriviallyRelocatableTooLarge{}; + f = nullptr; + assert(!f); + } +#endif + { + std::move_only_function f = NonTrivial{}; + f = nullptr; + assert(!f); + } +} + +struct S { + void func() noexcept {} +}; + +template +void test_member_function_pointer() { + { + std::move_only_function f = &S::func; + f = nullptr; + assert(!f); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + f = nullptr; + assert(!f); + } +} + +int main(int, char**) { + call_test([] { test(); }); + call_test([] { test_member_function_pointer(); }); +} 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/lvalue.pass.cpp @@ -0,0 +1,102 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +#include "test_macros.h" +#include "../common.h" + +struct S { + void func() & {} +}; + +static_assert(std::is_invocable_v&>); +static_assert(!std::is_invocable_v>); +static_assert(!std::is_invocable_v&&>); +static_assert(!std::is_invocable_v const&>); +static_assert(!std::is_invocable_v const >); +static_assert(!std::is_invocable_v const&&>); + +void test() { + { + called = false; + std::move_only_function f = &call_func; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructible{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleSqueezeFit{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleTooLarge{}; + f(); + assert(called); + } +#ifdef TEST_COMPILER_CLANG + { + called = false; + std::move_only_function f = TriviallyRelocatable{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyRelocatableSqueezeFit{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyRelocatableTooLarge{}; + f(); + assert(called); + } +#endif + { + called = false; + std::move_only_function f = NonTrivial{}; + f(); + assert(called); + } + { + std::move_only_function f = &S::func; + assert(f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + } + { + CallType type; + std::move_only_function f = CallTypeChecker{&type}; + f(); + assert(type == CallType::LValue); + } +} + +int main(int, char**) { + test(); + + 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/lvalue_const.pass.cpp @@ -0,0 +1,118 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include +#include + +#include "test_macros.h" +#include "../common.h" + +struct S { + void func() const& {} +}; + +static_assert(std::is_invocable_v&>); +static_assert(std::is_invocable_v>); +static_assert(std::is_invocable_v&&>); +static_assert(std::is_invocable_v const&>); +static_assert(std::is_invocable_v const >); +static_assert(std::is_invocable_v const&&>); + +void test() { + { + called = false; + std::move_only_function f = &call_func; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructible{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleSqueezeFit{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleTooLarge{}; + f(); + assert(called); + } +#ifdef TEST_COMPILER_CLANG + { + called = false; + std::move_only_function f = TriviallyRelocatable{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyRelocatableSqueezeFit{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyRelocatableTooLarge{}; + f(); + assert(called); + } +#endif + { + called = false; + std::move_only_function f = NonTrivial{}; + f(); + assert(called); + } + { + std::move_only_function f = &S::func; + assert(f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + } + { + CallType type; + std::move_only_function f = CallTypeChecker{&type}; + f(); + assert(type == CallType::ConstLValue); + } + { + CallType type; + std::move_only_function 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); + } +} + +int main(int, char**) { + test(); + + 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/lvalue_const_noexcept.pass.cpp @@ -0,0 +1,112 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include +#include + +#include "test_macros.h" +#include "../common.h" + +struct S { + void func() const& noexcept {} +}; + +static_assert(std::is_invocable_v&>); +static_assert(std::is_invocable_v>); +static_assert(std::is_invocable_v&&>); +static_assert(std::is_invocable_v const&>); +static_assert(std::is_invocable_v const >); +static_assert(std::is_invocable_v const&&>); + +void test() { + { + called = false; + std::move_only_function f = &call_func; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructible{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleSqueezeFit{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleTooLarge{}; + f(); + assert(called); + } +#ifdef TEST_COMPILER_CLANG + { + called = false; + std::move_only_function f = TriviallyRelocatable{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyRelocatableSqueezeFit{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyRelocatableTooLarge{}; + f(); + assert(called); + } +#endif + { + called = false; + std::move_only_function f = NonTrivial{}; + f(); + assert(called); + } + { + std::move_only_function f = &S::func; + assert(f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + } + { + CallType type; + std::move_only_function 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); + } +} + +int main(int, char**) { + test(); + + 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/lvalue_noexcept.pass.cpp @@ -0,0 +1,102 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +#include "test_macros.h" +#include "../common.h" + +struct S { + void func() & noexcept {} +}; + +static_assert(std::is_invocable_v&>); +static_assert(!std::is_invocable_v>); +static_assert(!std::is_invocable_v&&>); +static_assert(!std::is_invocable_v const&>); +static_assert(!std::is_invocable_v const >); +static_assert(!std::is_invocable_v const&&>); + +void test() { + { + called = false; + std::move_only_function f = &call_func; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructible{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleSqueezeFit{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleTooLarge{}; + f(); + assert(called); + } +#ifdef TEST_COMPILER_CLANG + { + called = false; + std::move_only_function f = TriviallyRelocatable{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyRelocatableSqueezeFit{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyRelocatableTooLarge{}; + f(); + assert(called); + } +#endif + { + called = false; + std::move_only_function f = NonTrivial{}; + f(); + assert(called); + } + { + std::move_only_function f = &S::func; + assert(f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + } + { + CallType type; + std::move_only_function f = CallTypeCheckerNoexcept{&type}; + f(); + assert(type == CallType::LValue); + } +} + +int main(int, char**) { + test(); + + 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/normal.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 + +#include +#include +#include + +#include "test_macros.h" +#include "../common.h" + +struct S { + void func() {} +}; + +static_assert(std::is_invocable_v&>); +static_assert(std::is_invocable_v>); +static_assert(std::is_invocable_v&&>); +static_assert(!std::is_invocable_v const&>); +static_assert(!std::is_invocable_v const >); +static_assert(!std::is_invocable_v const&&>); + +void test() { + { + called = false; + std::move_only_function f = &call_func; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructible{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleSqueezeFit{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleTooLarge{}; + f(); + assert(called); + } +#ifdef TEST_COMPILER_CLANG + { + called = false; + std::move_only_function f = TriviallyRelocatable{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyRelocatableSqueezeFit{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyRelocatableTooLarge{}; + f(); + assert(called); + } +#endif + { + called = false; + std::move_only_function f = NonTrivial{}; + f(); + assert(called); + } + { + std::move_only_function f = &S::func; + assert(f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + } + { + CallType type; + std::move_only_function f = CallTypeChecker{&type}; + f(); + assert(type == CallType::LValue); + type = CallType::None; + std::move(f)(); + assert(type == CallType::LValue); + } +} + +int main(int, char**) { + test(); + + 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/normal_const.pass.cpp @@ -0,0 +1,112 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include +#include + +#include "test_macros.h" +#include "../common.h" + +struct S { + void func() const noexcept {} +}; + +static_assert(std::is_invocable_v&>); +static_assert(std::is_invocable_v>); +static_assert(std::is_invocable_v&&>); +static_assert(std::is_invocable_v const&>); +static_assert(std::is_invocable_v const >); +static_assert(std::is_invocable_v const&&>); + +void test() { + { + called = false; + std::move_only_function f = &call_func; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructible{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleSqueezeFit{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleTooLarge{}; + f(); + assert(called); + } +#ifdef TEST_COMPILER_CLANG + { + called = false; + std::move_only_function f = TriviallyRelocatable{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyRelocatableSqueezeFit{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyRelocatableTooLarge{}; + f(); + assert(called); + } +#endif + { + called = false; + std::move_only_function f = NonTrivial{}; + f(); + assert(called); + } + { + std::move_only_function f = &S::func; + assert(f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + } + { + CallType type; + std::move_only_function 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); + } +} + +int main(int, char**) { + test(); + + 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/normal_const_noexcept.pass.cpp @@ -0,0 +1,112 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include +#include + +#include "test_macros.h" +#include "../common.h" + +struct S { + void func() const noexcept {} +}; + +static_assert(std::is_invocable_v&>); +static_assert(std::is_invocable_v>); +static_assert(std::is_invocable_v&&>); +static_assert(std::is_invocable_v const&>); +static_assert(std::is_invocable_v const >); +static_assert(std::is_invocable_v const&&>); + +void test() { + { + called = false; + std::move_only_function f = &call_func; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructible{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleSqueezeFit{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleTooLarge{}; + f(); + assert(called); + } +#ifdef TEST_COMPILER_CLANG + { + called = false; + std::move_only_function f = TriviallyRelocatable{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyRelocatableSqueezeFit{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyRelocatableTooLarge{}; + f(); + assert(called); + } +#endif + { + called = false; + std::move_only_function f = NonTrivial{}; + f(); + assert(called); + } + { + std::move_only_function f = &S::func; + assert(f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + } + { + CallType type; + std::move_only_function 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); + } +} + +int main(int, char**) { + test(); + + 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/normal_noexcept.pass.cpp @@ -0,0 +1,105 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +#include "test_macros.h" +#include "../common.h" + +struct S { + void func() noexcept {} +}; + +static_assert(std::is_invocable_v&>); +static_assert(std::is_invocable_v>); +static_assert(std::is_invocable_v&&>); +static_assert(!std::is_invocable_v const&>); +static_assert(!std::is_invocable_v const >); +static_assert(!std::is_invocable_v const&&>); + +void test() { + { + called = false; + std::move_only_function f = &call_func; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructible{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleSqueezeFit{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleTooLarge{}; + f(); + assert(called); + } +#ifdef TEST_COMPILER_CLANG + { + called = false; + std::move_only_function f = TriviallyRelocatable{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyRelocatableSqueezeFit{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyRelocatableTooLarge{}; + f(); + assert(called); + } +#endif + { + called = false; + std::move_only_function f = NonTrivial{}; + f(); + assert(called); + } + { + std::move_only_function f = &S::func; + assert(f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + } + { + CallType type; + std::move_only_function f = CallTypeCheckerNoexcept{&type}; + f(); + assert(type == CallType::LValue); + type = CallType::None; + std::move(f)(); + assert(type == CallType::LValue); + } +} + +int main(int, char**) { + test(); + + 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/rvalue.pass.cpp @@ -0,0 +1,103 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +#include "test_macros.h" +#include "../common.h" + +struct S { + void func() && noexcept {} +}; + +static_assert(!std::is_invocable_v&>); +static_assert(std::is_invocable_v>); +static_assert(std::is_invocable_v&&>); +static_assert(!std::is_invocable_v const&>); +static_assert(!std::is_invocable_v const >); +static_assert(!std::is_invocable_v const&&>); + +void test() { + { + called = false; + std::move_only_function f = &call_func; + std::move(f)(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructible{}; + std::move(f)(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleSqueezeFit{}; + std::move(f)(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleTooLarge{}; + std::move(f)(); + assert(called); + } +#ifdef TEST_COMPILER_CLANG + { + called = false; + std::move_only_function f = TriviallyRelocatable{}; + std::move(f)(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyRelocatableSqueezeFit{}; + std::move(f)(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyRelocatableTooLarge{}; + std::move(f)(); + assert(called); + } +#endif + { + called = false; + std::move_only_function f = NonTrivial{}; + std::move(f)(); + assert(called); + } + { + std::move_only_function f = &S::func; + assert(f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + } + { + CallType type; + std::move_only_function f = CallTypeChecker{&type}; + type = CallType::None; + std::move(f)(); + assert(type == CallType::RValue); + } +} + +int main(int, char**) { + test(); + + 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/rvalue_const.pass.cpp @@ -0,0 +1,107 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include +#include + +#include "test_macros.h" +#include "../common.h" + +struct S { + void func() const&& noexcept {} +}; + +static_assert(!std::is_invocable_v&>); +static_assert(std::is_invocable_v>); +static_assert(std::is_invocable_v&&>); +static_assert(!std::is_invocable_v const&>); +static_assert(std::is_invocable_v const >); +static_assert(std::is_invocable_v const&&>); + +void test() { + { + called = false; + std::move_only_function f = &call_func; + std::move(f)(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructible{}; + std::move(f)(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleSqueezeFit{}; + std::move(f)(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleTooLarge{}; + std::move(f)(); + assert(called); + } +#ifdef TEST_COMPILER_CLANG + { + called = false; + std::move_only_function f = TriviallyRelocatable{}; + std::move(f)(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyRelocatableSqueezeFit{}; + std::move(f)(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyRelocatableTooLarge{}; + std::move(f)(); + assert(called); + } +#endif + { + called = false; + std::move_only_function f = NonTrivial{}; + std::move(f)(); + assert(called); + } + { + std::move_only_function f = &S::func; + assert(f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + } + { + CallType type; + std::move_only_function 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); + } +} + +int main(int, char**) { + test(); + + 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/rvalue_const_noexcept.pass.cpp @@ -0,0 +1,107 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include +#include + +#include "test_macros.h" +#include "../common.h" + +struct S { + void func() const&& noexcept {} +}; + +static_assert(!std::is_invocable_v&>); +static_assert(std::is_invocable_v>); +static_assert(std::is_invocable_v&&>); +static_assert(!std::is_invocable_v const&>); +static_assert(std::is_invocable_v const >); +static_assert(std::is_invocable_v const&&>); + +void test() { + { + called = false; + std::move_only_function f = &call_func; + std::move(f)(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructible{}; + std::move(f)(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleSqueezeFit{}; + std::move(f)(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleTooLarge{}; + std::move(f)(); + assert(called); + } +#ifdef TEST_COMPILER_CLANG + { + called = false; + std::move_only_function f = TriviallyRelocatable{}; + std::move(f)(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyRelocatableSqueezeFit{}; + std::move(f)(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyRelocatableTooLarge{}; + std::move(f)(); + assert(called); + } +#endif + { + called = false; + std::move_only_function f = NonTrivial{}; + std::move(f)(); + assert(called); + } + { + std::move_only_function f = &S::func; + assert(f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + } + { + CallType type; + std::move_only_function 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); + } +} + +int main(int, char**) { + test(); + + 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/rvalue_noexcept.pass.cpp @@ -0,0 +1,104 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include +#include + +#include "test_macros.h" +#include "../common.h" + +struct S { + void func() && noexcept {} +}; + +static_assert(!std::is_invocable_v&>); +static_assert(std::is_invocable_v>); +static_assert(std::is_invocable_v&&>); +static_assert(!std::is_invocable_v const&>); +static_assert(!std::is_invocable_v const >); +static_assert(!std::is_invocable_v const&&>); + +void test() { + { + called = false; + std::move_only_function f = &call_func; + std::move(f)(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructible{}; + std::move(f)(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleSqueezeFit{}; + std::move(f)(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleTooLarge{}; + std::move(f)(); + assert(called); + } +#ifdef TEST_COMPILER_CLANG + { + called = false; + std::move_only_function f = TriviallyRelocatable{}; + std::move(f)(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyRelocatableSqueezeFit{}; + std::move(f)(); + assert(called); + } + { + called = false; + std::move_only_function f = TriviallyRelocatableTooLarge{}; + std::move(f)(); + assert(called); + } +#endif + { + called = false; + std::move_only_function f = NonTrivial{}; + std::move(f)(); + assert(called); + } + { + std::move_only_function f = &S::func; + assert(f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + } + { + CallType type; + std::move_only_function f = CallTypeCheckerNoexcept{&type}; + type = CallType::None; + std::move(f)(); + assert(type == CallType::RValue); + } +} + +int main(int, char**) { + test(); + + 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/common.h @@ -0,0 +1,151 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include "test_macros.h" + +inline bool called; +inline void call_func() noexcept { called = true; } + +template +struct call_test_impl; + +template +struct call_test_impl { + call_test_impl(Functor func) { + func.template operator()(); + func.template operator()(); + func.template operator()(); + func.template operator()(); + func.template operator()(); + func.template operator()(); + func.template operator()(); + func.template operator()(); + func.template operator()(); + func.template operator()(); + func.template operator()(); + func.template operator()(); + } +}; + +template +void call_test(Functor f) { + call_test_impl{f}; +} + +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, MoveCounter) {} + void operator()() const noexcept { called = true; } +}; + +struct TriviallyDestructibleSqueezeFit { + TriviallyDestructibleSqueezeFit() = default; + TriviallyDestructibleSqueezeFit(MoveCounter) {} + TriviallyDestructibleSqueezeFit(std::initializer_list, MoveCounter) {} + void operator()() const noexcept { called = true; } + +private: + [[maybe_unused]] void* ptr; + [[maybe_unused]] char a[4 * sizeof(void*) - 1]; +}; + +struct TriviallyDestructibleTooLarge { + TriviallyDestructibleTooLarge() = default; + TriviallyDestructibleTooLarge(MoveCounter) {} + TriviallyDestructibleTooLarge(std::initializer_list, MoveCounter) {} + void operator()() const noexcept { called = true; } + char a[5 * sizeof(void*)]; +}; + +#ifdef TEST_COMPILER_CLANG +struct [[clang::trivial_abi]] TriviallyRelocatable { + TriviallyRelocatable() = default; + TriviallyRelocatable(MoveCounter) {} + TriviallyRelocatable(std::initializer_list, MoveCounter) {} + TriviallyRelocatable(TriviallyRelocatable&&) {} + ~TriviallyRelocatable() {} + + void operator()() const noexcept { called = true; } +}; + +struct [[clang::trivial_abi]] TriviallyRelocatableSqueezeFit { + TriviallyRelocatableSqueezeFit() = default; + TriviallyRelocatableSqueezeFit(MoveCounter) {} + TriviallyRelocatableSqueezeFit(std::initializer_list, MoveCounter) {} + TriviallyRelocatableSqueezeFit(TriviallyRelocatableSqueezeFit&&) {} + ~TriviallyRelocatableSqueezeFit() {} + + void operator()() const noexcept { called = true; } + +private: + [[maybe_unused]] void* ptr; + [[maybe_unused]] char a[3 * sizeof(void*) - 1]; +}; + +struct [[clang::trivial_abi]] TriviallyRelocatableTooLarge { + TriviallyRelocatableTooLarge() = default; + TriviallyRelocatableTooLarge(MoveCounter) {} + TriviallyRelocatableTooLarge(std::initializer_list, MoveCounter) {} + ~TriviallyRelocatableTooLarge() {} + + void operator()() const noexcept { called = true; } + +private: + [[maybe_unused]] char a[4 * sizeof(void*)]; +}; +#endif + +struct NonTrivial { + NonTrivial() = default; + NonTrivial(MoveCounter) {} + NonTrivial(std::initializer_list, MoveCounter) {} + NonTrivial(NonTrivial&&) {} + ~NonTrivial() {} + + void operator()() const noexcept { called = true; } +}; + +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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/default.pass.cpp @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +#include "../common.h" + +template +void test() { + std::move_only_function f; + assert(!f); +} + +int main(int, char**) { + call_test([] { test(); }); +} 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/functor.pass.cpp @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +#include "test_macros.h" +#include "../common.h" + +template +void test() { + { + std::move_only_function f = &call_func; + assert(f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + decltype(&call_func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + } + { + std::move_only_function f = TriviallyDestructible{}; + assert(f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + std::move_only_function f = TriviallyDestructibleSqueezeFit{}; + assert(f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + std::move_only_function f = TriviallyDestructibleTooLarge{}; + assert(f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_Heap); + } +#ifdef TEST_COMPILER_CLANG + { + std::move_only_function f = TriviallyRelocatable{}; + assert(f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_TriviallyRelocatable); + } + { + std::move_only_function f = TriviallyRelocatableSqueezeFit{}; + assert(f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_TriviallyRelocatable); + } + { + std::move_only_function f = TriviallyRelocatableTooLarge{}; + assert(f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_Heap); + } +#endif + { + std::move_only_function f = NonTrivial{}; + assert(f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_Heap); + } +} + +struct S { + void func() noexcept {} +}; + +template +void test_member_function_pointer() { + { + std::move_only_function f = &S::func; + assert(f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + } +} + +int main(int, char**) { + call_test([] { test(); }); + call_test([] { test_member_function_pointer(); }); +} 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/in_place.pass.cpp @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +#include "test_macros.h" +#include "../common.h" + +template +void test() { + { + int counter = 0; + std::move_only_function f{std::in_place_type, MoveCounter{&counter}}; + assert(f); + assert(counter == 1); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + int counter = 0; + std::move_only_function f{std::in_place_type, MoveCounter{&counter}}; + assert(f); + assert(counter == 1); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + int counter = 0; + std::move_only_function f{std::in_place_type, MoveCounter{&counter}}; + assert(f); + assert(counter == 1); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_Heap); + } +#ifdef TEST_COMPILER_CLANG + { + int counter = 0; + std::move_only_function f{std::in_place_type, MoveCounter{&counter}}; + assert(f); + assert(counter == 1); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_TriviallyRelocatable); + } + { + int counter = 0; + std::move_only_function f{std::in_place_type, MoveCounter{&counter}}; + assert(f); + assert(counter == 1); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_TriviallyRelocatable); + } + { + int counter = 0; + std::move_only_function f{std::in_place_type, MoveCounter{&counter}}; + assert(f); + assert(counter == 1); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_Heap); + } +#endif + { + int counter = 0; + std::move_only_function f{std::in_place_type, MoveCounter{&counter}}; + assert(f); + assert(counter == 1); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_Heap); + } +} + +int main(int, char**) { + call_test([] { test(); }); +} 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/in_place_init_list.pass.cpp @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +#include "test_macros.h" +#include "../common.h" + +template +void test() { + { + int counter = 0; + std::move_only_function f{std::in_place_type, {1}, MoveCounter{&counter}}; + assert(f); + assert(counter == 1); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + int counter = 0; + std::move_only_function f{std::in_place_type, {1}, MoveCounter{&counter}}; + assert(f); + assert(counter == 1); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + int counter = 0; + std::move_only_function f{std::in_place_type, {1}, MoveCounter{&counter}}; + assert(f); + assert(counter == 1); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_Heap); + } +#ifdef TEST_COMPILER_CLANG + { + int counter = 0; + std::move_only_function f{std::in_place_type, {1}, MoveCounter{&counter}}; + assert(f); + assert(counter == 1); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_TriviallyRelocatable); + } + { + int counter = 0; + std::move_only_function f{std::in_place_type, {1}, MoveCounter{&counter}}; + assert(f); + assert(counter == 1); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_TriviallyRelocatable); + } + { + int counter = 0; + std::move_only_function f{std::in_place_type, {1}, MoveCounter{&counter}}; + assert(f); + assert(counter == 1); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_Heap); + } +#endif + { + int counter = 0; + std::move_only_function f{std::in_place_type, {1}, MoveCounter{&counter}}; + assert(f); + assert(counter == 1); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_Heap); + } +} + +int main(int, char**) { + call_test([] { test(); }); +} 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/move.pass.cpp @@ -0,0 +1,113 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +#include "test_macros.h" +#include "../common.h" + +template +void test() { + { + std::move_only_function f = &call_func; + std::move_only_function f2 = std::move(f); + assert(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + decltype(&call_func) ptr = nullptr; + std::move_only_function f = ptr; + std::move_only_function f2 = std::move(f); + assert(!f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + } + { + std::move_only_function f = TriviallyDestructible{}; + std::move_only_function f2 = std::move(f); + assert(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + std::move_only_function f = TriviallyDestructibleSqueezeFit{}; + std::move_only_function f2 = std::move(f); + assert(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + std::move_only_function f = TriviallyDestructibleTooLarge{}; + std::move_only_function f2 = std::move(f); + assert(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_Heap); + } +#ifdef TEST_COMPILER_CLANG + { + std::move_only_function f = TriviallyRelocatable{}; + std::move_only_function f2 = std::move(f); + assert(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_TriviallyRelocatable); + } + { + std::move_only_function f = TriviallyRelocatableSqueezeFit{}; + std::move_only_function f2 = std::move(f); + assert(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_TriviallyRelocatable); + } + { + std::move_only_function f = TriviallyRelocatableTooLarge{}; + std::move_only_function f2 = std::move(f); + assert(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_Heap); + } +#endif + { + std::move_only_function f = NonTrivial{}; + std::move_only_function f2 = std::move(f); + assert(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_Heap); + } +} + +struct S { + void func() noexcept {} +}; + +template +void test_member_function_pointer() { + { + std::move_only_function f = &S::func; + std::move_only_function f2 = std::move(f); + assert(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + std::move_only_function f2 = std::move(f); + assert(!f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + } +} + +int main(int, char**) { + call_test([] { test(); }); + call_test([] { test_member_function_pointer(); }); +} 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/nullptr.pass.cpp @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +#include "../common.h" + +template +void test() { + std::move_only_function f = nullptr; + assert(!f); +} + +int main(int, char**) { + call_test([] { test(); }); +} 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/swap.adl.pass.cpp @@ -0,0 +1,120 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +#include "test_macros.h" +#include "common.h" + +template +void test() { + { + std::move_only_function f = &call_func; + std::move_only_function f2; + swap(f, f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + decltype(&call_func) ptr = nullptr; + std::move_only_function f = ptr; + std::move_only_function f2; + swap(f, f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + } + { + std::move_only_function f = TriviallyDestructible{}; + std::move_only_function f2; + swap(f, f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + std::move_only_function f = TriviallyDestructibleSqueezeFit{}; + std::move_only_function f2; + swap(f, f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + std::move_only_function f = TriviallyDestructibleTooLarge{}; + std::move_only_function f2; + swap(f, f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_Heap); + } +#ifdef TEST_COMPILER_CLANG + { + std::move_only_function f = TriviallyRelocatable{}; + std::move_only_function f2; + swap(f, f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_TriviallyRelocatable); + } + { + std::move_only_function f = TriviallyRelocatableSqueezeFit{}; + std::move_only_function f2; + swap(f, f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_TriviallyRelocatable); + } + { + std::move_only_function f = TriviallyRelocatableTooLarge{}; + std::move_only_function f2; + swap(f, f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_Heap); + } +#endif + { + std::move_only_function f = NonTrivial{}; + std::move_only_function f2; + swap(f, f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_Heap); + } + { + std::move_only_function f = TriviallyDestructibleSqueezeFit{}; + std::move_only_function f2 = NonTrivial{}; + swap(f, f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_Heap); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } +} + +struct S { + void func() noexcept {} +}; + +template +void test_member_function_pointer() { + { + std::move_only_function f = &S::func; + std::move_only_function f2; + swap(f, f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + std::move_only_function f2; + swap(f, f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + } +} + +int main(int, char**) { + call_test([] { test(); }); + call_test([] { test_member_function_pointer(); }); +} 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/swap.member.pass.cpp @@ -0,0 +1,120 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +#include "test_macros.h" +#include "common.h" + +template +void test() { + { + std::move_only_function f = &call_func; + std::move_only_function f2; + f.swap(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + decltype(&call_func) ptr = nullptr; + std::move_only_function f = ptr; + std::move_only_function f2; + f.swap(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + } + { + std::move_only_function f = TriviallyDestructible{}; + std::move_only_function f2; + f.swap(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + std::move_only_function f = TriviallyDestructibleSqueezeFit{}; + std::move_only_function f2; + f.swap(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + std::move_only_function f = TriviallyDestructibleTooLarge{}; + std::move_only_function f2; + f.swap(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_Heap); + } +#ifdef TEST_COMPILER_CLANG + { + std::move_only_function f = TriviallyRelocatable{}; + std::move_only_function f2; + f.swap(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_TriviallyRelocatable); + } + { + std::move_only_function f = TriviallyRelocatableSqueezeFit{}; + std::move_only_function f2; + f.swap(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_TriviallyRelocatable); + } + { + std::move_only_function f = TriviallyRelocatableTooLarge{}; + std::move_only_function f2; + f.swap(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_Heap); + } +#endif + { + std::move_only_function f = NonTrivial{}; + std::move_only_function f2; + f.swap(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_Heap); + } + { + std::move_only_function f = TriviallyDestructibleSqueezeFit{}; + std::move_only_function f2 = NonTrivial{}; + f.swap(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_Heap); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } +} + +struct S { + void func() noexcept {} +}; + +template +void test_member_function_pointer() { + { + std::move_only_function f = &S::func; + std::move_only_function f2; + f.swap(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_TriviallyDestructible); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + std::move_only_function f2; + f.swap(f2); + LIBCPP_ASSERT(f.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + LIBCPP_ASSERT(f2.__get_status() == std::__move_only_function_storage::_Status::_NotEngaged); + } +} + +int main(int, char**) { + call_test([] { test(); }); + call_test([] { test_member_function_pointer(); }); +}