/* intprops.h -- properties of integer types
- Copyright (C) 2001-2020 Free Software Foundation, Inc.
+ Copyright (C) 2001-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
+ 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 General Public License for more details.
+ GNU Lesser General Public License for more details.
- You should have received a copy of the GNU General Public License
+ 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/>. */
-/* Written by Paul Eggert. */
#ifndef _GL_INTPROPS_H
#define _GL_INTPROPS_H
/* Minimum and maximum values for integer types and expressions. */
/* The width in bits of the integer type or expression T.
- Do not evaluate T.
+ Do not evaluate T. T must not be a bit-field expression.
Padding bits are not supported; this is checked at compile-time below. */
#define TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT)
? _GL_SIGNED_INT_MAXIMUM (e) \
: _GL_INT_NEGATE_CONVERT (e, 1))
#define _GL_SIGNED_INT_MAXIMUM(e) \
- (((_GL_INT_CONVERT (e, 1) << (TYPE_WIDTH ((e) + 0) - 2)) - 1) * 2 + 1)
+ (((_GL_INT_CONVERT (e, 1) << (TYPE_WIDTH (+ (e)) - 2)) - 1) * 2 + 1)
/* Work around OpenVMS incompatibility with C99. */
#if !defined LLONG_MAX && defined __INT64_MAX
/* Does the __typeof__ keyword work? This could be done by
'configure', but for now it's easier to do it by hand. */
#if (2 <= __GNUC__ \
+ || (4 <= __clang_major__) \
|| (1210 <= __IBMC__ && defined __IBM__TYPEOF__) \
|| (0x5110 <= __SUNPRO_C && !__STDC__))
# define _GL_HAVE___TYPEOF__ 1
#endif
/* Return 1 if the integer type or expression T might be signed. Return 0
- if it is definitely unsigned. This macro does not evaluate its argument,
- and expands to an integer constant expression. */
+ if it is definitely unsigned. T must not be a bit-field expression.
+ This macro does not evaluate its argument, and expands to an
+ integer constant expression. */
#if _GL_HAVE___TYPEOF__
# define _GL_SIGNED_TYPE_OR_EXPR(t) TYPE_SIGNED (__typeof__ (t))
#else
#define INT_BITS_STRLEN_BOUND(b) (((b) * 146 + 484) / 485)
/* Bound on length of the string representing an integer type or expression T.
+ T must not be a bit-field expression.
+
Subtract 1 for the sign bit if T is signed, and then add 1 more for
a minus sign if needed.
+ _GL_SIGNED_TYPE_OR_EXPR (t))
/* Bound on buffer size needed to represent an integer type or expression T,
- including the terminating null. */
+ including the terminating null. T must not be a bit-field expression. */
#define INT_BUFSIZE_BOUND(t) (INT_STRLEN_BOUND (t) + 1)
operators might not yield numerically correct answers due to
arithmetic overflow. They do not rely on undefined or
implementation-defined behavior. Their implementations are simple
- and straightforward, but they are a bit harder to use than the
+ and straightforward, but they are harder to use and may be less
+ efficient than the INT_<op>_WRAPV, INT_<op>_OK, and
INT_<op>_OVERFLOW macros described below.
Example usage:
must have minimum value MIN and maximum MAX. Unsigned types should
use a zero MIN of the proper type.
+ Because all arguments are subject to integer promotions, these
+ macros typically do not work on types narrower than 'int'.
+
These macros are tuned for constant MIN and MAX. For commutative
operations such as A + B, they are also tuned for constant B. */
/* True if __builtin_add_overflow (A, B, P) and __builtin_sub_overflow
(A, B, P) work when P is non-null. */
-#if 5 <= __GNUC__ && !defined __ICC
-# define _GL_HAS_BUILTIN_ADD_OVERFLOW 1
+#ifdef __EDG__
+/* EDG-based compilers like nvc 22.1 cannot add 64-bit signed to unsigned
+ <https://bugs.gnu.org/53256>. */
+# define _GL_HAS_BUILTIN_ADD_OVERFLOW 0
#elif defined __has_builtin
# define _GL_HAS_BUILTIN_ADD_OVERFLOW __has_builtin (__builtin_add_overflow)
+/* __builtin_{add,sub}_overflow exists but is not reliable in GCC 5.x and 6.x,
+ see <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98269>. */
+#elif 7 <= __GNUC__
+# define _GL_HAS_BUILTIN_ADD_OVERFLOW 1
#else
# define _GL_HAS_BUILTIN_ADD_OVERFLOW 0
#endif
/* True if __builtin_mul_overflow (A, B, P) works when P is non-null. */
-#ifdef __clang__
+#if defined __clang_major__ && __clang_major__ < 14
/* Work around Clang bug <https://bugs.llvm.org/show_bug.cgi?id=16404>. */
# define _GL_HAS_BUILTIN_MUL_OVERFLOW 0
#else
#endif
/* True if __builtin_add_overflow_p (A, B, C) works, and similarly for
- __builtin_mul_overflow_p and __builtin_mul_overflow_p. */
-#define _GL_HAS_BUILTIN_OVERFLOW_P (7 <= __GNUC__)
+ __builtin_sub_overflow_p and __builtin_mul_overflow_p. */
+#ifdef __EDG__
+/* In EDG-based compilers like ICC 2021.3 and earlier,
+ __builtin_add_overflow_p etc. are not treated as integral constant
+ expressions even when all arguments are. */
+# define _GL_HAS_BUILTIN_OVERFLOW_P 0
+#elif defined __has_builtin
+# define _GL_HAS_BUILTIN_OVERFLOW_P __has_builtin (__builtin_mul_overflow_p)
+#else
+# define _GL_HAS_BUILTIN_OVERFLOW_P (7 <= __GNUC__)
+#endif
/* The _GL*_OVERFLOW macros have the same restrictions as the
*_RANGE_OVERFLOW macros, except that they do not assume that operands
arguments should not have side effects.
The WRAPV macros are not constant expressions. They support only
- +, binary -, and *. Because the WRAPV macros convert the result,
- they report overflow in different circumstances than the OVERFLOW
- macros do.
+ +, binary -, and *.
+
+ 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)
+ returns false because the addition cannot overflow after A and B
+ 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.
_GL_INT_OP_WRAPV (a, b, r, -, _GL_INT_SUBTRACT_RANGE_OVERFLOW)
#endif
#if _GL_HAS_BUILTIN_MUL_OVERFLOW
-# if (9 < __GNUC__ + (3 <= __GNUC_MINOR__) \
- || (__GNUC__ == 8 && 4 <= __GNUC_MINOR__))
+# if ((9 < __GNUC__ + (3 <= __GNUC_MINOR__) \
+ || (__GNUC__ == 8 && 4 <= __GNUC_MINOR__)) \
+ && !defined __EDG__)
# define INT_MULTIPLY_WRAPV(a, b, r) __builtin_mul_overflow (a, b, r)
# else
/* Work around GCC bug 91450. */
For now, assume all versions of GCC-like compilers generate bogus
warnings for _Generic. This matters only for compilers that
lack relevant builtins. */
-#if __GNUC__
+#if __GNUC__ || defined __clang__
# define _GL__GENERIC_BOGUS 1
#else
# define _GL__GENERIC_BOGUS 0
? (EXPR_SIGNED (_GL_INT_CONVERT (tmax, b)) \
? (a) < (tmax) / (b) \
: ((INT_NEGATE_OVERFLOW (b) \
- ? _GL_INT_CONVERT (b, tmax) >> (TYPE_WIDTH (b) - 1) \
+ ? _GL_INT_CONVERT (b, tmax) >> (TYPE_WIDTH (+ (b)) - 1) \
: (tmax) / -(b)) \
<= -1 - (a))) \
: INT_NEGATE_OVERFLOW (_GL_INT_CONVERT (b, tmin)) && (b) == -1 \
: (tmin) / (a) < (b)) \
: (tmax) / (b) < (a)))
+/* The following macros compute A + B, A - B, and A * B, respectively.
+ If no overflow occurs, they set *R to the result and return 1;
+ otherwise, they return 0 and may modify *R.
+
+ Example usage:
+
+ long int result;
+ if (INT_ADD_OK (a, b, &result))
+ printf ("result is %ld\n", result);
+ else
+ printf ("overflow\n");
+
+ A, B, and *R should be integers; they need not be the same type,
+ and they need not be all signed or all unsigned.
+
+ These macros work correctly on all known practical hosts, and do not rely
+ on undefined behavior due to signed arithmetic overflow.
+
+ These macros are not constant expressions.
+
+ These macros may evaluate their arguments zero or multiple times, so the
+ arguments should not have side effects.
+
+ These macros are tuned for B being a constant. */
+
+#define INT_ADD_OK(a, b, r) ! INT_ADD_WRAPV (a, b, r)
+#define INT_SUBTRACT_OK(a, b, r) ! INT_SUBTRACT_WRAPV (a, b, r)
+#define INT_MULTIPLY_OK(a, b, r) ! INT_MULTIPLY_WRAPV (a, b, r)
+
#endif /* _GL_INTPROPS_H */