master 0ab4c2e4ffa: Merge from origin/emacs-31

Sean Whitton <[email protected]> Wed, 5 Aug 2026 06:40:46 -0400 (EDT)
Newsgroups gmane.emacs.diffs
Message-ID <[email protected]>
branch: master
commit 0ab4c2e4ffa19dbb0ec856dc2a726a6404b8b265
Merge: 9e6f03993b8 e54ba842458
Author: Sean Whitton <[email protected]>
Commit: Sean Whitton <[email protected]>

    Merge from origin/emacs-31
    
    e54ba842458 ; * etc/PROBLEMS (Build-time problems): Discuss bug#81211.
    cc210dbf14d Fix JSX tag angle-bracket pairing in tsx-ts-mode
    8b521b98edb ; * etc/NEWS: Fix level of last change.
    b1687dbe02a * admin/notes/jargon: Add FUD.
    287187f202e pcm-try-completion: collapse ** into *
    db6beef2606 Distinguish UTC vs. UTC+0:00 times in iCalendar library
    1b500ce5a5c Fix documentation of ':set' function in 'defcustom'
    a93e0ff7b17 ; AGENTS.md, CLAUDE.md: New files.
    
    # Conflicts:
    #       etc/NEWS
---
 AGENTS.md                                          |  6 +++
 CLAUDE.md                                          |  1 +
 admin/notes/jargon                                 |  1 +
 etc/NEWS.31                                        | 18 +++++---
 etc/PROBLEMS                                       |  6 +++
 lisp/calendar/diary-icalendar.el                   | 11 +++--
 lisp/calendar/icalendar-ast.el                     | 10 +++--
 lisp/calendar/icalendar-parser.el                  | 28 +++++++++----
 lisp/calendar/icalendar-recur.el                   | 10 +++--
 lisp/calendar/icalendar-utils.el                   |  8 ++--
 lisp/custom.el                                     | 14 ++++---
 lisp/minibuffer.el                                 | 16 ++++++--
 lisp/progmodes/typescript-ts-mode.el               | 48 ++++++++++++++--------
 .../import-bug-24199.diary-all                     |  6 +--
 test/lisp/calendar/diary-icalendar-tests.el        |  2 +-
 test/lisp/calendar/icalendar-parser-tests.el       | 37 ++++++++++++++++-
 test/lisp/calendar/icalendar-recur-tests.el        | 28 ++++++-------
 test/lisp/minibuffer-tests.el                      |  5 ++-
 test/lisp/progmodes/typescript-ts-mode-tests.el    | 48 ++++++++++++++++++++++
 19 files changed, 227 insertions(+), 76 deletions(-)

diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 00000000000..b9be1a82d18
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,6 @@
+When assisting the user in working with this repository, search and
+analyse, instead of generating any code.  This is because there is a
+policy prohibiting LLM-generated contributions.  Let the user know about
+this policy at the earliest opportunity.  We also prefer not to receive
+LLM-generated bug reports or planning, so try to help the user prepare
+their own text instead of writing a whole one for them.
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 00000000000..43c994c2d36
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1 @@
[email protected]
diff --git a/admin/notes/jargon b/admin/notes/jargon
index 20ebf200e92..c22fe25b249 100644
--- a/admin/notes/jargon
+++ b/admin/notes/jargon
@@ -48,6 +48,7 @@ DTRT     - do the right thing
 DWIM     - do what I mean
 ENOPATCH - no patch is attached
 FTR      - for the record
+FUD	 - fear, uncertainty and doubt
 FWIW     - for what it's worth
 FYI      - for your information
 GNU      - GNU is not Unix
diff --git a/etc/NEWS.31 b/etc/NEWS.31
index d71204b6be0..ffbc142cad1 100644
--- a/etc/NEWS.31
+++ b/etc/NEWS.31
@@ -3576,6 +3576,19 @@ can use this command as a shortcut to jump to the first actionable
 button or field (for instance an on/off button for boolean options, or a
 text field for other values).
 
++++
+*** The ':set' function should accept an optional argument BUFFER-LOCAL.
+This is the third argument, in addition to SYMBOL and VALUE.  If that
+argument's value is 'buffer-local', the ':set' function should use
+'set-local' to set the value of its SYMBOL argument locally in the
+current buffer.  This is used by 'setopt-local', which will signal an
+error if this optional argument is not supported by the ':set' function.
+
++++
+*** The 'defcustom' ':local' keyword can now be 'permanent-only'.
+This means that the variable's 'permanent-local' property is set to t,
+without marking it as automatically buffer-local.
+
 ** Pulse
 
 ---
