Subject: bug#34781: closed (Re: 27.0.50; integer in pcase sometimes compared by eq)

From: [email-masked] (GNU bug Tracking System)
Date: Thu, 28 Mar 2019 23:04:02 +0000

Your bug report

#34781: 27.0.50; integer in pcase sometimes compared by eq

which was filed against the emacs package, has been closed.

The explanation is attached below, along with your original report.
If you require more details, please reply to [email-masked].

-- 
34781: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=34781
GNU Bug Tracking System
Contact [email-masked] with problems

Subject: Re: 27.0.50; integer in pcase sometimes compared by eq
From: Mattias Engdegård <[email-masked]>
To: Paul Eggert <[email-masked]>, Stefan Monnier <[email-masked]>
Cc: [email-masked]
Date: Fri, 29 Mar 2019 00:03:01 +0100
List-Id: <debbugs-submit.debbugs.gnu.org>

tor 2019-03-28 klockan 15:38 -0700 skrev Paul Eggert:
> On 3/28/19 3:20 PM, Mattias Engdegård wrote:
> > I'll do the obvious (unless you beat me to it).
> 
> When you do that, please also change the name of the local from memq-
> ok
> to memql-ok, for clarity. Thanks.

Done. Thanks for your help! I'm attaching the mostly cleaned-up patch
(minus the necessary doc changes), in case someone will see some use
for it.

From a60e78be5dfc2172345d140f2cd8df0a77bea0a1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mattias=20Engdeg=C3=A5rd?= <[email-masked]>
Date: Thu, 28 Mar 2019 22:12:37 +0100
Subject: [PATCH] Add bounds for portable fixnums, and portable-fixnum-p

These are useful for macros that need to detect whether a number is a
fixnum on any machine, so that the bytecode becomes portable (Bug#34781).

* src/data.c (most-positive-portable-fixnum, most-negative-portable-fixnum):
* lisp/subr.el (portable-fixnum-p):
New.
* etc/NEWS (Lisp Changes): Mention portable-fixnum-p.
---
 etc/NEWS     |  5 +++++
 lisp/subr.el |  5 +++++
 src/data.c   | 24 ++++++++++++++++++++++++
 3 files changed, 34 insertions(+)

diff --git a/etc/NEWS b/etc/NEWS
index 7486d6bcfe..2ab3c5b4bb 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1424,6 +1424,11 @@ like 'file-attributes' that compute file sizes and other attributes,
 functions like 'process-id' that compute process IDs, and functions like
 'user-uid' and 'group-gid' that compute user and group IDs.
 
+Since the size of fixnums varies between platforms, the new predicate
+'portable-fixnum-p' determines whether a number is a fixnum on any
+machine running the current Emacs version. The corresponding bounds
+are 'most-negative-portable-fixnum' and 'most-negative-portable-fixnum'.
+
 +++
 ** Although the default timestamp format is still (HI LO US PS),
 it is planned to change in a future Emacs version, to exploit bignums.
diff --git a/lisp/subr.el b/lisp/subr.el
index f1a1dddd81..efa9cd4065 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -376,6 +376,11 @@ bignump
   "Return t if OBJECT is a bignum."
   (and (integerp object) (not (fixnump object))))
 
+(defun portable-fixnum-p (object)
+  "Return t if OBJECT is a fixnum on any machine running this Emacs version."
+  (and (integerp object)
+       (<= most-negative-portable-fixnum object most-positive-portable-fixnum)))
+
 (defun lsh (value count)
   "Return VALUE with its bits shifted left by COUNT.
 If COUNT is negative, shifting is actually to the right.
diff --git a/src/data.c b/src/data.c
index 15b6106cfe..6d50a14bde 100644
--- a/src/data.c
+++ b/src/data.c
@@ -4110,6 +4110,30 @@ This variable cannot be set; trying to do so will signal an error.  */);
   Vmost_negative_fixnum = make_fixnum (MOST_NEGATIVE_FIXNUM);
   make_symbol_constant (intern_c_string ("most-negative-fixnum"));
 
+  /* The smallest portable value of EMACS_INT_MAX.  */
+  int least_emacs_int_max = 2147483647;   /* 2**31 - 1 */
+
+  /* Largest and smallest values that are guaranteed to be representable
+     as fixnums on any machine.  */
+  int most_positive_portable_fixnum = least_emacs_int_max >> INTTYPEBITS;
+  int most_negative_portable_fixnum = -1 - most_positive_portable_fixnum;
+
+  DEFVAR_LISP ("most-positive-portable-fixnum",
+               Vmost_positive_portable_fixnum,
+               doc: /* The largest integer representable as a fixnum on any platform.
+This variable can be used to ensure portability of bytecode that works
+with fixnums.  It cannot be set; trying to do so will signal an error.  */);
+  Vmost_positive_portable_fixnum = make_fixnum (most_positive_portable_fixnum);
+  make_symbol_constant (intern_c_string ("most-positive-portable-fixnum"));
+
+  DEFVAR_LISP ("most-negative-portable-fixnum",
+               Vmost_negative_portable_fixnum,
+               doc: /* The least integer representable as a fixnum on any platform.
+This variable can be used to ensure portability of bytecode that works
+with fixnums.  It cannot be set; trying to do so will signal an error.  */);
+  Vmost_negative_portable_fixnum = make_fixnum (most_negative_portable_fixnum);
+  make_symbol_constant (intern_c_string ("most-negative-portable-fixnum"));
+
   DEFSYM (Qwatchers, "watchers");
   DEFSYM (Qmakunbound, "makunbound");
   DEFSYM (Qunlet, "unlet");
-- 
2.20.1

Subject: 27.0.50; integer in pcase sometimes compared by eq
From: Mattias Engdegård <[email-masked]>
To: [email-masked]
Date: Thu, 07 Mar 2019 16:13:27 +0100
List-Id: <debbugs-submit.debbugs.gnu.org>

(defun f (x)
  (pcase x
    ((or 'a #x10000000000000000) t)))

(f #x10000000000000000) => nil

Just replacing integerp with fixnump fixes this, but I'm not sure if
more of the same lurks somewhere.

--- a/lisp/emacs-lisp/pcase.el
+++ b/lisp/emacs-lisp/pcase.el
@@ -792,7 +792,7 @@ pcase--u1
                    (let ((upat (cddr alt)))
                      (eq (car-safe upat) 'quote)))
               (let ((val (cadr (cddr alt))))
-                (unless (or (integerp val) (symbolp val))
+                (unless (or (fixnump val) (symbolp val))
                   (setq memq-ok nil))
                 (push (cadr (cddr alt)) simples))
             (push alt others))))