Subject: Re: bug#67196: M-: uses a wrong value of debug-on-error when it is nil.

From: Stefan Monnier <[email-masked]>
Date: Tue, 19 Dec 2023 00:05:02 -0500

>   > > Side note: there's recently been several things pointing to the need to
>   > > add something like Common Lisp's `handler-bind`.
>
> Could someone explain the `handler-bind' construct and show its
> documentation?  It might be a good idea, but it could be that we can
> do better,

Here's my current handler-bind patch, which includes some doc.

        Stefan
commit 7252f6b48944e22980f4030c98a6c7b05243e19e
Author: Stefan Monnier <[email-masked]>
Date:   Tue Dec 19 00:03:25 2023 -0500

    tramp.el: Use `handler-bind` instead of `signal-hook-function`
    
    * lisp/net/tramp.el (tramp--trace-errors): Rename from
    `tramp-signal-hook-function` and change calling convention for
    `handler-bind`.
    (tramp-unknown-id-string, tramp-unknown-id-integer):
    Don't use `defconst` for vars which we let-bind (in tramp-tests.el).
    (tramp-file-name-handler): Use `handler-bind` instead of let-binding
    `signal-hook-function`.
    (tramp-handle-lock-file, tramp-handle-load, tramp-add-hops)
    (tramp-run-real-handler):
    * lisp/net/tramp-sshfs.el (tramp-sshfs-handle-insert-file-contents):
    * lisp/net/tramp-sh.el (tramp-sh-get-signal-strings):
    (tramp-send-command-and-read):
    * lisp/net/tramp-message.el (tramp-debug-message, tramp-error):
    * lisp/net/tramp-adb.el (tramp-do-parse-file-attributes-with-ls): Don't
    let-bind `signal-hook-function`.

diff --git a/lisp/net/tramp-adb.el b/lisp/net/tramp-adb.el
index e4d3ba8c74b..0b68e7384b2 100644
--- a/lisp/net/tramp-adb.el
+++ b/lisp/net/tramp-adb.el
@@ -297,9 +297,7 @@ tramp-do-parse-file-attributes-with-ls
 		 (cons uid tramp-unknown-id-integer)
 		 (cons gid tramp-unknown-id-integer)
 		 tramp-time-dont-know   ; atime
-		 ;; `date-to-time' checks `iso8601-parse', which might fail.
-		 (let (signal-hook-function)
-		   (date-to-time date))	; mtime
+		 (date-to-time date)	; mtime
 		 tramp-time-dont-know   ; ctime
 		 size
 		 mod-string
