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