[libcxx-commits] [libcxx] [libc++] P0792R14: `std::function_ref` (PR #94894)

via libcxx-commits libcxx-commits at lists.llvm.org
Sun Mar 8 03:52:56 PDT 2026


https://github.com/huixie90 updated https://github.com/llvm/llvm-project/pull/94894

>From bbb94dafea0cf8d620dff55733833fd8c2fb74a7 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Sat, 8 Jun 2024 17:32:42 -0700
Subject: [PATCH 01/13] [libc++] P0792R14: 'function_ref'

---
 libcxx/include/CMakeLists.txt                 |   4 +
 libcxx/include/__functional/function_ref.h    |  46 +++++
 .../__functional/function_ref_common.h        |  72 +++++++
 .../include/__functional/function_ref_impl.h  | 181 ++++++++++++++++++
 libcxx/include/__utility/nontype.h            |  34 ++++
 libcxx/include/functional                     |   4 +
 libcxx/include/module.modulemap.in            |   2 +
 libcxx/include/utility                        |  10 +
 .../func.wrap.ref/call/const.pass.cpp         | 124 ++++++++++++
 .../call/const_noexcept.pass.cpp              | 124 ++++++++++++
 .../func.wrap.ref/call/default.pass.cpp       | 119 ++++++++++++
 .../func.wrap.ref/call/noexcept.pass.cpp      | 119 ++++++++++++
 12 files changed, 839 insertions(+)
 create mode 100644 libcxx/include/__functional/function_ref.h
 create mode 100644 libcxx/include/__functional/function_ref_common.h
 create mode 100644 libcxx/include/__functional/function_ref_impl.h
 create mode 100644 libcxx/include/__utility/nontype.h
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/const.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/const_noexcept.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/default.pass.cpp
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/noexcept.pass.cpp

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 5cdf29b94e3eb..3b30fc47e4b2d 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -431,6 +431,9 @@ set(files
   __functional/compose.h
   __functional/default_searcher.h
   __functional/function.h
+  __functional/function_ref_common.h
+  __functional/function_ref_impl.h
+  __functional/function_ref.h
   __functional/hash.h
   __functional/identity.h
   __functional/invoke.h
@@ -940,6 +943,7 @@ set(files
   __utility/lazy_synth_three_way_comparator.h
   __utility/move.h
   __utility/no_destroy.h
+  __utility/nontype.h
   __utility/pair.h
   __utility/piecewise_construct.h
   __utility/priority_tag.h
diff --git a/libcxx/include/__functional/function_ref.h b/libcxx/include/__functional/function_ref.h
new file mode 100644
index 0000000000000..01cc22a64018e
--- /dev/null
+++ b/libcxx/include/__functional/function_ref.h
@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___FUNCTIONAL_FUNCTION_REF_H
+#define _LIBCPP___FUNCTIONAL_FUNCTION_REF_H
+
+#include <__config>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+// NOLINTBEGIN(readability-duplicate-include)
+
+#define _LIBCPP_FUNCTION_REF_CV
+#define _LIBCPP_FUNCTION_REF_NOEXCEPT false
+#include <__functional/function_ref_impl.h>
+#undef _LIBCPP_FUNCTION_REF_CV
+#undef _LIBCPP_FUNCTION_REF_NOEXCEPT
+
+#define _LIBCPP_FUNCTION_REF_CV
+#define _LIBCPP_FUNCTION_REF_NOEXCEPT true
+#include <__functional/function_ref_impl.h>
+#undef _LIBCPP_FUNCTION_REF_CV
+#undef _LIBCPP_FUNCTION_REF_NOEXCEPT
+
+#define _LIBCPP_FUNCTION_REF_CV const
+#define _LIBCPP_FUNCTION_REF_NOEXCEPT false
+#include <__functional/function_ref_impl.h>
+#undef _LIBCPP_FUNCTION_REF_CV
+#undef _LIBCPP_FUNCTION_REF_NOEXCEPT
+
+#define _LIBCPP_FUNCTION_REF_CV const
+#define _LIBCPP_FUNCTION_REF_NOEXCEPT true
+#include <__functional/function_ref_impl.h>
+#undef _LIBCPP_FUNCTION_REF_CV
+#undef _LIBCPP_FUNCTION_REF_NOEXCEPT
+
+// NOLINTEND(readability-duplicate-include)
+
+#endif // _LIBCPP___FUNCTIONAL_FUNCTION_REF_H
diff --git a/libcxx/include/__functional/function_ref_common.h b/libcxx/include/__functional/function_ref_common.h
new file mode 100644
index 0000000000000..f7d5575ebaffd
--- /dev/null
+++ b/libcxx/include/__functional/function_ref_common.h
@@ -0,0 +1,72 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___FUNCTIONAL_FUNCTION_REF_COMMON_H
+#define _LIBCPP___FUNCTIONAL_FUNCTION_REF_COMMON_H
+
+#include <__config>
+#include <__type_traits/invoke.h>
+#include <__type_traits/is_object.h>
+#include <__type_traits/remove_pointer.h>
+#include <__utility/nontype.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 26
+
+template <class...>
+class function_ref;
+
+template <class>
+inline constexpr bool __is_function_ref = false;
+
+template <class _Rp, class... _ArgTypes>
+inline constexpr bool __is_function_ref<function_ref<_Rp, _ArgTypes...>> = true;
+
+template <class _Fp, class _Tp>
+struct __function_ref_bind;
+
+template <class _Tp, class _Rp, class _Gp, class _ArgTypes>
+struct __function_ref_bind<_Rp (*)(_Gp, _ArgTypes...), _Tp> {
+  using type = _Rp(_ArgTypes...);
+};
+
+template <class _Tp, class _Rp, class _Gp, class _ArgTypes>
+struct __function_ref_bind<_Rp (*)(_Gp, _ArgTypes...) noexcept, _Tp> {
+  using type = _Rp(_ArgTypes...) noexcept;
+};
+
+template <class _Tp, class _Mp, class _Gp>
+  requires is_object_v<_Mp>
+struct __function_ref_bind<_Mp _Gp::*, _Tp> {
+  using type = invoke_result_t<_Mp _Gp::*, _Tp&>;
+};
+
+template <class _Fp, class _Tp>
+using __function_ref_bind_t = __function_ref_bind<_Fp, _Tp>::type;
+
+template <class _Fp>
+  requires is_function_v<_Fp>
+function_ref(_Fp*) -> function_ref<_Fp>;
+
+template <auto _Fn>
+  requires is_function_v<remove_pointer_t<decltype(_Fn)>>
+function_ref(nontype_t<_Fn>) -> function_ref<remove_pointer_t<decltype(_Fn)>>;
+
+template <auto _Fn, class _Tp>
+function_ref(nontype_t<_Fn>, _Tp&&) -> function_ref<__function_ref_bind_t<decltype(_Fn), _Tp&>>;
+
+#endif // _LIBCPP_STD_VER >= 26
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___FUNCTIONAL_FUNCTION_REF_COMMON_H
diff --git a/libcxx/include/__functional/function_ref_impl.h b/libcxx/include/__functional/function_ref_impl.h
new file mode 100644
index 0000000000000..4e1cd13a02ae2
--- /dev/null
+++ b/libcxx/include/__functional/function_ref_impl.h
@@ -0,0 +1,181 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <__assert>
+#include <__config>
+#include <__functional/function_ref_common.h>
+#include <__functional/invoke.h>
+#include <__memory/addressof.h>
+#include <__type_traits/invoke.h>
+#include <__type_traits/is_const.h>
+#include <__type_traits/is_function.h>
+#include <__type_traits/is_member_pointer.h>
+#include <__type_traits/is_object.h>
+#include <__type_traits/is_pointer.h>
+#include <__type_traits/is_void.h>
+#include <__type_traits/remove_cvref.h>
+#include <__type_traits/remove_pointer.h>
+#include <__type_traits/remove_reference.h>
+#include <__utility/forward.h>
+#include <__utility/nontype.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 26
+
+template <class...>
+class function_ref;
+
+template <class _Rp, class... _ArgTypes>
+class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT)> {
+private:
+#  if _LIBCPP_FUNCTION_REF_NOEXCEPT == true
+  template <class... _Tp>
+  static constexpr bool __is_invocable_using = is_nothrow_invocable_r_v<_Rp, _Tp..., _ArgTypes...>;
+#  else
+  template <class... _Tp>
+  static constexpr bool __is_invocable_using = is_invocable_r_v<_Rp, _Tp..., _ArgTypes...>;
+#  endif
+
+  union __storage_t {
+    void* __obj_ptr;
+    void const* __obj_const_ptr;
+    void (*__fn_ptr)();
+
+    constexpr explicit __storage_t() noexcept : __obj_ptr(nullptr) {};
+
+    template <class _Tp>
+    constexpr explicit __storage_t(_Tp* __ptr) noexcept {
+      if constexpr (is_object_v<_Tp>) {
+        if constexpr (is_const_v<_Tp>) {
+          __obj_const_ptr = __ptr;
+        } else {
+          __obj_ptr = __ptr;
+        }
+      } else {
+        static_assert(is_function_v<_Tp>);
+        __fn_ptr = reinterpret_cast<void (*)()>(__ptr);
+      }
+    }
+  } __storage_;
+
+  template <class _Tp>
+  _LIBCPP_HIDE_FROM_ABI static constexpr auto __get(__storage_t __storage) {
+    if constexpr (is_object_v<_Tp>) {
+      if constexpr (is_const_v<_Tp>) {
+        return static_cast<_Tp*>(__storage.__obj_const_ptr);
+      } else {
+        return static_cast<_Tp*>(__storage.__obj_ptr);
+      }
+    } else {
+      static_assert(is_function_v<_Tp>);
+      return reinterpret_cast<_Tp*>(__storage.__fn_ptr);
+    }
+  }
+
+  using __vtable_call_t = _Rp (*)(__storage_t, _ArgTypes&&...) noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT);
+  __vtable_call_t __vtable_call_;
+
+public:
+  template <class _Fp>
+    requires is_function_v<_Fp> && __is_invocable_using<_Fp>
+  _LIBCPP_HIDE_FROM_ABI function_ref(_Fp* __fn_ptr) noexcept
+      : __storage_(__fn_ptr),
+        __vtable_call_(
+            [](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp {
+              return __get<_Fp>(__storage)(std::forward<_ArgTypes>(__args)...);
+            }) {
+    _LIBCPP_ASSERT_UNCATEGORIZED(__fn_ptr != nullptr, "the function pointer should not be a nullptr");
+  }
+
+  template <class _Fp, class _Tp = remove_reference_t<_Fp>>
+    requires(!__is_function_ref<remove_cvref_t<_Fp>> && !is_member_pointer_v<_Tp> &&
+             __is_invocable_using<_LIBCPP_FUNCTION_REF_CV _Tp&>)
+  _LIBCPP_HIDE_FROM_ABI function_ref(_Fp&& __obj) noexcept
+      : __storage_(std::addressof(__obj)),
+        __vtable_call_(
+            [](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp {
+              _LIBCPP_FUNCTION_REF_CV _Tp& __obj = *__get<_Tp>(__storage);
+              return __obj(std::forward<_ArgTypes>(__args)...);
+            }) {}
+
+  template <auto _Fn>
+    requires __is_invocable_using<decltype(_Fn)>
+  constexpr function_ref(nontype_t<_Fn>) noexcept
+      : __vtable_call_([](__storage_t, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp {
+          return std::invoke_r<_Rp>(_Fn, std::forward<_ArgTypes>(__args)...);
+        }) {
+    if constexpr (is_pointer_v<decltype(_Fn)> || is_member_pointer_v<decltype(_Fn)>) {
+      static_assert(_Fn != nullptr, "the function pointer should not be a nullptr");
+    }
+  }
+
+  template <auto _Fn, class _Up, class _Tp = remove_reference_t<_Up>>
+    requires(!is_rvalue_reference_v<_Up &&>) && __is_invocable_using<decltype(_Fn), _LIBCPP_FUNCTION_REF_CV _Tp&>
+  constexpr function_ref(nontype_t<_Fn>, _Up&& __obj) noexcept
+      : __storage_(std::addressof(__obj)),
+        __vtable_call_(
+            [](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp {
+              _LIBCPP_FUNCTION_REF_CV _Tp& __obj = *__get<_Tp>(__storage);
+              return std::invoke_r<_Rp>(_Fn, __obj, std::forward<_ArgTypes>(__args)...);
+            }) {
+    if constexpr (is_pointer_v<decltype(_Fn)> || is_member_pointer_v<decltype(_Fn)>) {
+      static_assert(_Fn != nullptr, "the function pointer should not be a nullptr");
+    }
+  }
+
+  template <auto _Fn, class _Tp>
+    requires __is_invocable_using<decltype(_Fn), _LIBCPP_FUNCTION_REF_CV _Tp*>
+  constexpr function_ref(nontype_t<_Fn>, _LIBCPP_FUNCTION_REF_CV _Tp* __obj_ptr) noexcept
+      : __storage_(__obj_ptr),
+        __vtable_call_(
+            [](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp {
+              auto __obj = __get<_LIBCPP_FUNCTION_REF_CV _Tp>(__storage);
+              return std::invoke_r<_Rp>(_Fn, __obj, std::forward<_ArgTypes>(__args)...);
+            }) {
+    if constexpr (is_pointer_v<decltype(_Fn)> || is_member_pointer_v<decltype(_Fn)>) {
+      static_assert(_Fn != nullptr, "the function pointer should not be a nullptr");
+    }
+
+    if constexpr (is_member_pointer_v<decltype(_Fn)>) {
+      _LIBCPP_ASSERT_UNCATEGORIZED(__obj_ptr != nullptr, "the object pointer should not be a nullptr");
+    }
+  }
+
+  constexpr function_ref(const function_ref&) noexcept = default;
+
+  constexpr function_ref& operator=(const function_ref&) noexcept = default;
+
+  template <class _Tp>
+    requires(!__is_function_ref<_Tp>) && (!is_pointer_v<_Tp>) && (!__is_nontype_t<_Tp>)
+  function_ref& operator=(_Tp) = delete;
+
+  constexpr _Rp operator()(_ArgTypes... __args) const noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) {
+    return __vtable_call_(__storage_, std::forward<_ArgTypes>(__args)...);
+  }
+};
+
+template <class _Tp, class _Rp, class _Gp, class _ArgTypes>
+struct __function_ref_bind<_Rp (_Gp::*)(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT),
+                           _Tp> {
+  using type = _Rp(_ArgTypes...) noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT);
+};
+
+template <class _Tp, class _Rp, class _Gp, class _ArgTypes>
+struct __function_ref_bind<_Rp (_Gp::*)(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV & noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT),
+                           _Tp> {
+  using type = _Rp(_ArgTypes...) noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT);
+};
+
+#endif // _LIBCPP_STD_VER >= 26
+
+_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__utility/nontype.h b/libcxx/include/__utility/nontype.h
new file mode 100644
index 0000000000000..86893f17e2d96
--- /dev/null
+++ b/libcxx/include/__utility/nontype.h
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___UTILITY_NONTYPE_H
+#define _LIBCPP___UTILITY_NONTYPE_H
+
+#include <__config>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 26
+
+template <auto _Vp>
+struct nontype_t {
+  explicit nontype_t() = default;
+};
+
+template <auto _Vp>
+inline constexpr nontype_t<_Vp> nontype{};
+
+#endif // _LIBCPP_STD_VER >= 26
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___UTILITY_NONTYPE_H
diff --git a/libcxx/include/functional b/libcxx/include/functional
index 9ebcd818ec840..dbc023ac637d7 100644
--- a/libcxx/include/functional
+++ b/libcxx/include/functional
@@ -569,6 +569,10 @@ POLICY:  For non-variadic implementations, the number of arguments is limited
 #    include <__type_traits/unwrap_ref.h>
 #  endif
 
+#  if _LIBCPP_STD_VER >= 26
+#    include <__functional/function_ref.h>
+#  endif
+
 #  include <version>
 
 #  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 9012ed18cbd79..9ef908c66ca7c 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1425,6 +1425,7 @@ module std [system] {
     }
     module default_searcher             { header "__functional/default_searcher.h" }
     module function                     { header "__functional/function.h" }
+    module function_ref                 { header "__functional/function_ref.h" }
     module hash                         { header "__functional/hash.h" }
     module identity                     { header "__functional/identity.h" }
     module invoke                       { header "__functional/invoke.h" }
@@ -2186,6 +2187,7 @@ module std [system] {
     module lazy_synth_three_way_comparator { header "__utility/lazy_synth_three_way_comparator.h" }
     module move                            { header "__utility/move.h" }
     module no_destroy                      { header "__utility/no_destroy.h" }
+    module nontype                         { header "__utility/nontype.h" }
     module pair                            {
       header "__utility/pair.h"
       export std.utility.piecewise_construct
diff --git a/libcxx/include/utility b/libcxx/include/utility
index 1b19243afca1b..f6cffd3898c21 100644
--- a/libcxx/include/utility
+++ b/libcxx/include/utility
@@ -250,6 +250,15 @@ template <size_t I>
 template <size_t I>
   inline constexpr in_place_index_t<I> in_place_index{};
 
+// nontype argument tag
+template<auto V>
+  struct nontype_t {
+    explicit nontype_t() = default;
+  };
+template<auto V> constexpr nontype_t<V> nontype{};
+
+template<auto V> constexpr nontype_t<V> nontype{};
+
 // [utility.underlying], to_underlying
 template <class T>
     constexpr underlying_type_t<T> to_underlying( T value ) noexcept; // C++23
@@ -292,6 +301,7 @@ template <class T>
 #  endif
 
 #  if _LIBCPP_STD_VER >= 26
+#    include <__utility/nontype.h>
 #    include <__variant/monostate.h>
 #  endif
 
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/const.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/const.pass.cpp
new file mode 100644
index 0000000000000..53d7a5922353d
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/const.pass.cpp
@@ -0,0 +1,124 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+#include <cassert>
+#include <functional>
+#include <utility>
+#include <type_traits>
+
+#include "test_macros.h"
+
+static_assert(std::is_invocable_v<std::function_ref<void() const>&>);
+static_assert(std::is_invocable_v<std::function_ref<void() const>>);
+static_assert(std::is_invocable_v<std::function_ref<void() const>&&>);
+static_assert(std::is_invocable_v<std::function_ref<void() const> const&>);
+static_assert(std::is_invocable_v<std::function_ref<void() const> const>);
+static_assert(std::is_invocable_v<std::function_ref<void() const> const&&>);
+
+int fn() { return 42; }
+
+struct {
+  int operator()() const { return 42; }
+} fn_obj;
+
+void test() {
+  // template<class F> function_ref(F* f) noexcept;
+  {
+    // initialized from a function
+    std::function_ref<int() const> fn_ref = fn;
+    assert(fn_ref() == 42);
+  }
+  {
+    // initialized from a function pointer
+    std::function_ref<int() const> fn_ref = &fn;
+    assert(fn_ref() == 42);
+  }
+
+  // template<class F> constexpr function_ref(F&& f) noexcept;
+  {
+    // initialized from a function object
+    std::function_ref<int() const> fn_ref = fn_obj;
+    assert(fn_ref() == 42);
+  }
+}
+
+struct S {
+  int data_mem = 42;
+
+  int fn_mem() const { return 42; }
+};
+
+void test_nontype_t() {
+  // template<auto f> constexpr function_ref(nontype_t<f>) noexcept;
+  {
+    // initialized from a function through `nontype_t`
+    std::function_ref<int() const> fn_ref = std::nontype_t<fn>();
+    assert(fn_ref() == 42);
+  }
+  {
+    // initialized from a function pointer through `nontype_t`
+    std::function_ref<int() const> fn_ref = std::nontype_t<&fn>();
+    assert(fn_ref() == 42);
+  }
+  {
+    // initialized from a function object through `nontype_t`
+    std::function_ref<int() const> fn_ref = std::nontype_t<fn_obj>();
+    assert(fn_ref() == 42);
+  }
+  {
+    S s;
+    // initialized from a pointer to data member through `nontype_t`
+    std::function_ref<int(S) const> fn_ref = std::nontype_t<&S::data_mem>();
+    assert(fn_ref(s) == 42);
+  }
+  {
+    S s;
+    // initialized from a pointer to function member through `nontype_t`
+    std::function_ref<int(S) const> fn_ref = std::nontype_t<&S::fn_mem>();
+    assert(fn_ref(s) == 42);
+  }
+
+  // template<auto f, class U>
+  //   constexpr function_ref(nontype_t<f>, U&& obj) noexcept;
+  {
+    S s;
+    // initialized from a pointer to data member through `nontype_t` and bound to an object through a reference
+    std::function_ref<int() const> fn_ref = {std::nontype_t<&S::data_mem>(), s};
+    assert(fn_ref() == 42);
+  }
+  {
+    S s;
+    // initialized from a pointer to function member through `nontype_t` and bound to an object through a reference
+    std::function_ref<int() const> fn_ref = {std::nontype_t<&S::fn_mem>(), s};
+    assert(fn_ref() == 42);
+  }
+
+  // template<auto f, class T>
+  //   constexpr function_ref(nontype_t<f>, cv T* obj) noexcept;
+  {
+    S s;
+    // initialized from a pointer to data member through `nontype_t` and bound to an object through a pointer
+    std::function_ref<int() const> fn_ref = {std::nontype_t<&S::data_mem>(), &s};
+    assert(fn_ref() == 42);
+  }
+  {
+    S s;
+    // initialized from a pointer to function member through `nontype_t` and bound to an object through a pointer
+    static_assert(std::is_same_v<decltype(&s), S*>);
+    std::function_ref<int() const> fn_ref = {std::nontype_t<&S::fn_mem>(), &s};
+    assert(fn_ref() == 42);
+  }
+}
+
+int main(int, char**) {
+  test();
+  test_nontype_t();
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/const_noexcept.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/const_noexcept.pass.cpp
new file mode 100644
index 0000000000000..18d44e4b7ef0b
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/const_noexcept.pass.cpp
@@ -0,0 +1,124 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+#include <cassert>
+#include <functional>
+#include <utility>
+#include <type_traits>
+
+#include "test_macros.h"
+
+static_assert(std::is_invocable_v<std::function_ref<void() const noexcept>&>);
+static_assert(std::is_invocable_v<std::function_ref<void() const noexcept>>);
+static_assert(std::is_invocable_v<std::function_ref<void() const noexcept>&&>);
+static_assert(std::is_invocable_v<std::function_ref<void() const noexcept> const&>);
+static_assert(std::is_invocable_v<std::function_ref<void() const noexcept> const >);
+static_assert(std::is_invocable_v<std::function_ref<void() const noexcept> const&&>);
+
+int fn() noexcept { return 42; }
+
+struct {
+  int operator()() const noexcept { return 42; }
+} fn_obj;
+
+void test() {
+  // template<class F> function_ref(F* f) noexcept;
+  {
+    // initialized from a function
+    std::function_ref<int() const noexcept> fn_ref = fn;
+    assert(fn_ref() == 42);
+  }
+  {
+    // initialized from a function pointer
+    std::function_ref<int() const noexcept> fn_ref = &fn;
+    assert(fn_ref() == 42);
+  }
+
+  // template<class F> const noexceptexpr function_ref(F&& f) noexcept;
+  {
+    // initialized from a function object
+    std::function_ref<int() const noexcept> fn_ref = fn_obj;
+    assert(fn_ref() == 42);
+  }
+}
+
+struct S {
+  int data_mem = 42;
+
+  int fn_mem() const noexcept { return 42; }
+};
+
+void test_nontype_t() {
+  // template<auto f> const noexceptexpr function_ref(nontype_t<f>) noexcept;
+  {
+    // initialized from a function through `nontype_t`
+    std::function_ref<int() const noexcept> fn_ref = std::nontype_t<fn>();
+    assert(fn_ref() == 42);
+  }
+  {
+    // initialized from a function pointer through `nontype_t`
+    std::function_ref<int() const noexcept> fn_ref = std::nontype_t<&fn>();
+    assert(fn_ref() == 42);
+  }
+  {
+    // initialized from a function object through `nontype_t`
+    std::function_ref<int() const noexcept> fn_ref = std::nontype_t<fn_obj>();
+    assert(fn_ref() == 42);
+  }
+  {
+    S s;
+    // initialized from a pointer to data member through `nontype_t`
+    std::function_ref<int(S) const noexcept> fn_ref = std::nontype_t<&S::data_mem>();
+    assert(fn_ref(s) == 42);
+  }
+  {
+    S s;
+    // initialized from a pointer to function member through `nontype_t`
+    std::function_ref<int(S) const noexcept> fn_ref = std::nontype_t<&S::fn_mem>();
+    assert(fn_ref(s) == 42);
+  }
+
+  // template<auto f, class U>
+  //   const noexceptexpr function_ref(nontype_t<f>, U&& obj) noexcept;
+  {
+    S s;
+    // initialized from a pointer to data member through `nontype_t` and bound to an object through a reference
+    std::function_ref<int() const noexcept> fn_ref = {std::nontype_t<&S::data_mem>(), s};
+    assert(fn_ref() == 42);
+  }
+  {
+    S s;
+    // initialized from a pointer to function member through `nontype_t` and bound to an object through a reference
+    std::function_ref<int() const noexcept> fn_ref = {std::nontype_t<&S::fn_mem>(), s};
+    assert(fn_ref() == 42);
+  }
+
+  // template<auto f, class T>
+  //   const noexceptexpr function_ref(nontype_t<f>, cv T* obj) noexcept;
+  {
+    S s;
+    // initialized from a pointer to data member through `nontype_t` and bound to an object through a pointer
+    std::function_ref<int() const noexcept> fn_ref = {std::nontype_t<&S::data_mem>(), &s};
+    assert(fn_ref() == 42);
+  }
+  {
+    S s;
+    // initialized from a pointer to function member through `nontype_t` and bound to an object through a pointer
+    static_assert(std::is_same_v<decltype(&s), S*>);
+    std::function_ref<int() const noexcept> fn_ref = {std::nontype_t<&S::fn_mem>(), &s};
+    assert(fn_ref() == 42);
+  }
+}
+
+int main(int, char**) {
+  test();
+  test_nontype_t();
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/default.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/default.pass.cpp
new file mode 100644
index 0000000000000..ebc07a6c3520c
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/default.pass.cpp
@@ -0,0 +1,119 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+#include <cassert>
+#include <functional>
+#include <utility>
+#include <type_traits>
+
+#include "test_macros.h"
+
+static_assert(std::is_invocable_v<std::function_ref<void()>&>);
+static_assert(std::is_invocable_v<std::function_ref<void()>>);
+static_assert(std::is_invocable_v<std::function_ref<void()>&&>);
+static_assert(std::is_invocable_v<std::function_ref<void()> const&>);
+static_assert(std::is_invocable_v<std::function_ref<void()> const>);
+static_assert(std::is_invocable_v<std::function_ref<void()> const&&>);
+
+int fn() { return 42; }
+
+struct {
+  int operator()() { return 42; }
+} fn_obj;
+
+void test() {
+  // template<class F> function_ref(F* f) noexcept;
+  {
+    // initialized from a function
+    std::function_ref<int()> fn_ref = fn;
+    assert(fn_ref() == 42);
+  }
+  {
+    // initialized from a function pointer
+    std::function_ref<int()> fn_ref = &fn;
+    assert(fn_ref() == 42);
+  }
+
+  // template<class F> constexpr function_ref(F&& f) noexcept;
+  {
+    // initialized from a function object
+    std::function_ref<int()> fn_ref = fn_obj;
+    assert(fn_ref() == 42);
+  }
+}
+
+struct S {
+  int data_mem = 42;
+
+  int fn_mem() { return 42; }
+};
+
+void test_nontype_t() {
+  // template<auto f> constexpr function_ref(nontype_t<f>) noexcept;
+  {
+    // initialized from a function through `nontype_t`
+    std::function_ref<int()> fn_ref = std::nontype_t<fn>();
+    assert(fn_ref() == 42);
+  }
+  {
+    // initialized from a function pointer through `nontype_t`
+    std::function_ref<int()> fn_ref = std::nontype_t<&fn>();
+    assert(fn_ref() == 42);
+  }
+  {
+    S s;
+    // initialized from a pointer to data member through `nontype_t`
+    std::function_ref<int(S)> fn_ref = std::nontype_t<&S::data_mem>();
+    assert(fn_ref(s) == 42);
+  }
+  {
+    S s;
+    // initialized from a pointer to function member through `nontype_t`
+    std::function_ref<int(S)> fn_ref = std::nontype_t<&S::fn_mem>();
+    assert(fn_ref(s) == 42);
+  }
+
+  // template<auto f, class U>
+  //   constexpr function_ref(nontype_t<f>, U&& obj) noexcept;
+  {
+    S s;
+    // initialized from a pointer to data member through `nontype_t` and bound to an object through a reference
+    std::function_ref<int()> fn_ref = {std::nontype_t<&S::data_mem>(), s};
+    assert(fn_ref() == 42);
+  }
+  {
+    S s;
+    // initialized from a pointer to function member through `nontype_t` and bound to an object through a reference
+    std::function_ref<int()> fn_ref = {std::nontype_t<&S::fn_mem>(), s};
+    assert(fn_ref() == 42);
+  }
+
+  // template<auto f, class T>
+  //   constexpr function_ref(nontype_t<f>, cv T* obj) noexcept;
+  {
+    S s;
+    // initialized from a pointer to data member through `nontype_t` and bound to an object through a pointer
+    std::function_ref<int()> fn_ref = {std::nontype_t<&S::data_mem>(), &s};
+    assert(fn_ref() == 42);
+  }
+  {
+    S s;
+    // initialized from a pointer to function member through `nontype_t` and bound to an object through a pointer
+    static_assert(std::is_same_v<decltype(&s), S*>);
+    std::function_ref<int()> fn_ref = {std::nontype_t<&S::fn_mem>(), &s};
+    assert(fn_ref() == 42);
+  }
+}
+
+int main(int, char**) {
+  test();
+  test_nontype_t();
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/noexcept.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/noexcept.pass.cpp
new file mode 100644
index 0000000000000..9b58e677ed6ba
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/noexcept.pass.cpp
@@ -0,0 +1,119 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+#include <cassert>
+#include <functional>
+#include <utility>
+#include <type_traits>
+
+#include "test_macros.h"
+
+static_assert(std::is_invocable_v<std::function_ref<void() noexcept>&>);
+static_assert(std::is_invocable_v<std::function_ref<void() noexcept>>);
+static_assert(std::is_invocable_v<std::function_ref<void() noexcept>&&>);
+static_assert(std::is_invocable_v<std::function_ref<void() noexcept> const&>);
+static_assert(std::is_invocable_v<std::function_ref<void() noexcept> const>);
+static_assert(std::is_invocable_v<std::function_ref<void() noexcept> const&&>);
+
+int fn() noexcept { return 42; }
+
+struct {
+  int operator()() noexcept { return 42; }
+} fn_obj;
+
+void test() {
+  // template<class F> function_ref(F* f) noexcept;
+  {
+    // initialized from a function
+    std::function_ref<int() noexcept> fn_ref = fn;
+    assert(fn_ref() == 42);
+  }
+  {
+    // initialized from a function pointer
+    std::function_ref<int() noexcept> fn_ref = &fn;
+    assert(fn_ref() == 42);
+  }
+
+  // template<class F> constexpr function_ref(F&& f) noexcept;
+  {
+    // initialized from a function object
+    std::function_ref<int() noexcept> fn_ref = fn_obj;
+    assert(fn_ref() == 42);
+  }
+}
+
+struct S {
+  int data_mem = 42;
+
+  int fn_mem() noexcept { return 42; }
+};
+
+void test_nontype_t() {
+  // template<auto f> constexpr function_ref(nontype_t<f>) noexcept;
+  {
+    // initialized from a function through `nontype_t`
+    std::function_ref<int() noexcept> fn_ref = std::nontype_t<fn>();
+    assert(fn_ref() == 42);
+  }
+  {
+    // initialized from a function pointer through `nontype_t`
+    std::function_ref<int() noexcept> fn_ref = std::nontype_t<&fn>();
+    assert(fn_ref() == 42);
+  }
+  {
+    S s;
+    // initialized from a pointer to data member through `nontype_t`
+    std::function_ref<int(S) noexcept> fn_ref = std::nontype_t<&S::data_mem>();
+    assert(fn_ref(s) == 42);
+  }
+  {
+    S s;
+    // initialized from a pointer to function member through `nontype_t`
+    std::function_ref<int(S) noexcept> fn_ref = std::nontype_t<&S::fn_mem>();
+    assert(fn_ref(s) == 42);
+  }
+
+  // template<auto f, class U>
+  //   constexpr function_ref(nontype_t<f>, U&& obj) noexcept;
+  {
+    S s;
+    // initialized from a pointer to data member through `nontype_t` and bound to an object through a reference
+    std::function_ref<int() noexcept> fn_ref = {std::nontype_t<&S::data_mem>(), s};
+    assert(fn_ref() == 42);
+  }
+  {
+    S s;
+    // initialized from a pointer to function member through `nontype_t` and bound to an object through a reference
+    std::function_ref<int() noexcept> fn_ref = {std::nontype_t<&S::fn_mem>(), s};
+    assert(fn_ref() == 42);
+  }
+
+  // template<auto f, class T>
+  //   constexpr function_ref(nontype_t<f>, cv T* obj) noexcept;
+  {
+    S s;
+    // initialized from a pointer to data member through `nontype_t` and bound to an object through a pointer
+    std::function_ref<int() noexcept> fn_ref = {std::nontype_t<&S::data_mem>(), &s};
+    assert(fn_ref() == 42);
+  }
+  {
+    S s;
+    // initialized from a pointer to function member through `nontype_t` and bound to an object through a pointer
+    static_assert(std::is_same_v<decltype(&s), S*>);
+    std::function_ref<int() noexcept> fn_ref = {std::nontype_t<&S::fn_mem>(), &s};
+    assert(fn_ref() == 42);
+  }
+}
+
+int main(int, char**) {
+  test();
+  test_nontype_t();
+  return 0;
+}

>From 043f6110f85ea1247272510530360688d87fb07e Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Sat, 8 Jun 2024 23:22:06 -0700
Subject: [PATCH 02/13] [libc++] P0792R14: 'function_ref'

---
 .../__functional/function_ref_common.h        |  8 +-
 .../include/__functional/function_ref_impl.h  | 48 +++++------
 .../func.wrap.ref/ctor/ctad.pass.cpp          | 84 +++++++++++++++++++
 .../{call => invoke}/const.pass.cpp           |  0
 .../{call => invoke}/const_noexcept.pass.cpp  |  0
 .../{call => invoke}/default.pass.cpp         |  0
 .../{call => invoke}/noexcept.pass.cpp        |  0
 7 files changed, 111 insertions(+), 29 deletions(-)
 create mode 100644 libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/ctor/ctad.pass.cpp
 rename libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/{call => invoke}/const.pass.cpp (100%)
 rename libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/{call => invoke}/const_noexcept.pass.cpp (100%)
 rename libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/{call => invoke}/default.pass.cpp (100%)
 rename libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/{call => invoke}/noexcept.pass.cpp (100%)

diff --git a/libcxx/include/__functional/function_ref_common.h b/libcxx/include/__functional/function_ref_common.h
index f7d5575ebaffd..d34a47286cf58 100644
--- a/libcxx/include/__functional/function_ref_common.h
+++ b/libcxx/include/__functional/function_ref_common.h
@@ -33,14 +33,14 @@ template <class _Rp, class... _ArgTypes>
 inline constexpr bool __is_function_ref<function_ref<_Rp, _ArgTypes...>> = true;
 
 template <class _Fp, class _Tp>
-struct __function_ref_bind;
+struct __function_ref_bind {};
 
-template <class _Tp, class _Rp, class _Gp, class _ArgTypes>
+template <class _Tp, class _Rp, class _Gp, class... _ArgTypes>
 struct __function_ref_bind<_Rp (*)(_Gp, _ArgTypes...), _Tp> {
   using type = _Rp(_ArgTypes...);
 };
 
-template <class _Tp, class _Rp, class _Gp, class _ArgTypes>
+template <class _Tp, class _Rp, class _Gp, class... _ArgTypes>
 struct __function_ref_bind<_Rp (*)(_Gp, _ArgTypes...) noexcept, _Tp> {
   using type = _Rp(_ArgTypes...) noexcept;
 };
@@ -48,7 +48,7 @@ struct __function_ref_bind<_Rp (*)(_Gp, _ArgTypes...) noexcept, _Tp> {
 template <class _Tp, class _Mp, class _Gp>
   requires is_object_v<_Mp>
 struct __function_ref_bind<_Mp _Gp::*, _Tp> {
-  using type = invoke_result_t<_Mp _Gp::*, _Tp&>;
+  using type = invoke_result_t<_Mp _Gp::*, _Tp&>();
 };
 
 template <class _Fp, class _Tp>
diff --git a/libcxx/include/__functional/function_ref_impl.h b/libcxx/include/__functional/function_ref_impl.h
index 4e1cd13a02ae2..2e6ed45f32b19 100644
--- a/libcxx/include/__functional/function_ref_impl.h
+++ b/libcxx/include/__functional/function_ref_impl.h
@@ -46,6 +46,8 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU
   static constexpr bool __is_invocable_using = is_invocable_r_v<_Rp, _Tp..., _ArgTypes...>;
 #  endif
 
+  // use a union instead of a plain `void*` to avoid dropping const qualifiers and casting function pointers to data
+  // pointers
   union __storage_t {
     void* __obj_ptr;
     void const* __obj_const_ptr;
@@ -82,18 +84,17 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU
     }
   }
 
-  using __vtable_call_t = _Rp (*)(__storage_t, _ArgTypes&&...) noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT);
-  __vtable_call_t __vtable_call_;
+  using __call_t = _Rp (*)(__storage_t, _ArgTypes&&...) noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT);
+  __call_t __call_;
 
 public:
   template <class _Fp>
     requires is_function_v<_Fp> && __is_invocable_using<_Fp>
   _LIBCPP_HIDE_FROM_ABI function_ref(_Fp* __fn_ptr) noexcept
       : __storage_(__fn_ptr),
-        __vtable_call_(
-            [](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp {
-              return __get<_Fp>(__storage)(std::forward<_ArgTypes>(__args)...);
-            }) {
+        __call_([](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp {
+          return __get<_Fp>(__storage)(std::forward<_ArgTypes>(__args)...);
+        }) {
     _LIBCPP_ASSERT_UNCATEGORIZED(__fn_ptr != nullptr, "the function pointer should not be a nullptr");
   }
 
@@ -102,16 +103,15 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU
              __is_invocable_using<_LIBCPP_FUNCTION_REF_CV _Tp&>)
   _LIBCPP_HIDE_FROM_ABI function_ref(_Fp&& __obj) noexcept
       : __storage_(std::addressof(__obj)),
-        __vtable_call_(
-            [](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp {
-              _LIBCPP_FUNCTION_REF_CV _Tp& __obj = *__get<_Tp>(__storage);
-              return __obj(std::forward<_ArgTypes>(__args)...);
-            }) {}
+        __call_([](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp {
+          _LIBCPP_FUNCTION_REF_CV _Tp& __obj = *__get<_Tp>(__storage);
+          return __obj(std::forward<_ArgTypes>(__args)...);
+        }) {}
 
   template <auto _Fn>
     requires __is_invocable_using<decltype(_Fn)>
   constexpr function_ref(nontype_t<_Fn>) noexcept
-      : __vtable_call_([](__storage_t, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp {
+      : __call_([](__storage_t, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp {
           return std::invoke_r<_Rp>(_Fn, std::forward<_ArgTypes>(__args)...);
         }) {
     if constexpr (is_pointer_v<decltype(_Fn)> || is_member_pointer_v<decltype(_Fn)>) {
@@ -123,11 +123,10 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU
     requires(!is_rvalue_reference_v<_Up &&>) && __is_invocable_using<decltype(_Fn), _LIBCPP_FUNCTION_REF_CV _Tp&>
   constexpr function_ref(nontype_t<_Fn>, _Up&& __obj) noexcept
       : __storage_(std::addressof(__obj)),
-        __vtable_call_(
-            [](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp {
-              _LIBCPP_FUNCTION_REF_CV _Tp& __obj = *__get<_Tp>(__storage);
-              return std::invoke_r<_Rp>(_Fn, __obj, std::forward<_ArgTypes>(__args)...);
-            }) {
+        __call_([](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp {
+          _LIBCPP_FUNCTION_REF_CV _Tp& __obj = *__get<_Tp>(__storage);
+          return std::invoke_r<_Rp>(_Fn, __obj, std::forward<_ArgTypes>(__args)...);
+        }) {
     if constexpr (is_pointer_v<decltype(_Fn)> || is_member_pointer_v<decltype(_Fn)>) {
       static_assert(_Fn != nullptr, "the function pointer should not be a nullptr");
     }
@@ -137,11 +136,10 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU
     requires __is_invocable_using<decltype(_Fn), _LIBCPP_FUNCTION_REF_CV _Tp*>
   constexpr function_ref(nontype_t<_Fn>, _LIBCPP_FUNCTION_REF_CV _Tp* __obj_ptr) noexcept
       : __storage_(__obj_ptr),
-        __vtable_call_(
-            [](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp {
-              auto __obj = __get<_LIBCPP_FUNCTION_REF_CV _Tp>(__storage);
-              return std::invoke_r<_Rp>(_Fn, __obj, std::forward<_ArgTypes>(__args)...);
-            }) {
+        __call_([](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp {
+          auto __obj = __get<_LIBCPP_FUNCTION_REF_CV _Tp>(__storage);
+          return std::invoke_r<_Rp>(_Fn, __obj, std::forward<_ArgTypes>(__args)...);
+        }) {
     if constexpr (is_pointer_v<decltype(_Fn)> || is_member_pointer_v<decltype(_Fn)>) {
       static_assert(_Fn != nullptr, "the function pointer should not be a nullptr");
     }
@@ -160,17 +158,17 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU
   function_ref& operator=(_Tp) = delete;
 
   constexpr _Rp operator()(_ArgTypes... __args) const noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) {
-    return __vtable_call_(__storage_, std::forward<_ArgTypes>(__args)...);
+    return __call_(__storage_, std::forward<_ArgTypes>(__args)...);
   }
 };
 
-template <class _Tp, class _Rp, class _Gp, class _ArgTypes>
+template <class _Tp, class _Rp, class _Gp, class... _ArgTypes>
 struct __function_ref_bind<_Rp (_Gp::*)(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT),
                            _Tp> {
   using type = _Rp(_ArgTypes...) noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT);
 };
 
-template <class _Tp, class _Rp, class _Gp, class _ArgTypes>
+template <class _Tp, class _Rp, class _Gp, class... _ArgTypes>
 struct __function_ref_bind<_Rp (_Gp::*)(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV & noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT),
                            _Tp> {
   using type = _Rp(_ArgTypes...) noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT);
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/ctor/ctad.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/ctor/ctad.pass.cpp
new file mode 100644
index 0000000000000..c7490fc0982e3
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/ctor/ctad.pass.cpp
@@ -0,0 +1,84 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
+
+#include <cassert>
+#include <functional>
+#include <utility>
+#include <type_traits>
+
+#include "test_macros.h"
+
+int fn(int, float) { return 42; }
+
+int fn_noexcept(int, float) noexcept { return 42; }
+
+struct S {
+  int data_mem = 42;
+
+  int fn_mem(int, float) { return 42; }
+  int fn_mem_noexcept(int, float) noexcept { return 42; }
+};
+
+void test() {
+  // template<class F>
+  //  function_ref(F*) -> function_ref<F>;
+  {
+    std::function_ref fn_ref = fn;
+    static_assert(std::is_same_v<decltype(fn_ref), std::function_ref<int(int, float)>>);
+  }
+  {
+    std::function_ref fn_ref = fn_noexcept;
+    static_assert(std::is_same_v<decltype(fn_ref), std::function_ref<int(int, float) noexcept>>);
+  }
+
+  // template<auto f>
+  //  function_ref(nontype_t<f>) -> function_ref<...>;
+  {
+    std::function_ref fn_ref = std::nontype_t<fn>();
+    static_assert(std::is_same_v<decltype(fn_ref), std::function_ref<int(int, float)>>);
+  }
+  {
+    std::function_ref fn_ref = std::nontype_t<fn_noexcept>();
+    static_assert(std::is_same_v<decltype(fn_ref), std::function_ref<int(int, float) noexcept>>);
+  }
+
+  // template<auto f, class T>
+  //  function_ref(nontype_t<f>, T&&) -> function_ref<...>;
+  {
+    int arg                  = 0;
+    std::function_ref fn_ref = {std::nontype_t<fn>(), arg};
+    static_assert(std::is_same_v<decltype(fn_ref), std::function_ref<int(float)>>);
+  }
+  {
+    S s;
+    std::function_ref fn_ref = {std::nontype_t<&S::data_mem>(), s};
+    static_assert(std::is_same_v<decltype(fn_ref), std::function_ref<int&()>>);
+  }
+  {
+    const S s;
+    std::function_ref fn_ref = {std::nontype_t<&S::data_mem>(), s};
+    static_assert(std::is_same_v<decltype(fn_ref), std::function_ref<int const&()>>);
+  }
+  {
+    S s;
+    std::function_ref fn_ref = {std::nontype_t<&S::fn_mem>(), s};
+    static_assert(std::is_same_v<decltype(fn_ref), std::function_ref<int(int, float)>>);
+  }
+  {
+    S s;
+    std::function_ref fn_ref = {std::nontype_t<&S::fn_mem_noexcept>(), s};
+    static_assert(std::is_same_v<decltype(fn_ref), std::function_ref<int(int, float) noexcept>>);
+  }
+}
+
+int main(int, char**) {
+  test();
+  return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/const.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/const.pass.cpp
similarity index 100%
rename from libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/const.pass.cpp
rename to libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/const.pass.cpp
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/const_noexcept.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/const_noexcept.pass.cpp
similarity index 100%
rename from libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/const_noexcept.pass.cpp
rename to libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/const_noexcept.pass.cpp
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/default.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/default.pass.cpp
similarity index 100%
rename from libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/default.pass.cpp
rename to libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/default.pass.cpp
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/noexcept.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/noexcept.pass.cpp
similarity index 100%
rename from libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/call/noexcept.pass.cpp
rename to libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/noexcept.pass.cpp

>From 45f04ea5861ca1acece9a01fdec1e1ed9596b75d Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Sun, 9 Jun 2024 01:50:20 -0700
Subject: [PATCH 03/13] [libc++] P0792R14: 'function_ref'

---
 libcxx/modules/std/functional.inc | 4 ++++
 libcxx/modules/std/utility.inc    | 5 +++++
 2 files changed, 9 insertions(+)

diff --git a/libcxx/modules/std/functional.inc b/libcxx/modules/std/functional.inc
index 9ef8f584611fc..be804b19f75f8 100644
--- a/libcxx/modules/std/functional.inc
+++ b/libcxx/modules/std/functional.inc
@@ -95,6 +95,10 @@ export namespace std {
 
   using std::function;
 
+#if _LIBCPP_STD_VER >= 26
+  using std::function_ref;
+#endif // _LIBCPP_STD_VER >= 26
+
   using std::swap;
 
   using std::operator==;
diff --git a/libcxx/modules/std/utility.inc b/libcxx/modules/std/utility.inc
index 77c21b87640dd..28f8e36e30af9 100644
--- a/libcxx/modules/std/utility.inc
+++ b/libcxx/modules/std/utility.inc
@@ -89,6 +89,11 @@ export namespace std {
   using std::in_place_index;
   using std::in_place_index_t;
 
+#if _LIBCPP_STD_VER >= 26
+  using std::nontype;
+  using std::nontype_t;
+#endif // _LIBCPP_STD_VER >= 23
+
   // [depr.relops]
   namespace rel_ops {
     using rel_ops::operator!=;

>From bd5c50b6900d81882bda5db1e56b56bfb17559ff Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Sun, 9 Jun 2024 03:41:35 -0700
Subject: [PATCH 04/13] [libc++] P0792R14: 'function_ref'

---
 libcxx/include/CMakeLists.txt      | 2 +-
 libcxx/include/__utility/nontype.h | 5 +++++
 libcxx/include/module.modulemap.in | 2 ++
 3 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 3b30fc47e4b2d..90dc684944342 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -431,9 +431,9 @@ set(files
   __functional/compose.h
   __functional/default_searcher.h
   __functional/function.h
+  __functional/function_ref.h
   __functional/function_ref_common.h
   __functional/function_ref_impl.h
-  __functional/function_ref.h
   __functional/hash.h
   __functional/identity.h
   __functional/invoke.h
diff --git a/libcxx/include/__utility/nontype.h b/libcxx/include/__utility/nontype.h
index 86893f17e2d96..6a91d2cace162 100644
--- a/libcxx/include/__utility/nontype.h
+++ b/libcxx/include/__utility/nontype.h
@@ -27,6 +27,11 @@ struct nontype_t {
 template <auto _Vp>
 inline constexpr nontype_t<_Vp> nontype{};
 
+template <class>
+inline constexpr bool __is_nontype_t = false;
+template <auto _Vp>
+inline constexpr bool __is_nontype_t<nontype_t<_Vp>> = true;
+
 #endif // _LIBCPP_STD_VER >= 26
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 9ef908c66ca7c..b9f0ffeb2b41d 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1426,6 +1426,8 @@ module std [system] {
     module default_searcher             { header "__functional/default_searcher.h" }
     module function                     { header "__functional/function.h" }
     module function_ref                 { header "__functional/function_ref.h" }
+    module function_ref_common          { header "__functional/function_ref_common.h" }
+    module function_ref_impl            { header "__functional/function_ref_impl.h" }
     module hash                         { header "__functional/hash.h" }
     module identity                     { header "__functional/identity.h" }
     module invoke                       { header "__functional/invoke.h" }

>From a697bc80b3e3c10a0f464035b0f03759e61af042 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Sun, 9 Jun 2024 03:50:12 -0700
Subject: [PATCH 05/13] [libc++] P0792R14: 'function_ref'

---
 .../include/__functional/function_ref_impl.h   | 18 +++++++++---------
 libcxx/include/__utility/nontype.h             |  2 +-
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/libcxx/include/__functional/function_ref_impl.h b/libcxx/include/__functional/function_ref_impl.h
index 2e6ed45f32b19..261beb2d04dad 100644
--- a/libcxx/include/__functional/function_ref_impl.h
+++ b/libcxx/include/__functional/function_ref_impl.h
@@ -53,10 +53,10 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU
     void const* __obj_const_ptr;
     void (*__fn_ptr)();
 
-    constexpr explicit __storage_t() noexcept : __obj_ptr(nullptr) {};
+    _LIBCPP_HIDE_FROM_ABI constexpr explicit __storage_t() noexcept : __obj_ptr(nullptr){};
 
     template <class _Tp>
-    constexpr explicit __storage_t(_Tp* __ptr) noexcept {
+    _LIBCPP_HIDE_FROM_ABI constexpr explicit __storage_t(_Tp* __ptr) noexcept {
       if constexpr (is_object_v<_Tp>) {
         if constexpr (is_const_v<_Tp>) {
           __obj_const_ptr = __ptr;
@@ -110,7 +110,7 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU
 
   template <auto _Fn>
     requires __is_invocable_using<decltype(_Fn)>
-  constexpr function_ref(nontype_t<_Fn>) noexcept
+  _LIBCPP_HIDE_FROM_ABI constexpr function_ref(nontype_t<_Fn>) noexcept
       : __call_([](__storage_t, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp {
           return std::invoke_r<_Rp>(_Fn, std::forward<_ArgTypes>(__args)...);
         }) {
@@ -121,7 +121,7 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU
 
   template <auto _Fn, class _Up, class _Tp = remove_reference_t<_Up>>
     requires(!is_rvalue_reference_v<_Up &&>) && __is_invocable_using<decltype(_Fn), _LIBCPP_FUNCTION_REF_CV _Tp&>
-  constexpr function_ref(nontype_t<_Fn>, _Up&& __obj) noexcept
+  _LIBCPP_HIDE_FROM_ABI constexpr function_ref(nontype_t<_Fn>, _Up&& __obj) noexcept
       : __storage_(std::addressof(__obj)),
         __call_([](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp {
           _LIBCPP_FUNCTION_REF_CV _Tp& __obj = *__get<_Tp>(__storage);
@@ -134,7 +134,7 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU
 
   template <auto _Fn, class _Tp>
     requires __is_invocable_using<decltype(_Fn), _LIBCPP_FUNCTION_REF_CV _Tp*>
-  constexpr function_ref(nontype_t<_Fn>, _LIBCPP_FUNCTION_REF_CV _Tp* __obj_ptr) noexcept
+  _LIBCPP_HIDE_FROM_ABI constexpr function_ref(nontype_t<_Fn>, _LIBCPP_FUNCTION_REF_CV _Tp* __obj_ptr) noexcept
       : __storage_(__obj_ptr),
         __call_([](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp {
           auto __obj = __get<_LIBCPP_FUNCTION_REF_CV _Tp>(__storage);
@@ -149,15 +149,15 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU
     }
   }
 
-  constexpr function_ref(const function_ref&) noexcept = default;
+  _LIBCPP_HIDE_FROM_ABI constexpr function_ref(const function_ref&) noexcept = default;
 
-  constexpr function_ref& operator=(const function_ref&) noexcept = default;
+  _LIBCPP_HIDE_FROM_ABI constexpr function_ref& operator=(const function_ref&) noexcept = default;
 
   template <class _Tp>
     requires(!__is_function_ref<_Tp>) && (!is_pointer_v<_Tp>) && (!__is_nontype_t<_Tp>)
-  function_ref& operator=(_Tp) = delete;
+  _LIBCPP_HIDE_FROM_ABI function_ref& operator=(_Tp) = delete;
 
-  constexpr _Rp operator()(_ArgTypes... __args) const noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) {
+  _LIBCPP_HIDE_FROM_ABI constexpr _Rp operator()(_ArgTypes... __args) const noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) {
     return __call_(__storage_, std::forward<_ArgTypes>(__args)...);
   }
 };
diff --git a/libcxx/include/__utility/nontype.h b/libcxx/include/__utility/nontype.h
index 6a91d2cace162..3a10840154009 100644
--- a/libcxx/include/__utility/nontype.h
+++ b/libcxx/include/__utility/nontype.h
@@ -21,7 +21,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <auto _Vp>
 struct nontype_t {
-  explicit nontype_t() = default;
+  _LIBCPP_HIDE_FROM_ABI explicit nontype_t() = default;
 };
 
 template <auto _Vp>

>From 079e19f878f336959bc4ab6e6d138ab2c5717c10 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Sun, 9 Jun 2024 03:55:54 -0700
Subject: [PATCH 06/13] [libc++] P0792R14: 'function_ref'

---
 libcxx/include/__functional/function_ref_common.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libcxx/include/__functional/function_ref_common.h b/libcxx/include/__functional/function_ref_common.h
index d34a47286cf58..b2d1864e582c5 100644
--- a/libcxx/include/__functional/function_ref_common.h
+++ b/libcxx/include/__functional/function_ref_common.h
@@ -11,6 +11,7 @@
 
 #include <__config>
 #include <__type_traits/invoke.h>
+#include <__type_traits/is_function.h>
 #include <__type_traits/is_object.h>
 #include <__type_traits/remove_pointer.h>
 #include <__utility/nontype.h>

>From 5df75f1651a5111bcf45e5f227a5e9f90e5d3c3f Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Sun, 9 Jun 2024 04:01:41 -0700
Subject: [PATCH 07/13] [libc++] P0792R14: 'function_ref'

---
 libcxx/include/__functional/function_ref_impl.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libcxx/include/__functional/function_ref_impl.h b/libcxx/include/__functional/function_ref_impl.h
index 261beb2d04dad..50951228c10a8 100644
--- a/libcxx/include/__functional/function_ref_impl.h
+++ b/libcxx/include/__functional/function_ref_impl.h
@@ -17,6 +17,7 @@
 #include <__type_traits/is_member_pointer.h>
 #include <__type_traits/is_object.h>
 #include <__type_traits/is_pointer.h>
+#include <__type_traits/is_reference.h>
 #include <__type_traits/is_void.h>
 #include <__type_traits/remove_cvref.h>
 #include <__type_traits/remove_pointer.h>

>From d502218b944badf282f3e0312c75b5c247171a25 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Sun, 9 Jun 2024 04:41:50 -0700
Subject: [PATCH 08/13] [libc++] P0792R14: 'function_ref'

---
 libcxx/include/__functional/function_ref.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libcxx/include/__functional/function_ref.h b/libcxx/include/__functional/function_ref.h
index 01cc22a64018e..8fcebb8aa4825 100644
--- a/libcxx/include/__functional/function_ref.h
+++ b/libcxx/include/__functional/function_ref.h
@@ -10,6 +10,7 @@
 #define _LIBCPP___FUNCTIONAL_FUNCTION_REF_H
 
 #include <__config>
+#include <__functional/function_ref_common.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header

>From 7c1c7e4a9c5b4f723479475235e48aeeb2442c29 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Sun, 9 Jun 2024 05:10:54 -0700
Subject: [PATCH 09/13] [libc++] P0792R14: 'function_ref'

---
 libcxx/include/module.modulemap.in | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index b9f0ffeb2b41d..37bde6aafe7f2 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1427,7 +1427,7 @@ module std [system] {
     module function                     { header "__functional/function.h" }
     module function_ref                 { header "__functional/function_ref.h" }
     module function_ref_common          { header "__functional/function_ref_common.h" }
-    module function_ref_impl            { header "__functional/function_ref_impl.h" }
+    module function_ref_impl            { textual header "__functional/function_ref_impl.h" }
     module hash                         { header "__functional/hash.h" }
     module identity                     { header "__functional/identity.h" }
     module invoke                       { header "__functional/invoke.h" }

>From 3591a3a12dcf27e78fcd36c8e9cb84738f44d7eb Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Sun, 9 Jun 2024 11:18:14 -0700
Subject: [PATCH 10/13] [libc++] P0792R14: 'function_ref'

---
 libcxx/include/__functional/function_ref_impl.h | 1 -
 libcxx/include/module.modulemap.in              | 2 +-
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/libcxx/include/__functional/function_ref_impl.h b/libcxx/include/__functional/function_ref_impl.h
index 50951228c10a8..d992d6661cf1b 100644
--- a/libcxx/include/__functional/function_ref_impl.h
+++ b/libcxx/include/__functional/function_ref_impl.h
@@ -8,7 +8,6 @@
 
 #include <__assert>
 #include <__config>
-#include <__functional/function_ref_common.h>
 #include <__functional/invoke.h>
 #include <__memory/addressof.h>
 #include <__type_traits/invoke.h>
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 37bde6aafe7f2..183383e893f24 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1426,7 +1426,7 @@ module std [system] {
     module default_searcher             { header "__functional/default_searcher.h" }
     module function                     { header "__functional/function.h" }
     module function_ref                 { header "__functional/function_ref.h" }
-    module function_ref_common          { header "__functional/function_ref_common.h" }
+    module function_ref_common          { textual header "__functional/function_ref_common.h" }
     module function_ref_impl            { textual header "__functional/function_ref_impl.h" }
     module hash                         { header "__functional/hash.h" }
     module identity                     { header "__functional/identity.h" }

>From cfdcc5f769f83608c78bb2d84238952913f3f560 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Sun, 9 Jun 2024 11:23:21 -0700
Subject: [PATCH 11/13] [libc++] P0792R14: 'function_ref'

---
 libcxx/include/functional | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libcxx/include/functional b/libcxx/include/functional
index dbc023ac637d7..14e29f58cca2e 100644
--- a/libcxx/include/functional
+++ b/libcxx/include/functional
@@ -485,6 +485,11 @@ template <class  R, class ... ArgTypes>
 template <class  R, class ... ArgTypes>
   void swap(function<R(ArgTypes...)>&, function<R(ArgTypes...)>&) noexcept;
 
+// [func.wrap.ref], non-owning wrapper
+template<class... S> class function_ref;                              // freestanding, not defined, since C++26
+template<class R, class... ArgTypes>
+  class function_ref<R(ArgTypes...) cv noexcept(noex)>;               // freestanding, since C++26
+
 template <class T> struct hash;
 
 template <> struct hash<bool>;

>From 2701971b68e4b34bdf505e5445b62c0d9ca11216 Mon Sep 17 00:00:00 2001
From: Xiaoyang Liu <siujoeng.lau at gmail.com>
Date: Sun, 9 Jun 2024 11:58:22 -0700
Subject: [PATCH 12/13] [libc++] P0792R14: 'function_ref'

---
 libcxx/include/__functional/function_ref_impl.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/include/__functional/function_ref_impl.h b/libcxx/include/__functional/function_ref_impl.h
index d992d6661cf1b..daae5c87d9470 100644
--- a/libcxx/include/__functional/function_ref_impl.h
+++ b/libcxx/include/__functional/function_ref_impl.h
@@ -53,7 +53,7 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU
     void const* __obj_const_ptr;
     void (*__fn_ptr)();
 
-    _LIBCPP_HIDE_FROM_ABI constexpr explicit __storage_t() noexcept : __obj_ptr(nullptr){};
+    _LIBCPP_HIDE_FROM_ABI constexpr explicit __storage_t() noexcept : __obj_ptr(nullptr) {}
 
     template <class _Tp>
     _LIBCPP_HIDE_FROM_ABI constexpr explicit __storage_t(_Tp* __ptr) noexcept {

>From 0390be2ca09d79a4ead4c55652e1df6ffc2214c9 Mon Sep 17 00:00:00 2001
From: Hui Xie <hui.xie1990 at gmail.com>
Date: Sun, 8 Mar 2026 10:52:40 +0000
Subject: [PATCH 13/13] rebase + put in experimental + rename nontype to
 constant_arg

---
 libcxx/docs/FeatureTestMacroTable.rst         |  2 +-
 libcxx/docs/ReleaseNotes/23.rst               |  2 +
 libcxx/docs/Status/Cxx2cPapers.csv            |  2 +-
 libcxx/include/CMakeLists.txt                 |  2 +-
 libcxx/include/__configuration/experimental.h |  1 +
 libcxx/include/__functional/function_ref.h    |  2 +
 .../__functional/function_ref_common.h        | 18 ++++----
 .../include/__functional/function_ref_impl.h  | 20 ++++----
 .../__utility/{nontype.h => constant_arg.h}   | 16 +++----
 libcxx/include/module.modulemap.in            |  2 +-
 libcxx/include/utility                        | 12 ++---
 libcxx/include/version                        |  4 +-
 libcxx/modules/std/utility.inc                |  4 +-
 .../functional.version.compile.pass.cpp       |  4 +-
 .../version.version.compile.pass.cpp          |  4 +-
 .../func.wrap.ref/ctor/ctad.pass.cpp          | 18 ++++----
 .../func.wrap.ref/invoke/const.pass.cpp       | 46 +++++++++----------
 .../invoke/const_noexcept.pass.cpp            | 46 +++++++++----------
 .../func.wrap.ref/invoke/default.pass.cpp     | 42 ++++++++---------
 .../func.wrap.ref/invoke/noexcept.pass.cpp    | 42 ++++++++---------
 .../generate_feature_test_macro_components.py |  3 +-
 21 files changed, 149 insertions(+), 143 deletions(-)
 rename libcxx/include/__utility/{nontype.h => constant_arg.h} (63%)

diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 0f65770a4fa14..e3f9ccb3e7515 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -468,7 +468,7 @@ Status
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_fstream_native_handle``                        ``202306L``
     ---------------------------------------------------------- -----------------
-    ``__cpp_lib_function_ref``                                 *unimplemented*
+    ``__cpp_lib_function_ref``                                 ``202306L``
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_generate_random``                              *unimplemented*
     ---------------------------------------------------------- -----------------
diff --git a/libcxx/docs/ReleaseNotes/23.rst b/libcxx/docs/ReleaseNotes/23.rst
index bcf527869ac94..348764b084ad5 100644
--- a/libcxx/docs/ReleaseNotes/23.rst
+++ b/libcxx/docs/ReleaseNotes/23.rst
@@ -39,6 +39,8 @@ Implemented Papers
 ------------------
 
 - P2440R1: ``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right`` (`Github <https://llvm.org/PR105184>`__)
+- P0792R14: ``function_ref`` : a type-erased callable reference  (`Github <https://llvm.org/PR105376>`__) This feature is currently experimental and
+  therefore requires ``-fexperimental-library``.
 
 Improvements and New Features
 -----------------------------
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index 29642fc53cac6..6b135060c9d03 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -14,7 +14,7 @@
 "`P2363R5 <https://wg21.link/P2363R5>`__","Extending associative containers with the remaining heterogeneous overloads","2023-06 (Varna)","","","`#105371 <https://github.com/llvm/llvm-project/issues/105371>`__",""
 "`P1901R2 <https://wg21.link/P1901R2>`__","Enabling the Use of ``weak_ptr`` as Keys in Unordered Associative Containers","2023-06 (Varna)","","","`#105372 <https://github.com/llvm/llvm-project/issues/105372>`__",""
 "`P1885R12 <https://wg21.link/P1885R12>`__","Naming Text Encodings to Demystify Them","2023-06 (Varna)","","","`#105373 <https://github.com/llvm/llvm-project/issues/105373>`__",""
-"`P0792R14 <https://wg21.link/P0792R14>`__","``function_ref``: a type-erased callable reference","2023-06 (Varna)","","","`#105376 <https://github.com/llvm/llvm-project/issues/105376>`__",""
+"`P0792R14 <https://wg21.link/P0792R14>`__","``function_ref``: a type-erased callable reference","2023-06 (Varna)","|Complete|","23","`#105376 <https://github.com/llvm/llvm-project/issues/105376>`__",""
 "`P2874R2 <https://wg21.link/P2874R2>`__","P2874R2: Mandating Annex D Require No More","2023-06 (Varna)","|Complete|","12","`#105377 <https://github.com/llvm/llvm-project/issues/105377>`__",""
 "`P2757R3 <https://wg21.link/P2757R3>`__","Type-checking format args","2023-06 (Varna)","","","`#105378 <https://github.com/llvm/llvm-project/issues/105378>`__",""
 "`P2637R3 <https://wg21.link/P2637R3>`__","Member ``visit``","2023-06 (Varna)","|Complete|","19","`#105380 <https://github.com/llvm/llvm-project/issues/105380>`__","Change of ``__cpp_lib_variant`` is completed in LLVM 20. Change of ``__cpp_lib_format`` is blocked by `P2419R2 <https://wg21.link/P2419R2>`__."
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 90dc684944342..a2c69f1c77c2a 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -928,6 +928,7 @@ set(files
   __utility/as_lvalue.h
   __utility/auto_cast.h
   __utility/cmp.h
+  __utility/constant_arg.h
   __utility/convert_to_integral.h
   __utility/declval.h
   __utility/default_three_way_comparator.h
@@ -943,7 +944,6 @@ set(files
   __utility/lazy_synth_three_way_comparator.h
   __utility/move.h
   __utility/no_destroy.h
-  __utility/nontype.h
   __utility/pair.h
   __utility/piecewise_construct.h
   __utility/priority_tag.h
diff --git a/libcxx/include/__configuration/experimental.h b/libcxx/include/__configuration/experimental.h
index bb38d8297c63d..1e12c50802895 100644
--- a/libcxx/include/__configuration/experimental.h
+++ b/libcxx/include/__configuration/experimental.h
@@ -34,5 +34,6 @@
 #define _LIBCPP_HAS_EXPERIMENTAL_SYNCSTREAM _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
 #define _LIBCPP_HAS_EXPERIMENTAL_HARDENING_OBSERVE_SEMANTIC _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
 #define _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
+#define _LIBCPP_HAS_EXPERIMENTAL_FUNCTION_REF _LIBCPP_HAS_EXPERIMENTAL_LIBRARY
 
 #endif // _LIBCPP___CONFIGURATION_EXPERIMENTAL_H
diff --git a/libcxx/include/__functional/function_ref.h b/libcxx/include/__functional/function_ref.h
index 8fcebb8aa4825..fbfb0d8a8b3a8 100644
--- a/libcxx/include/__functional/function_ref.h
+++ b/libcxx/include/__functional/function_ref.h
@@ -16,6 +16,7 @@
 #  pragma GCC system_header
 #endif
 
+#if _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_FUNCTION_REF
 // NOLINTBEGIN(readability-duplicate-include)
 
 #define _LIBCPP_FUNCTION_REF_CV
@@ -43,5 +44,6 @@
 #undef _LIBCPP_FUNCTION_REF_NOEXCEPT
 
 // NOLINTEND(readability-duplicate-include)
+#endif // _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_FUNCTION_REF
 
 #endif // _LIBCPP___FUNCTIONAL_FUNCTION_REF_H
diff --git a/libcxx/include/__functional/function_ref_common.h b/libcxx/include/__functional/function_ref_common.h
index b2d1864e582c5..f1d1ee2279d9c 100644
--- a/libcxx/include/__functional/function_ref_common.h
+++ b/libcxx/include/__functional/function_ref_common.h
@@ -14,7 +14,7 @@
 #include <__type_traits/is_function.h>
 #include <__type_traits/is_object.h>
 #include <__type_traits/remove_pointer.h>
-#include <__utility/nontype.h>
+#include <__utility/constant_arg.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -22,7 +22,7 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-#if _LIBCPP_STD_VER >= 26
+#if _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_FUNCTION_REF
 
 template <class...>
 class function_ref;
@@ -38,22 +38,22 @@ struct __function_ref_bind {};
 
 template <class _Tp, class _Rp, class _Gp, class... _ArgTypes>
 struct __function_ref_bind<_Rp (*)(_Gp, _ArgTypes...), _Tp> {
-  using type = _Rp(_ArgTypes...);
+  using type _LIBCPP_NODEBUG = _Rp(_ArgTypes...);
 };
 
 template <class _Tp, class _Rp, class _Gp, class... _ArgTypes>
 struct __function_ref_bind<_Rp (*)(_Gp, _ArgTypes...) noexcept, _Tp> {
-  using type = _Rp(_ArgTypes...) noexcept;
+  using type _LIBCPP_NODEBUG = _Rp(_ArgTypes...) noexcept;
 };
 
 template <class _Tp, class _Mp, class _Gp>
   requires is_object_v<_Mp>
 struct __function_ref_bind<_Mp _Gp::*, _Tp> {
-  using type = invoke_result_t<_Mp _Gp::*, _Tp&>();
+  using type _LIBCPP_NODEBUG = invoke_result_t<_Mp _Gp::*, _Tp&>();
 };
 
 template <class _Fp, class _Tp>
-using __function_ref_bind_t = __function_ref_bind<_Fp, _Tp>::type;
+using __function_ref_bind_t _LIBCPP_NODEBUG = __function_ref_bind<_Fp, _Tp>::type;
 
 template <class _Fp>
   requires is_function_v<_Fp>
@@ -61,12 +61,12 @@ function_ref(_Fp*) -> function_ref<_Fp>;
 
 template <auto _Fn>
   requires is_function_v<remove_pointer_t<decltype(_Fn)>>
-function_ref(nontype_t<_Fn>) -> function_ref<remove_pointer_t<decltype(_Fn)>>;
+function_ref(constant_arg_t<_Fn>) -> function_ref<remove_pointer_t<decltype(_Fn)>>;
 
 template <auto _Fn, class _Tp>
-function_ref(nontype_t<_Fn>, _Tp&&) -> function_ref<__function_ref_bind_t<decltype(_Fn), _Tp&>>;
+function_ref(constant_arg_t<_Fn>, _Tp&&) -> function_ref<__function_ref_bind_t<decltype(_Fn), _Tp&>>;
 
-#endif // _LIBCPP_STD_VER >= 26
+#endif // _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_FUNCTION_REF
 
 _LIBCPP_END_NAMESPACE_STD
 
diff --git a/libcxx/include/__functional/function_ref_impl.h b/libcxx/include/__functional/function_ref_impl.h
index daae5c87d9470..4627fa6325305 100644
--- a/libcxx/include/__functional/function_ref_impl.h
+++ b/libcxx/include/__functional/function_ref_impl.h
@@ -21,8 +21,8 @@
 #include <__type_traits/remove_cvref.h>
 #include <__type_traits/remove_pointer.h>
 #include <__type_traits/remove_reference.h>
+#include <__utility/constant_arg.h>
 #include <__utility/forward.h>
-#include <__utility/nontype.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -30,7 +30,7 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-#if _LIBCPP_STD_VER >= 26
+#if _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_FUNCTION_REF
 
 template <class...>
 class function_ref;
@@ -84,7 +84,7 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU
     }
   }
 
-  using __call_t = _Rp (*)(__storage_t, _ArgTypes&&...) noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT);
+  using __call_t _LIBCPP_NODEBUG = _Rp (*)(__storage_t, _ArgTypes&&...) noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT);
   __call_t __call_;
 
 public:
@@ -110,7 +110,7 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU
 
   template <auto _Fn>
     requires __is_invocable_using<decltype(_Fn)>
-  _LIBCPP_HIDE_FROM_ABI constexpr function_ref(nontype_t<_Fn>) noexcept
+  _LIBCPP_HIDE_FROM_ABI constexpr function_ref(constant_arg_t<_Fn>) noexcept
       : __call_([](__storage_t, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp {
           return std::invoke_r<_Rp>(_Fn, std::forward<_ArgTypes>(__args)...);
         }) {
@@ -121,7 +121,7 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU
 
   template <auto _Fn, class _Up, class _Tp = remove_reference_t<_Up>>
     requires(!is_rvalue_reference_v<_Up &&>) && __is_invocable_using<decltype(_Fn), _LIBCPP_FUNCTION_REF_CV _Tp&>
-  _LIBCPP_HIDE_FROM_ABI constexpr function_ref(nontype_t<_Fn>, _Up&& __obj) noexcept
+  _LIBCPP_HIDE_FROM_ABI constexpr function_ref(constant_arg_t<_Fn>, _Up&& __obj) noexcept
       : __storage_(std::addressof(__obj)),
         __call_([](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp {
           _LIBCPP_FUNCTION_REF_CV _Tp& __obj = *__get<_Tp>(__storage);
@@ -134,7 +134,7 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU
 
   template <auto _Fn, class _Tp>
     requires __is_invocable_using<decltype(_Fn), _LIBCPP_FUNCTION_REF_CV _Tp*>
-  _LIBCPP_HIDE_FROM_ABI constexpr function_ref(nontype_t<_Fn>, _LIBCPP_FUNCTION_REF_CV _Tp* __obj_ptr) noexcept
+  _LIBCPP_HIDE_FROM_ABI constexpr function_ref(constant_arg_t<_Fn>, _LIBCPP_FUNCTION_REF_CV _Tp* __obj_ptr) noexcept
       : __storage_(__obj_ptr),
         __call_([](__storage_t __storage, _ArgTypes&&... __args) static noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) -> _Rp {
           auto __obj = __get<_LIBCPP_FUNCTION_REF_CV _Tp>(__storage);
@@ -154,7 +154,7 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU
   _LIBCPP_HIDE_FROM_ABI constexpr function_ref& operator=(const function_ref&) noexcept = default;
 
   template <class _Tp>
-    requires(!__is_function_ref<_Tp>) && (!is_pointer_v<_Tp>) && (!__is_nontype_t<_Tp>)
+    requires(!__is_function_ref<_Tp>) && (!is_pointer_v<_Tp>) && (!__is_constant_arg_t<_Tp>)
   _LIBCPP_HIDE_FROM_ABI function_ref& operator=(_Tp) = delete;
 
   _LIBCPP_HIDE_FROM_ABI constexpr _Rp operator()(_ArgTypes... __args) const noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT) {
@@ -165,15 +165,15 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FU
 template <class _Tp, class _Rp, class _Gp, class... _ArgTypes>
 struct __function_ref_bind<_Rp (_Gp::*)(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT),
                            _Tp> {
-  using type = _Rp(_ArgTypes...) noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT);
+  using type _LIBCPP_NODEBUG = _Rp(_ArgTypes...) noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT);
 };
 
 template <class _Tp, class _Rp, class _Gp, class... _ArgTypes>
 struct __function_ref_bind<_Rp (_Gp::*)(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV & noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT),
                            _Tp> {
-  using type = _Rp(_ArgTypes...) noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT);
+  using type _LIBCPP_NODEBUG = _Rp(_ArgTypes...) noexcept(_LIBCPP_FUNCTION_REF_NOEXCEPT);
 };
 
-#endif // _LIBCPP_STD_VER >= 26
+#endif // _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_FUNCTION_REF
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__utility/nontype.h b/libcxx/include/__utility/constant_arg.h
similarity index 63%
rename from libcxx/include/__utility/nontype.h
rename to libcxx/include/__utility/constant_arg.h
index 3a10840154009..f299ec509ed5c 100644
--- a/libcxx/include/__utility/nontype.h
+++ b/libcxx/include/__utility/constant_arg.h
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef _LIBCPP___UTILITY_NONTYPE_H
-#define _LIBCPP___UTILITY_NONTYPE_H
+#ifndef _LIBCPP___UTILITY_CONSTANT_ARG_H
+#define _LIBCPP___UTILITY_CONSTANT_ARG_H
 
 #include <__config>
 
@@ -20,20 +20,20 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 #if _LIBCPP_STD_VER >= 26
 
 template <auto _Vp>
-struct nontype_t {
-  _LIBCPP_HIDE_FROM_ABI explicit nontype_t() = default;
+struct constant_arg_t {
+  _LIBCPP_HIDE_FROM_ABI explicit constant_arg_t() = default;
 };
 
 template <auto _Vp>
-inline constexpr nontype_t<_Vp> nontype{};
+inline constexpr constant_arg_t<_Vp> constant_arg{};
 
 template <class>
-inline constexpr bool __is_nontype_t = false;
+inline constexpr bool __is_constant_arg_t = false;
 template <auto _Vp>
-inline constexpr bool __is_nontype_t<nontype_t<_Vp>> = true;
+inline constexpr bool __is_constant_arg_t<constant_arg_t<_Vp>> = true;
 
 #endif // _LIBCPP_STD_VER >= 26
 
 _LIBCPP_END_NAMESPACE_STD
 
-#endif // _LIBCPP___UTILITY_NONTYPE_H
+#endif // _LIBCPP___UTILITY_CONSTANT_ARG_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 183383e893f24..17ae13e91da81 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -2174,6 +2174,7 @@ module std [system] {
       export std_core.type_traits.decay // the macro expansion uses that trait
     }
     module cmp                             { header "__utility/cmp.h" }
+    module constant_arg                    { header "__utility/constant_arg.h" }
     module convert_to_integral             { header "__utility/convert_to_integral.h" }
     module default_three_way_comparator    { header "__utility/default_three_way_comparator.h" }
     module element_count                   { header "__utility/element_count.h" }
@@ -2189,7 +2190,6 @@ module std [system] {
     module lazy_synth_three_way_comparator { header "__utility/lazy_synth_three_way_comparator.h" }
     module move                            { header "__utility/move.h" }
     module no_destroy                      { header "__utility/no_destroy.h" }
-    module nontype                         { header "__utility/nontype.h" }
     module pair                            {
       header "__utility/pair.h"
       export std.utility.piecewise_construct
diff --git a/libcxx/include/utility b/libcxx/include/utility
index f6cffd3898c21..fbed5ec799972 100644
--- a/libcxx/include/utility
+++ b/libcxx/include/utility
@@ -250,14 +250,12 @@ template <size_t I>
 template <size_t I>
   inline constexpr in_place_index_t<I> in_place_index{};
 
-// nontype argument tag
+// constant_arg argument tag
 template<auto V>
-  struct nontype_t {
-    explicit nontype_t() = default;
+  struct constant_arg_t {
+    explicit constant_arg_t() = default;
   };
-template<auto V> constexpr nontype_t<V> nontype{};
-
-template<auto V> constexpr nontype_t<V> nontype{};
+template<auto V> constexpr constant_arg_t<V> constant_arg_t{};
 
 // [utility.underlying], to_underlying
 template <class T>
@@ -301,7 +299,7 @@ template <class T>
 #  endif
 
 #  if _LIBCPP_STD_VER >= 26
-#    include <__utility/nontype.h>
+#    include <__utility/constant_arg.h>
 #    include <__variant/monostate.h>
 #  endif
 
diff --git a/libcxx/include/version b/libcxx/include/version
index 562538c5393cc..e0c358edd8940 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -581,7 +581,9 @@ __cpp_lib_void_t                                        201411L <type_traits>
 # if _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION
 #   define __cpp_lib_fstream_native_handle              202306L
 # endif
-// # define __cpp_lib_function_ref                         202306L
+# if _LIBCPP_HAS_EXPERIMENTAL_FUNCTION_REF
+#   define __cpp_lib_function_ref                       202306L
+# endif
 // # define __cpp_lib_generate_random                      202403L
 // # define __cpp_lib_hazard_pointer                       202306L
 // # define __cpp_lib_inplace_vector                       202406L
diff --git a/libcxx/modules/std/utility.inc b/libcxx/modules/std/utility.inc
index 28f8e36e30af9..aacab46e6df02 100644
--- a/libcxx/modules/std/utility.inc
+++ b/libcxx/modules/std/utility.inc
@@ -90,8 +90,8 @@ export namespace std {
   using std::in_place_index_t;
 
 #if _LIBCPP_STD_VER >= 26
-  using std::nontype;
-  using std::nontype_t;
+  using std::constant_arg;
+  using std::constant_arg_t;
 #endif // _LIBCPP_STD_VER >= 23
 
   // [depr.relops]
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp
index b7b7d0334830a..eaab9bdd80ad8 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp
@@ -494,7 +494,7 @@
 #    endif
 #  endif
 
-#  if !defined(_LIBCPP_VERSION)
+#  if !defined(_LIBCPP_VERSION) || _LIBCPP_HAS_EXPERIMENTAL_FUNCTION_REF
 #    ifndef __cpp_lib_function_ref
 #      error "__cpp_lib_function_ref should be defined in c++26"
 #    endif
@@ -503,7 +503,7 @@
 #    endif
 #  else
 #    ifdef __cpp_lib_function_ref
-#      error "__cpp_lib_function_ref should not be defined because it is unimplemented in libc++!"
+#      error "__cpp_lib_function_ref should not be defined when the requirement '!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_EXPERIMENTAL_FUNCTION_REF' is not met!"
 #    endif
 #  endif
 
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index e74c2b58717a9..e3866130f9981 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -7008,7 +7008,7 @@
 #    endif
 #  endif
 
-#  if !defined(_LIBCPP_VERSION)
+#  if !defined(_LIBCPP_VERSION) || _LIBCPP_HAS_EXPERIMENTAL_FUNCTION_REF
 #    ifndef __cpp_lib_function_ref
 #      error "__cpp_lib_function_ref should be defined in c++26"
 #    endif
@@ -7017,7 +7017,7 @@
 #    endif
 #  else
 #    ifdef __cpp_lib_function_ref
-#      error "__cpp_lib_function_ref should not be defined because it is unimplemented in libc++!"
+#      error "__cpp_lib_function_ref should not be defined when the requirement '!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_EXPERIMENTAL_FUNCTION_REF' is not met!"
 #    endif
 #  endif
 
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/ctor/ctad.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/ctor/ctad.pass.cpp
index c7490fc0982e3..9ef7bd66a8953 100644
--- a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/ctor/ctad.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/ctor/ctad.pass.cpp
@@ -39,41 +39,41 @@ void test() {
   }
 
   // template<auto f>
-  //  function_ref(nontype_t<f>) -> function_ref<...>;
+  //  function_ref(constant_arg_t<f>) -> function_ref<...>;
   {
-    std::function_ref fn_ref = std::nontype_t<fn>();
+    std::function_ref fn_ref = std::constant_arg_t<fn>();
     static_assert(std::is_same_v<decltype(fn_ref), std::function_ref<int(int, float)>>);
   }
   {
-    std::function_ref fn_ref = std::nontype_t<fn_noexcept>();
+    std::function_ref fn_ref = std::constant_arg_t<fn_noexcept>();
     static_assert(std::is_same_v<decltype(fn_ref), std::function_ref<int(int, float) noexcept>>);
   }
 
   // template<auto f, class T>
-  //  function_ref(nontype_t<f>, T&&) -> function_ref<...>;
+  //  function_ref(constant_arg_t<f>, T&&) -> function_ref<...>;
   {
     int arg                  = 0;
-    std::function_ref fn_ref = {std::nontype_t<fn>(), arg};
+    std::function_ref fn_ref = {std::constant_arg_t<fn>(), arg};
     static_assert(std::is_same_v<decltype(fn_ref), std::function_ref<int(float)>>);
   }
   {
     S s;
-    std::function_ref fn_ref = {std::nontype_t<&S::data_mem>(), s};
+    std::function_ref fn_ref = {std::constant_arg_t<&S::data_mem>(), s};
     static_assert(std::is_same_v<decltype(fn_ref), std::function_ref<int&()>>);
   }
   {
     const S s;
-    std::function_ref fn_ref = {std::nontype_t<&S::data_mem>(), s};
+    std::function_ref fn_ref = {std::constant_arg_t<&S::data_mem>(), s};
     static_assert(std::is_same_v<decltype(fn_ref), std::function_ref<int const&()>>);
   }
   {
     S s;
-    std::function_ref fn_ref = {std::nontype_t<&S::fn_mem>(), s};
+    std::function_ref fn_ref = {std::constant_arg_t<&S::fn_mem>(), s};
     static_assert(std::is_same_v<decltype(fn_ref), std::function_ref<int(int, float)>>);
   }
   {
     S s;
-    std::function_ref fn_ref = {std::nontype_t<&S::fn_mem_noexcept>(), s};
+    std::function_ref fn_ref = {std::constant_arg_t<&S::fn_mem_noexcept>(), s};
     static_assert(std::is_same_v<decltype(fn_ref), std::function_ref<int(int, float) noexcept>>);
   }
 }
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/const.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/const.pass.cpp
index 53d7a5922353d..26a32e91adfd7 100644
--- a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/const.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/const.pass.cpp
@@ -55,70 +55,70 @@ struct S {
   int fn_mem() const { return 42; }
 };
 
-void test_nontype_t() {
-  // template<auto f> constexpr function_ref(nontype_t<f>) noexcept;
+void test_constant_arg_t() {
+  // template<auto f> constexpr function_ref(constant_arg_t<f>) noexcept;
   {
-    // initialized from a function through `nontype_t`
-    std::function_ref<int() const> fn_ref = std::nontype_t<fn>();
+    // initialized from a function through `constant_arg_t`
+    std::function_ref<int() const> fn_ref = std::constant_arg_t<fn>();
     assert(fn_ref() == 42);
   }
   {
-    // initialized from a function pointer through `nontype_t`
-    std::function_ref<int() const> fn_ref = std::nontype_t<&fn>();
+    // initialized from a function pointer through `constant_arg_t`
+    std::function_ref<int() const> fn_ref = std::constant_arg_t<&fn>();
     assert(fn_ref() == 42);
   }
   {
-    // initialized from a function object through `nontype_t`
-    std::function_ref<int() const> fn_ref = std::nontype_t<fn_obj>();
+    // initialized from a function object through `constant_arg_t`
+    std::function_ref<int() const> fn_ref = std::constant_arg_t<fn_obj>();
     assert(fn_ref() == 42);
   }
   {
     S s;
-    // initialized from a pointer to data member through `nontype_t`
-    std::function_ref<int(S) const> fn_ref = std::nontype_t<&S::data_mem>();
+    // initialized from a pointer to data member through `constant_arg_t`
+    std::function_ref<int(S) const> fn_ref = std::constant_arg_t<&S::data_mem>();
     assert(fn_ref(s) == 42);
   }
   {
     S s;
-    // initialized from a pointer to function member through `nontype_t`
-    std::function_ref<int(S) const> fn_ref = std::nontype_t<&S::fn_mem>();
+    // initialized from a pointer to function member through `constant_arg_t`
+    std::function_ref<int(S) const> fn_ref = std::constant_arg_t<&S::fn_mem>();
     assert(fn_ref(s) == 42);
   }
 
   // template<auto f, class U>
-  //   constexpr function_ref(nontype_t<f>, U&& obj) noexcept;
+  //   constexpr function_ref(constant_arg_t<f>, U&& obj) noexcept;
   {
     S s;
-    // initialized from a pointer to data member through `nontype_t` and bound to an object through a reference
-    std::function_ref<int() const> fn_ref = {std::nontype_t<&S::data_mem>(), s};
+    // initialized from a pointer to data member through `constant_arg_t` and bound to an object through a reference
+    std::function_ref<int() const> fn_ref = {std::constant_arg_t<&S::data_mem>(), s};
     assert(fn_ref() == 42);
   }
   {
     S s;
-    // initialized from a pointer to function member through `nontype_t` and bound to an object through a reference
-    std::function_ref<int() const> fn_ref = {std::nontype_t<&S::fn_mem>(), s};
+    // initialized from a pointer to function member through `constant_arg_t` and bound to an object through a reference
+    std::function_ref<int() const> fn_ref = {std::constant_arg_t<&S::fn_mem>(), s};
     assert(fn_ref() == 42);
   }
 
   // template<auto f, class T>
-  //   constexpr function_ref(nontype_t<f>, cv T* obj) noexcept;
+  //   constexpr function_ref(constant_arg_t<f>, cv T* obj) noexcept;
   {
     S s;
-    // initialized from a pointer to data member through `nontype_t` and bound to an object through a pointer
-    std::function_ref<int() const> fn_ref = {std::nontype_t<&S::data_mem>(), &s};
+    // initialized from a pointer to data member through `constant_arg_t` and bound to an object through a pointer
+    std::function_ref<int() const> fn_ref = {std::constant_arg_t<&S::data_mem>(), &s};
     assert(fn_ref() == 42);
   }
   {
     S s;
-    // initialized from a pointer to function member through `nontype_t` and bound to an object through a pointer
+    // initialized from a pointer to function member through `constant_arg_t` and bound to an object through a pointer
     static_assert(std::is_same_v<decltype(&s), S*>);
-    std::function_ref<int() const> fn_ref = {std::nontype_t<&S::fn_mem>(), &s};
+    std::function_ref<int() const> fn_ref = {std::constant_arg_t<&S::fn_mem>(), &s};
     assert(fn_ref() == 42);
   }
 }
 
 int main(int, char**) {
   test();
-  test_nontype_t();
+  test_constant_arg_t();
   return 0;
 }
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/const_noexcept.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/const_noexcept.pass.cpp
index 18d44e4b7ef0b..26ace9c496b88 100644
--- a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/const_noexcept.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/const_noexcept.pass.cpp
@@ -55,70 +55,70 @@ struct S {
   int fn_mem() const noexcept { return 42; }
 };
 
-void test_nontype_t() {
-  // template<auto f> const noexceptexpr function_ref(nontype_t<f>) noexcept;
+void test_constant_arg_t() {
+  // template<auto f> const noexceptexpr function_ref(constant_arg_t<f>) noexcept;
   {
-    // initialized from a function through `nontype_t`
-    std::function_ref<int() const noexcept> fn_ref = std::nontype_t<fn>();
+    // initialized from a function through `constant_arg_t`
+    std::function_ref<int() const noexcept> fn_ref = std::constant_arg_t<fn>();
     assert(fn_ref() == 42);
   }
   {
-    // initialized from a function pointer through `nontype_t`
-    std::function_ref<int() const noexcept> fn_ref = std::nontype_t<&fn>();
+    // initialized from a function pointer through `constant_arg_t`
+    std::function_ref<int() const noexcept> fn_ref = std::constant_arg_t<&fn>();
     assert(fn_ref() == 42);
   }
   {
-    // initialized from a function object through `nontype_t`
-    std::function_ref<int() const noexcept> fn_ref = std::nontype_t<fn_obj>();
+    // initialized from a function object through `constant_arg_t`
+    std::function_ref<int() const noexcept> fn_ref = std::constant_arg_t<fn_obj>();
     assert(fn_ref() == 42);
   }
   {
     S s;
-    // initialized from a pointer to data member through `nontype_t`
-    std::function_ref<int(S) const noexcept> fn_ref = std::nontype_t<&S::data_mem>();
+    // initialized from a pointer to data member through `constant_arg_t`
+    std::function_ref<int(S) const noexcept> fn_ref = std::constant_arg_t<&S::data_mem>();
     assert(fn_ref(s) == 42);
   }
   {
     S s;
-    // initialized from a pointer to function member through `nontype_t`
-    std::function_ref<int(S) const noexcept> fn_ref = std::nontype_t<&S::fn_mem>();
+    // initialized from a pointer to function member through `constant_arg_t`
+    std::function_ref<int(S) const noexcept> fn_ref = std::constant_arg_t<&S::fn_mem>();
     assert(fn_ref(s) == 42);
   }
 
   // template<auto f, class U>
-  //   const noexceptexpr function_ref(nontype_t<f>, U&& obj) noexcept;
+  //   const noexceptexpr function_ref(constant_arg_t<f>, U&& obj) noexcept;
   {
     S s;
-    // initialized from a pointer to data member through `nontype_t` and bound to an object through a reference
-    std::function_ref<int() const noexcept> fn_ref = {std::nontype_t<&S::data_mem>(), s};
+    // initialized from a pointer to data member through `constant_arg_t` and bound to an object through a reference
+    std::function_ref<int() const noexcept> fn_ref = {std::constant_arg_t<&S::data_mem>(), s};
     assert(fn_ref() == 42);
   }
   {
     S s;
-    // initialized from a pointer to function member through `nontype_t` and bound to an object through a reference
-    std::function_ref<int() const noexcept> fn_ref = {std::nontype_t<&S::fn_mem>(), s};
+    // initialized from a pointer to function member through `constant_arg_t` and bound to an object through a reference
+    std::function_ref<int() const noexcept> fn_ref = {std::constant_arg_t<&S::fn_mem>(), s};
     assert(fn_ref() == 42);
   }
 
   // template<auto f, class T>
-  //   const noexceptexpr function_ref(nontype_t<f>, cv T* obj) noexcept;
+  //   const noexceptexpr function_ref(constant_arg_t<f>, cv T* obj) noexcept;
   {
     S s;
-    // initialized from a pointer to data member through `nontype_t` and bound to an object through a pointer
-    std::function_ref<int() const noexcept> fn_ref = {std::nontype_t<&S::data_mem>(), &s};
+    // initialized from a pointer to data member through `constant_arg_t` and bound to an object through a pointer
+    std::function_ref<int() const noexcept> fn_ref = {std::constant_arg_t<&S::data_mem>(), &s};
     assert(fn_ref() == 42);
   }
   {
     S s;
-    // initialized from a pointer to function member through `nontype_t` and bound to an object through a pointer
+    // initialized from a pointer to function member through `constant_arg_t` and bound to an object through a pointer
     static_assert(std::is_same_v<decltype(&s), S*>);
-    std::function_ref<int() const noexcept> fn_ref = {std::nontype_t<&S::fn_mem>(), &s};
+    std::function_ref<int() const noexcept> fn_ref = {std::constant_arg_t<&S::fn_mem>(), &s};
     assert(fn_ref() == 42);
   }
 }
 
 int main(int, char**) {
   test();
-  test_nontype_t();
+  test_constant_arg_t();
   return 0;
 }
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/default.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/default.pass.cpp
index ebc07a6c3520c..ce9d7f8d73716 100644
--- a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/default.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/default.pass.cpp
@@ -55,65 +55,65 @@ struct S {
   int fn_mem() { return 42; }
 };
 
-void test_nontype_t() {
-  // template<auto f> constexpr function_ref(nontype_t<f>) noexcept;
+void test_constant_arg_t() {
+  // template<auto f> constexpr function_ref(constant_arg_t<f>) noexcept;
   {
-    // initialized from a function through `nontype_t`
-    std::function_ref<int()> fn_ref = std::nontype_t<fn>();
+    // initialized from a function through `constant_arg_t`
+    std::function_ref<int()> fn_ref = std::constant_arg_t<fn>();
     assert(fn_ref() == 42);
   }
   {
-    // initialized from a function pointer through `nontype_t`
-    std::function_ref<int()> fn_ref = std::nontype_t<&fn>();
+    // initialized from a function pointer through `constant_arg_t`
+    std::function_ref<int()> fn_ref = std::constant_arg_t<&fn>();
     assert(fn_ref() == 42);
   }
   {
     S s;
-    // initialized from a pointer to data member through `nontype_t`
-    std::function_ref<int(S)> fn_ref = std::nontype_t<&S::data_mem>();
+    // initialized from a pointer to data member through `constant_arg_t`
+    std::function_ref<int(S)> fn_ref = std::constant_arg_t<&S::data_mem>();
     assert(fn_ref(s) == 42);
   }
   {
     S s;
-    // initialized from a pointer to function member through `nontype_t`
-    std::function_ref<int(S)> fn_ref = std::nontype_t<&S::fn_mem>();
+    // initialized from a pointer to function member through `constant_arg_t`
+    std::function_ref<int(S)> fn_ref = std::constant_arg_t<&S::fn_mem>();
     assert(fn_ref(s) == 42);
   }
 
   // template<auto f, class U>
-  //   constexpr function_ref(nontype_t<f>, U&& obj) noexcept;
+  //   constexpr function_ref(constant_arg_t<f>, U&& obj) noexcept;
   {
     S s;
-    // initialized from a pointer to data member through `nontype_t` and bound to an object through a reference
-    std::function_ref<int()> fn_ref = {std::nontype_t<&S::data_mem>(), s};
+    // initialized from a pointer to data member through `constant_arg_t` and bound to an object through a reference
+    std::function_ref<int()> fn_ref = {std::constant_arg_t<&S::data_mem>(), s};
     assert(fn_ref() == 42);
   }
   {
     S s;
-    // initialized from a pointer to function member through `nontype_t` and bound to an object through a reference
-    std::function_ref<int()> fn_ref = {std::nontype_t<&S::fn_mem>(), s};
+    // initialized from a pointer to function member through `constant_arg_t` and bound to an object through a reference
+    std::function_ref<int()> fn_ref = {std::constant_arg_t<&S::fn_mem>(), s};
     assert(fn_ref() == 42);
   }
 
   // template<auto f, class T>
-  //   constexpr function_ref(nontype_t<f>, cv T* obj) noexcept;
+  //   constexpr function_ref(constant_arg_t<f>, cv T* obj) noexcept;
   {
     S s;
-    // initialized from a pointer to data member through `nontype_t` and bound to an object through a pointer
-    std::function_ref<int()> fn_ref = {std::nontype_t<&S::data_mem>(), &s};
+    // initialized from a pointer to data member through `constant_arg_t` and bound to an object through a pointer
+    std::function_ref<int()> fn_ref = {std::constant_arg_t<&S::data_mem>(), &s};
     assert(fn_ref() == 42);
   }
   {
     S s;
-    // initialized from a pointer to function member through `nontype_t` and bound to an object through a pointer
+    // initialized from a pointer to function member through `constant_arg_t` and bound to an object through a pointer
     static_assert(std::is_same_v<decltype(&s), S*>);
-    std::function_ref<int()> fn_ref = {std::nontype_t<&S::fn_mem>(), &s};
+    std::function_ref<int()> fn_ref = {std::constant_arg_t<&S::fn_mem>(), &s};
     assert(fn_ref() == 42);
   }
 }
 
 int main(int, char**) {
   test();
-  test_nontype_t();
+  test_constant_arg_t();
   return 0;
 }
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/noexcept.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/noexcept.pass.cpp
index 9b58e677ed6ba..7c947143ec0bd 100644
--- a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/noexcept.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/invoke/noexcept.pass.cpp
@@ -55,65 +55,65 @@ struct S {
   int fn_mem() noexcept { return 42; }
 };
 
-void test_nontype_t() {
-  // template<auto f> constexpr function_ref(nontype_t<f>) noexcept;
+void test_constant_arg_t() {
+  // template<auto f> constexpr function_ref(constant_arg_t<f>) noexcept;
   {
-    // initialized from a function through `nontype_t`
-    std::function_ref<int() noexcept> fn_ref = std::nontype_t<fn>();
+    // initialized from a function through `constant_arg_t`
+    std::function_ref<int() noexcept> fn_ref = std::constant_arg_t<fn>();
     assert(fn_ref() == 42);
   }
   {
-    // initialized from a function pointer through `nontype_t`
-    std::function_ref<int() noexcept> fn_ref = std::nontype_t<&fn>();
+    // initialized from a function pointer through `constant_arg_t`
+    std::function_ref<int() noexcept> fn_ref = std::constant_arg_t<&fn>();
     assert(fn_ref() == 42);
   }
   {
     S s;
-    // initialized from a pointer to data member through `nontype_t`
-    std::function_ref<int(S) noexcept> fn_ref = std::nontype_t<&S::data_mem>();
+    // initialized from a pointer to data member through `constant_arg_t`
+    std::function_ref<int(S) noexcept> fn_ref = std::constant_arg_t<&S::data_mem>();
     assert(fn_ref(s) == 42);
   }
   {
     S s;
-    // initialized from a pointer to function member through `nontype_t`
-    std::function_ref<int(S) noexcept> fn_ref = std::nontype_t<&S::fn_mem>();
+    // initialized from a pointer to function member through `constant_arg_t`
+    std::function_ref<int(S) noexcept> fn_ref = std::constant_arg_t<&S::fn_mem>();
     assert(fn_ref(s) == 42);
   }
 
   // template<auto f, class U>
-  //   constexpr function_ref(nontype_t<f>, U&& obj) noexcept;
+  //   constexpr function_ref(constant_arg_t<f>, U&& obj) noexcept;
   {
     S s;
-    // initialized from a pointer to data member through `nontype_t` and bound to an object through a reference
-    std::function_ref<int() noexcept> fn_ref = {std::nontype_t<&S::data_mem>(), s};
+    // initialized from a pointer to data member through `constant_arg_t` and bound to an object through a reference
+    std::function_ref<int() noexcept> fn_ref = {std::constant_arg_t<&S::data_mem>(), s};
     assert(fn_ref() == 42);
   }
   {
     S s;
-    // initialized from a pointer to function member through `nontype_t` and bound to an object through a reference
-    std::function_ref<int() noexcept> fn_ref = {std::nontype_t<&S::fn_mem>(), s};
+    // initialized from a pointer to function member through `constant_arg_t` and bound to an object through a reference
+    std::function_ref<int() noexcept> fn_ref = {std::constant_arg_t<&S::fn_mem>(), s};
     assert(fn_ref() == 42);
   }
 
   // template<auto f, class T>
-  //   constexpr function_ref(nontype_t<f>, cv T* obj) noexcept;
+  //   constexpr function_ref(constant_arg_t<f>, cv T* obj) noexcept;
   {
     S s;
-    // initialized from a pointer to data member through `nontype_t` and bound to an object through a pointer
-    std::function_ref<int() noexcept> fn_ref = {std::nontype_t<&S::data_mem>(), &s};
+    // initialized from a pointer to data member through `constant_arg_t` and bound to an object through a pointer
+    std::function_ref<int() noexcept> fn_ref = {std::constant_arg_t<&S::data_mem>(), &s};
     assert(fn_ref() == 42);
   }
   {
     S s;
-    // initialized from a pointer to function member through `nontype_t` and bound to an object through a pointer
+    // initialized from a pointer to function member through `constant_arg_t` and bound to an object through a pointer
     static_assert(std::is_same_v<decltype(&s), S*>);
-    std::function_ref<int() noexcept> fn_ref = {std::nontype_t<&S::fn_mem>(), &s};
+    std::function_ref<int() noexcept> fn_ref = {std::constant_arg_t<&S::fn_mem>(), &s};
     assert(fn_ref() == 42);
   }
 }
 
 int main(int, char**) {
   test();
-  test_nontype_t();
+  test_constant_arg_t();
   return 0;
 }
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 9d2e095ab9ff7..f1e7a92d0d44c 100644
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -693,7 +693,8 @@ def add_version_header(tc):
                 "c++26": 202306  # P0792R14 function_ref: a type-erased callable reference
             },
             "headers": ["functional"],
-            "unimplemented": True,
+            "test_suite_guard": "!defined(_LIBCPP_VERSION) || _LIBCPP_HAS_EXPERIMENTAL_FUNCTION_REF",
+            "libcxx_guard": "_LIBCPP_HAS_EXPERIMENTAL_FUNCTION_REF"
         },
         {
             "name": "__cpp_lib_gcd_lcm",



More information about the libcxx-commits mailing list