This patch implements C++26 function_ref as specified in P0792R14,
with correction for constraints for constructor accepting nontype_t
parameter from LWG 4256.

As function_ref may store a pointer to the const object, __Ptrs::_M_obj is
changed to const void*, so again we do not cast away const from const
objects. To help with necessary cast, a __polyfunc::__cast_to helper is
added, that accepts a reference to that type.

The _Invoker now defines additional call methods used by function_ref:
_S_ptrs() for invoking target passed by reference, and __S_nttp, _S_bind_ptr,
_S_bind_ref for handling constructors accepting nontype_t. The existing
_S_call_storage is changed to thin wrappers, that initialies _Ptrs,
and forwards to _S_call_ptrs.

This reduced the most uses of _Storage::_M_ptr and _Storage::_M_ref,
so this functions was removed, and _Manager uses were adjusted.

Finally we make function_ref available in freestanding mode, as
move_only_function and copyable_function are currently only available in hosted,
so we define _Manager and _Mo_base only if either __glibcxx_move_only_function
or __glibcxx_copyable_function is defined.

        PR libstdc++/119126

libstdc++-v3/ChangeLog:

        * doc/doxygen/stdheader.cc: Added funcref_impl.h file.
        * include/Makefile.am: Added funcref_impl.h file.
        * include/Makefile.in: Added funcref_impl.h file.
        * include/bits/funcref_impl.h: New file.
        * include/bits/funcwrap.h: (_Ptrs::_M_obj): Const-qualify.
        (_Storage::_M_ptr, _Storage::_M_ref): Remove.
        (__polyfunc::__cast_to) Define.
        (_Base_invoker::_S_ptrs, _Base_invoker::_S_nttp)
        (_Base_invoker::_S_bind_ptrs, _Base_invoker::_S_bind_ref)
        (_Base_invoker::_S_call_ptrs): Define.
        (_Base_invoker::_S_call_storage): Foward to _S_call_ptrs.
        (_Manager::_S_local, _Manager::_S_ptr): Adjust for _M_obj being
        const qualified.
        (__polyfunc::_Manager, __polyfunc::_Mo_base): Guard with
        __glibcxx_move_only_function || __glibcxx_copyable_function.
        (__polyfunc::__skip_first_arg, __polyfunc::__deduce_funcref)
        (std::function_ref) [__glibcxx_function_ref]: Define.
        * include/bits/utility.h (std::nontype_t, std::nontype)
        (__is_nontype_v) [__glibcxx_function_ref]: Define.
        * include/bits/version.def: Define function_ref.
        * include/bits/version.h: Regenerate.
        * include/std/functional: Define __cpp_lib_function_ref.
        * src/c++23/std.cc.in (std::nontype_t, std::nontype)
        (std::function_ref) [__cpp_lib_function_ref]: Export.
        * testsuite/20_util/function_ref/assign.cc: New test.
        * testsuite/20_util/function_ref/call.cc: New test.
        * testsuite/20_util/function_ref/cons.cc: New test.
        * testsuite/20_util/function_ref/cons_neg.cc: New test.
        * testsuite/20_util/function_ref/conv.cc: New test.
        * testsuite/20_util/function_ref/deduction.cc: New test.
---
This updated patch addresses review comments, and add a deduction
guide for the function_ref that was previously missing.
The handling of _GLIBCXX_MOF_REF and related macros was removed
from the funcref_impl.h, as it is not used currently.
For the ifdef checks, I replaced defined(__cpp_lib_XXXX) with
__cpp_lib_XXXX consistently.
The unused __is_function_ref variable template was removed.
All tests expect conv.cc now test with freestanding.

Tested on x86_64-linux. Tested *function_ref* with -ffreestanding.


 libstdc++-v3/doc/doxygen/stdheader.cc         |   1 +
 libstdc++-v3/include/Makefile.am              |   1 +
 libstdc++-v3/include/Makefile.in              |   1 +
 libstdc++-v3/include/bits/funcref_impl.h      | 188 +++++++++++++++
 libstdc++-v3/include/bits/funcwrap.h          | 183 +++++++++++----
 libstdc++-v3/include/bits/utility.h           |  17 ++
 libstdc++-v3/include/bits/version.def         |   8 +
 libstdc++-v3/include/bits/version.h           |  10 +
 libstdc++-v3/include/std/functional           |   3 +-
 libstdc++-v3/src/c++23/std.cc.in              |   7 +
 .../testsuite/20_util/function_ref/assign.cc  | 108 +++++++++
 .../testsuite/20_util/function_ref/call.cc    | 144 ++++++++++++
 .../testsuite/20_util/function_ref/cons.cc    | 218 ++++++++++++++++++
 .../20_util/function_ref/cons_neg.cc          |  30 +++
 .../testsuite/20_util/function_ref/conv.cc    | 152 ++++++++++++
 .../20_util/function_ref/deduction.cc         | 103 +++++++++
 16 files changed, 1127 insertions(+), 47 deletions(-)
 create mode 100644 libstdc++-v3/include/bits/funcref_impl.h
 create mode 100644 libstdc++-v3/testsuite/20_util/function_ref/assign.cc
 create mode 100644 libstdc++-v3/testsuite/20_util/function_ref/call.cc
 create mode 100644 libstdc++-v3/testsuite/20_util/function_ref/cons.cc
 create mode 100644 libstdc++-v3/testsuite/20_util/function_ref/cons_neg.cc
 create mode 100644 libstdc++-v3/testsuite/20_util/function_ref/conv.cc
 create mode 100644 libstdc++-v3/testsuite/20_util/function_ref/deduction.cc

diff --git a/libstdc++-v3/doc/doxygen/stdheader.cc 
b/libstdc++-v3/doc/doxygen/stdheader.cc
index 839bfc81bc0..938b2b04a26 100644
--- a/libstdc++-v3/doc/doxygen/stdheader.cc
+++ b/libstdc++-v3/doc/doxygen/stdheader.cc
@@ -55,6 +55,7 @@ void init_map()
     headers["functional_hash.h"]        = "functional";
     headers["mofunc_impl.h"]            = "functional";
     headers["cpyfunc_impl.h"]           = "functional";
+    headers["funcref_impl.h"]           = "functional";
     headers["funcwrap.h"]               = "functional";
     headers["invoke.h"]                 = "functional";
     headers["ranges_cmp.h"]             = "functional";
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 3e5b6c4142e..baf0290d655 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -205,6 +205,7 @@ bits_headers = \
        ${bits_srcdir}/fs_ops.h \
        ${bits_srcdir}/fs_path.h \
        ${bits_srcdir}/fstream.tcc \
+       ${bits_srcdir}/funcref_impl.h \
        ${bits_srcdir}/funcwrap.h \
        ${bits_srcdir}/gslice.h \
        ${bits_srcdir}/gslice_array.h \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index 3531162b5f7..e4e1079d8bd 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -559,6 +559,7 @@ bits_freestanding = \
 @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}/funcref_impl.h \
 @GLIBCXX_HOSTED_TRUE@  ${bits_srcdir}/gslice.h \
 @GLIBCXX_HOSTED_TRUE@  ${bits_srcdir}/gslice_array.h \
 @GLIBCXX_HOSTED_TRUE@  ${bits_srcdir}/hashtable.h \
