From: Tomasz Kamiński Date: Tue, 23 Sep 2025 06:54:28 +0000 (+0200) Subject: libstdc++: Make function_ref(nontype, r) CTAD SFINAE friendly [PR121940] X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7dd28f0a815cdaf52b6f8f6039cabfde256aacc1;p=thirdparty%2Fgcc.git libstdc++: Make function_ref(nontype, r) CTAD SFINAE friendly [PR121940] Instantiating the __deduce_funcref function body for function pointers without arguments or member pointers with non-matching object types previously led to hard errors due to the formation of invalid types. The __deduce_funcref function is now adjusted to return void in such cases. The corresponding function_ref deduction guide is constrained to only match if the return type is not void, making it SFINAE friendly. PR libstdc++/121940 libstdc++-v3/ChangeLog: * include/bits/funcwrap.h (__polyfunc::__deduce_funcref): Return void for ill-formed constructs. (function_ref(nontype_t<__f>, _Tp&&)): Constrain on __deduce_funcref producing non-void results. * testsuite/20_util/function_ref/deduction.cc: Negative tests. Reviewed-by: Jonathan Wakely Signed-off-by: Tomasz Kamiński --- diff --git a/libstdc++-v3/include/bits/funcwrap.h b/libstdc++-v3/include/bits/funcwrap.h index 70ecfd93e36..1a81c9a9b46 100644 --- a/libstdc++-v3/include/bits/funcwrap.h +++ b/libstdc++-v3/include/bits/funcwrap.h @@ -538,14 +538,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __skip_first_arg<_Ret(*)(_Arg, _Args...) noexcept(_Noex)> { using type = _Ret(_Args...) noexcept(_Noex); }; + // Returns a function pointer to signature to be used with function_ref, or void. template consteval auto __deduce_funcref() { if constexpr (is_member_object_pointer_v<_Fn>) - // TODO Consider reporting issue to make this noexcept - return static_cast(*)()>(nullptr); - else + { + if constexpr (is_invocable_v<_Fn, _Tr>) + // TODO Consider reporting issue to make this noexcept + return static_cast(*)()>(nullptr); + } + else if constexpr (requires { typename __skip_first_arg<_Fn>::type; }) return static_cast<__skip_first_arg<_Fn>::type*>(nullptr); } } // namespace __polyfunc @@ -562,11 +566,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION requires is_function_v<_Fn> function_ref(nontype_t<__f>) -> function_ref<_Fn>; - template - requires is_member_pointer_v<_Fn> || is_function_v> + template())> + requires (!is_void_v<_SignaturePtr>) function_ref(nontype_t<__f>, _Tp&&) - -> function_ref< - remove_pointer_t())>>; + -> function_ref>; #endif // __glibcxx_function_ref diff --git a/libstdc++-v3/testsuite/20_util/function_ref/deduction.cc b/libstdc++-v3/testsuite/20_util/function_ref/deduction.cc index 2940b876954..6ed2b4e5712 100644 --- a/libstdc++-v3/testsuite/20_util/function_ref/deduction.cc +++ b/libstdc++-v3/testsuite/20_util/function_ref/deduction.cc @@ -10,6 +10,13 @@ using std::function_ref; int i = 0; +template + concept deductible = requires (Args&... args) + { std::function_ref(std::nontype, args...); }; + +static_assert( !deductible<1> ); +static_assert( !deductible<1, int> ); + void f0(); void f0n() noexcept; @@ -21,6 +28,8 @@ static_assert( is_same_v)), function_ref> ); static_assert( is_same_v)), function_ref> ); +static_assert( !deductible ); +static_assert( !deductible ); void f1(int); void f1n(int) noexcept; @@ -37,6 +46,8 @@ static_assert( is_same_v, i)), function_ref> ); static_assert( is_same_v, i)), function_ref> ); +static_assert( !deductible ); +static_assert( !deductible ); void f2(int*, int); void f2n(int*, int) noexcept; @@ -53,6 +64,8 @@ static_assert( is_same_v, &i)), function_ref> ); static_assert( is_same_v, &i)), function_ref> ); +static_assert( !deductible ); +static_assert( !deductible ); struct S { @@ -68,6 +81,9 @@ struct S int fcl(float) const&; int fcln(float) const& noexcept; + + int fr(int) &&; + int frn(int) && noexcept; }; S s{}; const S cs{}; @@ -80,16 +96,23 @@ static_assert( is_same_v, &s)), function_ref> ); static_assert( is_same_v, &cs)), function_ref> ); +static_assert( !deductible<&S::mem, int> ); static_assert( is_same_v, s)), function_ref> ); static_assert( is_same_v, &s)), function_ref> ); +static_assert( !deductible<&S::f, char*> ); +static_assert( !deductible<&S::fn, char*> ); +static_assert( !deductible<&S::f, const S> ); +static_assert( !deductible<&S::fn, const S> ); static_assert( is_same_v, &s)), function_ref> ); static_assert( is_same_v, s)), function_ref> ); +static_assert( !deductible<&S::fc, char*> ); +static_assert( !deductible<&S::fcn, char*> ); static_assert( is_same_v, &s)), function_ref> ); @@ -101,3 +124,8 @@ static_assert( is_same_v, s)), static_assert( is_same_v, &s)), function_ref> ); +static_assert( !deductible<&S::fr, char*> ); +static_assert( !deductible<&S::frn, char*> ); +static_assert( !deductible<&S::fr, S> ); +static_assert( !deductible<&S::frn, S> ); +