]> git.eshelyaron.com Git - emacs.git/commitdiff
Warn about unreachable code
authorEshel Yaron <me@eshelyaron.com>
Thu, 26 Sep 2024 12:03:42 +0000 (14:03 +0200)
committerEshel Yaron <me@eshelyaron.com>
Thu, 26 Sep 2024 12:18:37 +0000 (14:18 +0200)
* lisp/emacs-lisp/byte-opt.el (byte-opt--every)
(byte-opt--return-p): New functions.
(byte-optimize-body): Emit warning for unreachable code.

lisp/emacs-lisp/byte-opt.el

index d8dbfa62bf96b4caf9cddef164475a3e421ee388..dc97080fbc2ac67c4478a21f77ee16d4ce62ef03 100644 (file)
@@ -674,6 +674,42 @@ There can be multiple entries for the same NAME if it has several aliases.")
               (car form))
        (byte-optimize-body (cdr form) for-effect)))))
 
+(defun byte-opt--every (pred seq)
+  "Check whether PRED holds for every element of SEQ."
+  (while (and seq (funcall pred (car seq)))
+    (setq seq (cdr seq)))
+  (null seq))
+
+(defun byte-opt--return-p (form)
+  "Check whether evaluating FORM may return.
+If this function returns nil, then FORM never returns."
+  (unless (memq (car-safe form) '(throw signal error user-error))
+    (pcase form
+      (`(,(or 'let 'let*) ,bindings . ,body)
+       (and (byte-opt--every (lambda (binding)
+                               (byte-opt--return-p
+                                (if (cdr binding) (cadr binding) (car binding))))
+                             bindings)
+            (byte-opt--every #'byte-opt--return-p body)))
+      (`(,(or 'progn 'prog1 'save-excursion 'save-restriction 'save-current-buffer) . ,exps)
+       (byte-opt--every #'byte-opt--return-p exps))
+      (`(if ,test ,then . ,else)
+       (and (byte-opt--return-p test)
+            (or (byte-opt--return-p then)
+                (byte-opt--every #'byte-opt--return-p else))))
+      (`(,(or 'and 'or) . ,exps)
+       (not (byte-opt--every (lambda (exp) (not (byte-opt--return-p exp))) exps)))
+      (`(while ,exp . ,exps)
+       (and (not (byte-compile-trueconstp exp))
+            (byte-opt--every #'byte-opt--return-p exps)))
+      ;; (`(cond . ,clauses) ...)
+      ;; (`(condition-case ,var ,exp . ,clauses) ...)
+      ;; (`(unwind-protect ,protected-expr :fun-body ,unwind-fun) ...)
+      ;; (`(catch ,tag . ,exps) ...)
+      ;; (`(internal-make-closure ,vars ,env . ,rest) ...)
+      ;; (`(setq ,var ,expr . ,more) ...)
+      ;; (`(defvar ,var . ,rest) ...)
+      (_ t))))
 
 (defun byte-optimize-body (forms all-for-effect)
   ;; Optimize the cdr of a progn or implicit progn; all forms is a list of
@@ -692,7 +728,9 @@ There can be multiple entries for the same NAME if it has several aliases.")
         (setq new (pop result)))
       (when (or new (not fe))
        (setq result (cons new result)))
-      (setq rest (cdr rest)))
+      (setq rest (cdr rest))
+      (when (and rest (not (byte-opt--return-p new)))
+        (byte-compile-warn-x rest "Unreachable code")))
     (nreverse result)))
 
 \f