Changes in v8:
 * Adjust template indentation to match rest of file
 * Change std Mandates conditions from "requires" to static_asserts.
 * Make _Bind_fn_t definition conditional on C++26, for static op().
 * Add negative tests for rejecting null function pointers, and for
  rejecting uncopyable / unmovable bound arguments.

Changes in v7:
 * Clean up comments, inactive cases in tests.
 * Add more tests for type handling.
 * Add test verifying arguments are moved into the capture object.

Changes in v6:
 * Remove deletion of op= for _Bind_fn_t.
 * Note no need for change to exports in summary.
 * Change "noexcept(noexcept(...))" to noexcept(is_noexcept_invocable<>)
 * Change "requires requires {...}" to "require is_invocable_v<>"
 * Adjust more whitespace.
 * Add more tests.

Changes in v5:
 * Switch back to decltype(auto) returns
 * Adjust tests to verify that calls treat <f> and all bound args
  as const.
 * Use "&&", "||" and "!" in preference to "and", "or" and "not"
  in deference to users "--no-operator-names".
 * Conform to conditional block format conventions, remove
  redundant () on noexcept predicates.
 * Return a static lambda in not_fn<f>()

Changes in v4:
 * For the no-bound-arguments case, bind_front and bind_back both
  return a zero-size _BindFn_t with static operator().
 * For the normal case, the lambda functions returned are declared
  to yield std::invoke_result_t<> instead of decltype(auto), which
  produces different test outcomes.

Changes in v3:
 * NTTP functions bind_front, bind_back are self-contained.
 * No tuples: bind_front and bind_back return a simple lambda.
 * bind_front, _back with no arguments simply return the template
  parameter function.
 * Forwarded-argument passing is disciplined.
 * NTTP not_fn uses a helper struct with static op().
 * Many more of tests that pass non-NTTP versions also pass

Add non-type template parameter function-object/-pointer argument
versions of bind_front, bind_back, and not_fn.

There is no need to change libstdc++-v3/src/c++23/std.cc.in
because existing exports: "using std::bind_front;" etc. export
the new overloads.

libstdc++-v3/ChangeLog:
        PR libstdc++/119744
        * include/bits/version.def: Redefine __cpp_lib_bind_front etc.
        * include/bits/version.h: Ditto.
        * include/std/functional: Add new bind_front etc. overloads
        * testsuite/20_util/function_objects/bind_back/1.cc:
        Check plumbing better
        * testsuite/20_util/function_objects/bind_back/nttp.cc: New test.
        * testsuite/20_util/function_objects/bind_back/nttp_neg.cc: New test.
        * testsuite/20_util/function_objects/bind_front/1.cc:
        Check plumbing better
        * testsuite/20_util/function_objects/bind_front/nttp.cc: New test.
        * testsuite/20_util/function_objects/bind_front/nttp_neg.cc: New test.
        * testsuite/20_util/function_objects/not_fn/nttp.cc: New test.
        * testsuite/20_util/function_objects/not_fn/nttp_neg.cc: New test.
        * testsuite/20_util/headers/functional/synopsis.cc: New decls.
---
 libstdc++-v3/include/bits/version.def         |  12 +
 libstdc++-v3/include/bits/version.h           |  21 +-
 libstdc++-v3/include/std/functional           | 144 +++++++++-
 .../20_util/function_objects/bind_back/1.cc   |  16 +-
 .../function_objects/bind_back/nttp.cc        | 258 +++++++++++++++++
 .../function_objects/bind_back/nttp_neg.cc    |  38 +++
 .../20_util/function_objects/bind_front/1.cc  |  16 +-
 .../function_objects/bind_front/nttp.cc       | 260 ++++++++++++++++++
 .../function_objects/bind_front/nttp_neg.cc   |  38 +++
 .../20_util/function_objects/not_fn/nttp.cc   |  98 +++++++
 .../function_objects/not_fn/nttp_neg.cc       |  28 ++
 .../20_util/headers/functional/synopsis.cc    |  21 ++
 12 files changed, 928 insertions(+), 22 deletions(-)
 create mode 100644 
libstdc++-v3/testsuite/20_util/function_objects/bind_back/nttp.cc
 create mode 100644 
libstdc++-v3/testsuite/20_util/function_objects/bind_back/nttp_neg.cc
 create mode 100644 
libstdc++-v3/testsuite/20_util/function_objects/bind_front/nttp.cc
 create mode 100644 
libstdc++-v3/testsuite/20_util/function_objects/bind_front/nttp_neg.cc
 create mode 100644 
libstdc++-v3/testsuite/20_util/function_objects/not_fn/nttp.cc
 create mode 100644 
libstdc++-v3/testsuite/20_util/function_objects/not_fn/nttp_neg.cc

