emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

scratch/pkg 8e8a256832f 2/2: Merge remote-tracking branch 'origin/master


From: Gerd Moellmann
Subject: scratch/pkg 8e8a256832f 2/2: Merge remote-tracking branch 'origin/master' into scratch/pkg
Date: Mon, 28 Aug 2023 10:40:55 -0400 (EDT)

branch: scratch/pkg
commit 8e8a256832f7ad4854b27e05e879bd7fdae9d2f2
Merge: fd58c37fca0 4986c2a088e
Author: Gerd Möllmann <gerd@gnu.org>
Commit: Gerd Möllmann <gerd@gnu.org>

    Merge remote-tracking branch 'origin/master' into scratch/pkg
---
 .clangd                                            |   5 +
 doc/emacs/sending.texi                             |  22 ++
 doc/misc/smtpmail.texi                             |   6 +-
 doc/misc/transient.texi                            |  66 +++---
 etc/ERC-NEWS                                       |   7 +
 java/org/gnu/emacs/EmacsActivity.java              |   8 -
 java/org/gnu/emacs/EmacsContextMenu.java           |   4 -
 java/org/gnu/emacs/EmacsDialog.java                |  12 -
 java/org/gnu/emacs/EmacsOpenActivity.java          |  12 -
 java/org/gnu/emacs/EmacsView.java                  | 105 +++++++--
 .../gnu/emacs/EmacsWindowAttachmentManager.java    |  24 --
 lisp/align.el                                      |  36 +--
 lisp/auth-source-pass.el                           |   8 +-
 lisp/auth-source.el                                |   3 +-
 lisp/calendar/appt.el                              |   3 +-
 lisp/cedet/mode-local.el                           |   2 +-
 lisp/cedet/semantic/fw.el                          |   5 +-
 lisp/cedet/semantic/grammar.el                     |   9 +-
 lisp/cus-edit.el                                   |   6 +-
 lisp/cus-theme.el                                  |  34 ++-
 lisp/custom.el                                     |   2 +-
 lisp/dired-x.el                                    |   6 +-
 lisp/dired.el                                      |   2 +-
 lisp/emacs-lisp/bytecomp.el                        |   2 -
 lisp/emacs-lisp/checkdoc.el                        |   3 +-
 lisp/emacs-lisp/eieio.el                           |   3 +-
 lisp/emacs-lisp/lisp-mode.el                       |   5 -
 lisp/emacs-lisp/pp.el                              |   1 -
 lisp/emulation/cua-base.el                         |   2 +-
 lisp/epg.el                                        |   3 +-
 lisp/erc/erc-button.el                             |  36 ++-
 lisp/erc/erc-common.el                             |   9 +-
 lisp/erc/erc-log.el                                |   9 +
 lisp/erc/erc-networks.el                           |  29 ++-
 lisp/erc/erc-speedbar.el                           | 112 +++++----
 lisp/erc/erc-truncate.el                           |  45 +++-
 lisp/eshell/em-ls.el                               |   6 +-
 lisp/eshell/esh-proc.el                            |   6 +-
 lisp/faces.el                                      |   3 +-
 lisp/files.el                                      |  10 +-
 lisp/format.el                                     |   2 +-
 lisp/gnus/gnus-cite.el                             |   6 -
 lisp/gnus/gnus-score.el                            |  11 +-
 lisp/gnus/gnus-uu.el                               |   3 +-
 lisp/gnus/message.el                               |   5 +-
 lisp/gnus/mm-view.el                               |   2 -
 lisp/gnus/nnmail.el                                |   4 +-
 lisp/gnus/nnmairix.el                              |   3 +-
 lisp/gnus/spam.el                                  |   3 +-
 lisp/help-fns.el                                   |   3 +-
 lisp/ibuf-macs.el                                  |   2 +-
 lisp/international/mule-cmds.el                    |   3 +-
 lisp/mail/rmail.el                                 |   4 +-
 lisp/net/eww.el                                    |   2 +-
 lisp/net/imap.el                                   |   2 +-
 lisp/net/tramp-adb.el                              |   2 +-
 lisp/net/tramp-cache.el                            |  17 +-
 lisp/net/tramp-message.el                          |  24 +-
 lisp/net/tramp.el                                  |  41 ++--
 lisp/org/org.el                                    |   1 -
 lisp/org/ox-beamer.el                              |   9 +-
 lisp/printing.el                                   |   3 +-
 lisp/progmodes/cperl-mode.el                       |   2 -
 lisp/progmodes/elisp-mode.el                       |  39 ++--
 lisp/progmodes/f90.el                              |   1 -
 lisp/progmodes/idlw-help.el                        |   1 -
 lisp/progmodes/idlwave.el                          |   1 -
 lisp/progmodes/make-mode.el                        |   2 +-
 lisp/progmodes/project.el                          |   7 +-
 lisp/progmodes/sh-script.el                        |   7 +-
 lisp/progmodes/sql.el                              |  15 +-
 lisp/speedbar.el                                   |   5 +-
 lisp/strokes.el                                    |   7 +-
 lisp/tab-bar.el                                    |  43 ++--
 lisp/tab-line.el                                   |  90 ++++---
 lisp/textmodes/ispell.el                           |   1 +
 lisp/textmodes/reftex-cite.el                      |   4 +-
 lisp/textmodes/reftex-index.el                     |   4 +-
 lisp/textmodes/reftex-ref.el                       |   1 -
 lisp/textmodes/reftex-sel.el                       |   2 +-
 lisp/textmodes/reftex-toc.el                       |   2 +-
 lisp/textmodes/reftex-vars.el                      |   1 -
 lisp/textmodes/reftex.el                           |  16 +-
 lisp/textmodes/rst.el                              |   3 +-
 lisp/textmodes/tex-mode.el                         |   6 +-
 lisp/transient.el                                  | 245 ++++++++++---------
 lisp/vc/cvs-status.el                              |   4 +-
 lisp/vc/diff.el                                    |   2 +-
 lisp/vc/ediff-util.el                              |   2 +-
 lisp/vc/smerge-mode.el                             |   4 -
 lisp/vc/vc-dir.el                                  |   3 +-
 lisp/vc/vc-git.el                                  |   1 -
 lisp/vc/vc-hg.el                                   |   1 -
 lisp/wid-edit.el                                   |   3 +-
 lisp/windmove.el                                   |  10 +-
 lisp/window.el                                     |   3 +-
 lisp/woman.el                                      |   6 +-
 src/emacs.c                                        |   2 +-
 src/fileio.c                                       |   4 +-
 src/frame.c                                        |  15 +-
 src/frame.h                                        |   4 +
 src/haikuterm.c                                    |   4 +-
 src/image.c                                        | 165 +++++++------
 src/keyboard.c                                     |   3 +-
 src/nsfns.m                                        |   6 +
 src/xterm.c                                        | 260 ++++++++++++++++-----
 test/lisp/erc/erc-button-tests.el                  |  28 +++
 test/lisp/erc/erc-scenarios-log.el                 |   1 +
 test/lisp/erc/erc-scenarios-status-sidebar.el      |  13 +-
 test/lisp/erc/erc-tests.el                         |  10 +-
 test/lisp/erc/resources/erc-scenarios-common.el    |   1 +
 test/manual/image-tests.el                         |  14 +-
 112 files changed, 1096 insertions(+), 801 deletions(-)

diff --git a/.clangd b/.clangd
new file mode 100644
index 00000000000..131d0af5843
--- /dev/null
+++ b/.clangd
@@ -0,0 +1,5 @@
+---
+If:
+    PathMatch: "src/.*\.c"
+CompileFlags:
+    Add: [-Wno-unused-macros, -include=config.h]
diff --git a/doc/emacs/sending.texi b/doc/emacs/sending.texi
index 6b94cd0b737..fb566a7f7f4 100644
--- a/doc/emacs/sending.texi
+++ b/doc/emacs/sending.texi
@@ -257,6 +257,24 @@ of the address, such as the person's full name.  Emacs 
puts them in if
 they are needed.  For instance, it inserts the above address as
 @samp{"John Q. Smith" <none@@example.com>}.
 
+@findex rebuild-mail-abbrevs
+@findex merge-mail-abbrevs
+  After editing the @file{~/.mailrc} file, or if the file was modified
+outside of Emacs, you can update the mail aliases used by a running
+Emacs session with @w{@kbd{M-x rebuild-mail-abbrevs @key{RET}}}.  This
+prompts for the name of the file to use, the default being the value
+of @code{mail-personal-alias-file}.  A similar command
+@code{merge-mail-abbrevs} prompts for a file with mail aliases, then
+merges the aliases in that file with the existing ones.
+
+@findex define-mail-abbrev
+  Alternatively, you can use Emacs commands to define mail aliases.
+The command @code{define-mail-abbrev} prompts for the alias and the
+full address, and defines the alias to expand to the full address.
+Emacs will save the added aliases whenever it offers to save all
+files (for @kbd{C-x s} or @kbd{C-x C-c}), like it does with other
+abbrevs (@pxref{Saving Abbrevs}).
+
   Emacs also recognizes include commands in @file{~/.mailrc}.  They
 look like this:
 
@@ -282,6 +300,10 @@ fields, such as @samp{Subject}.
 @kbd{M-x mail-abbrev-insert-alias}.  This reads an alias name, with
 completion, and inserts its definition at point.
 
+@findex mail-abbrev-complete-alias
+  The command @code{mail-abbrev-complete-alias} completes on the mail
+alias preceding point.
+
 @node Mail Commands
 @section Mail Commands
 @cindex Message mode
diff --git a/doc/misc/smtpmail.texi b/doc/misc/smtpmail.texi
index 99363483827..cc2f4f85fb3 100644
--- a/doc/misc/smtpmail.texi
+++ b/doc/misc/smtpmail.texi
@@ -264,12 +264,14 @@ file, @pxref{Top,,auth-source, auth, Emacs auth-source 
Library}.
 @cindex CRAM-MD5
 @cindex PLAIN
 @cindex LOGIN
+@cindex OAuth2
+@cindex OAuth 2.0
 The process by which the @acronym{SMTP} library authenticates you to
 the server is known as ``Simple Authentication and Security Layer''
 (@acronym{SASL}).  There are various @acronym{SASL} mechanisms, and
-this library supports three of them: @code{cram-md5}, @code{plain},
+this library supports four of them: @code{cram-md5}, @code{plain},
 @code{login} and @code{xoauth2}, where the first uses a form of
