On Tue, 23 Sept 2025 at 08:43, Tomasz Kamiński <[email protected]> wrote:
>
> 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++/PR121940
>
> libstdc++-v3/ChangeLog:
>
>         * include/bits/funcwrap.h (__polyfunc::__deduce_funcref): Return
>         void for in-case of ill-formed constructs.

I think this could just say "Return void for ill-formed constructs".

OK with that change.

>         (function_ref(nontype_t<__f>, _Tp&&)): Constrain on __deduce_funcref
>         producing non-void results.
>         * testsuite/20_util/function_ref/deduction.cc: Negative tests.
> ---
> Tested on x86_64-linux locally? OK for trunk?
>
>  libstdc++-v3/include/bits/funcwrap.h          | 19 ++++++++-----
>  .../20_util/function_ref/deduction.cc         | 28 +++++++++++++++++++
>  2 files changed, 40 insertions(+), 7 deletions(-)
>
> 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<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
>
> 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<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> );
> +
> --
> 2.51.0
>

Reply via email to