mirror of
https://gcc.gnu.org/git/gcc.git
synced 2026-02-22 03:46:53 -05:00
libstdc++: Make function_ref(nontype<f>, 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 <jwakely@redhat.com> Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
This commit is contained in:
@@ -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<typename _Fn, typename _Tr>
|
||||
consteval auto
|
||||
__deduce_funcref()
|
||||
{
|
||||
if constexpr (is_member_object_pointer_v<_Fn>)
|
||||
// TODO Consider reporting issue to make this noexcept
|
||||
return static_cast<invoke_result_t<_Fn, _Tr>(*)()>(nullptr);
|
||||
else
|
||||
{
|
||||
if constexpr (is_invocable_v<_Fn, _Tr>)
|
||||
// TODO Consider reporting issue to make this noexcept
|
||||
return static_cast<invoke_result_t<_Fn, _Tr>(*)()>(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<auto __f, typename _Tp, class _Fn = decltype(__f)>
|
||||
requires is_member_pointer_v<_Fn> || is_function_v<remove_pointer_t<_Fn>>
|
||||
template<auto __f, typename _Tp,
|
||||
typename _SignaturePtr =
|
||||
decltype(__polyfunc::__deduce_funcref<decltype(__f), _Tp&>())>
|
||||
requires (!is_void_v<_SignaturePtr>)
|
||||
function_ref(nontype_t<__f>, _Tp&&)
|
||||
-> function_ref<
|
||||
remove_pointer_t<decltype(__polyfunc::__deduce_funcref<_Fn, _Tp&>())>>;
|
||||
-> function_ref<remove_pointer_t<_SignaturePtr>>;
|
||||
|
||||
#endif // __glibcxx_function_ref
|
||||
|
||||
|
||||
@@ -10,6 +10,13 @@ using std::function_ref;
|
||||
|
||||
int i = 0;
|
||||
|
||||
template<auto f, class... Args>
|
||||
concept deductible = requires (Args&... args)
|
||||
{ std::function_ref(std::nontype<f>, args...); };
|
||||
|
||||
static_assert( !deductible<1> );
|
||||
static_assert( !deductible<1, int> );
|
||||
|
||||
void f0();
|
||||
void f0n() noexcept;
|
||||
|
||||
@@ -21,6 +28,8 @@ static_assert( is_same_v<decltype(function_ref(nontype<f0>)),
|
||||
function_ref<void()>> );
|
||||
static_assert( is_same_v<decltype(function_ref(nontype<f0n>)),
|
||||
function_ref<void() noexcept>> );
|
||||
static_assert( !deductible<f0, char*> );
|
||||
static_assert( !deductible<f0n, char*> );
|
||||
|
||||
void f1(int);
|
||||
void f1n(int) noexcept;
|
||||
@@ -37,6 +46,8 @@ static_assert( is_same_v<decltype(function_ref(nontype<f1>, i)),
|
||||
function_ref<void()>> );
|
||||
static_assert( is_same_v<decltype(function_ref(nontype<f1n>, i)),
|
||||
function_ref<void() noexcept>> );
|
||||
static_assert( !deductible<f1, char*> );
|
||||
static_assert( !deductible<f1n, char*> );
|
||||
|
||||
void f2(int*, int);
|
||||
void f2n(int*, int) noexcept;
|
||||
@@ -53,6 +64,8 @@ static_assert( is_same_v<decltype(function_ref(nontype<f2>, &i)),
|
||||
function_ref<void(int)>> );
|
||||
static_assert( is_same_v<decltype(function_ref(nontype<f2n>, &i)),
|
||||
function_ref<void(int) noexcept>> );
|
||||
static_assert( !deductible<f2, char*> );
|
||||
static_assert( !deductible<f2n, char*> );
|
||||
|
||||
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<decltype(function_ref(nontype<&S::mem>, &s)),
|
||||
function_ref<int&()>> );
|
||||
static_assert( is_same_v<decltype(function_ref(nontype<&S::mem>, &cs)),
|
||||
function_ref<const int&()>> );
|
||||
static_assert( !deductible<&S::mem, int> );
|
||||
|
||||
static_assert( is_same_v<decltype(function_ref(nontype<&S::f>, s)),
|
||||
function_ref<int()>> );
|
||||
static_assert( is_same_v<decltype(function_ref(nontype<&S::fn>, &s)),
|
||||
function_ref<int() noexcept>> );
|
||||
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<decltype(function_ref(nontype<&S::fc>, &s)),
|
||||
function_ref<int(int)>> );
|
||||
static_assert( is_same_v<decltype(function_ref(nontype<&S::fcn>, s)),
|
||||
function_ref<int(int) noexcept>> );
|
||||
static_assert( !deductible<&S::fc, char*> );
|
||||
static_assert( !deductible<&S::fcn, char*> );
|
||||
|
||||
static_assert( is_same_v<decltype(function_ref(nontype<&S::fl>, &s)),
|
||||
function_ref<int(int)>> );
|
||||
@@ -101,3 +124,8 @@ static_assert( is_same_v<decltype(function_ref(nontype<&S::fcl>, s)),
|
||||
static_assert( is_same_v<decltype(function_ref(nontype<&S::fcln>, &s)),
|
||||
function_ref<int(float) noexcept>> );
|
||||
|
||||
static_assert( !deductible<&S::fr, char*> );
|
||||
static_assert( !deductible<&S::frn, char*> );
|
||||
static_assert( !deductible<&S::fr, S> );
|
||||
static_assert( !deductible<&S::frn, S> );
|
||||
|
||||
|
||||
Reference in New Issue
Block a user