Make Rust/C++ callable manager calls pass CFI in both directions.

PiperOrigin-RevId: 999035084
diff --git a/absl/base/attributes.h b/absl/base/attributes.h
index 1e4c7c3..601be76 100644
--- a/absl/base/attributes.h
+++ b/absl/base/attributes.h
@@ -85,16 +85,16 @@
 // Note: As the GCC manual states, "[s]ince non-static C++ methods
 // have an implicit 'this' argument, the arguments of such methods
 // should be counted from two, not one."
-#if ABSL_HAVE_ATTRIBUTE(format) || (defined(__GNUC__) && !defined(__clang__))
-#define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check) \
-  __attribute__((__format__(__printf__, string_index, first_to_check)))
 #if ABSL_HAVE_CPP_ATTRIBUTE(gnu::format)
+#define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check) \
+  [[gnu::format(printf, string_index, first_to_check)]]
 #define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check) \
   [[gnu::format(scanf, string_index, first_to_check)]]
-#else
+#elif ABSL_HAVE_ATTRIBUTE(format) || (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check) \
+  __attribute__((__format__(__printf__, string_index, first_to_check)))
 #define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check) \
   __attribute__((__format__(__scanf__, string_index, first_to_check)))
-#endif
 #else
 #define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check)
 #define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check)
@@ -1117,4 +1117,52 @@
 #define ABSL_ATTRIBUTE_WARN_UNUSED
 #endif
 
+// ABSL_UNSAFE_BUFFERS()
+//
+// Wraps code that performs unsafe buffer accesses or pointer arithmetic. Used
+// to suppress warnings when `-Wunsafe-buffer-usage` is enabled.
+//
+// **WARNING**: This macro should be used when unavoidable. Applying it means
+// the compiler is unable to prove that your code avoids out-of-bounds reads or
+// writes, forcing reliance on manual review. Over time, code evolves and
+// undocumented assumptions can silently break, introducing vulnerabilities.
+// Always prioritize refactoring to safer alternatives (e.g. std::array,
+// absl::Span, or bounds-checked containers) over using this suppression.
+//
+// When using this macro is unavoidable, restrict its scope to the smallest
+// possible expression or statement. You must also add a `// SAFETY: ...`
+// comment explaining why the operation is actually safe.
+// Justifications include:
+//  * Explicit bounds checks (e.g., `CHECK()`) immediately preceding the access.
+//  * Invariants strictly enforced by surrounding types or functions.
+//  * Preconditions required of the caller (though this is heavily discouraged).
+//
+// Example (expression):
+//
+//   // SAFETY: `buf` is NUL-terminated so `strdup` won't read past the end.
+//   return ABSL_UNSAFE_BUFFERS(strdup(buf));
+//
+// Example (single-line statement):
+//
+//   // SAFETY: `offset` is bounds-checked above to be within `buffer`.
+//   ABSL_UNSAFE_BUFFERS(buffer += offset;)
+//
+// Example (multi-line statement):
+//
+//   // SAFETY: `offset` is bounds-checked above to be within `buffer`.
+//   ABSL_UNSAFE_BUFFERS(
+//       char* p = buffer + offset;
+//       p[0] = 'a';
+//   )
+//
+// Note: When wrapping a multi-line statement, placing a semicolon after the
+// closing parenthesis may produce an extra semicolon warning.
+#if defined(__clang__)
+#define ABSL_UNSAFE_BUFFERS(...)             \
+  _Pragma("clang unsafe_buffer_usage begin") \
+      __VA_ARGS__ _Pragma("clang unsafe_buffer_usage end")
+#else
+#define ABSL_UNSAFE_BUFFERS(...) __VA_ARGS__
+#endif
+
 #endif  // ABSL_BASE_ATTRIBUTES_H_
diff --git a/absl/base/attributes_test.cc b/absl/base/attributes_test.cc
index 058d1be..e87b66e 100644
--- a/absl/base/attributes_test.cc
+++ b/absl/base/attributes_test.cc
@@ -54,4 +54,22 @@
   Agg good1 [[maybe_unused]] = {ImplicitlyConstructible("hello")};
 }
 
