diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index a8ff87fb600..4dc771a540c 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -912,6 +912,7 @@ c_compatibility_headers = \
 	${c_compatibility_srcdir}/math.h \
 	${c_compatibility_srcdir}/stdatomic.h \
 	${c_compatibility_srcdir}/stdbit.h \
+	${c_compatibility_srcdir}/stdckdint.h \
 	${c_compatibility_srcdir}/stdlib.h
 endif
 
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index 859cbee53d6..0e3d09b3a75 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -1249,6 +1249,7 @@ c_compatibility_builddir = .
 @GLIBCXX_C_HEADERS_C_GLOBAL_TRUE@	${c_compatibility_srcdir}/math.h \
 @GLIBCXX_C_HEADERS_C_GLOBAL_TRUE@	${c_compatibility_srcdir}/stdatomic.h \
 @GLIBCXX_C_HEADERS_C_GLOBAL_TRUE@	${c_compatibility_srcdir}/stdbit.h \
+@GLIBCXX_C_HEADERS_C_GLOBAL_TRUE@	${c_compatibility_srcdir}/stdckdint.h \
 @GLIBCXX_C_HEADERS_C_GLOBAL_TRUE@	${c_compatibility_srcdir}/stdlib.h
 
 @GLIBCXX_C_HEADERS_C_STD_TRUE@c_compatibility_headers = 
diff --git a/libstdc++-v3/include/c_compatibility/stdckdint.h b/libstdc++-v3/include/c_compatibility/stdckdint.h
new file mode 100644
index 00000000000..1de2d18dc1a
--- /dev/null
+++ b/libstdc++-v3/include/c_compatibility/stdckdint.h
@@ -0,0 +1,113 @@
+// C compatibility header <stdckdint.h> -*- C++ -*-
+
+// Copyright The GNU Toolchain Authors.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/stdckdint.h
+ *  This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_STDCKDINT_H
+#define _GLIBCXX_STDCKDINT_H
+
+#if __cplusplus > 202302L
+#include <type_traits>
+#include <concepts>
+
+#define __STDC_VERSION_STDCKDINT_H__ 202311L
+
+#ifndef _GLIBCXX_DOXYGEN
+// We define these in our own namespace, but let Doxygen think otherwise.
+namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
+{
+#endif
+/// @cond undocumented
+namespace __detail
+{
+  template<typename _Tp>
+    concept __cv_unqual_signed_or_unsigned_integer_type
+      = std::same_as<_Tp, std::remove_cv_t<_Tp>>
+	  && std::__is_standard_integer<_Tp>::value;
+}
+/// @endcond
+
+/** Checked integer arithmetic
+ *
+ * Performs arithmetic on `__a` and `__b` and stores the result in `*__result`,
+ * with overflow detection.
+ * The arithmetic is performed in infinite signed precision, without overflow,
+ * then converted to the result type, `_Tp1`. If the converted result is not
+ * equal to the infinite precision result, the stored result is wrapped to the
+ * width of `_Tp1` and `true` is returned. Otherwise, the stored result is
+ * correct and `false` is returned.
+ *
+ * @param __result A pointer to a signed or unsigned integer type.
+ * @param __a      A signed or unsigned integer type.
+ * @param __b      A signed or unsigned integer type.
+ * @return True if overflow occurred, false otherwise.
+ * @since C++26
+ * @{
+ */
+template<typename _Tp1, typename _Tp2, typename _Tp3>
+  inline bool
+  ckd_add(_Tp1* __result, _Tp2 __a, _Tp3 __b)
+  {
+    using __gnu_cxx::__detail::__cv_unqual_signed_or_unsigned_integer_type;
+    static_assert(__cv_unqual_signed_or_unsigned_integer_type<_Tp1>);
+    static_assert(__cv_unqual_signed_or_unsigned_integer_type<_Tp2>);
+    static_assert(__cv_unqual_signed_or_unsigned_integer_type<_Tp3>);
+    return __builtin_add_overflow(__a, __b, __result);
+  }
+
+template<typename _Tp1, typename _Tp2, typename _Tp3>
+  inline bool
+  ckd_sub(_Tp1* __result, _Tp2 __a, _Tp3 __b)
+  {
+    using __gnu_cxx::__detail::__cv_unqual_signed_or_unsigned_integer_type;
+    static_assert(__cv_unqual_signed_or_unsigned_integer_type<_Tp1>);
+    static_assert(__cv_unqual_signed_or_unsigned_integer_type<_Tp2>);
+    static_assert(__cv_unqual_signed_or_unsigned_integer_type<_Tp3>);
+    return __builtin_sub_overflow(__a, __b, __result);
+  }
+
+template<typename _Tp1, typename _Tp2, typename _Tp3>
+  inline bool
+  ckd_mul(_Tp1* __result, _Tp2 __a, _Tp3 __b)
+  {
+    using __gnu_cxx::__detail::__cv_unqual_signed_or_unsigned_integer_type;
+    static_assert(__cv_unqual_signed_or_unsigned_integer_type<_Tp1>);
+    static_assert(__cv_unqual_signed_or_unsigned_integer_type<_Tp2>);
+    static_assert(__cv_unqual_signed_or_unsigned_integer_type<_Tp3>);
+    return __builtin_mul_overflow(__a, __b, __result);
+  }
+/// @}
+#ifndef _GLIBCXX_DOXYGEN
+}
+
+using __gnu_cxx::ckd_add;
+using __gnu_cxx::ckd_sub;
+using __gnu_cxx::ckd_mul;
+#endif
+
+#endif // C++26
+
+#endif // _GLIBCXX_STDCKDINT_H
diff --git a/libstdc++-v3/src/c++23/std.compat.cc.in b/libstdc++-v3/src/c++23/std.compat.cc.in
index 3c25295850f..ba7ed0312ab 100644
--- a/libstdc++-v3/src/c++23/std.compat.cc.in
+++ b/libstdc++-v3/src/c++23/std.compat.cc.in
@@ -53,6 +53,14 @@ _GLIBCXX_STDBIT_FUNC(stdc_bit_ceil);
 #undef _GLIBCXX_STDBIT_FUNC
 }
 
