diff options
| author | Daniel Colascione | 2014-04-21 02:34:21 -0700 |
|---|---|---|
| committer | Daniel Colascione | 2014-04-21 02:34:21 -0700 |
| commit | 985c035f2d4cf326a816fe463c400be96e358be2 (patch) | |
| tree | 8db28fe4100f4e5988824dcc956fd6a7088e98ae | |
| parent | 0c8d94555ce550d87afd6293bf5d17e864c13864 (diff) | |
| download | emacs-985c035f2d4cf326a816fe463c400be96e358be2.tar.gz emacs-985c035f2d4cf326a816fe463c400be96e358be2.zip | |
Correctly treat progn contents as toplevel forms when byte compiling
| -rw-r--r-- | lisp/ChangeLog | 6 | ||||
| -rw-r--r-- | lisp/emacs-lisp/bytecomp.el | 67 | ||||
| -rw-r--r-- | lisp/emacs-lisp/macroexp.el | 5 | ||||
| -rw-r--r-- | test/ChangeLog | 7 | ||||
| -rw-r--r-- | test/automated/bytecomp-tests.el | 50 |
5 files changed, 111 insertions, 24 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index cb91bbcb4d9..3c5dc44010b 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,5 +1,11 @@ | |||
| 1 | 2014-04-21 Daniel Colascione <dancol@dancol.org> | 1 | 2014-04-21 Daniel Colascione <dancol@dancol.org> |
| 2 | 2 | ||
| 3 | * emacs-lisp/bytecomp.el (byte-compile-recurse-toplevel): New | ||
| 4 | function. | ||
| 5 | (byte-compile-recurse-toplevel, | ||
| 6 | (byte-compile-initial-macro-environment, | ||
| 7 | (byte-compile-toplevel-file-form): Use it. | ||
| 8 | |||
| 3 | * emacs-lisp/cl-macs.el: | 9 | * emacs-lisp/cl-macs.el: |
| 4 | (cl--loop-let): Properly destructure `while' clauses. | 10 | (cl--loop-let): Properly destructure `while' clauses. |
| 5 | 11 | ||
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index e5f8a8cc22a..923d2067a49 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el | |||
| @@ -421,31 +421,46 @@ Filled in `cconv-analyse-form' but initialized and consulted here.") | |||
| 421 | 421 | ||
| 422 | (defvar byte-compiler-error-flag) | 422 | (defvar byte-compiler-error-flag) |
| 423 | 423 | ||
| 424 | (defun byte-compile-recurse-toplevel (form &optional non-toplevel-case) | ||
| 425 | "Implement `eval-when-compile' and `eval-and-compile'. | ||
| 426 | Return the compile-time value of FORM." | ||
| 427 | ;; Macroexpand (not macroexpand-all!) form at toplevel in case it | ||
| 428 | ;; expands into a toplevel-equivalent `progn'. See CLHS section | ||
| 429 | ;; 3.2.3.1, "Processing of Top Level Forms". The semantics are very | ||
| 430 | ;; subtle: see test/automated/bytecomp-tests.el for interesting | ||
| 431 | ;; cases. | ||
| 432 | (setf form (macroexpand form byte-compile-macro-environment)) | ||
| 433 | (if (eq (car-safe form) 'progn) | ||
| 434 | (cons 'progn | ||
| 435 | (mapcar (lambda (subform) | ||
| 436 | (byte-compile-recurse-toplevel | ||
| 437 | subform non-toplevel-case)) | ||
| 438 | (cdr form))) | ||
| 439 | (funcall non-toplevel-case form))) | ||
| 440 | |||
| 424 | (defconst byte-compile-initial-macro-environment | 441 | (defconst byte-compile-initial-macro-environment |
| 425 | '( | 442 | '( |
| 426 | ;; (byte-compiler-options . (lambda (&rest forms) | 443 | ;; (byte-compiler-options . (lambda (&rest forms) |
| 427 | ;; (apply 'byte-compiler-options-handler forms))) | 444 | ;; (apply 'byte-compiler-options-handler forms))) |
| 428 | (declare-function . byte-compile-macroexpand-declare-function) | 445 | (declare-function . byte-compile-macroexpand-declare-function) |
| 429 | (eval-when-compile . (lambda (&rest body) | 446 | (eval-when-compile . (lambda (&rest body) |
| 430 | (list | 447 | (let ((result nil)) |
| 431 | 'quote | 448 | (byte-compile-recurse-toplevel |
| 432 | (byte-compile-eval | 449 | (cons 'progn body) |
| 433 | (byte-compile-top-level | 450 | (lambda (form) |
| 434 | (byte-compile-preprocess (cons 'progn body))))))) | 451 | (setf result |
| 452 | (byte-compile-eval | ||
| 453 | (byte-compile-top-level | ||
| 454 | (byte-compile-preprocess form)))))) | ||
| 455 | (list 'quote result)))) | ||
| 435 | (eval-and-compile . (lambda (&rest body) | 456 | (eval-and-compile . (lambda (&rest body) |
| 436 | ;; Byte compile before running it. Do it piece by | 457 | (byte-compile-recurse-toplevel |
| 437 | ;; piece, in case further expressions need earlier | 458 | (cons 'progn body) |
| 438 | ;; ones to be evaluated already, as is the case in | 459 | (lambda (form) |
| 439 | ;; eieio.el. | 460 | (let ((compiled (byte-compile-top-level |
| 440 | `(progn | 461 | (byte-compile-preprocess form)))) |
| 441 | ,@(mapcar (lambda (exp) | 462 | (eval compiled) |
| 442 | (let ((cexp | 463 | compiled)))))) |
| 443 | (byte-compile-top-level | ||
| 444 | (byte-compile-preprocess | ||
| 445 | exp)))) | ||
| 446 | (eval cexp) | ||
| 447 | cexp)) | ||
| 448 | body))))) | ||
| 449 | "The default macro-environment passed to macroexpand by the compiler. | 464 | "The default macro-environment passed to macroexpand by the compiler. |
| 450 | Placing a macro here will cause a macro to have different semantics when | 465 | Placing a macro here will cause a macro to have different semantics when |
| 451 | expanded by the compiler as when expanded by the interpreter.") | 466 | expanded by the compiler as when expanded by the interpreter.") |
| @@ -2198,9 +2213,12 @@ list that represents a doc string reference. | |||
| 2198 | (t form))) | 2213 | (t form))) |
| 2199 | 2214 | ||
| 2200 | ;; byte-hunk-handlers cannot call this! | 2215 | ;; byte-hunk-handlers cannot call this! |
| 2201 | (defun byte-compile-toplevel-file-form (form) | 2216 | (defun byte-compile-toplevel-file-form (top-level-form) |
| 2202 | (let ((byte-compile-current-form nil)) ; close over this for warnings. | 2217 | (byte-compile-recurse-toplevel |
| 2203 | (byte-compile-file-form (byte-compile-preprocess form t)))) | 2218 | top-level-form |
| 2219 | (lambda (form) | ||
| 2220 | (let ((byte-compile-current-form nil)) ; close over this for warnings. | ||
| 2221 | (byte-compile-file-form (byte-compile-preprocess form t)))))) | ||
| 2204 | 2222 | ||
| 2205 | ;; byte-hunk-handlers can call this. | 2223 | ;; byte-hunk-handlers can call this. |
| 2206 | (defun byte-compile-file-form (form) | 2224 | (defun byte-compile-file-form (form) |
| @@ -2942,8 +2960,11 @@ for symbols generated by the byte compiler itself." | |||
| 2942 | interactive-only)) | 2960 | interactive-only)) |
| 2943 | (t ".")))) | 2961 | (t ".")))) |
| 2944 | (if (eq (car-safe (symbol-function (car form))) 'macro) | 2962 | (if (eq (car-safe (symbol-function (car form))) 'macro) |
| 2945 | (byte-compile-log-warning | 2963 | (progn |
| 2946 | (format "Forgot to expand macro %s" (car form)) nil :error)) | 2964 | (debug) |
| 2965 | (byte-compile-log-warning | ||
| 2966 | (format "Forgot to expand macro %s in %S" (car form) form) | ||
| 2967 | nil :error))) | ||
| 2947 | (if (and handler | 2968 | (if (and handler |
| 2948 | ;; Make sure that function exists. | 2969 | ;; Make sure that function exists. |
| 2949 | (and (functionp handler) | 2970 | (and (functionp handler) |
diff --git a/lisp/emacs-lisp/macroexp.el b/lisp/emacs-lisp/macroexp.el index e3a746fa69e..c2bfc891b72 100644 --- a/lisp/emacs-lisp/macroexp.el +++ b/lisp/emacs-lisp/macroexp.el | |||
| @@ -97,7 +97,10 @@ each clause." | |||
| 97 | (defun macroexp--compiler-macro (handler form) | 97 | (defun macroexp--compiler-macro (handler form) |
| 98 | (condition-case err | 98 | (condition-case err |
| 99 | (apply handler form (cdr form)) | 99 | (apply handler form (cdr form)) |
| 100 | (error (message "Compiler-macro error for %S: %S" (car form) err) | 100 | (error |
| 101 | (message "--------------------------------------------------") | ||
| 102 | (backtrace) | ||
| 103 | (message "Compiler-macro error for %S: %S" (car form) err) | ||
| 101 | form))) | 104 | form))) |
| 102 | 105 | ||
| 103 | (defun macroexp--funcall-if-compiled (_form) | 106 | (defun macroexp--funcall-if-compiled (_form) |
diff --git a/test/ChangeLog b/test/ChangeLog index 942455ad22b..4003a24bc6b 100644 --- a/test/ChangeLog +++ b/test/ChangeLog | |||
| @@ -1,5 +1,12 @@ | |||
| 1 | 2014-04-21 Daniel Colascione <dancol@dancol.org> | 1 | 2014-04-21 Daniel Colascione <dancol@dancol.org> |
| 2 | 2 | ||
| 3 | * automated/bytecomp-tests.el (test-byte-comp-compile-and-load): | ||
| 4 | New function. | ||
| 5 | (test-byte-comp-macro-expansion) | ||
| 6 | (test-byte-comp-macro-expansion-eval-and-compile) | ||
| 7 | (test-byte-comp-macro-expansion-eval-when-compile) | ||
| 8 | (test-byte-comp-macro-expand-lexical-override): New tests. | ||
| 9 | |||
| 3 | * automated/cl-lib.el (cl-loop-destructuring-with): New test. | 10 | * automated/cl-lib.el (cl-loop-destructuring-with): New test. |
| 4 | (cl-the): Fix cl-the test. | 11 | (cl-the): Fix cl-the test. |
| 5 | 12 | ||
diff --git a/test/automated/bytecomp-tests.el b/test/automated/bytecomp-tests.el index 0a9a301dd0d..e61c7c3a41d 100644 --- a/test/automated/bytecomp-tests.el +++ b/test/automated/bytecomp-tests.el | |||
| @@ -305,6 +305,56 @@ Subtests signal errors if something goes wrong." | |||
| 305 | 'face fail-face))) | 305 | 'face fail-face))) |
| 306 | (insert "\n")))) | 306 | (insert "\n")))) |
| 307 | 307 | ||
| 308 | (defun test-byte-comp-compile-and-load (&rest forms) | ||
| 309 | (let ((elfile nil) | ||
| 310 | (elcfile nil)) | ||
| 311 | (unwind-protect | ||
| 312 | (progn | ||
| 313 | (setf elfile (make-temp-file "test-bytecomp" nil ".el")) | ||
| 314 | (setf elcfile (make-temp-file "test-bytecomp" nil ".elc")) | ||
| 315 | (with-temp-buffer | ||
| 316 | (dolist (form forms) | ||
| 317 | (print form (current-buffer))) | ||
| 318 | (write-region (point-min) (point-max) elfile)) | ||
| 319 | (let ((byte-compile-dest-file elcfile)) | ||
| 320 | (byte-compile-file elfile t))) | ||
| 321 | (when elfile (delete-file elfile)) | ||
| 322 | (when elcfile (delete-file elcfile))))) | ||
| 323 | (put 'test-byte-comp-compile-and-load 'lisp-indent-function 0) | ||
| 324 | |||
| 325 | (ert-deftest test-byte-comp-macro-expansion () | ||
| 326 | (test-byte-comp-compile-and-load | ||
| 327 | '(progn (defmacro abc (arg) 1) (defun def () (abc 2)))) | ||
| 328 | (should (equal (funcall 'def) 1))) | ||
| 329 | |||
| 330 | (ert-deftest test-byte-comp-macro-expansion-eval-and-compile () | ||
| 331 | (test-byte-comp-compile-and-load | ||
| 332 | '(eval-and-compile (defmacro abc (arg) -1) (defun def () (abc 2)))) | ||
| 333 | (should (equal (funcall 'def) -1))) | ||
| 334 | |||
| 335 | (ert-deftest test-byte-comp-macro-expansion-eval-when-compile () | ||
| 336 | ;; Make sure we interpret eval-when-compile forms properly. CLISP | ||
| 337 | ;; and SBCL interpreter eval-when-compile (well, the CL equivalent) | ||
| 338 | ;; in the same way. | ||
| 339 | (test-byte-comp-compile-and-load | ||
| 340 | '(eval-when-compile | ||
| 341 | (defmacro abc (arg) -10) | ||
| 342 | (defun abc-1 () (abc 2))) | ||
| 343 | '(defmacro abc-2 () (abc-1)) | ||
| 344 | '(defun def () (abc-2))) | ||
| 345 | (should (equal (funcall 'def) -10))) | ||
| 346 | |||
| 347 | (ert-deftest test-byte-comp-macro-expand-lexical-override () | ||
| 348 | ;; Intuitively, one might expect the defmacro to override the | ||
| 349 | ;; macrolet since macrolet's is explicitly called out as being | ||
| 350 | ;; equivalent to toplevel, but CLISP and SBCL both evaluate the form | ||
| 351 | ;; this way, so we should too. | ||
| 352 | (test-byte-comp-compile-and-load | ||
| 353 | '(require 'cl-lib) | ||
| 354 | '(cl-macrolet ((m () 4)) | ||
| 355 | (defmacro m () 5) | ||
| 356 | (defun def () (m)))) | ||
| 357 | (should (equal (funcall 'def) 4))) | ||
| 308 | 358 | ||
| 309 | ;; Local Variables: | 359 | ;; Local Variables: |
| 310 | ;; no-byte-compile: t | 360 | ;; no-byte-compile: t |