+TEST(Attributes, UnsafeBuffers) {
+  int buffer[10] = {0};
+  int offset = 1;
+
+  // Expression example
+  int* p1 = ABSL_UNSAFE_BUFFERS(buffer + offset);
+  EXPECT_EQ(p1, &buffer[1]);
+
+  // Single-line statement example
+  int* p2 = buffer;
+  ABSL_UNSAFE_BUFFERS(p2 += offset;)
+  EXPECT_EQ(p2, &buffer[1]);
+
+  // Multi-line statement example
+  ABSL_UNSAFE_BUFFERS(int* p3 = buffer + offset; p3[0] = 1;)
+  EXPECT_EQ(buffer[1], 1);
+}
+
 }  // namespace
diff --git a/absl/crc/internal/crc_x86_arm_combined.cc b/absl/crc/internal/crc_x86_arm_combined.cc
index 95221e4..d6f42d9 100644
--- a/absl/crc/internal/crc_x86_arm_combined.cc
+++ b/absl/crc/internal/crc_x86_arm_combined.cc
@@ -1084,6 +1084,7 @@
           3, 1, PclmulStreamType::PCLMUL>();
     case CpuType::kAmdMilan:
     case CpuType::kAmdGenoa:
+    case CpuType::kAmdRyzenV3000:
     case CpuType::kAmdSiena:
     case CpuType::kAmdTurin:
     case CpuType::kAmdVenice:
diff --git a/absl/functional/BUILD.bazel b/absl/functional/BUILD.bazel
index d1b46c7..0cad083 100644
--- a/absl/functional/BUILD.bazel
+++ b/absl/functional/BUILD.bazel
@@ -124,6 +124,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":bind_front",
+        "//absl/base:config",
         "//absl/memory",
         "@googletest//:gtest",
         "@googletest//:gtest_main",
diff --git a/absl/functional/CMakeLists.txt b/absl/functional/CMakeLists.txt
index 1ddfa29..231c9dd 100644
--- a/absl/functional/CMakeLists.txt
+++ b/absl/functional/CMakeLists.txt
@@ -105,6 +105,7 @@
     ${ABSL_DEFAULT_COPTS}
   DEPS
     absl::bind_front
+    absl::config
     absl::memory
     GTest::gmock_main
 )
diff --git a/absl/functional/bind_front.h b/absl/functional/bind_front.h
index 45ca4fc..06b6e52 100644
--- a/absl/functional/bind_front.h
+++ b/absl/functional/bind_front.h
@@ -21,10 +21,11 @@
 // it does not require the use of argument placeholders. The simpler syntax of
 // `absl::bind_front()` allows you to avoid known misuses with `std::bind()`.
 //
-// `absl::bind_front()` is meant as a drop-in replacement for C++20's upcoming
-// `std::bind_front()`, which similarly resolves these issues with
-// `std::bind()`. Both `bind_front()` alternatives, unlike `std::bind()`, allow
-// partial function application. (See
+// `absl::bind_front()` is meant as a drop-in replacement for C++20's
+// `std::bind_front(func, args...)` and C++26's
+// `std::bind_front<ConstFn>(args...)`, which similarly resolve these issues
+// with `std::bind()`. Both `bind_front()` alternatives, unlike `std::bind()`,
+// allow partial function application. (See
 // https://en.wikipedia.org/wiki/Partial_application).
 
 #ifndef ABSL_FUNCTIONAL_BIND_FRONT_H_
@@ -39,17 +40,40 @@
 #include <functional>  // For std::bind_front.
 #endif  // defined(__cpp_lib_bind_front) && __cpp_lib_bind_front >= 201907L
 
+#include <type_traits>
 #include <utility>
 
 #include "absl/functional/internal/front_binder.h"
 #include "absl/utility/utility.h"
 
+// ABSL_INTERNAL_HAVE_STD_NTTP_BIND_FRONT
+//
+// Defined if the standard library implements C++26 `std::bind_front<ConstFn>`,
+// which `absl::bind_front<ConstFn>` then aliases.
+//
+// libc++ 17 through 22 define `__cpp_lib_bind_front` as 202306L in C++26 mode,
+// but `std::bind_front<ConstFn>` was first implemented in libc++ 23:
+// https://github.com/llvm/llvm-project/pull/165096#issuecomment-4487517016
+#ifdef ABSL_INTERNAL_HAVE_STD_NTTP_BIND_FRONT
+#error ABSL_INTERNAL_HAVE_STD_NTTP_BIND_FRONT cannot be directly set
+#elif defined(__cpp_lib_bind_front) && __cpp_lib_bind_front >= 202306L && \
+    (!defined(_LIBCPP_VERSION) || _LIBCPP_VERSION >= 230000)
+#define ABSL_INTERNAL_HAVE_STD_NTTP_BIND_FRONT 1
+#endif
+
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 
 // bind_front()
 //
 // Binds the first N arguments of an invocable object and stores them by value.