diff --git a/libstdc++-v3/include/bits/funcref_impl.h 
b/libstdc++-v3/include/bits/funcref_impl.h
new file mode 100644
index 00000000000..7d3ebe75faa
--- /dev/null
+++ b/libstdc++-v3/include/bits/funcref_impl.h
@@ -0,0 +1,188 @@
+// Implementation of std::function_ref -*- 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/funcref_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
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  /// @cond undocumented
+  namespace __polyfunc
+  {
+    template<bool _Noex, typename _Ret, typename _Class, typename... _Args>
+      struct __skip_first_arg<_Ret(_Class::*)(_Args...) _GLIBCXX_MOF_CV
+                             noexcept(_Noex)>
+      { using type = _Ret(_Args...) noexcept(_Noex); };
+
+    template<bool _Noex, typename _Ret, typename _Class, typename... _Args>
+      struct __skip_first_arg<_Ret(_Class::*)(_Args...) _GLIBCXX_MOF_CV&
+                             noexcept(_Noex)>
+      { using type = _Ret(_Args...) noexcept(_Noex); };
+  } // namespace __polyfunc
+  /// @endcond
+
+  /**
+   *  @brief Non-owning polymorphic function wrapper.
+   *  @ingroup functors
+   *  @since C++26
+   *  @headerfile functional
+   *
+   *  The `std::function_ref` class template is a non-owning call wrapper,
+   *  that refers a bound object. Using function_ref outside of lifetime
+   *  of bound object has undefined behavior.
+   *
+   *  It supports const-qualification and no-throw guarantees. The 
qualifications and
+   *  exception-specification of the signature are respected when when 
invoking the
+   *  reference function.
+   */
+  template<typename _Res, typename... _ArgTypes, bool _Noex>
+    class function_ref<_Res(_ArgTypes...) _GLIBCXX_MOF_CV
+                      noexcept(_Noex)>
+    {
+      using _Invoker = __polyfunc::_Invoker<_Noex, _Res, _ArgTypes...>;
+      using _Signature = _Invoker::_Signature;
+
+      // [func.wrap.ref.ctor]/1 is-invokable-using
+      template<typename... _Tps>
+       static constexpr bool __is_invocable_using
+         = __conditional_t<_Noex,
+                           is_nothrow_invocable_r<_Res, _Tps..., _ArgTypes...>,
+                           is_invocable_r<_Res, _Tps..., _ArgTypes...>>::value;
+
+    public:
+      /// Target and bound object is function pointed by parameter.
+      template<typename _Fn>
+       requires is_function_v<_Fn> && __is_invocable_using<_Fn*>
+       function_ref(_Fn* __fn) noexcept
+       {
+         __glibcxx_assert(__fn != nullptr);
+         this->_M_invoke = _Invoker::template _S_ptrs<_Fn*>();
+         this->_M_ptrs._M_func = reinterpret_cast<void(*)()>(__fn);
+       }
+
+      /// Target and bound object is object referenced by parameter.
+      template<typename _Fn, typename _Vt = remove_reference_t<_Fn>>
+       requires (!is_same_v<remove_cv_t<_Vt>, function_ref>)
+              && (!is_member_pointer_v<_Vt>)
+              // We deviate from standard by having this condition, that forces
+              // function references to use _Fn* constructors. This simplies
+              // implementation and provide better diagnostic when used in
+              // constant expression (above constructor is not constexpr).
+              && (!is_function_v<_Vt>)
+              && __is_invocable_using<_Vt _GLIBCXX_MOF_CV&>
+       constexpr
+       function_ref(_Fn&& __f) noexcept
+       {
+         this->_M_invoke = _Invoker::template _S_ptrs<_Vt _GLIBCXX_MOF_CV&>();
+         this->_M_ptrs._M_obj = std::addressof(__f);
+       }
+
+      // _GLIBCXX_RESOLVE_LIB_DEFECTS
+      // 4256. Incorrect constrains for function_ref constructors from nontype
+      /// Target object is __fn. There is no bound object.
+      template<auto __fn>
+       requires __is_invocable_using<const decltype(__fn)&>
+       constexpr
+       function_ref(nontype_t<__fn>) noexcept
+       {
+         using _Fn = remove_cv_t<decltype(__fn)>;
+         if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>)
+           static_assert(__fn != nullptr);
+
+         this->_M_invoke = &_Invoker::template _S_nttp<__fn>;
+         this->_M_ptrs._M_obj = nullptr;
+       }
+
+      /// Target object is equivalent to std::bind_front<_fn>(std::ref(__ref)).
+      /// Bound object is object referenced by second parameter.
+      template<auto __fn, typename _Up, typename _Td = remove_reference_t<_Up>>
+       requires (!is_rvalue_reference_v<_Up&&>)
+         && __is_invocable_using<const decltype(__fn)&, _Td _GLIBCXX_MOF_CV&>
+       constexpr
+       function_ref(nontype_t<__fn>, _Up&& __ref) noexcept
+       {
+         using _Fn = remove_cv_t<decltype(__fn)>;
+         if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>)
+           static_assert(__fn != nullptr);
+
+         using _Tr = _Td _GLIBCXX_MOF_CV&;
+         if constexpr (is_member_pointer_v<_Fn> && is_lvalue_reference_v<_Tr>)
+           // N.B. invoking member pointer on lvalue produces the same effects,
+           // as invoking it on pointer to that lvalue.
+           this->_M_invoke = &_Invoker::template _S_bind_ptr<__fn, _Td 
_GLIBCXX_MOF_CV>;
+         else
+           this->_M_invoke = &_Invoker::template _S_bind_ref<__fn, _Tr>;
+         this->_M_ptrs._M_obj = std::addressof(__ref);
+       }
+
+      /// Target object is equivalent to std::bind_front<_fn>(__ptr).
+      /// Bound object is object pointed by second parameter (if any).
+      template<auto __fn, typename _Td>
+       requires __is_invocable_using<const decltype(__fn)&, _Td 
_GLIBCXX_MOF_CV*>
+       constexpr
+       function_ref(nontype_t<__fn>, _Td _GLIBCXX_MOF_CV* __ptr) noexcept
+       {
+         using _Fn = remove_cv_t<decltype(__fn)>;
+         if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>)
+           static_assert(__fn != nullptr);
+         if constexpr (is_member_pointer_v<_Fn>)
+           __glibcxx_assert(__ptr != nullptr);
+
+         this->_M_invoke = &_Invoker::template _S_bind_ptr<__fn, _Td 
_GLIBCXX_MOF_CV>;
+         this->_M_ptrs._M_obj = __ptr;
+       }
+
+      template<typename _Tp>
+       requires (!is_same_v<_Tp, function_ref>)
+              && (!is_pointer_v<_Tp>) && (!__is_nontype_v<_Tp>)
+       function_ref&
+       operator=(_Tp) = delete;
+
+      /** Invoke the target object.
+       *
+       * The bound object will be invoked using the supplied arguments,
+       * and as const or non-const, as dictated by the template arguments
+       * of the `function_ref` specialization.
+       */
+      _Res
+      operator()(_ArgTypes... __args) const noexcept(_Noex)
+      { return _M_invoke(this->_M_ptrs, std::forward<_ArgTypes>(__args)...); }
+
+    private:
+      typename _Invoker::__ptrs_func_t _M_invoke;
+      __polyfunc::_Ptrs _M_ptrs;
+    };
+
+#undef _GLIBCXX_MOF_CV
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
diff --git a/libstdc++-v3/include/bits/funcwrap.h 
b/libstdc++-v3/include/bits/funcwrap.h
index 4e053534cf5..5c296d4cf51 100644
--- a/libstdc++-v3/include/bits/funcwrap.h
+++ b/libstdc++-v3/include/bits/funcwrap.h
@@ -1,4 +1,5 @@
-// Implementation of std::move_only_function and std::copyable_function -*- 
C++ -*-
+// Implementation of std::move_only_function, std::copyable_function
+// and std::function_ref  -*- C++ -*-
 
 // Copyright The GNU Toolchain Authors.
 //