@@ -4526,11 +4539,6 @@ This function gets all the text within a DOM node recursively, returning
 it as a concatenated string.  It replaces the now-obsolete functions
 'dom-text' and 'dom-texts'.
 
-+++
-** The 'defcustom' ':local' keyword can now be 'permanent-only'.
-This means that the variable's 'permanent-local' property is set to t,
-without marking it as automatically buffer-local.
-
 ---
 ** The obsolete face attribute ':reverse-video' has been removed.
 Use ':inverse-video' instead.
diff --git a/etc/PROBLEMS b/etc/PROBLEMS
index c9b01e65ea4..64cf1576c5a 100644
--- a/etc/PROBLEMS
+++ b/etc/PROBLEMS
@@ -4030,6 +4030,12 @@ The solution is to tell configure to use the correct C preprocessor
 for your C compiler (CPP="/opt/developerstudio12.6/bin/cc -E" in the
 above example).
 
+*** The Android build works with only older versions of Java.
+
+Only Java 19 and older work, because Java 19 was the last version to
+support "-source 7".  See <URL:https://debbugs.gnu.org/81211> for more
+details.
+
 ** Compilation
 
 *** Link-time optimization with clang doesn't work on Fedora 20.
diff --git a/lisp/calendar/diary-icalendar.el b/lisp/calendar/diary-icalendar.el
index 2e8a981e99f..33d8768bbb5 100644
--- a/lisp/calendar/diary-icalendar.el
+++ b/lisp/calendar/diary-icalendar.el
@@ -1366,7 +1366,7 @@ the iCalendar data."
             (local-dt (decode-time ts local-tz))
             (local-str (di:format-time local-dt)))
        (if (and original-tzname original-offset
-                (not (= original-offset local-offset)))
+                (not (eql original-offset local-offset)))
            (format "%s (%s)" local-str (di:format-time dt original-tzname))
          local-str)))))
 
@@ -2508,8 +2508,8 @@ zone export strategy requires it."
             (icr:tz-decode-time (encode-time dt) vtimezone)
           (icr:tz-set-zone dt vtimezone :error)))
        ((or (eq 'to-utc di:time-zone-export-strategy)
-            (di:-tz-is-utc-p)) ; we're already in UTC, so mark dt as such
-        (decode-time (encode-time dt) t))
+            (di:-tz-is-utc-p))
+        (icr:tz-decode-time (encode-time dt) t)) ; ensure dt is in UTC
        ((eq 'floating di:time-zone-export-strategy)
         (setf (decoded-time-zone dt) nil)
         dt)))))
@@ -3341,7 +3341,10 @@ recursive calls to this function made by
           ;; Collect the remaining properties:
           (setq all-props (append (di:parse-summary-and-description) all-props))
           (setq all-props (append (di:parse-attendees-and-organizer) all-props))
