@@ -909,6 +909,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
@@ -1246,6 +1246,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 =
new file mode 100644
@@ -0,0 +1,111 @@
+// 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
+
+namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
+{
+namespace __detail
+{
+ template<typename _Tp>
+ concept __signed_or_unsigned_integer_type
+ = std::__is_signed_integer<_Tp>::value
+ || std::__is_unsigned_integer<_Tp>::value;
+
+ template<typename _Tp>
+ concept __cv_unqual_signed_or_unsigned_integer_type
+ = std::same_as<_Tp, std::remove_cvref_t<_Tp>>
+ && __signed_or_unsigned_integer_type<_Tp>;
+}
+
+/** 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);
+ }
+/// @}
+}
+
+using __gnu_cxx::ckd_add;
+using __gnu_cxx::ckd_sub;
+using __gnu_cxx::ckd_mul;
+
+#endif // C++23
+
+#endif // _GLIBCXX_STDCKDINT_H
@@ -127,6 +127,14 @@ export
using __gnu_cxx::stdc_bit_ceil;
}
+// <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.
new file mode 100644
@@ -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();
+}
new file mode 100644
@@ -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'" }