From 2eb92c362ecfb2dae9c9cb37cb9246df6989181c Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 9 Aug 2022 23:20:49 -0700 Subject: [PATCH 4/6] stdckdint-h: new module This supports draft C23 . * 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 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 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. --- ChangeLog | 22 ++++++++++++++++ MODULES.html.sh | 15 +++++++++++ doc/gnulib.texi | 2 ++ doc/posix-headers/stdckdint.texi | 21 +++++++++++++++ lib/intprops-internal.h | 40 +++++++++++++++++++++------- lib/intprops.h | 11 ++++++-- lib/stdckdint.in.h | 37 ++++++++++++++++++++++++++ modules/stdckdint | 45 ++++++++++++++++++++++++++++++++ modules/stdckdint-tests | 15 +++++++++++ tests/test-intprops.c | 13 +++++++-- tests/test-stdckdint.c | 30 +++++++++++++++++++++ 11 files changed, 238 insertions(+), 13 deletions(-) create mode 100644 doc/posix-headers/stdckdint.texi create mode 100644 lib/stdckdint.in.h create mode 100644 modules/stdckdint create mode 100644 modules/stdckdint-tests create mode 100644 tests/test-stdckdint.c diff --git a/ChangeLog b/ChangeLog index e977f75b65..20c25c902a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,27 @@ 2022-08-09 Paul Eggert + stdckdint: new module + This supports draft C23 . + * 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 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 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. + intprops: refactor intprops.h into two * lib/intprops.h: Include new file intprops-internal.h. (_GL_INT_CONVERT, _GL_INT_NEGATE_CONVERT, _GL_INT_MINIMUM) diff --git a/MODULES.html.sh b/MODULES.html.sh index 03b72a4a9f..d48912b13e 100755 --- a/MODULES.html.sh +++ b/MODULES.html.sh @@ -2371,6 +2371,21 @@ func_all_modules () func_module limits-h func_end_table + element="Support for systems lacking draft ISO C 23" + func_section_wrap c23_ext + func_wrap H2 + func_echo "$element" + + element="Core language properties" + element=`printf "%s" "$element" | sed -e "$sed_lt" -e "$sed_gt"` + func_section_wrap c23_core_properties + func_wrap H3 + func_echo "$element" + + func_begin_table + func_module stdckdint + func_end_table + element="Support for GNU multiple precision arithmetic" func_section_wrap gmp func_wrap H2 diff --git a/doc/gnulib.texi b/doc/gnulib.texi index 8d24699216..ec5891e57f 100644 --- a/doc/gnulib.texi +++ b/doc/gnulib.texi @@ -913,6 +913,7 @@ which (known) portability problems are not worked around by Gnulib. * stdalign.h:: * stdarg.h:: * stdbool.h:: +* stdckdint.h:: * stddef.h:: * stdint.h:: * stdio.h:: @@ -1003,6 +1004,7 @@ which (known) portability problems are not worked around by Gnulib. @include posix-headers/stdalign.texi @include posix-headers/stdarg.texi @include posix-headers/stdbool.texi +@include posix-headers/stdckdint.texi @include posix-headers/stddef.texi @include posix-headers/stdint.texi @include posix-headers/stdio.texi diff --git a/doc/posix-headers/stdckdint.texi b/doc/posix-headers/stdckdint.texi new file mode 100644 index 0000000000..915174f696 --- /dev/null +++ b/doc/posix-headers/stdckdint.texi @@ -0,0 +1,21 @@ +@node stdckdint.h +@section @file{stdckdint.h} + +POSIX specification:@* Not in POSIX yet, but we expect it will be. +ISO draft C23 +(@url{https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3047.pdf}) +section 7.20. + +Gnulib module: stdckdint + +Portability problems fixed by Gnulib: +@itemize +@item +This header file is missing on many platforms. +@end itemize + +Portability problems not fixed by Gnulib: +@itemize +@item +In draft C23, arguments of @code{stdckdint.h} macros can have side effects. +@end itemize 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 +#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 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 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 . */ + +#ifndef _GL_STDCKDINT_H +#define _GL_STDCKDINT_H + +#include "intprops-internal.h" + +#include + +/* 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 */ diff --git a/modules/stdckdint b/modules/stdckdint new file mode 100644 index 0000000000..4b39a76d5f --- /dev/null +++ b/modules/stdckdint @@ -0,0 +1,45 @@ +Description: +An that is like C23. + +Files: +lib/stdckdint.in.h +lib/intprops-internal.h + +Depends-on: +gen-header + +configure.ac: +AC_CHECK_HEADERS_ONCE([stdckdint.h]) +if test $ac_cv_header_stdckdint_h = yes; then + GL_GENERATE_STDCKDINT_H=false +else + GL_GENERATE_STDCKDINT_H=true +fi +gl_CONDITIONAL_HEADER([stdckdint.h]) +AC_PROG_MKDIR_P + +Makefile.am: +BUILT_SOURCES += $(STDCKDINT_H) + +# We need the following in order to create when the system +# doesn't have one that works with the given compiler. +if GL_GENERATE_STDCKDINT_H +stdckdint.h: stdckdint.in.h $(top_builddir)/config.status +@NMD@ $(AM_V_GEN)$(MKDIR_P) '%reldir%' + $(gl_V_at)$(SED_HEADER_STDOUT) \ + $(srcdir)/stdckdint.in.h > $@-t + $(AM_V_at)mv $@-t $@ +else +stdckdint.h: $(top_builddir)/config.status + rm -f $@ +endif +MOSTLYCLEANFILES += stdckdint.h stdckdint.h-t + +Include: + + +License: +LGPLv2+ + +Maintainer: +Paul Eggert diff --git a/modules/stdckdint-tests b/modules/stdckdint-tests new file mode 100644 index 0000000000..153a1fbb42 --- /dev/null +++ b/modules/stdckdint-tests @@ -0,0 +1,15 @@ +Files: +tests/macros.h +tests/test-intprops.c +tests/test-stdckdint.c + +Depends-on: +inttypes +stdbool +verify + +configure.ac: + +Makefile.am: +TESTS += test-stdckdint +check_PROGRAMS += test-stdckdint diff --git a/tests/test-intprops.c b/tests/test-intprops.c index 277746a001..a46e9c5e4a 100644 --- a/tests/test-intprops.c +++ b/tests/test-intprops.c @@ -30,7 +30,11 @@ #include -#include "intprops.h" +#ifdef TEST_STDCKDINT +# include +#else +# include "intprops.h" +#endif #include "verify.h" #include @@ -45,10 +49,13 @@ /* VERIFY (X) uses a static assertion for compilers that are known to work, and falls back on a dynamic assertion for other compilers. + But it ignores X if testing stdckdint.h. These tests should be checkable via 'verify' rather than 'ASSERT', but using 'verify' would run into a bug with HP-UX 11.23 cc; see . */ -#if __GNUC__ || __clang__ || __SUNPRO_C +#ifdef TEST_STDCKDINT +# define VERIFY(x) ((void) 0) +#elif __GNUC__ || __clang__ || __SUNPRO_C # define VERIFY(x) verify_stmt (x) #else # define VERIFY(x) ASSERT (x) @@ -65,6 +72,7 @@ main (void) /* Use VERIFY for tests that must be integer constant expressions, ASSERT otherwise. */ +#ifndef TEST_STDCKDINT /* TYPE_IS_INTEGER. */ ASSERT (TYPE_IS_INTEGER (bool)); ASSERT (TYPE_IS_INTEGER (char)); @@ -161,6 +169,7 @@ main (void) VERIFY (INT_STRLEN_BOUND (int64_t) == sizeof ("-9223372036854775808") - 1); VERIFY (INT_BUFSIZE_BOUND (int64_t) == sizeof ("-9223372036854775808")); #endif +#endif /* All the INT__RANGE_OVERFLOW tests are equally valid as INT__OVERFLOW tests, so define macros to do both. OP is the diff --git a/tests/test-stdckdint.c b/tests/test-stdckdint.c new file mode 100644 index 0000000000..c19525518c --- /dev/null +++ b/tests/test-stdckdint.c @@ -0,0 +1,30 @@ +/* Test . + 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 General Public License as published by + the Free Software Foundation, either version 3 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Written by Paul Eggert. */ + +/* Tell test-intprops.c to test instead of . */ + +#define TEST_STDCKDINT 1 + +#define INT_ADD_WRAPV(a, b, r) ckd_add (r, a, b) +#define INT_SUBTRACT_WRAPV(a, b, r) ckd_sub (r, a, b) +#define INT_MULTIPLY_WRAPV(a, b, r) ckd_mul (r, a, b) + +/* Luckily, test-intprops.c uses INT_NEGATE_OVERFLOW only on INT_MIN. */ +#define INT_NEGATE_OVERFLOW(a) ((a) < -INT_MAX) + +#include "test-intprops.c" -- 2.34.1