@@ -36,7 +37,7 @@
 
 #include <bits/version.h>
 
-#if defined(__glibcxx_move_only_function) || 
defined(__glibcxx_copyable_function)
+#if __glibcxx_move_only_function || __glibcxx_copyable_function || 
__glibcxx_function_ref
 
 #include <bits/invoke.h>
 #include <bits/utility.h>
@@ -53,10 +54,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   {
     union _Ptrs
     {
-      void* _M_obj;
+      const void* _M_obj;
       void (*_M_func)();
     };
 
+   template<typename _Tp>
+     [[__gnu__::__always_inline__]]
+     constexpr auto*
+     __cast_to(_Ptrs __ptrs) noexcept
+     {
+       using _Td = remove_reference_t<_Tp>;
+       if constexpr (is_const_v<_Td>)
+        return static_cast<_Td*>(__ptrs._M_obj);
+       else
+        return static_cast<_Td*>(const_cast<void*>(__ptrs._M_obj));
+     }
+
    struct _Storage
    {
      void*       _M_addr() noexcept       { return &_M_bytes[0]; }
@@ -97,32 +110,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
           ::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 {
@@ -143,6 +130,36 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
         _S_storage()
         { return &_S_call_storage<_Adjust_target<_Tp>>; }
 
+       using __ptrs_func_t = _Ret(*)(_Ptrs, _Args...) noexcept(_Noex);
+       template<typename _Tp>
+        static consteval __ptrs_func_t
+        _S_ptrs()
+        { return &_S_call_ptrs<_Adjust_target<_Tp>>; }
+
+#ifdef __glibcxx_function_ref // C++ >= 26
+       template<auto __fn>
+        static _Ret
+        _S_nttp(_Ptrs, _Args... __args) noexcept(_Noex)
+        { return std::__invoke_r<_Ret>(__fn, std::forward<_Args>(__args)...); }
+
+       template<auto __fn, typename _Tp>
+        static _Ret
+        _S_bind_ptr(_Ptrs __ptrs, _Args... __args) noexcept(_Noex)
+        {
+          auto __p = __polyfunc::__cast_to<_Tp>(__ptrs);
+          return std::__invoke_r<_Ret>(__fn, __p, 
std::forward<_Args>(__args)...);
+        }
+
+       template<auto __fn, typename _Ref>
+        static _Ret
+        _S_bind_ref(_Ptrs __ptrs, _Args... __args) noexcept(_Noex)
+        {
+          auto __p = __polyfunc::__cast_to<_Ref>(__ptrs);
+          return std::__invoke_r<_Ret>(__fn, static_cast<_Ref>(*__p),
+                                       std::forward<_Args>(__args)...);
+        }
+#endif // __glibcxx_function_ref
+
      private:
        template<typename _Tp, typename _Td = remove_cvref_t<_Tp>>
         using _Adjust_target =
@@ -152,8 +169,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
         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)...);
+          _Ptrs __ptrs;
+          if constexpr (is_function_v<remove_pointer_t<_Tp>>)
+            __ptrs._M_func = __ref._M_ptrs._M_func;
+          else if constexpr 
(!_Storage::_S_stored_locally<remove_cvref_t<_Tp>>())
+            __ptrs._M_obj = __ref._M_ptrs._M_obj;
+          else
+            __ptrs._M_obj = __ref._M_addr();
+          return _S_call_ptrs<_Tp>(__ptrs, std::forward<_Args>(__args)...);
+        }
+
+       template<typename _Tp>
+        static _Ret
+        _S_call_ptrs(_Ptrs __ptrs, _Args... __args) noexcept(_Noex)
+        {
+          if constexpr (is_function_v<remove_pointer_t<_Tp>>)
+            return std::__invoke_r<_Ret>(reinterpret_cast<_Tp>(__ptrs._M_func),
+                                         std::forward<_Args>(__args)...);
+          else
+            {
+              auto __p = __polyfunc::__cast_to<_Tp>(__ptrs);
+              return std::__invoke_r<_Ret>(static_cast<_Tp>(*__p),
+                                           std::forward<_Args>(__args)...);
+            }
         }
      };
 
@@ -184,6 +222,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
         return false;
      }
 
+#if __glibcxx_move_only_function || __glibcxx_copyable_function
    struct _Manager
    {
      enum class _Op
@@ -241,7 +280,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        switch (__op)
        {
         case _Op::_Address:
-          __target._M_ptrs._M_obj = const_cast<void*>(__src->_M_addr());
+          __target._M_ptrs._M_obj = __src->_M_addr();
           return;
         case _Op::_Move:
         case _Op::_Copy:
@@ -263,24 +302,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
         switch (__op)
         {
           case _Op::_Address:
-            __target._M_ptrs._M_obj = __src->_M_ptr<_Tp>();
+            __target._M_ptrs._M_obj = __src->_M_addr();
             return;
           case _Op::_Move:
             {
-              _Tp* __obj = __src->_M_ptr<_Tp>();
+              _Tp* __obj = 
static_cast<_Tp*>(const_cast<void*>(__src->_M_addr()));
               ::new(__target._M_addr()) _Tp(std::move(*__obj));
               __obj->~_Tp();
             }
             return;
           case _Op::_Destroy:
-            __target._M_ptr<_Tp>()->~_Tp();
+            static_cast<_Tp*>(__target._M_addr())->~_Tp();
             return;
           case _Op::_Copy:
             if constexpr (_Provide_copy)
-              ::new (__target._M_addr()) _Tp(__src->_M_ref<const _Tp&>());
-            else
-              __builtin_unreachable();
-            return;
+              {
+                auto* __obj = static_cast<const _Tp*>(__src->_M_addr());
+                ::new (__target._M_addr()) _Tp(*__obj);
+                return;
+              }
+            __builtin_unreachable();
         }
        }
 
@@ -296,14 +337,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
             __target._M_ptrs._M_obj = __src->_M_ptrs._M_obj;
             return;
           case _Op::_Destroy:
-            delete __target._M_ptr<_Tp>();
+            delete static_cast<const _Tp*>(__target._M_ptrs._M_obj);
             return;
           case _Op::_Copy:
             if constexpr (_Provide_copy)
-              __target._M_ptrs._M_obj = new _Tp(__src->_M_ref<const _Tp&>());
-            else
-              __builtin_unreachable();
-            return;
+              {
+                auto* __obj = static_cast<const _Tp*>(__src->_M_ptrs._M_obj);
+                __target._M_ptrs._M_obj = new _Tp(*__obj);
+                return;
+              }
+            __builtin_unreachable();
          }
        }
    };
