aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3
diff options
context:
space:
mode:
Diffstat (limited to 'libstdc++-v3')
-rw-r--r--libstdc++-v3/doc/doxygen/stdheader.cc3
-rw-r--r--libstdc++-v3/include/Makefile.am3
-rw-r--r--libstdc++-v3/include/Makefile.in3
-rw-r--r--libstdc++-v3/include/bits/cpyfunc_impl.h269
-rw-r--r--libstdc++-v3/include/bits/funcwrap.h507
-rw-r--r--libstdc++-v3/include/bits/mofunc_impl.h78
-rw-r--r--libstdc++-v3/include/bits/move_only_function.h218
-rw-r--r--libstdc++-v3/include/bits/version.def9
-rw-r--r--libstdc++-v3/include/bits/version.h10
-rw-r--r--libstdc++-v3/include/std/format217
-rw-r--r--libstdc++-v3/include/std/functional31
-rw-r--r--libstdc++-v3/include/std/utility2
-rw-r--r--libstdc++-v3/src/c++23/std.cc.in3
-rw-r--r--libstdc++-v3/testsuite/20_util/copyable_function/call.cc224
-rw-r--r--libstdc++-v3/testsuite/20_util/copyable_function/cons.cc126
-rw-r--r--libstdc++-v3/testsuite/20_util/copyable_function/conv.cc251
-rw-r--r--libstdc++-v3/testsuite/20_util/copyable_function/copy.cc154
-rw-r--r--libstdc++-v3/testsuite/20_util/copyable_function/move.cc120
-rw-r--r--libstdc++-v3/testsuite/20_util/move_only_function/call.cc14
-rw-r--r--libstdc++-v3/testsuite/20_util/move_only_function/conv.cc188
-rw-r--r--libstdc++-v3/testsuite/20_util/move_only_function/move.cc11
-rw-r--r--libstdc++-v3/testsuite/std/format/arguments/args.cc45
-rw-r--r--libstdc++-v3/testsuite/std/format/parse_ctx.cc72
23 files changed, 2185 insertions, 373 deletions
diff --git a/libstdc++-v3/doc/doxygen/stdheader.cc b/libstdc++-v3/doc/doxygen/stdheader.cc
index 3ee825f..839bfc8 100644
--- a/libstdc++-v3/doc/doxygen/stdheader.cc
+++ b/libstdc++-v3/doc/doxygen/stdheader.cc
@@ -54,7 +54,8 @@ void init_map()
headers["function.h"] = "functional";
headers["functional_hash.h"] = "functional";
headers["mofunc_impl.h"] = "functional";
- headers["move_only_function.h"] = "functional";
+ headers["cpyfunc_impl.h"] = "functional";
+ headers["funcwrap.h"] = "functional";
headers["invoke.h"] = "functional";
headers["ranges_cmp.h"] = "functional";
headers["refwrap.h"] = "functional";
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 1140fa0..3e5b6c4 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -194,6 +194,7 @@ bits_headers = \
${bits_srcdir}/chrono_io.h \
${bits_srcdir}/codecvt.h \
${bits_srcdir}/cow_string.h \
+ ${bits_srcdir}/cpyfunc_impl.h \
${bits_srcdir}/deque.tcc \
${bits_srcdir}/erase_if.h \
${bits_srcdir}/formatfwd.h \
@@ -204,6 +205,7 @@ bits_headers = \
${bits_srcdir}/fs_ops.h \
${bits_srcdir}/fs_path.h \
${bits_srcdir}/fstream.tcc \
+ ${bits_srcdir}/funcwrap.h \
${bits_srcdir}/gslice.h \
${bits_srcdir}/gslice_array.h \
${bits_srcdir}/hashtable.h \
@@ -223,7 +225,6 @@ bits_headers = \
${bits_srcdir}/mask_array.h \
${bits_srcdir}/memory_resource.h \
${bits_srcdir}/mofunc_impl.h \
- ${bits_srcdir}/move_only_function.h \
${bits_srcdir}/new_allocator.h \
${bits_srcdir}/node_handle.h \
${bits_srcdir}/ostream.tcc \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index c96e981..3531162 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -547,6 +547,7 @@ bits_freestanding = \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/chrono_io.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/codecvt.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/cow_string.h \
+@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/cpyfunc_impl.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/deque.tcc \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/erase_if.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/formatfwd.h \
@@ -557,6 +558,7 @@ bits_freestanding = \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/fs_ops.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/fs_path.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/fstream.tcc \
+@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/funcwrap.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/gslice.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/gslice_array.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/hashtable.h \
@@ -576,7 +578,6 @@ bits_freestanding = \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/mask_array.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/memory_resource.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/mofunc_impl.h \
-@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/move_only_function.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/new_allocator.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/node_handle.h \
@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/ostream.tcc \
diff --git a/libstdc++-v3/include/bits/cpyfunc_impl.h b/libstdc++-v3/include/bits/cpyfunc_impl.h
new file mode 100644
index 0000000..bc44cd3e
--- /dev/null
+++ b/libstdc++-v3/include/bits/cpyfunc_impl.h
@@ -0,0 +1,269 @@
+// Implementation of std::copyable_function -*- C++ -*-
+
+// Copyright The GNU Toolchain Authors.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/bits/cpyfunc_impl.h
+ * This is an internal header file, included by other library headers.
+ * Do not attempt to use it directly. @headername{functional}
+ */
+
+#ifndef _GLIBCXX_MOF_CV
+# define _GLIBCXX_MOF_CV
+#endif
+
+#ifdef _GLIBCXX_MOF_REF
+# define _GLIBCXX_MOF_INV_QUALS _GLIBCXX_MOF_CV _GLIBCXX_MOF_REF
+#else
+# define _GLIBCXX_MOF_REF
+# define _GLIBCXX_MOF_INV_QUALS _GLIBCXX_MOF_CV &
+#endif
+
+#define _GLIBCXX_MOF_CV_REF _GLIBCXX_MOF_CV _GLIBCXX_MOF_REF
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ /**
+ * @brief Polymorphic copyable function wrapper.
+ * @ingroup functors
+ * @since C++26
+ * @headerfile functional
+ *
+ * The `std::copyable_function` class template is a call wrapper similar
+ * to `std::function`, but it does not provide information about it's
+ * target, and preserves constness.
+ *
+ * It also supports const-qualification, ref-qualification, and
+ * no-throw guarantees. The qualifications and exception-specification
+ * of the `copyable_function::operator()` member function are respected
+ * when invoking the target function.
+ */
+ template<typename _Res, typename... _ArgTypes, bool _Noex>
+ class copyable_function<_Res(_ArgTypes...) _GLIBCXX_MOF_CV
+ _GLIBCXX_MOF_REF noexcept(_Noex)>
+ : __polyfunc::_Cpy_base
+ {
+ using _Base = __polyfunc::_Cpy_base;
+ using _Invoker = __polyfunc::_Invoker<_Noex, _Res, _ArgTypes...>;
+ using _Signature = _Invoker::_Signature;
+
+ template<typename _Tp>
+ using __callable
+ = __conditional_t<_Noex,
+ is_nothrow_invocable_r<_Res, _Tp, _ArgTypes...>,
+ is_invocable_r<_Res, _Tp, _ArgTypes...>>;
+
+ // [func.wrap.copy.con]/1 is-callable-from<VT>
+ template<typename _Vt>
+ static constexpr bool __is_callable_from
+ = __and_v<__callable<_Vt _GLIBCXX_MOF_CV_REF>,
+ __callable<_Vt _GLIBCXX_MOF_INV_QUALS>>;
+
+ public:
+ using result_type = _Res;
+
+ /// Creates an empty object.
+ copyable_function() noexcept { }
+
+ /// Creates an empty object.
+ copyable_function(nullptr_t) noexcept { }
+
+ /// Moves the target object, leaving the source empty.
+ copyable_function(copyable_function&& __x) noexcept
+ : _Base(static_cast<_Base&&>(__x)),
+ _M_invoke(std::__exchange(__x._M_invoke, nullptr))
+ { }
+
+ /// Copies the target object.
+ copyable_function(copyable_function const& __x)
+ : _Base(static_cast<const _Base&>(__x)),
+ _M_invoke(__x._M_invoke)
+ { }
+
+ /// Stores a target object initialized from the argument.
+ template<typename _Fn, typename _Vt = decay_t<_Fn>>
+ requires (!is_same_v<_Vt, copyable_function>)
+ && (!__is_in_place_type_v<_Vt>) && __is_callable_from<_Vt>
+ copyable_function(_Fn&& __f) noexcept(_S_nothrow_init<_Vt, _Fn>())
+ {
+ static_assert(is_copy_constructible_v<_Vt>);
+ if constexpr (is_function_v<remove_pointer_t<_Vt>>
+ || is_member_pointer_v<_Vt>
+ || __is_polymorphic_function_v<_Vt>)
+ {
+ if (__f == nullptr)
+ return;
+ }
+
+ if constexpr (!__is_polymorphic_function_v<_Vt>
+ || !__polyfunc::__is_invoker_convertible<_Vt, copyable_function>())
+ {
+ _M_init<_Vt>(std::forward<_Fn>(__f));
+ _M_invoke = _Invoker::template _S_storage<_Vt _GLIBCXX_MOF_INV_QUALS>();
+ }
+ else if constexpr (is_lvalue_reference_v<_Fn>)
+ {
+ _M_copy(__polyfunc::__base_of(__f));
+ _M_invoke = __polyfunc::__invoker_of(__f);
+ }
+ else
+ {
+ _M_move(__polyfunc::__base_of(__f));
+ _M_invoke = std::__exchange(__polyfunc::__invoker_of(__f), nullptr);
+ }
+ }
+
+ /// Stores a target object initialized from the arguments.
+ template<typename _Tp, typename... _Args>
+ requires is_constructible_v<_Tp, _Args...>
+ && __is_callable_from<_Tp>
+ explicit
+ copyable_function(in_place_type_t<_Tp>, _Args&&... __args)
+ noexcept(_S_nothrow_init<_Tp, _Args...>())
+ : _M_invoke(_Invoker::template _S_storage<_Tp _GLIBCXX_MOF_INV_QUALS>())
+ {
+ static_assert(is_same_v<decay_t<_Tp>, _Tp>);
+ static_assert(is_copy_constructible_v<_Tp>);
+ _M_init<_Tp>(std::forward<_Args>(__args)...);
+ }
+
+ /// Stores a target object initialized from the arguments.
+ template<typename _Tp, typename _Up, typename... _Args>
+ requires is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>
+ && __is_callable_from<_Tp>
+ explicit
+ copyable_function(in_place_type_t<_Tp>, initializer_list<_Up> __il,
+ _Args&&... __args)
+ noexcept(_S_nothrow_init<_Tp, initializer_list<_Up>&, _Args...>())
+ : _M_invoke(_Invoker::template _S_storage<_Tp _GLIBCXX_MOF_INV_QUALS>())
+ {
+ static_assert(is_same_v<decay_t<_Tp>, _Tp>);
+ static_assert(is_copy_constructible_v<_Tp>);
+ _M_init<_Tp>(__il, std::forward<_Args>(__args)...);
+ }
+
+ /// Stores a new target object, leaving `x` empty.
+ copyable_function&
+ operator=(copyable_function&& __x) noexcept
+ {
+ // Standard requires support of self assigment, by specifying it as
+ // copy and swap.
+ if (this != std::addressof(__x)) [[likely]]
+ {
+ _Base::operator=(static_cast<_Base&&>(__x));
+ _M_invoke = std::__exchange(__x._M_invoke, nullptr);
+ }
+ return *this;
+ }
+
+ /// Stores a copy of the source target object
+ copyable_function&
+ operator=(const copyable_function& __x)
+ {
+ copyable_function(__x).swap(*this);
+ return *this;
+ }
+
+ /// Destroys the target object (if any).
+ copyable_function&
+ operator=(nullptr_t) noexcept
+ {
+ _M_reset();
+ _M_invoke = nullptr;
+ return *this;
+ }
+
+ /// Stores a new target object, initialized from the argument.
+ template<typename _Fn>
+ requires is_constructible_v<copyable_function, _Fn>
+ copyable_function&
+ operator=(_Fn&& __f)
+ noexcept(is_nothrow_constructible_v<copyable_function, _Fn>)
+ {
+ copyable_function(std::forward<_Fn>(__f)).swap(*this);
+ return *this;
+ }
+
+ ~copyable_function() = default;
+
+ /// True if a target object is present, false otherwise.
+ explicit operator bool() const noexcept
+ { return _M_invoke != nullptr; }
+
+ /** Invoke the target object.
+ *
+ * The target object will be invoked using the supplied arguments,
+ * and as an lvalue or rvalue, and as const or non-const, as dictated
+ * by the template arguments of the `copyable_function` specialization.
+ *
+ * @pre Must not be empty.
+ */
+ _Res
+ operator()(_ArgTypes... __args) _GLIBCXX_MOF_CV_REF noexcept(_Noex)
+ {
+ __glibcxx_assert(*this != nullptr);
+ return _M_invoke(this->_M_storage, std::forward<_ArgTypes>(__args)...);
+ }
+
+ /// Exchange the target objects (if any).
+ void
+ swap(copyable_function& __x) noexcept
+ {
+ _Base::swap(__x);
+ std::swap(_M_invoke, __x._M_invoke);
+ }
+
+ /// Exchange the target objects (if any).
+ friend void
+ swap(copyable_function& __x, copyable_function& __y) noexcept
+ { __x.swap(__y); }
+
+ /// Check for emptiness by comparing with `nullptr`.
+ friend bool
+ operator==(const copyable_function& __x, nullptr_t) noexcept
+ { return __x._M_invoke == nullptr; }
+
+ private:
+ typename _Invoker::__storage_func_t _M_invoke = nullptr;
+
+ template<typename _Func>
+ friend auto&
+ __polyfunc::__invoker_of(_Func&) noexcept;
+
+ template<typename _Func>
+ friend auto&
+ __polyfunc::__base_of(_Func&) noexcept;
+
+ template<typename _Dst, typename _Src>
+ friend consteval bool
+ __polyfunc::__is_invoker_convertible() noexcept;
+ };
+
+#undef _GLIBCXX_MOF_CV_REF
+#undef _GLIBCXX_MOF_CV
+#undef _GLIBCXX_MOF_REF
+#undef _GLIBCXX_MOF_INV_QUALS
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
diff --git a/libstdc++-v3/include/bits/funcwrap.h b/libstdc++-v3/include/bits/funcwrap.h
new file mode 100644
index 0000000..4e05353
--- /dev/null
+++ b/libstdc++-v3/include/bits/funcwrap.h
@@ -0,0 +1,507 @@
+// Implementation of std::move_only_function and std::copyable_function -*- C++ -*-
+
+// Copyright The GNU Toolchain Authors.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/bits/funcwrap.h
+ * This is an internal header file, included by other library headers.
+ * Do not attempt to use it directly. @headername{functional}
+ */
+
+#ifndef _GLIBCXX_FUNCWRAP_H
+#define _GLIBCXX_FUNCWRAP_H 1
+
+#ifdef _GLIBCXX_SYSHDR
+#pragma GCC system_header
+#endif
+
+#include <bits/version.h>
+
+#if defined(__glibcxx_move_only_function) || defined(__glibcxx_copyable_function)
+
+#include <bits/invoke.h>
+#include <bits/utility.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ /// @cond undocumented
+ template<typename _Tp>
+ inline constexpr bool __is_polymorphic_function_v = false;
+
+ namespace __polyfunc
+ {
+ union _Ptrs
+ {
+ void* _M_obj;
+ void (*_M_func)();
+ };
+
+ struct _Storage
+ {
+ void* _M_addr() noexcept { return &_M_bytes[0]; }
+ void const* _M_addr() const noexcept { return &_M_bytes[0]; }
+
+ template<typename _Tp>
+ static consteval bool
+ _S_stored_locally() noexcept
+ {
+ return sizeof(_Tp) <= sizeof(_Storage)
+ && alignof(_Tp) <= alignof(_Storage)
+ && is_nothrow_move_constructible_v<_Tp>;
+ }
+
+ template<typename _Tp, typename... _Args>
+ static consteval bool
+ _S_nothrow_init() noexcept
+ {
+ if constexpr (_S_stored_locally<_Tp>())
+ return is_nothrow_constructible_v<_Tp, _Args...>;
+ return false;
+ }
+
+ template<typename _Tp, typename... _Args>
+ void
+ _M_init(_Args&&... __args) noexcept(_S_nothrow_init<_Tp, _Args...>())
+ {
+ if constexpr (is_function_v<remove_pointer_t<_Tp>>)
+ {
+ static_assert( sizeof...(__args) <= 1 );
+ // __args can have up to one element, returns nullptr if empty.
+ _Tp __func = (nullptr, ..., __args);
+ _M_ptrs._M_func = reinterpret_cast<void(*)()>(__func);
+ }
+ else if constexpr (!_S_stored_locally<_Tp>())
+ _M_ptrs._M_obj = new _Tp(std::forward<_Args>(__args)...);
+ else
+ ::new (_M_addr()) _Tp(std::forward<_Args>(__args)...);
+ }
+
+ template<typename _Tp>
+ [[__gnu__::__always_inline__]]
+ _Tp*
+ _M_ptr() const noexcept
+ {
+ if constexpr (!_S_stored_locally<remove_const_t<_Tp>>())
+ return static_cast<_Tp*>(_M_ptrs._M_obj);
+ else if constexpr (is_const_v<_Tp>)
+ return static_cast<_Tp*>(_M_addr());
+ else
+ // _Manager and _Invoker pass _Storage by const&, even for mutable sources.
+ return static_cast<_Tp*>(const_cast<void*>(_M_addr()));
+ }
+
+ template<typename _Ref>
+ [[__gnu__::__always_inline__]]
+ _Ref
+ _M_ref() const noexcept
+ {
+ using _Tp = remove_reference_t<_Ref>;
+ if constexpr (is_function_v<remove_pointer_t<_Tp>>)
+ return reinterpret_cast<_Tp>(_M_ptrs._M_func);
+ else
+ return static_cast<_Ref>(*_M_ptr<_Tp>());
+ }
+
+ // We want to have enough space to store a simple delegate type.
+ struct _Delegate { void (_Storage::*__pfm)(); _Storage* __obj; };
+ union {
+ _Ptrs _M_ptrs;
+ alignas(_Delegate) alignas(void(*)())
+ unsigned char _M_bytes[sizeof(_Delegate)];
+ };
+ };
+
+ template<bool _Noex, typename _Ret, typename... _Args>
+ struct _Base_invoker
+ {
+ using _Signature = _Ret(*)(_Args...) noexcept(_Noex);
+
+ using __storage_func_t = _Ret(*)(const _Storage&, _Args...) noexcept(_Noex);
+ template<typename _Tp>
+ static consteval __storage_func_t
+ _S_storage()
+ { return &_S_call_storage<_Adjust_target<_Tp>>; }
+
+ private:
+ template<typename _Tp, typename _Td = remove_cvref_t<_Tp>>
+ using _Adjust_target =
+ __conditional_t<is_pointer_v<_Td> || is_member_pointer_v<_Td>, _Td, _Tp>;
+
+ template<typename _Tp>
+ static _Ret
+ _S_call_storage(const _Storage& __ref, _Args... __args) noexcept(_Noex)
+ {
+ return std::__invoke_r<_Ret>(__ref._M_ref<_Tp>(),
+ std::forward<_Args>(__args)...);
+ }
+ };
+
+ template<typename _Tp>
+ using __param_t = __conditional_t<is_scalar_v<_Tp>, _Tp, _Tp&&>;
+
+ template<bool _Noex, typename _Ret, typename... _Args>
+ using _Invoker = _Base_invoker<_Noex, remove_cv_t<_Ret>, __param_t<_Args>...>;
+
+ template<typename _Func>
+ auto&
+ __invoker_of(_Func& __f) noexcept
+ { return __f._M_invoke; }
+
+ template<typename _Func>
+ auto&
+ __base_of(_Func& __f) noexcept
+ { return static_cast<__like_t<_Func&, typename _Func::_Base>>(__f); }
+
+ template<typename _Src, typename _Dst>
+ consteval bool
+ __is_invoker_convertible() noexcept
+ {
+ if constexpr (requires { typename _Src::_Signature; })
+ return is_convertible_v<typename _Src::_Signature,
+ typename _Dst::_Signature>;
+ else
+ return false;
+ }
+
+ struct _Manager
+ {
+ enum class _Op
+ {
+ // saves address of entity in *__src to __target._M_ptrs,
+ _Address,
+ // moves entity stored in *__src to __target, __src becomes empty
+ _Move,
+ // copies entity stored in *__src to __target, supported only if
+ // _ProvideCopy is specified.
+ _Copy,
+ // destroys entity stored in __target, __src is ignoring
+ _Destroy,
+ };
+
+ // A function that performs operation __op on the __target and possibly __src.
+ using _Func = void (*)(_Op __op, _Storage& __target, const _Storage* __src);
+
+ // The no-op manager function for objects with no target.
+ static void _S_empty(_Op, _Storage&, const _Storage*) noexcept { }
+
+ template<bool _ProvideCopy, typename _Tp>
+ consteval static auto
+ _S_select()
+ {
+ if constexpr (is_function_v<remove_pointer_t<_Tp>>)
+ return &_S_func;
+ else if constexpr (!_Storage::_S_stored_locally<_Tp>())
+ return &_S_ptr<_ProvideCopy, _Tp>;
+ else if constexpr (is_trivially_copyable_v<_Tp>)
+ return &_S_trivial;
+ else
+ return &_S_local<_ProvideCopy, _Tp>;
+ }
+
+ private:
+ static void
+ _S_func(_Op __op, _Storage& __target, const _Storage* __src) noexcept
+ {
+ switch (__op)
+ {
+ case _Op::_Address:
+ case _Op::_Move:
+ case _Op::_Copy:
+ __target._M_ptrs._M_func = __src->_M_ptrs._M_func;
+ return;
+ case _Op::_Destroy:
+ return;
+ }
+ }
+
+ static void
+ _S_trivial(_Op __op, _Storage& __target, const _Storage* __src) noexcept
+ {
+ switch (__op)
+ {
+ case _Op::_Address:
+ __target._M_ptrs._M_obj = const_cast<void*>(__src->_M_addr());
+ return;
+ case _Op::_Move:
+ case _Op::_Copy:
+ // N.B. Creating _Storage starts lifetime of _M_bytes char array,
+ // that implicitly creates, amongst other, all possible trivially
+ // copyable objects, so we copy any object present in __src._M_bytes.
+ ::new (&__target) _Storage(*__src);
+ return;
+ case _Op::_Destroy:
+ return;
+ }
+ }
+
+ template<bool _Provide_copy, typename _Tp>
+ static void
+ _S_local(_Op __op, _Storage& __target, const _Storage* __src)
+ noexcept(!_Provide_copy)
+ {
+ switch (__op)
+ {
+ case _Op::_Address:
+ __target._M_ptrs._M_obj = __src->_M_ptr<_Tp>();
+ return;
+ case _Op::_Move:
+ {
+ _Tp* __obj = __src->_M_ptr<_Tp>();
+ ::new(__target._M_addr()) _Tp(std::move(*__obj));
+ __obj->~_Tp();
+ }
+ return;
+ case _Op::_Destroy:
+ __target._M_ptr<_Tp>()->~_Tp();
+ return;
+ case _Op::_Copy:
+ if constexpr (_Provide_copy)
+ ::new (__target._M_addr()) _Tp(__src->_M_ref<const _Tp&>());
+ else
+ __builtin_unreachable();
+ return;
+ }
+ }
+
+ template<bool _Provide_copy, typename _Tp>
+ static void
+ _S_ptr(_Op __op, _Storage& __target, const _Storage* __src)
+ noexcept(!_Provide_copy)
+ {
+ switch (__op)
+ {
+ case _Op::_Address:
+ case _Op::_Move:
+ __target._M_ptrs._M_obj = __src->_M_ptrs._M_obj;
+ return;
+ case _Op::_Destroy:
+ delete __target._M_ptr<_Tp>();
+ return;
+ case _Op::_Copy:
+ if constexpr (_Provide_copy)
+ __target._M_ptrs._M_obj = new _Tp(__src->_M_ref<const _Tp&>());
+ else
+ __builtin_unreachable();
+ return;
+ }
+ }
+ };
+
+ class _Mo_base
+ {
+ protected:
+ _Mo_base() noexcept
+ : _M_manage(_Manager::_S_empty)
+ { }
+
+ _Mo_base(_Mo_base&& __x) noexcept
+ { _M_move(__x); }
+
+ template<typename _Tp, typename... _Args>
+ static consteval bool
+ _S_nothrow_init() noexcept
+ { return _Storage::_S_nothrow_init<_Tp, _Args...>(); }
+
+ template<typename _Tp, typename... _Args>
+ void
+ _M_init(_Args&&... __args)
+ noexcept(_S_nothrow_init<_Tp, _Args...>())
+ {
+ _M_storage._M_init<_Tp>(std::forward<_Args>(__args)...);
+ _M_manage = _Manager::_S_select<false, _Tp>();
+ }
+
+ void
+ _M_move(_Mo_base& __x) noexcept
+ {
+ using _Op = _Manager::_Op;
+ _M_manage = std::__exchange(__x._M_manage, _Manager::_S_empty);
+ _M_manage(_Op::_Move, _M_storage, &__x._M_storage);
+ }
+
+ _Mo_base&
+ operator=(_Mo_base&& __x) noexcept
+ {
+ _M_destroy();
+ _M_move(__x);
+ return *this;
+ }
+
+ void
+ _M_reset() noexcept
+ {
+ _M_destroy();
+ _M_manage = _Manager::_S_empty;
+ }
+
+ ~_Mo_base()
+ { _M_destroy(); }
+
+ void
+ swap(_Mo_base& __x) noexcept
+ {
+ using _Op = _Manager::_Op;
+ // Order of operations here is more efficient if __x is empty.
+ _Storage __s;
+ __x._M_manage(_Op::_Move, __s, &__x._M_storage);
+ _M_manage(_Op::_Move, __x._M_storage, &_M_storage);
+ __x._M_manage(_Op::_Move, _M_storage, &__s);
+ std::swap(_M_manage, __x._M_manage);
+ }
+
+ _Storage _M_storage;
+
+ private:
+ void _M_destroy() noexcept
+ { _M_manage(_Manager::_Op::_Destroy, _M_storage, nullptr); }
+
+ _Manager::_Func _M_manage;
+
+#ifdef __glibcxx_copyable_function // C++ >= 26 && HOSTED
+ friend class _Cpy_base;
+#endif // __glibcxx_copyable_function
+ };
+
+} // namespace __polyfunc
+ /// @endcond
+
+#ifdef __glibcxx_move_only_function // C++ >= 23 && HOSTED
+ template<typename... _Signature>
+ class move_only_function; // not defined
+
+ /// @cond undocumented
+ template<typename _Tp>
+ constexpr bool __is_polymorphic_function_v<move_only_function<_Tp>> = true;
+
+ namespace __detail::__variant
+ {
+ template<typename> struct _Never_valueless_alt; // see <variant>
+
+ // Provide the strong exception-safety guarantee when emplacing a
+ // move_only_function into a variant.
+ template<typename... _Signature>
+ struct _Never_valueless_alt<std::move_only_function<_Signature...>>
+ : true_type
+ { };
+ } // namespace __detail::__variant
+ /// @endcond
+#endif // __glibcxx_move_only_function
+
+#ifdef __glibcxx_copyable_function // C++ >= 26 && HOSTED
+ /// @cond undocumented
+ namespace __polyfunc
+ {
+ class _Cpy_base : public _Mo_base
+ {
+ protected:
+ _Cpy_base() = default;
+
+ template<typename _Tp, typename... _Args>
+ void
+ _M_init(_Args&&... __args)
+ noexcept(_S_nothrow_init<_Tp, _Args...>())
+ {
+ _M_storage._M_init<_Tp>(std::forward<_Args>(__args)...);
+ _M_manage = _Manager::_S_select<true, _Tp>();
+ }
+
+ void
+ _M_copy(_Cpy_base const& __x)
+ {
+ using _Op = _Manager::_Op;
+ __x._M_manage(_Op::_Copy, _M_storage, &__x._M_storage);
+ _M_manage = __x._M_manage;
+ }
+
+ _Cpy_base(_Cpy_base&&) = default;
+
+ _Cpy_base(_Cpy_base const& __x)
+ { _M_copy(__x); }
+
+ _Cpy_base&
+ operator=(_Cpy_base&&) = default;
+
+ _Cpy_base&
+ // Needs to use copy and swap for exception guarantees.
+ operator=(_Cpy_base const&) = delete;
+ };
+ } // namespace __polyfunc
+ /// @endcond
+
+ template<typename... _Signature>
+ class copyable_function; // not defined
+
+ template<typename _Tp>
+ constexpr bool __is_polymorphic_function_v<copyable_function<_Tp>> = true;
+
+ namespace __detail::__variant
+ {
+ template<typename> struct _Never_valueless_alt; // see <variant>
+
+ // Provide the strong exception-safety guarantee when emplacing a
+ // copyable_function into a variant.
+ template<typename... _Signature>
+ struct _Never_valueless_alt<std::copyable_function<_Signature...>>
+ : true_type
+ { };
+ } // namespace __detail::__variant
+#endif // __glibcxx_copyable_function
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#ifdef __glibcxx_move_only_function // C++ >= 23 && HOSTED
+#include "mofunc_impl.h"
+#define _GLIBCXX_MOF_CV const
+#include "mofunc_impl.h"
+#define _GLIBCXX_MOF_REF &
+#include "mofunc_impl.h"
+#define _GLIBCXX_MOF_REF &&
+#include "mofunc_impl.h"
+#define _GLIBCXX_MOF_CV const
+#define _GLIBCXX_MOF_REF &
+#include "mofunc_impl.h"
+#define _GLIBCXX_MOF_CV const
+#define _GLIBCXX_MOF_REF &&
+#include "mofunc_impl.h"
+#endif // __glibcxx_move_only_function
+
+#ifdef __glibcxx_copyable_function // C++ >= 26 && HOSTED
+#include "cpyfunc_impl.h"
+#define _GLIBCXX_MOF_CV const
+#include "cpyfunc_impl.h"
+#define _GLIBCXX_MOF_REF &
+#include "cpyfunc_impl.h"
+#define _GLIBCXX_MOF_REF &&
+#include "cpyfunc_impl.h"
+#define _GLIBCXX_MOF_CV const
+#define _GLIBCXX_MOF_REF &
+#include "cpyfunc_impl.h"
+#define _GLIBCXX_MOF_CV const
+#define _GLIBCXX_MOF_REF &&
+#include "cpyfunc_impl.h"
+#endif // __glibcxx_copyable_function
+
+#endif // __glibcxx_copyable_function || __glibcxx_copyable_function
+#endif // _GLIBCXX_FUNCWRAP_H
diff --git a/libstdc++-v3/include/bits/mofunc_impl.h b/libstdc++-v3/include/bits/mofunc_impl.h
index 318a55e..1ceb910 100644
--- a/libstdc++-v3/include/bits/mofunc_impl.h
+++ b/libstdc++-v3/include/bits/mofunc_impl.h
@@ -62,8 +62,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Res, typename... _ArgTypes, bool _Noex>
class move_only_function<_Res(_ArgTypes...) _GLIBCXX_MOF_CV
_GLIBCXX_MOF_REF noexcept(_Noex)>
- : _Mofunc_base
+ : __polyfunc::_Mo_base
{
+ using _Base = __polyfunc::_Mo_base;
+ using _Invoker = __polyfunc::_Invoker<_Noex, _Res, _ArgTypes...>;
+ using _Signature = _Invoker::_Signature;
+
template<typename _Tp>
using __callable
= __conditional_t<_Noex,
@@ -87,7 +91,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// Moves the target object, leaving the source empty.
move_only_function(move_only_function&& __x) noexcept
- : _Mofunc_base(static_cast<_Mofunc_base&&>(__x)),
+ : _Base(static_cast<_Base&&>(__x)),
_M_invoke(std::__exchange(__x._M_invoke, nullptr))
{ }
@@ -97,15 +101,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
&& (!__is_in_place_type_v<_Vt>) && __is_callable_from<_Vt>
move_only_function(_Fn&& __f) noexcept(_S_nothrow_init<_Vt, _Fn>())
{
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4255. move_only_function constructor should recognize empty
+ // copyable_functions
if constexpr (is_function_v<remove_pointer_t<_Vt>>
|| is_member_pointer_v<_Vt>
- || __is_move_only_function_v<_Vt>)
+ || __is_polymorphic_function_v<_Vt>)
{
if (__f == nullptr)
return;
}
- _M_init<_Vt>(std::forward<_Fn>(__f));
- _M_invoke = &_S_invoke<_Vt>;
+
+ if constexpr (__is_polymorphic_function_v<_Vt>
+ && __polyfunc::__is_invoker_convertible<_Vt, move_only_function>())
+ {
+ // Handle cases where _Fn is const reference to copyable_function,
+ // by firstly creating temporary and moving from it.
+ _Vt __tmp(std::forward<_Fn>(__f));
+ _M_move(__polyfunc::__base_of(__tmp));
+ _M_invoke = std::__exchange(__polyfunc::__invoker_of(__tmp), nullptr);
+ }
+ else
+ {
+ _M_init<_Vt>(std::forward<_Fn>(__f));
+ _M_invoke = _Invoker::template _S_storage<_Vt _GLIBCXX_MOF_INV_QUALS>();
+ }
}
/// Stores a target object initialized from the arguments.
@@ -115,7 +135,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
explicit
move_only_function(in_place_type_t<_Tp>, _Args&&... __args)
noexcept(_S_nothrow_init<_Tp, _Args...>())
- : _M_invoke(&_S_invoke<_Tp>)
+ : _M_invoke(_Invoker::template _S_storage<_Tp _GLIBCXX_MOF_INV_QUALS>())
{
static_assert(is_same_v<decay_t<_Tp>, _Tp>);
_M_init<_Tp>(std::forward<_Args>(__args)...);
@@ -129,7 +149,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
move_only_function(in_place_type_t<_Tp>, initializer_list<_Up> __il,
_Args&&... __args)
noexcept(_S_nothrow_init<_Tp, initializer_list<_Up>&, _Args...>())
- : _M_invoke(&_S_invoke<_Tp>)
+ : _M_invoke(_Invoker::template _S_storage<_Tp _GLIBCXX_MOF_INV_QUALS>())
{
static_assert(is_same_v<decay_t<_Tp>, _Tp>);
_M_init<_Tp>(__il, std::forward<_Args>(__args)...);
@@ -139,8 +159,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
move_only_function&
operator=(move_only_function&& __x) noexcept
{
- _Mofunc_base::operator=(static_cast<_Mofunc_base&&>(__x));
- _M_invoke = std::__exchange(__x._M_invoke, nullptr);
+ // Standard requires support of self assigment, by specifying it as
+ // copy and swap.
+ if (this != std::addressof(__x)) [[likely]]
+ {
+ _Base::operator=(static_cast<_Base&&>(__x));
+ _M_invoke = std::__exchange(__x._M_invoke, nullptr);
+ }
return *this;
}
@@ -148,7 +173,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
move_only_function&
operator=(nullptr_t) noexcept
{
- _Mofunc_base::operator=(nullptr);
+ _M_reset();
_M_invoke = nullptr;
return *this;
}
@@ -167,7 +192,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
~move_only_function() = default;
/// True if a target object is present, false otherwise.
- explicit operator bool() const noexcept { return _M_invoke != nullptr; }
+ explicit operator bool() const noexcept
+ { return _M_invoke != nullptr; }
/** Invoke the target object.
*
@@ -181,14 +207,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
operator()(_ArgTypes... __args) _GLIBCXX_MOF_CV_REF noexcept(_Noex)
{
__glibcxx_assert(*this != nullptr);
- return _M_invoke(this, std::forward<_ArgTypes>(__args)...);
+ return _M_invoke(this->_M_storage, std::forward<_ArgTypes>(__args)...);
}
/// Exchange the target objects (if any).
void
swap(move_only_function& __x) noexcept
{
- _Mofunc_base::swap(__x);
+ _Base::swap(__x);
std::swap(_M_invoke, __x._M_invoke);
}
@@ -203,25 +229,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return __x._M_invoke == nullptr; }
private:
- template<typename _Tp>
- using __param_t = __conditional_t<is_scalar_v<_Tp>, _Tp, _Tp&&>;
+ typename _Invoker::__storage_func_t _M_invoke = nullptr;
- using _Invoker = _Res (*)(_Mofunc_base _GLIBCXX_MOF_CV*,
- __param_t<_ArgTypes>...) noexcept(_Noex);
+ template<typename _Func>
+ friend auto&
+ __polyfunc::__invoker_of(_Func&) noexcept;
- template<typename _Tp>
- static _Res
- _S_invoke(_Mofunc_base _GLIBCXX_MOF_CV* __self,
- __param_t<_ArgTypes>... __args) noexcept(_Noex)
- {
- using _TpCv = _Tp _GLIBCXX_MOF_CV;
- using _TpInv = _Tp _GLIBCXX_MOF_INV_QUALS;
- return std::__invoke_r<_Res>(
- std::forward<_TpInv>(*_S_access<_TpCv>(__self)),
- std::forward<__param_t<_ArgTypes>>(__args)...);
- }
+ template<typename _Func>
+ friend auto&
+ __polyfunc::__base_of(_Func&) noexcept;
- _Invoker _M_invoke = nullptr;
+ template<typename _Dst, typename _Src>
+ friend consteval bool
+ __polyfunc::__is_invoker_convertible() noexcept;
};
#undef _GLIBCXX_MOF_CV_REF
diff --git a/libstdc++-v3/include/bits/move_only_function.h b/libstdc++-v3/include/bits/move_only_function.h
deleted file mode 100644
index 42b33d0..0000000
--- a/libstdc++-v3/include/bits/move_only_function.h
+++ /dev/null
@@ -1,218 +0,0 @@
-// Implementation of std::move_only_function -*- C++ -*-
-
-// Copyright The GNU Toolchain Authors.
-//
-// This file is part of the GNU ISO C++ Library. This library is free
-// software; you can redistribute it and/or modify it under the
-// terms of the GNU General Public License as published by the
-// Free Software Foundation; either version 3, or (at your option)
-// any later version.
-
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// Under Section 7 of GPL version 3, you are granted additional
-// permissions described in the GCC Runtime Library Exception, version
-// 3.1, as published by the Free Software Foundation.
-
-// You should have received a copy of the GNU General Public License and
-// a copy of the GCC Runtime Library Exception along with this program;
-// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
-// <http://www.gnu.org/licenses/>.
-
-/** @file include/bits/move_only_function.h
- * This is an internal header file, included by other library headers.
- * Do not attempt to use it directly. @headername{functional}
- */
-
-#ifndef _GLIBCXX_MOVE_ONLY_FUNCTION_H
-#define _GLIBCXX_MOVE_ONLY_FUNCTION_H 1
-
-#ifdef _GLIBCXX_SYSHDR
-#pragma GCC system_header
-#endif
-
-#include <bits/version.h>
-
-#ifdef __glibcxx_move_only_function // C++ >= 23 && HOSTED
-
-#include <bits/invoke.h>
-#include <bits/utility.h>
-
-namespace std _GLIBCXX_VISIBILITY(default)
-{
-_GLIBCXX_BEGIN_NAMESPACE_VERSION
-
- template<typename... _Signature>
- class move_only_function; // not defined
-
- /// @cond undocumented
- class _Mofunc_base
- {
- protected:
- _Mofunc_base() noexcept
- : _M_manage(_S_empty)
- { }
-
- _Mofunc_base(_Mofunc_base&& __x) noexcept
- {
- _M_manage = std::__exchange(__x._M_manage, _S_empty);
- _M_manage(_M_storage, &__x._M_storage);
- }
-
- template<typename _Tp, typename... _Args>
- static constexpr bool
- _S_nothrow_init() noexcept
- {
- if constexpr (__stored_locally<_Tp>)
- return is_nothrow_constructible_v<_Tp, _Args...>;
- return false;
- }
-
- template<typename _Tp, typename... _Args>
- void
- _M_init(_Args&&... __args) noexcept(_S_nothrow_init<_Tp, _Args...>())
- {
- if constexpr (__stored_locally<_Tp>)
- ::new (_M_storage._M_addr()) _Tp(std::forward<_Args>(__args)...);
- else
- _M_storage._M_p = new _Tp(std::forward<_Args>(__args)...);
-
- _M_manage = &_S_manage<_Tp>;
- }
-
- _Mofunc_base&
- operator=(_Mofunc_base&& __x) noexcept
- {
- _M_manage(_M_storage, nullptr);
- _M_manage = std::__exchange(__x._M_manage, _S_empty);
- _M_manage(_M_storage, &__x._M_storage);
- return *this;
- }
-
- _Mofunc_base&
- operator=(nullptr_t) noexcept
- {
- _M_manage(_M_storage, nullptr);
- _M_manage = _S_empty;
- return *this;
- }
-
- ~_Mofunc_base() { _M_manage(_M_storage, nullptr); }
-
- void
- swap(_Mofunc_base& __x) noexcept
- {
- // Order of operations here is more efficient if __x is empty.
- _Storage __s;
- __x._M_manage(__s, &__x._M_storage);
- _M_manage(__x._M_storage, &_M_storage);
- __x._M_manage(_M_storage, &__s);
- std::swap(_M_manage, __x._M_manage);
- }
-
- template<typename _Tp, typename _Self>
- static _Tp*
- _S_access(_Self* __self) noexcept
- {
- if constexpr (__stored_locally<remove_const_t<_Tp>>)
- return static_cast<_Tp*>(__self->_M_storage._M_addr());
- else
- return static_cast<_Tp*>(__self->_M_storage._M_p);
- }
-
- private:
- struct _Storage
- {
- void* _M_addr() noexcept { return &_M_bytes[0]; }
- const void* _M_addr() const noexcept { return &_M_bytes[0]; }
-
- // We want to have enough space to store a simple delegate type.
- struct _Delegate { void (_Storage::*__pfm)(); _Storage* __obj; };
- union {
- void* _M_p;
- alignas(_Delegate) alignas(void(*)())
- unsigned char _M_bytes[sizeof(_Delegate)];
- };
- };
-
- template<typename _Tp>
- static constexpr bool __stored_locally
- = sizeof(_Tp) <= sizeof(_Storage) && alignof(_Tp) <= alignof(_Storage)
- && is_nothrow_move_constructible_v<_Tp>;
-
- // A function that either destroys the target object stored in __target,
- // or moves the target object from *__src to __target.
- using _Manager = void (*)(_Storage& __target, _Storage* __src) noexcept;
-
- // The no-op manager function for objects with no target.
- static void _S_empty(_Storage&, _Storage*) noexcept { }
-
- // The real manager function for a target object of type _Tp.
- template<typename _Tp>
- static void
- _S_manage(_Storage& __target, _Storage* __src) noexcept
- {
- if constexpr (__stored_locally<_Tp>)
- {
- if (__src)
- {
- _Tp* __rval = static_cast<_Tp*>(__src->_M_addr());
- ::new (__target._M_addr()) _Tp(std::move(*__rval));
- __rval->~_Tp();
- }
- else
- static_cast<_Tp*>(__target._M_addr())->~_Tp();
- }
- else
- {
- if (__src)
- __target._M_p = __src->_M_p;
- else
- delete static_cast<_Tp*>(__target._M_p);
- }
- }
-
- _Storage _M_storage;
- _Manager _M_manage;
- };
-
- template<typename _Tp>
- inline constexpr bool __is_move_only_function_v = false;
- template<typename _Tp>
- constexpr bool __is_move_only_function_v<move_only_function<_Tp>> = true;
- /// @endcond
-
- namespace __detail::__variant
- {
- template<typename> struct _Never_valueless_alt; // see <variant>
-
- // Provide the strong exception-safety guarantee when emplacing a
- // move_only_function into a variant.
- template<typename... _Signature>
- struct _Never_valueless_alt<std::move_only_function<_Signature...>>
- : true_type
- { };
- } // namespace __detail::__variant
-
-_GLIBCXX_END_NAMESPACE_VERSION
-} // namespace std
-
-#include "mofunc_impl.h"
-#define _GLIBCXX_MOF_CV const
-#include "mofunc_impl.h"
-#define _GLIBCXX_MOF_REF &
-#include "mofunc_impl.h"
-#define _GLIBCXX_MOF_REF &&
-#include "mofunc_impl.h"
-#define _GLIBCXX_MOF_CV const
-#define _GLIBCXX_MOF_REF &
-#include "mofunc_impl.h"
-#define _GLIBCXX_MOF_CV const
-#define _GLIBCXX_MOF_REF &&
-#include "mofunc_impl.h"
-
-#endif // __glibcxx_move_only_function
-#endif // _GLIBCXX_MOVE_ONLY_FUNCTION_H
diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
index 2d34a8d..6ca148f 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1748,6 +1748,15 @@ ftms = {
};
ftms = {
+ name = copyable_function;
+ values = {
+ v = 202306;
+ cxxmin = 26;
+ hosted = yes;
+ };
+};
+
+ftms = {
name = out_ptr;
values = {
v = 202311;
diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
index 24831f7..48a090c 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -1948,6 +1948,16 @@
#endif /* !defined(__cpp_lib_move_only_function) && defined(__glibcxx_want_move_only_function) */
#undef __glibcxx_want_move_only_function
+#if !defined(__cpp_lib_copyable_function)
+# if (__cplusplus > 202302L) && _GLIBCXX_HOSTED
+# define __glibcxx_copyable_function 202306L
+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_copyable_function)
+# define __cpp_lib_copyable_function 202306L
+# endif
+# endif
+#endif /* !defined(__cpp_lib_copyable_function) && defined(__glibcxx_want_copyable_function) */
+#undef __glibcxx_want_copyable_function
+
#if !defined(__cpp_lib_out_ptr)
# if (__cplusplus >= 202100L)
# define __glibcxx_out_ptr 202311L
diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format
index b3192cf..f0b0252 100644
--- a/libstdc++-v3/include/std/format
+++ b/libstdc++-v3/include/std/format
@@ -1863,20 +1863,24 @@ namespace __format
_Spec<_CharT> _M_spec{};
};
+#ifdef __BFLT16_DIG__
+ using __bflt16_t = decltype(0.0bf16);
+#endif
+
// Decide how 128-bit floating-point types should be formatted (or not).
- // When supported, the typedef __format::__float128_t is the type that
- // format arguments should be converted to for storage in basic_format_arg.
+ // When supported, the typedef __format::__flt128_t is the type that format
+ // arguments should be converted to before passing them to __formatter_fp.
// Define the macro _GLIBCXX_FORMAT_F128 to say they're supported.
- // _GLIBCXX_FORMAT_F128=1 means __float128, _Float128 etc. will be formatted
- // by converting them to long double (or __ieee128 for powerpc64le).
- // _GLIBCXX_FORMAT_F128=2 means basic_format_arg needs to enable explicit
- // support for _Float128, rather than formatting it as another type.
+ // The __float128, _Float128 will be formatted by converting them to:
+ // __ieee128 (same as __float128) when _GLIBCXX_FORMAT_F128=1,
+ // long double when _GLIBCXX_FORMAT_F128=2,
+ // _Float128 when _GLIBCXX_FORMAT_F128=3.
#undef _GLIBCXX_FORMAT_F128
#ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
// Format 128-bit floating-point types using __ieee128.
- using __float128_t = __ieee128;
+ using __flt128_t = __ieee128;
# define _GLIBCXX_FORMAT_F128 1
#ifdef __LONG_DOUBLE_IEEE128__
@@ -1910,14 +1914,14 @@ namespace __format
#elif defined _GLIBCXX_LDOUBLE_IS_IEEE_BINARY128
// Format 128-bit floating-point types using long double.
- using __float128_t = long double;
-# define _GLIBCXX_FORMAT_F128 1
+ using __flt128_t = long double;
+# define _GLIBCXX_FORMAT_F128 2
#elif __FLT128_DIG__ && defined(_GLIBCXX_HAVE_FLOAT128_MATH)
// Format 128-bit floating-point types using _Float128.
- using __float128_t = _Float128;
-# define _GLIBCXX_FORMAT_F128 2
+ using __flt128_t = _Float128;
+# define _GLIBCXX_FORMAT_F128 3
# if __cplusplus == 202002L
// These overloads exist in the library, but are not declared for C++20.
@@ -2947,8 +2951,8 @@ namespace __format
};
#endif
-#if defined(__FLT128_DIG__) && _GLIBCXX_FORMAT_F128 == 1
- // Reuse __formatter_fp<C>::format<__float128_t, Out> for _Float128.
+#if defined(__FLT128_DIG__) && _GLIBCXX_FORMAT_F128
+ // Use __formatter_fp<C>::format<__format::__flt128_t, Out> for _Float128.
template<__format::__char _CharT>
struct formatter<_Float128, _CharT>
{
@@ -2962,17 +2966,45 @@ namespace __format
template<typename _Out>
typename basic_format_context<_Out, _CharT>::iterator
format(_Float128 __u, basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f.format((__format::__float128_t)__u, __fc); }
+ { return _M_f.format((__format::__flt128_t)__u, __fc); }
+
+ private:
+ __format::__formatter_fp<_CharT> _M_f;
+ };
+#endif
+
+#if defined(__SIZEOF_FLOAT128__) && _GLIBCXX_FORMAT_F128 != 1
+ // Reuse __formatter_fp<C>::format<__format::__flt128_t, Out> for __float128.
+ // This formatter is not declared if _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT is true,
+ // as __float128 when present is same type as __ieee128, which may be same as
+ // long double.
+ template<__format::__char _CharT>
+ struct formatter<__float128, _CharT>
+ {
+ formatter() = default;
+
+ [[__gnu__::__always_inline__]]
+ constexpr typename basic_format_parse_context<_CharT>::iterator
+ parse(basic_format_parse_context<_CharT>& __pc)
+ { return _M_f.parse(__pc); }
+
+ template<typename _Out>
+ typename basic_format_context<_Out, _CharT>::iterator
+ format(__float128 __u, basic_format_context<_Out, _CharT>& __fc) const
+ { return _M_f.format((__format::__flt128_t)__u, __fc); }
private:
__format::__formatter_fp<_CharT> _M_f;
+
+ static_assert( !is_same_v<__float128, long double>,
+ "This specialization should not be used for long double" );
};
#endif
#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
// Reuse __formatter_fp<C>::format<float, Out> for bfloat16_t.
template<__format::__char _CharT>
- struct formatter<__gnu_cxx::__bfloat16_t, _CharT>
+ struct formatter<__format::__bflt16_t, _CharT>
{
formatter() = default;
@@ -3835,16 +3867,14 @@ namespace __format
enum _Arg_t : unsigned char {
_Arg_none, _Arg_bool, _Arg_c, _Arg_i, _Arg_u, _Arg_ll, _Arg_ull,
_Arg_flt, _Arg_dbl, _Arg_ldbl, _Arg_str, _Arg_sv, _Arg_ptr, _Arg_handle,
- _Arg_i128, _Arg_u128,
- _Arg_bf16, _Arg_f16, _Arg_f32, _Arg_f64, // These are unused.
+ _Arg_i128, _Arg_u128, _Arg_float128,
+ _Arg_bf16, _Arg_f16, _Arg_f32, _Arg_f64,
+ _Arg_max_,
+
#ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
- _Arg_next_value_,
- _Arg_f128 = _Arg_ldbl,
- _Arg_ibm128 = _Arg_next_value_,
-#else
- _Arg_f128,
+ _Arg_ibm128 = _Arg_ldbl,
+ _Arg_ieee128 = _Arg_float128,
#endif
- _Arg_max_
};
template<typename _Context>
@@ -3871,6 +3901,12 @@ namespace __format
double _M_dbl;
#ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT // No long double if it's ambiguous.
long double _M_ldbl;
+#else
+ __ibm128 _M_ibm128;
+ __ieee128 _M_ieee128;
+#endif
+#ifdef __SIZEOF_FLOAT128__
+ __float128 _M_float128;
#endif
const _CharT* _M_str;
basic_string_view<_CharT> _M_sv;
@@ -3880,11 +3916,17 @@ namespace __format
__int128 _M_i128;
unsigned __int128 _M_u128;
#endif
-#ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
- __ieee128 _M_f128;
- __ibm128 _M_ibm128;
-#elif _GLIBCXX_FORMAT_F128 == 2
- __float128_t _M_f128;
+#ifdef __BFLT16_DIG__
+ __bflt16_t _M_bf16;
+#endif
+#ifdef __FLT16_DIG__
+ _Float16 _M_f16;
+#endif
+#ifdef __FLT32_DIG__
+ _Float32 _M_f32;
+#endif
+#ifdef __FLT64_DIG__
+ _Float64 _M_f64;
#endif
};
@@ -3922,10 +3964,14 @@ namespace __format
else if constexpr (is_same_v<_Tp, long double>)
return __u._M_ldbl;
#else
- else if constexpr (is_same_v<_Tp, __ieee128>)
- return __u._M_f128;
else if constexpr (is_same_v<_Tp, __ibm128>)
return __u._M_ibm128;
+ else if constexpr (is_same_v<_Tp, __ieee128>)
+ return __u._M_ieee128;
+#endif
+#ifdef __SIZEOF_FLOAT128__
+ else if constexpr (is_same_v<_Tp, __float128>)
+ return __u._M_float128;
#endif
else if constexpr (is_same_v<_Tp, const _CharT*>)
return __u._M_str;
@@ -3939,9 +3985,21 @@ namespace __format
else if constexpr (is_same_v<_Tp, unsigned __int128>)
return __u._M_u128;
#endif
-#if _GLIBCXX_FORMAT_F128 == 2
- else if constexpr (is_same_v<_Tp, __float128_t>)
- return __u._M_f128;
+#ifdef __BFLT16_DIG__
+ else if constexpr (is_same_v<_Tp, __bflt16_t>)
+ return __u._M_bf16;
+#endif
+#ifdef __FLT16_DIG__
+ else if constexpr (is_same_v<_Tp, _Float16>)
+ return __u._M_f16;
+#endif
+#ifdef __FLT32_DIG__
+ else if constexpr (is_same_v<_Tp, _Float32>)
+ return __u._M_f32;
+#endif
+#ifdef __FLT64_DIG__
+ else if constexpr (is_same_v<_Tp, _Float64>)
+ return __u._M_f64;
#endif
else if constexpr (derived_from<_Tp, _HandleBase>)
return static_cast<_Tp&>(__u._M_handle);
@@ -4120,36 +4178,25 @@ namespace __format
else if constexpr (is_same_v<_Td, __ieee128>)
return type_identity<__ieee128>();
#endif
-
-#if defined(__FLT16_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
- else if constexpr (is_same_v<_Td, _Float16>)
- return type_identity<float>();
+#if defined(__SIZEOF_FLOAT128__) && _GLIBCXX_FORMAT_F128
+ else if constexpr (is_same_v<_Td, __float128>)
+ return type_identity<__float128>();
#endif
-
-#if defined(__BFLT16_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
- else if constexpr (is_same_v<_Td, decltype(0.0bf16)>)
- return type_identity<float>();
+#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+ else if constexpr (is_same_v<_Td, __format::__bflt16_t>)
+ return type_identity<__format::__bflt16_t>();
+#endif
+#if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+ else if constexpr (is_same_v<_Td, _Float16>)
+ return type_identity<_Float16>();
#endif
-
#if defined(__FLT32_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
else if constexpr (is_same_v<_Td, _Float32>)
- return type_identity<float>();
+ return type_identity<_Float32>();
#endif
-
#if defined(__FLT64_DIG__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64)
else if constexpr (is_same_v<_Td, _Float64>)
- return type_identity<double>();
-#endif
-
-#if _GLIBCXX_FORMAT_F128
-# if __FLT128_DIG__
- else if constexpr (is_same_v<_Td, _Float128>)
- return type_identity<__format::__float128_t>();
-# endif
-# if __SIZEOF_FLOAT128__
- else if constexpr (is_same_v<_Td, __float128>)
- return type_identity<__format::__float128_t>();
-# endif
+ return type_identity<_Float64>();
#endif
else if constexpr (__is_specialization_of<_Td, basic_string_view>
|| __is_specialization_of<_Td, basic_string>)
@@ -4205,7 +4252,27 @@ namespace __format
else if constexpr (is_same_v<_Tp, __ibm128>)
return _Arg_ibm128;
else if constexpr (is_same_v<_Tp, __ieee128>)
- return _Arg_f128;
+ return _Arg_ieee128;
+#endif
+#if defined(__SIZEOF_FLOAT128__) && _GLIBCXX_FORMAT_F128
+ else if constexpr (is_same_v<_Tp, __float128>)
+ return _Arg_float128;
+#endif
+#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+ else if constexpr (is_same_v<_Tp, __format::__bflt16_t>)
+ return _Arg_bf16;
+#endif
+#if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+ else if constexpr (is_same_v<_Tp, _Float16>)
+ return _Arg_f16;
+#endif
+#if defined(__FLT32_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+ else if constexpr (is_same_v<_Tp, _Float32>)
+ return _Arg_f32;
+#endif
+#if defined(__FLT64_DIG__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64)
+ else if constexpr (is_same_v<_Tp, _Float64>)
+ return _Arg_f64;
#endif
else if constexpr (is_same_v<_Tp, const _CharT*>)
return _Arg_str;
@@ -4219,11 +4286,6 @@ namespace __format
else if constexpr (is_same_v<_Tp, unsigned __int128>)
return _Arg_u128;
#endif
-
-#if _GLIBCXX_FORMAT_F128 == 2
- else if constexpr (is_same_v<_Tp, __format::__float128_t>)
- return _Arg_f128;
-#endif
else if constexpr (is_same_v<_Tp, handle>)
return _Arg_handle;
}
@@ -4296,13 +4358,33 @@ namespace __format
#ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
case _Arg_ldbl:
return std::forward<_Visitor>(__vis)(_M_val._M_ldbl);
+#if defined(__SIZEOF_FLOAT128__) && _GLIBCXX_FORMAT_F128
+ case _Arg_float128:
+ return std::forward<_Visitor>(__vis)(_M_val._M_float128);
+#endif
#else
- case _Arg_f128:
- return std::forward<_Visitor>(__vis)(_M_val._M_f128);
case _Arg_ibm128:
return std::forward<_Visitor>(__vis)(_M_val._M_ibm128);
+ case _Arg_ieee128:
+ return std::forward<_Visitor>(__vis)(_M_val._M_ieee128);
#endif
+#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+ case _Arg_bf16:
+ return std::forward<_Visitor>(__vis)(_M_val._M_bf16);
+#endif
+#if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+ case _Arg_f16:
+ return std::forward<_Visitor>(__vis)(_M_val._M_f16);
+#endif
+#if defined(__FLT32_DIG__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+ case _Arg_f32:
+ return std::forward<_Visitor>(__vis)(_M_val._M_f32);
#endif
+#if defined(__FLT64_DIG__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64)
+ case _Arg_f64:
+ return std::forward<_Visitor>(__vis)(_M_val._M_f64);
+#endif
+#endif // __glibcxx_to_chars
case _Arg_str:
return std::forward<_Visitor>(__vis)(_M_val._M_str);
case _Arg_sv:
@@ -4320,14 +4402,7 @@ namespace __format
case _Arg_u128:
return std::forward<_Visitor>(__vis)(_M_val._M_u128);
#endif
-
-#if _GLIBCXX_FORMAT_F128 == 2
- case _Arg_f128:
- return std::forward<_Visitor>(__vis)(_M_val._M_f128);
-#endif
-
default:
- // _Arg_f16 etc.
__builtin_unreachable();
}
}
diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional
index 1077e96..9a55b18 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -52,6 +52,20 @@
#if __cplusplus >= 201103L
+#define __glibcxx_want_boyer_moore_searcher
+#define __glibcxx_want_bind_front
+#define __glibcxx_want_bind_back
+#define __glibcxx_want_constexpr_functional
+#define __glibcxx_want_copyable_function
+#define __glibcxx_want_invoke
+#define __glibcxx_want_invoke_r
+#define __glibcxx_want_move_only_function
+#define __glibcxx_want_not_fn
+#define __glibcxx_want_ranges
+#define __glibcxx_want_reference_wrapper
+#define __glibcxx_want_transparent_operators
+#include <bits/version.h>
+
#include <tuple>
#include <type_traits>
#include <bits/functional_hash.h>
@@ -72,23 +86,10 @@
# include <bits/ranges_cmp.h> // std::identity, ranges::equal_to etc.
# include <compare>
#endif
-#if __cplusplus > 202002L && _GLIBCXX_HOSTED
-# include <bits/move_only_function.h>
+#if defined(__glibcxx_move_only_function) || defined(__glibcxx_copyable_function)
+# include <bits/funcwrap.h>
#endif
-#define __glibcxx_want_boyer_moore_searcher
-#define __glibcxx_want_bind_front
-#define __glibcxx_want_bind_back
-#define __glibcxx_want_constexpr_functional
-#define __glibcxx_want_invoke
-#define __glibcxx_want_invoke_r
-#define __glibcxx_want_move_only_function
-#define __glibcxx_want_not_fn
-#define __glibcxx_want_ranges
-#define __glibcxx_want_reference_wrapper
-#define __glibcxx_want_transparent_operators
-#include <bits/version.h>
-
#endif // C++11
namespace std _GLIBCXX_VISIBILITY(default)
diff --git a/libstdc++-v3/include/std/utility b/libstdc++-v3/include/std/utility
index 1c15c75..8a85ccf 100644
--- a/libstdc++-v3/include/std/utility
+++ b/libstdc++-v3/include/std/utility
@@ -201,7 +201,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#ifdef __cpp_lib_to_underlying // C++ >= 23
/// Convert an object of enumeration type to its underlying type.
template<typename _Tp>
- [[nodiscard]]
+ [[nodiscard, __gnu__::__always_inline__]]
constexpr underlying_type_t<_Tp>
to_underlying(_Tp __value) noexcept
{ return static_cast<underlying_type_t<_Tp>>(__value); }
diff --git a/libstdc++-v3/src/c++23/std.cc.in b/libstdc++-v3/src/c++23/std.cc.in
index d45ae63..417c8a1 100644
--- a/libstdc++-v3/src/c++23/std.cc.in
+++ b/libstdc++-v3/src/c++23/std.cc.in
@@ -1412,6 +1412,9 @@ export namespace std
#if __cpp_lib_move_only_function
using std::move_only_function;
#endif
+#if __cpp_lib_copyable_function
+ using std::copyable_function;
+#endif
using std::multiplies;
using std::negate;
using std::not_equal_to;
diff --git a/libstdc++-v3/testsuite/20_util/copyable_function/call.cc b/libstdc++-v3/testsuite/20_util/copyable_function/call.cc
new file mode 100644
index 0000000..cf99757
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/copyable_function/call.cc
@@ -0,0 +1,224 @@
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+#include <functional>
+#include <utility>
+#include <testsuite_hooks.h>
+
+using std::copyable_function;
+
+using std::is_same_v;
+using std::is_invocable_v;
+using std::is_nothrow_invocable_v;
+using std::invoke_result_t;
+
+// Check return types
+static_assert( is_same_v<void, invoke_result_t<copyable_function<void()>>> );
+static_assert( is_same_v<int, invoke_result_t<copyable_function<int()>>> );
+static_assert( is_same_v<int&, invoke_result_t<copyable_function<int&()>>> );
+
+// With const qualifier
+static_assert( ! is_invocable_v< copyable_function<void()> const > );
+static_assert( ! is_invocable_v< copyable_function<void()> const &> );
+static_assert( is_invocable_v< copyable_function<void() const> > );
+static_assert( is_invocable_v< copyable_function<void() const> &> );
+static_assert( is_invocable_v< copyable_function<void() const> const > );
+static_assert( is_invocable_v< copyable_function<void() const> const &> );
+
+// With no ref-qualifier
+static_assert( is_invocable_v< copyable_function<void()> > );
+static_assert( is_invocable_v< copyable_function<void()> &> );
+static_assert( is_invocable_v< copyable_function<void() const> > );
+static_assert( is_invocable_v< copyable_function<void() const> &> );
+static_assert( is_invocable_v< copyable_function<void() const> const > );
+static_assert( is_invocable_v< copyable_function<void() const> const &> );
+
+// With & ref-qualifier
+static_assert( ! is_invocable_v< copyable_function<void()&> > );
+static_assert( is_invocable_v< copyable_function<void()&> &> );
+static_assert( is_invocable_v< copyable_function<void() const&> > );
+static_assert( is_invocable_v< copyable_function<void() const&> &> );
+static_assert( is_invocable_v< copyable_function<void() const&> const > );
+static_assert( is_invocable_v< copyable_function<void() const&> const &> );
+
+// With && ref-qualifier
+static_assert( is_invocable_v< copyable_function<void()&&> > );
+static_assert( ! is_invocable_v< copyable_function<void()&&> &> );
+static_assert( is_invocable_v< copyable_function<void() const&&> > );
+static_assert( ! is_invocable_v< copyable_function<void() const&&> &> );
+static_assert( is_invocable_v< copyable_function<void() const&&> const > );
+static_assert( ! is_invocable_v< copyable_function<void() const&&> const &> );
+
+// With noexcept-specifier
+static_assert( ! is_nothrow_invocable_v< copyable_function<void()> > );
+static_assert( ! is_nothrow_invocable_v< copyable_function<void() noexcept(false)> > );
+static_assert( is_nothrow_invocable_v< copyable_function<void() noexcept> > );
+static_assert( is_nothrow_invocable_v< copyable_function<void()& noexcept>& > );
+
+void
+test01()
+{
+ struct F
+ {
+ int operator()() { return 0; }
+ int operator()() const { return 1; }
+ };
+
+ copyable_function<int()> f0{F{}};
+ VERIFY( f0() == 0 );
+ VERIFY( std::move(f0)() == 0 );
+
+ copyable_function<int() const> f1{F{}};
+ VERIFY( f1() == 1 );
+ VERIFY( std::as_const(f1)() == 1 );
+ VERIFY( std::move(f1)() == 1 );
+ VERIFY( std::move(std::as_const(f1))() == 1 );
+
+ copyable_function<int()&> f2{F{}};
+ VERIFY( f2() == 0 );
+ // Not rvalue-callable: std::move(f2)()
+
+ copyable_function<int() const&> f3{F{}};
+ VERIFY( f3() == 1 );
+ VERIFY( std::as_const(f3)() == 1 );
+ VERIFY( std::move(f3)() == 1 );
+ VERIFY( std::move(std::as_const(f3))() == 1 );
+
+ copyable_function<int()&&> f4{F{}};
+ // Not lvalue-callable: f4()
+ VERIFY( std::move(f4)() == 0 );
+
+ copyable_function<int() const&&> f5{F{}};
+ // Not lvalue-callable: f5()
+ VERIFY( std::move(f5)() == 1 );
+ VERIFY( std::move(std::as_const(f5))() == 1 );
+}
+
+void
+test02()
+{
+ struct F
+ {
+ int operator()() & { return 0; }
+ int operator()() && { return 1; }
+ };
+
+ copyable_function<int()> f0{F{}};
+ VERIFY( f0() == 0 );
+ VERIFY( std::move(f0)() == 0 );
+
+ copyable_function<int()&&> f1{F{}};
+ // Not lvalue callable: f1()
+ VERIFY( std::move(f1)() == 1 );
+
+ copyable_function<int()&> f2{F{}};
+ VERIFY( f2() == 0 );
+ // Not rvalue-callable: std::move(f2)()
+}
+
+void
+test03()
+{
+ struct F
+ {
+ int operator()() const & { return 0; }
+ int operator()() && { return 1; }
+ };
+
+ copyable_function<int()> f0{F{}};
+ VERIFY( f0() == 0 );
+ VERIFY( std::move(f0)() == 0 );
+
+ copyable_function<int()&&> f1{F{}};
+ // Not lvalue callable: f1()
+ VERIFY( std::move(f1)() == 1 );
+
+ copyable_function<int() const> f2{F{}};
+ VERIFY( f2() == 0 );
+ VERIFY( std::as_const(f2)() == 0 );
+ VERIFY( std::move(f2)() == 0 );
+ VERIFY( std::move(std::as_const(f2))() == 0 );
+
+ copyable_function<int() const &&> f3{F{}};
+ // Not lvalue callable: f3()
+ VERIFY( std::move(f3)() == 0 );
+ VERIFY( std::move(std::as_const(f3))() == 0 );
+
+ copyable_function<int() const &> f4{F{}};
+ VERIFY( f4() == 0 );
+ VERIFY( std::as_const(f4)() == 0 );
+ // Not rvalue-callable: std::move(f4)()
+}
+
+void
+test04()
+{
+ struct F
+ {
+ int operator()() & { return 0; }
+ int operator()() && { return 1; }
+ int operator()() const & { return 2; }
+ int operator()() const && { return 3; }
+ };
+
+ copyable_function<int()> f0{F{}};
+ VERIFY( f0() == 0 );
+ VERIFY( std::move(f0)() == 0 );
+
+ copyable_function<int()&> f1{F{}};
+ VERIFY( f1() == 0 );
+ // Not rvalue-callable: std::move(f1)()
+
+ copyable_function<int()&&> f2{F{}};
+ // Not lvalue callable: f2()
+ VERIFY( std::move(f2)() == 1 );
+
+ copyable_function<int() const> f3{F{}};
+ VERIFY( f3() == 2 );
+ VERIFY( std::as_const(f3)() == 2 );
+ VERIFY( std::move(f3)() == 2 );
+ VERIFY( std::move(std::as_const(f3))() == 2 );
+
+ copyable_function<int() const &> f4{F{}};
+ VERIFY( f4() == 2 );
+ VERIFY( std::as_const(f4)() == 2 );
+ // Not rvalue-callable: std::move(f4)()
+
+ copyable_function<int() const &&> f5{F{}};
+ // Not lvalue callable: f5()
+ VERIFY( std::move(f5)() == 3 );
+ VERIFY( std::move(std::as_const(f5))() == 3 );
+}
+
+void
+test05()
+{
+ int (*fp)() = [] { return 0; };
+ copyable_function<int()> f0{fp};
+ VERIFY( f0() == 0 );
+ VERIFY( std::move(f0)() == 0 );
+
+ const copyable_function<int() const> f1{fp};
+ VERIFY( f1() == 0 );
+ VERIFY( std::move(f1)() == 0 );
+}
+
+struct Incomplete;
+
+void
+test_params()
+{
+ std::copyable_function<void(Incomplete)> f1;
+ std::copyable_function<void(Incomplete&)> f2;
+ std::copyable_function<void(Incomplete&&)> f3;
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test05();
+ test_params();
+}
diff --git a/libstdc++-v3/testsuite/20_util/copyable_function/cons.cc b/libstdc++-v3/testsuite/20_util/copyable_function/cons.cc
new file mode 100644
index 0000000..8d422dc
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/copyable_function/cons.cc
@@ -0,0 +1,126 @@
+// { dg-do compile { target c++26 } }
+// { dg-require-effective-target hosted }
+// { dg-add-options no_pch }
+
+#include <functional>
+
+#ifndef __cpp_lib_copyable_function
+# error "Feature-test macro for copyable_function missing in <functional>"
+#elif __cpp_lib_copyable_function != 202306L
+# error "Feature-test macro for copyable_function has wrong value in <functional>"
+#endif
+
+using std::copyable_function;
+
+using std::is_constructible_v;
+using std::is_copy_constructible_v;
+using std::is_nothrow_default_constructible_v;
+using std::is_nothrow_move_constructible_v;
+using std::is_nothrow_constructible_v;
+using std::nullptr_t;
+using std::in_place_type_t;
+
+static_assert( is_nothrow_default_constructible_v<copyable_function<void()>> );
+static_assert( is_nothrow_constructible_v<copyable_function<void()>, nullptr_t> );
+static_assert( is_nothrow_move_constructible_v<copyable_function<void()>> );
+static_assert( is_copy_constructible_v<copyable_function<void()>> );
+
+static_assert( is_constructible_v<copyable_function<void()>, void()> );
+static_assert( is_constructible_v<copyable_function<void()>, void(&)()> );
+static_assert( is_constructible_v<copyable_function<void()>, void(*)()> );
+static_assert( is_constructible_v<copyable_function<void()>, int()> );
+static_assert( is_constructible_v<copyable_function<void()>, int(&)()> );
+static_assert( is_constructible_v<copyable_function<void()>, int(*)()> );
+static_assert( ! is_constructible_v<copyable_function<void()>, void(int)> );
+static_assert( is_constructible_v<copyable_function<void(int)>, void(int)> );
+
+static_assert( is_constructible_v<copyable_function<void(int)>,
+ in_place_type_t<void(*)(int)>, void(int)> );
+
+static_assert( is_constructible_v<copyable_function<void()>,
+ void() noexcept> );
+static_assert( is_constructible_v<copyable_function<void() noexcept>,
+ void() noexcept> );
+static_assert( ! is_constructible_v<copyable_function<void() noexcept>,
+ void() > );
+
+struct Q
+{
+ void operator()() const &;
+ void operator()() &&;
+};
+
+static_assert( is_constructible_v<copyable_function<void()>, Q> );
+static_assert( is_constructible_v<copyable_function<void() const>, Q> );
+static_assert( is_constructible_v<copyable_function<void() &>, Q> );
+static_assert( is_constructible_v<copyable_function<void() const &>, Q> );
+static_assert( is_constructible_v<copyable_function<void() &&>, Q> );
+static_assert( is_constructible_v<copyable_function<void() const &&>, Q> );
+
+struct R
+{
+ void operator()() &;
+ void operator()() &&;
+};
+
+static_assert( is_constructible_v<copyable_function<void()>, R> );
+static_assert( is_constructible_v<copyable_function<void()&>, R> );
+static_assert( is_constructible_v<copyable_function<void()&&>, R> );
+static_assert( ! is_constructible_v<copyable_function<void() const>, R> );
+static_assert( ! is_constructible_v<copyable_function<void() const&>, R> );
+static_assert( ! is_constructible_v<copyable_function<void() const&&>, R> );
+
+// The following nothrow-constructible guarantees are a GCC extension,
+// not required by the standard.
+
+static_assert( is_nothrow_constructible_v<copyable_function<void()>, void()> );
+static_assert( is_nothrow_constructible_v<copyable_function<void(int)>,
+ in_place_type_t<void(*)(int)>,
+ void(int)> );
+
+// These types are all small and nothrow move constructible
+struct F { void operator()(); };
+struct G { void operator()() const; };
+static_assert( is_nothrow_constructible_v<copyable_function<void()>, F> );
+static_assert( is_nothrow_constructible_v<copyable_function<void()>, G> );
+static_assert( is_nothrow_constructible_v<copyable_function<void() const>, G> );
+
+struct H {
+ H(int);
+ H(int, int) noexcept;
+ void operator()() noexcept;
+};
+static_assert( is_nothrow_constructible_v<copyable_function<void()>, H> );
+static_assert( is_nothrow_constructible_v<copyable_function<void() noexcept>,
+ H> );
+static_assert( ! is_nothrow_constructible_v<copyable_function<void() noexcept>,
+ in_place_type_t<H>, int> );
+static_assert( is_nothrow_constructible_v<copyable_function<void() noexcept>,
+ in_place_type_t<H>, int, int> );
+
+struct I {
+ I(int, const char*);
+ I(std::initializer_list<char>);
+ int operator()() const noexcept;
+};
+
+static_assert( is_constructible_v<copyable_function<void()>,
+ std::in_place_type_t<I>,
+ int, const char*> );
+static_assert( is_constructible_v<copyable_function<void()>,
+ std::in_place_type_t<I>,
+ std::initializer_list<char>> );
+
+void
+test_instantiation()
+{
+ // Instantiate the constructor bodies
+ copyable_function<void()> f0;
+ copyable_function<void()> f1(nullptr);
+ copyable_function<void()> f2( I(1, "two") );
+ copyable_function<void()> f3(std::in_place_type<I>, 3, "four");
+ copyable_function<void()> f4(std::in_place_type<I>, // PR libstdc++/102825
+ { 'P', 'R', '1', '0', '2', '8', '2', '5'});
+ auto f5 = std::move(f4);
+ f4 = std::move(f5);
+}
diff --git a/libstdc++-v3/testsuite/20_util/copyable_function/conv.cc b/libstdc++-v3/testsuite/20_util/copyable_function/conv.cc
new file mode 100644
index 0000000..e678e16
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/copyable_function/conv.cc
@@ -0,0 +1,251 @@
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+#include <functional>
+#include <testsuite_hooks.h>
+
+using std::copyable_function;
+
+static_assert( !std::is_constructible_v<std::copyable_function<void()>,
+ std::copyable_function<void()&>> );
+static_assert( !std::is_constructible_v<std::copyable_function<void()>,
+ std::copyable_function<void()&&>> );
+static_assert( !std::is_constructible_v<std::copyable_function<void()&>,
+ std::copyable_function<void()&&>> );
+static_assert( !std::is_constructible_v<std::copyable_function<void() const>,
+ std::copyable_function<void()>> );
+
+// Non-trivial args, guarantess that type is not passed by copy
+struct CountedArg
+{
+ CountedArg() = default;
+ CountedArg(const CountedArg& f) noexcept : counter(f.counter) { ++counter; }
+ CountedArg& operator=(CountedArg&&) = delete;
+
+ int counter = 0;
+};
+CountedArg const c;
+
+// When copyable_function or move_only_function is constructed from other copyable_function,
+// the compiler can avoid double indirection per C++26 [func.wrap.general] p2.
+
+void
+test01()
+{
+ auto f = [](CountedArg const& arg) noexcept { return arg.counter; };
+ std::copyable_function<int(CountedArg) const noexcept> c1(f);
+ using CF = std::copyable_function<int(CountedArg) const noexcept>;
+ VERIFY( c1(c) == 1 );
+
+ std::copyable_function<int(CountedArg) const> c2a(c1);
+ VERIFY( c2a(c) == 1 );
+
+ std::copyable_function<int(CountedArg) const> c2b(static_cast<CF>(c1));
+ VERIFY( c2b(c) == 1 );
+
+ std::move_only_function<int(CountedArg) const> m2a(c1);
+ VERIFY( m2a(c) == 1 );
+
+ std::move_only_function<int(CountedArg) const> m2b(static_cast<CF>(c1));
+ VERIFY( m2b(c) == 1 );
+
+ std::copyable_function<int(CountedArg)> c3a(c1);
+ VERIFY( c3a(c) == 1 );
+
+ std::copyable_function<int(CountedArg)> c3b(static_cast<CF>(c1));
+ VERIFY( c3b(c) == 1 );
+
+ std::move_only_function<int(CountedArg)> m3a(c1);
+ VERIFY( m3a(c) == 1 );
+
+ std::move_only_function<int(CountedArg)> m3b(static_cast<CF>(c1));
+ VERIFY( m3b(c) == 1 );
+
+ // Invokers internally uses Counted&& for non-trivial types,
+ // sinature remain compatible.
+ std::copyable_function<int(CountedArg&&)> c4a(c1);
+ VERIFY( c4a({}) == 0 );
+
+ std::copyable_function<int(CountedArg&&)> c4b(static_cast<CF>(c1));
+ VERIFY( c4b({}) == 0 );
+
+ std::move_only_function<int(CountedArg&&)> m4a(c1);
+ VERIFY( m4a({}) == 0 );
+
+ std::move_only_function<int(CountedArg&&)> m4b(static_cast<CF>(c1));
+ VERIFY( m4b({}) == 0 );
+
+ std::copyable_function<int(CountedArg&&)&> c5a(c1);
+ VERIFY( c5a({}) == 0 );
+
+ std::copyable_function<int(CountedArg&&)&&> c5b(static_cast<CF>(c1));
+ VERIFY( std::move(c5b)({}) == 0 );
+
+ std::move_only_function<int(CountedArg&&)&> m5a(c1);
+ VERIFY( m5a({}) == 0 );
+
+ std::move_only_function<int(CountedArg&&)&&> m5b(static_cast<CF>(c1));
+ VERIFY( std::move(m5b)({}) == 0 );
+
+ // Incompatible signatures
+ std::copyable_function<long(CountedArg) const noexcept> c6a(c1);
+ VERIFY( c6a(c) == 2 );
+
+ std::copyable_function<long(CountedArg) const noexcept> c6b(static_cast<CF>(c1));
+ VERIFY( c6b(c) == 2 );
+
+ std::move_only_function<long(CountedArg) const noexcept> m6a(c1);
+ VERIFY( m6a(c) == 2 );
+
+ std::move_only_function<long(CountedArg) const noexcept> m6b(static_cast<CF>(c1));
+ VERIFY( m6b(c) == 2 );
+}
+
+void
+test02()
+{
+ auto f = [](CountedArg const& arg) noexcept { return arg.counter; };
+ std::copyable_function<int(CountedArg) const noexcept> c1(f);
+ using CF = std::copyable_function<int(CountedArg) const noexcept>;
+ VERIFY( c1(c) == 1 );
+
+ std::copyable_function<int(CountedArg) const> c2;
+ c2 = c1;
+ VERIFY( c2(c) == 1 );
+ c2 = static_cast<CF>(c1);
+ VERIFY( c2(c) == 1 );
+
+ std::move_only_function<int(CountedArg) const> m2;
+ m2 = c1;
+ VERIFY( m2(c) == 1 );
+ m2 = static_cast<CF>(c1);
+ VERIFY( m2(c) == 1 );
+
+ // Incompatible signatures
+ std::copyable_function<long(CountedArg) const noexcept> c3;
+ c3 = c1;
+ VERIFY( c3(c) == 2 );
+ c3 = static_cast<CF>(c1);
+ VERIFY( c3(c) == 2 );
+
+ std::move_only_function<long(CountedArg) const noexcept> m3;
+ m3 = c1;
+ VERIFY( m3(c) == 2 );
+ m3 = static_cast<CF>(c1);
+ VERIFY( m3(c) == 2 );
+}
+
+void
+test03()
+{
+ std::copyable_function<int(long) const noexcept> c1;
+ VERIFY( c1 == nullptr );
+
+ std::copyable_function<int(long) const> c2(c1);
+ VERIFY( c2 == nullptr );
+ c2 = c1;
+ VERIFY( c2 == nullptr );
+ c2 = std::move(c1);
+ VERIFY( c2 == nullptr );
+
+ std::copyable_function<bool(int) const> c3(std::move(c1));
+ VERIFY( c3 == nullptr );
+ c3 = c1;
+ VERIFY( c3 == nullptr );
+ c3 = std::move(c1);
+ VERIFY( c3 == nullptr );
+
+ // LWG4255 move_only_function constructor should recognize empty
+ // copyable_functions
+ std::move_only_function<int(long) const noexcept> m1(c1);
+ VERIFY( m1 == nullptr );
+ m1 = c1;
+ VERIFY( m1 == nullptr );
+ m1 = std::move(c1);
+ VERIFY( m1 == nullptr );
+
+ std::move_only_function<int(long) const> m2(c1);
+ VERIFY( m2 == nullptr );
+ m2 = c1;
+ VERIFY( m2 == nullptr );
+ m2 = std::move(c1);
+ VERIFY( m2 == nullptr );
+
+ std::move_only_function<bool(int) const> m3(std::move(c1));
+ VERIFY( m3 == nullptr );
+ m3 = c1;
+ VERIFY( m3 == nullptr );
+ m3 = std::move(c1);
+ VERIFY( m3 == nullptr );
+}
+
+void
+test04()
+{
+ struct F
+ {
+ int operator()(CountedArg const& arg) noexcept
+ { return arg.counter; }
+
+ int operator()(CountedArg const& arg) const noexcept
+ { return arg.counter + 1000; }
+ };
+
+ F f;
+ std::copyable_function<int(CountedArg) const> c1(f);
+ VERIFY( c1(c) == 1001 );
+
+ // Call const overload as std::copyable_function<int(CountedArg) const>
+ // inside td::copyable_function<int(CountedArg)> would do.
+ std::copyable_function<int(CountedArg)> c2(c1);
+ VERIFY( c2(c) == 1001 );
+ std::move_only_function<int(CountedArg)> m2(c1);
+ VERIFY( m2(c) == 1001 );
+
+ std::copyable_function<int(CountedArg)> m3(f);
+ VERIFY( m3(c) == 1 );
+}
+
+void
+test05()
+{
+ auto f = [](CountedArg const& arg) noexcept { return arg.counter; };
+ std::copyable_function<int(CountedArg)> w1(f);
+ // copyable_function stores copyable_function due incompatibile signatures
+ std::copyable_function<int(CountedArg const&)> w2(std::move(w1));
+ // copy is made when passing to int(CountedArg)
+ VERIFY( w2(c) == 1 );
+ // wrapped 3 times
+ w1 = std::move(w2);
+ VERIFY( w1(c) == 2 );
+ // wrapped 4 times
+ w2 = std::move(w1);
+ VERIFY( w2(c) == 2 );
+ // wrapped 5 times
+ w1 = std::move(w2);
+ VERIFY( w1(c) == 3 );
+}
+
+void
+test06()
+{
+ // No special interoperability with std::function
+ auto f = [](CountedArg const& arg) noexcept { return arg.counter; };
+ std::function<int(CountedArg)> f1(f);
+ std::copyable_function<int(CountedArg) const> c1(std::move(f1));
+ VERIFY( c1(c) == 2 );
+
+ std::copyable_function<int(CountedArg) const> c2(f);
+ std::function<int(CountedArg)> f2(c2);
+ VERIFY( f2(c) == 2 );
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test05();
+ test06();
+}
diff --git a/libstdc++-v3/testsuite/20_util/copyable_function/copy.cc b/libstdc++-v3/testsuite/20_util/copyable_function/copy.cc
new file mode 100644
index 0000000..6445a27
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/copyable_function/copy.cc
@@ -0,0 +1,154 @@
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+#include <functional>
+#include <testsuite_hooks.h>
+
+using std::copyable_function;
+
+void
+test01()
+{
+ // Small type with non-throwing move constructor. Not allocated on the heap.
+ struct F
+ {
+ F() = default;
+ F(const F& f) : counters(f.counters) { ++counters.copy; }
+ F(F&& f) noexcept : counters(f.counters) { ++counters.move; }
+
+ F& operator=(F&&) = delete;
+
+ struct Counters
+ {
+ int copy = 0;
+ int move = 0;
+ } counters;
+
+ const Counters& operator()() const { return counters; }
+ };
+
+ F f;
+ std::copyable_function<const F::Counters&() const> m1(f);
+ VERIFY( m1().copy == 1 );
+ VERIFY( m1().move == 0 );
+
+ // This will copy construct a new target object
+ auto m2 = m1;
+ VERIFY( m1 != nullptr && m2 != nullptr );
+ VERIFY( m2().copy == 2 );
+ VERIFY( m2().move == 0 );
+
+ m1 = m2;
+ VERIFY( m1 != nullptr && m2 != nullptr );
+ VERIFY( m1().copy == 3 );
+ VERIFY( m1().move == 1 ); // Copies object first and then swaps
+
+ m1 = m1;
+ VERIFY( m1 != nullptr && m2 != nullptr );
+ VERIFY( m1().copy == 4 );
+ VERIFY( m1().move == 2 ); // Copies object first and then swaps
+
+ m2 = f;
+ VERIFY( m2().copy == 1 );
+ VERIFY( m2().move == 1 ); // Copy construct target object, then swap into m2.
+}
+
+void
+test02()
+{
+ // Move constructor is potentially throwing. Allocated on the heap.
+ struct F
+ {
+ F() = default;
+ F(const F& f) noexcept : counters(f.counters) { ++counters.copy; }
+ F(F&& f) noexcept(false) : counters(f.counters) { ++counters.move; }
+
+ F& operator=(F&&) = delete;
+
+ struct Counters
+ {
+ int copy = 0;
+ int move = 0;
+ } counters;
+
+ Counters operator()() const noexcept { return counters; }
+ };
+
+ F f;
+ std::copyable_function<F::Counters() const> m1(f);
+ VERIFY( m1().copy == 1 );
+ VERIFY( m1().move == 0 );
+
+ // The target object is on the heap, but we need to allocate new one
+ auto m2 = m1;
+ VERIFY( m1 != nullptr && m2 != nullptr );
+ VERIFY( m2().copy == 2 );
+ VERIFY( m2().move == 0 );
+
+ m1 = m2;
+ VERIFY( m1 != nullptr && m2 != nullptr );
+ VERIFY( m1().copy == 3 );
+ VERIFY( m1().move == 0 );
+
+ m1 = m1;
+ VERIFY( m1 != nullptr && m2 != nullptr );
+ VERIFY( m1().copy == 4 );
+ VERIFY( m1().move == 0 );
+
+ m2 = f;
+ VERIFY( m2().copy == 1 );
+ VERIFY( m2().move == 0 );
+}
+
+void
+test03()
+{
+ // Small type with non-throwing, but not non-trivial move constructor.
+ struct F
+ {
+ F(int i) noexcept : id(i) {}
+ F(const F& f) : id(f.id)
+ { if (id == 3) throw id; }
+ F(F&& f) noexcept : id(f.id) { }
+
+ int operator()() const
+ { return id; }
+
+ int id;
+ };
+
+ std::copyable_function<int() const> m1(std::in_place_type<F>, 1);
+ const std::copyable_function<int() const> m2(std::in_place_type<F>, 2);
+ const std::copyable_function<int() const> m3(std::in_place_type<F>, 3);
+
+ try
+ {
+ auto mc = m3;
+ VERIFY( false );
+ }
+ catch(int i)
+ {
+ VERIFY( i == 3 );
+ }
+
+ m1 = m2;
+ VERIFY( m1() == 2 );
+
+ try
+ {
+ m1 = m3;
+ VERIFY( false );
+ }
+ catch (int i)
+ {
+ VERIFY( i == 3 );
+ }
+ VERIFY( m1() == 2 );
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+}
diff --git a/libstdc++-v3/testsuite/20_util/copyable_function/move.cc b/libstdc++-v3/testsuite/20_util/copyable_function/move.cc
new file mode 100644
index 0000000..ec9d0d1
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/copyable_function/move.cc
@@ -0,0 +1,120 @@
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+#include <functional>
+#include <testsuite_hooks.h>
+
+using std::copyable_function;
+
+void
+test01()
+{
+ // Small type with non-throwing move constructor. Not allocated on the heap.
+ struct F
+ {
+ F() = default;
+ F(const F& f) : counters(f.counters) { ++counters.copy; }
+ F(F&& f) noexcept : counters(f.counters) { ++counters.move; }
+
+ F& operator=(F&&) = delete;
+
+ struct Counters
+ {
+ int copy = 0;
+ int move = 0;
+ } counters;
+
+ const Counters& operator()() const { return counters; }
+ };
+
+ F f;
+ std::copyable_function<const F::Counters&() const> m1(f);
+ VERIFY( m1().copy == 1 );
+ VERIFY( m1().move == 0 );
+
+ // Standard specifies move assigment as copy and swap
+ m1 = std::move(m1);
+ VERIFY( m1 != nullptr );
+ VERIFY( m1().copy == 1 );
+ VERIFY( m1().move == 0 );
+
+ // This will move construct a new target object and destroy the old one:
+ auto m2 = std::move(m1);
+ VERIFY( m1 == nullptr && m2 != nullptr );
+ VERIFY( m2().copy == 1 );
+ VERIFY( m2().move == 1 );
+
+ m1 = std::move(m2);
+ VERIFY( m1 != nullptr && m2 == nullptr );
+ VERIFY( m1().copy == 1 );
+ VERIFY( m1().move == 2 );
+
+ m2 = std::move(f);
+ VERIFY( m2().copy == 0 );
+ VERIFY( m2().move == 2 ); // Move construct target object, then swap into m2.
+ const int moves = m1().move + m2().move;
+ // This will do three moves:
+ swap(m1, m2);
+ VERIFY( m1().copy == 0 );
+ VERIFY( m2().copy == 1 );
+ VERIFY( (m1().move + m2().move) == (moves + 3) );
+}
+
+void
+test02()
+{
+ // Move constructor is potentially throwing. Allocated on the heap.
+ struct F
+ {
+ F() = default;
+ F(const F& f) noexcept : counters(f.counters) { ++counters.copy; }
+ F(F&& f) noexcept(false) : counters(f.counters) { ++counters.move; }
+
+ F& operator=(F&&) = delete;
+
+ struct Counters
+ {
+ int copy = 0;
+ int move = 0;
+ } counters;
+
+ Counters operator()() const noexcept { return counters; }
+ };
+
+ F f;
+ std::copyable_function<F::Counters() const> m1(f);
+ VERIFY( m1().copy == 1 );
+ VERIFY( m1().move == 0 );
+
+ m1 = std::move(m1);
+ VERIFY( m1 != nullptr );
+ VERIFY( m1().copy == 1 );
+ VERIFY( m1().move == 0 );
+
+ // The target object is on the heap so this just moves a pointer:
+ auto m2 = std::move(m1);
+ VERIFY( m1 == nullptr && m2 != nullptr );
+ VERIFY( m2().copy == 1 );
+ VERIFY( m2().move == 0 );
+
+ m1 = std::move(m2);
+ VERIFY( m1 != nullptr && m2 == nullptr );
+ VERIFY( m1().copy == 1 );
+ VERIFY( m1().move == 0 );
+
+ m2 = std::move(f);
+ VERIFY( m2().copy == 0 );
+ VERIFY( m2().move == 1 );
+ const int moves = m1().move + m2().move;
+ // This just swaps the pointers, so no moves:
+ swap(m1, m2);
+ VERIFY( m1().copy == 0 );
+ VERIFY( m2().copy == 1 );
+ VERIFY( (m1().move + m2().move) == moves );
+}
+
+int main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/20_util/move_only_function/call.cc b/libstdc++-v3/testsuite/20_util/move_only_function/call.cc
index bfc609a..217de37 100644
--- a/libstdc++-v3/testsuite/20_util/move_only_function/call.cc
+++ b/libstdc++-v3/testsuite/20_util/move_only_function/call.cc
@@ -190,6 +190,19 @@ test04()
VERIFY( std::move(std::as_const(f5))() == 3 );
}
+void
+test05()
+{
+ int (*fp)() = [] { return 0; };
+ move_only_function<int()> f0{fp};
+ VERIFY( f0() == 0 );
+ VERIFY( std::move(f0)() == 0 );
+
+ const move_only_function<int() const> f1{fp};
+ VERIFY( f1() == 0 );
+ VERIFY( std::move(f1)() == 0 );
+}
+
struct Incomplete;
void
@@ -206,5 +219,6 @@ int main()
test02();
test03();
test04();
+ test05();
test_params();
}
diff --git a/libstdc++-v3/testsuite/20_util/move_only_function/conv.cc b/libstdc++-v3/testsuite/20_util/move_only_function/conv.cc
new file mode 100644
index 0000000..3da5e9e
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/move_only_function/conv.cc
@@ -0,0 +1,188 @@
+// { dg-do run { target c++23 } }
+// { dg-require-effective-target hosted }
+
+#include <functional>
+#include <testsuite_hooks.h>
+
+using std::move_only_function;
+
+static_assert( !std::is_constructible_v<std::move_only_function<void()>,
+ std::move_only_function<void()&>> );
+static_assert( !std::is_constructible_v<std::move_only_function<void()>,
+ std::move_only_function<void()&&>> );
+static_assert( !std::is_constructible_v<std::move_only_function<void()&>,
+ std::move_only_function<void()&&>> );
+static_assert( !std::is_constructible_v<std::move_only_function<void() const>,
+ std::move_only_function<void()>> );
+
+// Non-trivial args, guarantess that type is not passed by copy
+struct CountedArg
+{
+ CountedArg() = default;
+ CountedArg(const CountedArg& f) noexcept : counter(f.counter) { ++counter; }
+ CountedArg& operator=(CountedArg&&) = delete;
+
+ int counter = 0;
+};
+CountedArg const c;
+
+// When move_only_functions is constructed from other move_only_function,
+// the compiler can avoid double indirection per C++26 [func.wrap.general] p2.
+
+void
+test01()
+{
+ auto f = [](CountedArg const& arg) noexcept { return arg.counter; };
+ std::move_only_function<int(CountedArg) const noexcept> m1(f);
+ VERIFY( m1(c) == 1 );
+
+ std::move_only_function<int(CountedArg) const> m2(std::move(m1));
+ VERIFY( m2(c) == 1 );
+
+ std::move_only_function<int(CountedArg)> m3(std::move(m2));
+ VERIFY( m3(c) == 1 );
+
+ // Invokers internally uses Counted&& for non-trivial types,
+ // sinature remain compatible.
+ std::move_only_function<int(CountedArg&&)> m4(std::move(m3));
+ VERIFY( m4({}) == 0 );
+
+ std::move_only_function<int(CountedArg&&)&&> m5(std::move(m4));
+ VERIFY( std::move(m5)({}) == 0 );
+
+ m4 = f;
+ std::move_only_function<int(CountedArg&&)&> m7(std::move(m4));
+ VERIFY( m7({}) == 0 );
+
+ m4 = f;
+ std::move_only_function<int(CountedArg&&)&> m8(std::move(m4));
+ VERIFY( m8({}) == 0 );
+
+ // Incompatible signatures
+ m1 = f;
+ std::move_only_function<long(CountedArg) const noexcept> m9(std::move(m1));
+ VERIFY( m9(c) == 2 );
+}
+
+void
+test02()
+{
+ auto f = [](CountedArg const& arg) noexcept { return arg.counter; };
+ std::move_only_function<int(CountedArg) const noexcept> m1(f);
+ VERIFY( m1(c) == 1 );
+
+ std::move_only_function<int(CountedArg) const> m2;
+ m2 = std::move(m1);
+ VERIFY( m2(c) == 1 );
+
+ std::move_only_function<int(CountedArg)> m3;
+ m3 = std::move(m2);
+ VERIFY( m3(c) == 1 );
+
+ // Invokers internally uses Counted&& for non-trivial types,
+ // sinature remain compatible.
+ std::move_only_function<int(CountedArg&&)> m4;
+ m4 = std::move(m3);
+ VERIFY( m4({}) == 0 );
+
+ std::move_only_function<int(CountedArg&&)&&> m5;
+ m5 = std::move(m4);
+ VERIFY( std::move(m5)({}) == 0 );
+
+ m4 = f;
+ std::move_only_function<int(CountedArg&&)&> m7;
+ m7 = std::move(m4);
+ VERIFY( m7({}) == 0 );
+
+ m4 = f;
+ std::move_only_function<int(CountedArg&&)&> m8;
+ m8 = std::move(m4);
+ VERIFY( m8({}) == 0 );
+
+ m1 = f;
+ std::move_only_function<long(CountedArg) const noexcept> m9;
+ m9 = std::move(m1);
+ VERIFY( m9(c) == 2 );
+}
+
+void
+test03()
+{
+ std::move_only_function<int(long) const noexcept> e;
+ VERIFY( e == nullptr );
+
+ std::move_only_function<int(long) const> e2(std::move(e));
+ VERIFY( e2 == nullptr );
+ e2 = std::move(e);
+ VERIFY( e2 == nullptr );
+
+ std::move_only_function<bool(int) const> e3(std::move(e));
+ VERIFY( e3 == nullptr );
+ e3 = std::move(e);
+ VERIFY( e3 == nullptr );
+}
+
+void
+test04()
+{
+ struct F
+ {
+ int operator()(CountedArg const& arg) noexcept
+ { return arg.counter; }
+
+ int operator()(CountedArg const& arg) const noexcept
+ { return arg.counter + 1000; }
+ };
+
+ F f;
+ std::move_only_function<int(CountedArg) const> m1(f);
+ VERIFY( m1(c) == 1001 );
+
+ // Call const overload as std::move_only_function<int(CountedArg) const>
+ // inside std::move_only_function<int(CountedArg)> would do.
+ std::move_only_function<int(CountedArg)> m2(std::move(m1));
+ VERIFY( m2(c) == 1001 );
+
+ std::move_only_function<int(CountedArg)> m3(f);
+ VERIFY( m3(c) == 1 );
+}
+
+void
+test05()
+{
+ auto f = [](CountedArg const& arg) noexcept { return arg.counter; };
+ std::move_only_function<int(CountedArg)> w1(f);
+ // move_only_function stores move_only_function due incompatibile signatures
+ std::move_only_function<int(CountedArg const&)> w2(std::move(w1));
+ // copy is made when passing to int(CountedArg)
+ VERIFY( w2(c) == 1 );
+ // wrapped 3 times
+ w1 = std::move(w2);
+ VERIFY( w1(c) == 2 );
+ // wrapped 4 times
+ w2 = std::move(w1);
+ VERIFY( w2(c) == 2 );
+ // wrapped 5 times
+ w1 = std::move(w2);
+ VERIFY( w1(c) == 3 );
+}
+
+void
+test06()
+{
+ // No special interoperability with std::function
+ auto f = [](CountedArg const& arg) noexcept { return arg.counter; };
+ std::function<int(CountedArg)> f1(f);
+ std::move_only_function<int(CountedArg) const> m1(std::move(f1));
+ VERIFY( m1(c) == 2 );
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test05();
+ test06();
+}
diff --git a/libstdc++-v3/testsuite/20_util/move_only_function/move.cc b/libstdc++-v3/testsuite/20_util/move_only_function/move.cc
index 51e31a6..6da02c9 100644
--- a/libstdc++-v3/testsuite/20_util/move_only_function/move.cc
+++ b/libstdc++-v3/testsuite/20_util/move_only_function/move.cc
@@ -32,6 +32,12 @@ test01()
VERIFY( m1().copy == 1 );
VERIFY( m1().move == 0 );
+ // Standard specifies move assigment as copy and swap
+ m1 = std::move(m1);
+ VERIFY( m1 != nullptr );
+ VERIFY( m1().copy == 1 );
+ VERIFY( m1().move == 0 );
+
// This will move construct a new target object and destroy the old one:
auto m2 = std::move(m1);
VERIFY( m1 == nullptr && m2 != nullptr );
@@ -80,6 +86,11 @@ test02()
VERIFY( m1().copy == 1 );
VERIFY( m1().move == 0 );
+ m1 = std::move(m1);
+ VERIFY( m1 != nullptr );
+ VERIFY( m1().copy == 1 );
+ VERIFY( m1().move == 0 );
+
// The target object is on the heap so this just moves a pointer:
auto m2 = std::move(m1);
VERIFY( m1 == nullptr && m2 != nullptr );
diff --git a/libstdc++-v3/testsuite/std/format/arguments/args.cc b/libstdc++-v3/testsuite/std/format/arguments/args.cc
index 4c50bc7..6029675 100644
--- a/libstdc++-v3/testsuite/std/format/arguments/args.cc
+++ b/libstdc++-v3/testsuite/std/format/arguments/args.cc
@@ -164,24 +164,6 @@ void test_visited_as_handle()
#endif
}
-template<typename E, typename S>
-void test_visited_as()
-{
- auto v = static_cast<S>(1.0);
- auto store = std::make_format_args(v);
- std::format_args args = store;
-
- auto is_expected_val = [v](auto arg) {
- if constexpr (std::is_same_v<decltype(arg), E>)
- return arg == static_cast<E>(v);
- return false;
- };
- VERIFY( std::visit_format_arg(is_expected_val, args.get(0)) );
-#if __cpp_lib_format >= 202306L // C++26 adds std::basic_format_arg::visit
- VERIFY( args.get(0).visit(is_expected_val) );
-#endif
-}
-
template<typename T>
concept can_format = std::is_default_constructible_v<std::formatter<T, char>>;
@@ -195,30 +177,31 @@ int main()
test_visited_as_handle<__int128>();
test_visited_as_handle<unsigned __int128>();
#endif
-// TODO: This should be visited as handle.
-#ifdef __STDCPP_FLOAT16_T__
- if constexpr (can_format<_Float16>)
- test_visited_as<float, _Float16>();
-#endif
-#ifdef __STDCPP_BFLOAT16_T__
+#ifdef __BFLT16_DIG__
if constexpr (can_format<__gnu_cxx::__bfloat16_t>)
- test_visited_as<float, __gnu_cxx::__bfloat16_t>();
+ test_visited_as_handle<__gnu_cxx::__bfloat16_t>();
+#endif
+#ifdef __FLT16_DIG__
+ if constexpr (can_format<_Float16>)
+ test_visited_as_handle<_Float16>();
#endif
#ifdef __FLT32_DIG__
if constexpr (can_format<_Float32>)
- test_visited_as<float, _Float32>();
+ test_visited_as_handle<_Float32>();
#endif
#ifdef __FLT64_DIG__
if constexpr (can_format<_Float64>)
- test_visited_as<double, _Float64>();
+ test_visited_as_handle<_Float64>();
#endif
#ifdef __FLT128_DIG__
if constexpr (can_format<_Float128>)
-# ifdef _GLIBCXX_LDOUBLE_IS_IEEE_BINARY128
- test_visited_as<long double, _Float128>();
-# else
test_visited_as_handle<_Float128>();
-# endif
+#endif
+#ifdef __SIZEOF_FLOAT128__
+ // __ieee128 is same type as __float128, and may be long double
+ if constexpr (!std::is_same_v<__float128, long double>)
+ if constexpr (can_format<__float128>)
+ test_visited_as_handle<__float128>();
#endif
#ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
if constexpr (!std::is_same_v<__ieee128, long double>)
diff --git a/libstdc++-v3/testsuite/std/format/parse_ctx.cc b/libstdc++-v3/testsuite/std/format/parse_ctx.cc
index b5dd7cd..adafc58 100644
--- a/libstdc++-v3/testsuite/std/format/parse_ctx.cc
+++ b/libstdc++-v3/testsuite/std/format/parse_ctx.cc
@@ -443,6 +443,8 @@ test_custom()
}
#if __cpp_lib_format >= 202305
+#include <stdfloat>
+
struct X { };
template<>
@@ -458,13 +460,20 @@ struct std::formatter<X, char>
if (spec == "int")
{
pc.check_dynamic_spec_integral(pc.next_arg_id());
- integer = true;
+ type = Type::integral;
}
else if (spec == "str")
{
pc.check_dynamic_spec_string(pc.next_arg_id());
- integer = false;
+ type = Type::string;
+ }
+ else if (spec == "float")
+ {
+ pc.check_dynamic_spec<float, double, long double>(pc.next_arg_id());
+ type = Type::floating;
}
+ else if (spec == "other")
+ type = Type::other;
else
throw std::format_error("invalid format-spec");
return pc.begin() + spec.size();
@@ -474,13 +483,44 @@ struct std::formatter<X, char>
format(X, std::format_context& c) const
{
std::visit_format_arg([this]<typename T>(T) { // { dg-warning "deprecated" "" { target c++26 } }
- if (is_integral_v<T> != this->integer)
- throw std::format_error("invalid argument type");
+ constexpr bool is_handle
+ = std::is_same_v<std::basic_format_arg<std::format_context>::handle, T>;
+ constexpr bool is_integral
+ = std::is_same_v<int, T> || std::is_same_v<unsigned int, T>
+ || is_same_v<long long, T> || std::is_same_v<unsigned long long, T>;
+ constexpr bool is_string
+ = std::is_same_v<const char*, T> || std::is_same_v<std::string_view, T>;
+ constexpr bool is_floating
+ = std::is_same_v<float, T> || std::is_same_v<double, T>
+ || std::is_same_v<long double, T>;
+ switch (this->type)
+ {
+ case Type::other:
+ if (is_handle) return;
+ break;
+ case Type::integral:
+ if (is_integral) return;
+ break;
+ case Type::string:
+ if (is_string) return;
+ break;
+ case Type::floating:
+ if (is_floating) return;
+ break;
+ }
+ throw std::format_error("invalid argument type");
}, c.arg(1));
return c.out();
}
private:
- bool integer = false;
+ enum class Type
+ {
+ other,
+ integral,
+ string,
+ floating,
+ };
+ Type type = Type::other;
};
#endif
@@ -497,6 +537,28 @@ test_dynamic_type_check()
(void) std::format("{:int}", X{}, 42L);
(void) std::format("{:str}", X{}, "H2G2");
+ (void) std::format("{:float}", X{}, 10.0);
+
+#ifdef __STDCPP_FLOAT16_T__
+ if constexpr (std::formattable<std::bfloat16_t, char>)
+ (void) std::format("{:other}", X{}, 10.0bf16);
+#endif
+#ifdef __STDCPP_FLOAT16_T__
+ if constexpr (std::formattable<std::float16_t, char>)
+ (void) std::format("{:other}", X{}, 10.0f16);
+#endif
+#ifdef __STDCPP_FLOAT32_T__
+ if constexpr (std::formattable<std::float32_t, char>)
+ (void) std::format("{:other}", X{}, 10.0f32);
+#endif
+#ifdef __STDCPP_FLOAT64_T__
+ if constexpr (std::formattable<std::float64_t, char>)
+ (void) std::format("{:other}", X{}, 10.0f64);
+#endif
+#ifdef __STDCPP_FLOAT128_T__
+ if constexpr (std::formattable<std::float128_t, char>)
+ (void) std::format("{:other}", X{}, 10.0f128);
+#endif
#endif
}