+// <stdckdint.h>
+export
+{
+  using __gnu_cxx::ckd_add;
+  using __gnu_cxx::ckd_sub;
+  using __gnu_cxx::ckd_mul;
+}
+
 #define STD_COMPAT 1
 
 // C library exports are appended from std-clib.cc.in.
diff --git a/libstdc++-v3/testsuite/26_numerics/stdckdint/1.cc b/libstdc++-v3/testsuite/26_numerics/stdckdint/1.cc
new file mode 100644
index 00000000000..1402c834a7e
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/stdckdint/1.cc
@@ -0,0 +1,63 @@
+// { dg-do run { target c++26 } }
+
+#include <stdckdint.h>
+
+#if __STDC_VERSION_STDCKDINT_H__ != 202311L
+# error "__STDC_VERSION_STDCKDINT_H__ not defined correctly in <stdckdint.h>"
+#endif
+
+#include <limits.h>
+#include <testsuite_hooks.h>
+
+void
+test_add()
+{
+  int result;
+  bool overflow;
+
+  overflow = ::ckd_add(&result, (unsigned)INT_MAX, 1LL);
+  VERIFY( overflow );
+  VERIFY( result == INT_MIN );
+
+  overflow = ::ckd_add(&result, (long long)INT_MIN, -1);
+  VERIFY( overflow );
+  VERIFY( result == INT_MAX );
+
+  overflow = ::ckd_add(&result, 99u, 100ll);
+  VERIFY( ! overflow );
+  VERIFY( result == 199 );
+}
+
+void
+test_sub()
+{
+  int result;
+  bool overflow;
+
+  overflow = ::ckd_sub(&result, -1, -5);
+  VERIFY( ! overflow );
+  VERIFY( result == 4 );
+}
+
+void
+test_mul()
+{
+  long long result;
+  bool overflow;
+
+  overflow = ::ckd_mul(&result, INT_MIN, -1);
+  VERIFY( ! overflow );
+  VERIFY( result == -(long long)INT_MIN );
+
+  unsigned uresult;
+  overflow = ::ckd_mul(&uresult, INT_MIN, -1);
+  VERIFY( ! overflow );
+  VERIFY( result == (unsigned)INT_MAX + 1u );
+}
+
+int main()
+{
+  test_add();
+  test_sub();
+  test_mul();
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/stdckdint/2_neg.cc b/libstdc++-v3/testsuite/26_numerics/stdckdint/2_neg.cc
new file mode 100644
index 00000000000..7954da2d0d9
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/stdckdint/2_neg.cc
@@ -0,0 +1,39 @@
+// { dg-do compile { target c++26 } }
+
+#include <stdckdint.h>
+
+void
+test_add(int i, char c, bool b)
+{
+  ::ckd_add(&i, c, 1); // { dg-error "here" }
+  ::ckd_add(&i, 1, c); // { dg-error "here" }
+  ::ckd_add(&i, b, 2); // { dg-error "here" }
+  ::ckd_add(&i, 2, b); // { dg-error "here" }
+  ::ckd_add(&c, 3, 3); // { dg-error "here" }
+  ::ckd_add((const int*)&i, 4, 4); // { dg-error "here" }
+}
+
+void
+test_sub(int i, char c, bool b)
+{
+  ::ckd_sub(&i, c, 1); // { dg-error "here" }
+  ::ckd_sub(&i, 1, c); // { dg-error "here" }
+  ::ckd_sub(&i, b, 2); // { dg-error "here" }
+  ::ckd_sub(&i, 2, b); // { dg-error "here" }
+  ::ckd_sub(&c, 3, 3); // { dg-error "here" }
+  ::ckd_sub((const int*)&i, 4, 4); // { dg-error "here" }
+}
+
+void
+test_mul(int i, char c, bool b)
+{
+  ::ckd_mul(&i, c, 1); // { dg-error "here" }
+  ::ckd_mul(&i, 1, c); // { dg-error "here" }
+  ::ckd_mul(&i, b, 2); // { dg-error "here" }
+  ::ckd_mul(&i, 2, b); // { dg-error "here" }
+  ::ckd_mul(&c, 3, 3); // { dg-error "here" }
+  ::ckd_mul((const int*)&i, 4, 4); // { dg-error "here" }
+}
+
+// { dg-prune-output "static assertion failed" }
+// { dg-prune-output "pointer to 'const'" }
