From 91cc7476ee2045c0a4f5d3d87fa6577248ea7b2b Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 29 Nov 2025 16:31:31 +0200 Subject: [PATCH 01/19] avoid preprocessor to make the checker less messy --- .../tests/GH_005504_avoid_function_call_wrapping/test.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp b/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp index 44ec403e220..d3ffb48b7bd 100644 --- a/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp +++ b/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp @@ -146,12 +146,10 @@ int main() { alloc_checker{0}, test_wrapped_call, move_only_function, small_callable>(0); alloc_checker{1}, test_wrapped_call, move_only_function, large_callable>(0); + constexpr bool is_64_bit = sizeof(void*) > 4; + // Moves from function to move_only_function -#ifdef _WIN64 - alloc_checker{0}, -#else - alloc_checker{1}, -#endif + alloc_checker{is_64_bit ? 0 : 1}, test_wrapped_call, function, small_callable>(0); alloc_checker{1}, test_wrapped_call, function, large_callable>(0); From 12d458b13cfa0d5e1c8911a174acdad6a453c558 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 29 Nov 2025 16:33:11 +0200 Subject: [PATCH 02/19] test status quo on abominables and noexcept specifier --- .../test.cpp | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp b/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp index d3ffb48b7bd..a2df15bcb1a 100644 --- a/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp +++ b/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp @@ -70,11 +70,18 @@ struct copy_counter { }; using fn_type = int(copy_counter); +using fn_type_r = int(copy_counter) &; +using fn_type_c = int(copy_counter) const; + +#ifdef __cpp_noexcept_function_type +using fn_type_nx = int(copy_counter) noexcept; +#endif // defined(__cpp_noexcept_function_type) + struct small_callable { const int context = 42; - int operator()(const copy_counter& counter) { + int operator()(const copy_counter& counter) const noexcept { assert(context == 42); return counter.count; } @@ -83,7 +90,7 @@ struct small_callable { struct alignas(128) large_callable { const int context = 1729; - int operator()(const copy_counter& counter) { + int operator()(const copy_counter& counter) const noexcept { assert((reinterpret_cast(this) & 0x7f) == 0); assert(context == 1729); return counter.count; @@ -146,6 +153,25 @@ int main() { alloc_checker{0}, test_wrapped_call, move_only_function, small_callable>(0); alloc_checker{1}, test_wrapped_call, move_only_function, large_callable>(0); + // Abominables and noexcept specifier + alloc_checker{1}, test_wrapped_call, move_only_function, small_callable>(1); + alloc_checker{2}, test_wrapped_call, move_only_function, large_callable>(1); + alloc_checker{1}, test_wrapped_call, move_only_function, small_callable>(1); + alloc_checker{2}, test_wrapped_call, move_only_function, large_callable>(1); + + static_assert(!is_constructible_v, move_only_function>); + static_assert(!is_constructible_v, move_only_function>); + static_assert(!is_constructible_v, move_only_function>); + static_assert(!is_constructible_v, move_only_function>); + +#ifdef __cpp_noexcept_function_type + alloc_checker{1}, test_wrapped_call, move_only_function, small_callable>(1); + alloc_checker{2}, test_wrapped_call, move_only_function, large_callable>(1); + + static_assert(!is_constructible_v, move_only_function>); + static_assert(!is_constructible_v, move_only_function>); +#endif // defined(__cpp_noexcept_function_type) + constexpr bool is_64_bit = sizeof(void*) > 4; // Moves from function to move_only_function @@ -153,6 +179,16 @@ int main() { test_wrapped_call, function, small_callable>(0); alloc_checker{1}, test_wrapped_call, function, large_callable>(0); + // Moves from function to abominable move_only_function + alloc_checker{1}, test_wrapped_call, function, small_callable>(1); + alloc_checker{2}, test_wrapped_call, function, large_callable>(1); + alloc_checker{1}, test_wrapped_call, function, small_callable>(1); + alloc_checker{2}, test_wrapped_call, function, large_callable>(1); + +#ifdef __cpp_noexcept_function_type + static_assert(!is_constructible_v, function>); +#endif // defined(__cpp_noexcept_function_type) + // nulls alloc_checker{0}, test_plain_null>(true); alloc_checker{0}, test_plain_null>(false); From 062fca720b1a336317df23f0b41bf834feb92cbc Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 29 Nov 2025 17:01:49 +0200 Subject: [PATCH 03/19] inner function --- stl/inc/functional | 3 ++- .../test.cpp | 16 +++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/stl/inc/functional b/stl/inc/functional index 65ad553b2da..379efc247a7 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -1576,6 +1576,7 @@ template class _Function_base { public: using result_type = _Rx; + using _Signature_no_cv_noex = _Rx(_Types...); struct _Impl_t { // A per-callable-type structure acting as a virtual function table. // Using vtable emulations gives more flexibility for optimizations and reduces the amount of RTTI data. @@ -2051,7 +2052,7 @@ public: using _Vt = decay_t<_Fn>; static_assert(is_constructible_v<_Vt, _Fn>, "_Vt should be constructible from _Fn. " "(N4950 [func.wrap.move.ctor]/6)"); - if constexpr (is_same_v<_Vt, function<_Signature...>>) { + if constexpr (is_same_v<_Vt, function>) { this->template _Construct_with_old_fn<_Vt>(_STD forward<_Fn>(_Callable)); } else { if constexpr (is_member_pointer_v<_Vt> || is_pointer_v<_Vt> diff --git a/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp b/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp index a2df15bcb1a..7c7f6e5cbde 100644 --- a/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp +++ b/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp @@ -69,12 +69,12 @@ struct copy_counter { int count = 0; }; -using fn_type = int(copy_counter); +using fn_type = int(copy_counter); using fn_type_r = int(copy_counter) &; -using fn_type_c = int(copy_counter) const; +using fn_type_c = int(copy_counter) const; #ifdef __cpp_noexcept_function_type -using fn_type_nx = int(copy_counter) noexcept; +using fn_type_nx = int(copy_counter) noexcept; #endif // defined(__cpp_noexcept_function_type) @@ -180,10 +180,12 @@ int main() { alloc_checker{1}, test_wrapped_call, function, large_callable>(0); // Moves from function to abominable move_only_function - alloc_checker{1}, test_wrapped_call, function, small_callable>(1); - alloc_checker{2}, test_wrapped_call, function, large_callable>(1); - alloc_checker{1}, test_wrapped_call, function, small_callable>(1); - alloc_checker{2}, test_wrapped_call, function, large_callable>(1); + alloc_checker{is_64_bit ? 0 : 1}, + test_wrapped_call, function, small_callable>(0); + alloc_checker{1}, test_wrapped_call, function, large_callable>(0); + alloc_checker{is_64_bit ? 0 : 1}, + test_wrapped_call, function, small_callable>(0); + alloc_checker{1}, test_wrapped_call, function, large_callable>(0); #ifdef __cpp_noexcept_function_type static_assert(!is_constructible_v, function>); From 2569e12faac32efc7ac291e07206571c08cd91bb Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 29 Nov 2025 17:24:07 +0200 Subject: [PATCH 04/19] inner move_only_function --- stl/inc/functional | 11 +++++++++++ .../GH_005504_avoid_function_call_wrapping/test.cpp | 12 ++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/stl/inc/functional b/stl/inc/functional index 379efc247a7..beebbfc6846 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -2063,11 +2063,22 @@ public: } } + if constexpr (_Is_specialization_v<_Vt, move_only_function>) { + if constexpr (is_same_v) { + this->_Checked_move(this->_Data, _Callable._Data); + _Callable._Reset_to_null(); + return; + } + } + using _VtInvQuals = _Call::template _VtInvQuals<_Vt>; this->template _Construct_with_fn<_Vt, _VtInvQuals>(_STD forward<_Fn>(_Callable)); } } + template + friend class move_only_function; + template requires _Enable_in_place_constructor<_Fn, _CTypes...> explicit move_only_function(in_place_type_t<_Fn>, _CTypes&&... _Args) { diff --git a/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp b/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp index 7c7f6e5cbde..ce96590e207 100644 --- a/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp +++ b/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp @@ -154,10 +154,10 @@ int main() { alloc_checker{1}, test_wrapped_call, move_only_function, large_callable>(0); // Abominables and noexcept specifier - alloc_checker{1}, test_wrapped_call, move_only_function, small_callable>(1); - alloc_checker{2}, test_wrapped_call, move_only_function, large_callable>(1); - alloc_checker{1}, test_wrapped_call, move_only_function, small_callable>(1); - alloc_checker{2}, test_wrapped_call, move_only_function, large_callable>(1); + alloc_checker{0}, test_wrapped_call, move_only_function, small_callable>(0); + alloc_checker{1}, test_wrapped_call, move_only_function, large_callable>(0); + alloc_checker{0}, test_wrapped_call, move_only_function, small_callable>(0); + alloc_checker{1}, test_wrapped_call, move_only_function, large_callable>(0); static_assert(!is_constructible_v, move_only_function>); static_assert(!is_constructible_v, move_only_function>); @@ -165,8 +165,8 @@ int main() { static_assert(!is_constructible_v, move_only_function>); #ifdef __cpp_noexcept_function_type - alloc_checker{1}, test_wrapped_call, move_only_function, small_callable>(1); - alloc_checker{2}, test_wrapped_call, move_only_function, large_callable>(1); + alloc_checker{0}, test_wrapped_call, move_only_function, small_callable>(0); + alloc_checker{1}, test_wrapped_call, move_only_function, large_callable>(0); static_assert(!is_constructible_v, move_only_function>); static_assert(!is_constructible_v, move_only_function>); From d6e3032acb66ac31c3edcf833da5c549267dae47 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 29 Nov 2025 17:46:25 +0200 Subject: [PATCH 05/19] format --- stl/inc/functional | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/functional b/stl/inc/functional index beebbfc6846..76421ba6b15 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -1575,7 +1575,7 @@ _NODISCARD void* _Function_new_large(_CTypes&&... _Args) { template class _Function_base { public: - using result_type = _Rx; + using result_type = _Rx; using _Signature_no_cv_noex = _Rx(_Types...); struct _Impl_t { // A per-callable-type structure acting as a virtual function table. From e3d13adf333fc90fb5e7a1d7b3457b8870c1c862 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 29 Nov 2025 17:48:14 +0200 Subject: [PATCH 06/19] -unnecessary repetitions --- .../std/tests/GH_005504_avoid_function_call_wrapping/test.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp b/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp index ce96590e207..2a9f4954fb8 100644 --- a/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp +++ b/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp @@ -160,8 +160,6 @@ int main() { alloc_checker{1}, test_wrapped_call, move_only_function, large_callable>(0); static_assert(!is_constructible_v, move_only_function>); - static_assert(!is_constructible_v, move_only_function>); - static_assert(!is_constructible_v, move_only_function>); static_assert(!is_constructible_v, move_only_function>); #ifdef __cpp_noexcept_function_type @@ -169,7 +167,6 @@ int main() { alloc_checker{1}, test_wrapped_call, move_only_function, large_callable>(0); static_assert(!is_constructible_v, move_only_function>); - static_assert(!is_constructible_v, move_only_function>); #endif // defined(__cpp_noexcept_function_type) constexpr bool is_64_bit = sizeof(void*) > 4; From febad5589d9935bafefcde56c5cc353fb915cb51 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 29 Nov 2025 17:51:20 +0200 Subject: [PATCH 07/19] -newline --- tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp b/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp index 2a9f4954fb8..00cec5c30be 100644 --- a/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp +++ b/tests/std/tests/GH_005504_avoid_function_call_wrapping/test.cpp @@ -77,7 +77,6 @@ using fn_type_c = int(copy_counter) const; using fn_type_nx = int(copy_counter) noexcept; #endif // defined(__cpp_noexcept_function_type) - struct small_callable { const int context = 42; From ffd98f88bc0082ea218ddee4a96c675588071b23 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 29 Nov 2025 18:37:49 +0200 Subject: [PATCH 08/19] clearer name --- stl/inc/functional | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/stl/inc/functional b/stl/inc/functional index 76421ba6b15..e0a0f8d84a3 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -1575,8 +1575,8 @@ _NODISCARD void* _Function_new_large(_CTypes&&... _Args) { template class _Function_base { public: - using result_type = _Rx; - using _Signature_no_cv_noex = _Rx(_Types...); + using result_type = _Rx; + using _Signature_without_cv_ref_noex = _Rx(_Types...); struct _Impl_t { // A per-callable-type structure acting as a virtual function table. // Using vtable emulations gives more flexibility for optimizations and reduces the amount of RTTI data. @@ -2052,7 +2052,7 @@ public: using _Vt = decay_t<_Fn>; static_assert(is_constructible_v<_Vt, _Fn>, "_Vt should be constructible from _Fn. " "(N4950 [func.wrap.move.ctor]/6)"); - if constexpr (is_same_v<_Vt, function>) { + if constexpr (is_same_v<_Vt, function>) { this->template _Construct_with_old_fn<_Vt>(_STD forward<_Fn>(_Callable)); } else { if constexpr (is_member_pointer_v<_Vt> || is_pointer_v<_Vt> @@ -2064,7 +2064,8 @@ public: } if constexpr (_Is_specialization_v<_Vt, move_only_function>) { - if constexpr (is_same_v) { + if constexpr (is_same_v) { this->_Checked_move(this->_Data, _Callable._Data); _Callable._Reset_to_null(); return; From ec48ebb43884f1b18ade34c13a34a673e9eb5154 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 29 Nov 2025 18:47:53 +0200 Subject: [PATCH 09/19] avoid emitting dead code --- stl/inc/functional | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/stl/inc/functional b/stl/inc/functional index e0a0f8d84a3..2d8b73c5efa 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -2033,6 +2033,19 @@ private: is_constructible_v, initializer_list<_Ux>&, _CTypes...> && _Call::template _Is_callable_from>; + template + friend class move_only_function; + + template + static constexpr bool _Is_move_only_fuction_varying_cv_ref_noex() { + if constexpr (_Is_specialization_v<_Vt, move_only_function>) { + return is_same_v; + } else { + return false; + } + } + public: using typename _Call::result_type; @@ -2063,23 +2076,16 @@ public: } } - if constexpr (_Is_specialization_v<_Vt, move_only_function>) { - if constexpr (is_same_v) { - this->_Checked_move(this->_Data, _Callable._Data); - _Callable._Reset_to_null(); - return; - } + if constexpr (_Is_move_only_fuction_varying_cv_ref_noex<_Vt>()) { + this->_Checked_move(this->_Data, _Callable._Data); + _Callable._Reset_to_null(); + } else { + using _VtInvQuals = _Call::template _VtInvQuals<_Vt>; + this->template _Construct_with_fn<_Vt, _VtInvQuals>(_STD forward<_Fn>(_Callable)); } - - using _VtInvQuals = _Call::template _VtInvQuals<_Vt>; - this->template _Construct_with_fn<_Vt, _VtInvQuals>(_STD forward<_Fn>(_Callable)); } } - template - friend class move_only_function; - template requires _Enable_in_place_constructor<_Fn, _CTypes...> explicit move_only_function(in_place_type_t<_Fn>, _CTypes&&... _Args) { From d726b1265fa3ff4f2a495ec04aa635562b15a85e Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 29 Nov 2025 19:36:10 +0200 Subject: [PATCH 10/19] let's not pretend it's non-static --- stl/inc/functional | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/functional b/stl/inc/functional index 2d8b73c5efa..ce38d49ea95 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -2077,7 +2077,7 @@ public: } if constexpr (_Is_move_only_fuction_varying_cv_ref_noex<_Vt>()) { - this->_Checked_move(this->_Data, _Callable._Data); + _Call::_Checked_move(this->_Data, _Callable._Data); _Callable._Reset_to_null(); } else { using _VtInvQuals = _Call::template _VtInvQuals<_Vt>; From 2c1002c505da5d4f93d9640f25ef0161a6612bb9 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 30 Nov 2025 16:58:09 +0200 Subject: [PATCH 11/19] no lvalue reference --- stl/inc/functional | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/stl/inc/functional b/stl/inc/functional index ce38d49ea95..1c998602605 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -2065,7 +2065,8 @@ public: using _Vt = decay_t<_Fn>; static_assert(is_constructible_v<_Vt, _Fn>, "_Vt should be constructible from _Fn. " "(N4950 [func.wrap.move.ctor]/6)"); - if constexpr (is_same_v<_Vt, function>) { + if constexpr (!is_lvalue_reference_v<_Fn> + && is_same_v<_Vt, function>) { this->template _Construct_with_old_fn<_Vt>(_STD forward<_Fn>(_Callable)); } else { if constexpr (is_member_pointer_v<_Vt> || is_pointer_v<_Vt> @@ -2076,7 +2077,7 @@ public: } } - if constexpr (_Is_move_only_fuction_varying_cv_ref_noex<_Vt>()) { + if constexpr (!is_lvalue_reference_v<_Fn> && _Is_move_only_fuction_varying_cv_ref_noex<_Vt>()) { _Call::_Checked_move(this->_Data, _Callable._Data); _Callable._Reset_to_null(); } else { From ed5dfc0b26096f97a2d05211433d4167d77e741a Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 30 Nov 2025 19:27:12 +0200 Subject: [PATCH 12/19] this part is not needed, move_only_function can't do this anyway --- stl/inc/functional | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/functional b/stl/inc/functional index 1c998602605..073a2d4596e 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -2077,7 +2077,7 @@ public: } } - if constexpr (!is_lvalue_reference_v<_Fn> && _Is_move_only_fuction_varying_cv_ref_noex<_Vt>()) { + if constexpr (_Is_move_only_fuction_varying_cv_ref_noex<_Vt>()) { _Call::_Checked_move(this->_Data, _Callable._Data); _Callable._Reset_to_null(); } else { From 21af113de280892d5aff140af4ddd8eb9b316a58 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sat, 17 Jan 2026 08:32:46 -0800 Subject: [PATCH 13/19] Fix product code typo. --- stl/inc/functional | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/functional b/stl/inc/functional index 062888fac41..2f127c28979 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -2065,7 +2065,7 @@ private: friend class move_only_function; template - static constexpr bool _Is_move_only_fuction_varying_cv_ref_noex() { + static constexpr bool _Is_move_only_function_varying_cv_ref_noex() { if constexpr (_Is_specialization_v<_Vt, move_only_function>) { return is_same_v; @@ -2104,7 +2104,7 @@ public: } } - if constexpr (_Is_move_only_fuction_varying_cv_ref_noex<_Vt>()) { + if constexpr (_Is_move_only_function_varying_cv_ref_noex<_Vt>()) { _Call::_Checked_move(this->_Data, _Callable._Data); _Callable._Reset_to_null(); } else { From 1f17e2678bd19c5d4f8244a18959b481256c6ab9 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 18 Jan 2026 20:01:35 +0200 Subject: [PATCH 14/19] Fix strict aliasing concern --- stl/inc/functional | 122 +++++++++++------- stl/inc/yvals_core.h | 4 +- .../move_only_function_specializations.py | 6 +- 3 files changed, 83 insertions(+), 49 deletions(-) diff --git a/stl/inc/functional b/stl/inc/functional index 2f127c28979..3823fd4f4f6 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -974,7 +974,7 @@ private: }; #if _HAS_CXX23 -template +template class _Function_base; #endif // _HAS_CXX23 @@ -1105,9 +1105,8 @@ protected: private: #if _HAS_CXX23 - friend _Function_base<_Ret, false, _Types...>; + friend _Function_base<_Ret, _Types...>; #endif // _HAS_CXX23 - bool _Local() const noexcept { // test for locally stored copy of object return _Getimpl() == static_cast(&_Mystorage); } @@ -1574,7 +1573,7 @@ _NODISCARD void* _Function_new_large(_CTypes&&... _Args) { return _Ptr; } -template +template class _Function_base { public: using result_type = _Rx; @@ -1589,7 +1588,7 @@ public: // empty function from a DLL that is unloaded later, and then safely moving/destroying that empty function. // Calls target - _Rx(__stdcall* _Invoke)(void*, _Types&&...) _NOEXCEPT_FNPTR_COND(_Noexcept); + _Rx(__stdcall* _Invoke)(void*, _Types&&...); // Moves the data, including pointer to "vtable", AND destroys old data (not resetting its "vtable"). // nullptr if we can trivially move two pointers. void(__stdcall* _Move)(_Function_data&, _Function_data&) _NOEXCEPT_FNPTR; @@ -1622,16 +1621,16 @@ public: _Data._Impl = nullptr; } - template + template void _Construct_with_old_fn(_Fn&& _Func) { const auto _Old_fn_impl = _Func._Getimpl(); if (_Old_fn_impl == nullptr) { - _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_null, _Vt, void>(); + _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_null, _Vt, _Noexcept, void>(); } else if (_Func._Local()) { #ifdef _WIN64 _STL_INTERNAL_STATIC_ASSERT(alignof(max_align_t) == alignof(void*)); // 64-bit target, can put small function into small move_only_function directly - _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_small, _Vt, void>(); + _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_small, _Vt, _Noexcept, void>(); if constexpr (is_lvalue_reference_v<_Fn>) { _Old_fn_impl->_Copy(_Data._Buf_ptr()); } else { @@ -1664,12 +1663,12 @@ public: _Func._Tidy(); } - _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_small_as_large, _Vt, void>(); + _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_small_as_large, _Vt, _Noexcept, void>(); _Data._Set_large_fn_ptr(_Where); #endif // ^^^ 32-bit ^^^ } else { // Just take ownership of the inner impl pointer - _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_large, _Vt, void>(); + _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_large, _Vt, _Noexcept, void>(); if constexpr (is_lvalue_reference_v<_Fn>) { _Data._Set_large_fn_ptr(_Old_fn_impl->_Copy(nullptr)); } else { @@ -1679,9 +1678,9 @@ public: } } - template + template void _Construct_with_fn(_CTypes&&... _Args) { - _Data._Impl = _Create_impl_ptr<_Impl_kind::_Usual, _Vt, _VtInvQuals>(); + _Data._Impl = _Create_impl_ptr<_Impl_kind::_Usual, _Vt, _Noexcept, _VtInvQuals>(); if constexpr (_Large_function_engaged<_Vt>) { _Data._Set_large_fn_ptr(_STD _Function_new_large<_Vt>(_STD forward<_CTypes>(_Args)...)); } else { @@ -1757,8 +1756,13 @@ public: || sizeof(_Vt) > _Function_data::_Buf_size<_Vt> || !is_nothrow_move_constructible_v<_Vt>; + template _NODISCARD auto _Get_invoke() const noexcept { - return _Get_impl(_Data)->_Invoke; + if constexpr (_Noexcept) { + return reinterpret_cast<_Rx(__stdcall*)(void*, _Types&&...) noexcept>(_Get_impl(_Data)->_Invoke); + } else { + return _Get_impl(_Data)->_Invoke; + } } _NODISCARD static const _Impl_t* _Get_impl(const _Function_data& _Data) noexcept { @@ -1772,7 +1776,7 @@ public: return _Ret ? _Ret : &_Null_move_only_function; } - template <_Impl_kind _Kind, class _Vt, class _VtInvQuals> + template <_Impl_kind _Kind, class _Vt, bool _Noexcept, class _VtInvQuals> _NODISCARD static constexpr _Impl_t _Create_impl() noexcept { _Impl_t _Impl{}; if constexpr (_Kind != _Impl_kind::_Usual) { @@ -1835,9 +1839,9 @@ public: return _Impl; } - template <_Impl_kind _Kind, class _Vt, class _VtInvQuals> + template <_Impl_kind _Kind, class _Vt, bool _Noexcept, class _VtInvQuals> _NODISCARD static const _Impl_t* _Create_impl_ptr() noexcept { - static constexpr _Impl_t _Impl = _Create_impl<_Kind, _Vt, _VtInvQuals>(); + static constexpr _Impl_t _Impl = _Create_impl<_Kind, _Vt, _Noexcept, _VtInvQuals>(); return &_Impl; } }; @@ -1857,7 +1861,7 @@ class _Function_call { // Beginning of generated code - DO NOT EDIT manually! template class _Function_call<_Rx(_Types...)> // Generated code - DO NOT EDIT manually! - : public _Function_base<_Rx, false, _Types...> { + : public _Function_base<_Rx, _Types...> { public: template using _VtInvQuals = _Vt&; @@ -1866,14 +1870,16 @@ public: static constexpr bool _Is_callable_from = is_invocable_r_v<_Rx, _Vt, _Types...> && is_invocable_r_v<_Rx, _Vt&, _Types...>; + static constexpr bool _Noexcept = false; + _Rx operator()(_Types... _Args) { - return this->_Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...); + return this->template _Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...); } }; template class _Function_call<_Rx(_Types...) &> // Generated code - DO NOT EDIT manually! - : public _Function_base<_Rx, false, _Types...> { + : public _Function_base<_Rx, _Types...> { public: template using _VtInvQuals = _Vt&; @@ -1881,14 +1887,16 @@ public: template static constexpr bool _Is_callable_from = is_invocable_r_v<_Rx, _Vt&, _Types...>; + static constexpr bool _Noexcept = false; + _Rx operator()(_Types... _Args) & { - return this->_Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...); + return this->template _Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...); } }; template class _Function_call<_Rx(_Types...) &&> // Generated code - DO NOT EDIT manually! - : public _Function_base<_Rx, false, _Types...> { + : public _Function_base<_Rx, _Types...> { public: template using _VtInvQuals = _Vt&&; @@ -1896,14 +1904,16 @@ public: template static constexpr bool _Is_callable_from = is_invocable_r_v<_Rx, _Vt, _Types...>; + static constexpr bool _Noexcept = false; + _Rx operator()(_Types... _Args) && { - return this->_Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...); + return this->template _Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...); } }; template class _Function_call<_Rx(_Types...) const> // Generated code - DO NOT EDIT manually! - : public _Function_base<_Rx, false, _Types...> { + : public _Function_base<_Rx, _Types...> { public: template using _VtInvQuals = const _Vt&; @@ -1912,14 +1922,17 @@ public: static constexpr bool _Is_callable_from = is_invocable_r_v<_Rx, const _Vt, _Types...> && is_invocable_r_v<_Rx, const _Vt&, _Types...>; + static constexpr bool _Noexcept = false; + _Rx operator()(_Types... _Args) const { - return this->_Get_invoke()(const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); + return this->template _Get_invoke()( + const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); } }; template class _Function_call<_Rx(_Types...) const&> // Generated code - DO NOT EDIT manually! - : public _Function_base<_Rx, false, _Types...> { + : public _Function_base<_Rx, _Types...> { public: template using _VtInvQuals = const _Vt&; @@ -1927,14 +1940,17 @@ public: template static constexpr bool _Is_callable_from = is_invocable_r_v<_Rx, const _Vt&, _Types...>; + static constexpr bool _Noexcept = false; + _Rx operator()(_Types... _Args) const& { - return this->_Get_invoke()(const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); + return this->template _Get_invoke()( + const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); } }; template class _Function_call<_Rx(_Types...) const&&> // Generated code - DO NOT EDIT manually! - : public _Function_base<_Rx, false, _Types...> { + : public _Function_base<_Rx, _Types...> { public: template using _VtInvQuals = const _Vt&&; @@ -1942,15 +1958,18 @@ public: template static constexpr bool _Is_callable_from = is_invocable_r_v<_Rx, const _Vt, _Types...>; + static constexpr bool _Noexcept = false; + _Rx operator()(_Types... _Args) const&& { - return this->_Get_invoke()(const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); + return this->template _Get_invoke()( + const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); } }; #ifdef __cpp_noexcept_function_type template class _Function_call<_Rx(_Types...) noexcept> // Generated code - DO NOT EDIT manually! - : public _Function_base<_Rx, true, _Types...> { + : public _Function_base<_Rx, _Types...> { public: template using _VtInvQuals = _Vt&; @@ -1959,14 +1978,16 @@ public: static constexpr bool _Is_callable_from = is_nothrow_invocable_r_v<_Rx, _Vt, _Types...> && is_nothrow_invocable_r_v<_Rx, _Vt&, _Types...>; + static constexpr bool _Noexcept = true; + _Rx operator()(_Types... _Args) noexcept { - return this->_Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...); + return this->template _Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...); } }; template class _Function_call<_Rx(_Types...) & noexcept> // Generated code - DO NOT EDIT manually! - : public _Function_base<_Rx, true, _Types...> { + : public _Function_base<_Rx, _Types...> { public: template using _VtInvQuals = _Vt&; @@ -1974,14 +1995,16 @@ public: template static constexpr bool _Is_callable_from = is_nothrow_invocable_r_v<_Rx, _Vt&, _Types...>; + static constexpr bool _Noexcept = true; + _Rx operator()(_Types... _Args) & noexcept { - return this->_Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...); + return this->template _Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...); } }; template class _Function_call<_Rx(_Types...) && noexcept> // Generated code - DO NOT EDIT manually! - : public _Function_base<_Rx, true, _Types...> { + : public _Function_base<_Rx, _Types...> { public: template using _VtInvQuals = _Vt&&; @@ -1989,14 +2012,16 @@ public: template static constexpr bool _Is_callable_from = is_nothrow_invocable_r_v<_Rx, _Vt, _Types...>; + static constexpr bool _Noexcept = true; + _Rx operator()(_Types... _Args) && noexcept { - return this->_Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...); + return this->template _Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...); } }; template class _Function_call<_Rx(_Types...) const noexcept> // Generated code - DO NOT EDIT manually! - : public _Function_base<_Rx, true, _Types...> { + : public _Function_base<_Rx, _Types...> { public: template using _VtInvQuals = const _Vt&; @@ -2005,14 +2030,17 @@ public: static constexpr bool _Is_callable_from = is_nothrow_invocable_r_v<_Rx, const _Vt, _Types...> && is_nothrow_invocable_r_v<_Rx, const _Vt&, _Types...>; + static constexpr bool _Noexcept = true; + _Rx operator()(_Types... _Args) const noexcept { - return this->_Get_invoke()(const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); + return this->template _Get_invoke()( + const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); } }; template class _Function_call<_Rx(_Types...) const & noexcept> // Generated code - DO NOT EDIT manually! - : public _Function_base<_Rx, true, _Types...> { + : public _Function_base<_Rx, _Types...> { public: template using _VtInvQuals = const _Vt&; @@ -2020,14 +2048,17 @@ public: template static constexpr bool _Is_callable_from = is_nothrow_invocable_r_v<_Rx, const _Vt&, _Types...>; + static constexpr bool _Noexcept = true; + _Rx operator()(_Types... _Args) const& noexcept { - return this->_Get_invoke()(const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); + return this->template _Get_invoke()( + const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); } }; template class _Function_call<_Rx(_Types...) const && noexcept> // Generated code - DO NOT EDIT manually! - : public _Function_base<_Rx, true, _Types...> { + : public _Function_base<_Rx, _Types...> { public: template using _VtInvQuals = const _Vt&&; @@ -2035,8 +2066,11 @@ public: template static constexpr bool _Is_callable_from = is_nothrow_invocable_r_v<_Rx, const _Vt, _Types...>; + static constexpr bool _Noexcept = true; + _Rx operator()(_Types... _Args) const&& noexcept { - return this->_Get_invoke()(const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); + return this->template _Get_invoke()( + const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); } }; #endif // defined(__cpp_noexcept_function_type) @@ -2094,7 +2128,7 @@ public: static_assert(is_constructible_v<_Vt, _Fn>, "_Vt should be constructible from _Fn. " "(N4950 [func.wrap.move.ctor]/6)"); if constexpr (is_same_v<_Vt, function>) { - this->template _Construct_with_old_fn<_Vt>(_STD forward<_Fn>(_Callable)); + this->template _Construct_with_old_fn<_Vt, _Call::_Noexcept>(_STD forward<_Fn>(_Callable)); } else { if constexpr (is_member_pointer_v<_Vt> || is_pointer_v<_Vt> || _Is_specialization_v<_Vt, move_only_function>) { @@ -2109,7 +2143,7 @@ public: _Callable._Reset_to_null(); } else { using _VtInvQuals = _Call::template _VtInvQuals<_Vt>; - this->template _Construct_with_fn<_Vt, _VtInvQuals>(_STD forward<_Fn>(_Callable)); + this->template _Construct_with_fn<_Vt, _Call::_Noexcept, _VtInvQuals>(_STD forward<_Fn>(_Callable)); } } } @@ -2121,7 +2155,7 @@ public: static_assert(is_same_v<_Vt, _Fn>, "_Vt should be the same type as _Fn. (N4950 [func.wrap.move.ctor]/12)"); using _VtInvQuals = _Call::template _VtInvQuals<_Vt>; - this->template _Construct_with_fn<_Vt, _VtInvQuals>(_STD forward<_CTypes>(_Args)...); + this->template _Construct_with_fn<_Vt, _Call::_Noexcept, _VtInvQuals>(_STD forward<_CTypes>(_Args)...); } template @@ -2131,7 +2165,7 @@ public: static_assert(is_same_v<_Vt, _Fn>, "_Vt should be the same type as _Fn. (N4950 [func.wrap.move.ctor]/18)"); using _VtInvQuals = _Call::template _VtInvQuals<_Vt>; - this->template _Construct_with_fn<_Vt, _VtInvQuals>(_Li, _STD forward<_CTypes>(_Args)...); + this->template _Construct_with_fn<_Vt, _Call::_Noexcept, _VtInvQuals>(_Li, _STD forward<_CTypes>(_Args)...); } ~move_only_function() { diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 7301d3fda1e..705a144947d 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -1930,11 +1930,9 @@ _EMIT_STL_ERROR(STL1013, "The STL doesn't support /RTCc because it rejects confo // The earliest Windows supported by this implementation is Windows 10. #ifdef __cpp_noexcept_function_type -#define _NOEXCEPT_FNPTR noexcept -#define _NOEXCEPT_FNPTR_COND(...) noexcept(__VA_ARGS__) +#define _NOEXCEPT_FNPTR noexcept #else // ^^^ defined(__cpp_noexcept_function_type) / !defined(__cpp_noexcept_function_type) vvv #define _NOEXCEPT_FNPTR -#define _NOEXCEPT_FNPTR_COND(...) #endif // ^^^ !defined(__cpp_noexcept_function_type) ^^^ #ifdef __clang__ diff --git a/tools/scripts/move_only_function_specializations.py b/tools/scripts/move_only_function_specializations.py index ad49c62e49c..d5ed8be756d 100644 --- a/tools/scripts/move_only_function_specializations.py +++ b/tools/scripts/move_only_function_specializations.py @@ -6,7 +6,7 @@ def specialization(self: str, cv: str, ref: str, ref_inv: str, noex: str, noex_val: str, callable: str) -> str: return f"""template class _Function_call<_Rx(_Types...) {cv} {ref} {noex}> // Generated code - DO NOT EDIT manually! - : public _Function_base<_Rx, {noex_val}, _Types...> {{ + : public _Function_base<_Rx, _Types...> {{ public: template using _VtInvQuals = {cv} _Vt {ref_inv}; @@ -14,8 +14,10 @@ class _Function_call<_Rx(_Types...) {cv} {ref} {noex}> // Generated code - DO NO template static constexpr bool _Is_callable_from = {callable}; + static constexpr bool _Noexcept = {noex_val}; + _Rx operator()(_Types... _Args) {cv} {ref} {noex} {{ - return this->_Get_invoke()({self}, _STD forward<_Types>(_Args)...); + return this->template _Get_invoke<{noex_val}>()({self}, _STD forward<_Types>(_Args)...); }} }}; """ From 4c8669a715c6ee2efcec9b2c8136939a9c7a0edf Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 18 Jan 2026 20:44:37 +0200 Subject: [PATCH 15/19] old function is never noexcept --- stl/inc/functional | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/stl/inc/functional b/stl/inc/functional index 3823fd4f4f6..600c0f114cd 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -1621,16 +1621,16 @@ public: _Data._Impl = nullptr; } - template + template void _Construct_with_old_fn(_Fn&& _Func) { const auto _Old_fn_impl = _Func._Getimpl(); if (_Old_fn_impl == nullptr) { - _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_null, _Vt, _Noexcept, void>(); + _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_null, _Vt, false, void>(); } else if (_Func._Local()) { #ifdef _WIN64 _STL_INTERNAL_STATIC_ASSERT(alignof(max_align_t) == alignof(void*)); // 64-bit target, can put small function into small move_only_function directly - _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_small, _Vt, _Noexcept, void>(); + _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_small, _Vt, false, void>(); if constexpr (is_lvalue_reference_v<_Fn>) { _Old_fn_impl->_Copy(_Data._Buf_ptr()); } else { @@ -1663,12 +1663,12 @@ public: _Func._Tidy(); } - _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_small_as_large, _Vt, _Noexcept, void>(); + _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_small_as_large, _Vt, false, void>(); _Data._Set_large_fn_ptr(_Where); #endif // ^^^ 32-bit ^^^ } else { // Just take ownership of the inner impl pointer - _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_large, _Vt, _Noexcept, void>(); + _Data._Impl = _Create_impl_ptr<_Impl_kind::_Old_fn_large, _Vt, false, void>(); if constexpr (is_lvalue_reference_v<_Fn>) { _Data._Set_large_fn_ptr(_Old_fn_impl->_Copy(nullptr)); } else { @@ -2128,7 +2128,7 @@ public: static_assert(is_constructible_v<_Vt, _Fn>, "_Vt should be constructible from _Fn. " "(N4950 [func.wrap.move.ctor]/6)"); if constexpr (is_same_v<_Vt, function>) { - this->template _Construct_with_old_fn<_Vt, _Call::_Noexcept>(_STD forward<_Fn>(_Callable)); + this->template _Construct_with_old_fn<_Vt>(_STD forward<_Fn>(_Callable)); } else { if constexpr (is_member_pointer_v<_Vt> || is_pointer_v<_Vt> || _Is_specialization_v<_Vt, move_only_function>) { From ff3b0c63cb3e8f0404a817240a4ee15a6e1437ed Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sun, 18 Jan 2026 10:23:29 -0800 Subject: [PATCH 16/19] Use `_Noexcept` in the generator. --- tools/scripts/move_only_function_specializations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/scripts/move_only_function_specializations.py b/tools/scripts/move_only_function_specializations.py index d5ed8be756d..122b2c14d9e 100644 --- a/tools/scripts/move_only_function_specializations.py +++ b/tools/scripts/move_only_function_specializations.py @@ -17,7 +17,7 @@ class _Function_call<_Rx(_Types...) {cv} {ref} {noex}> // Generated code - DO NO static constexpr bool _Noexcept = {noex_val}; _Rx operator()(_Types... _Args) {cv} {ref} {noex} {{ - return this->template _Get_invoke<{noex_val}>()({self}, _STD forward<_Types>(_Args)...); + return this->template _Get_invoke<_Noexcept>()({self}, _STD forward<_Types>(_Args)...); }} }}; """ From ab58959385656d04ee4ea6de1a28130d5dab96f7 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sun, 18 Jan 2026 10:25:26 -0800 Subject: [PATCH 17/19] Regenerate. --- stl/inc/functional | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/stl/inc/functional b/stl/inc/functional index 600c0f114cd..2bca84c733f 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -1873,7 +1873,7 @@ public: static constexpr bool _Noexcept = false; _Rx operator()(_Types... _Args) { - return this->template _Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...); + return this->template _Get_invoke<_Noexcept>()(&this->_Data, _STD forward<_Types>(_Args)...); } }; @@ -1890,7 +1890,7 @@ public: static constexpr bool _Noexcept = false; _Rx operator()(_Types... _Args) & { - return this->template _Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...); + return this->template _Get_invoke<_Noexcept>()(&this->_Data, _STD forward<_Types>(_Args)...); } }; @@ -1907,7 +1907,7 @@ public: static constexpr bool _Noexcept = false; _Rx operator()(_Types... _Args) && { - return this->template _Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...); + return this->template _Get_invoke<_Noexcept>()(&this->_Data, _STD forward<_Types>(_Args)...); } }; @@ -1925,7 +1925,7 @@ public: static constexpr bool _Noexcept = false; _Rx operator()(_Types... _Args) const { - return this->template _Get_invoke()( + return this->template _Get_invoke<_Noexcept>()( const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); } }; @@ -1943,7 +1943,7 @@ public: static constexpr bool _Noexcept = false; _Rx operator()(_Types... _Args) const& { - return this->template _Get_invoke()( + return this->template _Get_invoke<_Noexcept>()( const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); } }; @@ -1961,7 +1961,7 @@ public: static constexpr bool _Noexcept = false; _Rx operator()(_Types... _Args) const&& { - return this->template _Get_invoke()( + return this->template _Get_invoke<_Noexcept>()( const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); } }; @@ -1981,7 +1981,7 @@ public: static constexpr bool _Noexcept = true; _Rx operator()(_Types... _Args) noexcept { - return this->template _Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...); + return this->template _Get_invoke<_Noexcept>()(&this->_Data, _STD forward<_Types>(_Args)...); } }; @@ -1998,7 +1998,7 @@ public: static constexpr bool _Noexcept = true; _Rx operator()(_Types... _Args) & noexcept { - return this->template _Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...); + return this->template _Get_invoke<_Noexcept>()(&this->_Data, _STD forward<_Types>(_Args)...); } }; @@ -2015,7 +2015,7 @@ public: static constexpr bool _Noexcept = true; _Rx operator()(_Types... _Args) && noexcept { - return this->template _Get_invoke()(&this->_Data, _STD forward<_Types>(_Args)...); + return this->template _Get_invoke<_Noexcept>()(&this->_Data, _STD forward<_Types>(_Args)...); } }; @@ -2033,7 +2033,7 @@ public: static constexpr bool _Noexcept = true; _Rx operator()(_Types... _Args) const noexcept { - return this->template _Get_invoke()( + return this->template _Get_invoke<_Noexcept>()( const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); } }; @@ -2051,7 +2051,7 @@ public: static constexpr bool _Noexcept = true; _Rx operator()(_Types... _Args) const& noexcept { - return this->template _Get_invoke()( + return this->template _Get_invoke<_Noexcept>()( const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); } }; @@ -2069,7 +2069,7 @@ public: static constexpr bool _Noexcept = true; _Rx operator()(_Types... _Args) const&& noexcept { - return this->template _Get_invoke()( + return this->template _Get_invoke<_Noexcept>()( const_cast<_Function_data*>(&this->_Data), _STD forward<_Types>(_Args)...); } }; From a05d84a1000ecefd4a57b473415179a0613db78a Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sun, 18 Jan 2026 10:36:49 -0800 Subject: [PATCH 18/19] Restore newline. --- stl/inc/functional | 1 + 1 file changed, 1 insertion(+) diff --git a/stl/inc/functional b/stl/inc/functional index 2bca84c733f..0e668d981ef 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -1107,6 +1107,7 @@ private: #if _HAS_CXX23 friend _Function_base<_Ret, _Types...>; #endif // _HAS_CXX23 + bool _Local() const noexcept { // test for locally stored copy of object return _Getimpl() == static_cast(&_Mystorage); } From 5f2f254375d70fe09d92a7bc2069f9d2625e0b91 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sun, 18 Jan 2026 10:42:32 -0800 Subject: [PATCH 19/19] Always respect `__cpp_noexcept_function_type`. --- stl/inc/functional | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/stl/inc/functional b/stl/inc/functional index 0e668d981ef..21654698b9b 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -1760,7 +1760,11 @@ public: template _NODISCARD auto _Get_invoke() const noexcept { if constexpr (_Noexcept) { +#ifdef __cpp_noexcept_function_type return reinterpret_cast<_Rx(__stdcall*)(void*, _Types&&...) noexcept>(_Get_impl(_Data)->_Invoke); +#else + static_assert(false); // when noexcept isn't in the type system, this should never be selected +#endif } else { return _Get_impl(_Data)->_Invoke; }