diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index cfe1f44777bca..27375cf2e9164 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -393,6 +393,9 @@ set(files __functional/compose.h __functional/default_searcher.h __functional/function.h + __functional/function_ref.h + __functional/function_ref_common.h + __functional/function_ref_impl.h __functional/hash.h __functional/identity.h __functional/invoke.h @@ -855,6 +858,7 @@ set(files __utility/is_valid_range.h __utility/move.h __utility/no_destroy.h + __utility/nontype.h __utility/pair.h __utility/piecewise_construct.h __utility/priority_tag.h diff --git a/libcxx/include/__functional/function_ref.h b/libcxx/include/__functional/function_ref.h new file mode 100644 index 0000000000000..8fcebb8aa4825 --- /dev/null +++ b/libcxx/include/__functional/function_ref.h @@ -0,0 +1,47 @@ +//===----------------------------------------------------------------------===// +// +// 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_FUNCTION_REF_H +#define _LIBCPP___FUNCTIONAL_FUNCTION_REF_H + +#include <__config> +#include <__functional/function_ref_common.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +// NOLINTBEGIN(readability-duplicate-include) + +#define _LIBCPP_FUNCTION_REF_CV +#define _LIBCPP_FUNCTION_REF_NOEXCEPT false +#include <__functional/function_ref_impl.h> +#undef _LIBCPP_FUNCTION_REF_CV +#undef _LIBCPP_FUNCTION_REF_NOEXCEPT + +#define _LIBCPP_FUNCTION_REF_CV +#define _LIBCPP_FUNCTION_REF_NOEXCEPT true +#include <__functional/function_ref_impl.h> +#undef _LIBCPP_FUNCTION_REF_CV +#undef _LIBCPP_FUNCTION_REF_NOEXCEPT + +#define _LIBCPP_FUNCTION_REF_CV const +#define _LIBCPP_FUNCTION_REF_NOEXCEPT false +#include <__functional/function_ref_impl.h> +#undef _LIBCPP_FUNCTION_REF_CV +#undef _LIBCPP_FUNCTION_REF_NOEXCEPT + +#define _LIBCPP_FUNCTION_REF_CV const +#define _LIBCPP_FUNCTION_REF_NOEXCEPT true +#include <__functional/function_ref_impl.h> +#undef _LIBCPP_FUNCTION_REF_CV +#undef _LIBCPP_FUNCTION_REF_NOEXCEPT + +// NOLINTEND(readability-duplicate-include) + +#endif // _LIBCPP___FUNCTIONAL_FUNCTION_REF_H diff --git a/libcxx/include/__functional/function_ref_common.h b/libcxx/include/__functional/function_ref_common.h new file mode 100644 index 0000000000000..b2d1864e582c5 --- /dev/null +++ b/libcxx/include/__functional/function_ref_common.h @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// 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_FUNCTION_REF_COMMON_H +#define _LIBCPP___FUNCTIONAL_FUNCTION_REF_COMMON_H + +#include <__config> +#include <__type_traits/invoke.h> +#include <__type_traits/is_function.h> +#include <__type_traits/is_object.h> +#include <__type_traits/remove_pointer.h> +#include <__utility/nontype.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 26 + +template +class function_ref; + +template +inline constexpr bool __is_function_ref = false; + +template +inline constexpr bool __is_function_ref> = true; + +template +struct __function_ref_bind {}; + +template +struct __function_ref_bind<_Rp (*)(_Gp, _ArgTypes...), _Tp> { + using type = _Rp(_ArgTypes...); +}; + +template +struct __function_ref_bind<_Rp (*)(_Gp, _ArgTypes...) noexcept, _Tp> { + using type = _Rp(_ArgTypes...) noexcept; +}; + +template + requires is_object_v<_Mp> +struct __function_ref_bind<_Mp _Gp::*, _Tp> { + using type = invoke_result_t<_Mp _Gp::*, _Tp&>(); +}; + +template +using __function_ref_bind_t = __function_ref_bind<_Fp, _Tp>::type; + +template + requires is_function_v<_Fp> +function_ref(_Fp*) -> function_ref<_Fp>; + +template + requires is_function_v> +function_ref(nontype_t<_Fn>) -> function_ref>; + +template +function_ref(nontype_t<_Fn>, _Tp&&) -> function_ref<__function_ref_bind_t>; + +#endif // _LIBCPP_STD_VER >= 26 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_FUNCTION_REF_COMMON_H diff --git a/libcxx/include/__functional/function_ref_impl.h b/libcxx/include/__functional/function_ref_impl.h new file mode 100644 index 0000000000000..daae5c87d9470 --- /dev/null +++ b/libcxx/include/__functional/function_ref_impl.h @@ -0,0 +1,179 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include <__assert> +#include <__config> +#include <__functional/invoke.h> +#include <__memory/addressof.h> +#include <__type_traits/invoke.h> +#include <__type_traits/is_const.h> +#include <__type_traits/is_function.h> +#include <__type_traits/is_member_pointer.h> +#include <__type_traits/is_object.h> +#include <__type_traits/is_pointer.h> +#include <__type_traits/is_reference.h> +#include <__type_traits/is_void.h> +#include <__type_traits/remove_cvref.h> +#include <__type_traits/remove_pointer.h> +#include <__type_traits/remove_reference.h> +#include <__utility/forward.h> +#include <__utility/nontype.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 26 + +template +class function_ref; + +template +class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT)> { +private: +# if _LIBCPP_FUNCTION_REF_NOEXCEPT == true + template + static constexpr bool __is_invocable_using = is_nothrow_invocable_r_v<_Rp, _Tp..., _ArgTypes...>; +# else + template + static constexpr bool __is_invocable_using = is_invocable_r_v<_Rp, _Tp..., _ArgTypes...>; +# endif + + // use a union instead of a plain `void*` to avoid dropping const qualifiers and casting function pointers to data + // pointers + union __storage_t { + void* __obj_ptr; + void const* __obj_const_ptr; + void (*__fn_ptr)(); + + _LIBCPP_HIDE_FROM_ABI constexpr explicit __storage_t() noexcept : __obj_ptr(nullptr) {} + + template + _LIBCPP_HIDE_FROM_ABI constexpr explicit __storage_t(_Tp* __ptr) noexcept { + if constexpr (is_object_v<_Tp>) { + if constexpr (is_const_v<_Tp>) { + __obj_const_ptr = __ptr; + } else { + __obj_ptr = __ptr; + } + } else { + static_assert(is_function_v<_Tp>); + __fn_ptr = reinterpret_cast(__ptr); + } + } + } __storage_; + + template + _LIBCPP_HIDE_FROM_ABI static constexpr auto __get(__storage_t __storage) { + if constexpr (is_object_v<_Tp>) { + if constexpr (is_const_v<_Tp>) { + return static_cast<_Tp*>(__storage.__obj_const_ptr); + } else { + return static_cast<_Tp*>(__storage.__obj_ptr); + } + } else { + static_assert(is_function_v<_Tp>); + return reinterpret_cast<_Tp*>(__storage.__fn_ptr); + } + } + + using __call_t = _Rp (*)(__storage_t, _ArgTypes&&...) noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT); + __call_t __call_; + +public: + template + requires is_function_v<_Fp> && __is_invocable_using<_Fp> + _LIBCPP_HIDE_FROM_ABI function_ref(_Fp* __fn_ptr) noexcept + : __storage_(__fn_ptr), + __call_([](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp { + return __get<_Fp>(__storage)(std::forward<_ArgTypes>(__args)...); + }) { + _LIBCPP_ASSERT_UNCATEGORIZED(__fn_ptr != nullptr, "the function pointer should not be a nullptr"); + } + + template > + requires(!__is_function_ref> && !is_member_pointer_v<_Tp> && + __is_invocable_using<_LIBCPP_FUNCTION_REF_CV _Tp&>) + _LIBCPP_HIDE_FROM_ABI function_ref(_Fp&& __obj) noexcept + : __storage_(std::addressof(__obj)), + __call_([](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp { + _LIBCPP_FUNCTION_REF_CV _Tp& __obj = *__get<_Tp>(__storage); + return __obj(std::forward<_ArgTypes>(__args)...); + }) {} + + template + requires __is_invocable_using + _LIBCPP_HIDE_FROM_ABI constexpr function_ref(nontype_t<_Fn>) noexcept + : __call_([](__storage_t, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp { + return std::invoke_r<_Rp>(_Fn, std::forward<_ArgTypes>(__args)...); + }) { + if constexpr (is_pointer_v || is_member_pointer_v) { + static_assert(_Fn != nullptr, "the function pointer should not be a nullptr"); + } + } + + template > + requires(!is_rvalue_reference_v<_Up &&>) && __is_invocable_using + _LIBCPP_HIDE_FROM_ABI constexpr function_ref(nontype_t<_Fn>, _Up&& __obj) noexcept + : __storage_(std::addressof(__obj)), + __call_([](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp { + _LIBCPP_FUNCTION_REF_CV _Tp& __obj = *__get<_Tp>(__storage); + return std::invoke_r<_Rp>(_Fn, __obj, std::forward<_ArgTypes>(__args)...); + }) { + if constexpr (is_pointer_v || is_member_pointer_v) { + static_assert(_Fn != nullptr, "the function pointer should not be a nullptr"); + } + } + + template + requires __is_invocable_using + _LIBCPP_HIDE_FROM_ABI constexpr function_ref(nontype_t<_Fn>, _LIBCPP_FUNCTION_REF_CV _Tp* __obj_ptr) noexcept + : __storage_(__obj_ptr), + __call_([](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp { + auto __obj = __get<_LIBCPP_FUNCTION_REF_CV _Tp>(__storage); + return std::invoke_r<_Rp>(_Fn, __obj, std::forward<_ArgTypes>(__args)...); + }) { + if constexpr (is_pointer_v || is_member_pointer_v) { + static_assert(_Fn != nullptr, "the function pointer should not be a nullptr"); + } + + if constexpr (is_member_pointer_v) { + _LIBCPP_ASSERT_UNCATEGORIZED(__obj_ptr != nullptr, "the object pointer should not be a nullptr"); + } + } + + _LIBCPP_HIDE_FROM_ABI constexpr function_ref(const function_ref&) noexcept = default; + + _LIBCPP_HIDE_FROM_ABI constexpr function_ref& operator=(const function_ref&) noexcept = default; + + template + requires(!__is_function_ref<_Tp>) && (!is_pointer_v<_Tp>) && (!__is_nontype_t<_Tp>) + _LIBCPP_HIDE_FROM_ABI function_ref& operator=(_Tp) = delete; + + _LIBCPP_HIDE_FROM_ABI constexpr _Rp operator()(_ArgTypes... __args) const noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) { + return __call_(__storage_, std::forward<_ArgTypes>(__args)...); + } +}; + +template +struct __function_ref_bind<_Rp (_Gp::*)(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT), + _Tp> { + using type = _Rp(_ArgTypes...) noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT); +}; + +template +struct __function_ref_bind<_Rp (_Gp::*)(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV & noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT), + _Tp> { + using type = _Rp(_ArgTypes...) noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT); +}; + +#endif // _LIBCPP_STD_VER >= 26 + +_LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__utility/nontype.h b/libcxx/include/__utility/nontype.h new file mode 100644 index 0000000000000..3a10840154009 --- /dev/null +++ b/libcxx/include/__utility/nontype.h @@ -0,0 +1,39 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___UTILITY_NONTYPE_H +#define _LIBCPP___UTILITY_NONTYPE_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 26 + +template +struct nontype_t { + _LIBCPP_HIDE_FROM_ABI explicit nontype_t() = default; +}; + +template +inline constexpr nontype_t<_Vp> nontype{}; + +template +inline constexpr bool __is_nontype_t = false; +template +inline constexpr bool __is_nontype_t> = true; + +#endif // _LIBCPP_STD_VER >= 26 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___UTILITY_NONTYPE_H diff --git a/libcxx/include/functional b/libcxx/include/functional index 27cf21e1a4c8b..1a9bce7b00229 100644 --- a/libcxx/include/functional +++ b/libcxx/include/functional @@ -483,6 +483,11 @@ template template void swap(function&, function&) noexcept; +// [func.wrap.ref], non-owning wrapper +template class function_ref; // freestanding, not defined, since C++26 +template + class function_ref; // freestanding, since C++26 + template struct hash; template <> struct hash; @@ -541,6 +546,7 @@ POLICY: For non-variadic implementations, the number of arguments is limited #include <__functional/compose.h> #include <__functional/default_searcher.h> #include <__functional/function.h> +#include <__functional/function_ref.h> #include <__functional/hash.h> #include <__functional/identity.h> #include <__functional/invoke.h> diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 48391b2a12095..c24d17b62931a 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -1339,6 +1339,9 @@ module std_private_functional_compose [system] { } module std_private_functional_default_searcher [system] { header "__functional/default_searcher.h" } module std_private_functional_function [system] { header "__functional/function.h" } +module std_private_functional_function_ref [system] { header "__functional/function_ref.h" } +module std_private_functional_function_ref_common [system] { textual header "__functional/function_ref_common.h" } +module std_private_functional_function_ref_impl [system] { textual header "__functional/function_ref_impl.h" } module std_private_functional_hash [system] { header "__functional/hash.h" export std_cstdint @@ -2073,6 +2076,7 @@ module std_private_utility_move [system] { export std_private_type_traits_remove_reference } module std_private_utility_no_destroy [system] { header "__utility/no_destroy.h" } +module std_private_utility_nontype [system] { header "__utility/nontype.h" } module std_private_utility_pair [system] { header "__utility/pair.h" export std_private_ranges_subrange_fwd diff --git a/libcxx/include/utility b/libcxx/include/utility index 90713da621c5d..07dba7593f2df 100644 --- a/libcxx/include/utility +++ b/libcxx/include/utility @@ -238,6 +238,15 @@ template template inline constexpr in_place_index_t in_place_index{}; +// nontype argument tag +template + struct nontype_t { + explicit nontype_t() = default; + }; +template constexpr nontype_t nontype{}; + +template constexpr nontype_t nontype{}; + // [utility.underlying], to_underlying template constexpr underlying_type_t to_underlying( T value ) noexcept; // C++23 @@ -259,6 +268,7 @@ template #include <__utility/in_place.h> #include <__utility/integer_sequence.h> #include <__utility/move.h> +#include <__utility/nontype.h> #include <__utility/pair.h> #include <__utility/piecewise_construct.h> #include <__utility/priority_tag.h> diff --git a/libcxx/modules/std/functional.inc b/libcxx/modules/std/functional.inc index ddc7d023ee6dc..4d2be32f3f6bb 100644 --- a/libcxx/modules/std/functional.inc +++ b/libcxx/modules/std/functional.inc @@ -91,6 +91,10 @@ export namespace std { using std::function; +#if _LIBCPP_STD_VER >= 26 + using std::function_ref; +#endif // _LIBCPP_STD_VER >= 26 + using std::swap; using std::operator==; diff --git a/libcxx/modules/std/utility.inc b/libcxx/modules/std/utility.inc index 77c21b87640dd..28f8e36e30af9 100644 --- a/libcxx/modules/std/utility.inc +++ b/libcxx/modules/std/utility.inc @@ -89,6 +89,11 @@ export namespace std { using std::in_place_index; using std::in_place_index_t; +#if _LIBCPP_STD_VER >= 26 + using std::nontype; + using std::nontype_t; +#endif // _LIBCPP_STD_VER >= 23 + // [depr.relops] namespace rel_ops { using rel_ops::operator!=; diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/ctor/ctad.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/ctor/ctad.pass.cpp new file mode 100644 index 0000000000000..c7490fc0982e3 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/ctor/ctad.pass.cpp @@ -0,0 +1,84 @@ +//===----------------------------------------------------------------------===// +// +// 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, c++23 + +#include +#include +#include +#include + +#include "test_macros.h" + +int fn(int, float) { return 42; } + +int fn_noexcept(int, float) noexcept { return 42; } + +struct S { + int data_mem = 42; + + int fn_mem(int, float) { return 42; } + int fn_mem_noexcept(int, float) noexcept { return 42; } +}; + +void test() { + // template + // function_ref(F*) -> function_ref; + { + std::function_ref fn_ref = fn; + static_assert(std::is_same_v>); + } + { + std::function_ref fn_ref = fn_noexcept; + static_assert(std::is_same_v>); + } + + // template + // function_ref(nontype_t) -> function_ref<...>; + { + std::function_ref fn_ref = std::nontype_t(); + static_assert(std::is_same_v>); + } + { + std::function_ref fn_ref = std::nontype_t(); + static_assert(std::is_same_v>); + } + + // template + // function_ref(nontype_t, T&&) -> function_ref<...>; + { + int arg = 0; + std::function_ref fn_ref = {std::nontype_t(), arg}; + static_assert(std::is_same_v>); + } + { + S s; + std::function_ref fn_ref = {std::nontype_t<&S::data_mem>(), s}; + static_assert(std::is_same_v>); + } + { + const S s; + std::function_ref fn_ref = {std::nontype_t<&S::data_mem>(), s}; + static_assert(std::is_same_v>); + } + { + S s; + std::function_ref fn_ref = {std::nontype_t<&S::fn_mem>(), s}; + static_assert(std::is_same_v>); + } + { + S s; + std::function_ref fn_ref = {std::nontype_t<&S::fn_mem_noexcept>(), s}; + static_assert(std::is_same_v>); + } +} + +int main(int, char**) { + test(); + return 0; +} diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/const.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/const.pass.cpp new file mode 100644 index 0000000000000..53d7a5922353d --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/const.pass.cpp @@ -0,0 +1,124 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 + +#include +#include +#include +#include + +#include "test_macros.h" + +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&&>); + +int fn() { return 42; } + +struct { + int operator()() const { return 42; } +} fn_obj; + +void test() { + // template function_ref(F* f) noexcept; + { + // initialized from a function + std::function_ref fn_ref = fn; + assert(fn_ref() == 42); + } + { + // initialized from a function pointer + std::function_ref fn_ref = &fn; + assert(fn_ref() == 42); + } + + // template constexpr function_ref(F&& f) noexcept; + { + // initialized from a function object + std::function_ref fn_ref = fn_obj; + assert(fn_ref() == 42); + } +} + +struct S { + int data_mem = 42; + + int fn_mem() const { return 42; } +}; + +void test_nontype_t() { + // template constexpr function_ref(nontype_t) noexcept; + { + // initialized from a function through `nontype_t` + std::function_ref fn_ref = std::nontype_t(); + assert(fn_ref() == 42); + } + { + // initialized from a function pointer through `nontype_t` + std::function_ref fn_ref = std::nontype_t<&fn>(); + assert(fn_ref() == 42); + } + { + // initialized from a function object through `nontype_t` + std::function_ref fn_ref = std::nontype_t(); + assert(fn_ref() == 42); + } + { + S s; + // initialized from a pointer to data member through `nontype_t` + std::function_ref fn_ref = std::nontype_t<&S::data_mem>(); + assert(fn_ref(s) == 42); + } + { + S s; + // initialized from a pointer to function member through `nontype_t` + std::function_ref fn_ref = std::nontype_t<&S::fn_mem>(); + assert(fn_ref(s) == 42); + } + + // template + // constexpr function_ref(nontype_t, U&& obj) noexcept; + { + S s; + // initialized from a pointer to data member through `nontype_t` and bound to an object through a reference + std::function_ref fn_ref = {std::nontype_t<&S::data_mem>(), s}; + assert(fn_ref() == 42); + } + { + S s; + // initialized from a pointer to function member through `nontype_t` and bound to an object through a reference + std::function_ref fn_ref = {std::nontype_t<&S::fn_mem>(), s}; + assert(fn_ref() == 42); + } + + // template + // constexpr function_ref(nontype_t, cv T* obj) noexcept; + { + S s; + // initialized from a pointer to data member through `nontype_t` and bound to an object through a pointer + std::function_ref fn_ref = {std::nontype_t<&S::data_mem>(), &s}; + assert(fn_ref() == 42); + } + { + S s; + // initialized from a pointer to function member through `nontype_t` and bound to an object through a pointer + static_assert(std::is_same_v); + std::function_ref fn_ref = {std::nontype_t<&S::fn_mem>(), &s}; + assert(fn_ref() == 42); + } +} + +int main(int, char**) { + test(); + test_nontype_t(); + return 0; +} diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/const_noexcept.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/const_noexcept.pass.cpp new file mode 100644 index 0000000000000..18d44e4b7ef0b --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/const_noexcept.pass.cpp @@ -0,0 +1,124 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23 + +#include +#include +#include +#include + +#include "test_macros.h" + +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&&>); + +int fn() noexcept { return 42; } + +struct { + int operator()() const noexcept { return 42; } +} fn_obj; + +void test() { + // template function_ref(F* f) noexcept; + { + // initialized from a function + std::function_ref fn_ref = fn; + assert(fn_ref() == 42); + } + { + // initialized from a function pointer + std::function_ref fn_ref = &fn; + assert(fn_ref() == 42); + } + + // template const noexceptexpr function_ref(F&& f) noexcept; + { + // initialized from a function object + std::function_ref fn_ref = fn_obj; + assert(fn_ref() == 42); + } +} + +struct S { + int data_mem = 42; + + int fn_mem() const noexcept { return 42; } +}; + +void test_nontype_t() { + // template const noexceptexpr function_ref(nontype_t) noexcept; + { + // initialized from a function through `nontype_t` + std::function_ref fn_ref = std::nontype_t(); + assert(fn_ref() == 42); + } + { + // initialized from a function pointer through `nontype_t` + std::function_ref fn_ref = std::nontype_t<&fn>(); + assert(fn_ref() == 42); + } + { + // initialized from a function object through `nontype_t` + std::function_ref fn_ref = std::nontype_t(); + assert(fn_ref() == 42); + } + { + S s; + // initialized from a pointer to data member through `nontype_t` + std::function_ref fn_ref = std::nontype_t<&S::data_mem>(); + assert(fn_ref(s) == 42); + } + { + S s; + // initialized from a pointer to function member through `nontype_t` + std::function_ref fn_ref = std::nontype_t<&S::fn_mem>(); + assert(fn_ref(s) == 42); + } + + // template + // const noexceptexpr function_ref(nontype_t, U&& obj) noexcept; + { + S s; + // initialized from a pointer to data member through `nontype_t` and bound to an object through a reference + std::function_ref fn_ref = {std::nontype_t<&S::data_mem>(), s}; + assert(fn_ref() == 42); + } + { + S s; + // initialized from a pointer to function member through `nontype_t` and bound to an object through a reference + std::function_ref fn_ref = {std::nontype_t<&S::fn_mem>(), s}; + assert(fn_ref() == 42); + } + + // template + // const noexceptexpr function_ref(nontype_t, cv T* obj) noexcept; + { + S s; + // initialized from a pointer to data member through `nontype_t` and bound to an object through a pointer + std::function_ref fn_ref = {std::nontype_t<&S::data_mem>(), &s}; + assert(fn_ref() == 42); + } + { + S s; + // initialized from a pointer to function member through `nontype_t` and bound to an object through a pointer + static_assert(std::is_same_v); + std::function_ref fn_ref = {std::nontype_t<&S::fn_mem>(), &s}; + assert(fn_ref() == 42); + } +} + +int main(int, char**) { + test(); + test_nontype_t(); + return 0; +} diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/default.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/default.pass.cpp new file mode 100644 index 0000000000000..ebc07a6c3520c --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/default.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, c++23 + +#include +#include +#include +#include + +#include "test_macros.h" + +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&&>); + +int fn() { return 42; } + +struct { + int operator()() { return 42; } +} fn_obj; + +void test() { + // template function_ref(F* f) noexcept; + { + // initialized from a function + std::function_ref fn_ref = fn; + assert(fn_ref() == 42); + } + { + // initialized from a function pointer + std::function_ref fn_ref = &fn; + assert(fn_ref() == 42); + } + + // template constexpr function_ref(F&& f) noexcept; + { + // initialized from a function object + std::function_ref fn_ref = fn_obj; + assert(fn_ref() == 42); + } +} + +struct S { + int data_mem = 42; + + int fn_mem() { return 42; } +}; + +void test_nontype_t() { + // template constexpr function_ref(nontype_t) noexcept; + { + // initialized from a function through `nontype_t` + std::function_ref fn_ref = std::nontype_t(); + assert(fn_ref() == 42); + } + { + // initialized from a function pointer through `nontype_t` + std::function_ref fn_ref = std::nontype_t<&fn>(); + assert(fn_ref() == 42); + } + { + S s; + // initialized from a pointer to data member through `nontype_t` + std::function_ref fn_ref = std::nontype_t<&S::data_mem>(); + assert(fn_ref(s) == 42); + } + { + S s; + // initialized from a pointer to function member through `nontype_t` + std::function_ref fn_ref = std::nontype_t<&S::fn_mem>(); + assert(fn_ref(s) == 42); + } + + // template + // constexpr function_ref(nontype_t, U&& obj) noexcept; + { + S s; + // initialized from a pointer to data member through `nontype_t` and bound to an object through a reference + std::function_ref fn_ref = {std::nontype_t<&S::data_mem>(), s}; + assert(fn_ref() == 42); + } + { + S s; + // initialized from a pointer to function member through `nontype_t` and bound to an object through a reference + std::function_ref fn_ref = {std::nontype_t<&S::fn_mem>(), s}; + assert(fn_ref() == 42); + } + + // template + // constexpr function_ref(nontype_t, cv T* obj) noexcept; + { + S s; + // initialized from a pointer to data member through `nontype_t` and bound to an object through a pointer + std::function_ref fn_ref = {std::nontype_t<&S::data_mem>(), &s}; + assert(fn_ref() == 42); + } + { + S s; + // initialized from a pointer to function member through `nontype_t` and bound to an object through a pointer + static_assert(std::is_same_v); + std::function_ref fn_ref = {std::nontype_t<&S::fn_mem>(), &s}; + assert(fn_ref() == 42); + } +} + +int main(int, char**) { + test(); + test_nontype_t(); + return 0; +} diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/noexcept.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/noexcept.pass.cpp new file mode 100644 index 0000000000000..9b58e677ed6ba --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/noexcept.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, c++23 + +#include +#include +#include +#include + +#include "test_macros.h" + +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&&>); + +int fn() noexcept { return 42; } + +struct { + int operator()() noexcept { return 42; } +} fn_obj; + +void test() { + // template function_ref(F* f) noexcept; + { + // initialized from a function + std::function_ref fn_ref = fn; + assert(fn_ref() == 42); + } + { + // initialized from a function pointer + std::function_ref fn_ref = &fn; + assert(fn_ref() == 42); + } + + // template constexpr function_ref(F&& f) noexcept; + { + // initialized from a function object + std::function_ref fn_ref = fn_obj; + assert(fn_ref() == 42); + } +} + +struct S { + int data_mem = 42; + + int fn_mem() noexcept { return 42; } +}; + +void test_nontype_t() { + // template constexpr function_ref(nontype_t) noexcept; + { + // initialized from a function through `nontype_t` + std::function_ref fn_ref = std::nontype_t(); + assert(fn_ref() == 42); + } + { + // initialized from a function pointer through `nontype_t` + std::function_ref fn_ref = std::nontype_t<&fn>(); + assert(fn_ref() == 42); + } + { + S s; + // initialized from a pointer to data member through `nontype_t` + std::function_ref fn_ref = std::nontype_t<&S::data_mem>(); + assert(fn_ref(s) == 42); + } + { + S s; + // initialized from a pointer to function member through `nontype_t` + std::function_ref fn_ref = std::nontype_t<&S::fn_mem>(); + assert(fn_ref(s) == 42); + } + + // template + // constexpr function_ref(nontype_t, U&& obj) noexcept; + { + S s; + // initialized from a pointer to data member through `nontype_t` and bound to an object through a reference + std::function_ref fn_ref = {std::nontype_t<&S::data_mem>(), s}; + assert(fn_ref() == 42); + } + { + S s; + // initialized from a pointer to function member through `nontype_t` and bound to an object through a reference + std::function_ref fn_ref = {std::nontype_t<&S::fn_mem>(), s}; + assert(fn_ref() == 42); + } + + // template + // constexpr function_ref(nontype_t, cv T* obj) noexcept; + { + S s; + // initialized from a pointer to data member through `nontype_t` and bound to an object through a pointer + std::function_ref fn_ref = {std::nontype_t<&S::data_mem>(), &s}; + assert(fn_ref() == 42); + } + { + S s; + // initialized from a pointer to function member through `nontype_t` and bound to an object through a pointer + static_assert(std::is_same_v); + std::function_ref fn_ref = {std::nontype_t<&S::fn_mem>(), &s}; + assert(fn_ref() == 42); + } +} + +int main(int, char**) { + test(); + test_nontype_t(); + return 0; +}