+// The target invocable can be passed either as a runtime argument
+// `absl::bind_front(func, args...)` (C++20 `std::bind_front`) or as a
+// compile-time non-type template parameter `absl::bind_front<ConstFn>(args...)`
+// (C++26 `std::bind_front`).
+//
+// Passing `ConstFn` as a non-type template parameter avoids storing a function
+// pointer or pointer-to-member at runtime.
 //
 // Like `std::bind()`, `absl::bind_front()` is implicitly convertible to
 // `std::function`.  In particular, it may be used as a simpler replacement for
@@ -57,7 +81,8 @@
 // specified. More importantly, it provides more reliable correctness guarantees
 // than `std::bind()`; while `std::bind()` will silently ignore passing more
 // parameters than expected, for example, `absl::bind_front()` will report such
-// mis-uses as errors. In C++20, `absl::bind_front` is replaced by
+// mis-uses as errors. In C++20 (for runtime callables) and C++26 (for
+// non-type template parameter callables), `absl::bind_front` aliases
 // `std::bind_front`.
 //
 // absl::bind_front(a...) can be seen as storing the results of
@@ -70,6 +95,8 @@
 //   assert(absl::bind_front(Minus)(3, 2) == 3 - 2);
 //   assert(absl::bind_front(Minus, 3)(2) == 3 - 2);
 //   assert(absl::bind_front(Minus, 3, 2)() == 3 - 2);
+//   assert(absl::bind_front<&Minus>()(3, 2) == 3 - 2);
+//   assert(absl::bind_front<&Minus>(3)(2) == 3 - 2);
 //
 // Example: Binding a member function.
 //
@@ -80,8 +107,10 @@
 //   Math math;
 //
 //   assert(absl::bind_front(&Math::Double)(&math, 3) == 2 * 3);
+//   assert(absl::bind_front<&Math::Double>()(&math, 3) == 2 * 3);
 //   // Stores a pointer to math inside the functor.
 //   assert(absl::bind_front(&Math::Double, &math)(3) == 2 * 3);
+//   assert(absl::bind_front<&Math::Double>(&math)(3) == 2 * 3);
 //   // Stores a copy of math inside the functor.
 //   assert(absl::bind_front(&Math::Double, math)(3) == 2 * 3);
 //   // Stores std::unique_ptr<Math> inside the functor.
@@ -193,7 +222,23 @@
 }
 #endif  // defined(__cpp_lib_bind_front) && __cpp_lib_bind_front >= 201907L
 
+#ifndef ABSL_INTERNAL_HAVE_STD_NTTP_BIND_FRONT
+template <auto ConstFn, class... BoundArgs>
+constexpr auto bind_front(BoundArgs&&... args) {
+  using F = decltype(ConstFn);
+  if constexpr (std::is_pointer_v<F> || std::is_member_pointer_v<F>) {
+    static_assert(ConstFn != nullptr,
+                  "bind_front: ConstFn cannot be equal to nullptr");
+  }
+  // The runtime `bind_front` checks the requirements on `BoundArgs`.
+  return absl::bind_front(functional_internal::ConstFnInvoker<ConstFn>{},
+                          std::forward<BoundArgs>(args)...);
+}
+#endif  // ABSL_INTERNAL_HAVE_STD_NTTP_BIND_FRONT
+
 ABSL_NAMESPACE_END
 }  // namespace absl
 
+#undef ABSL_INTERNAL_HAVE_STD_NTTP_BIND_FRONT
+
 #endif  // ABSL_FUNCTIONAL_BIND_FRONT_H_
diff --git a/absl/functional/bind_front_test.cc b/absl/functional/bind_front_test.cc
index 6e87d43..300466c 100644
--- a/absl/functional/bind_front_test.cc
+++ b/absl/functional/bind_front_test.cc
@@ -19,15 +19,17 @@
 #include <functional>
 #include <memory>
 #include <string>
