>From 8a7ac1d24ac54ca8f076320a61548c343040357b Mon Sep 17 00:00:00 2001
From: Paul Eggert
Date: Wed, 14 Aug 2019 17:43:46 -0700
Subject: [PATCH] intprops: support unsigned *_WRAPV results
Add support for unsigned, unsigned long, and unsigned long long
results to INT_ADD_WRAPV, INT_SUBTRACT_WRAPV, and
INT_MULTIPLY_WRAPV. Also, work around GCC bug 91450, and fix a
bug with unsigned inputs reported by Eli Zaretskii in:
https://lists.gnu.org/r/bug-gnulib/2019-08/msg00012.html
* config/srclist.txt: Break the glibc connection for intprops.h
temporarily, while more testing is done in Gnulib-using apps.
* lib/intprops.h (INT_ADD_WRAPV, INT_SUBTRACT_WRAPV)
(INT_MULTIPLY_WRAPV, _GL_INT_OP_WRAPV, _GL_INT_OP_WRAPV_LONGISH):
Support unsigned results no narrower than unsigned int. Report
overflow correctly if some arguments are unsigned.
(_GL_BUILTIN_MUL_OVERFLOW): New macro, to work around GCC bug 91450.
(_GL_INT_OP_CALC): Simplify now that the OVERFLOW argument does
the right thing with narrow args.
(_GL_INT_OP_CALC1): Remove. All callers removed.
(_GL_INT_ADD_RANGE_OVERFLOW, _GL_INT_SUBTRACT_RANGE_OVERFLOW)
(_GL_INT_MULTIPLY_RANGE_OVERFLOW): New macros.
* tests/test-intprops.c: Check for bugs and test new behavior.
---
ChangeLog | 22 ++++++
config/srclist.txt | 3 +-
lib/intprops.h | 154 ++++++++++++++++++++++++++++++++++--------
tests/test-intprops.c | 78 +++++++++++++++------
4 files changed, 209 insertions(+), 48 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 4d1eeddfc..7fe978f4a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2019-08-14 Paul Eggert
+
+ intprops: support unsigned *_WRAPV results
+ Add support for unsigned, unsigned long, and unsigned long long
+ results to INT_ADD_WRAPV, INT_SUBTRACT_WRAPV, and
+ INT_MULTIPLY_WRAPV. Also, work around GCC bug 91450, and fix a
+ bug with unsigned inputs reported by Eli Zaretskii in:
+ https://lists.gnu.org/r/bug-gnulib/2019-08/msg00012.html
+ * config/srclist.txt: Break the glibc connection for intprops.h
+ temporarily, while more testing is done in Gnulib-using apps.
+ * lib/intprops.h (INT_ADD_WRAPV, INT_SUBTRACT_WRAPV)
+ (INT_MULTIPLY_WRAPV, _GL_INT_OP_WRAPV, _GL_INT_OP_WRAPV_LONGISH):
+ Support unsigned results no narrower than unsigned int. Report
+ overflow correctly if some arguments are unsigned.
+ (_GL_BUILTIN_MUL_OVERFLOW): New macro, to work around GCC bug 91450.
+ (_GL_INT_OP_CALC): Simplify now that the OVERFLOW argument does
+ the right thing with narrow args.
+ (_GL_INT_OP_CALC1): Remove. All callers removed.
+ (_GL_INT_ADD_RANGE_OVERFLOW, _GL_INT_SUBTRACT_RANGE_OVERFLOW)
+ (_GL_INT_MULTIPLY_RANGE_OVERFLOW): New macros.
+ * tests/test-intprops.c: Check for bugs and test new behavior.
+
2019-08-14 Bruno Haible
get_progname_of: New module.
diff --git a/config/srclist.txt b/config/srclist.txt
index b86e6a57a..bb6ad87ab 100644
--- a/config/srclist.txt
+++ b/config/srclist.txt
@@ -46,7 +46,8 @@ $GNUORG Copyright/request-assign.future doc/Copyright
$GNUORG Copyright/request-assign.program doc/Copyright
$GNUORG Copyright/request-disclaim.changes doc/Copyright
-$LIBCSRC include/intprops.h lib
+# Temporarily newer in Gnulib than in glibc.
+#$LIBCSRC include/intprops.h lib
$LIBCSRC posix/regcomp.c lib
$LIBCSRC posix/regex.c lib
$LIBCSRC posix/regex.h lib
diff --git a/lib/intprops.h b/lib/intprops.h
index 140f6d2a4..556cadec8 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)) \
+ ? (__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,55 @@
#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) : (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/tests/test-intprops.c b/tests/test-intprops.c
index babcafd60..be0c6b3a7 100644
--- a/tests/test-intprops.c
+++ b/tests/test-intprops.c
@@ -56,6 +56,9 @@
#define DONTCARE __LINE__
+int int_minus_2 = -2;
+int int_1 = 1;
+
int
main (void)
{
@@ -237,33 +240,48 @@ main (void)
/* INT__OVERFLOW and INT__WRAPV with mixed types. */
#define CHECK_SUM(a, b, t, v, vres) \
- CHECK_SUM1(a, b, t, v, vres); \
- CHECK_SUM1(b, a, t, v, vres)
- #define CHECK_SSUM(a, b, t, v, vres) \
- CHECK_SSUM1(a, b, t, v, vres); \
- CHECK_SSUM1(b, a, t, v, vres)
+ CHECK_SUM1 (a, b, t, v, vres); \
+ CHECK_SUM1 (b, a, t, v, vres)
+ #define CHECK_SUM_WRAPV(a, b, t, v, vres, okres) \
+ CHECK_SUM_WRAPV1 (a, b, t, v, vres, okres); \
+ CHECK_SUM_WRAPV1 (b, a, t, v, vres, okres)
#define CHECK_SUM1(a, b, t, v, vres) \
- VERIFY (INT_ADD_OVERFLOW (a, b) == (v))
- #define CHECK_SSUM1(a, b, t, v, vres) \
- CHECK_SUM1(a, b, t, v, vres); \
+ VERIFY (INT_ADD_OVERFLOW (a, b) == (v)); \
+ CHECK_SUM_WRAPV1 (a, b, t, v, vres, (a) + (b))
+ #define CHECK_SUM_WRAPV1(a, b, t, v, vres, okres) \
{ \
t result; \
ASSERT (INT_ADD_WRAPV (a, b, &result) == (v)); \
- ASSERT (result == ((v) ? (vres) : ((a) + (b)))); \
+ ASSERT (result == ((v) ? (vres) : (okres))); \
}
- CHECK_SSUM (-1, LONG_MIN, long int, true, LONG_MAX);
+ CHECK_SUM (-1, LONG_MIN, long int, true, LONG_MAX);
CHECK_SUM (-1, UINT_MAX, unsigned int, false, DONTCARE);
- CHECK_SSUM (-1L, INT_MIN, long int, INT_MIN == LONG_MIN,
+ CHECK_SUM (-1L, INT_MIN, long int, INT_MIN == LONG_MIN,
INT_MIN == LONG_MIN ? INT_MAX : DONTCARE);
CHECK_SUM (0u, -1, unsigned int, true, 0u + -1);
CHECK_SUM (0u, 0, unsigned int, false, DONTCARE);
CHECK_SUM (0u, 1, unsigned int, false, DONTCARE);
- CHECK_SSUM (1, LONG_MAX, long int, true, LONG_MIN);
+ CHECK_SUM (1, LONG_MAX, long int, true, LONG_MIN);
CHECK_SUM (1, UINT_MAX, unsigned int, true, 0u);
- CHECK_SSUM (1L, INT_MAX, long int, INT_MAX == LONG_MAX,
+ CHECK_SUM (1L, INT_MAX, long int, INT_MAX == LONG_MAX,
INT_MAX == LONG_MAX ? INT_MIN : DONTCARE);
CHECK_SUM (1u, INT_MAX, unsigned int, INT_MAX == UINT_MAX, 1u + INT_MAX);
CHECK_SUM (1u, INT_MIN, unsigned int, true, 1u + INT_MIN);
+ CHECK_SUM_WRAPV (-1, 1u, int, false, DONTCARE, 0);
+ CHECK_SUM_WRAPV (-1, 1ul, int, false, DONTCARE, 0);
+ CHECK_SUM_WRAPV (-1l, 1u, int, false, DONTCARE, 0);
+ CHECK_SUM_WRAPV (-100, 1000u, int, false, DONTCARE, 900);
+ CHECK_SUM_WRAPV (INT_MIN, UINT_MAX, int, false, DONTCARE, INT_MAX);
+ CHECK_SUM_WRAPV (1u, INT_MAX, int, true, INT_MIN, DONTCARE);
+ CHECK_SUM_WRAPV (INT_MAX, 1, long int, LONG_MAX <= INT_MAX, INT_MIN,
+ INT_MAX + 1L);
+ CHECK_SUM_WRAPV (UINT_MAX, 1, long int, LONG_MAX <= UINT_MAX, 0,
+ UINT_MAX + 1L);
+ CHECK_SUM_WRAPV (INT_MAX, 1, unsigned long int, ULONG_MAX <= INT_MAX, 0,
+ INT_MAX + 1uL);
+ CHECK_SUM_WRAPV (UINT_MAX, 1, unsigned long int, ULONG_MAX <= UINT_MAX, 0,
+ UINT_MAX + 1uL);
+
{
long int result;
ASSERT (INT_ADD_WRAPV (1, INT_MAX, &result) == (INT_MAX == LONG_MAX));
@@ -273,7 +291,9 @@ main (void)
#define CHECK_DIFFERENCE(a, b, t, v, vres) \
VERIFY (INT_SUBTRACT_OVERFLOW (a, b) == (v))
#define CHECK_SDIFFERENCE(a, b, t, v, vres) \
- CHECK_DIFFERENCE(a, b, t, v, vres); \
+ CHECK_DIFFERENCE (a, b, t, v, vres); \
+ CHECK_SDIFFERENCE_WRAPV (a, b, t, v, vres)
+ #define CHECK_SDIFFERENCE_WRAPV(a, b, t, v, vres) \
{ \
t result; \
ASSERT (INT_SUBTRACT_WRAPV (a, b, &result) == (v)); \
@@ -290,6 +310,11 @@ main (void)
CHECK_SDIFFERENCE (-1, INT_MAX, int, false, -1 - INT_MAX);
CHECK_SDIFFERENCE (0, INT_MIN, int, INT_MIN < -INT_MAX, INT_MIN);
CHECK_SDIFFERENCE (0, INT_MAX, int, false, 0 - INT_MAX);
+ CHECK_SDIFFERENCE_WRAPV (-1, 1u, int, false, DONTCARE);
+ CHECK_SDIFFERENCE_WRAPV (-1, 1ul, int, false, DONTCARE);
+ CHECK_SDIFFERENCE_WRAPV (-1l, 1u, int, false, DONTCARE);
+ CHECK_SDIFFERENCE_WRAPV (0u, INT_MAX, int, false, DONTCARE);
+ CHECK_SDIFFERENCE_WRAPV (1u, INT_MIN, int, true, 1u - INT_MIN);
{
long int result;
ASSERT (INT_SUBTRACT_WRAPV (INT_MAX, -1, &result) == (INT_MAX == LONG_MAX));
@@ -297,15 +322,20 @@ main (void)
}
#define CHECK_PRODUCT(a, b, t, v, vres) \
- CHECK_PRODUCT1(a, b, t, v, vres); \
- CHECK_PRODUCT1(b, a, t, v, vres)
+ CHECK_PRODUCT1 (a, b, t, v, vres); \
+ CHECK_PRODUCT1 (b, a, t, v, vres)
#define CHECK_SPRODUCT(a, b, t, v, vres) \
- CHECK_SPRODUCT1(a, b, t, v, vres); \
- CHECK_SPRODUCT1(b, a, t, v, vres)
+ CHECK_SPRODUCT1 (a, b, t, v, vres); \
+ CHECK_SPRODUCT1 (b, a, t, v, vres)
+ #define CHECK_SPRODUCT_WRAPV(a, b, t, v, vres) \
+ CHECK_SPRODUCT_WRAPV1 (a, b, t, v, vres); \
+ CHECK_SPRODUCT_WRAPV1 (b, a, t, v, vres)
#define CHECK_PRODUCT1(a, b, t, v, vres) \
VERIFY (INT_MULTIPLY_OVERFLOW (a, b) == (v))
#define CHECK_SPRODUCT1(a, b, t, v, vres) \
- CHECK_PRODUCT1(a, b, t, v, vres); \
+ CHECK_PRODUCT1 (a, b, t, v, vres); \
+ CHECK_SPRODUCT_WRAPV1 (a, b, t, v, vres)
+ #define CHECK_SPRODUCT_WRAPV1(a, b, t, v, vres) \
{ \
t result; \
ASSERT (INT_MULTIPLY_WRAPV (a, b, &result) == (v)); \
@@ -343,6 +373,10 @@ main (void)
CHECK_PRODUCT (INT_MIN, UINT_MAX, unsigned int, true, INT_MIN * UINT_MAX);
CHECK_PRODUCT (INT_MIN, ULONG_MAX, unsigned long int, true,
INT_MIN * ULONG_MAX);
+ CHECK_SPRODUCT_WRAPV (-1, INT_MAX + 1u, int, false, DONTCARE);
+ CHECK_SPRODUCT_WRAPV (-1, 1u, int, false, DONTCARE);
+ CHECK_SPRODUCT (0, ULONG_MAX, int, false, DONTCARE);
+ CHECK_SPRODUCT (0u, LONG_MIN, int, false, DONTCARE);
{
long int result;
ASSERT (INT_MULTIPLY_WRAPV (INT_MAX, INT_MAX, &result)
@@ -365,6 +399,12 @@ main (void)
}
# endif
+ /* Check for GCC bug 91450. */
+ {
+ unsigned long long result;
+ ASSERT (INT_MULTIPLY_WRAPV (int_minus_2, int_1, &result) && result == -2);
+ }
+
#define CHECK_QUOTIENT(a, b, v) VERIFY (INT_DIVIDE_OVERFLOW (a, b) == (v))
CHECK_QUOTIENT (INT_MIN, -1L, INT_MIN == LONG_MIN);
--
2.17.1