changeset 18294:a90f8370aad4

intprops, mktime, strtol: assume two's complement These macros were not portable to every conforming C11 ones' complement platform. It's not worth the hassle of porting to some platforms that use ones' complement or signed magnitude, as such platforms are almost purely theoretical nowadays and porting even to some of them makes the code harder to review for little practical benefit. Problem reported by Florian Weimer in: https://sourceware.org/ml/libc-alpha/2016-04/msg00295.html * lib/intprops.h (TYPE_TWOS_COMPLEMENT, TYPE_ONES_COMPLEMENT) (TYPE_SIGNED_MAGNITUDE, _GL_INT_TWOS_COMPLEMENT): * lib/mktime.c (TYPE_TWOS_COMPLEMENT): * lib/strtol.c (TYPE_TWOS_COMPLEMENT, TYPE_ONES_COMPLEMENT) (TYPE_SIGNED_MAGNITUDE): Remove. All uses rewritten to assume two's complement, which is all we can reasonably test nowadays anyway. * top/maint.mk (_intprops_names): Remove the removed macros.
author Paul Eggert <eggert@cs.ucla.edu>
date Wed, 13 Apr 2016 00:06:36 -0700
parents 294fa0173b5e
children 6ca9d396422c
files ChangeLog NEWS lib/intprops.h lib/mktime.c lib/strtol.c lib/utimecmp.c tests/test-intprops.c top/maint.mk
diffstat 8 files changed, 60 insertions(+), 85 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon Apr 11 08:42:02 2016 -0700
+++ b/ChangeLog	Wed Apr 13 00:06:36 2016 -0700
@@ -1,3 +1,22 @@
+2016-04-13  Paul Eggert  <eggert@cs.ucla.edu>
+
+	intprops, mktime, strtol: assume two's complement
+	These macros were not portable to every conforming C11 ones'
+	complement platform.  It's not worth the hassle of porting to some
+	platforms that use ones' complement or signed magnitude, as such
+	platforms are almost purely theoretical nowadays and porting even
+	to some of them makes the code harder to review for little
+	practical benefit.  Problem reported by Florian Weimer in:
+	https://sourceware.org/ml/libc-alpha/2016-04/msg00295.html
+	* lib/intprops.h (TYPE_TWOS_COMPLEMENT, TYPE_ONES_COMPLEMENT)
+	(TYPE_SIGNED_MAGNITUDE, _GL_INT_TWOS_COMPLEMENT):
+	* lib/mktime.c (TYPE_TWOS_COMPLEMENT):
+	* lib/strtol.c (TYPE_TWOS_COMPLEMENT, TYPE_ONES_COMPLEMENT)
+	(TYPE_SIGNED_MAGNITUDE):
+	Remove.  All uses rewritten to assume two's complement, which is
+	all we can reasonably test nowadays anyway.
+	* top/maint.mk (_intprops_names): Remove the removed macros.
+
 2016-04-11  Paul Eggert  <eggert@cs.ucla.edu>
 
 	stdint: port to strict C11 left shift
--- a/NEWS	Mon Apr 11 08:42:02 2016 -0700
+++ b/NEWS	Wed Apr 13 00:06:36 2016 -0700
@@ -42,6 +42,10 @@
 
 Date        Modules         Changes
 
+2016-04-12  intprops        The following macros were removed:
+                            TYPE_TWOS_COMPLEMENT  TYPE_ONES_COMPLEMENT
+                            TYPE_SIGNED_MAGNITUDE
+
 2015-09-25  c-ctype         The following macros were removed:
                             C_CTYPE_CONSECUTIVE_DIGITS
                             C_CTYPE_CONSECUTIVE_LOWERCASE
--- a/lib/intprops.h	Mon Apr 11 08:42:02 2016 -0700
+++ b/lib/intprops.h	Wed Apr 13 00:06:36 2016 -0700
@@ -36,17 +36,6 @@
    an integer.  */
 #define TYPE_IS_INTEGER(t) ((t) 1.5 == 1)
 
-/* True if negative values of the signed integer type T use two's
-   complement, ones' complement, or signed magnitude representation,
-   respectively.  Much GNU code assumes two's complement, but some
-   people like to be portable to all possible C hosts.  */
-#define TYPE_TWOS_COMPLEMENT(t) ((t) ~ (t) 0 == (t) -1)
-#define TYPE_ONES_COMPLEMENT(t) ((t) ~ (t) 0 == 0)
-#define TYPE_SIGNED_MAGNITUDE(t) ((t) ~ (t) 0 < (t) -1)
-
-/* True if the signed integer expression E uses two's complement.  */
-#define _GL_INT_TWOS_COMPLEMENT(e) (~ _GL_INT_CONVERT (e, 0) == -1)
-
 /* True if the real type T is signed.  */
 #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
 