+#include <type_traits>
 #include <utility>
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include "absl/base/config.h"
 #include "absl/memory/memory.h"
 
 namespace {
 
-char CharAt(const char* s, size_t index) { return s[index]; }
+constexpr char CharAt(const char* s, size_t index) { return s[index]; }
 
 TEST(BindTest, Basics) {
   EXPECT_EQ('C', absl::bind_front(CharAt)("ABC", 2));
@@ -200,7 +202,7 @@
   EXPECT_EQ(42, std::move(f)());
 }
 
-int Plus(int a, int b) { return a + b; }
+constexpr int Plus(int a, int b) { return a + b; }
 
 TEST(BindTest, ConstExpr) {
   constexpr auto f = absl::bind_front(CharAt);
@@ -223,4 +225,224 @@
   absl::bind_front(ManglingCall{}, 1, 3.3)("A");
 }
 
+struct Math {
+  constexpr int Add(int a, int b) const noexcept { return base + a + b; }
+  int base = 10;
+};
+
+TEST(BindConstFnTest, Basics) {
+  EXPECT_EQ('C', absl::bind_front<&CharAt>()("ABC", 2));
+  EXPECT_EQ('C', absl::bind_front<&CharAt>("ABC")(2));
+  EXPECT_EQ('C', absl::bind_front<&CharAt>("ABC", 2)());
+}
+
+TEST(BindConstFnTest, MemberPointers) {
+  Math m{10};
+  auto bound_ptr = absl::bind_front<&Math::Add>(&m);
+  EXPECT_EQ(15, bound_ptr(2, 3));
+
+  auto bound_ptr_and_arg = absl::bind_front<&Math::Add>(&m, 2);
+  EXPECT_EQ(15, bound_ptr_and_arg(3));
+
+  auto bound_zero_args = absl::bind_front<&Math::Add>();
+  EXPECT_EQ(15, bound_zero_args(&m, 2, 3));
+  EXPECT_EQ(15, bound_zero_args(m, 2, 3));
+}
+
+TEST(BindConstFnTest, StoreByCopyRefAndPointer) {
+  Struct s = {"hello"};
+  auto by_copy = absl::bind_front<&Struct::value>(s);
+  EXPECT_EQ("hello", by_copy());
+  EXPECT_NE(&s.value, &by_copy());
+
+  NonCopyable nc("hello");
+  auto by_ref = absl::bind_front<&GetNonCopyableValue>(std::ref(nc));
+  EXPECT_EQ("hello", by_ref());
+  EXPECT_EQ(&nc.value, &by_ref());
+
+  auto by_cref = absl::bind_front<&GetNonCopyableValue>(std::cref(nc));
+  EXPECT_EQ("hello", by_cref());
+  EXPECT_EQ(&nc.value, &by_cref());
+
+  auto by_ptr = absl::bind_front<&NonCopyable::value>(&nc);
+  EXPECT_EQ("hello", by_ptr());
+  EXPECT_EQ(&nc.value, &by_ptr());
+  nc.value = "goodbye";
+  EXPECT_EQ("goodbye", by_ref());
+  EXPECT_EQ("goodbye", by_cref());
+  EXPECT_EQ("goodbye", by_ptr());
+}
+
+TEST(BindConstFnTest, MoveOnlyArgsAndResult) {
+  EXPECT_EQ(42, absl::bind_front<&Sink>()(std::make_unique<int>(42)));
+  EXPECT_EQ(42, absl::bind_front<&Sink>(std::make_unique<int>(42))());
+  EXPECT_THAT(absl::bind_front<&Factory>()(42), ::testing::Pointee(42));
+  EXPECT_THAT(absl::bind_front<&Factory>(42)(), ::testing::Pointee(42));
+
+  FalseCopyable<std::unique_ptr<int>> x;
+  x.m = std::make_unique<int>(42);
+  auto f = absl::bind_front<&GetMember>(std::move(x));
+  EXPECT_EQ(42, std::move(f)());
+}
+
+TEST(BindConstFnTest, ConstExpr) {
+  constexpr auto f = absl::bind_front<&CharAt>();
+  EXPECT_EQ(f("ABC", 1), 'B');
+
+  constexpr auto plus5 = absl::bind_front<&Plus>(5);
+  EXPECT_EQ(plus5(1), 6);
+
+  constexpr auto plus5_1 = absl::bind_front<&Plus>(5, 1);
+  EXPECT_EQ(plus5_1(), 6);
+
+  constexpr Math m{10};
+  constexpr auto add_m = absl::bind_front<&Math::Add>(m, 2);
+  EXPECT_EQ(add_m(3), 15);
+
+  // Invoking the results is `constexpr` only where the runtime `bind_front`
+  // that produces them is `std::bind_front` (C++20). The pre-C++20 fallback's
+  // call operators and `std::invoke` are not `constexpr`.
+#if defined(__cpp_lib_bind_front) && __cpp_lib_bind_front >= 201907L
+  static_assert(f("ABC", 1) == 'B');
+  static_assert(plus5(1) == 6);
+  static_assert(plus5_1() == 6);
+  static_assert(add_m(3) == 15);
+#endif  // __cpp_lib_bind_front >= 201907L
+}
+
+// The results come from the runtime `bind_front`, which propagates `noexcept`
+// where it is `std::bind_front` (C++20).
+#if defined(__cpp_lib_bind_front) && __cpp_lib_bind_front >= 201907L
+int NoexceptPlus(int a, int b) noexcept { return a + b; }
+int PotentiallyThrowingPlus(int a, int b) { return a + b; }
+
+TEST(BindConstFnTest, NoexceptPropagation) {
+  auto noexcept_0 = absl::bind_front<&NoexceptPlus>();
+  static_assert(noexcept(noexcept_0(1, 2)));
+
+  auto throwing_0 = absl::bind_front<&PotentiallyThrowingPlus>();
+  static_assert(!noexcept(throwing_0(1, 2)));
+
+  Math m{10};
+  auto math_0 = absl::bind_front<&Math::Add>();
+  static_assert(noexcept(math_0(m, 1, 2)));
+}
+#endif  // __cpp_lib_bind_front >= 201907L
+
+// Invalid calls must be substitution failures rather than hard errors, so that
+// `std::is_invocable` works on the result.
+TEST(BindConstFnTest, SfinaeFriendly) {
+  using PlusBinder = decltype(absl::bind_front<&Plus>());
+  static_assert(std::is_invocable_v<PlusBinder, int, int>);
+  static_assert(!std::is_invocable_v<PlusBinder, std::string, int>);
+  static_assert(!std::is_invocable_v<PlusBinder, int>);
+
+  using Plus1Binder = decltype(absl::bind_front<&Plus>(1));
+  static_assert(std::is_invocable_v<Plus1Binder, int>);
+  static_assert(!std::is_invocable_v<Plus1Binder, std::string>);
+}
+
+// These tests pass class-type objects as template arguments (P0732R2,
+// P1907R1), and `StatelessLambdaNTTP` puts a lambda in a template argument
+// (P0315R4, which has no feature-test macro).
+//
+// We check the language version rather than
+// `__cpp_nontype_template_args >= 201911L` because Clang (through at least
+// 24) still defines it as 201411L: its P1907R1 support is incomplete, though
+// everything used here works. Checking the feature macro would silently skip
+// these tests on Clang. If a toolchain claims C++20 but can't compile these
+// tests, exclude it here.
+#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
+TEST(BindConstFnTest, StatelessLambdaNTTP) {
+  constexpr auto f = absl::bind_front<[](int x, int y) { return x + y; }>();
+  EXPECT_EQ(f(2, 3), 5);
+
+  constexpr auto f2 = absl::bind_front<[](int x, int y) { return x + y; }>(2);
+  EXPECT_EQ(f2(3), 5);
+}
+
+struct Adder {
+  constexpr int operator()(int x) const& { return base + x; }
+  // `ConstFn` names a template parameter object, which is a `const` lvalue
+  // ([temp.param]), so it must never be invoked as an rvalue.
+  int operator()(int) const&& = delete;
+
+  int base;
+};
+
+TEST(BindConstFnTest, StatefulObjectNTTP) {
+  constexpr auto add5 = absl::bind_front<Adder{5}>();
+  EXPECT_EQ(add5(1), 6);
+
+  constexpr auto add5_1 = absl::bind_front<Adder{5}>(1);
+  EXPECT_EQ(add5_1(), 6);
+}
+
+struct DescribeCall {
+  template <class... Args>
+  std::string operator()(Args&&...) & {
+    return "&";
+  }
+  template <class... Args>
+  std::string operator()(Args&&...) const& {
+    return "const&";
+  }
+  template <class... Args>
+  std::string operator()(Args&&...) && {
+    return "&&";
+  }
+  template <class... Args>
+  std::string operator()(Args&&...) const&& {
+    return "const&&";
+  }
+};
+
+// Since `ConstFn` is a `const` lvalue, it is invoked through its `const&`
+// overload whatever the value category of the result. Both zero and nonzero
+// bound arguments are tested, since the standard library's
+// `std::bind_front<ConstFn>` may implement them differently.
+TEST(BindConstFnTest, InvokesConstFnAsConstLvalue) {
+  auto f0 = absl::bind_front<DescribeCall{}>();
+  const auto& cf0 = f0;
+  EXPECT_EQ("const&", f0());
+  EXPECT_EQ("const&", cf0());
+  EXPECT_EQ("const&", std::move(f0)());
+  EXPECT_EQ("const&", std::move(cf0)());
+
+  auto f1 = absl::bind_front<DescribeCall{}>(1);
+  const auto& cf1 = f1;
+  EXPECT_EQ("const&", f1());
+  EXPECT_EQ("const&", cf1());
+  EXPECT_EQ("const&", std::move(f1)());
+  EXPECT_EQ("const&", std::move(cf1)());
+}
+
+struct DeletedConstLvalueCall {
+  template <class... Args>
+  void operator()(Args&&...) &;
+  template <class... Args>
+  void operator()(Args&&...) const& = delete;
+  template <class... Args>
+  void operator()(Args&&...) &&;
+  template <class... Args>
+  void operator()(Args&&...) const&&;
+};
+
+// If `ConstFn`'s `const&` overload is deleted, the result isn't invocable,
+// rather than falling back to another overload.
+TEST(BindConstFnTest, NotInvocableIfConstLvalueCallDeleted) {
+  using F0 = decltype(absl::bind_front<DeletedConstLvalueCall{}>());
+  static_assert(!std::is_invocable_v<F0&>);
+  static_assert(!std::is_invocable_v<const F0&>);
+  static_assert(!std::is_invocable_v<F0>);
+  static_assert(!std::is_invocable_v<const F0>);
+
+  using F1 = decltype(absl::bind_front<DeletedConstLvalueCall{}>(1));
+  static_assert(!std::is_invocable_v<F1&>);
+  static_assert(!std::is_invocable_v<const F1&>);
+  static_assert(!std::is_invocable_v<F1>);
+  static_assert(!std::is_invocable_v<const F1>);
+}
+#endif  // ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
+
 }  // namespace