diff --git a/libstdc++-v3/include/bits/version.def 
b/libstdc++-v3/include/bits/version.def
index dbe2cb8f175..81b6ec20ee5 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -463,6 +463,10 @@ ftms = {
 
 ftms = {
   name = not_fn;
+  values = {
+    v = 202306;
+    cxxmin = 26;
+  };
   values = {
     v = 201603;
     cxxmin = 17;
@@ -776,6 +780,10 @@ ftms = {
 
 ftms = {
   name = bind_front;
+  values = {
+    v = 202306;
+    cxxmin = 26;
+  };
   values = {
     v = 201907;
     cxxmin = 20;
@@ -784,6 +792,10 @@ ftms = {
 
 ftms = {
   name = bind_back;
+  values = {
+    v = 202306;
+    cxxmin = 26;
+  };
   values = {
     v = 202202;
     cxxmin = 23;
diff --git a/libstdc++-v3/include/bits/version.h 
b/libstdc++-v3/include/bits/version.h
index 7bb6016df68..1160ea0a00a 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -511,7 +511,12 @@
 #undef __glibcxx_want_make_from_tuple
 
 #if !defined(__cpp_lib_not_fn)
-# if (__cplusplus >= 201703L)
+# if (__cplusplus >  202302L)
+#  define __glibcxx_not_fn 202306L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_not_fn)
+#   define __cpp_lib_not_fn 202306L
+#  endif
+# elif (__cplusplus >= 201703L)
 #  define __glibcxx_not_fn 201603L
 #  if defined(__glibcxx_want_all) || defined(__glibcxx_want_not_fn)
 #   define __cpp_lib_not_fn 201603L
@@ -866,7 +871,12 @@
 #undef __glibcxx_want_atomic_value_initialization
 
 #if !defined(__cpp_lib_bind_front)
-# if (__cplusplus >= 202002L)
+# if (__cplusplus >  202302L)
+#  define __glibcxx_bind_front 202306L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_bind_front)
+#   define __cpp_lib_bind_front 202306L
+#  endif
+# elif (__cplusplus >= 202002L)
 #  define __glibcxx_bind_front 201907L
 #  if defined(__glibcxx_want_all) || defined(__glibcxx_want_bind_front)
 #   define __cpp_lib_bind_front 201907L
@@ -876,7 +886,12 @@
 #undef __glibcxx_want_bind_front
 
 #if !defined(__cpp_lib_bind_back)
-# if (__cplusplus >= 202100L) && (__cpp_explicit_this_parameter)
+# if (__cplusplus >  202302L)
+#  define __glibcxx_bind_back 202306L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_bind_back)
+#   define __cpp_lib_bind_back 202306L
+#  endif
+# elif (__cplusplus >= 202100L) && (__cpp_explicit_this_parameter)
 #  define __glibcxx_bind_back 202202L
 #  if defined(__glibcxx_want_all) || defined(__glibcxx_want_bind_back)
 #   define __cpp_lib_bind_back 202202L
diff --git a/libstdc++-v3/include/std/functional 
b/libstdc++-v3/include/std/functional
index 307bcb95bcc..9933715aa0d 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -71,6 +71,7 @@
 #include <type_traits>
 #include <bits/functional_hash.h>
 #include <bits/invoke.h>
+#include <bits/move.h>
 #include <bits/refwrap.h>      // std::reference_wrapper and _Mem_fn_traits
 #if _GLIBCXX_HOSTED
 # include <bits/std_function.h>        // std::function
@@ -87,7 +88,8 @@
 # include <bits/ranges_cmp.h> // std::identity, ranges::equal_to etc.
 # include <compare>
 #endif
-#if __glibcxx_move_only_function || __glibcxx_copyable_function || 
__glibcxx_function_ref
+#if __glibcxx_move_only_function || __glibcxx_copyable_function || \
+    __glibcxx_function_ref
 # include <bits/funcwrap.h>
 #endif
 
@@ -921,6 +923,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
                                          std::forward<_BoundArgs>(__args)...);
     }
 
+#if __cpp_lib_bind_front >= 202306 || __cpp_lib_bind_front >= 202306
+  template <auto __fn>
+    struct _Bind_fn_t
+    {
+      using _Fn = const decltype(__fn)&;
+      template <typename... _Args>
+       constexpr static decltype(auto)
+       operator()(_Args... __args)
+         noexcept(is_nothrow_invocable_v<_Fn, _Args...>)
+         requires is_invocable_v<_Fn, _Args...>
+       { return std::invoke(__fn, std::forward<_Args>(__args)...); }
+    };
+#endif
+
 #ifdef __cpp_lib_bind_front // C++ >= 20
 
   template<typename _Fd, typename... _BoundArgs>
@@ -940,7 +956,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          _M_bound_args(std::forward<_Args>(__args)...)
        { static_assert(sizeof...(_Args) == sizeof...(_BoundArgs)); }
 
-#if __cpp_explicit_this_parameter
+#ifdef __cpp_explicit_this_parameter
       template<typename _Self, typename... _CallArgs>
        constexpr
        invoke_result_t<__like_t<_Self, _Fd>, __like_t<_Self, _BoundArgs>..., 
_CallArgs...>
@@ -1049,6 +1065,50 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return _Bind_front_t<_Fn, _Args...>(0, std::forward<_Fn>(__fn),
                                          std::forward<_Args>(__args)...);
     }
+
+#if __cpp_lib_bind_front >= 202306
+
+  /** Create call wrapper by partial application of arguments to function.
+   *
+   * The result of `std::bind_front<fn>(bind_args...)` is a function object
+   * that stores the bound arguments, `bind_args...`. When that function
+   * object is invoked with `call_args...` it returns the result of calling
+   * `fn(bind_args..., call_args...)`.
+   *
+   *  @since C++26
+   */
+  template<auto __fn, typename... _BindArgs>
+    constexpr decltype(auto)
+    bind_front(_BindArgs&&... __bind_args)
+      noexcept(__and_<is_nothrow_constructible<_BindArgs>...>::value)
+    {
+      using _Fn = decltype(__fn);
+      static_assert(
+       (is_constructible_v<decay_t<_BindArgs>, _BindArgs> && ...) &&
+       (is_move_constructible_v<decay_t<_BindArgs>> && ...));
+      if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>)
+       static_assert(__fn != nullptr);
+
+      if constexpr (sizeof...(_BindArgs) == 0)
+       return _Bind_fn_t<__fn>{};
+      else {
+       return [... __bound_args(std::forward<_BindArgs>(__bind_args))]
+         <typename _Self, typename... _CallArgs>
+         (this _Self&&, _CallArgs&&... __call_args)
+           noexcept(is_nothrow_invocable_v<
+             const _Fn&, __like_t<_Self, decay_t<_BindArgs>>..., _CallArgs...>)
+           -> decltype(auto)
+           requires is_invocable_v<
+             const _Fn&, __like_t<_Self, decay_t<_BindArgs>>..., _CallArgs...>
+         {
+           return std::invoke(__fn,
+             std::forward_like<_Self>(__bound_args)...,
+             std::forward<_CallArgs>(__call_args)...);
+         };
+      }
+    }
+
+#endif // __cpp_lib_bind_front  // C++26
 #endif // __cpp_lib_bind_front
 
 #ifdef __cpp_lib_bind_back // C++ >= 23
@@ -1118,6 +1178,52 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return _Bind_back_t<_Fn, _Args...>(0, std::forward<_Fn>(__fn),
                                         std::forward<_Args>(__args)...);
     }
+
+#if __cpp_lib_bind_back >= 202306
+
+  /** Create call wrapper by partial application of arguments to function.
+   *
+   * The result of `std::bind_back<fn>(bind_args...)` is a function object
+   * that stores the arguments, `bind_args...`. When that function object
+   * is invoked with `call_args...` it returns the result of calling
+   * `fn(call_args..., bind_args...)`.
+   *
+   *  @since C++26
+   */
+  template<auto __fn, typename... _BindArgs>
+    constexpr decltype(auto)
+    bind_back(_BindArgs&&... __bind_args)
+      noexcept(__and_<is_nothrow_constructible<_BindArgs>...>::value)
+    {
+      using _Fn = decltype(__fn);
+      static_assert(
+       (is_constructible_v<decay_t<_BindArgs>, _BindArgs> && ...) &&
+       (is_move_constructible_v<decay_t<_BindArgs>> && ...));
+      if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>)
+       static_assert(__fn != nullptr);
+
+      if constexpr (sizeof...(_BindArgs) == 0)
+       return _Bind_fn_t<__fn>{};
+      else
+      {
+       // Capture arguments in a lambda and return that.
+       return [... __bound_args(std::forward<_BindArgs>(__bind_args))]
+         <typename _Self, typename... _CallArgs>
+         (this _Self&&, _CallArgs&&... __call_args)
+           noexcept(is_nothrow_invocable_v<
+             const _Fn&, _CallArgs..., __like_t<_Self, decay_t<_BindArgs>>...>)
+           -> decltype(auto)
+           requires is_invocable_v<
+             const _Fn&, _CallArgs..., __like_t<_Self, decay_t<_BindArgs>>...>
+         {
+           return std::invoke(__fn,
+             std::forward<_CallArgs>(__call_args)...,
+             std::forward_like<_Self>(__bound_args)...);
+         };
+      }
+    }
+
+#endif // __cpp_lib_bind_back  // C++26, nttp
 #endif // __cpp_lib_bind_back
 
 #if __cplusplus >= 201402L
@@ -1218,7 +1324,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     {
       return _Not_fn<std::decay_t<_Fn>>{std::forward<_Fn>(__fn), 0};
     }
-#endif
+
+#if __cpp_lib_not_fn >= 202306
+
+  /** Wrap a function type to create a function object that negates its result.
+   *
+   * The function template `std::not_fn` creates a "forwarding call wrapper",
+   * which is a function object that when called forwards its arguments to
+   * its invocable template argument.
+   *
+   * The result of invoking the wrapper is the negation (using `!`) of
+   * the wrapped function object.
+   *
+   *  @ingroup functors
+   *  @since C++26
+   */
+  template<auto __fn>
+    constexpr decltype(auto)
+    not_fn() noexcept
+    {
+      using _Fn = decltype(__fn);
+      if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>)
+       static_assert(__fn != nullptr);
+      return []<typename... _Args>(_Args... __args) static
+         noexcept(noexcept(
+           !std::invoke(__fn, std::forward<_Args>(__args)...) ))
+         -> decltype(auto)
+         requires requires {
+           !std::invoke(__fn, std::forward<_Args>(__args)...); }
+       { return !std::invoke(__fn, std::forward<_Args>(__args)...); };
+    };
+
+#endif // __cpp_lib_not_fn >= 202306
+#endif // __cpp_lib_not_fn
 
 #if __cplusplus >= 201703L
   // Searchers
diff --git a/libstdc++-v3/testsuite/20_util/function_objects/bind_back/1.cc 
b/libstdc++-v3/testsuite/20_util/function_objects/bind_back/1.cc
index c31d3228815..f3559b7f960 100644
--- a/libstdc++-v3/testsuite/20_util/function_objects/bind_back/1.cc
+++ b/libstdc++-v3/testsuite/20_util/function_objects/bind_back/1.cc
@@ -149,22 +149,22 @@ test03()
   static_assert(is_invocable_r_v<void*, const G4&&>);
 }
 
-constexpr int f(int i, int j, int k) { return i + 2*(j + k); }
+constexpr int f(int i, int j, int k) { return i + 2*j + 3*k; }
 
 constexpr bool
 test04()
 {
   auto g = bind_back(f);
-  VERIFY( g(1, 2, 3) == 1 + 2*(2 + 3) );
+  VERIFY( g(1, 2, 3) == 1 + 2*2 + 3*3 );
   auto g1 = bind_back(f, 1);
-  VERIFY( g1(2, 3) == 2 + 2*(3 + 1) );
-  VERIFY( bind_back(g, 1)(2, 3) == 2 + 2*(3 + 1) );
+  VERIFY( g1(2, 3) == 3*1 + 2 + 3*2);
+  VERIFY( bind_back(g, 1)(2, 3) == 3*1 + 2 + 2*3 );
   auto g2 = bind_back(f, 1, 2);
-  VERIFY( g2(3) == 3 + 2*(1 + 2) );
-  VERIFY( bind_back(g1, 2)(3) == 3 + 2*(2 + 1) );
+  VERIFY( g2(3) == 3 + 2*1 + 3*2);
+  VERIFY( bind_back(g1, 2)(3) == 3*1 + 2*2 + 3  );
   auto g3 = bind_back(f, 1, 2, 3);
-  VERIFY( g3() == 1 + 2*(2 + 3) );
-  VERIFY( bind_back(g2, 3)() == 3 + 2*(1 + 2) );
+  VERIFY( g3() == 1 + 2*2 + 3*3 );
+  VERIFY( bind_back(g2, 3)() == 3*1 + 1*2 + 2*3);
   return true;
 }
 
diff --git a/libstdc++-v3/testsuite/20_util/function_objects/bind_back/nttp.cc 
b/libstdc++-v3/testsuite/20_util/function_objects/bind_back/nttp.cc
new file mode 100644
index 00000000000..4dff909a387
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_objects/bind_back/nttp.cc
@@ -0,0 +1,258 @@
+// { dg-do run { target c++26 } }
+// { dg-add-options no_pch }
+
+// Test NTTP bind_back<f>(Args...), P2714
+
+#include <functional>
+
+#ifndef __cpp_lib_bind_back
+# error "Feature test macro for bind_back is missing in <functional>"
+#elif __cpp_lib_bind_back < 202306L
+# error "Feature test macro for bind_back has wrong value in <functional>"
+#endif
+
+#include <testsuite_hooks.h>
+
+using std::bind_back;
+using std::is_same_v;
+using std::is_invocable_v;
+using std::is_invocable_r_v;
+
+void
+test01()
+{
+  struct F { void operator()(int) {} };
+  constexpr F f{};
+
+  // Reference wrappers should be handled:
+  static_assert(!std::is_same_v<
+      decltype(bind_back<f>(std::declval<int&>())),
+      decltype(bind_back<f>(std::ref(std::declval<int&>())))
+      >);
+  static_assert(!std::is_same_v<
+      decltype(bind_back<f>(std::declval<const int&>())),
+      decltype(bind_back<f>(std::cref(std::declval<int&>())))
+      >);
+  static_assert(!std::is_same_v<
+      decltype(bind_back<f>(std::ref(std::declval<int&>()))),
+      decltype(bind_back<f>(std::cref(std::declval<int&>())))
+      >);
+}
+
+void
+test02()
+{
+  struct quals
+  {
+    bool as_const;
+    bool as_lvalue;
+  };
+
+  struct F
+  {
+    quals operator()(int, int) & { return { false, true }; }
+    quals operator()(int, int) const & { return { true, true }; }
+    quals operator()(int, int) && { return { false, false }; }
+    quals operator()(int, int) const && { return { true, false }; }
+  };
+
+  // Constness and value category forwarded to the target object?
+  { // no bound args
+    constexpr F f;
+    auto g = bind_back<f>();
+    const auto& cg = g;
+    quals q;
+
+    q = g(0,0);
+    VERIFY( q.as_const && q.as_lvalue );
+    q = std::move(g)(0,0);
+    VERIFY( q.as_const && q.as_lvalue );
+    q = cg(0,0);
+    VERIFY( q.as_const && q.as_lvalue );
+    q = std::move(cg)(0,0);
+    VERIFY( q.as_const && q.as_lvalue );
+  }
+  { // one bound arg
+    constexpr F f;
+    auto g = bind_back<f>(0);
+    const auto& cg = g;
+    quals q;
+
+    q = g(0);
+    VERIFY( q.as_const && q.as_lvalue );
+    q = std::move(g)(0);
+    VERIFY( q.as_const && q.as_lvalue );
+    q = cg(0);
+    VERIFY( q.as_const && q.as_lvalue );
+    q = std::move(cg)(0);
+    VERIFY( q.as_const && q.as_lvalue );
+  }
+  { // two bound args, the general case
+    constexpr F f;
+    auto g = bind_back<f>(0,0);
+    const auto& cg = g;
+    quals q;
+
+    q = g();
+    VERIFY( q.as_const && q.as_lvalue );
+    q = std::move(g)();
+    VERIFY( q.as_const && q.as_lvalue );
+    q = cg();
+    VERIFY( q.as_const && q.as_lvalue );
+    q = std::move(cg)();
+    VERIFY( q.as_const && q.as_lvalue );
+  }
+}
+
+void
+test02a()
+{
+  struct quals
+  {
+    bool as_const;
+    bool as_lvalue;
+  };
+  struct F
+  {
+    quals operator()(int, int&) const { return { false, true }; }
+    quals operator()(int, int const&) const { return { true, true }; }
+    quals operator()(int, int&&) const { return { false, false }; }
+    quals operator()(int, int const&&) const  { return { true, false }; }
+  };
+  constexpr F f{};
+
+  // verify propagation
+  auto h = bind_back<f>(10);
+  auto const& ch = h;
+  quals q;
+
+  q = h(0);
+  VERIFY( !q.as_const && q.as_lvalue );
+  q = ch(0);
+  VERIFY( q.as_const && q.as_lvalue );
+  q = std::move(h)(0);
+  VERIFY( !q.as_const && !q.as_lvalue );
+  q = std::move(ch)(0);
+  VERIFY( q.as_const && !q.as_lvalue );
+}
+
+void
+test03()
+{
+  struct F
+  {
+    int& operator()(void*, int& i) { return i; }
+    void* operator()(void* p, int) const { return p; }
+  };
+
+  int i = 5;
+  void* vp = &vp; // arbitrary void* value
+  constexpr F f;
+
+  // Bound arg always forwarded as const int& so can only call second overload:
+
+  auto g0 = bind_back<f>(); // call wrapper has no bound arg
+  using G0 = decltype(g0);
+  static_assert(is_invocable_r_v<void*, G0&, void*, int>);
+  static_assert(is_invocable_r_v<void*, G0&, void*, int&>);
+  static_assert(is_invocable_r_v<void*, G0&, void*, const int&>);
+  static_assert(is_invocable_r_v<void*, const G0&, void*, int>);
+  static_assert(is_invocable_r_v<void*, G0&&, void*, int>);
+  void* p0 = static_cast<G0&&>(g0)(vp, i);
+  VERIFY( p0 == vp );
+
+  auto g1 = bind_back<f>(i); // call wrapper has bound arg of type int
+  using G1 = decltype(g1);
+  static_assert(!is_invocable_r_v<int&, G1&, void*>);
+  static_assert(is_invocable_r_v<void*, const G1&, void*>);
+  static_assert(is_invocable_r_v<void*, G1&&, void*>);
+  void* p1 = static_cast<G1&&>(g1)(vp);
+  VERIFY( p1 == vp );
+
+  auto g2 = bind_back<f>(std::ref(i)); // bound arg of type int&
+  using G2 = decltype(g2);
+  static_assert(is_invocable_r_v<void*, G2&, void*>);
+  static_assert(is_invocable_r_v<void*, G2&&, void*>);
+  static_assert(is_invocable_r_v<void*, const G2&, void*>);
+  static_assert(is_invocable_r_v<void*, const G2&&, void*>);
+  void* p2 = g2(vp);
+  VERIFY( p2 == vp );
+  p2 = static_cast<G2&&>(g2)(vp);
+  VERIFY( p2 == vp );
+  p2 = const_cast<const G2&>(g2)(vp);
+  VERIFY( p2 == vp );
+
+  auto g3 = bind_back<f>(std::cref(i)); // bound arg of type const int&
+  using G3 = decltype(g3);
+  static_assert(is_invocable_r_v<void*, G3&, void*>);
+  static_assert(is_invocable_r_v<void*, G3&&, void*>);
+  static_assert(is_invocable_r_v<void*, const G3&, void*>);
+  static_assert(is_invocable_r_v<void*, const G3&&, void*>);
+}
+
+void test03a()
+{
+  struct F
+  {
+    int& operator()(void*, int& i) { return i; }
+    void* operator()(void* p, long) const { return p; }
+  };
+
+  int i = 5;
+  void* vp = &vp; // arbitrary void* value
+  constexpr F f;
+
+  // Bound arg always forwarded as const int& so can only call second overload:
+  auto g1 = bind_back<f>(i); // call wrapper has bound arg of type int
+  using G1 = decltype(g1);
+  static_assert(is_invocable_r_v<void*, G1&, void*>);
+  static_assert(is_invocable_r_v<void*, const G1&, void*>);
+  static_assert(is_invocable_r_v<void*, G1&&, void*>);
+  void* p1 = static_cast<G1&&>(g1)(vp);
+  VERIFY( p1 == vp );
+}
+
+
+constexpr int f(int i, int j, int k) { return i + 2*j + 3*k; }
+
+consteval bool
+test04()
+{
+  constexpr auto g = bind_back<f>();
+  VERIFY( std::is_empty_v<decltype(g)> );
+  VERIFY(g(1, 2, 3) == 1 + 2*2 + 3*3 );
+  constexpr auto g1 = bind_back<f>(1);
+  VERIFY(g1(2, 3) == 3*1 + 1*2 + 2*3 );
+  VERIFY(bind_back<g>(1)(2, 3) == 3*1 + 1*2 + 2*3 );
+  constexpr auto g2 = bind_back<f>(1, 2);
+  VERIFY(g2(3) == 2*1 + 3*2 + 1*3 );
+  VERIFY(bind_back<g1>(2)(3) == 3*1 + 2*2 + 1*3 );
+  constexpr auto g3 = bind_back<f>(1, 2, 3);
+  VERIFY(g3() == 1 + 2*2 + 3*3);
+  VERIFY(bind_back<g2>(3)() == 1*2 + 2*3 + 3*1 );
+  return true;
+}
+
+struct C { int i = 0; };
+struct D : C { D(){} D(D&&) { ++i; } };
+int f5(D const& d1, D const& d2, D const& d3)
+{ return d1.i + d2.i + d3.i; }
+
+void test05()
+{
+  // Must move arguments into capture object, not construct in place
+  // like normal arguments.
+  VERIFY( bind_back<f5>(D{}, D{})(D{}) == 2 );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test02a();
+  test03();
+  test03a();
+  static_assert(test04());
+  test05();
+}
diff --git 
a/libstdc++-v3/testsuite/20_util/function_objects/bind_back/nttp_neg.cc 
b/libstdc++-v3/testsuite/20_util/function_objects/bind_back/nttp_neg.cc
new file mode 100644
index 00000000000..d64d49e83f4
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_objects/bind_back/nttp_neg.cc
@@ -0,0 +1,38 @@
+//  { dg-do compile { target c++26 } }
+
+#include <functional>
+
+void f() {};
+using fp = decltype(&f);
+constexpr fp nfp = nullptr;
+
+struct A { void mf() const {} };
+using mfp = decltype(&A::mf);
+constexpr mfp nnmfp = &A::mf;
+constexpr mfp nmfp = nullptr;
+
+struct B { B() = default; B(B const&) = delete; };
+void bf(B const&) {};
+
+struct C { C() = default; C(C&&) = delete; };
+void cf(C&&) {};
+
+int main()
+{
+  std::bind_back<f>()();
+  // Verify bind_back<fn> with fn a null pointer fails.
+  std::bind_back<nfp>()();  // { dg-error "here" }
+
+  std::bind_back<nnmfp>(A{})();
+  // Verify bind_back<mfn> with mfn a null member pointer fails.
+  std::bind_back<nmfp>(A{})(); // { dg-error "here" }
+
+  // Verify passing uncopyable type fails.
+  std::bind_back<bf>(B{}); // { dg-error "here" }
+                          //
+  // Verify passing unmovable type fails.
+  std::bind_back<cf>(C{}); // { dg-error "here" }
+}
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
+// { dg-error "use of deleted function" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/20_util/function_objects/bind_front/1.cc 
b/libstdc++-v3/testsuite/20_util/function_objects/bind_front/1.cc
index 57482c52263..b038889fbb4 100644
--- a/libstdc++-v3/testsuite/20_util/function_objects/bind_front/1.cc
+++ b/libstdc++-v3/testsuite/20_util/function_objects/bind_front/1.cc
@@ -149,22 +149,22 @@ test03()
   static_assert(is_invocable_r_v<void*, const G4&&>);
 }
 
