bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] intprops, mktime, strtol: assume two's complement


From: Paul Eggert
Subject: [PATCH] intprops, mktime, strtol: assume two's complement
Date: Wed, 13 Apr 2016 00:13:38 -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             | 19 +++++++++++++++++++
 NEWS                  |  4 ++++
 lib/intprops.h        | 28 ++++++----------------------
 lib/mktime.c          | 31 +++++++++++--------------------
 lib/strtol.c          | 31 ++++++++++---------------------
 lib/utimecmp.c        |  1 -
 tests/test-intprops.c | 28 +++++++++-------------------
 top/maint.mk          |  3 +--
 8 files changed, 60 insertions(+), 85 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 6c5913d..a21cf78 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2016-04-13  Paul Eggert  <address@hidden>
+
+       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  <address@hidden>
 
        stdint: port to strict C11 left shift
diff --git a/NEWS b/NEWS
index 122abf5..00709e8 100644
--- 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
diff --git a/lib/intprops.h b/lib/intprops.h
index 27fc9f9..de6c324 100644
--- a/lib/intprops.h
+++ b/lib/intprops.h
@@ -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)                                                      \
diff --git a/lib/mktime.c b/lib/mktime.c
index bc7ed56..46f3e06 100644
--- a/lib/mktime.c
+++ b/lib/mktime.c
@@ -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
diff --git a/lib/strtol.c b/lib/strtol.c
index b0215fc..6ef8a96 100644
--- a/lib/strtol.c
+++ b/lib/strtol.c
@@ -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
diff --git a/lib/utimecmp.c b/lib/utimecmp.c
index 908fc1a..ac3d626 100644
--- a/lib/utimecmp.c
+++ b/lib/utimecmp.c
@@ -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;
diff --git a/tests/test-intprops.c b/tests/test-intprops.c
index 174ddec..51fe096 100644
--- a/tests/test-intprops.c
+++ b/tests/test-intprops.c
@@ -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,
diff --git a/top/maint.mk b/top/maint.mk
index 9470328..aa23364 100644
--- a/top/maint.mk
+++ b/top/maint.mk
@@ -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                        
\
-- 
2.5.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]