Fix INCF on a THE variable.

The following code:

(let ((foo 0))
  (incf (the fixnum foo) (bar)))

was being expanded into:

(let ((foo 0))
  (LET* ((#:G133 (BAR)) (#:G132 (THE FIXNUM (+ (THE FIXNUM FOO) (BAR)))))
    (DECLARE (:READ-ONLY #:G133))
    (SETQ FOO (THE FIXNUM #:G132))))

Which is obviously going to call (BAR) twice. If (BAR) has
side-effects, then it is going to be buggy.

The old define-modify-macro had an issue with out-of-order INCF/DECF,
which is why it was replaced with Bruno Haible's macro, which is
supposed to improve THE handling. It turns out that the improvement is
a bit broken, so we're just fixing this.

Fixes #401.
This commit is contained in:
Florian Margaine 2017-09-07 21:36:56 +02:00
parent 5ea8972421
commit 09899a3e15
2 changed files with 11 additions and 4 deletions

View file

@ -560,10 +560,7 @@ retrieved by (DOCUMENTATION 'SYMBOL 'FUNCTION)."
(LIST*
(LIST
(CAR STORES)
(IF (AND (LISTP %REFERENCE) (EQ (CAR %REFERENCE) 'THE))
(LIST 'THE (CADR %REFERENCE)
(LIST* (QUOTE ,function) GETTER ,@varlist ,restvar))
(LIST* (QUOTE ,function) GETTER (MAPCAR #'CAR ALL-VARS))))
(LIST* (QUOTE ,function) GETTER (MAPCAR #'CAR ALL-VARS)))
(APPEND ALL-VARS LET-LIST)))
`(LET* ,(NREVERSE LET-LIST)
(DECLARE (:READ-ONLY ,@(mapcar #'first all-vars)

View file

@ -47,6 +47,16 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 12.2.* Numbers tests ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;
(test ansi.12.2.incf
(let ((foo 0)
(bar 0))
(flet ((inc () (incf foo)))
(incf (the fixnum bar) (inc)))
(is (= foo 1))))
;;;;;;;;;;;;;;;;;;;;;;;;;
;; 19.* Pathname tests ;;
;;;;;;;;;;;;;;;;;;;;;;;;;