@@ -382,7 +425,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
      friend class _Cpy_base;
 #endif // __glibcxx_copyable_function
    };
-
+#endif // __glibcxx_copyable_function || __glibcxx_copyable_function
 } // namespace __polyfunc
   /// @endcond
 
@@ -468,6 +511,48 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   }  // namespace __detail::__variant
 #endif // __glibcxx_copyable_function
 
+#ifdef __glibcxx_function_ref  // C++ >= 26
+  /// @cond undocumented
+  namespace __polyfunc
+  {
+    template<typename _Sig>
+      struct __skip_first_arg;
+
+    template<bool _Noex, typename _Ret, typename _Arg, typename... _Args>
+      struct __skip_first_arg<_Ret(*)(_Arg, _Args...) noexcept(_Noex)>
+      { using type = _Ret(_Args...) noexcept(_Noex); };
+
+    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
+         return static_cast<__skip_first_arg<_Fn>::type*>(nullptr);
+      }
+  } // namespace __polyfunc
+  /// @endcond
+
+  template<typename... _Signature>
+    class function_ref; // not defined
+
+  template<typename _Fn>
+    requires is_function_v<_Fn>
+    function_ref(_Fn*) -> function_ref<_Fn>;
+
+  template<auto __f, class _Fn = remove_pointer_t<decltype(__f)>>
+    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>>
+    function_ref(nontype_t<__f>, _Tp&&)
+      -> function_ref<
+          remove_pointer_t<decltype(__polyfunc::__deduce_funcref<_Fn, 
_Tp&>())>>;
+
+#endif // __glibcxx_function_ref
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
@@ -503,5 +588,11 @@ _GLIBCXX_END_NAMESPACE_VERSION
 #include "cpyfunc_impl.h"
 #endif // __glibcxx_copyable_function
 
-#endif // __glibcxx_copyable_function || __glibcxx_copyable_function
+#ifdef __glibcxx_function_ref  // C++ >= 26
+#include "funcref_impl.h"
+#define _GLIBCXX_MOF_CV const
+#include "funcref_impl.h"
+#endif // __glibcxx_function_ref
+
+#endif // move_only_function || copyable_function || function_ref
 #endif // _GLIBCXX_FUNCWRAP_H
diff --git a/libstdc++-v3/include/bits/utility.h 
b/libstdc++-v3/include/bits/utility.h
index 6fa6b679c6d..84d25e0c658 100644
--- a/libstdc++-v3/include/bits/utility.h
+++ b/libstdc++-v3/include/bits/utility.h
@@ -316,6 +316,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   inline constexpr sorted_equivalent_t sorted_equivalent{};
 #endif
 
+#if __glibcxx_function_ref // >= C++26
+  template<auto>
+    struct nontype_t
+    {
+      explicit nontype_t() = default;
+    };
+
+  template<auto __val>
+    constexpr nontype_t<__val> nontype{};
+
+  template<typename>
+    inline constexpr bool __is_nontype_v = false;
+
+  template<auto __val>
+    inline constexpr bool __is_nontype_v<nontype_t<__val>> = true;
+#endif
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace
 
diff --git a/libstdc++-v3/include/bits/version.def 
b/libstdc++-v3/include/bits/version.def
index 6ca148f0488..55aab40d9bf 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1756,6 +1756,14 @@ ftms = {
   };
 };
 