-int f(int i, int j, int k) { return i + j + k; }
+int f(int i, int j, int k) { return i + 2*j + 3*k; }
 
 void
 test04()
 {
   auto g = bind_front(f);
-  VERIFY( g(1, 2, 3) == 6 );
+  VERIFY( g(1, 2, 3) == 14 );
   auto g1 = bind_front(f, 1);
-  VERIFY( g1(2, 3) == 6 );
-  VERIFY( bind_front(g, 1)(2, 3) == 6 );
+  VERIFY( g1(2, 3) == 14 );
+  VERIFY( bind_front(g, 1)(2, 3) == 14 );
   auto g2 = bind_front(f, 1, 2);
-  VERIFY( g2(3) == 6 );
-  VERIFY( bind_front(g1, 2)(3) == 6 );
+  VERIFY( g2(3) == 14 );
+  VERIFY( bind_front(g1, 2)(3) == 14 );
   auto g3 = bind_front(f, 1, 2, 3);
-  VERIFY( g3() == 6 );
-  VERIFY( bind_front(g2, 3)() == 6 );
+  VERIFY( g3() == 14 );
+  VERIFY( bind_front(g2, 3)() == 14 );
 }
 
 int
diff --git a/libstdc++-v3/testsuite/20_util/function_objects/bind_front/nttp.cc 
b/libstdc++-v3/testsuite/20_util/function_objects/bind_front/nttp.cc
new file mode 100644
index 00000000000..1287004460e
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_objects/bind_front/nttp.cc
@@ -0,0 +1,260 @@
+// { dg-do run { target c++26 } }
+// { dg-add-options no_pch }
+
+// Test NTTP bind_front<f>(Args...), P2714
+
+#include <functional>
+
+#ifndef __cpp_lib_bind_front
+# error "Feature test macro for bind_front is missing in <functional>"
+#elif __cpp_lib_bind_front < 201902L
+# error "Feature test macro for bind_front has wrong value in <functional>"
+#endif
+
+#include <testsuite_hooks.h>
+
+using std::bind_front;
+using std::is_same_v;
+using std::is_invocable_v;
+using std::is_invocable_r_v;
+
+void
+test01()
+{
+  struct F { void operator()(int) {} };
+  constexpr F f{};
+
+  // Reference wrappers should be handled:
+  static_assert(!std::is_same_v<
+      decltype(bind_front<f>(std::declval<int&>())),
+      decltype(bind_front<f>(std::ref(std::declval<int&>())))
+      >);
+  static_assert(!std::is_same_v<
+      decltype(bind_front<f>(std::declval<const int&>())),
+      decltype(bind_front<f>(std::cref(std::declval<int&>())))
+      >);
+  static_assert(!std::is_same_v<
+      decltype(bind_front<f>(std::ref(std::declval<int&>()))),
+      decltype(bind_front<f>(std::cref(std::declval<int&>())))
+      >);
+}
+
+void
+test02()
+{
+  struct quals
+  {
+    bool as_const;
+    bool as_lvalue;
+  };
+
+  struct F
+  {
+    quals operator()(int, int) & { return { false, true }; }
+    quals operator()(int, int) const & { return { true, true }; }
+    quals operator()(int, int) && { return { false, false }; }
+    quals operator()(int, int) const && { return { true, false }; }
+  };
+
+  // Constness and value category forwarded to the target object?
+  { // no bound args
+    constexpr F f;
+    auto g = bind_front<f>();
+    const auto& cg = g;
+    quals q;
+
+    // Constness and value category forwarded to the target object?
+    q = g(0,0);
+    VERIFY( q.as_const && q.as_lvalue );
+    q = std::move(g)(0,0);
+    VERIFY( q.as_const && q.as_lvalue );
+    q = cg(0,0);
+    VERIFY( q.as_const && q.as_lvalue );
+    q = std::move(cg)(0,0);
+    VERIFY( q.as_const && q.as_lvalue );
+  }
+  { // one bound arg (for when we implement that as a separate case)
+    constexpr F f;
+    auto g = bind_front<f>(0);
+    const auto& cg = g;
+    quals q;
+
+    // Constness and value category forwarded to the target object?
+    q = g(0);
+    VERIFY( q.as_const && q.as_lvalue );
+    q = std::move(g)(0);
+    VERIFY( q.as_const && q.as_lvalue );
+    q = cg(0);
+    VERIFY( q.as_const && q.as_lvalue );
+    q = std::move(cg)(0);
+    VERIFY( q.as_const && q.as_lvalue );
+  }
+  { // two bound args, the general case
+    constexpr F f;
+    auto g = bind_front<f>(0,0);
+    const auto& cg = g;
+    quals q;
+
+    q = g();
+    VERIFY( q.as_const && q.as_lvalue );
+    q = std::move(g)();
+    VERIFY( q.as_const && q.as_lvalue );
+    q = cg();
+    VERIFY( q.as_const && q.as_lvalue );
+    q = std::move(cg)();
+    VERIFY( q.as_const && q.as_lvalue );
+  }
+}
+
+void
+test02a()
+{
+  struct quals
+  {
+    bool as_const;
+    bool as_lvalue;
+  };
+
+  struct F
+  {
+    quals operator()(int&, int) const { return { false, true }; }
+    quals operator()(int const&, int) const { return { true, true }; }
+    quals operator()(int&&, int) const { return { false, false }; }
+    quals operator()(int const&&, int) const  { return { true, false }; }
+  };
+  constexpr F f{};
+
+  // verify propagation
+  auto h = bind_front<f>(10);
+  auto const& ch = h;
+  quals q;
+
+  q = h(0);
+  VERIFY( !q.as_const && q.as_lvalue );
+  q = ch(0);
+  VERIFY( q.as_const && q.as_lvalue );
+  q = std::move(h)(0);
+  VERIFY( !q.as_const && !q.as_lvalue );
+  q = std::move(ch)(0);
+  VERIFY( q.as_const && !q.as_lvalue );
+}
+
+void
+test03()
+{
+  struct F
+  {
+    int& operator()(int& i, void*) { return i; }
+    void* operator()(long, void* p) const { return p; }
+  };
+
+  int i = 5;
+  void* vp = &vp; // arbitrary void* value
+  constexpr F f;
+
+  // Bound arg always forwarded as const int& so can only call second overload:
+
+  auto g0 = bind_front<f>(); // call wrapper has no bound arg
+  using G0 = decltype(g0);
+  static_assert(is_invocable_r_v<void*, G0&, int, void*>);
+  static_assert(is_invocable_r_v<void*, G0&, int&, void*>);
+  static_assert(is_invocable_r_v<void*, G0&, const int&, void*>);
+  static_assert(is_invocable_r_v<void*, const G0&, int, void*>);
+  static_assert(is_invocable_r_v<void*, G0&&, int, void*>);
+  void* p0 = static_cast<G0&&>(g0)(i, vp);
+  VERIFY( p0 == vp );
+
+  auto g1 = bind_front<f>(i); // call wrapper has bound arg of type int
+  using G1 = decltype(g1);
+  static_assert(!is_invocable_r_v<int&, G1&, void*>);
+  static_assert(is_invocable_r_v<void*, const G1&, void*>);
+  static_assert(is_invocable_r_v<void*, G1&&, void*>);
+  void* p1 = static_cast<G1&&>(g1)(vp);
+  VERIFY( p1 == vp );
+
+  auto g2 = bind_front<f>(std::ref(i)); // bound arg of type int&
+  using G2 = decltype(g2);
+  static_assert(is_invocable_r_v<void*, G2&, void*>);
+  static_assert(is_invocable_r_v<void*, G2&&, void*>);
+  static_assert(is_invocable_r_v<void*, const G2&, void*>);
+  static_assert(is_invocable_r_v<void*, const G2&&, void*>);
+  void* p2 = g2(vp);
+  VERIFY( p2 == vp );
+  p2 = static_cast<G2&&>(g2)(vp);
+  VERIFY( p2 == vp );
+  p2 = const_cast<const G2&>(g2)(vp);
+  VERIFY( p2 == vp );
+
+  auto g3 = bind_front<f>(std::cref(i)); // bound arg of type const int&
+  using G3 = decltype(g3);
+  static_assert(is_invocable_r_v<void*, G3&, void*>);
+  static_assert(is_invocable_r_v<void*, G3&&, void*>);
+  static_assert(is_invocable_r_v<void*, const G3&, void*>);
+  static_assert(is_invocable_r_v<void*, const G3&&, void*>);
+}
+
+void test03a()
+{
+  struct F
+  {
+    int& operator()(int& i, void*) { return i; }
+    void* operator()(long, void* p) const { return p; }
+  };
+
+  int i = 5;
+  void* vp = &vp; // arbitrary void* value
+  constexpr F f;
+
+  // Bound arg always forwarded as const int& so can only call second overload:
+  auto g1 = bind_front<f>(i); // call wrapper has bound arg of type int
+  using G1 = decltype(g1);
+  static_assert(is_invocable_r_v<void*, G1&, void*>);
+  static_assert(is_invocable_r_v<void*, const G1&, void*>);
+  static_assert(is_invocable_r_v<void*, G1&&, void*>);
+  void* p1 = static_cast<G1&&>(g1)(vp);
+  VERIFY( p1 == vp );
+}
+
+constexpr int f(int i, int j, int k) { return i + 2*j + 3*k; }
+
+consteval bool
+test04()
+{
+  constexpr auto g = bind_front<f>();
+  VERIFY( std::is_empty_v<decltype(g)> );
+  VERIFY( g(1, 2, 3) == 1 + 2*2 + 3*3 );
+  constexpr auto g1 = bind_front<f>(1);
+  VERIFY( g1(2, 3) == 1 + 2*2 + 3*3 );
+  VERIFY( bind_front<g>(1)(2, 3) == 1 + 2*2 + 3*3 );
+  constexpr auto g2 = bind_front<f>(1, 2);
+  VERIFY( g2(3) == 1 + 2*2 + 3*3 );
+  VERIFY( bind_front<g1>(2)(3) == 1 + 2*2 + 3*3 );
+  constexpr auto g3 = bind_front<f>(1, 2, 3);
+  VERIFY( g3() == 1 + 2*2 + 3*3 );
+  VERIFY(bind_front<g2>(3)() == 1 + 2*2 + 3*3 );
+  return true;
+}
+
+struct C { int i = 0; };
+struct D : C { D(){} D(D&&) { ++i; } };
+int f5(D const& d1, D const& d2, D const& d3)
+{ return d1.i + d2.i + d3.i; }
+
+void test05()
+{
+  // Must move arguments into capture object, not construct in place
+  // like normal arguments.
+  VERIFY( bind_front<f5>(D{}, D{})(D{}) == 2 );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test02a();
+  test03();
+  test03a();
+  static_assert(test04());
+  test05();
+}
diff --git 
a/libstdc++-v3/testsuite/20_util/function_objects/bind_front/nttp_neg.cc 
b/libstdc++-v3/testsuite/20_util/function_objects/bind_front/nttp_neg.cc
new file mode 100644
index 00000000000..d274c191635
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_objects/bind_front/nttp_neg.cc
@@ -0,0 +1,38 @@
+//  { dg-do compile { target c++26 } }
+
+#include <functional>
+
+void f() {}
+using fp = decltype(&f);
+constexpr fp nfp = nullptr;
+
+struct A { void mf() const {} };
+using mfp = decltype(&A::mf);
+constexpr mfp nnmfp = &A::mf;
+constexpr mfp nmfp = nullptr;
+
+struct B { B() = default; B(B const&) = delete; };
+void bf(B const&) {};
+
+struct C { C() = default; C(C&&) = delete; };
+void cf(C&&) {};
+
+int main()
+{
+  std::bind_front<f>()();
+  // Verify bind_front<fn> with fn a null pointer fails:
+  std::bind_front<nfp>()();  // { dg-error "here" }
+
+  std::bind_front<nnmfp>(A{})();
+  // Verify bind_front<mfn> with mfn a null member pointer fails:
+  std::bind_front<nmfp>(A{})(); // { dg-error "here" }
+
+  // Verify passing uncopyable type fails:
+  std::bind_front<bf>(B{}); // { dg-error "here" }
+                           //
+  // Verify passing unmovable type fails:
+  std::bind_front<cf>(C{}); // { dg-error "here" }
+}
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
+// { dg-error "use of deleted function" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/20_util/function_objects/not_fn/nttp.cc 
b/libstdc++-v3/testsuite/20_util/function_objects/not_fn/nttp.cc
new file mode 100644
index 00000000000..f0b07e7acd8
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_objects/not_fn/nttp.cc
@@ -0,0 +1,98 @@
+// Test NTTP version of not_fn, from P2714
+
+// { dg-do run { target c++26 } }
+
+#ifndef __cpp_lib_bind_back
+# error "Feature test macro for bind_back is missing in <functional>"
+#elif __cpp_lib_bind_back < 202306L
+# error "Feature test macro for bind_back has wrong value in <functional>"
+#endif
+
+#include <functional>
+#include <testsuite_hooks.h>
+
+using std::not_fn;
+
+int func(int, char) { return 0; }
+
+struct F
+{
+  bool operator()() { return false; }
+  bool operator()() const { return true; }
+  bool operator()(int) const { return false; }
+};
+
+void
+test01()
+{
+  auto f1 = not_fn<func>();
+  VERIFY( std::is_empty_v<decltype(f1)> );
+  VERIFY( f1(1, '2') == true );
+
+  auto f2 = not_fn<[] { return true; }>();
+  VERIFY( std::is_empty_v<decltype(f2)> );
+  VERIFY( f2() == false );
+
+  auto f3 = not_fn<F{}>();
+  VERIFY( f3() == false );  // Prefer the const member.
+  VERIFY( f3(1) == true );
+  const auto f4 = f3;
+  VERIFY( f4() == false );
+}
+
+void
+test04()
+{
+  struct abstract { virtual void f() = 0; };
+  struct derived : abstract { void f() { } };
+  struct F { bool operator()(const abstract&) const { return false; } };
+  constexpr F f;
+  constexpr derived d;
+  VERIFY( not_fn<f>()(d) );
+}
+
+void
+test05()
+{
+  auto nf = std::not_fn<[] { return false; }>();
+  auto copy(nf); // PR libstdc++/70564
+}
+
+void
+test06()
+{
+  struct Boolean {
+    Boolean operator!() const noexcept(false) { return *this; }
+  };
+  struct F {
+    Boolean operator()() const { return {}; }
+  };
+  const F f;
+  const auto notf = std::not_fn<f>();
+  using NotF = decltype(notf);
+  static_assert( std::is_invocable<NotF>::value, "cannot negate" );
+  static_assert( !noexcept(notf()), "conversion to bool affects noexcept" );
+}
+
+void
+test07()
+{
+  struct NonNegatable { };  // there is no operator!(NonNegatable)
+  struct F {
+    NonNegatable operator()() const { return {}; }
+  };
+  F f;
+  constexpr auto notf = std::not_fn<f>();
+  using NotF = decltype(notf);
+  static_assert( !std::is_invocable<NotF>::value, "cannot negate" );
+}
+
+int
+main()
+{
+  test01();
+  test04();
+  test05();
+  test06();
+  test07();
+}
diff --git a/libstdc++-v3/testsuite/20_util/function_objects/not_fn/nttp_neg.cc 
b/libstdc++-v3/testsuite/20_util/function_objects/not_fn/nttp_neg.cc
new file mode 100644
index 00000000000..78752735f39
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_objects/not_fn/nttp_neg.cc
@@ -0,0 +1,28 @@
+//  { dg-do compile { target c++26 } }
+
+#include <functional>
+
+bool f() { return {}; }
+using fp = decltype(&f);
+constexpr fp nfp = nullptr;
+
+struct A { bool mf() const { return {}; } };
+using mfp = decltype(&A::mf);
+constexpr mfp nnmfp = &A::mf;
+constexpr mfp nmfp = nullptr;
+constexpr A a;
+
+int main()
+{
+  (void) std::not_fn<f>()();
+
+  // Verify not_fn<fn> with fn a null pointer fails.
+  (void) std::not_fn<nfp>()();  // { dg-error "here" }
+                               //
+  (void) std::not_fn<nnmfp>()(a);
+
+  // Verify not_fn<mfn> with mfn a null member pointer fails.
+  return std::not_fn<nmfp>()(a);  // { dg-error "here" }
+}
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/20_util/headers/functional/synopsis.cc 
b/libstdc++-v3/testsuite/20_util/headers/functional/synopsis.cc
index e3e92076f5c..5e835d684fd 100644
--- a/libstdc++-v3/testsuite/20_util/headers/functional/synopsis.cc
+++ b/libstdc++-v3/testsuite/20_util/headers/functional/synopsis.cc
@@ -57,6 +57,13 @@ namespace std {
   template <class Predicate>
   _GLIBCXX14_CONSTEXPR
   binary_negate<Predicate> not2(const Predicate&);
+#ifdef __cpp_lib_not_fn
+  template <typename F> _GLIBCXX20_CONSTEXPR auto not_fn(F&&)
+  noexcept(std::is_nothrow_constructible<std::decay_t<F>, F&&>::value);
+#if __cpp_lib_not_fn >= 2020306
+  template <auto f> constexpr auto not_fn() noexcept;
+#endif
+#endif
 
   //  lib.binders, binders:
   template <class Operation>  class binder1st;
@@ -65,6 +72,20 @@ namespace std {
   template <class Operation> class binder2nd;
   template <class Operation, class T>
   binder2nd<Operation> bind2nd(const Operation&, const T&);
+#ifdef __cpp_lib_bind_front
+  template <typename F, typename... Args>
+    _GLIBCXX20_CONSTEXPR auto bind_front(F&&, Args&&...);
+#if __cpp_lib_bind_front >= 202306
+  template <auto f, typename... Args> constexpr auto bind_front(Args&&...);
+#endif
+#endif
+#ifdef __cpp_lib_bind_back
+  template <typename F, typename... Args>
+    _GLIBCXX20_CONSTEXPR auto bind_back(F&&, Args&&...);
+#if __cpp_lib_bind_back >= 202306
+  template <auto f, typename... Args> constexpr auto bind_back(Args&&...);
+#endif
+#endif
 
   //  lib.function.pointer.adaptors, adaptors:
   template <class Arg, class Result> class pointer_to_unary_function;
-- 
2.50.0


Reply via email to