summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2022-08-09 23:20:49 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2022-08-10 00:22:09 -0700
commit2eb92c362ecfb2dae9c9cb37cb9246df6989181c (patch)
tree298053737c12bfc1144936111b7763b53ae51be7 /lib
parent9331caeffae1b7b5f49b65c98c2ff9cc8f3691fd (diff)
downloadgnulib-2eb92c362ecfb2dae9c9cb37cb9246df6989181c.tar.gz
stdckdint-h: new module
This supports draft C23 <stdckdint.h>. * doc/posix-headers/stdckdint.texi: * lib/stdckdint.in.h, modules/stdckdint: * modules/stdckdint-tests, tests/test-stdckdint.c: New files. * MODULES.html.sh, doc/gnulib.texi: Update for new module. * lib/intprops-internal.h: Include <stdckdint.h> if C23 and its macros would help and our substitute has not already started to be included. (_GL_INT_ADD_WRAPV, _GL_INT_SUBTRACT_WRAPV) (_GL_INT_MULTIPLY_WRAPV): Use ckd_add, ckd_sub, ckd_mul if they are defined and would help. * lib/intprops-internal.h, lib/intprops.h: Improve comments. The C23 restrictions on stdckdint macros already mostly applied to intprops.h, so these are clarifications, not further restrictions. * tests/test-intprops.c: If TEST_STDCKDINT is defined, include <stdckdint.h> instead of "intprops.h", and test it instead. (VERIFY) [TEST_STDCKDINT]: Ignore the arg in this case. (main) [TEST_STDCKDINT]: Skip tests irrelevant to stdckdint.h.
Diffstat (limited to 'lib')
-rw-r--r--lib/intprops-internal.h40
-rw-r--r--lib/intprops.h11
-rw-r--r--lib/stdckdint.in.h37
3 files changed, 77 insertions, 11 deletions
diff --git a/lib/intprops-internal.h b/lib/intprops-internal.h
index 11c5ba979a..f6455f7855 100644
--- a/lib/intprops-internal.h
+++ b/lib/intprops-internal.h
@@ -92,8 +92,8 @@
#endif
/* Return 1 if - A would overflow in [MIN,MAX] arithmetic.
- Arguments should not have side effects, and A's type should have
- minimum value MIN and maximum MAX. */
+ A should not have side effects, and A's type should be an
+ integer with minimum value MIN and maximum MAX. */
#define _GL_INT_NEGATE_RANGE_OVERFLOW(a, min, max) \
((min) < 0 ? (a) < - (max) : 0 < (a))
@@ -134,11 +134,21 @@
# define _GL_HAS_BUILTIN_OVERFLOW_P (7 <= __GNUC__)
#endif
+#if (!defined _GL_STDCKDINT_H && 202311 <= __STDC_VERSION__ \
+ && ! (_GL_HAS_BUILTIN_ADD_OVERFLOW && _GL_HAS_BUILTIN_MUL_OVERFLOW))
+# include <stdckdint.h>
+#endif
+
/* Store the low-order bits of A + B, A - B, A * B, respectively, into *R.
- Return 1 if the result overflows. See above for restrictions. */
+ Return 1 if the result overflows. Arguments should not have side
+ effects and A, B and *R can be of any integer type other than char,
+ bool, a bit-precise integer type, or an enumeration type. */
#if _GL_HAS_BUILTIN_ADD_OVERFLOW
# define _GL_INT_ADD_WRAPV(a, b, r) __builtin_add_overflow (a, b, r)
# define _GL_INT_SUBTRACT_WRAPV(a, b, r) __builtin_sub_overflow (a, b, r)
+#elif defined ckd_add && defined ckd_sub && !defined _GL_STDCKDINT_H
+# define _GL_INT_ADD_WRAPV(a, b, r) ckd_add (r, + (a), + (b))
+# define _GL_INT_SUBTRACT_WRAPV(a, b, r) ckd_sub (r, + (a), + (b))
#else
# define _GL_INT_ADD_WRAPV(a, b, r) \
_GL_INT_OP_WRAPV (a, b, r, +, _GL_INT_ADD_RANGE_OVERFLOW)
@@ -158,6 +168,8 @@
? ((void) __builtin_mul_overflow (a, b, r), 1) \
: __builtin_mul_overflow (a, b, r))
# endif
+#elif defined ckd_mul && !defined _GL_STDCKDINT_H
+# define _GL_INT_MULTIPLY_WRAPV(a, b, r) ckd_mul (r, + (a), + (b))
#else
# define _GL_INT_MULTIPLY_WRAPV(a, b, r) \
_GL_INT_OP_WRAPV (a, b, r, *, _GL_INT_MULTIPLY_RANGE_OVERFLOW)
@@ -177,7 +189,9 @@
/* Store the low-order bits of A <op> B into *R, where OP specifies
the operation and OVERFLOW the overflow predicate. Return 1 if the
- result overflows. See above for restrictions. */
+ result overflows. Arguments should not have side effects,
+ and A, B and *R can be of any integer type other than char, bool, a
+ bit-precise integer type, or an enumeration type. */
#if 201112 <= __STDC_VERSION__ && !_GL__GENERIC_BOGUS
# define _GL_INT_OP_WRAPV(a, b, r, op, overflow) \
(_Generic \
@@ -217,7 +231,9 @@
the operation and OVERFLOW the overflow predicate. If *R is
signed, its type is ST with bounds SMIN..SMAX; otherwise its type
is UT with bounds U..UMAX. ST and UT are narrower than int.
- Return 1 if the result overflows. See above for restrictions. */
+ Return 1 if the result overflows. Arguments should not have side
+ effects, and A, B and *R can be of any integer type other than
+ char, bool, a bit-precise integer type, or an enumeration type. */
# if _GL_HAVE___TYPEOF__
# define _GL_INT_OP_WRAPV_SMALLISH(a,b,r,op,overflow,st,smin,smax,ut,umax) \
(_GL_TYPE_SIGNED (__typeof__ (*(r))) \
@@ -276,14 +292,18 @@
/* Store the low-order bits of A <op> B into *R, where the operation
is given by OP. Use the unsigned type UT for calculation to avoid
overflow problems. *R's type is T, with extrema TMIN and TMAX.
- T must be a signed integer type. Return 1 if the result overflows. */
+ T can be any signed integer type other than char, bool, a
+ bit-precise integer type, or an enumeration type.
+ Return 1 if the result overflows. */
#define _GL_INT_OP_CALC(a, b, r, op, overflow, ut, t, tmin, tmax) \
(overflow (a, b, tmin, tmax) \
? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 1) \
: (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 0))
/* Return 1 if the integer expressions A - B and -A would overflow,
- respectively. Arguments should not have side effects.
+ respectively. Arguments should not have side effects,
+ and can be any signed integer type other than char, bool, a
+ bit-precise integer type, or an enumeration type.
These macros are tuned for their last input argument being a constant. */
#if _GL_HAS_BUILTIN_OVERFLOW_P
@@ -315,8 +335,10 @@
((t) ((ut) (a) op (ut) (b)))
/* Return true if the numeric values A + B, A - B, A * B fall outside
- the range TMIN..TMAX. Arguments should be integer expressions
- without side effects. TMIN should be signed and nonpositive.
+ the range TMIN..TMAX. Arguments should not have side effects
+ and can be any integer type other than char, bool,
+ a bit-precise integer type, or an enumeration type.
+ TMIN should be signed and nonpositive.
TMAX should be positive, and should be signed unless TMIN is zero. */
#define _GL_INT_ADD_RANGE_OVERFLOW(a, b, tmin, tmax) \
((b) < 0 \
diff --git a/lib/intprops.h b/lib/intprops.h
index 3899262d5f..b911384532 100644
--- a/lib/intprops.h
+++ b/lib/intprops.h
@@ -256,13 +256,18 @@
Because the WRAPV macros convert the result, they report overflow
in different circumstances than the OVERFLOW macros do. For
example, in the typical case with 16-bit 'short' and 32-bit 'int',
- if A, B and R are all of type 'short' then INT_ADD_OVERFLOW (A, B)
+ if A, B and *R are all of type 'short' then INT_ADD_OVERFLOW (A, B)
returns false because the addition cannot overflow after A and B
- are converted to 'int', whereas INT_ADD_WRAPV (A, B, &R) returns
+ are converted to 'int', whereas INT_ADD_WRAPV (A, B, R) returns
true or false depending on whether the sum fits into 'short'.
These macros are tuned for their last input argument being a constant.
+ A, B, and *R should be integers; they need not be the same type,
+ and they need not be all signed or all unsigned.
+ However, none of the integer types should be bit-precise,
+ and *R's type should not be char, bool, or an enumeration type.
+
Return 1 if the integer expressions A * B, A - B, -A, A * B, A / B,
A % B, and A << B would overflow, respectively. */
@@ -310,6 +315,8 @@
A, B, and *R should be integers; they need not be the same type,
and they need not be all signed or all unsigned.
+ However, none of the integer types should be bit-precise,
+ and *R's type should not be char, bool, or an enumeration type.
These macros work correctly on all known practical hosts, and do not rely
on undefined behavior due to signed arithmetic overflow.
diff --git a/lib/stdckdint.in.h b/lib/stdckdint.in.h
new file mode 100644
index 0000000000..90fa62e596
--- /dev/null
+++ b/lib/stdckdint.in.h
@@ -0,0 +1,37 @@
+/* stdckdint.h -- checked integer arithmetic
+
+ Copyright 2022 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ This program 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+#ifndef _GL_STDCKDINT_H
+#define _GL_STDCKDINT_H
+
+#include "intprops-internal.h"
+
+#include <stdbool.h>
+
+/* Store into *R the low-order bits of A + B, A - B, A * B, respectively.
+ Return 1 if the result overflows, 0 otherwise.
+ A, B, and *R can have any integer type other than char, bool, a
+ bit-precise integer type, or an enumeration type.
+
+ These are like the standard macros introduced in C23, except that
+ arguments should not have side effects. */
+
+#define ckd_add(r, a, b) ((bool) _GL_INT_ADD_WRAPV (a, b, r))
+#define ckd_sub(r, a, b) ((bool) _GL_INT_SUBTRACT_WRAPV (a, b, r))
+#define ckd_mul(r, a, b) ((bool) _GL_INT_MULTIPLY_WRAPV (a, b, r))
+
+#endif /* _GL_STDCKDINT_H */