diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -324,7 +324,7 @@ ------------------------------------------------- ----------------- ``__cpp_lib_is_scoped_enum`` ``202011L`` ------------------------------------------------- ----------------- - ``__cpp_lib_move_only_function`` *unimplemented* + ``__cpp_lib_move_only_function`` ``202110L`` ------------------------------------------------- ----------------- ``__cpp_lib_optional`` ``202110L`` ------------------------------------------------- ----------------- diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst --- a/libcxx/docs/ReleaseNotes.rst +++ b/libcxx/docs/ReleaseNotes.rst @@ -48,6 +48,7 @@ - P0482R6 - char8_t: A type for UTF-8 characters and strings - P2438R2 - ``std::string::substr() &&`` - P0600R1 - ``nodiscard`` in the library +- P0288R9 - ``move_only_function`` Improvements and New Features ----------------------------- 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 @@ -328,6 +328,9 @@ __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 @@ -389,6 +392,7 @@ __iterator/unreachable_sentinel.h __iterator/wrap_iter.h __locale + __math/log2i.h __mbstate_t.h __memory/addressof.h __memory/align.h @@ -684,8 +688,10 @@ __utility/move.h __utility/pair.h __utility/piecewise_construct.h + __utility/pointer_int_pair.h __utility/priority_tag.h __utility/rel_ops.h + __utility/small_buffer.h __utility/swap.h __utility/to_underlying.h __utility/transaction.h diff --git a/libcxx/include/__algorithm/sort.h b/libcxx/include/__algorithm/sort.h --- a/libcxx/include/__algorithm/sort.h +++ b/libcxx/include/__algorithm/sort.h @@ -22,6 +22,7 @@ #include <__functional/operations.h> #include <__functional/ranges_operations.h> #include <__iterator/iterator_traits.h> +#include <__math/log2i.h> #include <__memory/destruct_n.h> #include <__memory/unique_ptr.h> #include <__utility/move.h> @@ -604,29 +605,10 @@ } } -template -inline _LIBCPP_HIDE_FROM_ABI _Number __log2i(_Number __n) { - if (__n == 0) - return 0; - if (sizeof(__n) <= sizeof(unsigned)) - return sizeof(unsigned) * CHAR_BIT - 1 - __libcpp_clz(static_cast(__n)); - if (sizeof(__n) <= sizeof(unsigned long)) - return sizeof(unsigned long) * CHAR_BIT - 1 - __libcpp_clz(static_cast(__n)); - if (sizeof(__n) <= sizeof(unsigned long long)) - return sizeof(unsigned long long) * CHAR_BIT - 1 - __libcpp_clz(static_cast(__n)); - - _Number __log2 = 0; - while (__n > 1) { - __log2++; - __n >>= 1; - } - return __log2; -} - template _LIBCPP_HIDDEN void __sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _WrappedComp __wrapped_comp) { typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; - difference_type __depth_limit = 2 * __log2i(__last - __first); + difference_type __depth_limit = 2 * std::__log2i(__last - __first); using _Unwrap = _UnwrapAlgPolicy<_WrappedComp>; using _AlgPolicy = typename _Unwrap::_AlgPolicy; diff --git a/libcxx/include/__config b/libcxx/include/__config --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -138,6 +138,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_SMALL_BUFFER_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 // _LIBCPP_STD_VER > 20 + +#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 --- /dev/null +++ b/libcxx/include/__functional/move_only_function_common.h @@ -0,0 +1,46 @@ +//===----------------------------------------------------------------------===// +// +// 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> +#include <__type_traits/integral_constant.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +class move_only_function; + +template +struct __is_move_only_function : false_type {}; + +template +struct __is_move_only_function> : true_type {}; + +template +struct _MoveOnlyFunctionTrivialVTable { + using _CallFunc = _ReturnT(_BufferT&, _ArgTypes...); + + _CallFunc* __call_; +}; + +template +struct _MoveOnlyFunctionNonTrivialVTable : _MoveOnlyFunctionTrivialVTable<_BufferT, _ReturnT, _ArgTypes...> { + using _DestroyFunc = void(_BufferT&) noexcept; + + _DestroyFunc* __destroy_; +}; + +_LIBCPP_END_NAMESPACE_STD + +#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 --- /dev/null +++ b/libcxx/include/__functional/move_only_function_impl.h @@ -0,0 +1,254 @@ +//===----------------------------------------------------------------------===// +// +// 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 <__config> +#include <__functional/invoke.h> +#include <__functional/move_only_function_common.h> +#include <__memory/construct_at.h> +#include <__memory/unique_ptr.h> +#include <__type_traits/is_trivially_destructible.h> +#include <__type_traits/is_trivially_move_constructible.h> +#include <__utility/exchange.h> +#include <__utility/forward.h> +#include <__utility/in_place.h> +#include <__utility/move.h> +#include <__utility/pointer_int_pair.h> +#include <__utility/small_buffer.h> +#include <__utility/swap.h> +#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_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 + +#ifndef _LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT +# define _LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT false +#endif + +#define _LIBCPP_MOVE_ONLY_FUNCTION_CVREF _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 move_only_function; + +template +class _LIBCPP_MOVE_ONLY_FUNCTION_TRIVIAL_ABI move_only_function<_ReturnT( + _ArgTypes...) _LIBCPP_MOVE_ONLY_FUNCTION_CVREF noexcept(_LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT)> { +private: + static constexpr size_t __buffer_size_ = 3 * sizeof(void*); + static constexpr size_t __buffer_alignment_ = alignof(void*); + using _BufferT = __small_buffer<__buffer_size_, __buffer_alignment_>; + + 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(_BufferT& __buffer) noexcept { + std::destroy_at(__buffer.__get<_Functor>()); + __buffer.__deallocate<_Functor>(); + } + + _LIBCPP_HIDE_FROM_ABI static _ReturnT + __call(_BufferT& __buffer, _ArgTypes... __args) noexcept(_LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT) { + // TODO: Use std::invoke_r once P2136 is implemented + return std::invoke(static_cast<_Functor _LIBCPP_MOVE_ONLY_FUNCTION_INVOKE_QUALS>(*__buffer.__get<_Functor>()), + std::forward<_ArgTypes>(__args)...); + } + }; + + using _TrivialVTable = _MoveOnlyFunctionTrivialVTable<_BufferT, _ReturnT, _ArgTypes...>; + using _NonTrivialVTable = _MoveOnlyFunctionNonTrivialVTable<_BufferT, _ReturnT, _ArgTypes...>; + + template + using __function_wrappers = __function_wrappers_impl>; + + template + static constexpr _TrivialVTable __trivial_vptr_ = {.__call_ = __function_wrappers<_Functor>::__call}; + + template + static constexpr _NonTrivialVTable __non_trivial_vptr_{ + {.__call_ = __function_wrappers<_Functor>::__call}, + __function_wrappers<_Functor>::__destroy, + }; + + template + __pointer_bool_pair __get_vptr() { + if constexpr (_BufferT::__fits_in_buffer<_Functor> && is_trivially_destructible_v<_Functor>) { + return {&__trivial_vptr_<_Functor>, false}; + } else { + return {&__non_trivial_vptr_<_Functor>, true}; + } + } + + 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_CVREF, _ArgTypes...> && + is_nothrow_invocable_r_v<_ReturnT, _VT _LIBCPP_MOVE_ONLY_FUNCTION_INVOKE_QUALS, _ArgTypes...>; + } else { + return is_invocable_r_v<_ReturnT, _VT _LIBCPP_MOVE_ONLY_FUNCTION_CVREF, _ArgTypes...> && + is_invocable_r_v<_ReturnT, _VT _LIBCPP_MOVE_ONLY_FUNCTION_INVOKE_QUALS, _ArgTypes...>; + } + } + + 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 _StoredFunc = decay_t<_Func>; + __vtable_ = __get_vptr<_StoredFunc>(); + __buffer_.__construct<_StoredFunc>(std::forward<_Args>(__args)...); + } + + _LIBCPP_HIDE_FROM_ABI void __reset() { + if (__vtable_.__get_value()) + static_cast(__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 + 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 _StoredFunc = decay_t<_Func>; + + if constexpr ((is_pointer_v<_StoredFunc> && is_function_v>) || + is_member_function_pointer_v<_StoredFunc>) { + if (__func != nullptr) { + __vtable_ = __get_vptr<_StoredFunc>(); + static_assert(_BufferT::__fits_in_buffer<_StoredFunc>); + __buffer_.__construct<_StoredFunc>(std::forward<_Func>(__func)); + } + } else if constexpr (__is_move_only_function<_StoredFunc>::value) { + if (__func) { + __vtable_ = std::exchange(__func.__vtable_, nullptr); + __buffer_ = std::move(__func.__buffer_); + } + } else { + __construct<_Func>(std::forward<_Func>(__func)); + } + } + + 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) { + static_assert(is_same_v, _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 + requires(!is_same_v, 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_ != nullptr; } + + _LIBCPP_HIDE_FROM_ABI _ReturnT operator()(_ArgTypes... __args) _LIBCPP_MOVE_ONLY_FUNCTION_CVREF + noexcept(_LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT) { + _LIBCPP_ASSERT(static_cast(*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: + __pointer_bool_pair __vtable_ = nullptr; + mutable _BufferT __buffer_; + + template + friend class move_only_function; +}; + +#undef _LIBCPP_MOVE_ONLY_FUNCTION_CV +#undef _LIBCPP_MOVE_ONLY_FUNCTION_REF +#undef _LIBCPP_MOVE_ONLY_FUNCTION_NOEXCEPT +#undef _LIBCPP_MOVE_ONLY_FUNCTION_INVOKE_QUALS +#undef _LIBCPP_MOVE_ONLY_FUNCTION_CVREF + +_LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__math/log2i.h b/libcxx/include/__math/log2i.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__math/log2i.h @@ -0,0 +1,39 @@ +//===----------------------------------------------------------------------===// +// +// 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___MATH_LOG2I_H +#define _LIBCPP___MATH_LOG2I_H + +#include <__bits> +#include <__config> +#include + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Number __log2i(_Number __n) { + if (__n == 0) + return 0; + if (sizeof(__n) <= sizeof(unsigned)) + return sizeof(unsigned) * CHAR_BIT - 1 - __libcpp_clz(static_cast(__n)); + if (sizeof(__n) <= sizeof(unsigned long)) + return sizeof(unsigned long) * CHAR_BIT - 1 - __libcpp_clz(static_cast(__n)); + if (sizeof(__n) <= sizeof(unsigned long long)) + return sizeof(unsigned long long) * CHAR_BIT - 1 - __libcpp_clz(static_cast(__n)); + + _Number __log2 = 0; + while (__n > 1) { + __log2++; + __n >>= 1; + } + return __log2; +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MATH_LOG2I_H diff --git a/libcxx/include/__utility/pointer_int_pair.h b/libcxx/include/__utility/pointer_int_pair.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__utility/pointer_int_pair.h @@ -0,0 +1,90 @@ +//===----------------------------------------------------------------------===// +// +// 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___UTILITY_POINTER_INT_PAIR_H +#define _LIBCPP___UTILITY_POINTER_INT_PAIR_H + +#include <__assert> +#include <__concepts/derived_from.h> +#include <__config> +#include <__math/log2i.h> +#include <__type_traits/is_pointer.h> +#include <__type_traits/remove_pointer.h> +#include <__utility/swap.h> +#include +#include + +#if _LIBCPP_STD_VER >= 23 + +// A __pointer_int_pair is a pair of a pointer and an integral type. The integral type is stored inside the lower bits +// of the pointer, which allows the whole pair to be as large as only the pointer. To achieve that the pointed-to type +// has to have an alignment requirement of at least the amount of bits which should be used for the integral type. + +_LIBCPP_BEGIN_NAMESPACE_STD + +template + requires is_pointer_v<_Pointer> +struct _PointerLikeTraits { + static constexpr size_t __low_bits_available = std::__log2i(alignof(remove_pointer_t<_Pointer>)); +}; + +template <> +struct _PointerLikeTraits { + static constexpr size_t __low_bits_available = 0; +}; + +template > +class __pointer_int_pair { + static_assert(__int_bit_count <= _PointerTraits::__low_bits_available, + "Not enough bits available for requested bit count"); + static constexpr size_t __extra_bits = _PointerTraits::__low_bits_available - __int_bit_count; + static constexpr uintptr_t __int_mask = static_cast(1 << _PointerTraits::__low_bits_available) - 1; + static constexpr uintptr_t __ptr_mask = ~__int_mask; + + uintptr_t __value_ = 0; + +public: + _LIBCPP_HIDE_FROM_ABI __pointer_int_pair(nullptr_t) {} + _LIBCPP_HIDE_FROM_ABI __pointer_int_pair(_Pointer __ptr_value, _IntType __int_value) + : __value_(reinterpret_cast(__ptr_value) | (__int_value << __extra_bits)) { + _LIBCPP_ASSERT((__int_value & __int_mask) == __int_value, "integer is too large!"); + _LIBCPP_ASSERT((reinterpret_cast(__ptr_value) & __ptr_mask) == reinterpret_cast(__ptr_value), + "Pointer alignment is too low!"); + } + + _LIBCPP_HIDE_FROM_ABI __pointer_int_pair& operator=(nullptr_t) { + __value_ = 0; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI _IntType __get_value() const { return (__value_ & __int_mask) >> __extra_bits; } + + _LIBCPP_HIDE_FROM_ABI _Pointer __get_ptr() const { return reinterpret_cast<_Pointer>(__value_ & __ptr_mask); } + + _LIBCPP_HIDE_FROM_ABI _Pointer operator->() const { return __get_ptr(); } + + _LIBCPP_HIDE_FROM_ABI bool operator==(nullptr_t) const { return __get_ptr() == nullptr; } + + template + requires derived_from, remove_pointer_t<_Pointer>> + _LIBCPP_HIDE_FROM_ABI explicit operator _DerivedPointer() { + return static_cast<_DerivedPointer>(__get_ptr()); + } +}; + +template +using __pointer_bool_pair = __pointer_int_pair<_Pointer, 1, bool>; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 23 + +#endif // _LIBCPP___UTILITY_POINTER_INT_PAIR_H diff --git a/libcxx/include/__utility/small_buffer.h b/libcxx/include/__utility/small_buffer.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__utility/small_buffer.h @@ -0,0 +1,98 @@ +//===----------------------------------------------------------------------===// +// +// 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___UTILITY_SMALL_BUFFER_H +#define _LIBCPP___UTILITY_SMALL_BUFFER_H + +#include <__config> +#include <__memory/construct_at.h> +#include <__utility/transaction.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +# ifdef _LIBCPP_ABI_SMALL_BUFFER_TRIVIAL_ABI +# define _LIBCPP_SMALL_BUFFER_TRIVIAL_ABI [[_Clang::__trivial_abi__]] +# else +# define _LIBCPP_SMALL_BUFFER_TRIVIAL_ABI +# endif + +template +class _LIBCPP_SMALL_BUFFER_TRIVIAL_ABI __small_buffer { + static_assert(_BufferSize > 0, "The buffer size should not be zero"); + static_assert(_BufferAlignment > 0, "The buffer alignment should not be zero"); + + template + static constexpr bool __fits_in_buffer_impl = + is_trivially_move_constructible_v<_Tp> && is_trivially_destructible_v<_Tp> && sizeof(_Tp) <= _BufferSize && + alignof(_Tp) <= _BufferAlignment; + +public: + template + static constexpr bool __fits_in_buffer = __fits_in_buffer_impl>; + + __small_buffer() = default; + __small_buffer(const __small_buffer&) = delete; + __small_buffer& operator=(const __small_buffer&) = delete; + ~__small_buffer() = default; + + // Relocates the buffer - __delete() should never be called on a moved-from __small_buffer + __small_buffer(__small_buffer&&) = default; + __small_buffer& operator=(__small_buffer&&) = default; + + template + _LIBCPP_HIDE_FROM_ABI _Stored* __get() { + if constexpr (__fits_in_buffer<_Stored>) + return reinterpret_cast<_Stored*>(__buffer_); + else + return *reinterpret_cast<_Stored**>(__buffer_); + } + + template + _LIBCPP_HIDE_FROM_ABI _Stored* __allocate() { + if constexpr (__fits_in_buffer<_Stored>) { + return reinterpret_cast<_Stored*>(__buffer_); + } else { + byte* __allocation = static_cast(::operator new[](sizeof(_Stored), align_val_t{alignof(_Stored)})); + std::construct_at(reinterpret_cast(__buffer_), __allocation); + return reinterpret_cast<_Stored*>(__allocation); + } + } + + template + _LIBCPP_HIDE_FROM_ABI void __deallocate() noexcept { + if constexpr (!__fits_in_buffer<_Stored>) + ::operator delete[](*reinterpret_cast(__buffer_), sizeof(_Stored), align_val_t{alignof(_Stored)}); + } + + template + _LIBCPP_HIDE_FROM_ABI void __construct(_Args&&... __args) { + _Stored* __buffer = __allocate<_Stored>(); + __transaction __guard([&] { __deallocate<_Stored>(); }); + std::construct_at(__buffer, std::forward<_Args>(__args)...); + __guard.__complete(); + } + +private: + alignas(_BufferAlignment) byte __buffer_[_BufferSize]; +}; + +# undef _LIBCPP_SMALL_BUFFER_TRIVIAL_ABI + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 23 + +#endif // _LIBCPP___UTILITY_SMALL_BUFFER_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/include/module.modulemap.in b/libcxx/include/module.modulemap.in --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -107,6 +107,10 @@ } } + module __math { + module log2i { private header "__math/log2i.h" } + } + // and are not C headers in any real sense, do not // allow their use in extern "C" contexts. module complex_h { @@ -1511,6 +1515,7 @@ module move { private header "__utility/move.h" } module pair { private header "__utility/pair.h" } module pair_fwd { private header "__fwd/pair.h" } + module pointer_int_pair { private header "__utility/pointer_int_pair.h" } module piecewise_construct { private header "__utility/piecewise_construct.h" } module priority_tag { private header "__utility/priority_tag.h" } module rel_ops { private header "__utility/rel_ops.h" } diff --git a/libcxx/include/version b/libcxx/include/version --- a/libcxx/include/version +++ b/libcxx/include/version @@ -393,7 +393,7 @@ # define __cpp_lib_forward_like 202207L // # define __cpp_lib_invoke_r 202106L # define __cpp_lib_is_scoped_enum 202011L -// # 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/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp --- a/libcxx/test/libcxx/private_headers.verify.cpp +++ b/libcxx/test/libcxx/private_headers.verify.cpp @@ -360,6 +360,9 @@ #include <__functional/is_transparent.h> // expected-error@*:* {{use of private header from outside its module: '__functional/is_transparent.h'}} #include <__functional/mem_fn.h> // expected-error@*:* {{use of private header from outside its module: '__functional/mem_fn.h'}} #include <__functional/mem_fun_ref.h> // expected-error@*:* {{use of private header from outside its module: '__functional/mem_fun_ref.h'}} +#include <__functional/move_only_function.h> // expected-error@*:* {{use of private header from outside its module: '__functional/move_only_function.h'}} +#include <__functional/move_only_function_common.h> // expected-error@*:* {{use of private header from outside its module: '__functional/move_only_function_common.h'}} +#include <__functional/move_only_function_impl.h> // expected-error@*:* {{use of private header from outside its module: '__functional/move_only_function_impl.h'}} #include <__functional/not_fn.h> // expected-error@*:* {{use of private header from outside its module: '__functional/not_fn.h'}} #include <__functional/operations.h> // expected-error@*:* {{use of private header from outside its module: '__functional/operations.h'}} #include <__functional/perfect_forward.h> // expected-error@*:* {{use of private header from outside its module: '__functional/perfect_forward.h'}} @@ -698,6 +701,7 @@ #include <__utility/piecewise_construct.h> // expected-error@*:* {{use of private header from outside its module: '__utility/piecewise_construct.h'}} #include <__utility/priority_tag.h> // expected-error@*:* {{use of private header from outside its module: '__utility/priority_tag.h'}} #include <__utility/rel_ops.h> // expected-error@*:* {{use of private header from outside its module: '__utility/rel_ops.h'}} +#include <__utility/small_buffer.h> // expected-error@*:* {{use of private header from outside its module: '__utility/small_buffer.h'}} #include <__utility/swap.h> // expected-error@*:* {{use of private header from outside its module: '__utility/swap.h'}} #include <__utility/to_underlying.h> // expected-error@*:* {{use of private header from outside its module: '__utility/to_underlying.h'}} #include <__utility/transaction.h> // expected-error@*:* {{use of private header from outside its module: '__utility/transaction.h'}} 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 --- /dev/null +++ b/libcxx/test/libcxx/utilities/function.objects/func.wrap/func.wrap.move/assert.engaged.cpp @@ -0,0 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 + +#include + +#include "check_assertion.h" + +int main(int, char**) { + std::move_only_function func; + TEST_LIBCPP_ASSERT_FAILURE(func(), "Tried to call a disengaged move_only_function"); +} diff --git a/libcxx/test/libcxx/utilities/pointer_int_pair.pass.cpp b/libcxx/test/libcxx/utilities/pointer_int_pair.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/pointer_int_pair.pass.cpp @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// 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 "test_macros.h" + +TEST_DIAGNOSTIC_PUSH +TEST_CLANG_DIAGNOSTIC_IGNORED("-Wprivate-header") +#include <__utility/pointer_int_pair.h> +TEST_DIAGNOSTIC_POP + +#include + +int main(int, char**) { + { + std::__pointer_int_pair pair; + assert(pair.__get_int() == 0); + assert(pair.__get_ptr() == nullptr); + } + { + std::__pointer_int_pair pair(nullptr, 1); + assert(pair.__get_int() == 1); + assert(pair.__get_ptr() == nullptr); + } + { + static_assert(alignof(int) <= 4); + std::__pointer_int_pair pair(reinterpret_cast(4), 0); + assert(pair.__get_int() == 0); + assert(pair.__get_ptr() == reinterpret_cast(4)); + } +} diff --git a/libcxx/test/libcxx/utilities/pointer_union.pass.cpp b/libcxx/test/libcxx/utilities/pointer_union.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/pointer_union.pass.cpp @@ -0,0 +1,9 @@ +//===----------------------------------------------------------------------===// +// +// 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 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 --- 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 @@ -338,17 +338,11 @@ # endif # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_move_only_function -# error "__cpp_lib_move_only_function should be defined in c++2b" -# endif -# if __cpp_lib_move_only_function != 202110L -# error "__cpp_lib_move_only_function should have the value 202110L in c++2b" -# endif -# else // _LIBCPP_VERSION -# 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++2b" +# endif +# if __cpp_lib_move_only_function != 202110L +# error "__cpp_lib_move_only_function should have the value 202110L in c++2b" # 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 --- 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 @@ -4404,17 +4404,11 @@ # error "__cpp_lib_memory_resource should have the value 201603L in c++2b" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_move_only_function -# error "__cpp_lib_move_only_function should be defined in c++2b" -# endif -# if __cpp_lib_move_only_function != 202110L -# error "__cpp_lib_move_only_function should have the value 202110L in c++2b" -# endif -# else // _LIBCPP_VERSION -# 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++2b" +# endif +# if __cpp_lib_move_only_function != 202110L +# error "__cpp_lib_move_only_function should have the value 202110L in c++2b" # 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/assignment/functor.pass.cpp @@ -0,0 +1,81 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include "type_algorithms.h" +#include "../common.h" + +template +void test() { + static_assert(!std::is_nothrow_assignable_v&, NonTrivial>); + { + std::move_only_function f; + std::same_as&> decltype(auto) ret = (f = &call_func); + assert(&ret == &f); + assert(f); + } + { + std::move_only_function f; + decltype(&call_func) ptr = nullptr; + std::same_as&> decltype(auto) ret = (f = ptr); + assert(&ret == &f); + assert(!f); + } + { + std::move_only_function f; + std::same_as&> decltype(auto) ret = (f = TriviallyDestructible{}); + assert(&ret == &f); + assert(f); + } + { + std::move_only_function f; + std::same_as&> decltype(auto) ret = (f = TriviallyDestructibleTooLarge{}); + assert(&ret == &f); + assert(f); + } + { + std::move_only_function f; + std::same_as&> decltype(auto) ret = (f = NonTrivial{}); + assert(&ret == &f); + assert(f); + } +} + +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); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + std::move_only_function f2; + f2 = std::move(f); + assert(!f2); + } +} + +int main(int, char**) { + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { test(); }); + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { + test_member_function_pointer(); + }); +} 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,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 + +#include +#include +#include + +#include "test_macros.h" +#include "type_algorithms.h" +#include "../common.h" + +template +void test() { + static_assert(!std::is_assignable_v, int>); + { + std::move_only_function f = &call_func; + std::move_only_function f2; + f2 = std::move(f); + assert(f2); + LIBCPP_ASSERT(!f); + } + { + 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); + } + { + std::move_only_function f = TriviallyDestructible{}; + std::move_only_function f2; + f2 = std::move(f); + assert(f2); + LIBCPP_ASSERT(!f); + } + { + std::move_only_function f = TriviallyDestructibleTooLarge{}; + std::move_only_function f2; + f2 = std::move(f); + assert(f2); + LIBCPP_ASSERT(!f); + } + { + std::move_only_function f = NonTrivial{}; + std::move_only_function f2; + f2 = std::move(f); + assert(f2); + LIBCPP_ASSERT(!f); + } +} + +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); + } + { + 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); + } +} + +int main(int, char**) { + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { test(); }); + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { + test_member_function_pointer(); + }); +} 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/assignment/move_other.pass.cpp @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// +// 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 "type_algorithms.h" +#include "../common.h" + +template +void test() { + { + std::move_only_function f1; + std::move_only_function f2; + std::same_as&> decltype(auto) ret = (f2 = std::move(f1)); + assert(&ret == &f2); + assert(!f2); + } + { + std::move_only_function f1; + std::move_only_function f2; + std::same_as&> decltype(auto) ret = (f2 = std::move(f1)); + assert(&ret == &f2); + assert(!f2); + } +} + +template +void test2() { + { + std::move_only_function f1 = [] noexcept { return 109; }; + std::move_only_function f2; + std::same_as&> decltype(auto) ret = (f2 = std::move(f1)); + assert(&ret == &f2); + assert(f2); + assert(f2() == 109); + } + { + std::move_only_function f1 = [] noexcept { return 109; }; + std::move_only_function f2; + std::same_as&> decltype(auto) ret = (f2 = std::move(f1)); + assert(&ret == &f2); + assert(f2); + assert(f2() == 109); + } +} + +int main(int, char**) { + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { test(); }); + meta::for_each(meta::function_noexcept_const_lvalue_ref_qualified{}, [] { test2(); }); +} 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,71 @@ +//===----------------------------------------------------------------------===// +// +// 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 "type_algorithms.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 = TriviallyDestructibleTooLarge{}; + f = nullptr; + assert(!f); + } + { + 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**) { + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { test(); }); + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { + 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 = TriviallyDestructibleTooLarge{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = NonTrivial{}; + f(); + assert(called); + } + { + std::move_only_function f = &S::func; + assert(f); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + } + { + CallType type; + std::move_only_function f = CallTypeChecker{&type}; + f(); + assert(type == CallType::LValue); + } +} + +void test_return() { + { + called = false; + std::move_only_function f = &get_val; + assert(f(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function f = TriviallyDestructible{}; + assert(f(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleTooLarge{}; + assert(f(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function 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 --- /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 = TriviallyDestructibleTooLarge{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = NonTrivial{}; + f(); + assert(called); + } + { + std::move_only_function f = &S::func; + assert(f); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + } + { + 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); + } +} + +void test_return() { + { + called = false; + std::move_only_function f = &get_val; + assert(f(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function f = TriviallyDestructible{}; + assert(f(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleTooLarge{}; + assert(f(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/call/lvalue_const_noexcept.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 +#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 = TriviallyDestructibleTooLarge{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = NonTrivial{}; + f(); + assert(called); + } + { + std::move_only_function f = &S::func; + assert(f); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + } + { + 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); + } +} + +void test_return() { + { + called = false; + std::move_only_function f = &get_val; + assert(f(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function f = TriviallyDestructible{}; + assert(f(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleTooLarge{}; + assert(f(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function 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 --- /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 = TriviallyDestructibleTooLarge{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = NonTrivial{}; + f(); + assert(called); + } + { + std::move_only_function f = &S::func; + assert(f); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + } + { + CallType type; + std::move_only_function f = CallTypeCheckerNoexcept{&type}; + f(); + assert(type == CallType::LValue); + } +} + +void test_return() { + { + called = false; + std::move_only_function f = &get_val; + assert(f(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function f = TriviallyDestructible{}; + assert(f(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleTooLarge{}; + assert(f(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function 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 --- /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 = TriviallyDestructibleTooLarge{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = NonTrivial{}; + f(); + assert(called); + } + { + std::move_only_function f = &S::func; + assert(f); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + } + { + CallType type; + std::move_only_function 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 f = &get_val; + assert(f(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function f = TriviallyDestructible{}; + assert(f(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleTooLarge{}; + assert(f(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function 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 --- /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 = TriviallyDestructibleTooLarge{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = NonTrivial{}; + f(); + assert(called); + } + { + std::move_only_function f = &S::func; + assert(f); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + } + { + 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); + } +} + +void test_return() { + { + called = false; + std::move_only_function f = &get_val; + assert(f(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function f = TriviallyDestructible{}; + assert(f(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleTooLarge{}; + assert(f(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function 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 --- /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 = TriviallyDestructibleTooLarge{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = NonTrivial{}; + f(); + assert(called); + } + { + std::move_only_function f = &S::func; + assert(f); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + } + { + 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); + } +} + +void test_return() { + { + called = false; + std::move_only_function f = &get_val; + assert(f(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function f = TriviallyDestructible{}; + assert(f(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleTooLarge{}; + assert(f(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function 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 --- /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 = TriviallyDestructibleTooLarge{}; + f(); + assert(called); + } + { + called = false; + std::move_only_function f = NonTrivial{}; + f(); + assert(called); + } + { + std::move_only_function f = &S::func; + assert(f); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + } + { + CallType type; + std::move_only_function 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 f = &get_val; + assert(f(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function f = TriviallyDestructible{}; + assert(f(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleTooLarge{}; + assert(f(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function 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 --- /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 = TriviallyDestructibleTooLarge{}; + std::move(f)(); + assert(called); + } + { + called = false; + std::move_only_function f = NonTrivial{}; + std::move(f)(); + assert(called); + } + { + std::move_only_function f = &S::func; + assert(f); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + } + { + CallType type; + std::move_only_function f = CallTypeChecker{&type}; + type = CallType::None; + std::move(f)(); + assert(type == CallType::RValue); + } +} + +void test_return() { + { + called = false; + std::move_only_function f = &get_val; + assert(std::move(f)(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function f = TriviallyDestructible{}; + assert(std::move(f)(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleTooLarge{}; + assert(std::move(f)(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function 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 --- /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 = TriviallyDestructibleTooLarge{}; + std::move(f)(); + assert(called); + } + { + called = false; + std::move_only_function f = NonTrivial{}; + std::move(f)(); + assert(called); + } + { + std::move_only_function f = &S::func; + assert(f); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + } + { + 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); + } +} + +void test_return() { + { + called = false; + std::move_only_function f = &get_val; + assert(std::move(f)(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function f = TriviallyDestructible{}; + assert(std::move(f)(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleTooLarge{}; + assert(std::move(f)(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function 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 --- /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 = TriviallyDestructibleTooLarge{}; + std::move(f)(); + assert(called); + } + { + called = false; + std::move_only_function f = NonTrivial{}; + std::move(f)(); + assert(called); + } + { + std::move_only_function f = &S::func; + assert(f); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + } + { + 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); + } +} + +void test_return() { + { + called = false; + std::move_only_function f = &get_val; + assert(std::move(f)(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function f = TriviallyDestructible{}; + assert(std::move(f)(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleTooLarge{}; + assert(std::move(f)(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function 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 --- /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 = TriviallyDestructibleTooLarge{}; + std::move(f)(); + assert(called); + } + { + called = false; + std::move_only_function f = NonTrivial{}; + std::move(f)(); + assert(called); + } + { + std::move_only_function f = &S::func; + assert(f); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + } + { + CallType type; + std::move_only_function f = CallTypeCheckerNoexcept{&type}; + type = CallType::None; + std::move(f)(); + assert(type == CallType::RValue); + } +} + +void test_return() { + { + called = false; + std::move_only_function f = &get_val; + assert(std::move(f)(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function f = TriviallyDestructible{}; + assert(std::move(f)(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function f = TriviallyDestructibleTooLarge{}; + assert(std::move(f)(3) == 3); + assert(!called); + } + { + called = false; + std::move_only_function 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 --- /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 +#include + +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, 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, 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&, 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/default.pass.cpp @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// +// 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 "type_algorithms.h" + +template +void test() { + std::move_only_function f; + assert(!f); +} + +int main(int, char**) { + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { test(); }); + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { test(); }); + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { 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,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 + +#include +#include + +#include "count_new.h" +#include "test_macros.h" +#include "type_algorithms.h" +#include "../common.h" + +template +void test() { + { + std::move_only_function f = &call_func; + assert(f); + } + { + decltype(&call_func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + } + { + std::move_only_function f = TriviallyDestructible{}; + assert(f); + } + { + std::move_only_function f = TriviallyDestructibleTooLarge{}; + assert(f); + } + { + std::move_only_function f = NonTrivial{}; + assert(f); + } +} + +struct S { + void func() noexcept {} +}; + +template +void test_member_function_pointer() { + { + std::move_only_function f = &S::func; + assert(f); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + } +} + +template +void test_value_return_type() { + { + std::move_only_function f = &get_val; + assert(f); + } + { + decltype(&get_val) ptr = nullptr; + std::move_only_function f = ptr; + assert(!f); + } + { + std::move_only_function f = TriviallyDestructible{}; + assert(f); + } + { + std::move_only_function f = TriviallyDestructibleTooLarge{}; + assert(f); + } + { + std::move_only_function f = NonTrivial{}; + assert(f); + } +} + +template +void test_throwing() { + struct ThrowingFunctor { + ThrowingFunctor() = default; + ThrowingFunctor(const ThrowingFunctor&) { throw 1; } + void operator()() {} + }; + std::move_only_function 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**) { + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { test(); }); + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { + test_member_function_pointer(); + }); + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { test_value_return_type(); }); + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { test_throwing(); }); + check_new_delete_called(); +} 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,43 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include + +#include "test_macros.h" +#include "type_algorithms.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); + } + { + int counter = 0; + std::move_only_function f{std::in_place_type, MoveCounter{&counter}}; + assert(f); + assert(counter == 1); + } + { + int counter = 0; + std::move_only_function f{std::in_place_type, MoveCounter{&counter}}; + assert(f); + assert(counter == 1); + } +} + +int main(int, char**) { + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { test(); }); + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { 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,43 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include + +#include "test_macros.h" +#include "type_algorithms.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); + } + { + int counter = 0; + std::move_only_function f{std::in_place_type, {1}, MoveCounter{&counter}}; + assert(f); + assert(counter == 1); + } + { + int counter = 0; + std::move_only_function f{std::in_place_type, {1}, MoveCounter{&counter}}; + assert(f); + assert(counter == 1); + } +} + +int main(int, char**) { + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { test(); }); + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { 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,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 "type_algorithms.h" +#include "../common.h" + +template +void test() { + { + std::move_only_function f = &call_func; + std::move_only_function f2 = std::move(f); + assert(f2); + } + { + decltype(&call_func) ptr = nullptr; + std::move_only_function f = ptr; + std::move_only_function f2 = std::move(f); + assert(!f2); + } + { + std::move_only_function f = TriviallyDestructible{}; + std::move_only_function f2 = std::move(f); + assert(f2); + } + { + std::move_only_function f = TriviallyDestructibleTooLarge{}; + std::move_only_function f2 = std::move(f); + assert(f2); + } + { + std::move_only_function f = NonTrivial{}; + std::move_only_function f2 = std::move(f); + assert(f2); + } +} + +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); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + std::move_only_function f2 = std::move(f); + assert(!f2); + } +} + +template +void test_value() { + { + std::move_only_function f = &get_val; + std::move_only_function f2 = std::move(f); + assert(f2); + } + { + decltype(&get_val) ptr = nullptr; + std::move_only_function f = ptr; + std::move_only_function f2 = std::move(f); + assert(!f2); + } + { + std::move_only_function f = TriviallyDestructible{}; + std::move_only_function f2 = std::move(f); + assert(f2); + } + { + std::move_only_function f = TriviallyDestructibleTooLarge{}; + std::move_only_function f2 = std::move(f); + assert(f2); + } + { + std::move_only_function f = NonTrivial{}; + std::move_only_function f2 = std::move(f); + assert(f2); + } +} + +int main(int, char**) { + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { test(); }); + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { + test_member_function_pointer(); + }); + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { test_value(); }); +} 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/move_other.pass.cpp @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include + +#include "type_algorithms.h" + +static_assert(!std::is_constructible_v, std::move_only_function>); +static_assert(!std::is_constructible_v, std::move_only_function>); +static_assert( + !std::is_constructible_v, std::move_only_function>); +static_assert( + !std::is_constructible_v, std::move_only_function>); +static_assert( + !std::is_constructible_v, std::move_only_function>); + +template +void test() { + { + std::move_only_function f1; + std::move_only_function f2 = std::move(f1); + assert(!f2); + } + { + std::move_only_function f1; + std::move_only_function f2 = std::move(f1); + assert(!f2); + } +} + +int main(int, char**) { + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { test(); }); + + 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 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.move/ctors/nullptr.pass.cpp @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// +// 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 "type_algorithms.h" + +template +void test() { + std::move_only_function f = nullptr; + assert(!f); +} + +int main(int, char**) { + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { test(); }); + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { test(); }); + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { 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,71 @@ +//===----------------------------------------------------------------------===// +// +// 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 "type_algorithms.h" +#include "common.h" + +template +void test() { + { + std::move_only_function f = &call_func; + std::move_only_function f2; + swap(f, f2); + } + { + decltype(&call_func) ptr = nullptr; + std::move_only_function f = ptr; + std::move_only_function f2; + swap(f, f2); + } + { + std::move_only_function f = TriviallyDestructible{}; + std::move_only_function f2; + swap(f, f2); + } + { + std::move_only_function f = TriviallyDestructibleTooLarge{}; + std::move_only_function f2; + swap(f, f2); + } + { + std::move_only_function f = NonTrivial{}; + std::move_only_function f2; + swap(f, f2); + } +} + +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); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + std::move_only_function f2; + swap(f, f2); + } +} + +int main(int, char**) { + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { test(); }); + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { + 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,71 @@ +//===----------------------------------------------------------------------===// +// +// 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 "type_algorithms.h" +#include "common.h" + +template +void test() { + { + std::move_only_function f = &call_func; + std::move_only_function f2; + f.swap(f2); + } + { + decltype(&call_func) ptr = nullptr; + std::move_only_function f = ptr; + std::move_only_function f2; + f.swap(f2); + } + { + std::move_only_function f = TriviallyDestructible{}; + std::move_only_function f2; + f.swap(f2); + } + { + std::move_only_function f = TriviallyDestructibleTooLarge{}; + std::move_only_function f2; + f.swap(f2); + } + { + std::move_only_function f = NonTrivial{}; + std::move_only_function f2; + f.swap(f2); + } +} + +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); + } + { + decltype(&S::func) ptr = nullptr; + std::move_only_function f = ptr; + std::move_only_function f2; + f.swap(f2); + } +} + +int main(int, char**) { + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { test(); }); + meta::for_each(meta::function_noexcept_const_ref_qualified{}, [] { + test_member_function_pointer(); + }); +} diff --git a/libcxx/test/support/count_new.h b/libcxx/test/support/count_new.h --- a/libcxx/test/support/count_new.h +++ b/libcxx/test/support/count_new.h @@ -9,8 +9,9 @@ #ifndef COUNT_NEW_H #define COUNT_NEW_H -# include +#include # include +# include # include #include "test_macros.h" @@ -413,7 +414,9 @@ #ifdef USE_ALIGNED_ALLOC ret = _aligned_malloc(s, a); #else - posix_memalign(&ret, a, s); + // The alignment has to be a power of two and a multiple of sizeof(void*) for posix_memalign + // The power of two is required by the C++ standard, a multiple sizeof(void*) is only required for posix_memalign + posix_memalign(&ret, std::max(a, sizeof(void*)), s); #endif if (ret == nullptr) detail::throw_bad_alloc_helper(); diff --git a/libcxx/test/support/type_algorithms.h b/libcxx/test/support/type_algorithms.h --- a/libcxx/test/support/type_algorithms.h +++ b/libcxx/test/support/type_algorithms.h @@ -100,6 +100,42 @@ using floating_point_types = type_list; using arithmetic_types = concatenate_t; + +template +struct function_noexcept_const_lvalue_ref_qualified_impl; + +template +struct function_noexcept_const_lvalue_ref_qualified_impl { + using type = + type_list; +}; + +template +using function_noexcept_const_lvalue_ref_qualified = function_noexcept_const_lvalue_ref_qualified_impl::type; + +template +struct function_noexcept_const_ref_qualified_impl; + +template +struct function_noexcept_const_ref_qualified_impl { + using type = + concatenate_t, + type_list>; +}; + +template +using function_noexcept_const_ref_qualified = function_noexcept_const_ref_qualified_impl::type; + } // namespace meta #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 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -490,7 +490,6 @@ "name": "__cpp_lib_move_only_function", "values": { "c++2b": 202110 }, "headers": ["functional"], - "unimplemented": True, }, { "name": "__cpp_lib_node_extract", "values": { "c++17": 201606 },