diff --git a/absl/functional/internal/front_binder.h b/absl/functional/internal/front_binder.h
index fcada9c..33d4fb4 100644
--- a/absl/functional/internal/front_binder.h
+++ b/absl/functional/internal/front_binder.h
@@ -18,6 +18,7 @@
 #define ABSL_FUNCTIONAL_INTERNAL_FRONT_BINDER_H_
 
 #include <cstddef>
+#include <functional>
 #include <type_traits>
 #include <utility>
 
@@ -87,6 +88,34 @@
 template <class F, class... BoundArgs>
 using bind_front_t = FrontBinder<std::decay_t<F>, std::decay_t<BoundArgs>...>;
 
+// Stateless invoker for the compile-time constant target `ConstFn` of
+// `absl::bind_front<ConstFn>(args...)` (C++26 [func.bind.front]).
+//
+// `operator()` has a trailing `decltype(std::invoke(ConstFn, ...))` return type
+// rather than `decltype(auto)` so that an invalid call is a substitution
+// failure instead of a hard error. Deducing a `decltype(auto)` return type
+// instantiates the body, so merely checking whether a call is valid would fail
+// to compile. That would break `std::is_invocable` and overload resolution,
+// including among the call operators of a `bind_front` result wrapping the
+// invoker: e.g. calling such a result as an rvalue fails if it holds a
+// move-only bound argument, because its `const&` overload is also considered.
+//
+// The return type is `decltype(std::invoke(ConstFn, ...))` rather than
+// `std::invoke_result_t<decltype(ConstFn), ...>` because for C++20 class-type
+// non-type template parameters, `decltype(ConstFn)` is the unqualified type `F`
+// (which `std::invoke_result_t` treats as an rvalue `F&&`), whereas the
+// template parameter expression `ConstFn` is a `const F` lvalue as specified by
+// [func.bind.front].
+template <auto ConstFn>
+struct ConstFnInvoker {
+  template <class... FreeArgs>
+  constexpr auto operator()(FreeArgs&&... free_args) const noexcept(
+      noexcept(std::invoke(ConstFn, std::forward<FreeArgs>(free_args)...)))
+      -> decltype(std::invoke(ConstFn, std::forward<FreeArgs>(free_args)...)) {
+    return std::invoke(ConstFn, std::forward<FreeArgs>(free_args)...);
+  }
+};
+
 }  // namespace functional_internal
 ABSL_NAMESPACE_END
 }  // namespace absl