-encryption to obscure your password, while the other two do not.  It
+encryption to obscure your password, while the others do not.  It
 tries each of them, in that order, until one succeeds.
 (@code{xoauth2} requires using the @file{oauth2.el} library.  You can
 override this by assigning a specific authentication mechanism to a
diff --git a/doc/misc/transient.texi b/doc/misc/transient.texi
index be9e8698ab4..e6144dcf2bc 100644
--- a/doc/misc/transient.texi
+++ b/doc/misc/transient.texi
@@ -31,7 +31,7 @@ General Public License for more details.
 @finalout
 @titlepage
 @title Transient User and Developer Manual
-@subtitle for version 0.4.1
+@subtitle for version 0.4.3
 @author Jonas Bernoulli
 @page
 @vskip 0pt plus 1filll
@@ -74,7 +74,7 @@ that hurdle is Psionic K's interactive tutorial, available at
 @end quotation
 
 @noindent
-This manual is for Transient version 0.4.1.
+This manual is for Transient version 0.4.3.
 
 @insertcopying
 @end ifnottex
@@ -248,18 +248,18 @@ When using Transient, one can call a command with 
arguments that are
 just as complex as when calling the same function non-interactively
 from Lisp.
 
-Invoking a transient command with arguments is similar to invoking a
-command in a shell with command-line completion and history enabled.
-One benefit of the Transient interface is that it remembers history
-not only on a global level (“this command was invoked using these
-arguments, and previously it was invoked using those other arguments”),
-but also remembers the values of individual arguments independently.
-@xref{Using History}.
+Invoking a transient suffix command with arguments is similar to
+invoking a command in a shell with command-line completion and history
+enabled.  One benefit of the Transient interface is that it remembers
+history not only on a global level (“this command was invoked using
+these arguments, and previously it was invoked using those other
+arguments”), but also remembers the values of individual arguments
+independently.  See @xref{Using History}.
 
 After a transient prefix command is invoked, @kbd{C-h @var{KEY}} can be used to
 show the documentation for the infix or suffix command that @kbd{@var{KEY}} is
-bound to (@pxref{Getting Help for Suffix Commands}), and infixes and
-suffixes can be removed from the transient using @kbd{C-x l @var{KEY}}.  
Infixes
+bound to (see @ref{Getting Help for Suffix Commands}), and infixes and
+suffixes can be removed from the transient using @kbd{C-x l @var{KEY}}. Infixes
 and suffixes that are disabled by default can be enabled the same way.
 @xref{Enabling and Disabling Suffixes}.
 
@@ -270,21 +270,26 @@ Additionally, Transient provides abstractions for 
defining new types,
 which the author of Transient did not anticipate (or didn't get around
 to implementing yet).
 
+Note that suffix commands also support regular prefix arguments.  A
+suffix command may even be called with both infix and prefix arguments
+at the same time.  If you invoke a command as a suffix of a transient
+prefix command, but also want to pass prefix arguments to it, then
+first invoke the prefix command, and only after doing that invoke the
+prefix arguments, before finally invoking the suffix command.  If you
+instead began by providing the prefix arguments, then those would
+apply to the prefix command, not the suffix command.  Likewise, if you
+want to change infix arguments before invoking a suffix command with
+prefix arguments, then change the infix arguments before invoking the
+prefix arguments.  In other words, regular prefix arguments always
+apply to the next command, and since transient prefix, infix and
+suffix commands are just regular commands, the same applies to them.
+(Regular prefix keys behave differently because they are not commands
+at all, instead they are just incomplete key sequences, and those
+cannot be interrupted with prefix commands.)
+
 @node Usage
 @chapter Usage
 
-@menu
-* Invoking Transients::
-* Aborting and Resuming Transients::
-* Common Suffix Commands::
-* Saving Values::
-* Using History::
-* Getting Help for Suffix Commands::
-* Enabling and Disabling Suffixes::
-* Other Commands::
-* Configuration::
-@end menu
-
 @node Invoking Transients
 @section Invoking Transients
 
@@ -997,14 +1002,6 @@ signal an error.
 @node Defining New Commands
 @chapter Defining New Commands
 
-@menu
-* Defining Transients::
-* Binding Suffix and Infix Commands::
-* Defining Suffix and Infix Commands::
-* Using Infix Arguments::
-* Transient State::
-@end menu
-
 @node Defining Transients
 @section Defining Transients
 
@@ -2234,11 +2231,6 @@ available depending on user preference.
 @node Related Abstractions and Packages
 @chapter Related Abstractions and Packages
 
-@menu
-* Comparison With Prefix Keys and Prefix Arguments::
-* Comparison With Other Packages::
-@end menu
-
 @node Comparison With Prefix Keys and Prefix Arguments
 @section Comparison With Prefix Keys and Prefix Arguments
 
@@ -2559,8 +2551,6 @@ currently exist.
 @node FAQ
 @appendix FAQ
 
-
-
 @anchor{Can I control how the popup buffer is displayed?}
 @appendixsec Can I control how the popup buffer is displayed?
 
diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS
index 94452514e6d..7ee55982b17 100644
--- a/etc/ERC-NEWS
+++ b/etc/ERC-NEWS
@@ -196,6 +196,13 @@ these changes has been the deprecation of the ancient 
option
 'erc-truncate-buffer-on-save'.  Users of the 'log' module can achieve
 the same effect by issuing a "/CLEAR" at the prompt.
 
+** The 'truncate' module no longer enables logging automatically.
+Users expecting 'truncate' to perform logging based on the option
+'erc-enable-logging' need to instead add 'log' to 'erc-modules' for
+continued integration.  With the existing design, merely loading the
+library 'erc-log' caused 'truncate' to start writing logs, possibly
+against a user's wishes.
+
 ** Miscellaneous UX changes.
 Some minor quality-of-life niceties have finally made their way to
 ERC.  For example, the function 'erc-echo-timestamp' is now
diff --git a/java/org/gnu/emacs/EmacsActivity.java 
b/java/org/gnu/emacs/EmacsActivity.java
index 4ddf51fbb20..cecd9c21d99 100644
--- a/java/org/gnu/emacs/EmacsActivity.java
+++ b/java/org/gnu/emacs/EmacsActivity.java
@@ -149,8 +149,6 @@ public class EmacsActivity extends Activity
   public final void
   attachWindow (EmacsWindow child)
   {
-    Log.d (TAG, "attachWindow: " + child);
-
     if (window != null)
       throw new IllegalStateException ("trying to attach window when one"
                                       + " already exists");
@@ -257,7 +255,6 @@ public class EmacsActivity extends Activity
 
     /* The activity will die shortly hereafter.  If there is a window
        attached, close it now.  */
-    Log.d (TAG, "onDestroy " + this);
     isMultitask = this instanceof EmacsMultitaskActivity;
     manager.removeWindowConsumer (this, isMultitask || isFinishing ());
     focusedActivities.remove (this);
@@ -274,9 +271,6 @@ public class EmacsActivity extends Activity
   public final void
   onWindowFocusChanged (boolean isFocused)
   {
-    Log.d (TAG, ("onWindowFocusChanged: "
-                + (isFocused ? "YES" : "NO")));
-
     if (isFocused && !focusedActivities.contains (this))
       {
        focusedActivities.add (this);
@@ -323,8 +317,6 @@ public class EmacsActivity extends Activity
   {
     int serial;
 
-    Log.d (TAG, "onContextMenuClosed: " + menu);
-
     /* See the comment inside onMenuItemClick.  */
 
     if (((EmacsContextMenu.wasSubmenuSelected == -2)
diff --git a/java/org/gnu/emacs/EmacsContextMenu.java 
b/java/org/gnu/emacs/EmacsContextMenu.java
index 46eddeeda3d..c5b87aa804a 100644
--- a/java/org/gnu/emacs/EmacsContextMenu.java
+++ b/java/org/gnu/emacs/EmacsContextMenu.java
@@ -72,8 +72,6 @@ public final class EmacsContextMenu
     public boolean
     onMenuItemClick (MenuItem item)
     {
-      Log.d (TAG, "onMenuItemClick: " + itemName + " (" + itemID + ")");
-
       if (subMenu != null)
        {
          /* Android 6.0 and earlier don't support nested submenus
@@ -81,8 +79,6 @@ public final class EmacsContextMenu
 
          if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N)
            {
-             Log.d (TAG, "onMenuItemClick: displaying submenu " + subMenu);
-
              /* Still set wasSubmenuSelected -- if not set, the
                 dismissal of this context menu will result in a
                 context menu event being sent.  */
diff --git a/java/org/gnu/emacs/EmacsDialog.java 
b/java/org/gnu/emacs/EmacsDialog.java
index 2291207fbcc..af3bf538410 100644
--- a/java/org/gnu/emacs/EmacsDialog.java
+++ b/java/org/gnu/emacs/EmacsDialog.java
@@ -88,8 +88,6 @@ public final class EmacsDialog implements 
DialogInterface.OnDismissListener
     public void
     onClick (View view)
     {
-      Log.d (TAG, "onClicked " + this);
-
       wasButtonClicked = true;
       EmacsNative.sendContextMenu ((short) 0, id, menuEventSerial);
       dismissDialog.dismiss ();
@@ -99,8 +97,6 @@ public final class EmacsDialog implements 
DialogInterface.OnDismissListener
     public void
     onClick (DialogInterface dialog, int which)
     {
-      Log.d (TAG, "onClicked " + this);
-
       wasButtonClicked = true;
       EmacsNative.sendContextMenu ((short) 0, id, menuEventSerial);
     }
@@ -300,10 +296,6 @@ public final class EmacsDialog implements 
DialogInterface.OnDismissListener
           work, then any focused EmacsOpenActivity, and finally the
           last EmacsActivity to be focused.  */
 
-       Log.d (TAG, "display1: no focused activities...");
-       Log.d (TAG, ("display1: EmacsOpenActivity.currentActivity: "
-                    + EmacsOpenActivity.currentActivity));
-
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M
            || Settings.canDrawOverlays (EmacsService.SERVICE))
          context = EmacsService.SERVICE;
@@ -321,8 +313,6 @@ public final class EmacsDialog implements 
DialogInterface.OnDismissListener
         consistently.  */
       context = EmacsActivity.focusedActivities.get (0);
 
-    Log.d (TAG, "display1: using context " + context);
-
     dialog = dismissDialog = toAlertDialog (context);
 
     try
@@ -418,8 +408,6 @@ public final class EmacsDialog implements 
DialogInterface.OnDismissListener
   public void
   onDismiss (DialogInterface dialog)
   {
-    Log.d (TAG, "onDismiss: " + this);
-
     if (wasButtonClicked)
       return;
 
diff --git a/java/org/gnu/emacs/EmacsOpenActivity.java 
b/java/org/gnu/emacs/EmacsOpenActivity.java
index 3832cd2faab..ea503ebd120 100644
--- a/java/org/gnu/emacs/EmacsOpenActivity.java
+++ b/java/org/gnu/emacs/EmacsOpenActivity.java
@@ -232,19 +232,14 @@ public final class EmacsOpenActivity extends Activity
     int read;
     String content;
 
-    Log.d (TAG, "checkReadableOrCopy: " + file);
-
     inFile = new File (file);
 
     if (inFile.canRead ())
       return file;
 
-    Log.d (TAG, "checkReadableOrCopy: NO");
-
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
       {
        content = EmacsService.buildContentName (uri);
-       Log.d (TAG, "checkReadableOrCopy: " + content);
        return content;
       }
 
@@ -509,8 +504,6 @@ public final class EmacsOpenActivity extends Activity
   public void
   onDestroy ()
   {
-    Log.d (TAG, "onDestroy: " + this);
-
     /* Clear `currentActivity' if it refers to the activity being
        destroyed.  */
 
@@ -524,9 +517,6 @@ public final class EmacsOpenActivity extends Activity
   public void
   onWindowFocusChanged (boolean isFocused)
   {
-    Log.d (TAG, "onWindowFocusChanged: " + this + ", is now focused: "
-          + isFocused);
-
     if (isFocused)
       currentActivity = this;
     else if (currentActivity == this)
@@ -539,8 +529,6 @@ public final class EmacsOpenActivity extends Activity
   public void
   onPause ()
   {
-    Log.d (TAG, "onPause: " + this);
-
     /* XXX: clear currentActivity here as well; I don't know whether
        or not onWindowFocusChanged is always called prior to this.  */
 
diff --git a/java/org/gnu/emacs/EmacsView.java 
b/java/org/gnu/emacs/EmacsView.java
index 12d8ff4da56..5a4bcbaa005 100644
--- a/java/org/gnu/emacs/EmacsView.java
+++ b/java/org/gnu/emacs/EmacsView.java
@@ -29,6 +29,7 @@ import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
+import android.view.WindowInsets;
 
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
@@ -302,6 +303,26 @@ public final class EmacsView extends ViewGroup
     super.setMeasuredDimension (width, height);
   }
 
+  /* Return whether this view's window is focused.  This is made
+     necessary by Android 11's unreliable dispatch of
+     onWindowFocusChanged prior to gesture navigation away from a
+     frame.  */
+
+  public boolean
+  checkWindowFocus ()
+  {
+    EmacsActivity activity;
+    Object consumer;
+
+    consumer = window.getAttachedConsumer ();
+
+    if (!(consumer instanceof EmacsActivity))
+      return false;
+
+    activity = (EmacsActivity) consumer;
+    return activity.hasWindowFocus ();
+  }
+
   /* Note that the monitor lock for the window must never be held from
      within the lock for the view, because the window also locks the
      other way around.  */
@@ -315,6 +336,7 @@ public final class EmacsView extends ViewGroup
     View child;
     Rect windowRect;
     boolean needExpose;
+    WindowInsets rootWindowInsets;
 
     count = getChildCount ();
     needExpose = false;
@@ -330,11 +352,17 @@ public final class EmacsView extends ViewGroup
        measuredHeight = bottom - top;
       }
 
+    /* If oldMeasuredHeight or oldMeasuredWidth are wrong, set changed
+       to true as well.  */
+
+    if (right - left != oldMeasuredWidth
+       || bottom - top != oldMeasuredHeight)
+      changed = true;
+
     /* Dirty the back buffer if the layout change resulted in the view
        being resized.  */
 
-    if (changed && (right - left != oldMeasuredWidth
-                   || bottom - top != oldMeasuredHeight))
+    if (changed)
       {
        explicitlyDirtyBitmap ();
 
@@ -343,14 +371,37 @@ public final class EmacsView extends ViewGroup
        if (right - left > oldMeasuredWidth
            || bottom - top > oldMeasuredHeight)
          needExpose = true;
+
+       /* This might return NULL if this view is not attached.  */
+       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
+         {
+           /* If a toplevel view is focused and isCurrentlyTextEditor
+              is enabled when the IME is hidden, clear
+              isCurrentlyTextEditor so it isn't shown again if the
+              user dismisses Emacs before returning.  */
+           rootWindowInsets = getRootWindowInsets ();
+
+           if (isCurrentlyTextEditor
+               && rootWindowInsets != null
+               && isAttachedToWindow
+               && !rootWindowInsets.isVisible (WindowInsets.Type.ime ())
+               /* N.B. that the keyboard is dismissed during gesture
+                  navigation under Android 30, but the system is
+                  quite tempermental regarding whether the window is
+                  focused at that point.  Ideally
+                  isCurrentlyTextEditor shouldn't be reset in that
+                  case, but detecting that situation appears to be
+                  impossible.  Sigh.  */
+               && (window == EmacsActivity.focusedWindow
+                   && hasWindowFocus ()))
+             isCurrentlyTextEditor = false;
+         }
       }
 
     for (i = 0; i < count; ++i)
       {
        child = getChildAt (i);
 
-       Log.d (TAG, "onLayout: " + child);
-
        if (child == surfaceView)
          child.layout (0, 0, right - left, bottom - top);
        else if (child.getVisibility () != GONE)
@@ -485,6 +536,8 @@ public final class EmacsView extends ViewGroup
     return window.onTouchEvent (motion);
   }
 
+
+
   private void
   moveChildToBack (View child)
   {
@@ -512,8 +565,6 @@ public final class EmacsView extends ViewGroup
 
     parent = (EmacsView) getParent ();
 
-    Log.d (TAG, "raise: parent " + parent);
-
     if (parent.indexOfChild (this)
        == parent.getChildCount () - 1)
       return;
@@ -528,8 +579,6 @@ public final class EmacsView extends ViewGroup
 
     parent = (EmacsView) getParent ();
 
-    Log.d (TAG, "lower: parent " + parent);
-
     if (parent.indexOfChild (this) == 1)
       return;
 
@@ -556,9 +605,6 @@ public final class EmacsView extends ViewGroup
     contextMenu = menu;
     popupActive = true;
 
-    Log.d (TAG, "popupMenu: " + menu + " @" + xPosition
-          + ", " + yPosition + " " + force);
-
     /* Use showContextMenu (float, float) on N to get actual popup
        behavior.  */
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
@@ -694,14 +740,8 @@ public final class EmacsView extends ViewGroup
 
     selection = EmacsService.viewGetSelection (window.handle);
 
-    if (selection != null)
-      Log.d (TAG, "onCreateInputConnection: current selection is: "
-            + selection[0] + ", by " + selection[1]);
-    else
+    if (selection == null)
       {
-       Log.d (TAG, "onCreateInputConnection: current selection could"
-              + " not be retrieved.");
-
        /* If the selection could not be obtained, return 0 by 0.
           However, ask for the selection position to be updated as
           soon as possible.  */
@@ -774,4 +814,33 @@ public final class EmacsView extends ViewGroup
     window.notifyContentRectPosition (locations[0],
                                      locations[1]);
   }
+
+  @Override
+  public WindowInsets
+  onApplyWindowInsets (WindowInsets insets)
+  {
+    WindowInsets rootWindowInsets;
+
+    /* This function is called when window insets change, which
+       encompasses input method visibility changes under Android 30
+       and later.  If a toplevel view is focused and
+       isCurrentlyTextEditor is enabled when the IME is hidden, clear
+       isCurrentlyTextEditor so it isn't shown again if the user
+       dismisses Emacs before returning.  */
+
+    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R)
+      return super.onApplyWindowInsets (insets);
+
+    /* This might return NULL if this view is not attached.  */
+    rootWindowInsets = getRootWindowInsets ();
+
+    if (isCurrentlyTextEditor
+       && rootWindowInsets != null
+       && isAttachedToWindow
+       && !rootWindowInsets.isVisible (WindowInsets.Type.ime ())
+       && window == EmacsActivity.focusedWindow)
+      isCurrentlyTextEditor = false;
+
+    return super.onApplyWindowInsets (insets);
+  }
 };
diff --git a/java/org/gnu/emacs/EmacsWindowAttachmentManager.java 
b/java/org/gnu/emacs/EmacsWindowAttachmentManager.java
index bc96de7fe1a..4ba5b35aacf 100644
--- a/java/org/gnu/emacs/EmacsWindowAttachmentManager.java
+++ b/java/org/gnu/emacs/EmacsWindowAttachmentManager.java
@@ -87,21 +87,17 @@ public final class EmacsWindowAttachmentManager
   public void
   registerWindowConsumer (WindowConsumer consumer)
   {
-    Log.d (TAG, "registerWindowConsumer " + consumer);
-
     consumers.add (consumer);
 
     for (EmacsWindow window : windows)
       {
        if (window.getAttachedConsumer () == null)
          {
-           Log.d (TAG, "registerWindowConsumer: attaching " + window);
            consumer.attachWindow (window);
            return;
          }
       }
 
-    Log.d (TAG, "registerWindowConsumer: sendWindowAction 0, 0");
     EmacsNative.sendWindowAction ((short) 0, 0);
   }
 
@@ -111,21 +107,16 @@ public final class EmacsWindowAttachmentManager
     Intent intent;
     ActivityOptions options;
 
-    Log.d (TAG, "registerWindow (maybe): " + window);
-
     if (windows.contains (window))
       /* The window is already registered.  */
       return;
 
-    Log.d (TAG, "registerWindow: " + window);
-
     windows.add (window);
 
     for (WindowConsumer consumer : consumers)
       {
        if (consumer.getAttachedWindow () == null)
          {
-           Log.d (TAG, "registerWindow: attaching " + consumer);
            consumer.attachWindow (window);
            return;
          }
@@ -147,8 +138,6 @@ public final class EmacsWindowAttachmentManager
        EmacsService.SERVICE.startActivity (intent,
                                            options.toBundle ());
       }
-
-    Log.d (TAG, "registerWindow: startActivity");
   }
 
   public void
@@ -156,19 +145,14 @@ public final class EmacsWindowAttachmentManager
   {
     EmacsWindow window;
 
-    Log.d (TAG, "removeWindowConsumer " + consumer);
-
     window = consumer.getAttachedWindow ();
 
     if (window != null)
       {
-       Log.d (TAG, "removeWindowConsumer: detaching " + window);
-
        consumer.detachWindow ();
        window.onActivityDetached (isFinishing);
       }
 
-    Log.d (TAG, "removeWindowConsumer: removing " + consumer);
     consumers.remove (consumer);
   }
 
@@ -177,14 +161,10 @@ public final class EmacsWindowAttachmentManager
   {
     WindowConsumer consumer;
 
-    Log.d (TAG, "detachWindow " + window);
-
     if (window.getAttachedConsumer () != null)
       {
        consumer = window.getAttachedConsumer ();
 
-       Log.d (TAG, "detachWindow: removing" + consumer);
-
        consumers.remove (consumer);
        consumer.destroy ();
       }
@@ -197,8 +177,6 @@ public final class EmacsWindowAttachmentManager
   {
     EmacsWindow window;
 
-    Log.d (TAG, "noticeIconified " + consumer);
-
     /* If a window is attached, send the appropriate iconification
        events.  */
     window = consumer.getAttachedWindow ();
@@ -212,8 +190,6 @@ public final class EmacsWindowAttachmentManager
   {
     EmacsWindow window;
 
-    Log.d (TAG, "noticeDeiconified " + consumer);
-
     /* If a window is attached, send the appropriate iconification
        events.  */
     window = consumer.getAttachedWindow ();
diff --git a/lisp/align.el b/lisp/align.el
index bc8ccbd599c..13e31e2ad60 100644
--- a/lisp/align.el
+++ b/lisp/align.el
@@ -1270,6 +1270,14 @@ Otherwise, create a new marker at position POS, with 
type TYPE."
        (move-marker ,marker-var ,pos)
      (setq ,marker-var (copy-marker ,pos ,type))))
 
+(defun align--rule-should-run (rule)
+  "Given an `align-rules-list' entry RULE, return t if it should run.
+This is decided by the `modes' and `run-if' keys in the alist
+RULE.  Their meaning is documented in `align-rules-list' (which see)."
+  (let-alist rule
+    (not (or (and .modes (not (apply #'derived-mode-p (eval .modes))))
+             (and .run-if (not (funcall .run-if)))))))
+
 (defun align-region (beg end separate rules exclude-rules
                         &optional func)
   "Align a region based on a given set of alignment rules.
@@ -1307,23 +1315,20 @@ This feature (of passing a FUNC) is used internally to 
locate the
 position of exclusion areas, but could also be used for any other
 purpose where you might want to know where the regions that the
 aligner would have dealt with are."
-  (let ((end-mark (and end (copy-marker end t)))
-       (real-beg beg)
-       (report (and (not func) align-large-region beg end
-                    (>= (- end beg) align-large-region)))
-       (rule-index 1)
-       (rule-count (length rules))
-       markers)
+  (let* ((end-mark (and end (copy-marker end t)))
+        (real-beg beg)
+        (report (and (not func) align-large-region beg end
+                     (>= (- end beg) align-large-region)))
+         (rules (seq-filter #'align--rule-should-run rules))
+        (rule-index 1)
+        (rule-count (length rules))
+        markers)
     (if (and align-indent-before-aligning real-beg end-mark)
        (indent-region real-beg end-mark nil))
     (while rules
-      (let* ((rule (car rules))
-            (run-if (assq 'run-if rule))
-            (modes (assq 'modes rule)))
-       ;; unless the `run-if' form tells us not to, look for the
-       ;; rule..
-       (unless (or (and modes (not (apply #'derived-mode-p (eval (cdr 
modes)))))
-                   (and run-if (not (funcall (cdr run-if)))))
+      (let ((rule (car rules)))
+        (progn
+          ;; Search for a match for the rule.
          (let* ((case-fold-search case-fold-search)
                 (case-fold (assq 'case-fold rule))
                 (regexp  (cdr (assq 'regexp rule)))
@@ -1458,8 +1463,7 @@ aligner would have dealt with are."
                     ;; that we need it
                     (unless nil ;; group-c
                       (setq groups (or (cdr (assq 'group rule)) 1))
-                      (unless (listp groups)
-                        (setq groups (list groups)))
+                      (setq groups (ensure-list groups))
                       (setq first (car groups)))
 
                     (unless spacing-c
diff --git a/lisp/auth-source-pass.el b/lisp/auth-source-pass.el
index dbcc9d05753..0f51755a250 100644
--- a/lisp/auth-source-pass.el
+++ b/lisp/auth-source-pass.el
@@ -1,6 +1,6 @@
 ;;; auth-source-pass.el --- Integrate auth-source with password-store -*- 
lexical-binding: t -*-
 
-;; Copyright (C) 2015, 2017-2023 Free Software Foundation, Inc.
+;; Copyright (C) 2015-2023 Free Software Foundation, Inc.
 
 ;; Author: Damien Cassou <damien@cassou.me>,
 ;;         Nicolas Petton <nicolas@petton.fr>
@@ -122,9 +122,9 @@ HOSTS can be a string or a list of strings."
 
 (defun auth-source-pass--build-result-many (hosts ports users require max)
   "Return multiple `auth-source-pass--build-result' values."
-  (unless (listp hosts) (setq hosts (list hosts)))
-  (unless (listp users) (setq users (list users)))
-  (unless (listp ports) (setq ports (list ports)))
+  (setq hosts (ensure-list hosts))
+  (setq users (ensure-list users))
+  (setq ports (ensure-list ports))
   (let* ((auth-source-pass--match-regexp (auth-source-pass--match-regexp
                                           auth-source-pass-port-separator))
          (rv (auth-source-pass--find-match-many hosts users ports
diff --git a/lisp/auth-source.el b/lisp/auth-source.el
index 66de763f671..365f6697ec8 100644
--- a/lisp/auth-source.el
+++ b/lisp/auth-source.el
@@ -899,8 +899,7 @@ Remove trailing \": \"."
 (defun auth-source-ensure-strings (values)
   (if (eq values t)
       values
-    (unless (listp values)
-      (setq values (list values)))
+    (setq values (ensure-list values))
     (mapcar (lambda (value)
              (if (numberp value)
                  (format "%s" value)
diff --git a/lisp/calendar/appt.el b/lisp/calendar/appt.el
index 11beee94e64..469b3f4023c 100644
--- a/lisp/calendar/appt.el
+++ b/lisp/calendar/appt.el
@@ -453,8 +453,7 @@ separate appointment."
     ;; It repeatedly reminds you of the date?
     ;; It would make more sense if it was eg the time of the appointment.
     ;; Let's allow it to be a list or not independent of the other elements.
-    (or (listp new-time)
-        (setq new-time (list new-time)))
+    (setq new-time (ensure-list new-time))
     ;; FIXME Link to diary entry?
     (calendar-set-mode-line
      (format " %s. %s" (appt-mode-line min-to-app)
diff --git a/lisp/cedet/mode-local.el b/lisp/cedet/mode-local.el
index e1746e1a541..c1a48bc50c8 100644
--- a/lisp/cedet/mode-local.el
+++ b/lisp/cedet/mode-local.el
@@ -89,7 +89,7 @@ Return nil if MODE has no parent."
   "Run FUNCTION on every file buffer with major mode in MODES.
 MODES can be a symbol or a list of symbols.
 FUNCTION does not have arguments."
-  (or (listp modes) (setq modes (list modes)))
+  (setq modes (ensure-list modes))
   (mode-local-map-file-buffers
    function (lambda ()
               (let ((mm (mode-local-equivalent-mode-p major-mode))
diff --git a/lisp/cedet/semantic/fw.el b/lisp/cedet/semantic/fw.el
index 30704760c1d..184a74c8c2e 100644
--- a/lisp/cedet/semantic/fw.el
+++ b/lisp/cedet/semantic/fw.el
@@ -434,9 +434,8 @@ FILE, NOWARN, RAWFILE, and WILDCARDS are passed into 
`find-file-noselect'."
 ;;       ))
 ;;   "Highlighted Semantic keywords.")
 
-;; (when (fboundp 'font-lock-add-keywords)
-;;   (font-lock-add-keywords 'emacs-lisp-mode
-;;                           semantic-fw-font-lock-keywords))
+;; (font-lock-add-keywords 'emacs-lisp-mode
+;;                         semantic-fw-font-lock-keywords)
 
 
 (provide 'semantic/fw)
diff --git a/lisp/cedet/semantic/grammar.el b/lisp/cedet/semantic/grammar.el
index 2dccd87a710..60c57210b8f 100644
--- a/lisp/cedet/semantic/grammar.el
+++ b/lisp/cedet/semantic/grammar.el
@@ -1156,18 +1156,13 @@ END is the limit of the search."
     ("^\\(\\(\\sw\\|\\s_\\)+\\)[ \n\r\t]*:"
      1 font-lock-function-name-face)
     (semantic--grammar-macros-matcher
-     1 ,(if (boundp 'font-lock-builtin-face)
-            'font-lock-builtin-face
-          'font-lock-preprocessor-face))
+     1 font-lock-builtin-face)
     ("\\$\\(\\sw\\|\\s_\\)*"
      0 font-lock-variable-name-face)
     ("<\\(\\(\\sw\\|\\s_\\)+\\)>"
      1 font-lock-type-face)
     (,semantic-grammar-lex-c-char-re
-     0 ,(if (boundp 'font-lock-constant-face)
-            'font-lock-constant-face
-          'font-lock-string-face)
-     t)
+     0 font-lock-constant-face t)
     ;; Must highlight :keyword here, because ':' is a punctuation in
     ;; grammar mode!
     ("[\r\n\t ]+:\\sw+\\>"
diff --git a/lisp/cus-edit.el b/lisp/cus-edit.el
index 9b73a72b238..1021707907d 100644
--- a/lisp/cus-edit.el
+++ b/lisp/cus-edit.el
@@ -973,8 +973,7 @@ it as the third element in the list."
          (let ((prop (get var 'variable-interactive))
                (type (get var 'custom-type))
                (prompt (format prompt-val var)))
-           (unless (listp type)
-             (setq type (list type)))
+            (setq type (ensure-list type))
            (cond (prop
                   ;; Use VAR's `variable-interactive' property
                   ;; as an interactive spec for prompting.
@@ -5145,8 +5144,7 @@ This function does not save the buffer."
 (defun custom-variable-menu-create (_widget symbol)
   "Ignoring WIDGET, create a menu entry for customization variable SYMBOL."
   (let ((type (get symbol 'custom-type)))
-    (unless (listp type)
-      (setq type (list type)))
+    (setq type (ensure-list type))
     (if (and type (widget-get type :custom-menu))
        (widget-apply type :custom-menu symbol)
       (vector (custom-unlispify-menu-entry symbol)
diff --git a/lisp/cus-theme.el b/lisp/cus-theme.el
index 5d3f2585976..ccd8ba51c9d 100644
--- a/lisp/cus-theme.el
+++ b/lisp/cus-theme.el
@@ -490,6 +490,29 @@ It includes all faces in list FACES."
     (with-current-buffer standard-output
       (describe-theme-1 theme))))
 
+(defun describe-theme-from-file (theme &optional file short)
+  "Describe THEME from its FILE without loading it.
+
+If FILE is nil try to look in `custom-theme-load-path' for the
+theme's file using the theme's name.
+If SHORT is non-nil, show only the first line of thene's documentation."
+    (let ((file (or file
+                  (locate-file (concat (symbol-name theme) "-theme.el")
+                              (custom-theme--load-path)
+                              '("" "c")))))
+      (with-temp-buffer
+        (insert-file-contents file)
+        (catch 'found
+          (let (sexp)
+            (while (setq sexp (let ((read-circle nil))
+                               (condition-case nil
+                                   (read (current-buffer))
+                                 (end-of-file nil))))
+              (when (eq (car-safe sexp) 'deftheme)
+               (throw 'found (if short
+                                  (car (split-string (nth 2 sexp) "\n"))
+                                (nth 2 sexp))))))))))
+
 (defun describe-theme-1 (theme)
   (prin1 theme)
   (princ " is a custom theme")
@@ -510,16 +533,9 @@ It includes all faces in list FACES."
            (princ "It is loaded but disabled."))
          (setq doc (get theme 'theme-documentation)))
       (princ "It is not loaded.")
-      ;; Attempt to grab the theme documentation
+      ;; Attempt to grab the theme documentation from file.
       (when fn
-       (with-temp-buffer
-         (insert-file-contents fn)
-         (let ((sexp (let ((read-circle nil))
-                       (condition-case nil
-                           (read (current-buffer))
-                         (end-of-file nil)))))
-            (and (eq (car-safe sexp) 'deftheme)
-                (setq doc (nth 2 sexp)))))))
+       (setq doc (describe-theme-from-file theme fn))))
     (princ "\n\nDocumentation:\n")
     (princ (if (stringp doc)
               (substitute-command-keys doc)
diff --git a/lisp/custom.el b/lisp/custom.el
index 083349e3591..5c134ff7f13 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -1208,7 +1208,7 @@ The command `customize-create-theme' writes theme files 
into this
 directory.  By default, Emacs searches for custom themes in this
 directory first---see `custom-theme-load-path'."
   :initialize #'custom-initialize-delay
-  :type 'string
+  :type 'directory
   :group 'customize
   :version "22.1")
 
diff --git a/lisp/dired-x.el b/lisp/dired-x.el
index 5780f1353ad..398f55f2a24 100644
--- a/lisp/dired-x.el
+++ b/lisp/dired-x.el
@@ -300,8 +300,7 @@ Interactively, ask for EXTENSION.
 Prefixed with one \\[universal-argument], unmark files instead.
 Prefixed with two \\[universal-argument]'s, prompt for MARKER-CHAR and mark 
files with it."
   (interactive (dired--mark-suffix-interactive-spec))
-  (unless (listp extension)
-    (setq extension (list extension)))
+  (setq extension (ensure-list extension))
   (dired-mark-files-regexp
    (concat ".";; don't match names with nothing but an extension
            "\\("
@@ -325,8 +324,7 @@ Interactively, ask for SUFFIX.
 Prefixed with one \\[universal-argument], unmark files instead.
 Prefixed with two \\[universal-argument]'s, prompt for MARKER-CHAR and mark 
files with it."
   (interactive (dired--mark-suffix-interactive-spec))
-  (unless (listp suffix)
-    (setq suffix (list suffix)))
+  (setq suffix (ensure-list suffix))
   (dired-mark-files-regexp
    (concat ".";; don't match names with nothing but an extension
            "\\("
diff --git a/lisp/dired.el b/lisp/dired.el
index 27172c50a9f..e96b85a173a 100644
--- a/lisp/dired.el
+++ b/lisp/dired.el
@@ -294,7 +294,7 @@ then this will always be equivalent to `move'."
                (revert-buffer nil t)))))
   :type '(choice (const :tag "Don't allow dragging" nil)
                  (const :tag "Copy file to new location" t)
-                 (const :tag "Move file to new location" t)
+                 (const :tag "Move file to new location" move)
                  (const :tag "Create symbolic link to file" link))
   :group 'dired
   :version "29.1")
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index 85dd6bedc41..6a6eab6a98c 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -1879,8 +1879,6 @@ It is too wide if it has any lines longer than the 
largest of
          (byte-compile-dynamic byte-compile-dynamic)
          (byte-compile-dynamic-docstrings
           byte-compile-dynamic-docstrings)
-         ;;            (byte-compile-generate-emacs19-bytecodes
-         ;;             byte-compile-generate-emacs19-bytecodes)
          (byte-compile-warnings byte-compile-warnings)
          ;; Indicate that we're not currently loading some file.
          ;; This is used in `macroexp-file-name' to make sure that
diff --git a/lisp/emacs-lisp/checkdoc.el b/lisp/emacs-lisp/checkdoc.el
index aadd6480086..3c4b6baca53 100644
--- a/lisp/emacs-lisp/checkdoc.el
+++ b/lisp/emacs-lisp/checkdoc.el
@@ -2042,8 +2042,7 @@ from the comment."
                           (condition-case nil
                               (setq lst (read (current-buffer)))
                             (error (setq lst nil))) ; error in text
-                           (if (not (listp lst)) ; not a list of args
-                               (setq lst (list lst)))
+                           (setq lst (ensure-list lst))
                           (if (and lst (not (symbolp (car lst)))) ;weird arg
                               (setq lst nil))
                           (while lst
diff --git a/lisp/emacs-lisp/eieio.el b/lisp/emacs-lisp/eieio.el
index 9a1f5b9db0f..ccdb52d6a1f 100644
--- a/lisp/emacs-lisp/eieio.el
+++ b/lisp/emacs-lisp/eieio.el
@@ -652,8 +652,7 @@ If SLOT is unbound, bind it to the list containing ITEM."
        (setq ov (list item))
       (setq ov (eieio-oref object slot))
       ;; turn it into a list.
-      (unless (listp ov)
-       (setq ov (list ov)))
+      (setq ov (ensure-list ov))
       ;; Do the combination
       (if (not (member item ov))
          (setq ov
diff --git a/lisp/emacs-lisp/lisp-mode.el b/lisp/emacs-lisp/lisp-mode.el
index 3bf9a2f10db..b1fc65b09ac 100644
--- a/lisp/emacs-lisp/lisp-mode.el
+++ b/lisp/emacs-lisp/lisp-mode.el
@@ -31,11 +31,6 @@
 (eval-when-compile (require 'cl-lib))
 (eval-when-compile (require 'subr-x))
 
-(defvar font-lock-comment-face)
-(defvar font-lock-doc-face)
-(defvar font-lock-keywords-case-fold-search)
-(defvar font-lock-string-face)
-
 (define-abbrev-table 'lisp-mode-abbrev-table ()
   "Abbrev table for Lisp mode.")
 
diff --git a/lisp/emacs-lisp/pp.el b/lisp/emacs-lisp/pp.el
index 95ad222cc4d..50e0e7d1da4 100644
--- a/lisp/emacs-lisp/pp.el
+++ b/lisp/emacs-lisp/pp.el
@@ -25,7 +25,6 @@
 ;;; Code:
 
 (require 'cl-lib)
-(defvar font-lock-verbose)
 
 (defgroup pp nil
   "Pretty printer for Emacs Lisp."
diff --git a/lisp/emulation/cua-base.el b/lisp/emulation/cua-base.el
index a6d6f47ead5..6d21088cb29 100644
--- a/lisp/emulation/cua-base.el
+++ b/lisp/emulation/cua-base.el
@@ -1134,7 +1134,7 @@ If ARG is the atom `-', scroll upward by nearly full 
screen."
 
 (defun cua--M/H-key (map key fct)
   ;; bind H-KEY or M-KEY to FCT in MAP
-  (unless (listp key) (setq key (list key)))
+  (setq key (ensure-list key))
   (define-key map (vector (cons cua--rectangle-modifier-key key)) fct))
 
 (defun cua--self-insert-char-p (def)
diff --git a/lisp/epg.el b/lisp/epg.el
index 9da5a36ba3d..b8423d82a26 100644
--- a/lisp/epg.el
+++ b/lisp/epg.el
@@ -1264,8 +1264,7 @@ callback data (if any)."
        keys string field index)
     (if name
        (progn
-         (unless (listp name)
-           (setq name (list name)))
+          (setq name (ensure-list name))
          (while name
            (setq args (append args (list list-keys-option (car name)))
                  name (cdr name))))
diff --git a/lisp/erc/erc-button.el b/lisp/erc/erc-button.el
index bfaf4fa821a..8c1188e64a2 100644
--- a/lisp/erc/erc-button.el
+++ b/lisp/erc/erc-button.el
@@ -787,33 +787,31 @@ and `apropos' for other symbols."
     (erc-button-add-button from (point) fun nick-p data regexp)))
 
 ;;;###autoload
-(defun erc-button--display-error-notice-with-keys (&optional parsed buffer
-                                                             &rest strings)
+(defun erc-button--display-error-notice-with-keys (maybe-buffer &rest strings)
   "Add help keys to STRINGS for configuration-related admonishments.
-Return inserted result.  Expect PARSED to be an `erc-response'
-object, a string, or nil.  Expect BUFFER to be a buffer, a string,
-or nil.  As a special case, allow PARSED to be a buffer as long
-as BUFFER is a string or nil.  If STRINGS contains any trailing
+Return inserted result.  Expect MAYBE-BUFFER to be an ERC buffer,
+a string, or nil.  When it's a buffer, specify the `buffer'
+argument when calling `erc-display-message'.  Otherwise, add it
+to STRINGS.  If STRINGS contains any trailing non-nil
 non-strings, concatenate leading string members before applying
 `format'.  Otherwise, just concatenate everything."
-  (when (stringp buffer)
-    (push buffer strings)
-    (setq buffer nil))
-  (when (stringp parsed)
-    (push parsed strings)
-    (setq parsed nil))
-  (when (bufferp parsed)
-    (cl-assert (null buffer))
-    (setq buffer parsed
-          parsed nil))
-  (let* ((op (if (seq-every-p #'stringp (cdr strings))
+  (let* ((buffer (if (bufferp maybe-buffer)
+                     maybe-buffer
+                   (when (stringp maybe-buffer)
+                     (push maybe-buffer strings))
+                   'active))
+         (op (if (seq-every-p (lambda (o) (or (not o) (stringp o)))
+                              (cdr strings))
                  #'concat
                (let ((head (pop strings)))
-                 (while (stringp (car strings))
+                 (while (or (stringp (car strings))
+                            (and strings (not (car strings))))
                    (setq head (concat head (pop strings))))
                  (push head strings))
                #'format))
          (string (apply op strings))
+         (erc-insert-modify-hook (remove 'erc-add-timestamp
+                                         erc-insert-modify-hook))
          (erc-insert-post-hook
           (cons (lambda ()
                   (setq string (buffer-substring (point-min)
@@ -824,7 +822,7 @@ non-strings, concatenate leading string members before 
applying
              erc-button--display-error-with-buttons
              erc-button-describe-symbol 1)
             ,@erc-button-alist)))
-    (erc-display-message parsed '(t notice error) (or buffer 'active) string)
+    (erc-display-message nil '(t notice error) buffer string)
     string))
 
 ;;;###autoload
diff --git a/lisp/erc/erc-common.el b/lisp/erc/erc-common.el
index 08c11d518a8..85971797c2f 100644
--- a/lisp/erc/erc-common.el
+++ b/lisp/erc/erc-common.el
@@ -475,12 +475,11 @@ Use the CASEMAPPING ISUPPORT parameter to determine the 
style."
 
 (defmacro erc--with-dependent-type-match (type &rest features)
   "Massage Custom :type TYPE with :match function that pre-loads FEATURES."
-  `(backquote (,(car type)
-               :match
-               ,(list '\, `(lambda (w v)
+  `(backquote-list* ',(car type)
+                    :match (lambda (w v)
                              ,@(mapcar (lambda (ft) `(require ',ft)) features)
-                             (,(widget-get (widget-convert type) :match) w v)))
-               ,@(cdr type))))
+                             (,(widget-get (widget-convert type) :match) w v))
+                    ',(cdr type)))
 
 (provide 'erc-common)
 
diff --git a/lisp/erc/erc-log.el b/lisp/erc/erc-log.el
index d3106da4017..472cc1388a4 100644
--- a/lisp/erc/erc-log.el
+++ b/lisp/erc/erc-log.el
@@ -445,6 +445,15 @@ You can save every individual message by putting this 
function on
            (set-buffer-modified-p nil))))))
   t)
 
+;; This is a kludge to avoid littering erc-truncate.el with forward
+;; declarations needed only for a corner-case compatibility check.
+(defun erc-log--call-when-logging-enabled-sans-module (fn)
+  (when (and (erc-logging-enabled)
+             (not (or erc-log-mode (memq 'log erc-modules))))
+    (let ((dirfile (and (stringp erc-log-channels-directory)
+                        erc-log-channels-directory)))
+      (funcall fn dirfile))))
+
 (provide 'erc-log)
 
 ;;; erc-log.el ends here
diff --git a/lisp/erc/erc-networks.el b/lisp/erc/erc-networks.el
index bf4ef1d35a9..ba7990e87d6 100644
--- a/lisp/erc/erc-networks.el
+++ b/lisp/erc/erc-networks.el
@@ -66,7 +66,7 @@
 (declare-function erc-set-active-buffer "erc" (buffer))
 
 (declare-function erc-button--display-error-notice-with-keys
-                  (parsed &rest strings))
+                  (maybe-buffer &rest strings))
 
 ;; Variables
 
@@ -1295,17 +1295,16 @@ shutting down the connection."
                          erc-network)))
      (erc-display-message parsed 'notice nil m)
      nil)
-    ((and
-      (guard (eq erc-network erc-networks--name-missing-sentinel))
-      ;; This can happen theoretically, e.g., when adjusting settings
-      ;; on a proxy service that partially impersonates IRC but isn't
-      ;; currently conveying anything through to a real network.  The
-      ;; service may send a 422 but no NETWORK param (or *any* 005s).
-      (let m (concat "Failed to determine network.  Please set entry for \""
-                     erc-server-announced-name "\" in `erc-networks-alist'"
-                     " or consider calling `erc-tls' with the keyword `:id'."
-                     "  See Info:\"(erc) Network Identifier\" for more.")))
-     (erc-display-error-notice parsed m)
+    ((guard (eq erc-network erc-networks--name-missing-sentinel))
+     ;; This can happen theoretically, e.g., when adjusting settings
+     ;; on a proxy service that partially impersonates IRC but isn't
+     ;; currently conveying anything through to a real network.  The
+     ;; service may send a 422 but no NETWORK param (or *any* 005s).
+     (erc-button--display-error-notice-with-keys
+      "Failed to determine network. Please set entry for \""
+      erc-server-announced-name "\" in `erc-networks-alist' or consider"
+      " calling `erc-tls' with the keyword `:id'."
+      " See Info:\"(erc) Network Identifier\" for more.")
      (if erc-networks--allow-unknown-network
          (progn
            (erc-display-error-notice
@@ -1325,9 +1324,9 @@ Copy source (prefix) from MOTD-ish message as a last 
resort."
   (unless erc-server-announced-name
     (require 'erc-button)
     (erc-button--display-error-notice-with-keys
-     parsed "Failed to determine server name.  Using \""
+     "Failed to determine server name. Using \""
      (setq erc-server-announced-name (erc-response.sender parsed)) "\" instead"
-     ".  If this was unexpected, consider reporting it via \\[erc-bug]" "."))
+     ". If this was unexpected, consider reporting it via \\[erc-bug]."))
   nil)
 
 (defun erc-unset-network-name (_nick _ip _reason)
@@ -1508,7 +1507,7 @@ to be a false alarm.  If `erc-reuse-buffers' is nil, let
                                proc)
       (require 'erc-button)
       (erc-button--display-error-notice-with-keys
-       parsed "Unexpected state detected.  Please report via \\[erc-bug].")))
+       "Unexpected state detected. Please report via \\[erc-bug].")))
 
   ;; For now, retain compatibility with erc-server-NNN-functions.
   (or (erc-networks--ensure-announced proc parsed)
diff --git a/lisp/erc/erc-speedbar.el b/lisp/erc/erc-speedbar.el
index f5fbaac767d..625d59530b0 100644
--- a/lisp/erc/erc-speedbar.el
+++ b/lisp/erc/erc-speedbar.el
@@ -439,7 +439,6 @@ The INDENT level is ignored."
 (defvar erc-status-sidebar-buffer-name)
 (declare-function erc-status-sidebar-set-window-preserve-size
                   "erc-status-sidebar" nil)
-(declare-function erc-status-sidebar-mode--unhook "erc-status-sidebar" nil)
 
 (defvar erc-speedbar--buffer-options
   '((speedbar-update-flag . t)
@@ -490,36 +489,64 @@ The INDENT level is ignored."
           (cl-assert (buffer-live-p speedbar-buffer))
           (if (or (and force (< arg 0))
                   (and (not force) (get-buffer-window speedbar-buffer nil)))
-              (erc-speedbar-close-nicknames-window nil)
+              ;; Close associated windows and stop updating but leave timer.
+              (progn
+                (dolist (window (get-buffer-window-list speedbar-buffer nil t))
+                  (unless (frame-root-window-p window)
+                    (when erc-speedbar--hidden-speedbar-frame
+                      (cl-assert
+                       (not (eq (window-frame window)
+                                erc-speedbar--hidden-speedbar-frame))))
+                    (delete-window window)))
+                (with-current-buffer speedbar-buffer
+                  (setq speedbar-update-flag nil)
+                  (speedbar-set-mode-line-format)))
             (when (or (not force) (>= arg 0))
               (with-selected-frame speedbar-frame
                 (erc-speedbar--emulate-sidebar-set-window-preserve-size)))))
-      (when (or (not force) (>= arg 0))
-        (let ((speedbar-frame-parameters (backquote-list*
-                                          '(visibility . nil)
-                                          '(no-other-frame . t)
-                                          speedbar-frame-parameters))
-              (speedbar-after-create-hook #'erc-speedbar--emulate-sidebar))
-          (erc-speedbar-browser)
-          ;; If we put the remaining parts in the "create hook" along
-          ;; with everything else, the frame with `window-main-window'
-          ;; gets raised and steals focus if you've switched away from
-          ;; Emacs in the meantime.
-          (make-frame-invisible speedbar-frame)
-          (select-frame (setq speedbar-frame (previous-frame)))
-          (erc-speedbar--emulate-sidebar-set-window-preserve-size))))))
+      (when-let (((or (not force) (>= arg 0)))
+                 (speedbar-frame-parameters (backquote-list*
+                                             '(visibility . nil)
+                                             '(no-other-frame . t)
+                                             speedbar-frame-parameters))
+                 (speedbar-after-create-hook #'erc-speedbar--emulate-sidebar))
+        (erc-install-speedbar-variables)
+        ;; Run before toggling mode to prevent timer from being
+        ;; created twice.
+        (speedbar-change-initial-expansion-list "ERC")
+        (speedbar-frame-mode 1)
+        ;; If we put the remaining parts in the "create hook" along
+        ;; with everything else, the frame with `window-main-window'
+        ;; gets raised and steals focus if you've switched away from
+        ;; Emacs in the meantime.
+        (make-frame-invisible speedbar-frame)
+        (select-frame (setq speedbar-frame (previous-frame)))
+        (erc-speedbar--emulate-sidebar-set-window-preserve-size))))
+  (cl-assert (not (cdr (erc-speedbar--get-timers))) t))
 
 (defun erc-speedbar--ensure (&optional force)
   (when (or (erc-server-buffer) force)
     (when erc-track-mode
       (cl-pushnew '(derived-mode . speedbar-mode)
                   erc-track--switch-fallback-blockers :test #'equal))
+    (unless speedbar-update-flag
+      (erc-button--display-error-notice-with-keys
+       (erc-server-buffer)
+       "Module `nickbar' needs `speedbar-update-flag' to be non-nil"
+       (and (not (display-graphic-p)) " in text terminals")
+       ". Setting to t for the current Emacs session."
+       " Customize it permanently to avoid this message.")
+      (setq speedbar-update-flag t))
     (erc-speedbar--toggle-nicknames-sidebar +1)
-    (speedbar-enable-update)))
+    (with-current-buffer speedbar-buffer
+      (setq speedbar-update-flag t)
+      (speedbar-set-mode-line-format))))
+
+(defvar erc-speedbar--shutting-down-p nil)
 
 ;;;###autoload(autoload 'erc-nickbar-mode "erc-speedbar" nil t)
 (define-erc-module nickbar nil
-  "Show nicknames in a side window.
+  "Show nicknames for current target buffer in a side window.
 When enabling, create a speedbar session if one doesn't exist and
 show its buffer in an `erc-status-sidebar' window instead of a
 separate frame.  When disabling, close the window or, with a
@@ -527,8 +554,8 @@ negative prefix arg, destroy the session.
 
 WARNING: this module may produce unwanted side effects, like the
 raising of frames or the stealing of input focus.  If you witness
-such an occurrence, and can reproduce it, please file a bug
-report with \\[erc-bug]."
+such a thing and can reproduce it, please file a bug report with
+\\[erc-bug]."
   ((add-hook 'erc--setup-buffer-hook #'erc-speedbar--ensure)
    (erc-speedbar--ensure)
    (unless (or erc--updating-modules-p
@@ -542,31 +569,44 @@ report with \\[erc-bug]."
          (erc-error "Not initializing `erc-nickbar-mode' in %s"
                     (current-buffer))))))
   ((remove-hook 'erc--setup-buffer-hook #'erc-speedbar--ensure)
-   (speedbar-disable-update)
    (when erc-track-mode
      (setq erc-track--switch-fallback-blockers
            (remove '(derived-mode . speedbar-mode)
                    erc-track--switch-fallback-blockers)))
    (erc-speedbar--toggle-nicknames-sidebar -1)
-   (when-let ((arg erc--module-toggle-prefix-arg)
+   (when-let (((not erc-speedbar--shutting-down-p))
+              (arg erc--module-toggle-prefix-arg)
               ((numberp arg))
               ((< arg 0)))
-     (erc-speedbar-close-nicknames-window 'kill))))
+     (with-current-buffer speedbar-buffer
+       (dframe-close-frame)
+       (setq erc-speedbar--hidden-speedbar-frame nil)))))
+
+(defun erc-speedbar--get-timers ()
+  (cl-remove #'dframe-timer-fn timer-idle-list
+             :key #'timer--function
+             :test-not #'eq))
 
 (defun erc-speedbar--dframe-controlled (arg)
+  (when speedbar-buffer
+    (cl-assert (eq speedbar-buffer (current-buffer))))
   (when (and erc-speedbar--hidden-speedbar-frame (numberp arg) (< arg 0))
     (when erc-nickbar-mode
-      (erc-nickbar-mode -1))
+      (let ((erc-speedbar--shutting-down-p t))
+        (erc-nickbar-mode -1)))
     (setq speedbar-frame erc-speedbar--hidden-speedbar-frame
           erc-speedbar--hidden-speedbar-frame nil)
     ;; It's unknown whether leaving the frame invisible interferes
-    ;; with the upstream teardown procedure.
+    ;; with the upstream teardown sequence.
     (when (display-graphic-p)
       (make-frame-visible speedbar-frame))
-    (speedbar-frame-mode arg)
-    (when speedbar-buffer
-      (kill-buffer speedbar-buffer)
-      (setq speedbar-buffer nil))))
+    (speedbar-frame-mode arg) ; -1
+    ;; As of Emacs 29, `dframe-set-timer' can't remove `dframe-timer'.
+    (cl-assert (= 1 (length (erc-speedbar--get-timers))) t)
+    (cancel-function-timers #'dframe-timer-fn)
+    ;; `dframe-close-frame' kills the buffer but no function in
+    ;; erc-speedbar.el resets this to nil.
+    (setq speedbar-buffer nil)))
 
 (defun erc-speedbar-toggle-nicknames-window-lock ()
   "Toggle whether nicknames window is selectable with \\[other-window]."
@@ -578,20 +618,6 @@ report with \\[erc-bug]."
       (set-window-parameter window 'no-other-window (not val))
       (message "nick-window: %s" (if val "selectable" "protected")))))
 
-(defun erc-speedbar-close-nicknames-window (kill)
-  (interactive "P")
-  (if kill
-      (with-current-buffer speedbar-buffer
-        (dframe-close-frame)
-        (cl-assert (not erc-nickbar-mode))
-        (setq erc-speedbar--hidden-speedbar-frame nil))
-    (dolist (window (get-buffer-window-list speedbar-buffer nil t))
-      (unless (frame-root-window-p window)
-        (when erc-speedbar--hidden-speedbar-frame
-          (cl-assert (not (eq (window-frame window)
-                              erc-speedbar--hidden-speedbar-frame))))
-        (delete-window window)))))
-
 
 ;;;; Nicks integration
 
diff --git a/lisp/erc/erc-truncate.el b/lisp/erc/erc-truncate.el
index 8430a68d92b..48d8408a85a 100644
--- a/lisp/erc/erc-truncate.el
+++ b/lisp/erc/erc-truncate.el
@@ -24,10 +24,8 @@
 
 ;;; Commentary:
 
-;; This implements buffer truncation (and optional log file writing
-;; support for the Emacs IRC client.  Use `erc-truncate-mode' to switch
-;; on.  Use `erc-enable-logging' to enable logging of the stuff which
-;; is getting truncated.
+;; This file implements buffer truncation through the `truncate'
+;; module, with optional `log' module integration.
 
 ;;; Code:
 
@@ -50,15 +48,41 @@ This prevents the query buffer from getting too large, 
which can
 bring any grown Emacs to its knees after a few days worth of
 tracking heavy-traffic channels."
   ;;enable
-  ((add-hook 'erc-insert-done-hook #'erc-truncate-buffer))
+  ((add-hook 'erc-insert-done-hook #'erc-truncate-buffer)
+   (add-hook 'erc-connect-pre-hook #'erc-truncate--warn-about-logging))
   ;; disable
-  ((remove-hook 'erc-insert-done-hook #'erc-truncate-buffer)))
+  ((remove-hook 'erc-insert-done-hook #'erc-truncate-buffer)
+   (remove-hook 'erc-connect-pre-hook #'erc-truncate--warn-about-logging)))
+
+(defun erc-truncate--warn-about-logging (&rest _)
+  (when (and (not erc--target)
+             (fboundp 'erc-log--call-when-logging-enabled-sans-module))
+    ;; We could also enable `erc-log-mode' here, but the risk of
+    ;; lasting damage is nonzero.
+    (erc-log--call-when-logging-enabled-sans-module
+     (lambda (dirfile)
+       ;; Emit a real Emacs warning because the message may be
+       ;; truncated away before it can be read if merely inserted.
+       (erc-button--display-error-notice-with-keys-and-warn
+        "The `truncate' module no longer enables logging implicitly."
+        " If you want ERC to write logs before truncating, add `log' to"
+        " `erc-modules' using something like \\[customize-option]."
+        " To silence this message, don't `require' `erc-log'."
+        (and dirfile " Alternatively, change the value of")
+        (and dirfile " `erc-log-channels-directory', or move ")
+        dirfile (and dirfile " elsewhere."))))))
 
 ;;;###autoload
 (defun erc-truncate-buffer-to-size (size &optional buffer)
-  "Truncates the buffer to the size SIZE.
-If BUFFER is not provided, the current buffer is assumed.  The deleted
-region is logged if `erc-logging-enabled' returns non-nil."
+  "Truncate BUFFER or the current buffer to SIZE.
+Log the deleted region when the `log' module is active and
+`erc-logging-enabled' returns non-nil.
+
+Note that prior to ERC 5.6, whenever erc-log.el happened to be
+loaded and the option `erc-enable-logging' was left at its
+default value, this function would cause logging to commence
+regardless of whether `erc-log-mode' was enabled or `log' was
+present in `erc-modules'."
   ;; If buffer is non-nil, but get-buffer does not return anything,
   ;; then this is a bug.  If buffer is a buffer name, get the buffer
   ;; object.  If buffer is nil, use the current buffer.
@@ -93,6 +117,9 @@ region is logged if `erc-logging-enabled' returns non-nil."
          ;; (not (memq 'erc-save-buffer-in-logs
          ;;             erc-insert-post-hook))
          ;; Comments?
+          ;; The comments above concern pre-5.6 behavior and reflect
+          ;; an obsolete understanding of how `erc-logging-enabled'
+          ;; behaves in practice.
           (run-hook-with-args 'erc--pre-clear-functions end)
          ;; disable undoing for the truncating
          (buffer-disable-undo)
diff --git a/lisp/eshell/em-ls.el b/lisp/eshell/em-ls.el
index 9b53bf29559..30f39d14b40 100644
--- a/lisp/eshell/em-ls.el
+++ b/lisp/eshell/em-ls.el
@@ -274,11 +274,7 @@ instead."
           ;; use the fancy highlighting in `eshell-ls' rather than font-lock
           (when eshell-ls-use-colors
             (font-lock-mode -1)
-            (setq font-lock-defaults nil)
-            (if (boundp 'font-lock-buffers)
-                (setq font-lock-buffers
-                      (delq (current-buffer)
-                            (symbol-value 'font-lock-buffers)))))
+            (setq font-lock-defaults nil))
           (require 'em-glob)
           (let* ((insert-func 'insert)
                  (error-func 'insert)
diff --git a/lisp/eshell/esh-proc.el b/lisp/eshell/esh-proc.el
index f2d20b4cded..9c4036004ff 100644
--- a/lisp/eshell/esh-proc.el
+++ b/lisp/eshell/esh-proc.el
@@ -491,11 +491,11 @@ PROC is the process that's exiting.  STRING is the exit 
message."
                             (eshell-close-handles
                              status
                              (when status (list 'quote (= status 0)))
-                             handles)))))
+                             handles)
+                            (eshell-kill-process-function proc string)))))
                 (funcall finish-io))))
         (when-let ((entry (assq proc eshell-process-list)))
-          (eshell-remove-process-entry entry))
-        (eshell-kill-process-function proc string)))))
+          (eshell-remove-process-entry entry))))))
 
 (defun eshell-process-interact (func &optional all query)
   "Interact with a process, using PROMPT if more than one, via FUNC.
diff --git a/lisp/faces.el b/lisp/faces.el
index 1a446aacacd..8f93f9b2c0c 100644
--- a/lisp/faces.el
+++ b/lisp/faces.el
@@ -1118,8 +1118,7 @@ element of DEFAULT is returned.  If DEFAULT isn't a list, 
but
 MULTIPLE is non-nil, a one-element list containing DEFAULT is
 returned.  Otherwise, DEFAULT is returned verbatim."
   (let (defaults)
-    (unless (listp default)
-      (setq default (list default)))
+    (setq default (ensure-list default))
     (when default
       (setq default
             (if multiple
diff --git a/lisp/files.el b/lisp/files.el
index 8f25e8562e0..ad1ce57bb7b 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -6624,7 +6624,15 @@ into NEWNAME instead."
                                     (file-attributes directory))))
              (follow-flag (unless follow 'nofollow)))
          (if modes (set-file-modes newname modes follow-flag))
-         (if times (set-file-times newname times follow-flag)))))))
+         (when times
+            ;; When built for an Android GUI build, don't attempt to
+            ;; set file times for a file within /content, as the
+            ;; Android VFS layer does not provide means to change file
+            ;; timestamps.
+            (when (or (not (and (eq system-type 'android)
+                                (featurep 'android)))
+                      (not (string-prefix-p "/content/" newname)))
+                (set-file-times newname times follow-flag))))))))
 
 
 ;; At time of writing, only info uses this.
diff --git a/lisp/format.el b/lisp/format.el
index 5c72a78f325..89a83c3cee2 100644
--- a/lisp/format.el
+++ b/lisp/format.el
@@ -295,7 +295,7 @@ For most purposes, consider using `format-decode-region' 
instead."
                          (setq try format-alist))
                      (setq try (cdr try))))))
            ;; Deal with given format(s)
-           (or (listp format) (setq format (list format)))
+            (setq format (ensure-list format))
            (let ((do format) f)
              (while do
                (or (setq f (assq (car do) format-alist))
diff --git a/lisp/gnus/gnus-cite.el b/lisp/gnus/gnus-cite.el
index d9071491ed4..a3c24ea05d9 100644
--- a/lisp/gnus/gnus-cite.el
+++ b/lisp/gnus/gnus-cite.el
@@ -1117,12 +1117,6 @@ Returns nil if there is no such line before LIMIT, t 
otherwise."
           (setq count (1+ count)))))) ;;
   "Keywords for highlighting different levels of message citations.")
 
-(defvar font-lock-defaults-computed)
-(defvar font-lock-keywords)
-(defvar font-lock-set-defaults)
-
-(autoload 'font-lock-set-defaults "font-lock")
-
 (define-minor-mode gnus-message-citation-mode
   "Minor mode providing more font-lock support for nested citations.
 When enabled, it automatically turns on `font-lock-mode'."
diff --git a/lisp/gnus/gnus-score.el b/lisp/gnus/gnus-score.el
index 8bdfccf7eb8..62167ea9e6a 100644
--- a/lisp/gnus/gnus-score.el
+++ b/lisp/gnus/gnus-score.el
@@ -2994,10 +2994,7 @@ The list is determined from the variable 
`gnus-score-file-alist'."
        (group (or group gnus-newsgroup-name))
        score-files)
     (when group
-      ;; Make sure funcs is a list.
-      (and funcs
-          (not (listp funcs))
-          (setq funcs (list funcs)))
+      (setq funcs (ensure-list funcs))
       (when gnus-score-use-all-scores
        ;; Get the initial score files for this group.
        (when funcs
@@ -3104,12 +3101,8 @@ The list is determined from the variable 
`gnus-score-file-alist'."
 (defun gnus-home-score-file (group &optional adapt)
   "Return the home score file for GROUP.
 If ADAPT, return the home adaptive file instead."
-  (let ((list (if adapt gnus-home-adapt-file gnus-home-score-file))
+  (let ((list (ensure-list (if adapt gnus-home-adapt-file 
gnus-home-score-file)))
        elem found)
-    ;; Make sure we have a list.
-    (unless (listp list)
-      (setq list (list list)))
-    ;; Go through the list and look for matches.
     (while (and (not found)
                (setq elem (pop list)))
       (setq found
diff --git a/lisp/gnus/gnus-uu.el b/lisp/gnus/gnus-uu.el
index 1846f05af2d..6ed6358e8ce 100644
--- a/lisp/gnus/gnus-uu.el
+++ b/lisp/gnus/gnus-uu.el
@@ -1371,8 +1371,7 @@ When called interactively, prompt for REGEXP."
          ;; Allow user-defined functions to be run on this file.
          (when gnus-uu-grabbed-file-functions
            (let ((funcs gnus-uu-grabbed-file-functions))
-             (unless (listp funcs)
-               (setq funcs (list funcs)))
+              (setq funcs (ensure-list funcs))
              (while funcs
                (funcall (pop funcs) result-file))))
          (setq result-file nil)
diff --git a/lisp/gnus/message.el b/lisp/gnus/message.el
index 45cc21701b3..7a31f86a2c4 100644
--- a/lisp/gnus/message.el
+++ b/lisp/gnus/message.el
@@ -7707,10 +7707,7 @@ the message."
                ""))
        (when message-wash-forwarded-subjects
          (setq subject (message-wash-subject subject)))
-       ;; Make sure funcs is a list.
-       (and funcs
-            (not (listp funcs))
-            (setq funcs (list funcs)))
+        (setq funcs (ensure-list funcs))
        ;; Apply funcs in order, passing subject generated by previous
        ;; func to the next one.
        (dolist (func funcs)
diff --git a/lisp/gnus/mm-view.el b/lisp/gnus/mm-view.el
index 2c407353559..47d2b5f57e6 100644
--- a/lisp/gnus/mm-view.el
+++ b/lisp/gnus/mm-view.el
@@ -487,8 +487,6 @@ after inserting the part."
             (let ((inhibit-read-only t))
               (delete-region beg end)))))))))
 
-;; Shut up byte-compiler.
-(defvar font-lock-mode-hook)
 (defun mm-display-inline-fontify (handle &optional mode)
   "Insert HANDLE inline fontifying with MODE.
 If MODE is not set, try to find mode automatically."
diff --git a/lisp/gnus/nnmail.el b/lisp/gnus/nnmail.el
index e8f157392d4..904b564409a 100644
--- a/lisp/gnus/nnmail.el
+++ b/lisp/gnus/nnmail.el
@@ -667,7 +667,9 @@ nn*-request-list should have been called before calling 
this function."
                  (cond ((symbolp group)
                         (symbol-name group))
                        ((numberp group)
-                        (number-to-string group))))
+                        (number-to-string group))
+                        ((stringp group)
+                        group)))
            (if (and (numberp (setq max (read buffer)))
                     (numberp (setq min (read buffer))))
                (push (list group (cons min max))
diff --git a/lisp/gnus/nnmairix.el b/lisp/gnus/nnmairix.el
index 72833d7bc33..deb2b669b6b 100644
--- a/lisp/gnus/nnmairix.el
+++ b/lisp/gnus/nnmairix.el
@@ -741,8 +741,7 @@ called interactively, user will be asked for parameters."
   (when (and (stringp query)
             (string-match "\\s-" query))
     (setq query (split-string query)))
-  (when (not (listp query))
-    (setq query (list query)))
+  (setq query (ensure-list query))
   (when (and server group query)
     (let ((groupname (gnus-group-prefixed-name group server))
           ) ;; info
diff --git a/lisp/gnus/spam.el b/lisp/gnus/spam.el
index 3178d9f59e6..c598b10bc08 100644
--- a/lisp/gnus/spam.el
+++ b/lisp/gnus/spam.el
@@ -1375,8 +1375,7 @@ In the case of mover backends, checks the setting of
   (when (and (car-safe groups) (listp (car-safe groups)))
     (setq groups (pop groups)))
 
-  (unless (listp groups)
-    (setq groups (list groups)))
+  (setq groups (ensure-list groups))
 
     ;; remove the current process mark
   (gnus-summary-kill-process-mark)
diff --git a/lisp/help-fns.el b/lisp/help-fns.el
index 22cfbbc39cd..609bed18f2f 100644
--- a/lisp/help-fns.el
+++ b/lisp/help-fns.el
@@ -1749,8 +1749,7 @@ If FRAME is omitted or nil, use the selected frame."
                     (called-interactively-p 'interactive))
     (unless face
       (setq face 'default))
-    (if (not (listp face))
-        (setq face (list face)))
+    (setq face (ensure-list face))
     (with-help-window (help-buffer)
       (with-current-buffer standard-output
         (dolist (f face (buffer-string))
diff --git a/lisp/ibuf-macs.el b/lisp/ibuf-macs.el
index 2c9e9ea8bcd..c38dfefe0c5 100644
--- a/lisp/ibuf-macs.el
+++ b/lisp/ibuf-macs.el
@@ -310,7 +310,7 @@ bound to the current value of the filter.
            (,qualifier-str qualifier))
        ,(when accept-list
           `(progn
-         (unless (listp qualifier) (setq qualifier (list qualifier)))
+         (setq qualifier (ensure-list qualifier))
          ;; Reject equivalent filters: (or f1 f2) is same as (or f2 f1).
          (setq qualifier (sort (delete-dups qualifier) #'string-lessp))
          (setq ,filter (cons ',name (car qualifier)))
diff --git a/lisp/international/mule-cmds.el b/lisp/international/mule-cmds.el
index e3811d81ec2..c26898f7649 100644
--- a/lisp/international/mule-cmds.el
+++ b/lisp/international/mule-cmds.el
@@ -868,8 +868,7 @@ overrides ACCEPT-DEFAULT-P.
 
 Kludgy feature: if FROM is a string, the string is the target text,
 and TO is ignored."
-  (if (not (listp default-coding-system))
-      (setq default-coding-system (list default-coding-system)))
+  (setq default-coding-system (ensure-list default-coding-system))
 
   (let ((no-other-defaults nil)
        auto-cs)
diff --git a/lisp/mail/rmail.el b/lisp/mail/rmail.el
index 716848dc34f..f76600000c9 100644
--- a/lisp/mail/rmail.el
+++ b/lisp/mail/rmail.el
@@ -1,7 +1,6 @@
 ;;; rmail.el --- main code of "RMAIL" mail reader for Emacs  -*- 
lexical-binding:t -*-
 
-;; Copyright (C) 1985-1988, 1993-1998, 2000-2023 Free Software
-;; Foundation, Inc.
+;; Copyright (C) 1985-2023 Free Software Foundation, Inc.
 
 ;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: mail
@@ -90,7 +89,6 @@
 its character representation and its display representation.")
 
 (defvar deleted-head)
-(defvar font-lock-fontified)
 (defvar mail-abbrev-syntax-table)
 (defvar mail-abbrevs)
 (defvar messages-head)
diff --git a/lisp/net/eww.el b/lisp/net/eww.el
index 3cdbe9dd471..089e481ead2 100644
--- a/lisp/net/eww.el
+++ b/lisp/net/eww.el
@@ -566,7 +566,7 @@ NO-SELECT non-nil means do not make the new buffer the 
current buffer."
             (tab-new)
             (eww--open-url-in-new-buffer url)
             (when no-select
-              (tab-bar-switch-to-prev-tab)))
+              (tab-bar-switch-to-recent-tab)))
         (if no-select
             (save-window-excursion (eww--open-url-in-new-buffer url))
           (eww--open-url-in-new-buffer url)))
diff --git a/lisp/net/imap.el b/lisp/net/imap.el
index cfb92674d8a..7de847e2a59 100644
--- a/lisp/net/imap.el
+++ b/lisp/net/imap.el
@@ -1833,7 +1833,7 @@ on failure."
 
 (defun imap-send-command (command &optional buffer)
   (with-current-buffer (or buffer (current-buffer))
-    (if (not (listp command)) (setq command (list command)))
+    (setq command (ensure-list command))
     (let ((tag (setq imap-tag (1+ imap-tag)))
          cmd cmdstr)
       (setq cmdstr (concat (number-to-string imap-tag) " "))
diff --git a/lisp/net/tramp-adb.el b/lisp/net/tramp-adb.el
index 076103e8ae4..3de4721ec77 100644
--- a/lisp/net/tramp-adb.el
+++ b/lisp/net/tramp-adb.el
@@ -923,7 +923,7 @@ implementation will be used."
 
            (when (string-match-p (rx multibyte) command)
              (tramp-error
-              v 'file-error "Cannot apply multi-byte command `%s'" command))
+              v 'file-error "Cannot apply multibyte command `%s'" command))
 
            (while (get-process name1)
              ;; NAME must be unique as process name.
diff --git a/lisp/net/tramp-cache.el b/lisp/net/tramp-cache.el
index 8282e9c87ff..6ecb80f09b2 100644
--- a/lisp/net/tramp-cache.el
+++ b/lisp/net/tramp-cache.el
@@ -28,8 +28,8 @@
 ;; An implementation of information caching for remote files.
 
 ;; Each connection, identified by a `tramp-file-name' structure or by
-;; a process, has a unique cache.  We distinguish 6 kind of caches,
-;; depending on the key:
+;; a process, has a unique cache.  We distinguish several kinds of
+;; caches, depending on the key:
 ;;
 ;; - localname is nil.  These are reusable properties.  Examples:
 ;;   "remote-shell" identifies the POSIX shell to be called on the
@@ -50,11 +50,14 @@
 ;;   definitions already sent to the remote shell, "last-cmd-time" is
 ;;   the timestamp a command has been sent to the remote process.
 ;;
-;; - The key is nil.  These are temporary properties related to the
-;;   local machine.  Examples: "parse-passwd" and "parse-group" keep
-;;   the results of parsing "/etc/passwd" and "/etc/group",
+;; - The key is `tramp-null-hop' or nil.  These are temporary
+;;   properties related to the local machine.  If the key is nil, it
+;;   is silently converted into `tramp-null-hop'.
+;;   Examples: "parse-passwd" and "parse-group" keep the results of
+;;   parsing "/etc/passwd" and "/etc/group",
 ;;   "{uid,gid}-{integer,string}" are the local uid and gid, and
-;;   "locale" is the used shell locale.
+;;   "locale" is the used shell locale.  "user-host-completions" keeps
+;;   the reachable hosts for the commands in tramp-container.el.
 ;;
 ;; - The key is `tramp-cache-version'.  It keeps the Tramp version the
 ;;   cache data was produced with.  If the cache is read by another
@@ -568,6 +571,8 @@ PROPERTIES is a list of file properties (strings)."
               (stringp tramp-persistency-file-name))
       (let ((cache (copy-hash-table tramp-cache-data))
            print-length print-level)
+       ;; Remove `tramp-null-hop'.
+       (remhash tramp-null-hop cache)
        ;; Remove temporary data.  If there is the key "login-as", we
        ;; don't save either, because all other properties might
        ;; depend on the login name, and we want to give the
diff --git a/lisp/net/tramp-message.el b/lisp/net/tramp-message.el
index c91af638449..5b909b69ae3 100644
--- a/lisp/net/tramp-message.el
+++ b/lisp/net/tramp-message.el
@@ -328,9 +328,10 @@ applicable)."
                               (process-buffer vec-or-proc)
                             (tramp-get-connection-buffer
                              vec-or-proc 'dont-create))))))))
-           ;; Translate proc to vec.
+           ;; Translate proc to vec.  Handle nil vec.
            (when (processp vec-or-proc)
-             (setq vec-or-proc (process-get vec-or-proc 'tramp-vector))))
+             (setq vec-or-proc (process-get vec-or-proc 'tramp-vector)))
+           (setq vec-or-proc (tramp-file-name-unify vec-or-proc)))
          ;; Do it.
          (when (and (tramp-file-name-p vec-or-proc)
                     (or (null tramp-debug-command-messages) (= level 6)))
@@ -351,10 +352,8 @@ forces the backtrace even if `tramp-verbose' is less than 
10.
 This function is meant for debugging purposes."
   (let ((tramp-verbose (if force 10 tramp-verbose)))
     (when (>= tramp-verbose 10)
-      (if vec-or-proc
-         (tramp-message
-          vec-or-proc 10 "\n%s" (with-output-to-string (backtrace)))
-       (with-output-to-temp-buffer "*debug tramp*" (backtrace))))))
+      (tramp-message
+       vec-or-proc 10 "\n%s" (with-output-to-string (backtrace))))))
 
 (defsubst tramp-error (vec-or-proc signal fmt-string &rest arguments)
   "Emit an error.
@@ -370,13 +369,12 @@ FMT-STRING and ARGUMENTS."
       ;; character, as in smb domain spec.
       (setq arguments (list fmt-string)
            fmt-string "%s"))
-    (when vec-or-proc
-      (tramp-message
-       vec-or-proc 1 "%s"
-       (error-message-string
-       (list signal
-             (get signal 'error-message)
-             (apply #'format-message fmt-string arguments)))))
+    (tramp-message
+     vec-or-proc 1 "%s"
+     (error-message-string
+      (list signal
+           (get signal 'error-message)
+           (apply #'format-message fmt-string arguments))))
     (signal signal (list (substring-no-properties
                          (apply #'format-message fmt-string arguments))))))
 
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index 30602c353b3..05d28e8494f 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -1190,7 +1190,7 @@ The `ftp' syntax does not support methods.")
      ;; We cannot use `tramp-prefix-regexp', because it starts with `bol'.
      (literal tramp-prefix-format)
 
-     ;; Optional multi hops.
+     ;; Optional multi-hops.
      (* (regexp tramp-remote-file-name-spec-regexp)
         (regexp tramp-postfix-hop-regexp))
 
@@ -1457,10 +1457,12 @@ calling HANDLER.")
 (function-put #'tramp-file-name-localname 'tramp-suppress-trace t)
 (function-put #'tramp-file-name-hop 'tramp-suppress-trace t)
 
-;; Needed for `tramp-read-passwd' and `tramp-get-remote-null-device'.
+;;;###tramp-autoload
 (defconst tramp-null-hop
-  (make-tramp-file-name :user (user-login-name) :host tramp-system-name)
-"Connection hop which identifies the virtual hop before the first one.")
+  (make-tramp-file-name
+   :method "local" :user (user-login-name) :host tramp-system-name)
+  "Connection hop which identifies the virtual hop before the first one.
+Used also for caching properties of the local machine.")
 
 (defun tramp-file-name-user-domain (vec)
   "Return user and domain components of VEC."
@@ -1490,14 +1492,17 @@ If nil, return `tramp-default-port'."
 ;;;###tramp-autoload
 (defun tramp-file-name-unify (vec &optional localname)
   "Unify VEC by removing localname and hop from `tramp-file-name' structure.
-If LOCALNAME is an absolute file name, set it as localname.  If
-LOCALNAME is a relative file name, return `tramp-cache-undefined'.
-Objects returned by this function compare `equal' if they refer to the
-same connection.  Make a copy in order to avoid side effects."
+IF VEC is nil, set it to `tramp-null-hop'.
+If LOCALNAME is an absolute file name, set it as localname.
+If LOCALNAME is a relative file name, return `tramp-cache-undefined'.
+Objects returned by this function compare `equal' if they refer
+to the same connection.  Make a copy in order to avoid side
+effects."
   ;; (declare (tramp-suppress-trace t))
   (if (and (stringp localname)
           (not (file-name-absolute-p localname)))
       (setq vec tramp-cache-undefined)
+    (unless vec (setq vec tramp-null-hop))
     (when (tramp-file-name-p vec)
       (setq vec (copy-tramp-file-name vec))
       (setf (tramp-file-name-localname vec)
@@ -2134,6 +2139,8 @@ Example:
                    ;; DNS-SD service type.
                    ((string-match-p
                      tramp-dns-sd-service-regexp (nth 1 (car v))))
+                   ;; Method.
+                   ((string-equal method (nth 1 (car v))))
                    ;; Configuration file or empty string.
                    (t (file-exists-p (nth 1 (car v))))))
        (setq r (delete (car v) r)))
@@ -2774,16 +2781,14 @@ not in completion mode."
 
            ;; Possible methods.
            (setq result
-                 (append result (tramp-get-completion-methods m)))))))
+                 (append result (tramp-get-completion-methods m hop)))))))
 
     ;; Unify list, add hop, remove nil elements.
     (dolist (elt result)
       (when elt
-       (string-match tramp-prefix-regexp elt)
-       (setq elt (replace-match (concat tramp-prefix-format hop) nil nil elt))
-       (push
-        (substring elt (length (tramp-drop-volume-letter directory)))
-        result1)))
+       (setq elt (replace-regexp-in-string
+                  tramp-prefix-regexp (concat tramp-prefix-format hop) elt))
+       (push (substring elt (length directory)) result1)))
 
     ;; Complete local parts.
     (delete-dups
@@ -2911,11 +2916,14 @@ remote host and localname (filename on remote host)."
 
 ;; This function returns all possible method completions, adding the
 ;; trailing method delimiter.
-(defun tramp-get-completion-methods (partial-method)
-  "Return all method completions for PARTIAL-METHOD."
+(defun tramp-get-completion-methods (partial-method hop)
+  "Return all method completions for PARTIAL-METHOD.
+If HOP is non-nil, return only multi-hop capable methods."
   (mapcar
    (lambda (method)
      (and method (string-prefix-p (or partial-method "") method)
+         (or (not hop)
+             (tramp-multi-hop-p (make-tramp-file-name :method method)))
          (tramp-completion-make-tramp-file-name method nil nil nil)))
    (mapcar #'car tramp-methods)))
 
@@ -6380,6 +6388,7 @@ are written with verbosity of 6."
        (temporary-file-directory tramp-compat-temporary-file-directory)
        (process-environment (default-toplevel-value 'process-environment))
        (buffer (if (eq buffer t) (current-buffer) buffer))
+       (vec (or vec (car tramp-current-connection)))
        result)
     (tramp-message
      vec 6 "`%s %s' %s %s %s %s"
diff --git a/lisp/org/org.el b/lisp/org/org.el
index 175e095e806..f56aa4f6f69 100644
--- a/lisp/org/org.el
+++ b/lisp/org/org.el
@@ -3760,7 +3760,6 @@ This is needed for font-lock setup.")
 (defvar calc-embedded-close-formula)
 (defvar calc-embedded-open-formula)
 (defvar calc-embedded-open-mode)
-(defvar font-lock-unfontify-region-function)
 (defvar org-agenda-tags-todo-honor-ignore-options)
 (defvar remember-data-file)
 (defvar texmathp-why)
diff --git a/lisp/org/ox-beamer.el b/lisp/org/ox-beamer.el
index 689bf1559b4..2590bd5fa72 100644
--- a/lisp/org/ox-beamer.el
+++ b/lisp/org/ox-beamer.el
@@ -924,11 +924,10 @@ holding export options."
   "Support for editing Beamer oriented Org mode files."
   :lighter " Bm")
 
-(when (fboundp 'font-lock-add-keywords)
-  (font-lock-add-keywords
-   'org-mode
-   '((":\\(B_[a-z]+\\|BMCOL\\):" 1 'org-beamer-tag prepend))
-   'prepend))
+(font-lock-add-keywords
+ 'org-mode
+ '((":\\(B_[a-z]+\\|BMCOL\\):" 1 'org-beamer-tag prepend))
+ 'prepend)
 
 (defface org-beamer-tag '((t (:box (:line-width 1 :color grey40))))
   "The special face for beamer tags."
diff --git a/lisp/printing.el b/lisp/printing.el
index 4a6d14260a0..8aea58e157b 100644
--- a/lisp/printing.el
+++ b/lisp/printing.el
@@ -1148,8 +1148,7 @@ Used by `pr-menu-bind' and `pr-update-menus'.")
 
 (defun pr-menu-get-item (name-list)
   ;; NAME-LIST is a string or a list of strings.
-  (or (listp name-list)
-      (setq name-list (list name-list)))
+  (setq name-list (ensure-list name-list))
   (and name-list
        (let* ((reversed (reverse name-list))
              (name (easy-menu-intern (car reversed)))
diff --git a/lisp/progmodes/cperl-mode.el b/lisp/progmodes/cperl-mode.el
index 75ea81d55a4..98943ebda3f 100644
--- a/lisp/progmodes/cperl-mode.el
+++ b/lisp/progmodes/cperl-mode.el
@@ -8834,8 +8834,6 @@ start with default arguments, then refine the slowdown 
regions."
       (message "to %s:%6s,%7s" l delta tot))
     tot))
 
-(defvar font-lock-cache-position)
-
 (defun cperl-emulate-lazy-lock (&optional window-size)
   "Emulate `lazy-lock' without `condition-case', so `debug-on-error' works.
 Start fontifying the buffer from the start (or end) using the given
diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el
index 3e1803fcc98..8a12a154f72 100644
--- a/lisp/progmodes/elisp-mode.el
+++ b/lisp/progmodes/elisp-mode.el
@@ -429,6 +429,14 @@ be used instead.
 
 (defvar warning-minimum-log-level)
 
+(defvar elisp--local-macroenv
+  `((cl-eval-when . ,(lambda (&rest args) `(progn . ,(cdr args))))
+    (eval-when-compile . ,(lambda (&rest args) `(progn . ,args)))
+    (eval-and-compile . ,(lambda (&rest args) `(progn . ,args))))
+  "Environment to use while tentatively expanding macros.
+This is used to try and avoid the most egregious problems linked to the
+use of `macroexpand-all' as a way to find the \"underlying raw code\".")
+
 (defun elisp--local-variables ()
   "Return a list of locally let-bound variables at point."
   (save-excursion
@@ -444,15 +452,17 @@ be used instead.
                        (car (read-from-string
                              (concat txt "elisp--witness--lisp" closer)))
                      ((invalid-read-syntax end-of-file) nil)))
-             (macroexpand-advice (lambda (expander form &rest args)
-                                   (condition-case nil
-                                       (apply expander form args)
-                                     (error form))))
+             (macroexpand-advice
+              (lambda (expander form &rest args)
+                (condition-case err
+                    (apply expander form args)
+                  (error (message "Ignoring macroexpansion error: %S" err)
+                         form))))
              (sexp
               (unwind-protect
                   (let ((warning-minimum-log-level :emergency))
-                    (advice-add 'macroexpand :around macroexpand-advice)
-                    (macroexpand-all sexp))
+                    (advice-add 'macroexpand-1 :around macroexpand-advice)
+                    (macroexpand-all sexp elisp--local-macroenv))
                 (advice-remove 'macroexpand macroexpand-advice)))
              (vars (elisp--local-variables-1 nil sexp)))
         (delq nil
@@ -1380,9 +1390,9 @@ BEG and END are the start and end of the output in 
current buffer.
 VALUE is the Lisp value printed, ALT1 and ALT2 are strings for the
 alternative printed representations that can be displayed."
   (let ((map (make-sparse-keymap)))
-    (define-key map "\C-m" 'elisp-last-sexp-toggle-display)
-    (define-key map [down-mouse-2] 'mouse-set-point)
-    (define-key map [mouse-2] 'elisp-last-sexp-toggle-display)
+    (define-key map "\C-m" #'elisp-last-sexp-toggle-display)
+    (define-key map [down-mouse-2] #'mouse-set-point)
+    (define-key map [mouse-2] #'elisp-last-sexp-toggle-display)
     (add-text-properties
      beg end
      `(printed-value (,value ,alt1 ,alt2)
@@ -1439,7 +1449,7 @@ If CHAR is not a character, return nil."
                     (lambda (modif)
                       (cond ((eq modif 'super) "\\s-")
                             (t (string ?\\ (upcase (aref (symbol-name modif) 
0)) ?-))))
-                    mods "")
+                    mods)
                    (cond
                     ((memq c '(?\; ?\( ?\) ?\{ ?\} ?\[ ?\] ?\" ?\' ?\\)) 
(string ?\\ c))
                     ((eq c 127) "\\C-?")
@@ -1515,7 +1525,7 @@ If CHAR is not a character, return nil."
                   `(call-interactively
                     (lambda (&rest args) ,expr args))))
          expr)))))
-(define-obsolete-function-alias 'preceding-sexp 'elisp--preceding-sexp "25.1")
+(define-obsolete-function-alias 'preceding-sexp #'elisp--preceding-sexp "25.1")
 
 (defun elisp--eval-last-sexp (eval-last-sexp-arg-internal)
   "Evaluate sexp before point; print value in the echo area.
@@ -1643,9 +1653,8 @@ Reinitialize the face according to the `defface' 
specification."
                    ;; The second arg is an expression that evaluates to
                    ;; an expression.  The second evaluation is the one
                    ;; normally performed not by normal execution but by
-                   ;; custom-initialize-set (for example), which does not
-                   ;; use lexical-binding.
-                   (eval (eval (nth 2 form) lexical-binding))))
+                   ;; custom-initialize-set (for example).
+                   (eval (eval (nth 2 form) lexical-binding) t)))
         form)
        ;; `defface' is macroexpanded to `custom-declare-face'.
        ((eq (car form) 'custom-declare-face)
@@ -1785,7 +1794,7 @@ Elements are as follows:
     (or (progn (elisp-eldoc-var-docstring callback) str)
         (progn (elisp-eldoc-funcall callback) str))))
 
-(defalias 'elisp-eldoc-documentation-function 'elisp--documentation-one-liner
+(defalias 'elisp-eldoc-documentation-function #'elisp--documentation-one-liner
   "Return Elisp documentation for the thing at point as one-line string.
 This is meant as a backward compatibility aide to the \"old\"
 Elisp eldoc behavior.  Consider variable docstrings and function
diff --git a/lisp/progmodes/f90.el b/lisp/progmodes/f90.el
index deccc75b156..815c7352281 100644
--- a/lisp/progmodes/f90.el
+++ b/lisp/progmodes/f90.el
@@ -159,7 +159,6 @@
 ;; 3. Labels for "else" statements (F2003)?
 
 (defvar comment-auto-fill-only-comments)
-(defvar font-lock-keywords)
 
 ;; User options
 
diff --git a/lisp/progmodes/idlw-help.el b/lisp/progmodes/idlw-help.el
index 2d08714b7cf..a57a0c32ac7 100644
--- a/lisp/progmodes/idlw-help.el
+++ b/lisp/progmodes/idlw-help.el
@@ -1141,7 +1141,6 @@ When DING is non-nil, ring the bell as well."
          (goto-char pos)
          (recenter 0)))))
 
-(defvar font-lock-verbose)
 (defvar idlwave-mode-syntax-table)
 (defvar idlwave-font-lock-defaults)
 (defun idlwave-help-fontify ()
diff --git a/lisp/progmodes/idlwave.el b/lisp/progmodes/idlwave.el
index 7bdaa6b1b6f..3c00046a26a 100644
--- a/lisp/progmodes/idlwave.el
+++ b/lisp/progmodes/idlwave.el
@@ -5335,7 +5335,6 @@ directories and save the routine info.
        (idlwave-path-alist-remove-flag dir-entry 'user)))
     (idlwave-scan-user-lib-files path-alist)))
 
-(defvar font-lock-mode)
 (defun idlwave-scan-user-lib-files (path-alist)
   ;; Scan the PRO files in PATH-ALIST and store the info in the user catalog
   (let* ((idlwave-scanning-lib t)
diff --git a/lisp/progmodes/make-mode.el b/lisp/progmodes/make-mode.el
index 017a551bc05..ff2aa137813 100644
--- a/lisp/progmodes/make-mode.el
+++ b/lisp/progmodes/make-mode.el
@@ -695,7 +695,7 @@ The function must satisfy this calling convention:
   "Table of all macro names known for this buffer.")
 (put 'makefile-macro-table 'risky-local-variable t)
 
-(defvar makefile-browser-client
+(defvar makefile-browser-client nil
   "A buffer in Makefile mode that is currently using the browser.")
 
 (defvar makefile-browser-selection-vector nil)
diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el
index ab7376b7dc6..7aaf7a9f9fb 100644
--- a/lisp/progmodes/project.el
+++ b/lisp/progmodes/project.el
@@ -1070,8 +1070,8 @@ paths.  This only affects history entries added by 
earlier calls
 to `project-find-file' or `project-find-dir'.
 
 This has the effect of sharing more history between projects."
-  :type '(choice (const t :tag "Default behavior")
-                 (const relativize :tag "Adjust to be relative to current"))
+  :type '(choice (const :tag "Default behavior" t)
+                 (const :tag "Adjust to be relative to current" relativize))
   :group 'project
   :version "30.1")
 
@@ -1911,7 +1911,8 @@ listed in the dispatch menu produced from 
`project-switch-commands'."
 
 When `brackets', use text brackets and `bold' for the character.
 Otherwise, use the face `help-key-binding' in the prompt."
-  :type 'boolean
+  :type '(choice (const :tag "Using help-key-binding face" t)
+                 (const :tag "Using bold face and brackets" brackets))
   :group 'project
   :version "30.1")
 
diff --git a/lisp/progmodes/sh-script.el b/lisp/progmodes/sh-script.el
index cfc10878922..ed4ea8e3618 100644
--- a/lisp/progmodes/sh-script.el
+++ b/lisp/progmodes/sh-script.el
@@ -1,7 +1,6 @@
 ;;; sh-script.el --- shell-script editing commands for Emacs  -*- 
lexical-binding:t -*-
 
-;; Copyright (C) 1993-1997, 1999, 2001-2023 Free Software Foundation,
-;; Inc.
+;; Copyright (C) 1993-2023 Free Software Foundation, Inc.
 
 ;; Author: Daniel Pfeiffer <occitan@esperanto.org>
 ;; Old-Version: 2.0f
@@ -158,10 +157,6 @@
 (autoload 'shell-command-completion "shell")
 (autoload 'shell-environment-variable-completion "shell")
 
-(defvar font-lock-comment-face)
-(defvar font-lock-set-defaults)
-(defvar font-lock-string-face)
-
 
 (defgroup sh nil
   "Shell programming utilities."
diff --git a/lisp/progmodes/sql.el b/lisp/progmodes/sql.el
index 61c8525b77a..004ae50ef50 100644
--- a/lisp/progmodes/sql.el
+++ b/lisp/progmodes/sql.el
@@ -235,10 +235,6 @@
 (require 'view)
 (eval-when-compile (require 'subr-x))   ; string-empty-p
 
-(defvar font-lock-keyword-face)
-(defvar font-lock-set-defaults)
-(defvar font-lock-string-face)
-
 ;;; Allow customization
 
 (defgroup SQL nil
@@ -1191,12 +1187,11 @@ Starts `sql-interactive-mode' after doing some setup."
 
 (defcustom sql-postgres-options '("-P" "pager=off")
   "List of additional options for `sql-postgres-program'.
-The default setting includes the -P option which breaks older versions
-of the psql client (such as version 6.5.3).  The -P option is equivalent
-to the --pset option.  If you want the psql to prompt you for a user
-name, add the string \"-u\" to the list of options.  If you want to
-provide a user name on the command line (newer versions such as 7.1),
-add your name with a \"-U\" prefix (such as \"-Umark\") to the list."
+The default -P option is equivalent to the --pset option.  If you
+want psql to prompt you for a user name, add the string \"-u\" to
+the list of options.  If you want to provide a user name on the
+command line, add your name with a \"-U\" prefix (such as
+\"-Umark\") to the list."
   :type '(repeat string)
   :version "20.8")
 
diff --git a/lisp/speedbar.el b/lisp/speedbar.el
index f56c3915521..67d4e8c4df1 100644
--- a/lisp/speedbar.el
+++ b/lisp/speedbar.el
@@ -662,7 +662,7 @@ the dot should NOT be quoted in with \\.  Other regular 
expression
 matchers are allowed however.  EXTENSION may be a single string or a
 list of strings."
   (interactive "sExtension: ")
-  (if (not (listp extension)) (setq extension (list extension)))
+  (setq extension (ensure-list extension))
   (while extension
     (if (member (car extension) speedbar-supported-extension-expressions)
        nil
@@ -677,8 +677,7 @@ list of strings."
 This function will modify `speedbar-ignored-directory-regexp' and add
 DIRECTORY-EXPRESSION to `speedbar-ignored-directory-expressions'."
   (interactive "sDirectory regex: ")
-  (if (not (listp directory-expression))
-      (setq directory-expression (list directory-expression)))
+  (setq directory-expression (ensure-list directory-expression))
   (while directory-expression
     (if (member (car directory-expression) 
speedbar-ignored-directory-expressions)
        nil
diff --git a/lisp/strokes.el b/lisp/strokes.el
index 293bdf0f369..694677ada0b 100644
--- a/lisp/strokes.el
+++ b/lisp/strokes.el
@@ -1211,12 +1211,7 @@ the stroke as a character in some language."
 ;;\\{edit-strokes-mode-map}"
 ;;  (setq truncate-lines nil
 ;;     auto-show-mode nil              ; don't want problems here either
-;;     mode-popup-menu edit-strokes-menu) ; what about extent-specific stuff?
-;;  (and (featurep 'menubar)
-;;       current-menubar
-;;       (setq-local current-menubar
-;;                   (copy-sequence current-menubar))
-;;       (add-submenu nil edit-strokes-menu)))
+;;     mode-popup-menu edit-strokes-menu)) ; what about extent-specific stuff?
 
 ;;(let ((map edit-strokes-mode-map))
 ;;  (define-key map "<" 'beginning-of-buffer)
diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el
index e9ce7735229..9a59e480f06 100644
--- a/lisp/tab-bar.el
+++ b/lisp/tab-bar.el
@@ -164,7 +164,8 @@ For easier selection of tabs by their numbers, consider 
customizing
   (declare-function icons--register "icons")
   (unless (iconp 'tab-bar-new)
     (define-icon tab-bar-new nil
-      `((image "tabs/new.xpm"
+      `((image "symbols/plus_16.svg" "tabs/new.xpm"
+               :face shadow
                :margin ,tab-bar-button-margin
                :ascent center)
         ;; (emoji "➕")
@@ -177,7 +178,9 @@ For easier selection of tabs by their numbers, consider 
customizing
 
   (unless (iconp 'tab-bar-close)
     (define-icon tab-bar-close nil
-      `((image "tabs/close.xpm"
+      `((image "symbols/cross_16.svg" "tabs/close.xpm"
+               :face shadow
+               :height (1.0 . em)
                :margin ,tab-bar-button-margin
                :ascent center)
         ;; (emoji " ❌")
@@ -191,7 +194,10 @@ For easier selection of tabs by their numbers, consider 
customizing
 
   (unless (iconp 'tab-bar-menu-bar)
     (define-icon tab-bar-menu-bar nil
-      '(;; (emoji "🍔")
+      `((image "symbols/menu_16.svg"
+               :margin ,tab-bar-button-margin
+               :ascent center)
+        ;; (emoji "🍔")
         (symbol "☰")
         (text "Menu" :face tab-bar-tab-inactive))
       "Icon for the menu bar."
@@ -799,16 +805,17 @@ the formatted tab name to display in the tab bar."
   :version "28.1")
 
 (defun tab-bar-tab-name-format-default (tab i)
-  (let ((current-p (eq (car tab) 'current-tab)))
-    (propertize
-     (concat (if tab-bar-tab-hints (format "%d " i) "")
-             (alist-get 'name tab)
-             (or (and tab-bar-close-button-show
-                      (not (eq tab-bar-close-button-show
-                               (if current-p 'non-selected 'selected)))
-                      tab-bar-close-button)
-                 ""))
-     'face (funcall tab-bar-tab-face-function tab))))
+  (let* ((current-p (eq (car tab) 'current-tab))
+         (name (concat (if tab-bar-tab-hints (format "%d " i) "")
+                       (alist-get 'name tab)
+                       (or (and tab-bar-close-button-show
+                                (not (eq tab-bar-close-button-show
+                                         (if current-p 'non-selected 
'selected)))
+                                tab-bar-close-button)
+                           ""))))
+    (add-face-text-property
+     0 (length name) (funcall tab-bar-tab-face-function tab) t name)
+    name))
 
 (defcustom tab-bar-format '(tab-bar-format-history
                             tab-bar-format-tabs
@@ -867,7 +874,7 @@ Used by `tab-bar-format-menu-bar'."
 (defun tab-bar-format-menu-bar ()
   "Produce the Menu button for the tab bar that shows the menu bar."
   `((menu-bar menu-item ,tab-bar-menu-bar-button
-     tab-bar-menu-bar :help "Menu Bar")))
+     tab-bar-menu-bar :help "Menu bar")))
 
 (defun tab-bar-format-history ()
   "Produce back and forward buttons for the tab bar.
@@ -894,13 +901,13 @@ You can hide these buttons by customizing 
`tab-bar-format' and removing
         menu-item
         ,(funcall tab-bar-tab-name-format-function tab i)
         ignore
-        :help "Current tab")))
+        :help ,(alist-get 'name tab))))
     (t
      `((,(intern (format "tab-%i" i))
         menu-item
         ,(funcall tab-bar-tab-name-format-function tab i)
         ,(alist-get 'binding tab)
-        :help "Click to visit tab"))))
+        :help ,(alist-get 'name tab)))))
    (when (alist-get 'close-binding tab)
      `((,(if (eq (car tab) 'current-tab) 'C-current-tab
            (intern (format "C-tab-%i" i)))
@@ -2233,7 +2240,7 @@ and can restore them."
 
         (unless (iconp 'tab-bar-back)
           (define-icon tab-bar-back nil
-            `((image "tabs/left-arrow.xpm"
+            `((image "symbols/chevron_left_16.svg" "tabs/left-arrow.xpm"
                      :margin ,tab-bar-button-margin
                      :ascent center)
               (text " < "))
@@ -2243,7 +2250,7 @@ and can restore them."
 
         (unless (iconp 'tab-bar-forward)
           (define-icon tab-bar-forward nil
-            `((image "tabs/right-arrow.xpm"
+            `((image "symbols/chevron_right_16.svg" "tabs/right-arrow.xpm"
                      :margin ,tab-bar-button-margin
                      :ascent center)
               (text " > "))
diff --git a/lisp/tab-line.el b/lisp/tab-line.el
index d7c3049270a..e277d1fb9ed 100644
--- a/lisp/tab-line.el
+++ b/lisp/tab-line.el
@@ -29,6 +29,7 @@
 
 (require 'cl-lib)
 (require 'seq) ; tab-line.el is not pre-loaded so it's safe to use it here
+(require 'icons)
 
 
 (defgroup tab-line nil
@@ -190,12 +191,19 @@ If the value is a function, call it with no arguments."
   :group 'tab-line
   :version "27.1")
 
+(define-icon tab-line-new nil
+  `((image "symbols/plus_16.svg" "tabs/new.xpm"
+           :face shadow
+           :margin (2 . 0)
+           :ascent center)
+    (text " + "))
+  "Icon for creating a new tab."
+  :version "30.1"
+  :help-echo "New tab")
+
 (defvar tab-line-new-button
-  (propertize " + "
-              'display '(image :type xpm
-                               :file "tabs/new.xpm"
-                               :margin (2 . 0)
-                               :ascent center)
+  (propertize (icon-string 'tab-line-new)
+              'rear-nonsticky nil
               'keymap tab-line-add-map
               'mouse-face 'tab-line-highlight
               'help-echo "Click to add tab")
@@ -218,34 +226,54 @@ If nil, don't show it at all."
   :group 'tab-line
   :version "27.1")
 
+(define-icon tab-line-close nil
+  `((image "symbols/cross_16.svg" "tabs/close.xpm"
+           :face shadow
+           :height (1.0 . em)
+           :margin (2 . 0)
+           :ascent center)
+    (text " x"))
+  "Icon for closing the clicked tab."
+  :version "30.1"
+  :help-echo "Click to close tab")
+
 (defvar tab-line-close-button
-  (propertize " x"
-              'display '(image :type xpm
-                               :file "tabs/close.xpm"
-                               :margin (2 . 0)
-                               :ascent center)
+  (propertize (icon-string 'tab-line-close)
+              'rear-nonsticky nil ;; important to not break auto-scroll
               'keymap tab-line-tab-close-map
               'mouse-face 'tab-line-close-highlight
               'help-echo "Click to close tab")
   "Button for closing the clicked tab.")
 
+(define-icon tab-line-left nil
+  `((image "symbols/chevron_left_16.svg" "tabs/left-arrow.xpm"
+           :face shadow
+           :margin (2 . 0)
+           :ascent center)
+    (text " <"))
+  "Icon for scrolling horizontally to the left."
+  :version "30.1")
+
 (defvar tab-line-left-button
-  (propertize " <"
-              'display '(image :type xpm
-                               :file "tabs/left-arrow.xpm"
-                               :margin (2 . 0)
-                               :ascent center)
+  (propertize (icon-string 'tab-line-left)
+              'rear-nonsticky nil
               'keymap tab-line-left-map
               'mouse-face 'tab-line-highlight
               'help-echo "Click to scroll left")
   "Button for scrolling horizontally to the left.")
 
+(define-icon tab-line-right nil
+  `((image "symbols/chevron_right_16.svg" "tabs/right-arrow.xpm"
+           :face shadow
+           :margin (2 . 0)
+           :ascent center)
+    (text "> "))
+  "Icon for scrolling horizontally to the right."
+  :version "30.1")
+
 (defvar tab-line-right-button
-  (propertize "> "
-              'display '(image :type xpm
-                               :file "tabs/right-arrow.xpm"
-                               :margin (2 . 0)
-                               :ascent center)
+  (propertize (icon-string 'tab-line-right)
+              'rear-nonsticky nil
               'keymap tab-line-right-map
               'mouse-face 'tab-line-highlight
               'help-echo "Click to scroll right")
@@ -531,21 +559,27 @@ which the tab will represent."
       (setf face (funcall fn tab tabs face buffer-p selected-p)))
     (apply 'propertize
            (concat (propertize (string-replace "%" "%%" name) ;; (bug#57848)
+                               'face face
                                'keymap tab-line-tab-map
                                'help-echo (if selected-p "Current tab"
                                             "Click to select tab")
                                ;; Don't turn mouse-1 into mouse-2 (bug#49247)
                                'follow-link 'ignore)
-                   (or (and (or buffer-p (assq 'buffer tab) (assq 'close tab))
-                            tab-line-close-button-show
-                            (not (eq tab-line-close-button-show
-                                     (if selected-p 'non-selected 'selected)))
-                            tab-line-close-button)
-                       ""))
+                   (let ((close (or (and (or buffer-p (assq 'buffer tab)
+                                             (assq 'close tab))
+                                         tab-line-close-button-show
+                                         (not (eq tab-line-close-button-show
+                                                  (if selected-p 'non-selected
+                                                    'selected)))
+                                         tab-line-close-button)
+                                    "")))
+                     (setq close (copy-sequence close))
+                     ;; Don't overwrite the icon face
+                     (add-face-text-property 0 (length close) face t close)
+                     close))
            `(
              tab ,tab
              ,@(if selected-p '(selected t))
-             face ,face
              mouse-face tab-line-highlight))))
 
 (defun tab-line-format-template (tabs)
@@ -684,7 +718,7 @@ the selected tab visible."
       (erase-buffer)
       (apply 'insert strings)
       (goto-char (point-min))
-      (add-face-text-property (point-min) (point-max) 'tab-line)
+      (add-face-text-property (point-min) (point-max) 'tab-line t)
       ;; Continuation means tab-line doesn't fit completely,
       ;; thus scroll arrows are needed for scrolling.
       (setq show-arrows (> (vertical-motion 1) 0))
diff --git a/lisp/textmodes/ispell.el b/lisp/textmodes/ispell.el
index 97c4ce9f32d..c73f92aa0b3 100644
--- a/lisp/textmodes/ispell.el
+++ b/lisp/textmodes/ispell.el
@@ -1747,6 +1747,7 @@ Ispell is then restarted because the local words could 
conflict.")
 
 (defvar-local ispell-buffer-session-localwords nil
   "List of words accepted for session in this buffer.")
+(put 'ispell-buffer-session-localwords 'safe-local-variable 
#'list-of-strings-p)
 
 (defvar ispell-parser 'use-mode-name
   "Indicates whether ispell should parse the current buffer as TeX Code.
diff --git a/lisp/textmodes/reftex-cite.el b/lisp/textmodes/reftex-cite.el
index 6beae816257..eaa03c96fe9 100644
--- a/lisp/textmodes/reftex-cite.el
+++ b/lisp/textmodes/reftex-cite.el
@@ -566,7 +566,7 @@ If FORMAT is non-nil `format' entry accordingly."
           (reftex-get-bib-field "booktitle" entry "in: %s"))
          (t ""))))
     (setq authors (reftex-truncate authors 30 t t))
-    (when (reftex-use-fonts)
+    (when reftex-use-fonts
       (put-text-property 0 (length key)     'face reftex-label-face
                          key)
       (put-text-property 0 (length authors) 'face reftex-bib-author-face
@@ -609,7 +609,7 @@ If FORMAT is non-nil `format' entry accordingly."
     (push text lines)
     (setq text (mapconcat #'identity (nreverse lines) "\n     "))
 
-    (when (reftex-use-fonts)
+    (when reftex-use-fonts
       (put-text-property 0 (length text) 'face reftex-bib-author-face text))
     (concat key "\n     " text "\n\n")))
 
diff --git a/lisp/textmodes/reftex-index.el b/lisp/textmodes/reftex-index.el
index c8a45f068d1..7cb15c7e99a 100644
--- a/lisp/textmodes/reftex-index.el
+++ b/lisp/textmodes/reftex-index.el
@@ -536,7 +536,7 @@ SPC=view TAB=goto RET=goto+hide [e]dit [q]uit [r]escan 
[f]ollow [?]Help
                    (nth 2 (car reftex-index-restriction-data))
                  reftex-index-restriction-indicator)))
 
-      (if (reftex-use-fonts)
+      (if reftex-use-fonts
           (put-text-property (point-min) (point)
                              'face reftex-index-header-face))
       (cursor-intangible-mode 1)
@@ -567,7 +567,7 @@ SPC=view TAB=goto RET=goto+hide [e]dit [q]uit [r]escan 
[f]ollow [?]Help
          (context-indent (concat indent "  "))
          (section-chars (mapcar #'identity reftex-index-section-letters))
          (this-section-char 0)
-         (font (reftex-use-fonts))
+         (font reftex-use-fonts)
          (bor (car reftex-index-restriction-data))
          (eor (nth 1 reftex-index-restriction-data))
          (mouse-face
diff --git a/lisp/textmodes/reftex-ref.el b/lisp/textmodes/reftex-ref.el
index d0a44eca17c..64cf3fa4bbb 100644
--- a/lisp/textmodes/reftex-ref.el
+++ b/lisp/textmodes/reftex-ref.el
@@ -781,7 +781,6 @@ When called with 2 \\[universal-argument] prefix args, 
disable magic word recogn
         (funcall errorf "Label %s not found" label))
       found)))
 
-(defvar font-lock-mode)
 (defun reftex-show-entry (beg-hlt end-hlt)
   ;; Show entry if point is hidden
   (let* ((n (/ (window-height) 2))
diff --git a/lisp/textmodes/reftex-sel.el b/lisp/textmodes/reftex-sel.el
index 3c9f9ca94c8..61baf9408c2 100644
--- a/lisp/textmodes/reftex-sel.el
+++ b/lisp/textmodes/reftex-sel.el
@@ -204,7 +204,7 @@ During a selection process, these are the local bindings.
   ;;           a used member near to this one, as a possible starting point.
   ;; XR-PREFIX is the prefix to put in front of labels.
   ;; TOC-BUFFER means this is to fill the toc buffer.
-  (let* ((font (reftex-use-fonts))
+  (let* ((font reftex-use-fonts)
          (cnt 0)
          (index -1)
          (toc-indent " ")
diff --git a/lisp/textmodes/reftex-toc.el b/lisp/textmodes/reftex-toc.el
index de49b7c6c70..312ccb0f2be 100644
--- a/lisp/textmodes/reftex-toc.el
+++ b/lisp/textmodes/reftex-toc.el
@@ -263,7 +263,7 @@ SPC=view TAB=goto RET=goto+hide [q]uit [r]escan [l]abels 
[f]ollow [x]r [?]Help
 ------------------------------------------------------------------------------
 " (abbreviate-file-name reftex-last-toc-master)))
 
-      (if (reftex-use-fonts)
+      (if reftex-use-fonts
           (put-text-property (point-min) (point) 'font-lock-face 
reftex-toc-header-face))
       (cursor-intangible-mode 1)
       (add-text-properties (point-min) (point)
diff --git a/lisp/textmodes/reftex-vars.el b/lisp/textmodes/reftex-vars.el
index 60ee40180d1..ebe49ae9fef 100644
--- a/lisp/textmodes/reftex-vars.el
+++ b/lisp/textmodes/reftex-vars.el
@@ -1933,7 +1933,6 @@ The value of this variable will only have any effect when
 
 (defcustom reftex-use-fonts t
   "Non-nil means, use fonts in *toc* and selection buffers.
-Font-lock must be loaded as well to actually get fontified display.
 When changing this option, a rescan may be necessary to activate the change."
   :group 'reftex-fontification-configurations
   :type 'boolean)
diff --git a/lisp/textmodes/reftex.el b/lisp/textmodes/reftex.el
index 50bec6ef172..ae3ae1a198d 100644
--- a/lisp/textmodes/reftex.el
+++ b/lisp/textmodes/reftex.el
@@ -250,9 +250,6 @@ on the menu bar.
 (defvar LaTeX-label-function)
 (defvar tex-main-file)
 (defvar outline-minor-mode)
-(defvar font-lock-mode)
-(defvar font-lock-keywords)
-(defvar font-lock-fontify-region-function)
 
 ;;; =========================================================================
 ;;;
@@ -2027,21 +2024,14 @@ IGNORE-WORDS List of words which should be removed from 
the string."
 ;;;
 ;;; Fontification and Highlighting
 
-(defun reftex-use-fonts ()
-  ;; Return t if we can and want to use fonts.
-  (and ; window-system
-       reftex-use-fonts
-       (featurep 'font-lock)))
-
 (defun reftex-refontify ()
   ;; Return t if we need to refontify context
-  (and (reftex-use-fonts)
+  (and reftex-use-fonts
        (or (eq t reftex-refontify-context)
            (and (eq 1 reftex-refontify-context)
                 ;; Test of we use the font-lock version of x-symbol
                 (and (featurep 'x-symbol-tex) (not (boundp 
'x-symbol-mode)))))))
 
-(defvar font-lock-defaults-computed)
 (defun reftex-fontify-select-label-buffer (parent-buffer)
   ;; Fontify the `*RefTeX Select*' buffer.  Buffer is temporarily renamed to
   ;; start with none-SPC char, because Font-Lock otherwise refuses operation.
@@ -2342,6 +2332,10 @@ Your bug report will be posted to the AUCTeX bug 
reporting list.
 
 (define-obsolete-function-alias 'reftex-window-height #'window-height "30.1")
 
+(defun reftex-use-fonts ()
+  (declare (obsolete "use variable `reftex-use-fonts' instead." "30.1"))
+  reftex-use-fonts)
+
 (provide 'reftex)
 
 ;;; reftex.el ends here
diff --git a/lisp/textmodes/rst.el b/lisp/textmodes/rst.el
index 6108e80363c..d2661a44734 100644
--- a/lisp/textmodes/rst.el
+++ b/lisp/textmodes/rst.el
@@ -170,8 +170,7 @@ When FUN is called match data is just set by `looking-at' 
and
 point is at the beginning of the line.  Return nil if moving
 forward failed or otherwise the return value of FUN.  Preserve
 global match data, point, mark and current buffer."
-  (unless (listp rst-re-args)
-    (setq rst-re-args (list rst-re-args)))
+  (setq rst-re-args (ensure-list rst-re-args))
   (unless fun
     (setq fun #'identity))
   (save-match-data
diff --git a/lisp/textmodes/tex-mode.el b/lisp/textmodes/tex-mode.el
index 294c9792f39..41c4a6a1373 100644
--- a/lisp/textmodes/tex-mode.el
+++ b/lisp/textmodes/tex-mode.el
@@ -1,7 +1,6 @@
 ;;; tex-mode.el --- TeX, LaTeX, and SliTeX mode commands  -*- 
lexical-binding:t -*-
 
-;; Copyright (C) 1985-1986, 1989, 1992, 1994-1999, 2001-2023 Free
-;; Software Foundation, Inc.
+;; Copyright (C) 1985-2023 Free Software Foundation, Inc.
 
 ;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: tex
@@ -33,9 +32,6 @@
   (require 'cl-lib)
   (require 'skeleton))
 
-(defvar font-lock-comment-face)
-(defvar font-lock-doc-face)
-
 (require 'shell)
 (require 'compile)
 
diff --git a/lisp/transient.el b/lisp/transient.el
index 78496843284..52c21871548 100644
--- a/lisp/transient.el
+++ b/lisp/transient.el
@@ -6,7 +6,7 @@
 ;; URL: https://github.com/magit/transient
 ;; Keywords: extensions
 
-;; Package-Version: 0.4.1
+;; Package-Version: 0.4.3
 ;; Package-Requires: ((emacs "26.1"))
 
 ;; SPDX-License-Identifier: GPL-3.0-or-later
@@ -67,6 +67,7 @@
 
 (defvar display-line-numbers) ; since Emacs 26.1
 (defvar Man-notify-method)
+(defvar pp-default-function) ; since Emacs 29.1
 
 (defmacro transient--with-emergency-exit (&rest body)
   (declare (indent defun))
@@ -565,7 +566,9 @@ the previous prefix."
   (setq list (cl-sort (copy-sequence list) #'string< :key #'car))
   (with-temp-file file
     (let ((print-level nil)
-          (print-length nil))
+          (print-length nil)
+          (pp-default-function 'pp-28)
+          (fill-column 999))
       (pp list (current-buffer)))))
 
 (defvar transient-values
@@ -953,7 +956,7 @@ keyword.
   (pcase-let ((`(,class ,slots ,_ ,docstr ,_)
                (transient--expand-define-args args arglist)))
     `(progn
-       (defalias ',name ,(transient--default-infix-command))
+       (defalias ',name #'transient--default-infix-command)
        (put ',name 'interactive-only t)
        (put ',name 'command-modes (list 'not-a-mode))
        (put ',name 'function-documentation ,docstr)
@@ -969,6 +972,15 @@ example, sets a variable, use `transient-define-infix' 
instead.
 
 \(fn NAME ARGLIST [DOCSTRING] [KEYWORD VALUE]...)")
 
+(defun transient--default-infix-command ()
+  "Most transient infix commands are but an alias for this command."
+  (interactive)
+  (let ((obj (transient-suffix-object)))
+    (transient-infix-set obj (transient-infix-read obj)))
+  (transient--show))
+(put 'transient--default-infix-command 'interactive-only t)
+(put 'transient--default-infix-command 'command-modes (list 'not-a-mode))
+
 (defun transient--expand-define-args (args &optional arglist)
   (unless (listp arglist)
     (error "Mandatory ARGLIST is missing"))
@@ -1071,11 +1083,16 @@ example, sets a variable, use `transient-define-infix' 
instead.
                               (if (and desc (or (stringp desc) (symbolp desc)))
                                   desc
                                 (plist-get args :key)))))))
-          (setq args (plist-put args :command
-                                `(defalias ',sym ,(macroexp-quote cmd))))))
+          (setq args (plist-put
+                      args :command
+                      `(prog1 ',sym
+                         (put ',sym 'interactive-only t)
+                         (put ',sym 'command-modes (list 'not-a-mode))
+                         (defalias ',sym ,(macroexp-quote cmd)))))))
        ((or (stringp car)
             (and car (listp car)))
-        (let ((arg pop))
+        (let ((arg pop)
+              (sym nil))
           (cl-typecase arg
             (list
              (setq args (plist-put args :shortarg (car  arg)))
@@ -1085,9 +1102,13 @@ example, sets a variable, use `transient-define-infix' 
instead.
              (when-let ((shortarg (transient--derive-shortarg arg)))
                (setq args (plist-put args :shortarg shortarg)))
              (setq args (plist-put args :argument arg))))
-          (setq args (plist-put args :command
-                                (list 'quote (intern (format "transient:%s:%s"
-                                                             prefix arg)))))
+          (setq sym (intern (format "transient:%s:%s" prefix arg)))
+          (setq args (plist-put
+                      args :command
+                      `(prog1 ',sym
+                         (put ',sym 'interactive-only t)
+                         (put ',sym 'command-modes (list 'not-a-mode))
+                         (defalias ',sym #'transient--default-infix-command))))
           (cond ((and car (not (keywordp car)))
                  (setq class 'transient-option)
                  (setq args (plist-put args :reader (macroexp-quote pop))))
@@ -1116,26 +1137,6 @@ example, sets a variable, use `transient-define-infix' 
instead.
           (macroexp-quote (or class 'transient-suffix))
           (cons 'list args))))
 
-(defun transient--default-infix-command ()
-  (cons 'lambda
-        '(()
-          (interactive)
-          (let ((obj (transient-suffix-object)))
-            (transient-infix-set obj (transient-infix-read obj)))
-          (transient--show))))
-
-(defun transient--ensure-infix-command (obj)
-  (let ((cmd (oref obj command)))
-    (unless (or (commandp cmd)
-                (get cmd 'transient--infix-command))
-      (if (or (cl-typep obj 'transient-switch)
-              (cl-typep obj 'transient-option))
-          (put cmd 'transient--infix-command
-               (transient--default-infix-command))
-        ;; This is not an anonymous infix argument.
-        (when (transient--use-suffix-p obj)
-          (error "Suffix %s is not defined or autoloaded as a command" 
cmd))))))
-
 (defun transient--derive-shortarg (arg)
   (save-match-data
     (and (string-match "\\`\\(-[a-zA-Z]\\)\\(\\'\\|=\\)" arg)
@@ -1420,11 +1421,11 @@ Each suffix commands is associated with an object, 
which holds
 additional information about the suffix, such as its value (in
 the case of an infix command, which is a kind of suffix command).
 
-This function is intended to be called by infix commands, whose
-command definition usually (at least when defined using
-`transient-define-infix') is this:
+This function is intended to be called by infix commands, which
+are usually aliases of `transient--default-infix-command', which
+is defined like this:
 
-   (lambda ()
+   (defun transient--default-infix-command ()
      (interactive)
      (let ((obj (transient-suffix-object)))
        (transient-infix-set obj (transient-infix-read obj)))
@@ -1441,7 +1442,7 @@ commands) may also need the object to guide their 
behavior.
 This function attempts to return the object associated with the
 current suffix command even if the suffix command was not invoked
 from a transient.  (For some suffix command that is a valid thing
-to do, for others it is not.)  In that case nil may be returned
+to do, for others it is not.)  In that case nil may be returned,
 if the command was not defined using one of the macros intended
 to define such commands.
 
@@ -1457,7 +1458,7 @@ probably use this instead:
       (let ((suffixes
              (cl-remove-if-not
               (lambda (obj)
-                (eq (transient--suffix-command obj)
+                (eq (oref obj command)
                     (or command
                         (if (eq this-command 'transient-set-level)
                             ;; This is how it can look up for which
@@ -1480,38 +1481,6 @@ probably use this instead:
       (transient-init-value obj)
       obj)))
 
-(defun transient--suffix-command (object)
-  "Return the command represented by OBJECT.
-
-If the value of OBJECT's `command' slot is a command, then return
-that.  Otherwise it is a symbol whose `transient--infix-command'
-property holds an anonymous command, which is returned instead."
-  (cl-check-type object transient-suffix)
-  (let ((sym (oref object command)))
-    (if (commandp sym)
-        sym
-      (get sym 'transient--infix-command))))
-
-(defun transient--suffix-symbol (arg)
-  "Return a symbol representing ARG.
-
-ARG must be a command and/or a symbol.  If it is a symbol,
-then just return it.  Otherwise return the symbol whose
-`transient--infix-command' property's value is ARG."
-  (or (cl-typep arg 'command)
-      (cl-typep arg 'symbol)
-      (signal 'wrong-type-argument `((command symbol) ,arg)))
-  (if (symbolp arg)
-      arg
-    (let* ((obj (transient-suffix-object))
-           (sym (oref obj command)))
-      (if (eq (get sym 'transient--infix-command) arg)
-          sym
-        (catch 'found
-          (mapatoms (lambda (sym)
-                      (when (eq (get sym 'transient--infix-command) arg)
-                        (throw 'found sym)))))))))
-
 ;;; Keymaps
 
 (defvar-keymap transient-base-map
@@ -1709,7 +1678,7 @@ of the corresponding object."
                       (funcall transient-substitute-key-function obj)))
           (oset obj key key))
         (let ((kbd (kbd key))
-              (cmd (transient--suffix-command obj)))
+              (cmd (oref obj command)))
           (when-let ((conflict (and transient-detect-key-conflicts
                                     (transient--lookup-key map kbd))))
             (unless (eq cmd conflict)
@@ -1737,13 +1706,12 @@ of the corresponding object."
       (keymap-set map "<handle-switch-frame>" #'transient--do-suspend))
     (dolist (obj transient--suffixes)
       (let* ((cmd (oref obj command))
-             (sub-prefix (and (symbolp cmd) (get cmd 'transient--prefix) t))
-             (sym (transient--suffix-symbol cmd)))
+             (sub-prefix (and (symbolp cmd) (get cmd 'transient--prefix) t)))
         (cond
          ((oref obj inapt)
-          (define-key map (vector sym) #'transient--do-warn-inapt))
+          (define-key map (vector cmd) #'transient--do-warn-inapt))
          ((slot-boundp obj 'transient)
-          (define-key map (vector sym)
+          (define-key map (vector cmd)
             (let ((do (oref obj transient)))
               (pcase (list do sub-prefix)
                 ('(t     t) #'transient--do-recurse)
@@ -1753,8 +1721,8 @@ of the corresponding object."
                 ('(nil   t) #'transient--do-replace)
                 ('(nil nil) #'transient--do-exit)
                 (_          do)))))
-         ((not (lookup-key transient-predicate-map (vector sym)))
-          (define-key map (vector sym)
+         ((not (lookup-key transient-predicate-map (vector cmd)))
+          (define-key map (vector cmd)
             (if sub-prefix
                 #'transient--do-replace
               (or (oref transient--prefix transient-suffix)
@@ -1904,21 +1872,28 @@ value.  Otherwise return CHILDREN as is."
 (defun transient--init-suffix (levels spec)
   (pcase-let* ((`(,level ,class ,args) spec)
                (cmd (plist-get args :command))
-               (level (or (alist-get (transient--suffix-symbol cmd) levels)
-                          level)))
+               (level (or (alist-get cmd levels) level)))
     (let ((fn (and (symbolp cmd)
                    (symbol-function cmd))))
       (when (autoloadp fn)
         (transient--debug "   autoload %s" cmd)
         (autoload-do-load fn)))
     (when (transient--use-level-p level)
-      (let ((obj (if-let ((proto (and cmd
-                                      (symbolp cmd)
-                                      (get cmd 'transient--suffix))))
+      (unless (and cmd (symbolp cmd))
+        (error "BUG: Non-symbolic suffix command: %s" cmd))
+      (let ((obj (if-let ((proto (get cmd 'transient--suffix)))
                      (apply #'clone proto :level level args)
-                   (apply class :level level args))))
+                   (apply class :command cmd :level level args))))
+        (cond ((commandp cmd))
+              ((or (cl-typep obj 'transient-switch)
+                   (cl-typep obj 'transient-option))
+               ;; As a temporary special case, if the package was compiled
+               ;; with an older version of Transient, then we must define
+               ;; "anonymous" switch and option commands here.
+               (defalias cmd #'transient--default-infix-command))
+              ((transient--use-suffix-p obj)
+               (error "Suffix command %s is not defined or autoloaded" cmd)))
         (transient--init-suffix-key obj)
-        (transient--ensure-infix-command obj)
         (when (transient--use-suffix-p obj)
           (if (transient--inapt-suffix-p obj)
               (oset obj inapt t)
@@ -2074,8 +2049,7 @@ value.  Otherwise return CHILDREN as is."
 
 (defun transient--get-predicate-for (cmd &optional suffix-only)
   (or (ignore-errors
-        (lookup-key transient--predicate-map
-                    (vector (transient--suffix-symbol cmd))))
+        (lookup-key transient--predicate-map (vector cmd)))
       (and (not suffix-only)
            (let ((pred (oref transient--prefix transient-non-suffix)))
              (pcase pred
@@ -2189,36 +2163,65 @@ value.  Otherwise return CHILDREN as is."
        ,@body)))
 
 (defun transient--wrap-command ()
+  (if (>= emacs-major-version 30)
+      (transient--wrap-command-30)
+    (transient--wrap-command-29)))
+
+(defun transient--wrap-command-30 ()
+  (letrec
+      ((prefix transient--prefix)
+       (suffix this-command)
+       (advice (lambda (fn &rest args)
+                 (interactive
+                  (lambda (spec)
+                    (let ((abort t))
+                      (unwind-protect
+                         (prog1 (advice-eval-interactive-spec spec)
+                           (setq abort nil))
+                       (when abort
+                          (when-let ((unwind (oref prefix unwind-suffix)))
+                            (transient--debug 'unwind-interactive)
+                            (funcall unwind suffix))
+                          (advice-remove suffix advice)
+                          (oset prefix unwind-suffix nil))))))
+                 (unwind-protect
+                     (apply fn args)
+                   (when-let ((unwind (oref prefix unwind-suffix)))
+                     (transient--debug 'unwind-command)
+                     (funcall unwind suffix))
+                   (advice-remove suffix advice)
+                   (oset prefix unwind-suffix nil)))))
+    (advice-add suffix :around advice '((depth . -99)))))
+
+(defun transient--wrap-command-29 ()
   (let* ((prefix transient--prefix)
-         (suffix this-command))
-    (letrec ((advice
-              (lambda (fn &rest args)
-                (interactive
-                 (lambda (spec)
-                   (let ((abort t))
-                     (unwind-protect
-                        (prog1 (advice-eval-interactive-spec spec)
-                          (setq abort nil))
-                      (when abort
-                        (when-let ((unwind (oref prefix unwind-suffix)))
-                          (transient--debug 'unwind-interactive)
-                          (funcall unwind suffix))
-                        (if (symbolp suffix)
-                            (advice-remove suffix advice)
-                          (remove-function suffix advice))
-                        (oset prefix unwind-suffix nil))))))
-                (unwind-protect
-                    (apply fn args)
+         (suffix this-command)
+         (advice nil)
+         (advice-interactive
+          (lambda (spec)
+            (let ((abort t))
+              (unwind-protect
+                 (prog1 (advice-eval-interactive-spec spec)
+                   (setq abort nil))
+               (when abort
                   (when-let ((unwind (oref prefix unwind-suffix)))
-                    (transient--debug 'unwind-command)
+                    (transient--debug 'unwind-interactive)
                     (funcall unwind suffix))
-                  (if (symbolp suffix)
-                      (advice-remove suffix advice)
-                    (remove-function suffix advice))
-                  (oset prefix unwind-suffix nil)))))
-      (if (symbolp suffix)
-          (advice-add suffix :around advice '((depth . -99)))
-        (add-function :around (var suffix) advice '((depth . -99)))))))
+                  (advice-remove suffix advice)
+                  (oset prefix unwind-suffix nil))))))
+         (advice-body
+          (lambda (fn &rest args)
+            (unwind-protect
+                (apply fn args)
+              (when-let ((unwind (oref prefix unwind-suffix)))
+                (transient--debug 'unwind-command)
+                (funcall unwind suffix))
+              (advice-remove suffix advice)
+              (oset prefix unwind-suffix nil)))))
+    (setq advice `(lambda (fn &rest args)
+                    (interactive ,advice-interactive)
+                    (apply ',advice-body fn args)))
+    (advice-add suffix :around advice '((depth . -99)))))
 
 (defun transient--premature-post-command ()
   (and (equal (this-command-keys-vector) [])
@@ -2339,7 +2342,7 @@ value.  Otherwise return CHILDREN as is."
       (if (symbolp arg)
           (message "-- %-22s (cmd: %s, event: %S, exit: %s%s)"
                    arg
-                   (or (ignore-errors (transient--suffix-symbol this-command))
+                   (or (and (symbolp this-command) this-command)
                        (if (byte-code-function-p this-command)
                            "#[...]"
                          this-command))
@@ -2522,12 +2525,9 @@ prefix argument and pivot to `transient-update'."
            (propertize "?"   'face 'transient-key)
            ;; `this-command' is `transient-undefined' or `transient-inapt'.
            ;; Show the command (`this-original-command') the user actually
-           ;; tried to invoke.  For an anonymous inapt command that is a
-           ;; lambda expression, which cannot be mapped to a symbol, so
-           ;; forgo displaying the command.
-           (if-let ((cmd (ignore-errors
-                           (symbol-name (transient--suffix-symbol
-                                         this-original-command)))))
+           ;; tried to invoke.
+           (if-let ((cmd (or (ignore-errors (symbol-name 
this-original-command))
+                             (ignore-errors (symbol-name this-command)))))
                (format " [%s]" (propertize cmd 'face 'font-lock-warning-face))
              ""))
   (unless (and transient--transient-map
@@ -2617,8 +2617,7 @@ transient is active."
                                (transient-suffix-object command)))
                           (transient--show)
                           (transient--read-number-N
-                           (format "Set level for `%s': "
-                                   (transient--suffix-symbol command))
+                           (format "Set level for `%s': " command)
                            nil nil (not (eq command prefix)))))))))))
   (cond
    ((not command)
@@ -2627,7 +2626,7 @@ transient is active."
    (level
     (let* ((prefix (oref transient--prefix command))
            (alist (alist-get prefix transient-levels))
-           (sym (transient--suffix-symbol command)))
+           (sym command))
       (if (eq command prefix)
           (progn (oset transient--prefix level level)
                  (setq sym t))
@@ -3459,7 +3458,7 @@ Optional support for popup buttons is also implemented 
here."
     (if transient-enable-popup-navigation
         (make-text-button str nil
                           'type 'transient
-                          'command (transient--suffix-command obj))
+                          'command (oref obj command))
       str)))
 
 (cl-defmethod transient-format ((obj transient-infix))
@@ -3659,7 +3658,7 @@ that, else its name.
 
 Intended to be temporarily used as the `:suffix-description' of
 a prefix command, while porting a regular keymap to a transient."
-  (let ((command (transient--suffix-symbol (oref obj command))))
+  (let ((command (oref obj command)))
     (if-let ((doc (documentation command)))
         (propertize (car (split-string doc "\n")) 'face 'font-lock-doc-face)
       (propertize (symbol-name command) 'face 'font-lock-function-name-face))))
@@ -3687,7 +3686,7 @@ prefix method."
   (cond
    ((eq this-command 'transient-help)
     (transient-show-help transient--prefix))
-   ((let ((prefix (get (transient--suffix-command obj)
+   ((let ((prefix (get (oref obj command)
                        'transient--prefix)))
       (and prefix (not (eq (oref transient--prefix command) this-command))
            (prog1 t (transient-show-help prefix)))))
diff --git a/lisp/vc/cvs-status.el b/lisp/vc/cvs-status.el
index 7982cd89efc..7532a059d3b 100644
--- a/lisp/vc/cvs-status.el
+++ b/lisp/vc/cvs-status.el
@@ -352,10 +352,8 @@ the list is a three-string list TAG, KIND, REV."
        (delete-region pt (point)))
       tags)))
 
-(defvar font-lock-mode)
 ;; (defun cvs-refontify (beg end)
-;;   (when (and font-lock-mode
-;;             (fboundp 'font-lock-fontify-region))
+;;   (when font-lock-mode
 ;;     (font-lock-fontify-region (1- beg) (1+ end))))
 
 (defun cvs-status-trees ()
diff --git a/lisp/vc/diff.el b/lisp/vc/diff.el
index 90c43d111f5..a411d98da31 100644
--- a/lisp/vc/diff.el
+++ b/lisp/vc/diff.el
@@ -165,7 +165,7 @@ returns the buffer used."
   (unless (bufferp new) (setq new (expand-file-name new)))
   (unless (bufferp old) (setq old (expand-file-name old)))
   (or switches (setq switches diff-switches)) ; If not specified, use default.
-  (unless (listp switches) (setq switches (list switches)))
+  (setq switches (ensure-list switches))
   (or buf (setq buf (get-buffer-create "*Diff*")))
   (diff-check-labels)
   (let* ((old-alt (diff-file-local-copy old))
diff --git a/lisp/vc/ediff-util.el b/lisp/vc/ediff-util.el
index 8011d7ce2e0..c4ebe20d7e4 100644
--- a/lisp/vc/ediff-util.el
+++ b/lisp/vc/ediff-util.el
@@ -3741,7 +3741,7 @@ Ediff Control Panel to restore highlighting."
 ;; these buffers).
 ;; EXCL-BUFF-LIST is an exclusion list.
 (defun ediff-other-buffer (excl-buff-lst)
-  (or (listp excl-buff-lst) (setq excl-buff-lst (list excl-buff-lst)))
+  (setq excl-buff-lst (ensure-list excl-buff-lst))
   (let* ((all-buffers (nconc (ediff-get-selected-buffers) (buffer-list)))
         ;; we compute this the second time because we need to do memq on it
         ;; later, and nconc above will break it. Either this or use slow
diff --git a/lisp/vc/smerge-mode.el b/lisp/vc/smerge-mode.el
index c39a9cc2f22..7847a6c7670 100644
--- a/lisp/vc/smerge-mode.el
+++ b/lisp/vc/smerge-mode.el
@@ -255,10 +255,6 @@ Can be nil if the style is undecided, or else:
 - `diff3-E'
 - `diff3-A'")
 
-;; Compiler pacifiers
-(defvar font-lock-mode)
-(defvar font-lock-keywords)
-
 ;;;;
 ;;;; Actual code
 ;;;;
diff --git a/lisp/vc/vc-dir.el b/lisp/vc/vc-dir.el
index 53d58870b32..d5226910211 100644
--- a/lisp/vc/vc-dir.el
+++ b/lisp/vc/vc-dir.el
@@ -785,8 +785,7 @@ MARK-FILES should be a list of absolute filenames."
 
 (defun vc-dir-mark-state-files (states)
   "Mark files that are in the state specified by the list in STATES."
-  (unless (listp states)
-    (setq states (list states)))
+  (setq states (ensure-list states))
   (ewoc-map
    (lambda (filearg)
      (when (memq (vc-dir-fileinfo->state filearg) states)
diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el
index a7763360795..c689eec444b 100644
--- a/lisp/vc/vc-git.el
+++ b/lisp/vc/vc-git.el
@@ -1631,7 +1631,6 @@ This requires git 1.8.4 or later, for the \"-L\" option 
of \"git log\"."
     map))
 
 (defvar vc-git--log-view-long-font-lock-keywords nil)
-(defvar font-lock-keywords)
 (defvar vc-git-region-history-font-lock-keywords
   '((vc-git-region-history-font-lock)))
 
diff --git a/lisp/vc/vc-hg.el b/lisp/vc/vc-hg.el
index 182d76882bb..b62420393aa 100644
--- a/lisp/vc/vc-hg.el
+++ b/lisp/vc/vc-hg.el
@@ -497,7 +497,6 @@ This requires hg 4.4 or later, for the \"-L\" option of 
\"hg log\"."
     map))
 
 (defvar vc-hg--log-view-long-font-lock-keywords nil)
-(defvar font-lock-keywords)
 (defvar vc-hg-region-history-font-lock-keywords
   '((vc-hg-region-history-font-lock)))
 
diff --git a/lisp/wid-edit.el b/lisp/wid-edit.el
index a70598bb6c9..ae060c92d0e 100644
--- a/lisp/wid-edit.el
+++ b/lisp/wid-edit.el
@@ -644,8 +644,7 @@ Return a list whose car contains all members of VALS that 
matched WIDGET."
 (defun widget-prompt-value (widget prompt &optional value unbound)
   "Prompt for a value matching WIDGET, using PROMPT.
 The current value is assumed to be VALUE, unless UNBOUND is non-nil."
-  (unless (listp widget)
-    (setq widget (list widget)))
+  (setq widget (ensure-list widget))
   (setq prompt (format "[%s] %s" (widget-type widget) prompt))
   (setq widget (widget-convert widget))
   (let ((answer (widget-apply widget :prompt-value prompt value unbound)))
diff --git a/lisp/windmove.el b/lisp/windmove.el
index 746a440bacb..96b8597ae09 100644
--- a/lisp/windmove.el
+++ b/lisp/windmove.el
@@ -485,7 +485,7 @@ Default value of MODIFIERS is `shift'."
   (interactive)
   (unless modifiers (setq modifiers 'shift))
   (when (eq modifiers 'none) (setq modifiers nil))
-  (unless (listp modifiers) (setq modifiers (list modifiers)))
+  (setq modifiers (ensure-list modifiers))
   (windmove-install-defaults nil modifiers
                              '((windmove-left left)
                                (windmove-right right)
@@ -626,7 +626,7 @@ Default value of MODIFIERS is `shift-meta'."
   (interactive)
   (unless modifiers (setq modifiers '(shift meta)))
   (when (eq modifiers 'none) (setq modifiers nil))
-  (unless (listp modifiers) (setq modifiers (list modifiers)))
+  (setq modifiers (ensure-list modifiers))
   (windmove-install-defaults nil modifiers
                              '((windmove-display-left left)
                                (windmove-display-right right)
@@ -703,10 +703,10 @@ Default value of PREFIX is \\`C-x' and MODIFIERS is 
`shift'."
   (interactive)
   (unless prefix (setq prefix '(?\C-x)))
   (when (eq prefix 'none) (setq prefix nil))
-  (unless (listp prefix) (setq prefix (list prefix)))
+  (setq prefix (ensure-list prefix))
   (unless modifiers (setq modifiers '(shift)))
   (when (eq modifiers 'none) (setq modifiers nil))
-  (unless (listp modifiers) (setq modifiers (list modifiers)))
+  (setq modifiers (ensure-list modifiers))
   (windmove-install-defaults prefix modifiers
                              '((windmove-delete-left left)
                                (windmove-delete-right right)
@@ -766,7 +766,7 @@ Default value of MODIFIERS is `shift-super'."
   (interactive)
   (unless modifiers (setq modifiers '(shift super)))
   (when (eq modifiers 'none) (setq modifiers nil))
-  (unless (listp modifiers) (setq modifiers (list modifiers)))
+  (setq modifiers (ensure-list modifiers))
   (windmove-install-defaults nil modifiers
                              '((windmove-swap-states-left left)
                                (windmove-swap-states-right right)
diff --git a/lisp/window.el b/lisp/window.el
index b0970cfb064..b9b032c33e9 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -7990,8 +7990,7 @@ indirectly called by the latter."
                           buffer-mode))
          (curwin (selected-window))
          (curframe (selected-frame)))
-    (unless (listp allowed-modes)
-      (setq allowed-modes (list allowed-modes)))
+    (setq allowed-modes (ensure-list allowed-modes))
     (let (same-mode-same-frame
           same-mode-other-frame
           derived-mode-same-frame
diff --git a/lisp/woman.el b/lisp/woman.el
index e4e3d176d08..e20a2399c00 100644
--- a/lisp/woman.el
+++ b/lisp/woman.el
@@ -1338,8 +1338,8 @@ PATH-DIRS should be a list of general manual directories 
(like
 manual directory regexps (like `woman-path').
 Ignore any paths that are unreadable or not directories."
   ;; Allow each path to be a single string or a list of strings:
-  (if (not (listp path-dirs)) (setq path-dirs (list path-dirs)))
-  (if (not (listp path-regexps)) (setq path-regexps (list path-regexps)))
+  (setq path-dirs (ensure-list path-dirs))
+  (setq path-regexps (ensure-list path-regexps))
   (let (head dirs path)
     (dolist (dir path-dirs)
       (when (consp dir)
@@ -2081,8 +2081,6 @@ European characters."
 
 ;;; The main decoding driver:
 
-(defvar font-lock-mode)                        ; for the compiler
-
 (defun woman-decode-buffer ()
   "Decode a buffer in UN*X man-page source format.
 No external programs are used."
diff --git a/src/emacs.c b/src/emacs.c
index de553f31980..8c55edb214b 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -1291,7 +1291,7 @@ main (int argc, char **argv)
      for pointers.  */
   void *stack_bottom_variable;
   int old_argc;
-#if !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
+#if defined HAVE_PDUMPER && !(defined HAVE_ANDROID && !defined ANDROID_STUBIFY)
   char *dump_file;
 
   /* This is just a dummy argument used to avoid extra defines.  */
diff --git a/src/fileio.c b/src/fileio.c
index 51e3e8849d1..23e1a83d8bf 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -2518,8 +2518,8 @@ permissions.  */)
       ts[1] = get_stat_mtime (&st);
       if (futimens (ofd, ts) != 0
          /* Various versions of the Android C library are missing
-            futimens, which leads a gnulib fallback to be installed
-            that uses fdutimens instead.  However, fdutimens is not
+            futimens, prompting Gnulib to install a fallback that
+            uses fdutimens instead.  However, fdutimens is not
             supported on many Android kernels, so just silently fail
             if errno is ENOTSUP or ENOSYS.  */
 #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
diff --git a/src/frame.c b/src/frame.c
index 4be9f06bd3c..38ac316ce87 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -2212,12 +2212,15 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
        }
 #ifdef NS_IMPL_COCOA
       else
-       /* Under NS, there is no system mechanism for choosing a new
-          window to get focus -- it is left to application code.
-          So the portion of THIS application interfacing with NS
-          needs to know about it.  We call Fraise_frame, but the
-          purpose is really to transfer focus.  */
-       Fraise_frame (frame1);
+       {
+         /* Under NS, there is no system mechanism for choosing a new
+            window to get focus -- it is left to application code.
+            So the portion of THIS application interfacing with NS
+            needs to make the frame we switch to the key window.  */
+         struct frame *f1 = XFRAME (frame1);
+         if (FRAME_NS_P (f1))
+           ns_make_frame_key_window (f1);
+       }
 #endif
 
       do_switch_frame (frame1, 0, 1, Qnil);
diff --git a/src/frame.h b/src/frame.h
index c85df378da6..f4726f1c0e5 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -1521,6 +1521,10 @@ extern Lisp_Object mouse_position (bool);
 extern void frame_size_history_plain (struct frame *, Lisp_Object);
 extern void frame_size_history_extra (struct frame *, Lisp_Object,
                                      int, int, int, int, int, int);
+#ifdef NS_IMPL_COCOA
+/* Implemented in nsfns.m.  */
+extern void ns_make_frame_key_window (struct frame *);
+#endif
 extern Lisp_Object Vframe_list;
 
 /* Value is a pointer to the selected frame.  If the selected frame
diff --git a/src/haikuterm.c b/src/haikuterm.c
index 70984936bf9..b1a016b49a9 100644
--- a/src/haikuterm.c
+++ b/src/haikuterm.c
@@ -1219,7 +1219,7 @@ static void
 haiku_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
 {
   struct glyph *glyph = s->first_glyph;
-  unsigned char2b[8];
+  static unsigned char2b[8];
   int x, i, j;
   struct face *face = s->face;
   unsigned long color;
@@ -1399,7 +1399,7 @@ haiku_draw_stretch_glyph_string (struct glyph_string *s)
        }
 
       if (background_width > 0)
-       haiku_draw_background_rect (s, s->face, s->x, s->y,
+       haiku_draw_background_rect (s, s->face, x, s->y,
                                    background_width, s->height);
     }
   s->background_filled_p = 1;
diff --git a/src/image.c b/src/image.c
index 5ac97618742..e4d336331ee 100644
--- a/src/image.c
+++ b/src/image.c
@@ -1336,6 +1336,18 @@ image_error (const char *format, ...)
   va_end (ap);
 }
 
+static void
+image_invalid_data_error (Lisp_Object data)
+{
+  image_error ("Invalid image data `%s'", data);
+}
+
+static void
+image_not_found_error (Lisp_Object filename)
+{
+  image_error ("Cannot find image file `%s'", filename);
+}
+
 static void
 image_size_error (void)
 {
@@ -3840,8 +3852,8 @@ image_create_x_image_and_pixmap_1 (struct frame *f, int 
width, int height, int d
   if (*pixmap == NO_PIXMAP)
     {
       *pimg = NULL;
-      image_error ("Unable to create X pixmap", Qnil, Qnil);
-      return 0;
+      image_error ("Unable to create X pixmap");
+      return false;
     }
 
   *pimg = *pixmap;
@@ -3873,8 +3885,8 @@ image_create_x_image_and_pixmap_1 (struct frame *f, int 
width, int height, int d
   if (*pixmap == NO_PIXMAP)
     {
       *pimg = NULL;
-      image_error ("Unable to create pixmap", Qnil, Qnil);
-      return 0;
+      image_error ("Unable to create pixmap");
+      return false;
     }
 
   *pimg = *pixmap;
@@ -5067,8 +5079,8 @@ xbm_load (struct frame *f, struct image *img)
       Lisp_Object file = image_find_image_fd (file_name, &fd);
       if (!STRINGP (file))
        {
-         image_error ("Cannot find image file `%s'", file_name);
-         return 0;
+         image_not_found_error (file_name);
+         return false;
        }
 
       ptrdiff_t size;
@@ -5719,12 +5731,12 @@ xpm_load (struct frame *f, struct image *img)
       Lisp_Object file = image_find_image_file (specified_file);
       if (!STRINGP (file))
        {
-         image_error ("Cannot find image file `%s'", specified_file);
+         image_not_found_error (specified_file);
 #ifdef ALLOC_XPM_COLORS
          xpm_free_color_cache ();
 #endif
          SAFE_FREE ();
-         return 0;
+         return false;
        }
 
       file = ENCODE_FILE (file);
@@ -5751,7 +5763,7 @@ xpm_load (struct frame *f, struct image *img)
       Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
       if (!STRINGP (buffer))
        {
-         image_error ("Invalid image data `%s'", buffer);
+         image_invalid_data_error (buffer);
 #ifdef ALLOC_XPM_COLORS
          xpm_free_color_cache ();
 #endif
@@ -6363,8 +6375,8 @@ xpm_load (struct frame *f,
       Lisp_Object file = image_find_image_fd (file_name, &fd);
       if (!STRINGP (file))
        {
-         image_error ("Cannot find image file `%s'", file_name);
-         return 0;
+         image_not_found_error (file_name);
+         return false;
        }
 
       ptrdiff_t size;
@@ -6385,8 +6397,8 @@ xpm_load (struct frame *f,
       data = image_spec_value (img->spec, QCdata, NULL);
       if (!STRINGP (data))
        {
-         image_error ("Invalid image data `%s'", data);
-         return 0;
+         image_invalid_data_error (data);
+         return false;
        }
       success_p = xpm_load_image (f, img, SSDATA (data),
                                  SSDATA (data) + SBYTES (data));
@@ -7392,8 +7404,8 @@ pbm_load (struct frame *f, struct image *img)
       Lisp_Object file = image_find_image_fd (specified_file, &fd);
       if (!STRINGP (file))
        {
-         image_error ("Cannot find image file `%s'", specified_file);
-         return 0;
+         image_not_found_error (specified_file);
+         return false;
        }
 
       ptrdiff_t size;
@@ -7413,8 +7425,8 @@ pbm_load (struct frame *f, struct image *img)
       data = image_spec_value (img->spec, QCdata, NULL);
       if (!STRINGP (data))
        {
-         image_error ("Invalid image data `%s'", data);
-         return 0;
+         image_invalid_data_error (data);
+         return false;
        }
       p = SSDATA (data);
       end = p + SBYTES (data);
@@ -8062,8 +8074,8 @@ png_load_body (struct frame *f, struct image *img, struct 
png_load_context *c)
          || (fd = emacs_open (SSDATA (ENCODE_FILE (file)),
                               O_RDONLY, 0)) < 0)
        {
-         image_error ("Cannot find image file `%s'", specified_file);
-         return 0;
+         image_not_found_error (specified_file);
+         return false;
        }
 
       /* Open the image file.  */
@@ -8087,8 +8099,8 @@ png_load_body (struct frame *f, struct image *img, struct 
png_load_context *c)
     {
       if (!STRINGP (specified_data))
        {
-         image_error ("Invalid image data `%s'", specified_data);
-         return 0;
+         image_invalid_data_error (specified_data);
+         return false;
        }
 
       /* Read from memory.  */
@@ -8791,8 +8803,8 @@ jpeg_load_body (struct frame *f, struct image *img,
          || (fd = emacs_open (SSDATA (ENCODE_FILE (file)),
                               O_RDONLY, 0)) < 0)
        {
-         image_error ("Cannot find image file `%s'", specified_file);
-         return 0;
+         image_not_found_error (specified_file);
+         return false;
        }
 
       fp = emacs_fdopen (fd, "rb");
@@ -8804,8 +8816,8 @@ jpeg_load_body (struct frame *f, struct image *img,
     }
   else if (!STRINGP (specified_data))
     {
-      image_error ("Invalid image data `%s'", specified_data);
-      return 0;
+      image_invalid_data_error (specified_data);
+      return false;
     }
 
   /* Customize libjpeg's error handling to call my_error_exit when an
@@ -9246,8 +9258,8 @@ tiff_load (struct frame *f, struct image *img)
       Lisp_Object file = image_find_image_file (specified_file);
       if (!STRINGP (file))
        {
-         image_error ("Cannot find image file `%s'", specified_file);
-         return 0;
+         image_not_found_error (specified_file);
+         return false;
        }
 
       Lisp_Object encoded_file = ENCODE_FILE (file);
@@ -9267,8 +9279,8 @@ tiff_load (struct frame *f, struct image *img)
     {
       if (!STRINGP (specified_data))
        {
-         image_error ("Invalid image data `%s'", specified_data);
-         return 0;
+         image_invalid_data_error (specified_data);
+         return false;
        }
 
       /* Memory source! */
@@ -9675,7 +9687,7 @@ gif_load (struct frame *f, struct image *img)
          Lisp_Object file = image_find_image_file (specified_file);
          if (!STRINGP (file))
            {
-             image_error ("Cannot find image file `%s'", specified_file);
+             image_not_found_error (specified_file);
              return false;
            }
 
@@ -9720,7 +9732,7 @@ gif_load (struct frame *f, struct image *img)
        {
          if (!STRINGP (specified_data))
            {
-             image_error ("Invalid image data `%s'", specified_data);
+             image_invalid_data_error (specified_data);
              return false;
            }
 
@@ -10296,7 +10308,7 @@ webp_load (struct frame *f, struct image *img)
       file = image_find_image_fd (specified_file, &fd);
       if (!STRINGP (file))
        {
-         image_error ("Cannot find image file `%s'", specified_file);
+         image_not_found_error (specified_file);
          return false;
        }
 
@@ -10311,7 +10323,7 @@ webp_load (struct frame *f, struct image *img)
     {
       if (!STRINGP (specified_data))
        {
-         image_error ("Invalid image data `%s'", specified_data);
+         image_invalid_data_error (specified_data);
          return false;
        }
       contents = SDATA (specified_data);
@@ -10452,22 +10464,36 @@ webp_load (struct frame *f, struct image *img)
     }
 
   /* Create the x image and pixmap.  */
-  Emacs_Pix_Container ximg, mask_img = NULL;
+  Emacs_Pix_Container ximg;
   if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 
false))
     goto webp_error2;
 
-  /* Create an image and pixmap serving as mask if the WebP image
-     contains an alpha channel.  */
-  if (features.has_alpha
-      && !image_create_x_image_and_pixmap (f, img, width, height, 1,
-                                          &mask_img, true))
+  /* Find the background to use if the WebP image contains an alpha
+     channel.  */
+  Emacs_Color bg_color;
+  if (features.has_alpha)
     {
-      image_destroy_x_image (ximg);
-      image_clear_image_1 (f, img, CLEAR_IMAGE_PIXMAP);
-      goto webp_error2;
+      Lisp_Object specified_bg
+       = image_spec_value (img->spec, QCbackground, NULL);
+
+      /* If the user specified a color, try to use it; if not, use the
+        current frame background, ignoring any default background
+        color set by the image.  */
+      if (STRINGP (specified_bg))
+       FRAME_TERMINAL (f)->defined_color_hook (f,
+                                               SSDATA (specified_bg),
+                                               &bg_color,
+                                               false,
+                                               false);
+      else
+       FRAME_TERMINAL (f)->query_frame_background_color (f, &bg_color);
+      bg_color.red   >>= 8;
+      bg_color.green >>= 8;
+      bg_color.blue  >>= 8;
     }
 
-  /* Fill the X image and mask from WebP data.  */
+  /* Fill the X image from WebP data.  */
+
   init_color_table ();
 
   img->corners[TOP_CORNER] = 0;
@@ -10482,21 +10508,24 @@ webp_load (struct frame *f, struct image *img)
     {
       for (int x = 0; x < width; ++x)
        {
-         int r = *p++ << 8;
-         int g = *p++ << 8;
-         int b = *p++ << 8;
-         PUT_PIXEL (ximg, x, y, lookup_rgb_color (f, r, g, b));
-
-         /* An alpha channel associates variable transparency with an
-            image.  WebP allows up to 256 levels of partial transparency.
-            We handle this like with PNG (which see), using the frame's
-            background color to combine the image with.  */
+         int r, g, b;
+         /* The WebP alpha channel allows 256 levels of partial
+            transparency.  Blend it with the background manually.  */
          if (features.has_alpha || anim)
            {
-             if (mask_img)
-               PUT_PIXEL (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW : 
PIX_MASK_RETAIN);
-             ++p;
+             float a = (float) p[3] / UINT8_MAX;
+             r = (int)(a * p[0] + (1 - a) * bg_color.red)   << 8;
+             g = (int)(a * p[1] + (1 - a) * bg_color.green) << 8;
+             b = (int)(a * p[2] + (1 - a) * bg_color.blue)  << 8;
+             p += 4;
+           }
+         else
+           {
+             r = *p++ << 8;
+             g = *p++ << 8;
+             b = *p++ << 8;
            }
+         PUT_PIXEL (ximg, x, y, lookup_rgb_color (f, r, g, b));
        }
     }
 
@@ -10509,16 +10538,6 @@ webp_load (struct frame *f, struct image *img)
   /* Put ximg into the image.  */
   image_put_x_image (f, img, ximg, 0);
 
-  /* Same for the mask.  */
-  if (mask_img)
-    {
-      /* Fill in the background_transparent field while we have the
-        mask handy.  Casting avoids a GCC warning.  */
-      image_background_transparent (img, f, (Emacs_Pix_Context)mask_img);
-
-      image_put_x_image (f, img, mask_img, 1);
-    }
-
   img->width = width;
   img->height = height;
 
@@ -11313,8 +11332,8 @@ imagemagick_load (struct frame *f, struct image *img)
       Lisp_Object file = image_find_image_file (file_name);
       if (!STRINGP (file))
        {
-         image_error ("Cannot find image file `%s'", file_name);
-         return 0;
+         image_not_found_error (file_name);
+         return false;
        }
       file = ENCODE_FILE (file);
 #ifdef WINDOWSNT
@@ -11331,8 +11350,8 @@ imagemagick_load (struct frame *f, struct image *img)
       data = image_spec_value (img->spec, QCdata, NULL);
       if (!STRINGP (data))
        {
-         image_error ("Invalid image data `%s'", data);
-         return 0;
+         image_invalid_data_error (data);
+         return false;
        }
       success_p = imagemagick_load_image (f, img, SDATA (data),
                                           SBYTES (data), NULL);
@@ -11695,8 +11714,8 @@ svg_load (struct frame *f, struct image *img)
       Lisp_Object file = image_find_image_fd (file_name, &fd);
       if (!STRINGP (file))
        {
-         image_error ("Cannot find image file `%s'", file_name);
-         return 0;
+         image_not_found_error (file_name);
+         return false;
        }
 
       /* Read the entire file into memory.  */
@@ -11723,8 +11742,8 @@ svg_load (struct frame *f, struct image *img)
       data = image_spec_value (img->spec, QCdata, NULL);
       if (!STRINGP (data))
        {
-         image_error ("Invalid image data `%s'", data);
-         return 0;
+         image_invalid_data_error (data);
+         return false;
        }
       if (!STRINGP (base_uri))
         base_uri = BVAR (current_buffer, filename);
diff --git a/src/keyboard.c b/src/keyboard.c
index 78c88a2859b..6ab1cdebc12 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -4833,7 +4833,8 @@ The value when Emacs is idle is a Lisp timestamp in the 
style of
 
 The value when Emacs is not idle is nil.
 
-PSEC is a multiple of the system clock resolution.  */)
+If the value is a list of four integers (HIGH LOW USEC PSEC), then PSEC
+is a multiple of the system clock resolution.  */)
   (void)
 {
   if (timespec_valid_p (timer_idleness_start_time))
diff --git a/src/nsfns.m b/src/nsfns.m
index b846b490ff7..a79892f73b6 100644
--- a/src/nsfns.m
+++ b/src/nsfns.m
@@ -685,6 +685,12 @@ ns_change_tab_bar_height (struct frame *f, int height)
   SET_FRAME_GARBAGED (f);
 }
 
+void
+ns_make_frame_key_window (struct frame *f)
+{
+  [[FRAME_NS_VIEW (f) window] makeKeyWindow];
+}
+
 /* tabbar support */
 static void
 ns_set_tab_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
diff --git a/src/xterm.c b/src/xterm.c
index 6a1642ff56e..d826eec2419 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -20198,15 +20198,24 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #ifdef HAVE_XKB
              int overflow;
              unsigned int consumed;
+             KeySym sym;
 
              if (dpyinfo->xkb_desc)
                {
+                 /* Translate the keycode into the keysym it
+                    represents, using STATE.  CONSUMED is set to the
+                    modifier bits consumed while undertaking this
+                    translation and should be subsequently ignored
+                    during keysym translation.  */
+
                  if (!XkbTranslateKeyCode (dpyinfo->xkb_desc,
                                            xkey.keycode, xkey.state,
                                            &consumed, &keysym))
                    goto done_keysym;
 
-                 overflow = 0;
+                 /* Save the original keysym in case
+                    XkbTranslateKeysym overflows.  */
+                 sym = keysym, overflow = 0;
 
                  nbytes = XkbTranslateKeySym (dpyinfo->display, &keysym,
                                               xkey.state & ~consumed,
@@ -20218,7 +20227,11 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                      copy_bufptr = SAFE_ALLOCA ((copy_bufsiz += overflow)
                                                 * sizeof *copy_bufptr);
                      overflow = 0;
-                     nbytes = XkbTranslateKeySym (dpyinfo->display, &keysym,
+
+                     /* Use the original keysym derived from the
+                        keycode translation in this second call to
+                        XkbTranslateKeysym.  */
+                     nbytes = XkbTranslateKeySym (dpyinfo->display, &sym,
                                                   xkey.state & ~consumed,
                                                   (char *) copy_bufptr,
                                                   copy_bufsiz, &overflow);
@@ -23725,7 +23738,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              Lisp_Object c;
 #ifdef HAVE_XKB
              unsigned int mods_rtrn;
-#endif
+#endif /* HAVE_XKB */
              int keycode = xev->detail;
              KeySym keysym;
              char copy_buffer[81];
@@ -23734,15 +23747,123 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              ptrdiff_t i;
              unsigned int old_state;
              struct xi_device_t *device, *source;
+             XKeyPressedEvent xkey;
 
              coding = Qlatin_1;
 
+             /* The code under this label is quite desultory.  There
+                are also several important discrepancies with the
+                core KeyPress code to mind.
+
+                There are three principal objectives:
+
+                The first is to produce a core or GDK translation of
+                this XI_KeyPress event, which is relayed to the
+                toolkit.  This transpires by setting `copy' to a
+                close copy of XEV, which is later copied or
+                dispatched to the toolkit by the code beneath the
+                OTHER label.
+
+                The second objective is to filter the event through
+                an input method, by generating a second copy of the
+                event expressly tailored for such a purpose.  The
+                core KeyPress code does not endeavor to do so;
+                instead, this action is taken prior to calling
+                handle_one_xevent.  Calls to `x_filter_event' or
+                `xg_filter_key' serve to implement this objective.
+
+                If the event is not removed by the input method's
+                filter, the third objective is to establish either a
+                keysym or a sequence of characters to insert, using
+                the information supplied within the key event.
+
+                When an input method connection is available, this
+                responsibility is vested in the hands of the input
+                method -- yet another copy of XEV as a core event is
+                produced, and the input method is responsible for
+                deriving a keysym or text to insert.
+
+                Otherwise, if the XKB extension is available, calls
+                are made to XkbTranslateKeyCode and
+                XkbTranslateKeySym.
+
+                And if all else fails, XEV is transformed into a core
+                event and provided to XLookupString, in a manner
+                analogous to the core event processing under the
+                KeyPress label.
+
+                A wide number of variables are employed during this
+                translation process.  The most pertinent ones are:
+
+                `copy'
+
+                  This variable is defined when an X toolkit
+                  incognizant of input extension events is being
+                  employed.  If a popup is active, Emacs copies
+                  fields of interest from the extension event to
+                  COPY, sets the `use_copy' flag, and jumps to the
+                  XI_OTHER label.  `copy' is then relayed to the
+                  toolkit.
+
+                `xkey'
+
+                  This variable is defined to a copy of the event
+                  used by input methods or XLookupString at various
+                  points during the execution of this label.
+
+                `coding'
+
+                  This variable is consulted at the conclusion of
+                  event generation, and holds the coding system
+                  for any generated string.
+
+                `keysym'
+
+                  This variable is eventually set to the keysym tied
+                  to the event, which may be directly provided within
+                  a generated struct input_event, should it bear a
+                  direct relation to an ASCII or Unicode character,
+                  or if it is a control key.
+
+                `copy_buffer', `copy_bufptr', `copy_bufsiz'
+
+                  These variables hold the buffer that incorporates
+                  characters generated during the keycode-to-keysym
+                  conversion process.
+
+                `nbytes'
+
+                  Holds the number of characters within that buffer,
+                  in bytes.  These characters are encoded using the
+                  coding system in `coding'.
+
+                  If greater than 0 and KEYSYM does not immediately
+                  relate to a function key, control key or character,
+                  it is provided as the string to insert within a
+                  MULTIBYTE_CHAR_KEYSTROKE_EVENT.
+
+                `state'
+
+                  Holds the keyboard and group (but not button)
+                  state.  After event filtering concludes, modifier
+                  bits within `extra_keyboard_modifiers' are also
+                  introduced.
+
+                This illustration may reflect the treatment taken
+                towards core key events to some degree.  */
+
              device = xi_device_from_id (dpyinfo, xev->deviceid);
              source = xi_device_from_id (dpyinfo, xev->sourceid);
 
              if (!device)
                goto XI_OTHER;
 
+             /* Convert the keyboard state within XEV to a core
+                modifier mask, later supplied as arguments to XKB and
+                core functions.  This encompasses the keyboard group
+                and effective modifiers but not the button state.  */
+             state = xi_convert_event_keyboard_state (xev);
+
 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
              /* Dispatch XI_KeyPress events when in menu.  */
              if (popup_activated ())
@@ -23758,7 +23879,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                  copy.xkey.root = xev->root;
                  copy.xkey.subwindow = xev->child;
                  copy.xkey.time = xev->time;
-                 copy.xkey.state = xi_convert_event_keyboard_state (xev);
+                 copy.xkey.state = state;
                  xi_convert_button_state (&xev->buttons, &copy.xkey.state);
 
                  copy.xkey.x = lrint (xev->event_x);
@@ -23767,10 +23888,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                  copy.xkey.y_root = lrint (xev->root_y);
                  copy.xkey.keycode = xev->detail;
                  copy.xkey.same_screen = True;
-#endif
+#endif /* USE_LUCID */
                  goto XI_OTHER;
                }
-#endif
+#endif /* USE_X_TOOLKIT || USE_GTK */
 
              x_display_set_last_user_time (dpyinfo, xev->time,
                                            xev->send_event, true);
@@ -23790,7 +23911,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #ifdef USE_GTK
              if (f)
                x_set_gtk_user_time (f, xev->time);
-#endif
+#endif /* USE_GTK */
 
              if (f)
                {
@@ -23802,7 +23923,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                                           xev->time);
                }
 
-             XKeyPressedEvent xkey;
+             /* Convert the XI event into a core event structure
+                provided to old Xlib functions and input method
+                filter functions.  */
 
              memset (&xkey, 0, sizeof xkey);
 
@@ -23814,8 +23937,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              xkey.root = xev->root;
              xkey.subwindow = xev->child;
              xkey.time = xev->time;
-             xkey.state = xi_convert_event_keyboard_state (xev);
-
+             xkey.state = state;
              xkey.x = lrint (xev->event_x);
              xkey.y = lrint (xev->event_y);
              xkey.x_root = lrint (xev->root_x);
@@ -23844,7 +23966,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                  *finish = X_EVENT_DROP;
                  goto XI_OTHER;
                }
-#else
+#else /* !USE_GTK */
              if (x_filter_event (dpyinfo, (XEvent *) &xkey))
                {
                  /* Try to attribute core key events from the input
@@ -23856,8 +23978,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                  *finish = X_EVENT_DROP;
                  goto XI_OTHER;
                }
-#endif
-#elif USE_GTK
+#endif /* HAVE_X_I18N */
+#elif USE_GTK /* && !HAVE_X_I18N */
              if ((x_gtk_use_native_input
                   || dpyinfo->prefer_native_input)
                  && xg_filter_key (any, event))
@@ -23871,48 +23993,17 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                  *finish = X_EVENT_DROP;
                  goto XI_OTHER;
                }
-#endif
+#endif /* HAVE_X_I18N || USE_GTK */
 
              state |= x_emacs_to_x_modifiers (dpyinfo, 
extra_keyboard_modifiers);
 
-#ifdef HAVE_XKB
-             if (dpyinfo->xkb_desc)
-               {
-                 unsigned int xkb_state;
-
-                 xkb_state = state & ~(1 << 13 | 1 << 14);
-                 xkb_state |= xev->group.effective << 13;
-
-                 if (!XkbTranslateKeyCode (dpyinfo->xkb_desc, keycode,
-                                           xkb_state, &mods_rtrn, &keysym))
-                   goto XI_OTHER;
-               }
-             else
-               {
-#endif
-                 int keysyms_per_keycode_return;
-                 KeySym *ksms = XGetKeyboardMapping (dpyinfo->display, 
keycode, 1,
-                                                     
&keysyms_per_keycode_return);
-                 if (!(keysym = ksms[0]))
-                   {
-                     XFree (ksms);
-                     goto XI_OTHER;
-                   }
-                 XFree (ksms);
-#ifdef HAVE_XKB
-               }
-#endif
-
-             if (keysym == NoSymbol)
-               goto XI_OTHER;
-
              /* If mouse-highlight is an integer, input clears out
                 mouse highlighting.  */
              if (!hlinfo->mouse_face_hidden && FIXNUMP (Vmouse_highlight)
                  && (f == 0
 #if ! defined (USE_GTK)
                      || !EQ (f->tool_bar_window, hlinfo->mouse_face_window)
-#endif
+#endif /* !USE_GTK */
                      || !EQ (f->tab_bar_window, hlinfo->mouse_face_window))
                  )
                {
@@ -23933,7 +24024,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                     dialogs because in that case popup_activated is nonzero
                     (see above).  */
                  *finish = X_EVENT_DROP;
-#endif
+#endif /* USE_GTK */
 
                  XSETFRAME (inev.ie.frame_or_window, f);
                  inev.ie.timestamp = xev->time;
@@ -23970,25 +24061,54 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                        emacs_abort ();
                    }
                  else
-#endif
+#endif /* HAVE_X_I18N */
                    {
 #ifdef HAVE_XKB
-                     int overflow = 0;
-                     KeySym sym = keysym;
-
                      if (dpyinfo->xkb_desc)
                        {
-                         nbytes = XkbTranslateKeySym (dpyinfo->display, &sym,
-                                                      state & ~mods_rtrn, 
copy_bufptr,
-                                                      copy_bufsiz, &overflow);
+                         KeySym sym;
+                         int overflow;
+
+                         /* Translate the keycode into the keysym it
+                            represents, using STATE.  MODS_RTRN is
+                            set to the modifier bits consumed while
+                            undertaking this translation and should
+                            be subsequently ignored during keysym
+                            translation.  */
+
+                         if (!XkbTranslateKeyCode (dpyinfo->xkb_desc,
+                                                   keycode, state,
+                                                   &mods_rtrn, &keysym))
+                           goto xi_done_keysym;
+
+                         /* Save the original keysym in case
+                            XkbTranslateKeySym overflows.  */
+                         sym = keysym, overflow = 0;
+
+                         /* Translate this keysym and its modifier
+                            state into the actual symbol and string
+                            it represents.  */
+                         nbytes = XkbTranslateKeySym (dpyinfo->display,
+                                                      &keysym,
+                                                      state & ~mods_rtrn,
+                                                      copy_bufptr,
+                                                      copy_bufsiz,
+                                                      &overflow);
                          if (overflow)
                            {
-                             copy_bufptr = SAFE_ALLOCA ((copy_bufsiz += 
overflow)
-                                                        * sizeof *copy_bufptr);
+                             copy_bufptr
+                               = SAFE_ALLOCA ((copy_bufsiz += overflow)
+                                              * sizeof *copy_bufptr);
                              overflow = 0;
-                             nbytes = XkbTranslateKeySym (dpyinfo->display, 
&sym,
-                                                          state & ~mods_rtrn, 
copy_bufptr,
-                                                          copy_bufsiz, 
&overflow);
+
+                             /* Use the original keysym derived from
+                                the keycode translation.  */
+                             nbytes = XkbTranslateKeySym (dpyinfo->display,
+                                                          &sym,
+                                                          state & ~mods_rtrn,
+                                                          copy_bufptr,
+                                                          copy_bufsiz,
+                                                          &overflow);
 
                              if (overflow)
                                nbytes = 0;
@@ -23997,8 +24117,14 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                          coding = Qnil;
                        }
                      else
-#endif
+#endif /* HAVE_XKB */
                        {
+                         /* Save the state within XKEY, then remove
+                            all modifier keys Emacs understands from
+                            it, forestalling any attempt by
+                            XLookupString to introduce control
+                            characters.  */
+
                          old_state = xkey.state;
                          xkey.state &= ~ControlMask;
                          xkey.state &= ~(dpyinfo->meta_mod_mask
@@ -24024,7 +24150,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                      x_dnd_xm_use_help = true;
                      goto xi_done_keysym;
                    }
-#endif
+#endif /* XK_F1 */
 
                  /* See if keysym should make Emacs quit.  */
 
@@ -30973,7 +31099,17 @@ x_term_init (Lisp_Object display_name, char 
*xrm_option, char *resource_name)
                       XkbNewKeyboardNotifyMask | XkbMapNotifyMask,
                       XkbNewKeyboardNotifyMask | XkbMapNotifyMask);
     }
-#endif
+
+  /* XFree86 extends XKBlib with a new Xlib control `ControlFallback',
+     which enables a search for symbols designating ASCII characters
+     within inactive groups during keycode translation when
+     ControlMask is set.  Users find this behavior gratuitous, so
+     disable it if present.  */
+
+#ifdef XkbLC_ControlFallback
+  XkbSetXlibControls (dpyinfo->display, XkbLC_ControlFallback, 0);
+#endif /* XkbLC_ControlFallback */
+#endif /* HAVE_XKB */
 
 #ifdef HAVE_XFIXES
   int xfixes_error_base;
diff --git a/test/lisp/erc/erc-button-tests.el 
b/test/lisp/erc/erc-button-tests.el
index 3dacf95a59f..34ad06b7eb8 100644
--- a/test/lisp/erc/erc-button-tests.el
+++ b/test/lisp/erc/erc-button-tests.el
@@ -274,6 +274,34 @@
                         "abc" " %d def" " 45%s" 123 '\6)
                        "*** abc 123 def 456")))
 
+      (ert-info ("Respects buffer as first argument when given")
+        (should (equal (erc-button--display-error-notice-with-keys
+                        (make-erc-response) "abc") ; compat
+                       "*** abc"))
+        (should (equal (erc-button--display-error-notice-with-keys
+                        (current-buffer) "abc")
+                       "*** abc")))
+
+      (ert-info ("Accounts for nil members when concatenating")
+        (should (equal (erc-button--display-error-notice-with-keys
+                        "a" nil)
+                       "*** a"))
+        (should (equal (erc-button--display-error-notice-with-keys
+                        "a" nil " b")
+                       "*** a b"))
+        (should (equal (erc-button--display-error-notice-with-keys
+                        "a: %d" nil 1)
+                       "*** a: 1"))
+        (should (equal (erc-button--display-error-notice-with-keys
+                        "a: %d %s" 1 nil)
+                       "*** a: 1 nil"))
+        (should (equal (erc-button--display-error-notice-with-keys
+                        "a: " "%d %s" 1 nil)
+                       "*** a: 1 nil"))
+        (should (equal (erc-button--display-error-notice-with-keys
+                        "a: " nil "%d %s" 1 nil)
+                       "*** a: 1 nil")))
+
       (when noninteractive
         (unless mode
           (erc-button-mode -1))
diff --git a/test/lisp/erc/erc-scenarios-log.el 
b/test/lisp/erc/erc-scenarios-log.el
index c37e6b323aa..fd030d90c2f 100644
--- a/test/lisp/erc/erc-scenarios-log.el
+++ b/test/lisp/erc/erc-scenarios-log.el
@@ -202,6 +202,7 @@
         (funcall expect -0.1 "please your lordship")))
 
     (erc-log-mode -1)
+    (erc-truncate-mode -1)
     (when noninteractive (delete-directory tempdir :recursive))))
 
 ;;; erc-scenarios-log.el ends here
diff --git a/test/lisp/erc/erc-scenarios-status-sidebar.el 
b/test/lisp/erc/erc-scenarios-status-sidebar.el
index 92229121c9f..3a047bf3983 100644
--- a/test/lisp/erc/erc-scenarios-status-sidebar.el
+++ b/test/lisp/erc/erc-scenarios-status-sidebar.el
@@ -94,7 +94,7 @@
 ;; terminal, and we lack a fixture for that.  Please try running this
 ;; test interactively with both graphical Emacs and non.
 (declare-function erc-nickbar-mode "erc-speedbar" (arg))
-(declare-function erc-speedbar-close-nicknames-window "erc-speedbar" (kill))
+(declare-function erc-speedbar--get-timers "erc-speedbar" nil)
 (declare-function speedbar-timer-fn "speedbar" nil)
 (defvar erc-nickbar-mode)
 (defvar speedbar-buffer)
@@ -154,16 +154,21 @@
       (ert-info ("Core toggle and kill commands work")
         ;; Avoid using API, e.g., `erc-status-sidebar-buffer-exists-p',
         ;; etc. for testing commands that call those same functions.
-        (erc-nickbar-mode -1)
+        (call-interactively #'erc-nickbar-mode)
+        (should-not erc-nickbar-mode)
         (should-not (and speedbar-buffer
                          (get-buffer-window speedbar-buffer)))
+        (should speedbar-buffer)
+
         (erc-nickbar-mode +1)
         (should (and speedbar-buffer
                      (get-buffer-window speedbar-buffer)))
         (should (get-buffer " SPEEDBAR"))
-        (erc-speedbar-close-nicknames-window 'kill)
+        (erc-nickbar-mode -1)
         (should-not (get-buffer " SPEEDBAR"))
         (should-not erc-nickbar-mode)
-        (should-not (cdr (frame-list)))))))
+        (should-not (cdr (frame-list)))))
+
+    (should-not (erc-speedbar--get-timers))))
 
 ;;; erc-scenarios-status-sidebar.el ends here
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el
index 327ee46a736..9fdad823059 100644
--- a/test/lisp/erc/erc-tests.el
+++ b/test/lisp/erc/erc-tests.el
@@ -132,11 +132,11 @@
 (ert-deftest erc--with-dependent-type-match ()
   (should (equal (macroexpand-1
                   '(erc--with-dependent-type-match (repeat face) erc-match))
-                 '(backquote
-                   (repeat :match ,(lambda (w v)
-                                     (require 'erc-match)
-                                     (widget-editable-list-match w v))
-                           face)))))
+                 '(backquote-list*
+                   'repeat :match (lambda (w v)
+                                    (require 'erc-match)
+                                    (widget-editable-list-match w v))
+                   '(face)))))
 
 (defun erc-tests--send-prep ()
   ;; Caller should probably shadow `erc-insert-modify-hook' or
diff --git a/test/lisp/erc/resources/erc-scenarios-common.el 
b/test/lisp/erc/resources/erc-scenarios-common.el
index 972faa5c73f..2eb040d28d9 100644
--- a/test/lisp/erc/resources/erc-scenarios-common.el
+++ b/test/lisp/erc/resources/erc-scenarios-common.el
@@ -122,6 +122,7 @@
       (inhibit-interaction t)
       (auth-source-do-cache nil)
       (timer-list (copy-sequence timer-list))
+      (timer-idle-list (copy-sequence timer-idle-list))
       (erc-auth-source-parameters-join-function nil)
       (erc-autojoin-channels-alist nil)
       (erc-server-auto-reconnect nil)
diff --git a/test/manual/image-tests.el b/test/manual/image-tests.el
index a359bb0f91f..eb5bf13e8b0 100644
--- a/test/manual/image-tests.el
+++ b/test/manual/image-tests.el
@@ -31,6 +31,8 @@
 
 ;;; Code:
 
+(require 'ert)
+
 (defmacro image-skip-unless (format &rest condition)
   `(skip-unless (and (and (display-images-p)
                           (image-type-available-p ,format))
@@ -41,9 +43,9 @@
                               source-directory))
     (jpeg . ,(expand-file-name "test/data/image/black.jpg"
                                source-directory))
-    (pbm . ,(find-image '((:file "splash.svg" :type svg))))
+    (svg . ,(find-image '((:file "splash.svg" :type svg))))
     (png . ,(find-image '((:file "splash.png" :type png))))
-    (svg . ,(find-image '((:file "splash.pbm" :type pbm))))
+    (pbm . ,(find-image '((:file "splash.pbm" :type pbm))))
     (tiff . ,(expand-file-name
               "nextstep/GNUstep/Emacs.base/Resources/emacs.tiff"
               source-directory))
@@ -80,6 +82,7 @@
 (image-tests-make-load-image-test 'xpm)
 
 (ert-deftest image-tests-load-image/svg-too-big ()
+  (image-skip-unless svg)
   (with-temp-buffer
     (let* ((max-image-size 0)
            (messages-buffer-name (buffer-name (current-buffer)))
@@ -95,6 +98,7 @@
       (should-not (string-match-p "error parsing" (buffer-string))))))
 
 (ert-deftest image-tests-load-image/svg-invalid ()
+  (image-skip-unless svg)
   (with-temp-buffer
     (let ((messages-buffer-name (buffer-name (current-buffer))))
       (with-temp-buffer
@@ -240,6 +244,8 @@
 
 (ert-deftest image-tests-image-metadata/gif ()
   (image-skip-unless 'gif
+                ;; FIXME: Why is this failing on macOS?
+                (not (eq system-type 'darwin))
                 (not (bound-and-true-p w32-use-native-image-API)))
   (should (memq 'delay
                 (image-metadata
@@ -268,7 +274,9 @@
                (create-image (cdr (assq 'tiff image-tests--images))))))
 
 (ert-deftest image-tests-image-metadata/webp ()
-  (image-skip-unless 'webp)
+  (image-skip-unless 'webp
+                ;; FIXME: Why is this failing on macOS?
+                (not (eq system-type 'darwin)))
   (should (memq 'delay
                 (image-metadata
                  (create-image (cdr (assq 'webp image-tests--images)))))))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]