]> Savannah Git Hosting - gnulib.git/commitdiff
intprops, mktime, strtol: assume two's complement
authorPaul Eggert <eggert@cs.ucla.edu>
Wed, 13 Apr 2016 07:06:36 +0000 (00:06 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Wed, 13 Apr 2016 07:13:23 +0000 (00:13 -0700)
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.

ChangeLog
NEWS
lib/intprops.h
lib/mktime.c
lib/strtol.c
lib/utimecmp.c
tests/test-intprops.c
top/maint.mk

index 6c5913dabfd5382e31fb4ae292554ef63f22fab4..a21cf7845b644938c8f440412f1e77b1637f1f47 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/NEWS b/NEWS
index 122abf54baaf9537d97990f49ac3a0e947ebb893..00709e8708ce8c0b41da5710f2123b2453ed44e7 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -42,6 +42,10 @@ User visible incompatible changes
 
 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
index 27fc9f95e3fe87ac298290e33cdb4af21035d4b9..de6c324385f8523904e8de0dca46c56105180211 100644 (file)
    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))
 
 #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)                                                      \
index bc7ed5674ba81d47b07abfcc5c2dd3cbbe63a8aa..46f3e06af0e8002671cb1576af78b66a8b344236 100644 (file)
@@ -103,25 +103,20 @@ verify (long_int_is_wide_enough, INT_MAX == INT_MAX * (long_int) 2 / 2);
    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 @@ verify (long_int_is_wide_enough, INT_MAX == INT_MAX * (long_int) 2 / 2);
 #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
index b0215fce76b8693d1b553067f0b70c21258de1fa..6ef8a9624c9ee69f4d0f0879ecc4b12bcaaf706c 100644 (file)
 /* 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
index 908fc1af85990497aacd739f2b34ecb6276a1474..ac3d6262883ae9d211fbf68792239e3d925bfa89 100644 (file)
@@ -132,7 +132,6 @@ utimecmp (char const *dst_name,
      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;
index 174ddec6d1f3daced38b332638113c2ec5333648..51fe09638ed3d71a14976c780a3e9996ecc56096 100644 (file)
@@ -94,12 +94,8 @@ main (void)
   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 @@ main (void)
     {                                                                     \
       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 @@ main (void)
   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 @@ main (void)
     {                                                                     \
       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 @@ main (void)
     {                                                                     \
       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 @@ main (void)
     {                                                                     \
       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 @@ main (void)
 
   #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 @@ main (void)
 
   #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,
index 947032879cdccb1f3a92fb92614f3e99be1a9fa5..aa23364a1b677c3a1cae07848a10e700fec8a071 100644 (file)
@@ -651,8 +651,7 @@ sc_prohibit_strings_without_use:
 # 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                        \