From aa1411b20fba73ca6fde90fc9ce62cc8a854bf20 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Wed, 14 Aug 2019 18:13:27 -0700 Subject: [PATCH] Update from Gnulib This incorporates: 2019-08-14 intprops: pacify picky GCC 2019-08-14 intprops: support unsigned *_WRAPV results 2019-08-12 verify: improve diagnostic quality in recent GCC * lib/intprops.h, lib/verify.h: Copy from Gnulib. --- lib/intprops.h | 156 ++++++++++++++++++++++++++++++++++++++++--------- lib/verify.h | 33 ++++++----- 2 files changed, 147 insertions(+), 42 deletions(-) diff --git a/lib/intprops.h b/lib/intprops.h index 1a44ae55653..d1785ac6f16 100644 --- a/lib/intprops.h +++ b/lib/intprops.h @@ -111,8 +111,8 @@ Subtract 1 for the sign bit if T is signed, and then add 1 more for a minus sign if needed. - Because _GL_SIGNED_TYPE_OR_EXPR sometimes returns 0 when its argument is - signed, this macro may overestimate the true bound by one byte when + Because _GL_SIGNED_TYPE_OR_EXPR sometimes returns 1 when its argument is + unsigned, this macro may overestimate the true bound by one byte when applied to unsigned types of size 2, 4, 16, ... bytes. */ #define INT_STRLEN_BOUND(t) \ (INT_BITS_STRLEN_BOUND (TYPE_WIDTH (t) - _GL_SIGNED_TYPE_OR_EXPR (t)) \ @@ -281,7 +281,9 @@ The INT__OVERFLOW macros return 1 if the corresponding C operators might not yield numerically correct answers due to arithmetic overflow. - The INT__WRAPV macros also store the low-order bits of the answer. + The INT__WRAPV macros compute the low-order bits of the sum, + difference, and product of two C integers, and return 1 if these + low-order bits are not numerically correct. These macros work correctly on all known practical hosts, and do not rely on undefined behavior due to signed arithmetic overflow. @@ -309,9 +311,12 @@ arguments should not have side effects. The WRAPV macros are not constant expressions. They support only - +, binary -, and *. The result type must be signed. + +, binary -, and *. The result type must be either signed, or an + unsigned type that is 'unsigned int' or wider. Because the WRAPV + macros convert the result, the report overflow in different + circumstances than the OVERFLOW macros do. - These macros are tuned for their last argument being a constant. + These macros are tuned for their last input argument being a constant. Return 1 if the integer expressions A * B, A - B, -A, A * B, A / B, A % B, and A << B would overflow, respectively. */ @@ -348,11 +353,21 @@ /* 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. */ #define INT_ADD_WRAPV(a, b, r) \ - _GL_INT_OP_WRAPV (a, b, r, +, __builtin_add_overflow, INT_ADD_OVERFLOW) + _GL_INT_OP_WRAPV (a, b, r, +, __builtin_add_overflow, \ + _GL_INT_ADD_RANGE_OVERFLOW) #define INT_SUBTRACT_WRAPV(a, b, r) \ - _GL_INT_OP_WRAPV (a, b, r, -, __builtin_sub_overflow, INT_SUBTRACT_OVERFLOW) + _GL_INT_OP_WRAPV (a, b, r, -, __builtin_sub_overflow, \ + _GL_INT_SUBTRACT_RANGE_OVERFLOW) #define INT_MULTIPLY_WRAPV(a, b, r) \ - _GL_INT_OP_WRAPV (a, b, r, *, __builtin_mul_overflow, INT_MULTIPLY_OVERFLOW) + _GL_INT_OP_WRAPV (a, b, r, *, _GL_BUILTIN_MUL_OVERFLOW, \ + _GL_INT_MULTIPLY_RANGE_OVERFLOW) + +/* Like __builtin_mul_overflow, but work around GCC bug 91450. */ +#define _GL_BUILTIN_MUL_OVERFLOW(a, b, r) \ + ((!_GL_SIGNED_TYPE_OR_EXPR (*(r)) && EXPR_SIGNED (a) && EXPR_SIGNED (b) \ + && _GL_INT_MULTIPLY_RANGE_OVERFLOW (a, b, 0, (__typeof__ (*(r))) -1)) \ + ? ((void) __builtin_mul_overflow (a, b, r), 1) \ + : __builtin_mul_overflow (a, b, r)) /* Nonzero if this compiler has GCC bug 68193 or Clang bug 25390. See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68193 @@ -379,41 +394,79 @@ signed char: \ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ signed char, SCHAR_MIN, SCHAR_MAX), \ + unsigned char: \ + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ + unsigned char, 0, UCHAR_MAX), \ short int: \ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ short int, SHRT_MIN, SHRT_MAX), \ + unsigned short int: \ + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ + unsigned short int, 0, USHRT_MAX), \ int: \ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ int, INT_MIN, INT_MAX), \ + unsigned int: \ + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ + unsigned int, 0, UINT_MAX), \ long int: \ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ long int, LONG_MIN, LONG_MAX), \ + unsigned long int: \ + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ + unsigned long int, 0, ULONG_MAX), \ long long int: \ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \ - long long int, LLONG_MIN, LLONG_MAX))) + long long int, LLONG_MIN, LLONG_MAX), + unsigned long long int: \ + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \ + unsigned long long int, ULLONG_MIN, ULLONG_MAX))) #else +/* This fallback implementation uses _GL_SIGNED_TYPE_OR_EXPR, and so + may guess wrong on some non-GNU pre-C11 compilers when the type of + *R is unsigned char or unsigned short. This is why the + documentation for INT_ADD_WRAPV says that the result type, if + unsigned, should be unsigned int or wider. */ # define _GL_INT_OP_WRAPV(a, b, r, op, builtin, overflow) \ (sizeof *(r) == sizeof (signed char) \ - ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ - signed char, SCHAR_MIN, SCHAR_MAX) \ + ? (_GL_SIGNED_TYPE_OR_EXPR (*(r)) \ + ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ + signed char, SCHAR_MIN, SCHAR_MAX) \ + : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ + unsigned char, 0, UCHAR_MAX)) \ : sizeof *(r) == sizeof (short int) \ - ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ - short int, SHRT_MIN, SHRT_MAX) \ + ? (_GL_SIGNED_TYPE_OR_EXPR (*(r)) \ + ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ + short int, SHRT_MIN, SHRT_MAX) \ + : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ + unsigned short int, 0, USHRT_MAX)) \ : sizeof *(r) == sizeof (int) \ - ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ - int, INT_MIN, INT_MAX) \ + ? (EXPR_SIGNED (*(r)) \ + ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ + int, INT_MIN, INT_MAX) \ + : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ + unsigned int, 0, UINT_MAX)) \ : _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow)) # ifdef LLONG_MAX # define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \ (sizeof *(r) == sizeof (long int) \ - ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ - long int, LONG_MIN, LONG_MAX) \ - : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \ - long long int, LLONG_MIN, LLONG_MAX)) + ? (EXPR_SIGNED (*(r)) \ + ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ + long int, LONG_MIN, LONG_MAX) \ + : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ + unsigned long int, 0, ULONG_MAX)) \ + : (EXPR_SIGNED (*(r)) \ + ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \ + long long int, LLONG_MIN, LLONG_MAX) \ + : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \ + unsigned long long int, 0, ULLONG_MAX))) # else # define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \ - _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ - long int, LONG_MIN, LONG_MAX) + (EXPR_SIGNED (*(r)) \ + ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ + long int, LONG_MIN, LONG_MAX) \ + : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ + unsigned long int, 0, ULONG_MAX)) # endif #endif @@ -422,13 +475,7 @@ 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. */ #define _GL_INT_OP_CALC(a, b, r, op, overflow, ut, t, tmin, tmax) \ - (sizeof ((a) op (b)) < sizeof (t) \ - ? _GL_INT_OP_CALC1 ((t) (a), (t) (b), r, op, overflow, ut, t, tmin, tmax) \ - : _GL_INT_OP_CALC1 (a, b, r, op, overflow, ut, t, tmin, tmax)) -#define _GL_INT_OP_CALC1(a, b, r, op, overflow, ut, t, tmin, tmax) \ - ((overflow (a, b) \ - || (EXPR_SIGNED ((a) op (b)) && ((a) op (b)) < (tmin)) \ - || (tmax) < ((a) op (b))) \ + (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)) @@ -452,4 +499,57 @@ #define _GL_INT_OP_WRAPV_VIA_UNSIGNED(a, b, op, ut, t) \ ((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. + TMAX should be positive, and should be signed unless TMIN is zero. */ +#define _GL_INT_ADD_RANGE_OVERFLOW(a, b, tmin, tmax) \ + ((b) < 0 \ + ? (((tmin) \ + ? ((EXPR_SIGNED (_GL_INT_CONVERT (a, (tmin) - (b))) || (b) < (tmin)) \ + && (a) < (tmin) - (b)) \ + : (a) <= -1 - (b)) \ + || ((EXPR_SIGNED (a) ? 0 <= (a) : (tmax) < (a)) && (tmax) < (a) + (b))) \ + : (a) < 0 \ + ? (((tmin) \ + ? ((EXPR_SIGNED (_GL_INT_CONVERT (b, (tmin) - (a))) || (a) < (tmin)) \ + && (b) < (tmin) - (a)) \ + : (b) <= -1 - (a)) \ + || ((EXPR_SIGNED (_GL_INT_CONVERT (a, b)) || (tmax) < (b)) \ + && (tmax) < (a) + (b))) \ + : (tmax) < (b) || (tmax) - (b) < (a)) +#define _GL_INT_SUBTRACT_RANGE_OVERFLOW(a, b, tmin, tmax) \ + (((a) < 0) == ((b) < 0) \ + ? ((a) < (b) \ + ? !(tmin) || -1 - (tmin) < (b) - (a) - 1 \ + : (tmax) < (a) - (b)) \ + : (a) < 0 \ + ? ((!EXPR_SIGNED (_GL_INT_CONVERT ((a) - (tmin), b)) && (a) - (tmin) < 0) \ + || (a) - (tmin) < (b)) \ + : ((! (EXPR_SIGNED (_GL_INT_CONVERT (tmax, b)) \ + && EXPR_SIGNED (_GL_INT_CONVERT ((tmax) + (b), a))) \ + && (tmax) <= -1 - (b)) \ + || (tmax) + (b) < (a))) +#define _GL_INT_MULTIPLY_RANGE_OVERFLOW(a, b, tmin, tmax) \ + ((b) < 0 \ + ? ((a) < 0 \ + ? (EXPR_SIGNED (_GL_INT_CONVERT (tmax, b)) \ + ? (a) < (tmax) / (b) \ + : ((INT_NEGATE_OVERFLOW (b) \ + ? _GL_INT_CONVERT (b, tmax) >> (TYPE_WIDTH (b) - 1) \ + : (tmax) / -(b)) \ + <= -1 - (a))) \ + : INT_NEGATE_OVERFLOW (_GL_INT_CONVERT (b, tmin)) && (b) == -1 \ + ? (EXPR_SIGNED (a) \ + ? 0 < (a) + (tmin) \ + : 0 < (a) && -1 - (tmin) < (a) - 1) \ + : (tmin) / (b) < (a)) \ + : (b) == 0 \ + ? 0 \ + : ((a) < 0 \ + ? (INT_NEGATE_OVERFLOW (_GL_INT_CONVERT (a, tmin)) && (a) == -1 \ + ? (EXPR_SIGNED (b) ? 0 < (b) + (tmin) : -1 - (tmin) < (b) - 1) \ + : (tmin) / (a) < (b)) \ + : (tmax) / (b) < (a))) + #endif /* _GL_INTPROPS_H */ diff --git a/lib/verify.h b/lib/verify.h index 9b8e1ed20fa..afdc1ad81f1 100644 --- a/lib/verify.h +++ b/lib/verify.h @@ -175,9 +175,11 @@ #define _GL_GENSYM(prefix) _GL_CONCAT (prefix, _GL_COUNTER) /* Verify requirement R at compile-time, as an integer constant expression - that returns 1. If R is false, fail at compile-time. */ + that returns 1. If R is false, fail at compile-time, preferably + with a diagnostic that includes the string-literal DIAGNOSTIC. */ -#define _GL_VERIFY_TRUE(R) (!!sizeof (_GL_VERIFY_TYPE (R))) +#define _GL_VERIFY_TRUE(R, DIAGNOSTIC) \ + (!!sizeof (_GL_VERIFY_TYPE (R, DIAGNOSTIC))) #ifdef __cplusplus # if !GNULIB_defined_struct__gl_verify_type @@ -187,15 +189,16 @@ template }; # define GNULIB_defined_struct__gl_verify_type 1 # endif -# define _GL_VERIFY_TYPE(R) _gl_verify_type<(R) ? 1 : -1> -#elif defined _GL_HAVE__STATIC_ASSERT1 -# define _GL_VERIFY_TYPE(R) \ +# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \ + _gl_verify_type<(R) ? 1 : -1> +#elif defined _GL_HAVE__STATIC_ASSERT +# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \ struct { \ - _Static_assert (R); \ + _Static_assert (R, DIAGNOSTIC); \ int _gl_dummy; \ } #else -# define _GL_VERIFY_TYPE(R) \ +# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \ struct { unsigned int _gl_verify_error_if_negative: (R) ? 1 : -1; } #endif @@ -214,7 +217,7 @@ template #else # define _GL_VERIFY(R, DIAGNOSTIC, ...) \ extern int (*_GL_GENSYM (_gl_verify_function) (void)) \ - [_GL_VERIFY_TRUE (R)] + [_GL_VERIFY_TRUE (R, DIAGNOSTIC)] #endif /* _GL_STATIC_ASSERT_H is defined if this code is copied into assert.h. */ @@ -242,17 +245,19 @@ template /* Verify requirement R at compile-time. Return the value of the expression E. */ -#define verify_expr(R, E) (_GL_VERIFY_TRUE (R) ? (E) : (E)) +#define verify_expr(R, E) \ + (_GL_VERIFY_TRUE (R, "verify_expr (" #R ", " #E ")") ? (E) : (E)) /* Verify requirement R at compile-time, as a declaration without a trailing ';'. verify (R) acts like static_assert (R) except that - it is portable to C11/C++14 and earlier, and its name is shorter - and may be more convenient. */ + it is portable to C11/C++14 and earlier, it can issue better + diagnostics, and its name is shorter and may be more convenient. */ -#ifdef _GL_HAVE__STATIC_ASSERT1 -# define verify(R) _Static_assert (R) -#else +#ifdef __PGI +/* PGI barfs if R is long. */ # define verify(R) _GL_VERIFY (R, "verify (...)", -) +#else +# define verify(R) _GL_VERIFY (R, "verify (" #R ")", -) #endif #ifndef __has_builtin -- 2.39.2