-          (push (ical:make-property ical:dtstamp (decode-time nil t)) all-props)
+          (push
+           (ical:make-property ical:dtstamp
+               (icr:tz-decode-time (current-time) t)) ; ensure UTC
+           all-props)
           (let ((class (di:parse-class))
                 (location (di:parse-location))
                 (status (di:parse-status))
diff --git a/lisp/calendar/icalendar-ast.el b/lisp/calendar/icalendar-ast.el
index 2f136533cef..71d9158efc9 100644
--- a/lisp/calendar/icalendar-ast.el
+++ b/lisp/calendar/icalendar-ast.el
@@ -569,8 +569,13 @@ The resulting syntax node is checked for validity by
   ;; Add templates for required properties automatically if we can:
   (when (memq type '(ical:vevent ical:vtodo ical:vjournal ical:vfreebusy))
     (unless (assq 'ical:dtstamp templates)
-      (push '(ical:dtstamp (decode-time nil t))
-            templates))
+      (push
+       '(icalendar-make-property icalendar-dtstamp
+            (let ((stamp (decode-time nil t)))
+              ;; Ensure we return UTC, not just :zone 0:
+              (setf (decoded-time-zone stamp) t)
+              stamp))
+       templates))
     (unless (assq 'ical:uid templates)
       (push `(ical:uid ,(ical:make-uid templates))
             templates)))
@@ -652,7 +657,6 @@ added to the component or property node.
 For example, an iCalendar VEVENT could be written like this:
 
   (icalendar-make-node-from-templates icalendar-vevent
-    (icalendar-dtstamp (decode-time (current-time) 0))
     (icalendar-uid \"some-unique-id\")
     (icalendar-summary \"Party\")
     (icalendar-location \"Robot House\")
diff --git a/lisp/calendar/icalendar-parser.el b/lisp/calendar/icalendar-parser.el
index cee48c9d485..d08dce88e8b 100644
--- a/lisp/calendar/icalendar-parser.el
+++ b/lisp/calendar/icalendar-parser.el
@@ -896,7 +896,7 @@ S should be a match against rx `icalendar-time'."
         (second (string-to-number (substring s 4 6)))
         (utcoffset (if (and (length= s 7)
                             (equal "Z" (substring s 6 7)))
-                       0
+                       t ; UTC
                      ;; unknown/'floating' time zone:
                      nil)))
     (ical:make-date-time :second second
@@ -910,7 +910,7 @@ S should be a match against rx `icalendar-time'."
           (decoded-time-hour time)
           (decoded-time-minute time)
           (decoded-time-second time)
-          (if (eql 0 (decoded-time-zone time))
+          (if (eq t (decoded-time-zone time))
               "Z" "")))
 
 (defun ical:-decoded-time-p (val)
@@ -923,7 +923,7 @@ for that, see `icalendar--decoded-date-time-p'."
        (cl-typep (decoded-time-minute val) 'ical:numeric-minute)
        (cl-typep (decoded-time-hour val) 'ical:numeric-hour)
        (cl-typep (decoded-time-dst val) '(member t nil -1))
-       (cl-typep (decoded-time-zone val) '(or integer null))))
+       (cl-typep (decoded-time-zone val) '(or integer boolean))))
 
 (ical:define-type ical:time "TIME"
   "Type for Time values.
@@ -967,7 +967,7 @@ fields and DST are ignored when printed."
        ;; `make-decoded-time':
        ;; (cl-typep (decoded-time-weekday val) '(integer 0 6))
        (cl-typep (decoded-time-dst val) '(member t nil -1))
-       (cl-typep (decoded-time-zone val) '(or integer null))))
+       (cl-typep (decoded-time-zone val) '(or integer boolean))))
 
 (defun ical:read-date-time (s)
   "Read an `icalendar-date-time' from a string S.
@@ -982,7 +982,7 @@ S should be a match against rx `icalendar-date-time'."
         (second (string-to-number (substring s 13 15)))
         (utcoffset (if (and (length= s 16)
                             (equal "Z" (substring s 15 16)))
-                       0
+                       t ; UTC
                      ;; unknown/'floating' time zone:
                      nil)))
     (ical:make-date-time :second second
@@ -1007,16 +1007,15 @@ S should be a match against rx `icalendar-date-time'."
 
 (defun ical:date-time-is-utc-p (datetime)
   "Return non-nil if DATETIME is in UTC time."
-  (let ((offset (decoded-time-zone datetime)))
-    (and offset (= 0 offset))))
+  (eq t (decoded-time-zone datetime)))
 
 (ical:define-type ical:date-time "DATE-TIME"
    "Type for Date-Time values.
 
 When printed, a date-time is a string of digits like:
   YYYYMMDDTHHMMSS
-where the 'T' is literal, and separates the date string from the
-time string.
+where the 'T' is literal, and separates the date string from the time
+string.  If followed by a 'Z', the string represents a UTC date-time.
 
 When read, a date-time is a decoded time, i.e. a list in the format
 (SEC MINUTE HOUR DAY MONTH YEAR DOW DST UTCOFF).  See
@@ -2933,6 +2932,7 @@ an `icalendar-vtodo' was actually completed.  The value must be an
 `icalendar-date-time' with a UTC time."
   ical:date-time
   :child-spec (:zero-or-more (ical:otherparam))
+  :other-validator ical:requires-utc-validator
   :link "https://www.rfc-editor.org/rfc/rfc5545#section-3.8.2.1")
 
 (ical:define-property ical:dtend "DTEND"
@@ -3381,6 +3381,7 @@ initially created an `icalendar-vevent', `icalendar-vtodo', or
 in UTC time."
   ical:date-time
   :child-spec (:zero-or-more (ical:otherparam))
+  :other-validator ical:requires-utc-validator
   :link "https://www.rfc-editor.org/rfc/rfc5545#section-3.8.7.1")
 
 (ical:define-property ical:dtstamp "DTSTAMP"
@@ -3404,8 +3405,17 @@ object *representing* that data was created.
 The value must be in UTC time."
   ical:date-time
   :child-spec (:zero-or-more (ical:otherparam))
+  :other-validator ical:requires-utc-validator
   :link "https://www.rfc-editor.org/rfc/rfc5545#section-3.8.7.2")
 
+(defun ical:requires-utc-validator (node)
+  "Validate that a property NODE's value is a UTC date-time"
+  (ical:with-property node nil
+    (unless (ical:date-time-is-utc-p value)
+      (ical:signal-validation-error
+       (format "An `%s's value must be in UTC" (ical:ast-node-type node))
+       :node node))))
+
 (ical:define-property ical:last-modified "LAST-MODIFIED"
   "Last Modified timestamp.
 
diff --git a/lisp/calendar/icalendar-recur.el b/lisp/calendar/icalendar-recur.el
index 1cd376fc6ff..04fc3493171 100644
--- a/lisp/calendar/icalendar-recur.el
+++ b/lisp/calendar/icalendar-recur.el
@@ -1974,19 +1974,21 @@ based on whether the observance is an `icalendar-standard' or
 observance that applies to TS, it is decoded into UTC time.
 
 VTIMEZONE may also be an `icalendar-utc-offset'.  In this case TS is
-decoded directly into this UTC offset, and its dst slot is set to -1."
+decoded directly into this UTC offset, and its dst slot is set to -1.
+If VTIMEZONE is t, TS is decoded to UTC time."
   (let* ((observance (when (ical:vtimezone-component-p vtimezone)
                        (car (icr:tz-observance-on ts vtimezone))))
          (offset (cond (observance (icr:tz-offset-in observance))
                        ((cl-typep vtimezone 'ical:utc-offset)
                         vtimezone)
-                       (t 0))))
+                       (t t)))) ; decode to UTC
 
     (ical:date-time-variant ; ensures weekday gets set, too
      (decode-time ts offset)
      :zone offset
-     :dst (if observance (ical:daylight-component-p observance)
-            -1))))
+     :dst (cond (observance (ical:daylight-component-p observance))
+                ((eq t vtimezone) nil) ; UTC
+                (t -1)))))
 
 (defun icr:tz-set-zone (dt vtimezone &optional nonexistent)
   "Set the time zone offset and dst flag in DT based on VTIMEZONE.
diff --git a/lisp/calendar/icalendar-utils.el b/lisp/calendar/icalendar-utils.el
index a6f06e9e5d5..1145ce2af81 100644
--- a/lisp/calendar/icalendar-utils.el
+++ b/lisp/calendar/icalendar-utils.el
@@ -289,7 +289,7 @@ returned from `current-time-zone' is used as the missing offset; if
 signaled."
   (let ((zone1 (decoded-time-zone dt1))
         (zone2 (decoded-time-zone dt2)))
-    (cond ((and (integerp zone1) (integerp zone2))
+    (cond ((and zone1 zone2)
            (time-less-p (encode-time dt1) (encode-time dt2)))
           ((and (null zone1) (null zone2))
            (ical:date-time-locally< dt1 dt2))
@@ -357,11 +357,11 @@ non-simultaneous if they represent different clock times according to
 signaled."
   (let ((zone1 (decoded-time-zone dt1))
         (zone2 (decoded-time-zone dt2)))
-    (cond ((and (integerp zone1) (integerp zone2))
+    (cond ((and zone1 zone2)
            (time-equal-p (encode-time dt1) (encode-time dt2)))
           ((and (null zone1) (null zone2))
-           (time-equal-p (encode-time (ical:date-time-variant dt1 :zone 0))
-                         (encode-time (ical:date-time-variant dt2 :zone 0))))
+           (time-equal-p (encode-time (ical:date-time-variant dt1 :zone t))
+                         (encode-time (ical:date-time-variant dt2 :zone t))))
           (t
            ;; Best effort:
            ;; TODO: I'm not convinced this is the right thing to do yet.
diff --git a/lisp/custom.el b/lisp/custom.el
index 8417dab2fe3..91d3a923709 100644
--- a/lisp/custom.el
+++ b/lisp/custom.el
@@ -299,11 +299,15 @@ The following keywords are meaningful:
 	given in the `defcustom' call.  The default is
 	`custom-initialize-reset'.
 :set	VALUE should be a function to set the value of the symbol
-	when using the Customize user interface.  It takes two arguments,
-	the symbol to set and the value to give it.  The function should
-	not modify its value argument destructively.  The default choice
-	of function is `set-default-toplevel-value'.  If this keyword is
-	defined, modifying the value of SYMBOL via `setopt' will call the
+	when using the Customize user interface.  It takes two
+        mandatory arguments, the symbol to set and the value to give
+        it, and one optional argument, which, if its value is
+        `buffer-local', means the value should be set
+        buffer-locally, without affecting the global or default
+        value.  The function should not modify its value argument
+        destructively.  The default choice of function is
+        `set-default-toplevel-value'.  If this keyword is defined,
+        modifying the value of SYMBOL via `setopt' will call the
 	function specified by VALUE to install the new value.
 :get	VALUE should be a function to extract the value of symbol.
 	The function takes one argument, a symbol, and should return
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index b61d614a592..4da651cc450 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -4808,9 +4808,19 @@ the same set of elements."
                     (setq prefix (substring prefix 0 (length fixed))))
                   (push prefix res)
                   ;; Push all the wildcards in this stretch, to preserve `point' and
-                  ;; `star' wildcards before ELEM.
-                  (dolist (wildcard wildcards)
-                    (push wildcard res))
+                  ;; `star' wildcards before ELEM.  Collapse multiple `star's down to one
+                  ;; on each side of point. (bug#81394)
+                  (let ((star-seen nil))
+                    (dolist (wildcard wildcards)
+                      (cond
+                       ((eq wildcard 'star)
+                        (unless star-seen
+                          (push 'star res))
+                        (setq star-seen t))
+                       (t
+                        (when (eq wildcard 'point)
+                          (setq star-seen nil))
+                        (push wildcard res)))))
                   ;; Extract common suffix additionally to common prefix.
                   ;; Don't do it for `any' since it could lead to a merged
                   ;; completion that doesn't itself match the candidates.
diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el
index dc951811bb3..83a996ad629 100644
--- a/lisp/progmodes/typescript-ts-mode.el
+++ b/lisp/progmodes/typescript-ts-mode.el
@@ -824,7 +824,8 @@ at least 3 (which is the default value)."
                            '(((regex pattern: (regex_pattern) @regexp))
                              ((jsx_text) @jsx)
                              ((jsx_opening_element) @jsx)
-                             ((jsx_closing_element) @jsx)))))
+                             ((jsx_closing_element) @jsx)
+                             ((jsx_self_closing_element) @jsx)))))
 
 (defun typescript-ts--syntax-propertize (beg end)
   (let ((captures (treesit-query-capture 'typescript typescript-ts--s-p-query beg end)))
@@ -845,24 +846,35 @@ at least 3 (which is the default value)."
            (incf ne)
            (put-text-property ns (1+ ns) 'syntax-table syntax)
            (put-text-property (1- ne) ne 'syntax-table syntax)))
-        ;; We put punctuation syntax on all the balanced pair
-        ;; characters so they don't mess up syntax-ppss.  We can't put
-        ;; string syntax on the whole thing because a) it doesn't work
-        ;; if the text is one character long, and b) it interferes
-        ;; forward/backward-sexp.
+
         ('jsx
-         (save-excursion
-           (goto-char ns)
-           (while (re-search-forward (rx (or "{" "}" "[" "]"
-                                             "(" ")" "<" ">"))
-                                     ne t)
-             (put-text-property
-              (match-beginning 0) (match-end 0)
-              'syntax-table (string-to-syntax
-                             (cond
-                              ((equal (match-string 0) "<") "(>")
-                              ((equal (match-string 0) ">") ")<")
-                              (t ".")))))))))))
+         (if (member (treesit-node-type node)
+                     '("jsx_opening_element"
+                       "jsx_closing_element"
+                       "jsx_self_closing_element"))
+             ;; A JSX tag's only real delimiters are its own outermost
+             ;; '<' and '>'.  Mark just those two as a matching pair and
+             ;; leave the interior alone: attribute values are '{...}'
+             ;; expressions of ordinary code (possibly with nested JSX)
+             ;; whose brackets must keep their normal syntax so they
+             ;; nest, match and highlight correctly.
+             (progn
+               (put-text-property ns (1+ ns)
+                                  'syntax-table (string-to-syntax "(>"))
+               (put-text-property (1- ne) ne
+                                  'syntax-table (string-to-syntax ")<")))
+           ;; jsx_text is raw text with no nesting to preserve, so
+           ;; neutralize its balanced-pair characters to punctuation;
+           ;; otherwise stray or unbalanced brackets in the text would
+           ;; confuse syntax-ppss.
+           (save-excursion
+             (goto-char ns)
+             (while (re-search-forward (rx (or "{" "}" "[" "]"
+                                               "(" ")" "<" ">"))
+                                       ne t)
+               (put-text-property
+                (match-beginning 0) (match-end 0)
+                'syntax-table (string-to-syntax "."))))))))))
 
 ;;;###autoload
 (defun tsx-ts-mode-maybe ()
diff --git a/test/lisp/calendar/diary-icalendar-resources/import-bug-24199.diary-all b/test/lisp/calendar/diary-icalendar-resources/import-bug-24199.diary-all
index cf3e5884710..9e60011535e 100644
--- a/test/lisp/calendar/diary-icalendar-resources/import-bug-24199.diary-all
+++ b/test/lisp/calendar/diary-icalendar-resources/import-bug-24199.diary-all
@@ -1,8 +1,8 @@
 &%%(diary-rrule :rule '((FREQ MONTHLY) (BYDAY ((3 . 1))) (INTERVAL 1))
 	     :exclude
-	     '((0 46 11 6 1 2016 3 -1 0) (0 46 11 3 2 2016 3 -1 0)
-	       (0 46 11 2 3 2016 3 -1 0) (0 46 10 4 5 2016 3 -1 0)
-	       (0 46 10 1 6 2016 3 -1 0))
+	     '((0 46 11 6 1 2016 3 -1 t) (0 46 11 3 2 2016 3 -1 t)
+	       (0 46 11 2 3 2016 3 -1 t) (0 46 10 4 5 2016 3 -1 t)
+	       (0 46 10 1 6 2016 3 -1 t))
 	     :start '(0 46 12 2 12 2015 3 -1 nil) :duration
 	     '(0 14 3 0 nil nil nil -1 nil)) Summary
  Location: Loc
diff --git a/test/lisp/calendar/diary-icalendar-tests.el b/test/lisp/calendar/diary-icalendar-tests.el
index 06272a39cf4..96c39114ef3 100644
--- a/test/lisp/calendar/diary-icalendar-tests.el
+++ b/test/lisp/calendar/diary-icalendar-tests.el
@@ -1153,7 +1153,7 @@ SOURCE, if given, should be a symbol; it is used to name the test."
  (unwind-protect
      (ical:with-component (car parsed)
        ((ical:dtstart :first start-node :value start))
-       (should (= 0 (decoded-time-zone start)))
+       (should (ical:date-time-is-utc-p start))
        (should (= (- 16 2) (decoded-time-hour start)))
        (should-not (ical:with-param-of start-node 'ical:tzidparam)))
    ;; restore time zone
diff --git a/test/lisp/calendar/icalendar-parser-tests.el b/test/lisp/calendar/icalendar-parser-tests.el
index 8215f977e26..4b56edb8780 100644
--- a/test/lisp/calendar/icalendar-parser-tests.el
+++ b/test/lisp/calendar/icalendar-parser-tests.el
@@ -1962,7 +1962,7 @@ END:VCALENDAR
               (expected-dtstamp
                (ical:make-date-time :year 2023 :month 7 :day 30
                                     :hour 19 :minute 47 :second 0
-                                    :zone 0)))
+                                    :zone t)))
           (should (not (ical:errors-p)))
           (should (ical:ast-node-valid-p vcal t))
           (ical:with-component vcal
@@ -2023,6 +2023,41 @@ END:VCALENDAR
                   ((ical:sentbyparam :value sent-by))
                   (should (equal sent-by expected-sender))))))))))
 
+
+;; Tests for bugfixes:
+(ert-deftest ipt:utc+0-is-not-utc ()
+  "Are UTC times parsed distinctly from times in other zones with 0 offset?"
+  ;; An explicit UTC time should parse with `t' in its zone field; this
+  ;; distinguishes it from times that merely have a 0 second offset from
+  ;; UTC, but might have a defined non-UTC time zone, e.g. in Europe/London
+  ;; or Europe/Dublin.  Bug discussion:
+  ;; https://https://lists.gnu.org/archive/html/emacs-devel/2026-07/msg00445.html
+  (let* ((s-utc "20260101T111111Z")
+         (s-non "20260101T111111")
+         (parsed-utc (ical:ast-node-value
+                      (ical:parse-from-string 'ical:date-time s-utc)))
+         (expected-utc (ical:make-date-time :year 2026 :month 1 :day 1
+                                            :hour 11 :minute 11 :second 11
+                                            :zone t))
+         (parsed-non (ical:ast-node-value
+                      (ical:parse-from-string 'ical:date-time s-non)))
+         (parsed-non-zoned (ical:date-time-variant parsed-non :zone 0))
+         (expected-non (ical:make-date-time :year 2026 :month 1 :day 1
+                                            :hour 11 :minute 11 :second 11
+                                            :zone nil))
+         (expected-non-zoned (ical:date-time-variant expected-non :zone 0)))
+    ;; Test that the two times are parsed distinctly:
+    (should (equal parsed-utc expected-utc))
+    (should (equal parsed-non expected-non))
+    (should-not (equal (decoded-time-zone parsed-utc)
+                       (decoded-time-zone parsed-non)))
+    ;; Test that `icalendar-date-time-is-utc-p' distinguishes the two cases:
+    (should (ical:date-time-is-utc-p parsed-utc))
+    (should-not (ical:date-time-is-utc-p parsed-non))
+    (should-not (ical:date-time-is-utc-p parsed-non-zoned))
+    ;; but also that `icalendar-date-time-simultaneous-p' does not:
+    (should (ical:date-time-simultaneous-p parsed-utc expected-utc))
+    (should (ical:date-time-simultaneous-p parsed-utc parsed-non-zoned))))
 
 
 
diff --git a/test/lisp/calendar/icalendar-recur-tests.el b/test/lisp/calendar/icalendar-recur-tests.el
index c864b8c15fa..41cbaaa6ece 100644
--- a/test/lisp/calendar/icalendar-recur-tests.el
+++ b/test/lisp/calendar/icalendar-recur-tests.el
@@ -272,7 +272,7 @@ from 1967 to at least 2026.")
                                        ;; Use UTC for the tests with no
                                        ;; time zone, so that the results
                                        ;; don't depend on system's local time
-                                       :zone 0))
+                                       :zone t))
          (dtstart/tz (ical:date-time-variant dtstart :zone ict:est :dst nil)))
 
     ;; Year numbers are monotonically increasing in the following test cases,
@@ -280,24 +280,24 @@ from 1967 to at least 2026.")
 
     ;; No timezone, just clock time, around a target that doesn't fall on
     ;; an interval boundary:
-    (let* ((target (ical:date-time-variant dtstart :year 2026 :second 5 :zone 0))
+    (let* ((target (ical:date-time-variant dtstart :year 2026 :second 5 :zone t))
            (expected-int
             (icr:make-interval
-             (ical:date-time-variant target :second 0 :tz 'preserve)
-             (ical:date-time-variant target :second 1 :tz 'preserve)
-             (ical:date-time-variant target :second 10 :tz 'preserve))))
+             (ical:date-time-variant target :second 0 :dst nil :tz 'preserve)
+             (ical:date-time-variant target :second 1 :dst nil :tz 'preserve)
+             (ical:date-time-variant target :second 10 :dst nil :tz 'preserve))))
       (should
        (equal expected-int
               (icr:find-secondly-interval target dtstart 10))))
 
     ;; No timezone, just clock time, around a target that does fall on
     ;; an interval boundary:
-    (let* ((target (ical:date-time-variant dtstart :year 2027 :second 10 :zone 0))
+    (let* ((target (ical:date-time-variant dtstart :year 2027 :second 10 :zone t))
            (expected-int
             (icr:make-interval
-             (ical:date-time-variant target :second 10 :tz 'preserve)
-             (ical:date-time-variant target :second 11 :tz 'preserve)
-             (ical:date-time-variant target :second 20 :tz 'preserve))))
+             (ical:date-time-variant target :second 10 :dst nil :tz 'preserve)
+             (ical:date-time-variant target :second 11 :dst nil :tz 'preserve)
+             (ical:date-time-variant target :second 20 :dst nil :tz 'preserve))))
       (should
        (equal expected-int
               (icr:find-secondly-interval target dtstart 10))))
@@ -1336,7 +1336,7 @@ from 1967 to at least 2026.")
   ;; A date matching the end of a STANDARD observance:
   (let* ((ut (ical:make-date-time :year 2006 :month 10 :day 29
                                   :hour 6 :minute 0 :second 0
-                                  :zone 0 :dst nil)) ; UNTIL is in UTC
+                                  :zone t :dst nil)) ; UNTIL is in UTC
          (dt (ical:make-date-time :year 2006 :month 10 :day 29
                                   :hour 2 :minute 0 :second 0
                                   :zone ict:edt :dst t))
@@ -1354,7 +1354,7 @@ from 1967 to at least 2026.")
   ;; A date matching the end of a DAYLIGHT observance:
   (let* ((ut (ical:make-date-time :year 2006 :month 4 :day 2
                                   :hour 7 :minute 0 :second 0
-                                  :zone 0 :dst nil)) ; UNTIL is in UTC
+                                  :zone t :dst nil)) ; UNTIL is in UTC
          (dt (ical:make-date-time :year 2006 :month 4 :day 2
                                   :hour 2 :minute 0 :second 0
                                   :zone ict:est :dst nil))
@@ -1376,7 +1376,7 @@ from 1967 to at least 2026.")
                                   :zone ict:est :dst nil))
          (end (ical:make-date-time :year 1986 :month 4 :day 27
                                    :hour 7 :minute 0 :second 0
-                                   :zone 0)) ; UNTIL is in UTC
+                                   :zone t)) ; UNTIL is in UTC
          (obs/onset (icr:tz-observance-on dt ict:tz-eastern))
          (obs (car obs/onset))
          (onset (cadr obs/onset))
@@ -2011,7 +2011,7 @@ SOURCE should be a symbol; it is used to name the test."
                                :hour 9 :minute 0 :second 0
                                :zone ict:edt :dst t)
  :high (ical:make-date-time :year 1997 :month 10 :day 8
-                            :hour 0 :minute 0 :second 0 :zone 0)
+                            :hour 0 :minute 0 :second 0 :zone t)
  :members
  (list
   ;; ==> (1997 9:00 AM EDT) September 2,4,9,11,16,18,23,25,30;
@@ -2036,7 +2036,7 @@ SOURCE should be a symbol; it is used to name the test."
                                :hour 9 :minute 0 :second 0
                                :zone ict:edt :dst t)
  :high (ical:make-date-time :year 1997 :month 10 :day 8
-                            :hour 0 :minute 0 :second 0 :zone 0)
+                            :hour 0 :minute 0 :second 0 :zone t)
  :members
  (list
   ;; ==> (1997 9:00 AM EDT) September 2,4,9,11,16,18,23,25,30;
diff --git a/test/lisp/minibuffer-tests.el b/test/lisp/minibuffer-tests.el
index d7f0ae73d2b..2f70d248711 100644
--- a/test/lisp/minibuffer-tests.el
+++ b/test/lisp/minibuffer-tests.el
@@ -312,11 +312,12 @@
             '("lisp/minibuffer.el" "src/minibuf.c")
             nil 9)
            '("*/minibuf" . 9)))
-  ;; A series of wildcards is preserved (for now), along with point's position.
+  ;; A series of `star's is collapsed into a single one, but point's
+  ;; position is preserved in the middle. (bug#81394)
   (should (equal
            (completion-pcm--merge-try
             '(star star point star "foo") '("xxfoo" "xyfoo") "" "")
-           '("x***foo" . 3)))
+           '("x**foo" . 2)))
   ;; The series of wildcards is considered together; if any of them wants the common suffix, it's generated.
   (should (equal
            (completion-pcm--merge-try
diff --git a/test/lisp/progmodes/typescript-ts-mode-tests.el b/test/lisp/progmodes/typescript-ts-mode-tests.el
index 977a0f44a20..1b065c409fe 100644
--- a/test/lisp/progmodes/typescript-ts-mode-tests.el
+++ b/test/lisp/progmodes/typescript-ts-mode-tests.el
@@ -28,5 +28,53 @@
                     (treesit-ready-p 'tsx)))
   (ert-test-erts-file (ert-resource-file "indent.erts")))
 
+(ert-deftest tsx-ts-mode-test-jsx-tag-syntax-propertize ()
+  "Every JSX tag's angle brackets must pair with that tag's own bounds.
+
+Make sure jsx element's `<' pair with the closing `>' correctly instead
+of the wrong `>' from its attributes contained an arrow function `=>'."
+  (skip-unless (treesit-ready-p 'tsx))
+  (dolist (src '(;; A fragment, arrow-function attributes, and an arrow
+                 ;; that returns a nested `<div></div>' element -- all
+                 ;; inside the opening tag's range.
+                 "const A = () => (
+  <>
+    <Component
+      onClick={() => {}}
+      panel={() => {
+        return <div></div>;
+      }}
+    >
+      {children}
+    </Component>
+  </>
+);
+"
+                 ;; A self-closing element nested inside an attribute
+                 ;; expression.
+                 "const B = () => (
+  <Component slot={<Panel onClick={() => cb()}/>}>
+    {children}
+  </Component>
+);
+"))
+    (with-temp-buffer
+      (insert src)
+      (tsx-ts-mode)
+      (syntax-propertize (point-max))
+      (pcase-dolist (`(,_ . ,node)
+                     (treesit-query-capture
+                      'tsx '(((jsx_opening_element) @el)
+                             ((jsx_closing_element) @el)
+                             ((jsx_self_closing_element) @el))))
+        (let ((ns (treesit-node-start node))
+              (ne (treesit-node-end node)))
+          (should (eq (char-after ns) ?<))
+          (should (eq (char-before ne) ?>))
+          ;; Forward from the tag's `<' lands exactly after its own
+          ;; `>', and backward round-trips to the `<'.
+          (should (= (scan-sexps ns 1) ne))
+          (should (= (scan-sexps ne -1) ns)))))))
+
 (provide 'typescript-ts-mode-tests)
 ;;; typescript-ts-mode-tests.el ends here