diff --git a/lisp/net/tramp-message.el b/lisp/net/tramp-message.el
index e05357f1f4f..924f4d15ad2 100644
--- a/lisp/net/tramp-message.el
+++ b/lisp/net/tramp-message.el
@@ -207,8 +207,7 @@ tramp-debug-message
 ARGUMENTS to actually emit the message (if applicable)."
   (declare (tramp-suppress-trace t))
   (let ((inhibit-message t)
-	create-lockfiles file-name-handler-alist message-log-max
-	signal-hook-function)
+	create-lockfiles file-name-handler-alist message-log-max)
     (with-current-buffer (tramp-get-debug-buffer vec)
       (goto-char (point-max))
       (let ((point (point)))
@@ -364,7 +363,7 @@ tramp-error
 signal identifier to be raised, remaining arguments passed to
 `tramp-message'.  Finally, signal SIGNAL is raised with
 FMT-STRING and ARGUMENTS."
-  (let (signal-hook-function)
+  (let ()
     (tramp-backtrace vec-or-proc)
     (unless arguments
       ;; FMT-STRING could be just a file name, as in
diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el
index a7ead1f2997..77ab5b0a399 100644
--- a/lisp/net/tramp-sh.el
+++ b/lisp/net/tramp-sh.el
@@ -3168,12 +3168,11 @@ tramp-sh-get-signal-strings
 	(setcdr signals (cddr signals)))
       ;; Sanity check.  "kill -l" shall have returned just the signal
       ;; names.  Some shells don't, like the one in "docker alpine".
-      (let (signal-hook-function)
-	(condition-case nil
-	    (dolist (sig (cdr signals))
-	      (unless (string-match-p (rx bol (+ (any "+-" alnum)) eol) sig)
-		(error nil)))
-	  (error (setq signals '(0)))))
+      (condition-case nil
+	  (dolist (sig (cdr signals))
+	    (unless (string-match-p (rx bol (+ (any "+-" alnum)) eol) sig)
+	      (error nil)))
+	(error (setq signals '(0))))
       (dotimes (i 128)
 	(push
 	 (cond
@@ -5536,9 +5535,7 @@ tramp-send-command-and-read
       ;; Read the expression.
       (condition-case nil
 	  (prog1
-	      (let ((signal-hook-function
-		     (unless noerror signal-hook-function)))
-		(read (current-buffer)))
+	      (read (current-buffer))
 	    ;; Error handling.
 	    (when (search-forward-regexp (rx (not space)) (line-end-position) t)
 	      (error nil)))
diff --git a/lisp/net/tramp-sshfs.el b/lisp/net/tramp-sshfs.el
index 102ba637f55..afc2033ee6e 100644
--- a/lisp/net/tramp-sshfs.el
+++ b/lisp/net/tramp-sshfs.el
@@ -242,7 +242,7 @@ tramp-sshfs-handle-insert-file-contents
   (filename &optional visit beg end replace)
   "Like `insert-file-contents' for Tramp files."
   (setq filename (expand-file-name filename))
-  (let (signal-hook-function result)
+  (let (result)
     (unwind-protect
         (setq result
 	      (insert-file-contents
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index 88cbfa2d88c..ebdc8bf97ef 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -1085,10 +1085,10 @@ tramp-postfix-host-regexp
 (defconst tramp-localname-regexp (rx (* (not (any "\r\n"))) eos)
   "Regexp matching localnames.")
 
-(defconst tramp-unknown-id-string "UNKNOWN"
+(defvar tramp-unknown-id-string "UNKNOWN"
   "String used to denote an unknown user or group.")
 
-(defconst tramp-unknown-id-integer -1
+(defvar tramp-unknown-id-integer -1
   "Integer used to denote an unknown user or group.")
 
 ;;;###tramp-autoload
@@ -1994,16 +1994,16 @@ tramp-barf-if-file-missing
 
 ;; This function provides traces in case of errors not triggered by
 ;; Tramp functions.
-(defun tramp-signal-hook-function (error-symbol data)
-  "Function to be called via `signal-hook-function'."
+(defun tramp--trace-errors (err)
+  "Function to be called via `handler-bind'."
   ;; `custom-initialize-*' functions provoke `void-variable' errors.
   ;; We don't want to see them in the backtrace.
   (declare (tramp-suppress-trace t))
-  (unless (eq error-symbol 'void-variable)
+  (unless (eq (car err) 'void-variable)
     (let ((inhibit-message t))
       (tramp-error
-       (car tramp-current-connection) error-symbol
-       (mapconcat (lambda (x) (format "%s" x)) data " ")))))
+       (car tramp-current-connection) (car err)
+       (mapconcat (lambda (x) (format "%s" x)) (cdr err) " ")))))
 
 (defmacro with-parsed-tramp-file-name (filename var &rest body)
   "Parse a Tramp filename and make components available in the body.
@@ -2081,7 +2081,7 @@ with-tramp-progress-reporter
 (defmacro with-tramp-timeout (list &rest body)
   "Like `with-timeout', but allow SECONDS to be nil.
 
-(fn (SECONDS TIMEOUT-FORMS...) BODY)"
+\(fn (SECONDS TIMEOUT-FORMS...) BODY)"
   (declare (indent 1) (debug ((form body) body)))
   (let ((seconds (car list))
 	(timeout-forms (cdr list)))
@@ -2248,8 +2248,7 @@ tramp-run-real-handler
 	    ,(and (eq inhibit-file-name-operation operation)
 		  inhibit-file-name-handlers)))
 	 (inhibit-file-name-operation operation)
-	 (args (if (tramp-file-name-p (car args)) (cons nil (cdr args)) args))
-	 signal-hook-function)
+	 (args (if (tramp-file-name-p (car args)) (cons nil (cdr args)) args)))
     (apply operation args)))
 
 ;; We handle here all file primitives.  Most of them have the file
@@ -2386,8 +2385,8 @@ tramp-file-name-handler
             (let ((current-connection tramp-current-connection)
 		  (foreign
 		   (tramp-find-foreign-file-name-handler v operation))
-		  (signal-hook-function #'tramp-signal-hook-function)
 		  result)
+	      (handler-bind ((error #'tramp--trace-errors))
 	      ;; Set `tramp-current-connection'.
 	      (unless
 		  (tramp-file-name-equal-p v (car tramp-current-connection))
@@ -2453,7 +2452,7 @@ tramp-file-name-handler
 		(unless
 		    (tramp-file-name-equal-p
 		     (car current-connection) (car tramp-current-connection))
-		  (setq tramp-current-connection current-connection))))))
+		  (setq tramp-current-connection current-connection)))))))
 
       ;; When `tramp-mode' is not enabled, or the file name is quoted,
       ;; we don't do anything.
@@ -4584,7 +4583,7 @@ tramp-handle-lock-file
 
 	;; Do the lock.
         (let ((tramp-verbose 0)
-              create-lockfiles signal-hook-function)
+              create-lockfiles)
 	  (condition-case nil
 	      (make-symbolic-link info lockname 'ok-if-already-exists)
 	    (error
@@ -4632,8 +4631,7 @@ tramp-handle-load
       (tramp-error v 'file-missing file))
     (if (not (file-exists-p file))
 	nil
-      (let ((signal-hook-function (unless noerror signal-hook-function))
-	    (inhibit-message (or inhibit-message nomessage)))
+      (let ((inhibit-message (or inhibit-message nomessage)))
 	(with-tramp-progress-reporter v 0 (format "Loading %s" file)
 	  (let ((local-copy (file-local-copy file)))
 	    (unwind-protect
@@ -4651,7 +4649,7 @@ tramp-add-hops
   "Add ad-hoc proxy definitions to `tramp-default-proxies-alist'."
   (when-let ((hops (tramp-file-name-hop vec))
 	     (item vec))
-    (let (signal-hook-function changed)
+    (let (changed)
       (dolist
 	  (proxy (reverse (split-string hops tramp-postfix-hop-regexp 'omit)))
 	(let* ((host-port (tramp-file-name-host-port item))