+ftms = {
+  name = function_ref;
+  values = {
+    v = 202306;
+    cxxmin = 26;
+  };
+};
+
 ftms = {
   name = out_ptr;
   values = {
diff --git a/libstdc++-v3/include/bits/version.h 
b/libstdc++-v3/include/bits/version.h
index 48a090c14a3..026c9959482 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -1958,6 +1958,16 @@
 #endif /* !defined(__cpp_lib_copyable_function) && 
defined(__glibcxx_want_copyable_function) */
 #undef __glibcxx_want_copyable_function
 
+#if !defined(__cpp_lib_function_ref)
+# if (__cplusplus >  202302L)
+#  define __glibcxx_function_ref 202306L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_function_ref)
+#   define __cpp_lib_function_ref 202306L
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_function_ref) && 
defined(__glibcxx_want_function_ref) */
+#undef __glibcxx_want_function_ref
+
 #if !defined(__cpp_lib_out_ptr)
 # if (__cplusplus >= 202100L)
 #  define __glibcxx_out_ptr 202311L
diff --git a/libstdc++-v3/include/std/functional 
b/libstdc++-v3/include/std/functional
index 9a55b181e6d..307bcb95bcc 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -57,6 +57,7 @@
 #define __glibcxx_want_bind_back
 #define __glibcxx_want_constexpr_functional
 #define __glibcxx_want_copyable_function
+#define __glibcxx_want_function_ref
 #define __glibcxx_want_invoke
 #define __glibcxx_want_invoke_r
 #define __glibcxx_want_move_only_function
@@ -86,7 +87,7 @@
 # include <bits/ranges_cmp.h> // std::identity, ranges::equal_to etc.
 # include <compare>
 #endif
-#if defined(__glibcxx_move_only_function) || 
defined(__glibcxx_copyable_function)
+#if __glibcxx_move_only_function || __glibcxx_copyable_function || 
__glibcxx_function_ref
 # include <bits/funcwrap.h>
 #endif
 
diff --git a/libstdc++-v3/src/c++23/std.cc.in b/libstdc++-v3/src/c++23/std.cc.in
index 417c8a1a562..ba468530338 100644
--- a/libstdc++-v3/src/c++23/std.cc.in
+++ b/libstdc++-v3/src/c++23/std.cc.in
@@ -1414,6 +1414,9 @@ export namespace std
 #endif
 #if __cpp_lib_copyable_function
   using std::copyable_function;
+#endif
+#if __cpp_lib_function_ref
+  using std::function_ref;
 #endif
   using std::multiplies;
   using std::negate;
@@ -3195,6 +3198,10 @@ export namespace std
   using std::make_integer_sequence;
   using std::move;
   using std::move_if_noexcept;
+#if __cpp_lib_function_ref
+  using std::nontype_t;
+  using std::nontype;
+#endif
   using std::pair;
   using std::swap;
   using std::operator==;
diff --git a/libstdc++-v3/testsuite/20_util/function_ref/assign.cc 
b/libstdc++-v3/testsuite/20_util/function_ref/assign.cc
new file mode 100644
index 00000000000..9b02dc49c2a
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_ref/assign.cc
@@ -0,0 +1,108 @@
+// { dg-do compile { target c++26 } }
+
+#include <functional>
+
+#ifndef __cpp_lib_function_ref
+# error "Feature-test macro for function_ref missing in <functional>"
+#elif __cpp_lib_function_ref != 202306L
+# error "Feature-test macro for function_ref has wrong value in <functional>"
+#endif
+
+using std::nontype;
+using std::nontype_t;
+using std::function_ref;
+
+using std::is_nothrow_move_assignable_v;
+using std::is_nothrow_copy_assignable_v;
+using std::is_nothrow_assignable_v;
+using std::is_assignable_v;
+using std::is_nothrow_swappable_v;
+using std::is_trivially_copyable_v;
+
+static_assert( is_nothrow_move_assignable_v<function_ref<void()>> );
+static_assert( is_nothrow_copy_assignable_v<function_ref<void()>> );
+static_assert( is_nothrow_swappable_v<function_ref<void()>> );
+
+static_assert( ! is_assignable_v<function_ref<void()>, std::nullptr_t> );
+
+static_assert( is_nothrow_assignable_v<function_ref<void()>, void()> );
+static_assert( is_nothrow_assignable_v<function_ref<void()>, void(&)()> );
+static_assert( is_nothrow_assignable_v<function_ref<void()>, void(*)()> );
+static_assert( is_nothrow_assignable_v<function_ref<void()>, int()> );
+static_assert( is_nothrow_assignable_v<function_ref<void()>, int(&)()> );
+static_assert( is_nothrow_assignable_v<function_ref<void()>, int(*)()> );
+static_assert( ! is_nothrow_assignable_v<function_ref<void()>, void(int)> );
+static_assert( is_nothrow_assignable_v<function_ref<void(int)>, void(int)> );
+
+static_assert( is_nothrow_assignable_v<function_ref<void()>,
+                                      void() noexcept> );
+static_assert( is_nothrow_assignable_v<function_ref<void() noexcept>,
+                                       void() noexcept> );
+static_assert( ! is_assignable_v<function_ref<void() noexcept>, void() > );
+
+struct S
+{
+  int x;
+  int f();
+};
+int funS(S);
+
+static_assert( is_nothrow_assignable_v<function_ref<int(S)>,
+                                      decltype(funS)> );
+static_assert( is_nothrow_assignable_v<function_ref<int(S)>,
+                                      decltype(&funS)> );
+static_assert( ! is_assignable_v<function_ref<int(S)>, decltype(&S::x)> );
+static_assert( ! is_assignable_v<function_ref<int(S)>, decltype(&S::f)> );
+
+static_assert( is_nothrow_assignable_v<function_ref<int(S)>,
+                                      nontype_t<funS>> );
+static_assert( is_nothrow_assignable_v<function_ref<int(S)>,
+                                      nontype_t<&funS>> );
+static_assert( is_nothrow_assignable_v<function_ref<int(S)>,
+                                      nontype_t<&S::x>> );
+static_assert( is_nothrow_assignable_v<function_ref<int(S)>,
+                                      nontype_t<&S::f>> );
+struct Q
+{
+  void operator()() const;
+};
+
+static_assert( ! is_assignable_v<function_ref<void()>, Q> );
+static_assert( ! is_assignable_v<function_ref<void()>, Q&> );
+static_assert( ! is_assignable_v<function_ref<void()>, const Q&> );
+static_assert( ! is_assignable_v<function_ref<void() const>, Q> );
+static_assert( ! is_assignable_v<function_ref<void() const>, Q&> );
+static_assert( ! is_assignable_v<function_ref<void() const>, const Q&> );
+
+static_assert( is_nothrow_assignable_v<function_ref<void()>,
+                                      nontype_t<Q{}>> );
+static_assert( is_nothrow_assignable_v<function_ref<void() const>,
+                                      nontype_t<Q{}>> );
+
+constexpr bool
+test_constexpr()
+{
+  function_ref<void(S)> fp(nontype<funS>);
+  fp = nontype<funS>;
+  fp = nontype<&funS>;
+  fp = nontype<&S::x>;
+  fp = nontype<&S::f>;
+
+  constexpr Q cq;
+  function_ref<void() const> fq(cq);
+  fq = nontype<cq>;
+  return true;
+}
+static_assert( test_constexpr() );
+
+void func();
+
+void
+test_instantiation()
+{
+  function_ref<void(S)> fp(funS);
+  fp = funS;
+  fp = &funS;
+
+  test_constexpr();
+}
diff --git a/libstdc++-v3/testsuite/20_util/function_ref/call.cc 
b/libstdc++-v3/testsuite/20_util/function_ref/call.cc
new file mode 100644
index 00000000000..27231d1219b
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_ref/call.cc
@@ -0,0 +1,144 @@
+// { dg-do run { target c++26 } }
+
+#include <functional>
+#include <utility>
+#include <testsuite_hooks.h>
+
+using std::nontype;
+using std::function_ref;
+
+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<function_ref<void()>>> );
+static_assert( is_same_v<int, invoke_result_t<function_ref<int()>>> );
+static_assert( is_same_v<int&, invoke_result_t<function_ref<int&()>>> );
+
+// Const qualier applies to target object
+static_assert( is_invocable_v< function_ref<void()> const > );
+static_assert( is_invocable_v< function_ref<void()> const &> );
+static_assert( is_invocable_v< function_ref<void() const> > );
+static_assert( is_invocable_v< function_ref<void() const> &> );
+static_assert( is_invocable_v< function_ref<void() const> const > );
+static_assert( is_invocable_v< function_ref<void() const> const &> );
+
+// With noexcept-specifier
+static_assert( ! is_nothrow_invocable_v< function_ref<void()> > );
+static_assert( ! is_nothrow_invocable_v< function_ref<void() noexcept(false)> 
> );
+static_assert( is_nothrow_invocable_v< function_ref<void() noexcept> > );
+
+void
+test01()
+{
+  struct F
+  {
+    int operator()() { return 0; }
+    int operator()() const { return 1; }
+  };
+
+  function_ref<int()> f0{F{}};
+  VERIFY( f0() == 0 );
+  VERIFY( std::move(f0)() == 0 );
+
+  function_ref<int()> f1{nontype<F{}>};
+  VERIFY( f1() == 1 );
+  VERIFY( std::move(f1)() == 1 );
+
+  function_ref<int() const> f2{F{}};
+  VERIFY( f2() == 1 );
+  VERIFY( std::as_const(f2)() == 1 );
+  VERIFY( std::move(f2)() == 1 );
+  VERIFY( std::move(std::as_const(f2))() == 1 );
+
+  function_ref<int() const> f3{nontype<F{}>};
+  VERIFY( f3() == 1 );
+  VERIFY( std::as_const(f3)() == 1 );
+  VERIFY( std::move(f3)() == 1 );
+  VERIFY( std::move(std::as_const(f3))() == 1 );
+}
+
+void
+test02()
+{
+  struct F
+  {
+    struct Arg {};
+    int operator()(Arg& arg) const { return 0; }
+    int operator()(const Arg& arg) const { return 1; }
+  };
+  F::Arg arg;
+
+  function_ref<int()> f0{std::nontype<F{}>, arg};
+  VERIFY( f0() == 0 );
+  VERIFY( std::move(f0)() == 0 );
+
+  function_ref<int() const> f1{std::nontype<F{}>, arg};
+  VERIFY( f1() == 1 );
+  VERIFY( std::as_const(f1)() == 1 );
+}
+
+void
+test03()
+{
+  struct F
+  {
+    struct Arg {};
+    int operator()(Arg* arg) const { return 0; }
+    int operator()(const Arg* arg) const { return 1; }
+  };
+  F::Arg arg;
+
+  function_ref<int()> f0{std::nontype<F{}>, &arg};
+  VERIFY( f0() == 0 );
+  VERIFY( std::move(f0)() == 0 );
+
+  function_ref<int() const> f1{std::nontype<F{}>, &arg};
+  VERIFY( f1() == 1 );
+  VERIFY( std::as_const(f1)() == 1 );
+}
+
+void
+test04()
+{
+  constexpr int (*fp)() = [] { return 0; };
+  function_ref<int()> f0{fp};
+  VERIFY( f0() == 0 );
+  VERIFY( std::move(f0)() == 0 );
+
+  function_ref<int()> f1{nontype<fp>};
+  VERIFY( f1() == 0 );
+  VERIFY( std::move(f1)() == 0 );
+
+  const function_ref<int() const> f2{fp};
+  VERIFY( f2() == 0 );
+  VERIFY( std::move(f2)() == 0 );
+
+  const function_ref<int() const> f3{nontype<fp>};
+  VERIFY( f2() == 0 );
+  VERIFY( std::move(f2)() == 0 );
+}
+
+struct Incomplete;
+
+void
+test_params()
+{
+  auto f = [](auto&&) {};
+  // There is discussion if this is supported.
+  // std::function_ref<void(Incomplete)> f1(f);
+  std::function_ref<void(Incomplete&)> f2(f);
+  // See PR120259, this should be supported.
+  // std::function_ref<void(Incomplete&&)> f3(f);
+}
+
+int main()
+{
+  test01();
+  test02();
+  test03();
+  test04();
+  test_params();
+}
diff --git a/libstdc++-v3/testsuite/20_util/function_ref/cons.cc 
b/libstdc++-v3/testsuite/20_util/function_ref/cons.cc
new file mode 100644
index 00000000000..a91f5ba3dab
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_ref/cons.cc
@@ -0,0 +1,218 @@
+// { dg-do compile { target c++26 } }
+// { dg-add-options no_pch }
+
+#include <functional>
+
+#ifndef __cpp_lib_function_ref
+# error "Feature-test macro for function_ref missing in <functional>"
+#elif __cpp_lib_function_ref != 202306L
+# error "Feature-test macro for function_ref has wrong value in <functional>"
+#endif
+
+using std::nontype;
+using std::nontype_t;
+using std::function_ref;
+
+using std::is_default_constructible_v;
+using std::is_nothrow_copy_constructible_v;
+using std::is_nothrow_move_constructible_v;
+using std::is_nothrow_constructible_v;
+using std::is_constructible_v;
+using std::is_trivially_copyable_v;
+
+static_assert( ! is_default_constructible_v<function_ref<void()>> );
+static_assert( is_nothrow_move_constructible_v<function_ref<void()>> );
+static_assert( is_nothrow_copy_constructible_v<function_ref<void()>> );
+static_assert( is_trivially_copyable_v<function_ref<void()>> );
+
+static_assert( ! is_constructible_v<function_ref<void()>, std::nullptr_t> );
+
+static_assert( is_nothrow_constructible_v<function_ref<void()>, void()> );
+static_assert( is_nothrow_constructible_v<function_ref<void()>, void(&)()> );
+static_assert( is_nothrow_constructible_v<function_ref<void()>, void(*)()> );
+static_assert( is_nothrow_constructible_v<function_ref<void()>, int()> );
+static_assert( is_nothrow_constructible_v<function_ref<void()>, int(&)()> );
+static_assert( is_nothrow_constructible_v<function_ref<void()>, int(*)()> );
+static_assert( ! is_constructible_v<function_ref<void()>, void(int)> );
+static_assert( is_nothrow_constructible_v<function_ref<void(int)>, void(int)> 
);
+
+static_assert( is_nothrow_constructible_v<function_ref<void()>,
+                                         void() noexcept> );
+static_assert( is_nothrow_constructible_v<function_ref<void() noexcept>,
+                                         void() noexcept> );
+static_assert( ! is_constructible_v<function_ref<void() noexcept>,
+                                   void() > );
+
+struct S
+{
+  int x;
+  int f();
+};
+int funS(S);
+
+static_assert( is_nothrow_constructible_v<function_ref<int(S)>,
+                                         decltype(funS)> );
+static_assert( is_nothrow_constructible_v<function_ref<int(S)>,
+                                         decltype(&funS)> );
+static_assert( ! is_constructible_v<function_ref<int(S)>,
+                                   decltype(&S::x)> );
+static_assert( ! is_constructible_v<function_ref<int(S)>,
+                                   decltype(&S::f)> );
+
+static_assert( is_nothrow_constructible_v<function_ref<int(S)>,
+                                         nontype_t<funS>> );
+static_assert( is_nothrow_constructible_v<function_ref<int(S)>,
+                                         nontype_t<&funS>> );
+static_assert( is_nothrow_constructible_v<function_ref<int(S)>,
+                                         nontype_t<&S::x>> );
+static_assert( is_nothrow_constructible_v<function_ref<int(S)>,
+                                         nontype_t<&S::f>> );
+
+static_assert( is_nothrow_constructible_v<function_ref<int()>,
+                                         nontype_t<funS>, S&> );
+static_assert( is_nothrow_constructible_v<function_ref<int()>,
+                                         nontype_t<&funS>, S&> );
+static_assert( is_nothrow_constructible_v<function_ref<int()>,
+                                         nontype_t<&S::x>, S&> );
+static_assert( is_nothrow_constructible_v<function_ref<int()>,
+                                         nontype_t<&S::f>, S&> );
+
+static_assert( ! is_constructible_v<function_ref<int()>,
+                                   nontype_t<funS>, S*> );
+static_assert( ! is_constructible_v<function_ref<int()>,
+                                   nontype_t<&funS>, S*> );
+static_assert( is_nothrow_constructible_v<function_ref<int()>,
+                                         nontype_t<&S::x>, S*> );
+static_assert( is_nothrow_constructible_v<function_ref<int()>,
+                                         nontype_t<&S::f>, S*> );
+
+struct M
+{
+  void operator()();
+};
+
+
+static_assert( is_nothrow_constructible_v<function_ref<void()>, M> );
+static_assert( is_nothrow_constructible_v<function_ref<void()>, M&> );
+static_assert( ! is_constructible_v<function_ref<void()>, const M&> );
+static_assert( ! is_constructible_v<function_ref<void() const>, M> );
+static_assert( ! is_constructible_v<function_ref<void() const>, const M&> );
+static_assert( ! is_constructible_v<function_ref<void()>,
+                                   nontype_t<M{}>> );
+static_assert( ! is_constructible_v<function_ref<void() const>,
+                                   nontype_t<M{}>> );
+struct Q
+{
+  void operator()(int) const;
+  void operator()(int*) const;
+};
+
+static_assert( is_nothrow_constructible_v<function_ref<void(int)>, Q> );
+static_assert( is_nothrow_constructible_v<function_ref<void(int)>, Q&> );
+static_assert( is_nothrow_constructible_v<function_ref<void(int)>, const Q&> );
+static_assert( is_nothrow_constructible_v<function_ref<void(int) const>, Q> );
+static_assert( is_nothrow_constructible_v<function_ref<void(int) const>, Q&> );
+static_assert( is_nothrow_constructible_v<function_ref<void(int) const>, const 
Q&> );
+
+static_assert( is_nothrow_constructible_v<function_ref<void(int)>,
+                                         nontype_t<Q{}>> );
+static_assert( is_nothrow_constructible_v<function_ref<void(int) const>,
+                                         nontype_t<Q{}>> );
+static_assert( is_nothrow_constructible_v<function_ref<void()>,
+                                         nontype_t<Q{}>, int&> );
+static_assert( is_nothrow_constructible_v<function_ref<void() const>,
+                                         nontype_t<Q{}>, int&> );
+static_assert( ! is_constructible_v<function_ref<void()>,
+                                   nontype_t<Q{}>, int> );
+static_assert( ! is_constructible_v<function_ref<void() const>,
+                                   nontype_t<Q{}>, int> );
+
+static_assert( is_nothrow_constructible_v<function_ref<void()>,
+                                         nontype_t<Q{}>, int*> );
+static_assert( ! is_constructible_v<function_ref<void() const>,
+                                   nontype_t<Q{}>, int*> );
+
+struct L
+{
+  void operator()() &;
+};
+
+static_assert( is_nothrow_constructible_v<function_ref<void()>, L> );
+static_assert( is_nothrow_constructible_v<function_ref<void()>, L&> );
+static_assert( ! is_constructible_v<function_ref<void()>, const L&> );
+static_assert( ! is_constructible_v<function_ref<void() const>, L> );
+static_assert( ! is_constructible_v<function_ref<void() const>, const L&> );
+static_assert( ! is_constructible_v<function_ref<void()>,
+                                   nontype_t<L{}>> );
+static_assert( ! is_constructible_v<function_ref<void() const>,
+                                   nontype_t<L{}>> );
+
+struct R
+{
+  void operator()(float) const&&;
+};
+
+static_assert( ! is_constructible_v<function_ref<void(float)>, R> );
+static_assert( ! is_constructible_v<function_ref<void(float)>, R&> );
+static_assert( ! is_constructible_v<function_ref<void(float) const>, R> );
+static_assert( ! is_constructible_v<function_ref<void(float) const>, R&> );
+static_assert( ! is_constructible_v<function_ref<void(float) const>, const R&> 
);
+
+static_assert( ! is_constructible_v<function_ref<void(float)>,
+                                                nontype_t<R{}>> );
+static_assert( ! is_constructible_v<function_ref<void(float) const>,
+                                                nontype_t<R{}>> );
+
+constexpr bool
+test_constexpr()
+{
+  function_ref<void(S)> fp1(nontype<funS>);
+  function_ref<void(S)> fp3(nontype<&funS>);
+  function_ref<void(S)> fp4(nontype<&S::x>);
+  function_ref<void(S)> fp5(nontype<&S::f>);
+
+  S s;
+  function_ref<void()> fp6(nontype<&funS>, s);
+  function_ref<void()> fp7(nontype<&S::x>, s);
+  function_ref<void()> fp8(nontype<&S::x>, &s);
+  function_ref<void()> fp9(nontype<&S::f>, s);
+  function_ref<void()> fp10(nontype<&S::f>, &s);
+
+  M m;
+  function_ref<void()> fm1(m);
+  function_ref<void()> fm2(std::move(m));
+
+  Q q;
+  constexpr Q cq;
+  function_ref<void(int)> fq1(q);
+  function_ref<void(int) const> fq2(q);
+  function_ref<void(int) const> fq3(std::move(q));
+
+  function_ref<void(int)> fcq1(cq);
+  function_ref<void(int) const> f(cq);
+  function_ref<void(int)> fcq3(nontype<cq>);
+  function_ref<void(int) const> fcq4(nontype<cq>);
+
+  int i = 0;
+  function_ref<void()> fcq5(nontype<cq>, i);
+  function_ref<void() const> fcq6(nontype<cq>, i);
+  function_ref<void()> fcq7(nontype<cq>, &i);
+
+  L l;
+  function_ref<void()> fl1(l);
+  function_ref<void()> fl2(std::move(l));
+
+  return true;
+}
+static_assert( test_constexpr() );
+
+void func();
+
+void
+test_instantiation()
+{
+  function_ref<void(S)> fp1(funS);
+  function_ref<void(S)> fp2(&funS);
+
+  test_constexpr();
+}
diff --git a/libstdc++-v3/testsuite/20_util/function_ref/cons_neg.cc 
b/libstdc++-v3/testsuite/20_util/function_ref/cons_neg.cc
new file mode 100644
index 00000000000..050090df370
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_ref/cons_neg.cc
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++26 } }
+
+#include <functional>
+
+using std::nontype;
+using std::function_ref;
+
+struct S
+{
+  int x;
+  void foo();
+};
+S s;
+
+constexpr int(*fp)(S) = nullptr;
+constexpr int S::*mdp = nullptr;
+constexpr int (S::*mfp)() = nullptr;
+
+function_ref<int(S)> fd1(nontype<fp>);  // { dg-error "from here" }
+function_ref<int(S)> fd2(nontype<mdp>); // { dg-error "from here" }
+function_ref<int(S)> fd3(nontype<mfp>); // { dg-error "from here" }
+
+function_ref<int()> br4(nontype<fp>, s);  // { dg-error "from here" }
+function_ref<int()> br5(nontype<mdp>, s); // { dg-error "from here" }
+function_ref<int()> br6(nontype<mfp>, s); // { dg-error "from here" }
+
+function_ref<int()> bp7(nontype<mdp>, &s); // { dg-error "from here" }
+function_ref<int()> bp8(nontype<mfp>, &s); // { dg-error "from here" }
+
+// { dg-prune-output "static assertion failed" }
diff --git a/libstdc++-v3/testsuite/20_util/function_ref/conv.cc 
b/libstdc++-v3/testsuite/20_util/function_ref/conv.cc
new file mode 100644
index 00000000000..49ff0a78829
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_ref/conv.cc
@@ -0,0 +1,152 @@
+// { dg-do run { target c++26 } }
+// { dg-require-effective-target hosted }
+
+#include <functional>
+#include <testsuite_hooks.h>
+
+using std::function_ref;
+
+static_assert( std::is_constructible_v<std::function_ref<void() const>,
+                                      std::function_ref<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;
+
+// The C++26 [func.wrap.general] p2 does not currently cover funciton_ref,
+// so we make extra copies of arguments.
+
+void
+test01()
+{
+  auto f = [](CountedArg const& arg) noexcept { return arg.counter; };
+  std::function_ref<int(CountedArg) const noexcept> r1(f);
+  std::move_only_function<int(CountedArg) const noexcept> m1(f);
+  std::copyable_function<int(CountedArg) const noexcept> c1(f);
+
+  // Complatible signatures
+  std::function_ref<int(CountedArg) const noexcept> r2m(m1);
+  VERIFY( r2m(c) == 2 );
+  std::function_ref<int(CountedArg) const noexcept> r2c(c1);
+  VERIFY( r2c(c) == 2 );
+
+  std::function_ref<int(CountedArg) const> r3r(r1);
+  VERIFY( r3r(c) == 2 );
+  std::function_ref<int(CountedArg) const> r3m(m1);
+  VERIFY( r3m(c) == 2 );
+  std::function_ref<int(CountedArg) const> r3c(c1);
+  VERIFY( r3c(c) == 2 );
+
+  std::function_ref<int(CountedArg)> r4r(r1);
+  VERIFY( r4r(c) == 2 );
+  std::function_ref<int(CountedArg)> r4m(m1);
+  VERIFY( r4m(c) == 2 );
+  std::function_ref<int(CountedArg)> r4c(c1);
+  VERIFY( r4c(c) == 2 );
+
+  // Incompatible signatures
+  std::function_ref<long(CountedArg) const noexcept> r5r(r1);
+  VERIFY( r5r(c) == 2 );
+  std::function_ref<long(CountedArg) const noexcept> r5m(m1);
+  VERIFY( r5r(c) == 2 );
+  std::function_ref<long(CountedArg) const noexcept> r5c(c1);
+  VERIFY( r5r(c) == 2 );
+}
+
+void
+test02()
+{
+  // Constructing move_only_function and copyable_function from function_ref,
+  // have not chance to restore manager, so we store function_ref inside.
+  auto f = [](CountedArg const& arg) noexcept { return arg.counter; };
+  std::function_ref<int(CountedArg) const noexcept> r1(f);
+
+  std::move_only_function<int(CountedArg) const noexcept> m1(r1);
+  VERIFY( m1(c) == 2 );
+
+  std::copyable_function<int(CountedArg) const noexcept> c1(r1);
+  VERIFY( c1(c) == 2 );
+}
+
+void
+test03()
+{
+  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::function_ref<int(CountedArg) const> r1(f);
+  VERIFY( r1(c) == 1001 );
+
+  // Call const overload as std::function_ref<int(CountedArg) const>
+  // inside std::function_ref<int(CountedArg)> would do.
+  std::function_ref<int(CountedArg)> r2(r1);
+  VERIFY( r2(c) == 1002 );
+  std::move_only_function<int(CountedArg)> m2(r1);
+  VERIFY( m2(c) == 1002 );
+
+  // Call non-const overload as const-qualifed operator() for
+  // std::function_ref<int(CountedArg)> do.
+  std::function_ref<int(CountedArg)> r3(f);
+  VERIFY( r3(c) == 1 );
+  std::function_ref<int(CountedArg) const> r4(r3);
+  VERIFY( r4(c) == 2 );
+  std::move_only_function<int(CountedArg) const> m4(r3);
+  VERIFY( m4(c) == 2 );
+}
+
+void
+test04()
+{
+  auto f = [](CountedArg const& arg) noexcept { return arg.counter; };
+  std::function_ref<int(CountedArg)> w1(f);
+  // function_ref stores function_ref due incompatibile signatures
+  std::function_ref<int(CountedArg const&)> w2(std::move(w1));
+  // copy is made when passing to int(CountedArg)
+  VERIFY( w2(c) == 1 );
+  // wrapped 3 times
+  std::function_ref<int(CountedArg)> w3(w2);
+  VERIFY( w3(c) == 2 );
+  // wrapped 4 times
+  std::function_ref<int(CountedArg const&)> w4(w3);
+  VERIFY( w4(c) == 2 );
+  // wrapped 5 times
+  std::function_ref<int(CountedArg)> w5(w4);
+  VERIFY( w5(c) == 3 );
+}
+
+void
+test05()
+{
+  // No special interoperability with std::function
+  auto f = [](CountedArg const& arg) noexcept { return arg.counter; };
+  std::function<int(CountedArg)> f1(f);
+  std::function_ref<int(CountedArg) const> c1(std::move(f1));
+  VERIFY( c1(c) == 2 );
+
+  std::function_ref<int(CountedArg) const> c2(f);
+  std::function<int(CountedArg)> f2(c2);
+  VERIFY( f2(c) == 2 );
+}
+
+int main()
+{
+  test01();
+  test02();
+  test03();
+  test04();
+  test05();
+}
diff --git a/libstdc++-v3/testsuite/20_util/function_ref/deduction.cc 
b/libstdc++-v3/testsuite/20_util/function_ref/deduction.cc
new file mode 100644
index 00000000000..2940b876954
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_ref/deduction.cc
@@ -0,0 +1,103 @@
+// { dg-do compile { target c++26 } }
+
+#include <functional>
+#include <type_traits>
+
+using std::is_same_v;
+using std::nontype;
+using std::nontype_t;
+using std::function_ref;
+
+int i = 0;
+
+void f0();
+void f0n() noexcept;
+
+static_assert( is_same_v<decltype(function_ref(f0)),
+                        function_ref<void()>> );
+static_assert( is_same_v<decltype(function_ref(f0n)),
+                        function_ref<void() noexcept>> );
+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>> );
+
+void f1(int);
+void f1n(int) noexcept;
+
+static_assert( is_same_v<decltype(function_ref(f1)),
+                        function_ref<void(int)>> );
+static_assert( is_same_v<decltype(function_ref(f1n)),
+                        function_ref<void(int) noexcept>> );
+static_assert( is_same_v<decltype(function_ref(nontype<f1>)),
+                        function_ref<void(int)>> );
+static_assert( is_same_v<decltype(function_ref(nontype<f1n>)),
+                        function_ref<void(int) noexcept>> );
+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>> );
+
+void f2(int*, int);
+void f2n(int*, int) noexcept;
+
+static_assert( is_same_v<decltype(function_ref(f2)),
+                        function_ref<void(int*, int)>> );
+static_assert( is_same_v<decltype(function_ref(f2n)),
+                        function_ref<void(int*, int) noexcept>> );
+static_assert( is_same_v<decltype(function_ref(nontype<f2>)),
+                        function_ref<void(int*, int)>> );
+static_assert( is_same_v<decltype(function_ref(nontype<f2n>)),
+                        function_ref<void(int*, int) noexcept>> );
+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>> );
+
+struct S
+{
+  int mem;
+  int f();
+  int fn() noexcept;
+
+  int fc(int) const;
+  int fcn(int) const noexcept;
+
+  int fl(int) &;
+  int fln(int) & noexcept;
+
+  int fcl(float) const&;
+  int fcln(float) const& noexcept;
+};
+S s{};
+const S cs{};
+
+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( 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( 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( 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( is_same_v<decltype(function_ref(nontype<&S::fl>, &s)),
+                        function_ref<int(int)>> );
+static_assert( is_same_v<decltype(function_ref(nontype<&S::fln>, s)),
+                        function_ref<int(int) noexcept>> );
+
+static_assert( is_same_v<decltype(function_ref(nontype<&S::fcl>, s)),
+                        function_ref<int(float)>> );
+static_assert( is_same_v<decltype(function_ref(nontype<&S::fcln>, &s)),
+                        function_ref<int(float) noexcept>> );
+
-- 
2.49.0

Reply via email to