summaryrefslogtreecommitdiff
path: root/lisp
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2018-08-18 15:20:46 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2018-08-18 15:22:35 -0700
commit673b1785db4604efe81b8045a9d8ab68936af719 (patch)
tree0f78d72a7d4eef42b62bcfbaec2627aa04986c80 /lisp
parent877cd22f553624b6d7f24141acd134f9cf839259 (diff)
downloademacs-673b1785db4604efe81b8045a9d8ab68936af719.tar.gz
emacs-673b1785db4604efe81b8045a9d8ab68936af719.tar.bz2
emacs-673b1785db4604efe81b8045a9d8ab68936af719.zip
Restore traditional lsh behavior on fixnums
* doc/lispref/numbers.texi (Bitwise Operations): Document that the traditional (lsh A B) behavior is for fixnums, and that it is an error if A and B are both negative and A is a bignum. See Bug#32463. * lisp/subr.el (lsh): New function, moved here from src/data.c. * src/data.c (ash_lsh_impl): Remove, moving body into Fash since it’s the only caller now. (Fash): Check for out-of-range counts. If COUNT is zero, return first argument instead of going through libgmp. Omit lsh code since lsh is now done in Lisp. Add code for shifting fixnums right, to avoid a round trip through libgmp. (Flsh): Remove; moved to lisp/subr.el. * test/lisp/international/ccl-tests.el (shift): Test for traditional lsh behavior, instead of assuming lsh is like ash when bignums are present. * test/src/data-tests.el (data-tests-logand) (data-tests-logior, data-tests-logxor, data-tests-ash-lsh): New tests.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/subr.el12
1 files changed, 12 insertions, 0 deletions
diff --git a/lisp/subr.el b/lisp/subr.el
index fbb3e49a35c..cafa4835eaf 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -366,6 +366,18 @@ was called."
(declare (compiler-macro (lambda (_) `(= 0 ,number))))
(= 0 number))
+(defun lsh (value count)
+ "Return VALUE with its bits shifted left by COUNT.
+If COUNT is negative, shifting is actually to the right.
+In this case, if VALUE is a negative fixnum treat it as unsigned,
+i.e., subtract 2 * most-negative-fixnum from VALUE before shifting it."
+ (when (and (< value 0) (< count 0))
+ (when (< value most-negative-fixnum)
+ (signal 'args-out-of-range (list value count)))
+ (setq value (logand (ash value -1) most-positive-fixnum))
+ (setq count (1+ count)))
+ (ash value count))
+
;;;; List functions.