@@ -55,18 +44,13 @@
 #define EXPR_SIGNED(e) (_GL_INT_NEGATE_CONVERT (e, 1) < 0)
 
 
-/* Minimum and maximum values for integer types and expressions.  These
-   macros have undefined behavior if T is signed and has padding bits.
-   If this is a problem for you, please let us know how to fix it for
-   your host.  */
+/* Minimum and maximum values for integer types and expressions.
+   These macros have undefined behavior for signed types that either
+   have padding bits or do not use two's complement.  If this is a
+   problem for you, please let us know how to fix it for your host.  */
 
 /* The maximum and minimum values for the integer type T.  */
-#define TYPE_MINIMUM(t)                                                 \
-  ((t) (! TYPE_SIGNED (t)                                               \
-        ? (t) 0                                                         \
-        : TYPE_SIGNED_MAGNITUDE (t)                                     \
-        ? ~ (t) 0                                                       \
-        : ~ TYPE_MAXIMUM (t)))
+#define TYPE_MINIMUM(t) ((t) ~ TYPE_MAXIMUM (t))
 #define TYPE_MAXIMUM(t)                                                 \
   ((t) (! TYPE_SIGNED (t)                                               \
         ? (t) -1                                                        \
@@ -76,7 +60,7 @@
    after integer promotion.  E should not have side effects.  */
 #define _GL_INT_MINIMUM(e)                                              \
   (EXPR_SIGNED (e)                                                      \
-   ? - _GL_INT_TWOS_COMPLEMENT (e) - _GL_SIGNED_INT_MAXIMUM (e)         \
+   ? ~ _GL_SIGNED_INT_MAXIMUM (e)                                       \
    : _GL_INT_CONVERT (e, 0))
 #define _GL_INT_MAXIMUM(e)                                              \
   (EXPR_SIGNED (e)                                                      \
--- a/lib/mktime.c	Mon Apr 11 08:42:02 2016 -0700
+++ b/lib/mktime.c	Wed Apr 13 00:06:36 2016 -0700
@@ -103,25 +103,20 @@
    an integer.  */
 #define TYPE_IS_INTEGER(t) ((t) 1.5 == 1)
 
-/* True if negative values of the signed integer type T use two's
-   complement, or if T is an unsigned integer type.  */
-#define TYPE_TWOS_COMPLEMENT(t) ((t) ~ (t) 0 == (t) -1)
-
 /* True if the arithmetic type T is signed.  */
 #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
 
-/* The maximum and minimum values for the integer type T.  These
-   macros have undefined behavior if T is signed and has padding bits.
-   If this is a problem for you, please let us know how to fix it for
-   your host.  */
-#define TYPE_MINIMUM(t) \
-  ((t) (! TYPE_SIGNED (t) \
-	? (t) 0 \
-	: ~ TYPE_MAXIMUM (t)))
-#define TYPE_MAXIMUM(t) \
-  ((t) (! TYPE_SIGNED (t) \
-	? (t) -1 \
-	: ((((t) 1 << (sizeof (t) * CHAR_BIT - 2)) - 1) * 2 + 1)))
+/* Minimum and maximum values for integer types.
+   These macros have undefined behavior for signed types that either
+   have padding bits or do not use two's complement.  If this is a
+   problem for you, please let us know how to fix it for your host.  */
+
+/* The maximum and minimum values for the integer type T.  */
+#define TYPE_MINIMUM(t) ((t) ~ TYPE_MAXIMUM (t))
+#define TYPE_MAXIMUM(t)                                                 \
+  ((t) (! TYPE_SIGNED (t)                                               \
+        ? (t) -1                                                        \
+        : ((((t) 1 << (sizeof (t) * CHAR_BIT - 2)) - 1) * 2 + 1)))
 
 #ifndef TIME_T_MIN
 # define TIME_T_MIN TYPE_MINIMUM (time_t)
@@ -132,10 +127,6 @@
 #define TIME_T_MIDPOINT (SHR (TIME_T_MIN + TIME_T_MAX, 1) + 1)
 
 verify (time_t_is_integer, TYPE_IS_INTEGER (time_t));
-verify (twos_complement_arithmetic,
-	(TYPE_TWOS_COMPLEMENT (int)
-	 && TYPE_TWOS_COMPLEMENT (long_int)
-	 && TYPE_TWOS_COMPLEMENT (time_t)));
 
 #define EPOCH_YEAR 1970
 #define TM_YEAR_BASE 1900
--- a/lib/strtol.c	Mon Apr 11 08:42:02 2016 -0700
+++ b/lib/strtol.c	Wed Apr 13 00:06:36 2016 -0700
@@ -121,30 +121,19 @@
 /* The extra casts in the following macros work around compiler bugs,
    e.g., in Cray C 5.0.3.0.  */
 
-/* True if negative values of the signed integer type T use two's
-   complement, ones' complement, or signed magnitude representation,
-   respectively.  Much GNU code assumes two's complement, but some
-   people like to be portable to all possible C hosts.  */
-# define TYPE_TWOS_COMPLEMENT(t) ((t) ~ (t) 0 == (t) -1)
-# define TYPE_ONES_COMPLEMENT(t) ((t) ~ (t) 0 == 0)
-# define TYPE_SIGNED_MAGNITUDE(t) ((t) ~ (t) 0 < (t) -1)
-
 /* True if the arithmetic type T is signed.  */
 # define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
 
-/* The maximum and minimum values for the integer type T.  These
-   macros have undefined behavior if T is signed and has padding bits.
-   If this is a problem for you, please let us know how to fix it for
-   your host.  */
-# define TYPE_MINIMUM(t) \
-   ((t) (! TYPE_SIGNED (t) \
-         ? (t) 0 \
-         : TYPE_SIGNED_MAGNITUDE (t) \
-         ? ~ (t) 0 \
-         : ~ TYPE_MAXIMUM (t)))
-# define TYPE_MAXIMUM(t) \
-   ((t) (! TYPE_SIGNED (t) \
-         ? (t) -1 \
+/* Minimum and maximum values for integer types.
+   These macros have undefined behavior for signed types that either
+   have padding bits or do not use two's complement.  If this is a
+   problem for you, please let us know how to fix it for your host.  */
+
+/* The maximum and minimum values for the integer type T.  */
+# define TYPE_MINIMUM(t) ((t) ~ TYPE_MAXIMUM (t))
+# define TYPE_MAXIMUM(t)                                                 \
+   ((t) (! TYPE_SIGNED (t)                                               \
+         ? (t) -1                                                        \
          : ((((t) 1 << (sizeof (t) * CHAR_BIT - 2)) - 1) * 2 + 1)))
 
 # ifndef ULLONG_MAX
--- a/lib/utimecmp.c	Mon Apr 11 08:42:02 2016 -0700
+++ b/lib/utimecmp.c	Wed Apr 13 00:06:36 2016 -0700
@@ -132,7 +132,6 @@
      time_t might be unsigned.  */
 
   verify (TYPE_IS_INTEGER (time_t));
-  verify (TYPE_TWOS_COMPLEMENT (int));
 
   /* Destination and source time stamps.  */
   time_t dst_s = dst_stat->st_mtime;
--- a/tests/test-intprops.c	Mon Apr 11 08:42:02 2016 -0700
+++ b/tests/test-intprops.c	Wed Apr 13 00:06:36 2016 -0700
@@ -94,12 +94,8 @@
   ASSERT (TYPE_SIGNED (double));
   ASSERT (TYPE_SIGNED (long double));
 
-  /* Integer representation.  */
-  VERIFY (INT_MIN + INT_MAX < 0
-          ? (TYPE_TWOS_COMPLEMENT (int)
-             && ! TYPE_ONES_COMPLEMENT (int) && ! TYPE_SIGNED_MAGNITUDE (int))
-          : (! TYPE_TWOS_COMPLEMENT (int)
-             && (TYPE_ONES_COMPLEMENT (int) || TYPE_SIGNED_MAGNITUDE (int))));
+  /* Integer representation.  Check that it is two's complement.  */
+  VERIFY (INT_MIN + INT_MAX < 0);
 
   /* TYPE_MINIMUM, TYPE_MAXIMUM.  */
   VERIFY (TYPE_MINIMUM (char) == CHAR_MIN);
@@ -156,8 +152,7 @@
     {                                                                     \
       t result;                                                           \
       ASSERT (INT_##opname##_WRAPV (a, b, &result) == (v));               \
-      ASSERT (result == ((v) ? (vres) : ((a) op (b)))                     \
-              || ((v) && !TYPE_TWOS_COMPLEMENT (t)));                     \
+      ASSERT (result == ((v) ? (vres) : ((a) op (b))));                   \
     }
   #define CHECK_UNOP(op, opname, a, t, v)                                 \
     VERIFY (INT_##opname##_RANGE_OVERFLOW (a, TYPE_MINIMUM (t),           \
@@ -183,7 +178,7 @@
   CHECK_BINOP (-, SUBTRACT, UINT_MAX, 1u, unsigned int, false, UINT_MAX - 1u);
   CHECK_BINOP (-, SUBTRACT, 0u, 1u, unsigned int, true, 0u - 1u);
 
-  CHECK_UNOP (-, NEGATE, INT_MIN, int, TYPE_TWOS_COMPLEMENT (int));
+  CHECK_UNOP (-, NEGATE, INT_MIN, int, true);
   CHECK_UNOP (-, NEGATE, 0, int, false);
   CHECK_UNOP (-, NEGATE, INT_MAX, int, false);
   CHECK_UNOP (-, NEGATE, 0u, unsigned int, false);
@@ -230,8 +225,7 @@
     {                                                                     \
       t result;                                                           \
       ASSERT (INT_ADD_WRAPV (a, b, &result) == (v));                      \
-      ASSERT (result == ((v) ? (vres) : ((a) + (b)))                      \
-              || ((v) && !TYPE_TWOS_COMPLEMENT (t)));                     \
+      ASSERT (result == ((v) ? (vres) : ((a) + (b))));                    \
     }
   CHECK_SSUM (-1, LONG_MIN, long int, true, LONG_MAX);
   CHECK_SUM (-1, UINT_MAX, unsigned int, false, DONTCARE);
@@ -259,8 +253,7 @@
     {                                                                     \
       t result;                                                           \
       ASSERT (INT_SUBTRACT_WRAPV (a, b, &result) == (v));                 \
-      ASSERT (result == ((v) ? (vres) : ((a) - (b)))                      \
-              || ((v) && !TYPE_TWOS_COMPLEMENT (t)));                     \
+      ASSERT (result == ((v) ? (vres) : ((a) - (b))));                    \
     }
   CHECK_DIFFERENCE (INT_MAX, 1u, unsigned int, UINT_MAX < INT_MAX - 1,
                     INT_MAX - 1u);
@@ -292,8 +285,7 @@
     {                                                                     \
       t result;                                                           \
       ASSERT (INT_MULTIPLY_WRAPV (a, b, &result) == (v));                 \
-      ASSERT (result == ((v) ? (vres) : ((a) * (b)))                      \
-              || ((v) && !TYPE_TWOS_COMPLEMENT (t)));                     \
+      ASSERT (result == ((v) ? (vres) : ((a) * (b))));                    \
     }
   CHECK_PRODUCT (-1, 1u, unsigned int, true, -1 * 1u);
   CHECK_SPRODUCT (-1, INT_MIN, int, INT_NEGATE_OVERFLOW (INT_MIN), INT_MIN);
@@ -351,8 +343,7 @@
 
   #define CHECK_QUOTIENT(a, b, v) VERIFY (INT_DIVIDE_OVERFLOW (a, b) == (v))
 
-  CHECK_QUOTIENT (INT_MIN, -1L,
-                  TYPE_TWOS_COMPLEMENT (long int) && INT_MIN == LONG_MIN);
+  CHECK_QUOTIENT (INT_MIN, -1L, INT_MIN == LONG_MIN);
   CHECK_QUOTIENT (INT_MIN, UINT_MAX, false);
   CHECK_QUOTIENT (INTMAX_MIN, UINTMAX_MAX, false);
   CHECK_QUOTIENT (INTMAX_MIN, UINT_MAX, false);
@@ -365,8 +356,7 @@
 
   #define CHECK_REMAINDER(a, b, v) VERIFY (INT_REMAINDER_OVERFLOW (a, b) == (v))
 
-  CHECK_REMAINDER (INT_MIN, -1L,
-                   TYPE_TWOS_COMPLEMENT (long int) && INT_MIN == LONG_MIN);
+  CHECK_REMAINDER (INT_MIN, -1L, INT_MIN == LONG_MIN);
   CHECK_REMAINDER (-1, UINT_MAX, true);
   CHECK_REMAINDER ((intmax_t) -1, UINTMAX_MAX, true);
   CHECK_REMAINDER (INTMAX_MIN, UINT_MAX,
--- a/top/maint.mk	Mon Apr 11 08:42:02 2016 -0700
+++ b/top/maint.mk	Wed Apr 13 00:06:36 2016 -0700
@@ -651,8 +651,7 @@
 # Get the list of symbol names with this:
 # perl -lne '/^# *define ([A-Z]\w+)\(/ and print $1' lib/intprops.h|fmt
 _intprops_names =							\
-  TYPE_IS_INTEGER TYPE_TWOS_COMPLEMENT TYPE_ONES_COMPLEMENT		\
-  TYPE_SIGNED_MAGNITUDE TYPE_SIGNED TYPE_MINIMUM TYPE_MAXIMUM		\
+  TYPE_IS_INTEGER TYPE_SIGNED TYPE_MINIMUM TYPE_MAXIMUM			\
   INT_BITS_STRLEN_BOUND INT_STRLEN_BOUND INT_BUFSIZE_BOUND		\
   INT_ADD_RANGE_OVERFLOW INT_SUBTRACT_RANGE_OVERFLOW			\
   INT_NEGATE_RANGE_OVERFLOW INT_MULTIPLY_RANGE_OVERFLOW			\