diff --git a/Cargo.lock b/Cargo.lock
index 0c492e3af1623..022688b698f5c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5216,9 +5216,9 @@ dependencies = [
 
 [[package]]
 name = "stringdex"
-version = "0.0.1-alpha9"
+version = "0.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7081029913fd7d591c0112182aba8c98ae886b4f12edb208130496cd17dc3c15"
+checksum = "18b3bd4f10d15ef859c40291769f0d85209de6b0f1c30713ff9cdf45ac43ea36"
 dependencies = [
  "stacker",
 ]
diff --git a/RELEASES.md b/RELEASES.md
index 33abe45ce4629..74b0d4424c163 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,340 @@
+Version 1.91.0 (2025-10-30)
+==========================
+
+
+
+Language
+--------
+
+- [Lower pattern bindings in the order they're written and base drop order on primary bindings' order](https://github.com/rust-lang/rust/pull/143764)
+- [Stabilize declaration of C-style variadic functions for `sysv64`, `win64`, `efiapi`, and `aapcs` ABIs](https://github.com/rust-lang/rust/pull/144066).
+  This brings these ABIs in line with the C ABI: variadic functions can be declared in extern blocks but not defined.
+- [Add `dangling_pointers_from_locals` lint to warn against dangling pointers from local variables](https://github.com/rust-lang/rust/pull/144322)
+- [Upgrade `semicolon_in_expressions_from_macros` from warn to deny](https://github.com/rust-lang/rust/pull/144369)
+- [Stabilize LoongArch32 inline assembly](https://github.com/rust-lang/rust/pull/144402)
+- [Add warn-by-default `integer_to_ptr_transmutes` lint against integer-to-pointer transmutes](https://github.com/rust-lang/rust/pull/144531)
+- [Stabilize `sse4a` and `tbm` target features](https://github.com/rust-lang/rust/pull/144542)
+- [Add `target_env = "macabi"` and `target_env = "sim"` cfgs](https://github.com/rust-lang/rust/pull/139451) as replacements for the `target_abi` cfgs with the same values.
+
+
+
+Compiler
+--------
+
+- [Don't warn on never-to-any `as` casts as unreachable](https://github.com/rust-lang/rust/pull/144804)
+
+
+
+Platform Support
+----------------
+
+- [Promote `aarch64-pc-windows-gnullvm` and `x86_64-pc-windows-gnullvm` to Tier 2 with host tools.](https://github.com/rust-lang/rust/pull/143031)
+  Note: llvm-tools and MSI installers are missing but will be added in future releases.
+- [Promote `aarch64-pc-windows-msvc` to Tier 1](https://github.com/rust-lang/rust/pull/145682)
+
+Refer to Rust's [platform support page][platform-support-doc]
+for more information on Rust's tiered platform support.
+
+[platform-support-doc]: https://doc.rust-lang.org/rustc/platform-support.html
+
+
+
+Libraries
+---------
+
+- [Print thread ID in panic message](https://github.com/rust-lang/rust/pull/115746)
+- [Fix overly restrictive lifetime in `core::panic::Location::file` return type](https://github.com/rust-lang/rust/pull/132087)
+- [Guarantee parameter order for `_by()` variants of `min` / `max`/ `minmax` in `std::cmp`](https://github.com/rust-lang/rust/pull/139357)
+- [Document assumptions about `Clone` and `Eq` traits](https://github.com/rust-lang/rust/pull/144330/)
+- [`std::thread`: Return error if setting thread stack size fails](https://github.com/rust-lang/rust/pull/144210)
+  This used to panic within the standard library.
+
+
+
+Stabilized APIs
+---------------
+
+- [`Path::file_prefix`](https://doc.rust-lang.org/stable/std/path/struct.Path.html#method.file_prefix)
+- [`AtomicPtr::fetch_ptr_add`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicPtr.html#method.fetch_ptr_add)
+- [`AtomicPtr::fetch_ptr_sub`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicPtr.html#method.fetch_ptr_sub)
+- [`AtomicPtr::fetch_byte_add`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicPtr.html#method.fetch_byte_add)
+- [`AtomicPtr::fetch_byte_sub`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicPtr.html#method.fetch_byte_sub)
+- [`AtomicPtr::fetch_or`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicPtr.html#method.fetch_or)
+- [`AtomicPtr::fetch_and`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicPtr.html#method.fetch_and)
+- [`AtomicPtr::fetch_xor`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicPtr.html#method.fetch_xor)
+- [`{integer}::strict_add`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.strict_add)
+- [`{integer}::strict_sub`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.strict_sub)
+- [`{integer}::strict_mul`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.strict_mul)
+- [`{integer}::strict_div`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.strict_div)
+- [`{integer}::strict_div_euclid`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.strict_div_euclid)
+- [`{integer}::strict_rem`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.strict_rem)
+- [`{integer}::strict_rem_euclid`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.strict_rem_euclid)
+- [`{integer}::strict_neg`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.strict_neg)
+- [`{integer}::strict_shl`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.strict_shl)
+- [`{integer}::strict_shr`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.strict_shr)
+- [`{integer}::strict_pow`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.strict_pow)
+- [`i{N}::strict_add_unsigned`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.strict_add_unsigned)
+- [`i{N}::strict_sub_unsigned`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.strict_sub_unsigned)
+- [`i{N}::strict_abs`](https://doc.rust-lang.org/stable/std/primitive.i32.html#method.strict_abs)
+- [`u{N}::strict_add_signed`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.strict_add_signed)
+- [`u{N}::strict_sub_signed`](https://doc.rust-lang.org/stable/std/primitive.u32.html#method.strict_sub_signed)
+- [`PanicHookInfo::payload_as_str`](https://doc.rust-lang.org/stable/std/panic/struct.PanicHookInfo.html#method.payload_as_str)
+- [`core::iter::chain`](https://doc.rust-lang.org/stable/core/iter/fn.chain.html)
+- [`u{N}::checked_signed_diff`](https://doc.rust-lang.org/stable/std/primitive.u16.html#method.checked_signed_diff)
+- [`core::array::repeat`](https://doc.rust-lang.org/stable/core/array/fn.repeat.html)
+- [`PathBuf::add_extension`](https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#method.add_extension)
+- [`PathBuf::with_added_extension`](https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#method.with_added_extension)
+- [`Duration::from_mins`](https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.from_mins)
+- [`Duration::from_hours`](https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.from_hours)
+- [`impl PartialEq for PathBuf`](https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#impl-PartialEq%3Cstr%3E-for-PathBuf)
+- [`impl PartialEq for PathBuf`](https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#impl-PartialEq%3CString%3E-for-PathBuf)
+- [`impl PartialEq for Path`](https://doc.rust-lang.org/stable/std/path/struct.Path.html#impl-PartialEq%3Cstr%3E-for-Path)
+- [`impl PartialEq for Path`](https://doc.rust-lang.org/stable/std/path/struct.Path.html#impl-PartialEq%3CString%3E-for-Path)
+- [`impl PartialEq for String`](https://doc.rust-lang.org/stable/std/string/struct.String.html#impl-PartialEq%3CPathBuf%3E-for-String)
+- [`impl PartialEq for String`](https://doc.rust-lang.org/stable/std/string/struct.String.html#impl-PartialEq%3CPath%3E-for-String)
+- [`impl PartialEq for str`](https://doc.rust-lang.org/stable/std/primitive.str.html#impl-PartialEq%3CPathBuf%3E-for-str)
+- [`impl PartialEq for str`](https://doc.rust-lang.org/stable/std/primitive.str.html#impl-PartialEq%3CPath%3E-for-str)
+- [`Ipv4Addr::from_octets`](https://doc.rust-lang.org/stable/std/net/struct.Ipv4Addr.html#method.from_octets)
+- [`Ipv6Addr::from_octets`](https://doc.rust-lang.org/stable/std/net/struct.Ipv6Addr.html#method.from_octets)
+- [`Ipv6Addr::from_segments`](https://doc.rust-lang.org/stable/std/net/struct.Ipv6Addr.html#method.from_segments)
+- [`impl Default for Pin> where Box: Default, T: ?Sized`](https://doc.rust-lang.org/stable/std/default/trait.Default.html#impl-Default-for-Pin%3CBox%3CT%3E%3E)
+- [`impl Default for Pin> where Rc: Default, T: ?Sized`](https://doc.rust-lang.org/stable/std/default/trait.Default.html#impl-Default-for-Pin%3CRc%3CT%3E%3E)
+- [`impl Default for Pin> where Arc: Default, T: ?Sized`](https://doc.rust-lang.org/stable/std/default/trait.Default.html#impl-Default-for-Pin%3CArc%3CT%3E%3E)
+- [`Cell::as_array_of_cells`](https://doc.rust-lang.org/stable/std/cell/struct.Cell.html#method.as_array_of_cells)
+- [`u{N}::carrying_add`](https://doc.rust-lang.org/stable/std/primitive.u64.html#method.carrying_add)
+- [`u{N}::borrowing_sub`](https://doc.rust-lang.org/stable/std/primitive.u64.html#method.borrowing_sub)
+- [`u{N}::carrying_mul`](https://doc.rust-lang.org/stable/std/primitive.u64.html#method.carrying_mul)
+- [`u{N}::carrying_mul_add`](https://doc.rust-lang.org/stable/std/primitive.u64.html#method.carrying_mul_add)
+- [`BTreeMap::extract_if`](https://doc.rust-lang.org/stable/std/collections/struct.BTreeMap.html#method.extract_if)
+- [`BTreeSet::extract_if`](https://doc.rust-lang.org/stable/std/collections/struct.BTreeSet.html#method.extract_if)
+- [`impl Debug for windows::ffi::EncodeWide<'_>`](https://doc.rust-lang.org/stable/std/os/windows/ffi/struct.EncodeWide.html#impl-Debug-for-EncodeWide%3C'_%3E)
+- [`str::ceil_char_boundary`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.ceil_char_boundary)
+- [`str::floor_char_boundary`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.floor_char_boundary)
+- [`impl Sum for Saturating`](https://doc.rust-lang.org/stable/std/num/struct.Saturating.html#impl-Sum-for-Saturating%3Cu32%3E)
+- [`impl Sum<&Self> for Saturating`](https://doc.rust-lang.org/stable/std/num/struct.Saturating.html#impl-Sum%3C%26Saturating%3Cu32%3E%3E-for-Saturating%3Cu32%3E)
+- [`impl Product for Saturating`](https://doc.rust-lang.org/stable/std/num/struct.Saturating.html#impl-Product-for-Saturating%3Cu32%3E)
+- [`impl Product<&Self> for Saturating`](https://doc.rust-lang.org/stable/std/num/struct.Saturating.html#impl-Product%3C%26Saturating%3Cu32%3E%3E-for-Saturating%3Cu32%3E)
+
+These previously stable APIs are now stable in const contexts:
+
+- [`<[T; N]>::each_ref`](https://doc.rust-lang.org/stable/std/primitive.array.html#method.each_ref)
+- [`<[T; N]>::each_mut`](https://doc.rust-lang.org/stable/std/primitive.array.html#method.each_mut)
+- [`OsString::new`](https://doc.rust-lang.org/stable/std/ffi/struct.OsString.html#method.new)
+- [`PathBuf::new`](https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#method.new)
+- [`TypeId::of`](https://doc.rust-lang.org/stable/std/any/struct.TypeId.html#method.of)
+- [`ptr::with_exposed_provenance`](https://doc.rust-lang.org/stable/std/ptr/fn.with_exposed_provenance.html)
+- [`ptr::with_exposed_provenance_mut`](https://doc.rust-lang.org/stable/std/ptr/fn.with_exposed_provenance_mut.html)
+
+
+
+Cargo
+-----
+
+- 🎉 Stabilize `build.build-dir`.
+  This config sets the directory where intermediate build artifacts are stored.
+  These artifacts are produced by Cargo and rustc during the build process.
+  End users usually won't need to interact with them, and the layout inside
+  `build-dir` is an implementation detail that may change without notice.
+  ([config doc](https://doc.rust-lang.org/stable/cargo/reference/config.html#buildbuild-dir))
+  ([build cache doc](https://doc.rust-lang.org/stable/cargo/reference/build-cache.html))
+  [#15833](https://github.com/rust-lang/cargo/pull/15833)
+  [#15840](https://github.com/rust-lang/cargo/pull/15840)
+- The `--target` flag and the `build.target` configuration can now take literal
+  `"host-tuple"` string, which will internally be substituted by the host
+  machine's target triple.
+  [#15838](https://github.com/rust-lang/cargo/pull/15838)
+  [#16003](https://github.com/rust-lang/cargo/pull/16003)
+  [#16032](https://github.com/rust-lang/cargo/pull/16032)
+
+
+
+Rustdoc
+-----
+- [In search results, rank doc aliases lower than non-alias items with the same name](https://github.com/rust-lang/rust/pull/145100)
+- [Raw pointers now work in type-based search like references](https://github.com/rust-lang/rust/pull/145731). This means you can now search for things like `*const u8 ->`, and additionally functions that take or return raw pointers will now display their signature properly in search results.
+
+
+
+Compatibility Notes
+-------------------
+
+- [Always require coroutine captures to be drop-live](https://github.com/rust-lang/rust/pull/144156)
+- [Apple: Always pass SDK root when linking with `cc`, and pass it via `SDKROOT` env var](https://github.com/rust-lang/rust/pull/131477). This should fix linking issues with `rustc` running inside Xcode. Libraries in `/usr/local/lib` may no longer be linked automatically, if you develop or use a crate that relies on this, you should explicitly set `cargo::rustc-link-search=/usr/local/lib` in a `build.rs` script.
+- [Relaxed bounds in associated type bound position like in `TraitRef` are now correctly forbidden](https://github.com/rust-lang/rust/pull/135331)
+- [Add unstable `#[sanitize(xyz = "on|off")]` built-in attribute that shadows procedural macros with the same name](https://github.com/rust-lang/rust/pull/142681)
+- [Fix the drop checker being more permissive for bindings declared with let-else](https://github.com/rust-lang/rust/pull/143028)
+- [Be more strict when parsing attributes, erroring on many invalid attributes](https://github.com/rust-lang/rust/pull/144689)
+    - [Error on invalid `#[should_panic]` attributes](https://github.com/rust-lang/rust/pull/143808)
+    - [Error on invalid `#[link]` attributes](https://github.com/rust-lang/rust/pull/143193)
+- [Mark all deprecation lints in name resolution as deny-by-default and also report in dependencies](https://github.com/rust-lang/rust/pull/143929)
+- The lint `semicolon_in_expressions_from_macros`, for `macro_rules!` macros in expression position that expand to end in a semicolon (`;`), is now deny-by-default. It was already warn-by-default, and a future compatibility warning (FCW) that warned even in dependencies. This lint will become a hard error in the future.
+- [Trait impl modifiers (e.g., `unsafe`, `!`, `default`) in inherent impls are no longer syntactically valid](https://github.com/rust-lang/rust/pull/144386)
+- [Start reporting future breakage for `ill_formed_attribute_input` in dependencies](https://github.com/rust-lang/rust/pull/144544)
+- [Restrict the scope of temporaries created by the macros `pin!`, `format_args!`, `write!`, and `writeln!` in `if let` scrutinees in Rust Edition 2024.](https://github.com/rust-lang/rust/pull/145342) This applies [Rust Edition 2024's `if let` temporary scope rules](https://doc.rust-lang.org/edition-guide/rust-2024/temporary-if-let-scope.html) to these temporaries, which previously could live past the `if` expression regardless of Edition.
+- [Invalid numeric literal suffixes in tuple indexing, tuple struct indexing, and struct field name positions are now correctly rejected](https://github.com/rust-lang/rust/pull/145463)
+- [Closures marked with the keyword `static` are now syntactically invalid](https://github.com/rust-lang/rust/pull/145604)
+- [Shebangs inside `--cfg` and `--check-cfg` arguments are no longer allowed](https://github.com/rust-lang/rust/pull/146211)
+- [Add future incompatibility lint for temporary lifetime shortening in Rust 1.92](https://github.com/rust-lang/rust/pull/147056)
+
+Cargo compatibility notes:
+
+- `cargo publish` no longer keeps `.crate` tarballs as final build artifacts
+  when `build.build-dir` is set. These tarballs were previously included due to
+  an oversight and are now treated as intermediate artifacts.
+  To get `.crate` tarballs as final artifacts, use `cargo package`.
+  In a future version, this change will apply regardless of `build.build-dir`.
+  [#15910](https://github.com/rust-lang/cargo/pull/15910)
+- Adjust Cargo messages to match rustc diagnostic style.
+  This changes some of the terminal colors used by Cargo messages.
+  [#15928](https://github.com/rust-lang/cargo/pull/15928)
+- Tools and projects relying on the
+  [internal details of Cargo's `build-dir`](https://doc.rust-lang.org/cargo/reference/build-cache.html)
+  may not work for users changing their `build-dir` layout.
+  For those doing so, we'd recommend proactively testing these cases
+  particularly as we are considering changing the default location of the `build-dir` in the future
+  ([cargo#16147](https://github.com/rust-lang/cargo/issues/16147)).
+  If you can't migrate off of Cargo's internal details,
+  we'd like to learn more about your use case as we prepare to change the layout of the `build-dir`
+  ([cargo#15010](https://github.com/rust-lang/cargo/issues/15010)).
+
+
+
+Internal Changes
+----------------
+
+These changes do not affect any public interfaces of Rust, but they represent
+significant improvements to the performance or internals of rustc and related
+tools.
+
+- [Update to LLVM 21](https://github.com/rust-lang/rust/pull/143684)
+
+
+Version 1.90.0 (2025-09-18)
+===========================
+
+
+
+Language
+--------
+- [Split up the `unknown_or_malformed_diagnostic_attributes` lint](https://github.com/rust-lang/rust/pull/140717). This lint has been split up into four finer-grained lints, with `unknown_or_malformed_diagnostic_attributes` now being the lint group that contains these lints:
+    1. `unknown_diagnostic_attributes`: unknown to the current compiler
+    2. `misplaced_diagnostic_attributes`: placed on the wrong item
+    3. `malformed_diagnostic_attributes`: malformed attribute syntax or options
+    4. `malformed_diagnostic_format_literals`: malformed format string literal
+- [Allow constants whose final value has references to mutable/external memory, but reject such constants as patterns](https://github.com/rust-lang/rust/pull/140942)
+- [Allow volatile access to non-Rust memory, including address 0](https://github.com/rust-lang/rust/pull/141260)
+
+
+
+
+Compiler
+--------
+- [Use `lld` by default on `x86_64-unknown-linux-gnu`](https://github.com/rust-lang/rust/pull/140525).
+- [Tier 3 `musl` targets now link dynamically by default](https://github.com/rust-lang/rust/pull/144410). Affected targets:
+    - `mips64-unknown-linux-muslabi64`
+    - `powerpc64-unknown-linux-musl`
+    - `powerpc-unknown-linux-musl`
+    - `powerpc-unknown-linux-muslspe`
+    - `riscv32gc-unknown-linux-musl`
+    - `s390x-unknown-linux-musl`
+    - `thumbv7neon-unknown-linux-musleabihf`
+
+
+
+
+Platform Support
+----------------
+- [Demote `x86_64-apple-darwin` to Tier 2 with host tools](https://github.com/rust-lang/rust/pull/145252)
+
+
+Refer to Rust's [platform support page][platform-support-doc]
+for more information on Rust's tiered platform support.
+
+[platform-support-doc]: https://doc.rust-lang.org/rustc/platform-support.html
+
+
+
+Libraries
+---------
+- [Stabilize `u*::{checked,overflowing,saturating,wrapping}_sub_signed`](https://github.com/rust-lang/rust/issues/126043)
+- [Allow comparisons between `CStr`, `CString`, and `Cow`](https://github.com/rust-lang/rust/pull/137268)
+- [Remove some unsized tuple impls since unsized tuples can't be constructed](https://github.com/rust-lang/rust/pull/138340)
+- [Set `MSG_NOSIGNAL` for `UnixStream`](https://github.com/rust-lang/rust/pull/140005)
+- [`proc_macro::Ident::new` now supports `$crate`.](https://github.com/rust-lang/rust/pull/141996)
+- [Guarantee the pointer returned from `Thread::into_raw` has at least 8 bytes of alignment](https://github.com/rust-lang/rust/pull/143859)
+
+
+
+
+Stabilized APIs
+---------------
+
+- [`u{n}::checked_sub_signed`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.checked_sub_signed)
+- [`u{n}::overflowing_sub_signed`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.overflowing_sub_signed)
+- [`u{n}::saturating_sub_signed`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.saturating_sub_signed)
+- [`u{n}::wrapping_sub_signed`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.wrapping_sub_signed)
+- [`impl Copy for IntErrorKind`](https://doc.rust-lang.org/stable/std/num/enum.IntErrorKind.html#impl-Copy-for-IntErrorKind)
+- [`impl Hash for IntErrorKind`](https://doc.rust-lang.org/stable/std/num/enum.IntErrorKind.html#impl-Hash-for-IntErrorKind)
+- [`impl PartialEq<&CStr> for CStr`](https://doc.rust-lang.org/stable/std/ffi/struct.CStr.html#impl-PartialEq%3C%26CStr%3E-for-CStr)
+- [`impl PartialEq for CStr`](https://doc.rust-lang.org/stable/std/ffi/struct.CStr.html#impl-PartialEq%3CCString%3E-for-CStr)
+- [`impl PartialEq> for CStr`](https://doc.rust-lang.org/stable/std/ffi/struct.CStr.html#impl-PartialEq%3CCow%3C'_,+CStr%3E%3E-for-CStr)
+- [`impl PartialEq<&CStr> for CString`](https://doc.rust-lang.org/stable/std/ffi/struct.CString.html#impl-PartialEq%3C%26CStr%3E-for-CString)
+- [`impl PartialEq for CString`](https://doc.rust-lang.org/stable/std/ffi/struct.CString.html#impl-PartialEq%3CCStr%3E-for-CString)
+- [`impl PartialEq> for CString`](https://doc.rust-lang.org/stable/std/ffi/struct.CString.html#impl-PartialEq%3CCow%3C'_,+CStr%3E%3E-for-CString)
+- [`impl PartialEq<&CStr> for Cow`](https://doc.rust-lang.org/stable/std/borrow/enum.Cow.html#impl-PartialEq%3C%26CStr%3E-for-Cow%3C'_,+CStr%3E)
+- [`impl PartialEq for Cow`](https://doc.rust-lang.org/stable/std/borrow/enum.Cow.html#impl-PartialEq%3CCStr%3E-for-Cow%3C'_,+CStr%3E)
+- [`impl PartialEq for Cow`](https://doc.rust-lang.org/stable/std/borrow/enum.Cow.html#impl-PartialEq%3CCString%3E-for-Cow%3C'_,+CStr%3E)
+
+
+These previously stable APIs are now stable in const contexts:
+
+- [`<[T]>::reverse`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.reverse)
+- [`f32::floor`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.floor)
+- [`f32::ceil`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.ceil)
+- [`f32::trunc`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.trunc)
+- [`f32::fract`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.fract)
+- [`f32::round`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.round)
+- [`f32::round_ties_even`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.round_ties_even)
+- [`f64::floor`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.floor)
+- [`f64::ceil`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.ceil)
+- [`f64::trunc`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.trunc)
+- [`f64::fract`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.fract)
+- [`f64::round`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.round)
+- [`f64::round_ties_even`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.round_ties_even)
+
+
+
+
+Cargo
+-----
+- [Add `http.proxy-cainfo` config for proxy certs](https://github.com/rust-lang/cargo/pull/15374/)
+- [Use `gix` for `cargo package`](https://github.com/rust-lang/cargo/pull/15534/)
+- [feat(publish): Stabilize multi-package publishing](https://github.com/rust-lang/cargo/pull/15636/)
+
+
+
+Rustdoc
+-----
+- [Add ways to collapse all impl blocks](https://github.com/rust-lang/rust/pull/141663). Previously the "Summary" button and "-" keyboard shortcut would never collapse `impl` blocks, now they do when shift is held
+- [Display unsafe attributes with `unsafe()` wrappers](https://github.com/rust-lang/rust/pull/143662)
+
+
+
+
+Compatibility Notes
+-------------------
+- [Use `lld` by default on `x86_64-unknown-linux-gnu`](https://github.com/rust-lang/rust/pull/140525).
+  See also .
+- [Make `core::iter::Fuse`'s `Default` impl construct `I::default()` internally as promised in the docs instead of always being empty](https://github.com/rust-lang/rust/pull/140985)
+- [Set `MSG_NOSIGNAL` for `UnixStream`](https://github.com/rust-lang/rust/pull/140005)
+  This may change program behavior but results in the same behavior as other primitives (e.g., stdout, network sockets).
+  Programs relying on signals to terminate them should update handling of sockets to handle errors on write by exiting.
+- [On Unix `std::env::home_dir` will use the fallback if the `HOME` environment variable is empty](https://github.com/rust-lang/rust/pull/141840)
+- We now [reject unsupported `extern "{abi}"`s consistently in all positions](https://github.com/rust-lang/rust/pull/142134). This primarily affects the use of implementing traits on an `extern "{abi}"` function pointer, like `extern "stdcall" fn()`, on a platform that doesn't support that, like aarch64-unknown-linux-gnu. Direct usage of these unsupported ABI strings by declaring or defining functions was already rejected, so this is only a change for consistency.
+- [const-eval: error when initializing a static writes to that static](https://github.com/rust-lang/rust/pull/143084)
+- [Check that the `proc_macro_derive` macro has correct arguments when applied to the crate root](https://github.com/rust-lang/rust/pull/143607)
+
+
 Version 1.89.0 (2025-08-07)
 ==========================
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index e85945d633b66..3827c7268c228 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -1607,6 +1607,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         tcx.node_span_lint(MACRO_EXTENDED_TEMPORARY_SCOPES, lint_root, labels, |diag| {
             diag.primary_message("temporary lifetime will be shortened in Rust 1.92");
             diag.note("consider using a `let` binding to create a longer lived value");
+            diag.note("some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`");
         });
     }
 }
diff --git a/src/ci/channel b/src/ci/channel
index 65b2df87f7df3..2bf5ad0447d33 100644
--- a/src/ci/channel
+++ b/src/ci/channel
@@ -1 +1 @@
-beta
+stable
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index f37a8d85361f2..daa6595a65507 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -21,7 +21,7 @@ rustdoc-json-types = { path = "../rustdoc-json-types" }
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
 smallvec = "1.8.1"
-stringdex = { version = "0.0.1-alpha9" }
+stringdex = "=0.0.2"
 tempfile = "3"
 threadpool = "1.8.1"
 tracing = "0.1"
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index 2984f3ab50eea..497a529773831 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -239,6 +239,34 @@ impl SerializedSearchIndex {
         self.alias_pointers.push(alias_pointer);
         index
     }
+    /// Add potential search result to the database and return the row ID.
+    ///
+    /// The returned ID can be used to attach more data to the search result.
+    fn add_entry(&mut self, name: Symbol, entry_data: EntryData, desc: String) -> usize {
+        let fqp = if let Some(module_path_index) = entry_data.module_path {
+            let mut fqp = self.path_data[module_path_index].as_ref().unwrap().module_path.clone();
+            fqp.push(Symbol::intern(&self.names[module_path_index]));
+            fqp.push(name);
+            fqp
+        } else {
+            vec![name]
+        };
+        // If a path with the same name already exists, but no entry does,
+        // we can fill in the entry without having to allocate a new row ID.
+        //
+        // Because paths and entries both share the same index, using the same
+        // ID saves space by making the tree smaller.
+        if let Some(&other_path) = self.crate_paths_index.get(&(entry_data.ty, fqp))
+            && self.entry_data[other_path].is_none()
+            && self.descs[other_path].is_empty()
+        {
+            self.entry_data[other_path] = Some(entry_data);
+            self.descs[other_path] = desc;
+            other_path
+        } else {
+            self.push(name.as_str().to_string(), None, Some(entry_data), desc, None, None, None)
+        }
+    }
     fn push_path(&mut self, name: String, path_data: PathData) -> usize {
         self.push(name, Some(path_data), None, String::new(), None, None, None)
     }
@@ -1513,10 +1541,9 @@ pub(crate) fn build_index(
             .as_ref()
             .map(|path| serialized_index.get_id_by_module_path(path));
 
-        let new_entry_id = serialized_index.push(
-            item.name.as_str().to_string(),
-            None,
-            Some(EntryData {
+        let new_entry_id = serialized_index.add_entry(
+            item.name,
+            EntryData {
                 ty: item.ty,
                 parent: item.parent_idx,
                 module_path,
@@ -1535,11 +1562,8 @@ pub(crate) fn build_index(
                     None
                 },
                 krate: crate_idx,
-            }),
+            },
             item.desc.to_string(),
-            None, // filled in after all the types have been indexed
-            None,
-            None,
         );
 
         // Aliases
diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts
index 938ccc7d2c32e..951eb2291b89e 100644
--- a/src/librustdoc/html/static/js/rustdoc.d.ts
+++ b/src/librustdoc/html/static/js/rustdoc.d.ts
@@ -348,7 +348,7 @@ declare namespace rustdoc {
         returned: rustdoc.QueryElement[],
         is_alias: boolean,
         alias?: string,
-        original?: rustdoc.Rlow,
+        item: rustdoc.Row,
     }
 
     /**
@@ -533,4 +533,27 @@ declare namespace rustdoc {
      * Generated by `render_call_locations` in `render/mod.rs`.
      */
     type ScrapedLoc = [[number, number], string, string]
+
+    /**
+     * Each of these identifiers are used specially by
+     * type-driven search. Most of them are lang items
+     * in the compiler.
+     */
+    type TypeNameIds = {
+        "typeNameIdOfOutput": number,
+        "typeNameIdOfFnPtr": number,
+        "typeNameIdOfFn": number,
+        "typeNameIdOfFnMut": number,
+        "typeNameIdOfFnOnce": number,
+        "typeNameIdOfArray": number,
+        "typeNameIdOfSlice": number,
+        "typeNameIdOfArrayOrSlice": number,
+        "typeNameIdOfTuple": number,
+        "typeNameIdOfUnit": number,
+        "typeNameIdOfTupleOrUnit": number,
+        "typeNameIdOfReference": number,
+        "typeNameIdOfPointer": number,
+        "typeNameIdOfHof": number,
+        "typeNameIdOfNever": number,
+    };
 }
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 3b84ae2bed060..482134933a61e 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -1190,17 +1190,6 @@ class DocSearch {
         this.rootPath = rootPath;
         this.database = database;
 
-        this.typeNameIdOfOutput = -1;
-        this.typeNameIdOfArray = -1;
-        this.typeNameIdOfSlice = -1;
-        this.typeNameIdOfArrayOrSlice = -1;
-        this.typeNameIdOfTuple = -1;
-        this.typeNameIdOfUnit = -1;
-        this.typeNameIdOfTupleOrUnit = -1;
-        this.typeNameIdOfReference = -1;
-        this.typeNameIdOfPointer = -1;
-        this.typeNameIdOfHof = -1;
-
         this.utf8decoder = new TextDecoder();
 
         /** @type {Map} */
@@ -1208,14 +1197,49 @@ class DocSearch {
     }
 
     /**
-     * Load search index. If you do not call this function, `execQuery`
-     * will never fulfill.
+     * Load type name ID set.
+     *
+     * Each of these identifiers are used specially by
+     * type-driven search. Most of them are lang items
+     * in the compiler.
+     *
+     * Use this function, which caches the result, and not
+     * getTypeNameIdsAsync, which is an internal implementation
+     * detail for this.
+     *
+     * @return {Promise|rustdoc.TypeNameIds}
      */
-    async buildIndex() {
+    getTypeNameIds() {
+        if (this.typeNameIds) {
+            return this.typeNameIds;
+        }
         const nn = this.database.getData("normalizedName");
         if (!nn) {
-            return;
+            return {
+                typeNameIdOfOutput: -1,
+                typeNameIdOfFnPtr: -1,
+                typeNameIdOfFn: -1,
+                typeNameIdOfFnMut: -1,
+                typeNameIdOfFnOnce: -1,
+                typeNameIdOfArray: -1,
+                typeNameIdOfSlice: -1,
+                typeNameIdOfArrayOrSlice: -1,
+                typeNameIdOfTuple: -1,
+                typeNameIdOfUnit: -1,
+                typeNameIdOfTupleOrUnit: -1,
+                typeNameIdOfReference: -1,
+                typeNameIdOfPointer: -1,
+                typeNameIdOfHof: -1,
+                typeNameIdOfNever: -1,
+            };
         }
+        return this.getTypeNameIdsAsync(nn);
+    }
+    /**
+     * @param {stringdex.DataColumn} nn
+     * @returns {Promise}
+     */
+    async getTypeNameIdsAsync(nn) {
         // Each of these identifiers are used specially by
         // type-driven search.
         const [
@@ -1274,21 +1298,39 @@ class DocSearch {
             }
             return -1;
         };
-        this.typeNameIdOfOutput = await first(output, TY_ASSOCTYPE, "");
-        this.typeNameIdOfFnPtr = await first(fn, TY_PRIMITIVE, "");
-        this.typeNameIdOfFn = await first(fn, TY_TRAIT, "core::ops");
-        this.typeNameIdOfFnMut = await first(fnMut, TY_TRAIT, "core::ops");
-        this.typeNameIdOfFnOnce = await first(fnOnce, TY_TRAIT, "core::ops");
-        this.typeNameIdOfArray = await first(array, TY_PRIMITIVE, "");
-        this.typeNameIdOfSlice = await first(slice, TY_PRIMITIVE, "");
-        this.typeNameIdOfArrayOrSlice = await first(arrayOrSlice, TY_PRIMITIVE, "");
-        this.typeNameIdOfTuple = await first(tuple, TY_PRIMITIVE, "");
-        this.typeNameIdOfUnit = await first(unit, TY_PRIMITIVE, "");
-        this.typeNameIdOfTupleOrUnit = await first(tupleOrUnit, TY_PRIMITIVE, "");
-        this.typeNameIdOfReference = await first(reference, TY_PRIMITIVE, "");
-        this.typeNameIdOfPointer = await first(pointer, TY_PRIMITIVE, "");
-        this.typeNameIdOfHof = await first(hof, TY_PRIMITIVE, "");
-        this.typeNameIdOfNever = await first(never, TY_PRIMITIVE, "");
+        const typeNameIdOfOutput = await first(output, TY_ASSOCTYPE, "");
+        const typeNameIdOfFnPtr = await first(fn, TY_PRIMITIVE, "");
+        const typeNameIdOfFn = await first(fn, TY_TRAIT, "core::ops");
+        const typeNameIdOfFnMut = await first(fnMut, TY_TRAIT, "core::ops");
+        const typeNameIdOfFnOnce = await first(fnOnce, TY_TRAIT, "core::ops");
+        const typeNameIdOfArray = await first(array, TY_PRIMITIVE, "");
+        const typeNameIdOfSlice = await first(slice, TY_PRIMITIVE, "");
+        const typeNameIdOfArrayOrSlice = await first(arrayOrSlice, TY_PRIMITIVE, "");
+        const typeNameIdOfTuple = await first(tuple, TY_PRIMITIVE, "");
+        const typeNameIdOfUnit = await first(unit, TY_PRIMITIVE, "");
+        const typeNameIdOfTupleOrUnit = await first(tupleOrUnit, TY_PRIMITIVE, "");
+        const typeNameIdOfReference = await first(reference, TY_PRIMITIVE, "");
+        const typeNameIdOfPointer = await first(pointer, TY_PRIMITIVE, "");
+        const typeNameIdOfHof = await first(hof, TY_PRIMITIVE, "");
+        const typeNameIdOfNever = await first(never, TY_PRIMITIVE, "");
+        this.typeNameIds = {
+            typeNameIdOfOutput,
+            typeNameIdOfFnPtr,
+            typeNameIdOfFn,
+            typeNameIdOfFnMut,
+            typeNameIdOfFnOnce,
+            typeNameIdOfArray,
+            typeNameIdOfSlice,
+            typeNameIdOfArrayOrSlice,
+            typeNameIdOfTuple,
+            typeNameIdOfUnit,
+            typeNameIdOfTupleOrUnit,
+            typeNameIdOfReference,
+            typeNameIdOfPointer,
+            typeNameIdOfHof,
+            typeNameIdOfNever,
+        };
+        return this.typeNameIds;
     }
 
     /**
@@ -1758,12 +1800,8 @@ class DocSearch {
         const l = crateNames.length;
         const names = [];
         for (let i = 0; i < l; ++i) {
-            names.push(crateNames.at(i).then(name => {
-                if (name === undefined) {
-                    return "";
-                }
-                return this.utf8decoder.decode(name);
-            }));
+            const name = await crateNames.at(i);
+            names.push(name === undefined ? "" : this.utf8decoder.decode(name));
         }
         return Promise.all(names);
     }
@@ -1820,6 +1858,9 @@ class DocSearch {
             modulePathData,
             exactModuleName,
             exactModulePathData,
+            parentName,
+            parentPath,
+            crate,
         ] = await Promise.all([
             entry && entry.modulePath !== null ? this.getName(entry.modulePath) : null,
             entry && entry.modulePath !== null ? this.getPathData(entry.modulePath) : null,
@@ -1829,6 +1870,13 @@ class DocSearch {
             entry && entry.exactModulePath !== null ?
                 this.getPathData(entry.exactModulePath) :
                 null,
+            entry && entry.parent !== null ?
+                this.getName(entry.parent) :
+                null,
+            entry && entry.parent !== null ?
+                this.getPathData(entry.parent) :
+                null,
+            entry ? nonnull(await this.getName(entry.krate)) : "",
         ]);
         const name = name_ === null ? "" : name_;
         const normalizedName = (name.indexOf("_") === -1 ?
@@ -1838,12 +1886,9 @@ class DocSearch {
             (modulePathData.modulePath === "" ?
                 moduleName :
                 `${modulePathData.modulePath}::${moduleName}`);
-        const [parentName, parentPath] = entry !== null && entry.parent !== null ?
-            await Promise.all([this.getName(entry.parent), this.getPathData(entry.parent)]) :
-            [null, null];
         return {
             id,
-            crate: entry ? nonnull(await this.getName(entry.krate)) : "",
+            crate,
             ty: entry ? entry.ty : nonnull(path).ty,
             name,
             normalizedName,
@@ -2148,6 +2193,7 @@ class DocSearch {
          * @returns {Promise}
          */
         const formatDisplayTypeSignature = async(obj, typeInfo, elems, returned) => {
+            const typeNameIds = await this.getTypeNameIds();
             const objType = obj.type;
             if (!objType) {
                 return {type: [], mappedNames: new Map(), whereClause: new Map()};
@@ -2173,10 +2219,12 @@ class DocSearch {
                                 return true;
                             },
                             0,
+                            typeNameIds,
                         );
                         return !!fnOutput;
                     },
                     0,
+                    typeNameIds,
                 );
             } else {
                 const highlighted = unifyFunctionTypes(
@@ -2189,6 +2237,7 @@ class DocSearch {
                         return true;
                     },
                     0,
+                    typeNameIds,
                 );
                 if (typeInfo === "elems") {
                     fnInputs = highlighted;
@@ -2268,7 +2317,7 @@ class DocSearch {
              * @returns {Promise}
              */
             const writeHof = async(fnType, result) => {
-                const hofOutput = fnType.bindings.get(this.typeNameIdOfOutput) || [];
+                const hofOutput = fnType.bindings.get(typeNameIds.typeNameIdOfOutput) || [];
                 const hofInputs = fnType.generics;
                 pushText(fnType, result);
                 pushText({name: " (", highlighted: false}, result);
@@ -2309,11 +2358,14 @@ class DocSearch {
              * @returns {Promise}
              */
             const writeSpecialPrimitive = async(fnType, result) => {
-                if (fnType.id === this.typeNameIdOfArray || fnType.id === this.typeNameIdOfSlice ||
-                    fnType.id === this.typeNameIdOfTuple || fnType.id === this.typeNameIdOfUnit) {
+                if (fnType.id === typeNameIds.typeNameIdOfArray ||
+                    fnType.id === typeNameIds.typeNameIdOfSlice ||
+                    fnType.id === typeNameIds.typeNameIdOfTuple ||
+                    fnType.id === typeNameIds.typeNameIdOfUnit
+                ) {
                     const [ob, sb] =
-                        fnType.id === this.typeNameIdOfArray ||
-                            fnType.id === this.typeNameIdOfSlice ?
+                        fnType.id === typeNameIds.typeNameIdOfArray ||
+                            fnType.id === typeNameIds.typeNameIdOfSlice ?
                         ["[", "]"] :
                         ["(", ")"];
                     pushText({ name: ob, highlighted: fnType.highlighted }, result);
@@ -2325,7 +2377,7 @@ class DocSearch {
                     );
                     pushText({ name: sb, highlighted: fnType.highlighted }, result);
                     return true;
-                } else if (fnType.id === this.typeNameIdOfReference) {
+                } else if (fnType.id === typeNameIds.typeNameIdOfReference) {
                     pushText({ name: "&", highlighted: fnType.highlighted }, result);
                     let prevHighlighted = false;
                     await onEachBtwnAsync(
@@ -2341,7 +2393,7 @@ class DocSearch {
                         }, result),
                     );
                     return true;
-                } else if (fnType.id === this.typeNameIdOfPointer) {
+                } else if (fnType.id === typeNameIds.typeNameIdOfPointer) {
                     pushText({ name: "*", highlighted: fnType.highlighted }, result);
                     if (fnType.generics.length < 2) {
                         pushText({ name: "const ", highlighted: fnType.highlighted }, result);
@@ -2361,14 +2413,14 @@ class DocSearch {
                     );
                     return true;
                 } else if (
-                    fnType.id === this.typeNameIdOfFn ||
-                    fnType.id === this.typeNameIdOfFnMut ||
-                    fnType.id === this.typeNameIdOfFnOnce ||
-                    fnType.id === this.typeNameIdOfFnPtr
+                    fnType.id === typeNameIds.typeNameIdOfFn ||
+                    fnType.id === typeNameIds.typeNameIdOfFnMut ||
+                    fnType.id === typeNameIds.typeNameIdOfFnOnce ||
+                    fnType.id === typeNameIds.typeNameIdOfFnPtr
                 ) {
                     await writeHof(fnType, result);
                     return true;
-                } else if (fnType.id === this.typeNameIdOfNever) {
+                } else if (fnType.id === typeNameIds.typeNameIdOfNever) {
                     pushText({ name: "!", highlighted: fnType.highlighted }, result);
                     return true;
                 }
@@ -2426,10 +2478,10 @@ class DocSearch {
                             return;
                         }
                     } else if (fnType.ty === TY_TRAIT && (
-                        fnType.id === this.typeNameIdOfFn ||
-                        fnType.id === this.typeNameIdOfFnMut ||
-                        fnType.id === this.typeNameIdOfFnOnce ||
-                        fnType.id === this.typeNameIdOfFnPtr
+                        fnType.id === typeNameIds.typeNameIdOfFn ||
+                        fnType.id === typeNameIds.typeNameIdOfFnMut ||
+                        fnType.id === typeNameIds.typeNameIdOfFnOnce ||
+                        fnType.id === typeNameIds.typeNameIdOfFnPtr
                     )) {
                         await writeHof(fnType, result);
                         return;
@@ -2540,7 +2592,7 @@ class DocSearch {
          * Add extra data to result objects, and filter items that have been
          * marked for removal.
          *
-         * @param {[rustdoc.PlainResultObject, rustdoc.Row][]} results
+         * @param {rustdoc.PlainResultObject[]} results
          * @param {"sig"|"elems"|"returned"|null} typeInfo
          * @param {Set} duplicates
          * @returns {rustdoc.ResultObject[]}
@@ -2548,7 +2600,8 @@ class DocSearch {
         const transformResults = (results, typeInfo, duplicates) => {
             const out = [];
 
-            for (const [result, item] of results) {
+            for (const result of results) {
+                const item = result.item;
                 if (item.id !== -1) {
                     const res = buildHrefAndPath(item);
                     // many of these properties don't strictly need to be
@@ -2633,7 +2686,7 @@ class DocSearch {
                 const normalizedUserQuery = parsedQuery.userQuery.toLowerCase();
                 const isMixedCase = normalizedUserQuery !== userQuery;
                 /**
-                 * @type {[rustdoc.PlainResultObject, rustdoc.Row][]}
+                 * @type {rustdoc.PlainResultObject[]}
                  */
                 const result_list = [];
                 for (const result of results.values()) {
@@ -2641,23 +2694,22 @@ class DocSearch {
                         continue;
                     }
                     /**
-                     * @type {rustdoc.Row?}
+                     * @type {rustdoc.Row}
                      */
-                    const item = await this.getRow(result.id, typeInfo !== null);
-                    if (!item) {
-                        continue;
-                    }
+                    const item = result.item;
                     if (filterCrates !== null && item.crate !== filterCrates) {
                         continue;
                     }
                     if (item) {
-                        result_list.push([result, item]);
+                        result_list.push(result);
                     } else {
                         continue;
                     }
                 }
 
-                result_list.sort(([aaa, aai], [bbb, bbi]) => {
+                result_list.sort((aaa, bbb) => {
+                    const aai = aaa.item;
+                    const bbi = bbb.item;
                     /** @type {number} */
                     let a;
                     /** @type {number} */
@@ -2804,6 +2856,7 @@ class DocSearch {
          * @param {number} unboxingDepth
          *     - Limit checks that Ty matches Vec,
          *       but not Vec>>>>
+         * @param {rustdoc.TypeNameIds} typeNameIds
          *
          * @return {rustdoc.HighlightedFunctionType[]|null}
          *     - Returns highlighted results if a match, null otherwise.
@@ -2815,6 +2868,7 @@ class DocSearch {
             mgensIn,
             solutionCb,
             unboxingDepth,
+            typeNameIds,
         ) {
             if (unboxingDepth >= UNBOXING_LIMIT) {
                 return null;
@@ -2837,7 +2891,12 @@ class DocSearch {
                 && queryElems[0].bindings.size === 0) {
                 const queryElem = queryElems[0];
                 for (const [i, fnType] of fnTypesIn.entries()) {
-                    if (!unifyFunctionTypeIsMatchCandidate(fnType, queryElem, mgens)) {
+                    if (!unifyFunctionTypeIsMatchCandidate(
+                        fnType,
+                        queryElem,
+                        mgens,
+                        typeNameIds,
+                    )) {
                         continue;
                     }
                     if (fnType.id !== null &&
@@ -2873,6 +2932,7 @@ class DocSearch {
                                 mgens ? new Map(mgens) : null,
                                 solutionCb,
                                 unboxingDepth,
+                                typeNameIds,
                             ) || fnType.generics,
                         });
                         return highlighted;
@@ -2885,6 +2945,7 @@ class DocSearch {
                         whereClause,
                         mgens,
                         unboxingDepth + 1,
+                        typeNameIds,
                     )) {
                         continue;
                     }
@@ -2898,6 +2959,7 @@ class DocSearch {
                             mgens,
                             solutionCb,
                             unboxingDepth + 1,
+                            typeNameIds,
                         );
                         if (highlightedGenerics) {
                             const highlighted = [...fnTypesIn];
@@ -2916,6 +2978,7 @@ class DocSearch {
                             mgens ? new Map(mgens) : null,
                             solutionCb,
                             unboxingDepth + 1,
+                            typeNameIds,
                         );
                         if (highlightedGenerics) {
                             const highlighted = [...fnTypesIn];
@@ -2960,7 +3023,12 @@ class DocSearch {
             let queryElemsTmp = null;
             for (let i = flast; i >= 0; i -= 1) {
                 const fnType = fnTypes[i];
-                if (!unifyFunctionTypeIsMatchCandidate(fnType, queryElem, mgens)) {
+                if (!unifyFunctionTypeIsMatchCandidate(
+                    fnType,
+                    queryElem,
+                    mgens,
+                    typeNameIds,
+                )) {
                     continue;
                 }
                 let mgensScratch;
@@ -3004,6 +3072,7 @@ class DocSearch {
                             whereClause,
                             mgensScratch,
                             unboxingDepth,
+                            typeNameIds,
                         );
                         if (!solution) {
                             return false;
@@ -3017,6 +3086,7 @@ class DocSearch {
                                 simplifiedMgens,
                                 solutionCb,
                                 unboxingDepth,
+                                typeNameIds,
                             );
                             if (unifiedGenerics !== null) {
                                 unifiedGenericsMgens = simplifiedMgens;
@@ -3026,6 +3096,7 @@ class DocSearch {
                         return false;
                     },
                     unboxingDepth,
+                    typeNameIds,
                 );
                 if (passesUnification) {
                     passesUnification.length = fl;
@@ -3042,6 +3113,7 @@ class DocSearch {
                                 unifiedGenericsMgens,
                                 solutionCb,
                                 unboxingDepth,
+                                typeNameIds,
                             // @ts-expect-error
                             ) : unifiedGenerics.splice(0, v.length)];
                         })),
@@ -3061,6 +3133,7 @@ class DocSearch {
                     whereClause,
                     mgens,
                     unboxingDepth + 1,
+                    typeNameIds,
                 )) {
                     continue;
                 }
@@ -3077,6 +3150,7 @@ class DocSearch {
                     mgens,
                     solutionCb,
                     unboxingDepth + 1,
+                    typeNameIds,
                 );
                 if (passesUnification) {
                     const highlightedGenerics = passesUnification.slice(
@@ -3117,6 +3191,7 @@ class DocSearch {
          * @param {number} unboxingDepth
          *     - Limit checks that Ty matches Vec,
          *       but not Vec>>>>
+         * @param {rustdoc.TypeNameIds} typeNameIds
          *
          * @return {rustdoc.HighlightedFunctionType[]|null}
          *     - Returns highlighted results if a match, null otherwise.
@@ -3128,6 +3203,7 @@ class DocSearch {
             mgensIn,
             solutionCb,
             unboxingDepth,
+            typeNameIds,
         ) {
             if (unboxingDepth >= UNBOXING_LIMIT) {
                 return null;
@@ -3145,7 +3221,12 @@ class DocSearch {
             }
             const fnType = fnTypesIn[0];
             const queryElem = queryElems[0];
-            if (unifyFunctionTypeIsMatchCandidate(fnType, queryElem, mgens)) {
+            if (unifyFunctionTypeIsMatchCandidate(
+                fnType,
+                queryElem,
+                mgens,
+                typeNameIds,
+            )) {
                 if (fnType.id !== null &&
                     fnType.id < 0 &&
                     queryElem.id !== null &&
@@ -3163,6 +3244,7 @@ class DocSearch {
                             mgensScratch,
                             solutionCb,
                             unboxingDepth,
+                            typeNameIds,
                         );
                         if (fnTypesRemaining) {
                             const highlighted = [fnType, ...fnTypesRemaining];
@@ -3189,6 +3271,7 @@ class DocSearch {
                                 whereClause,
                                 mgensScratch,
                                 unboxingDepth,
+                                typeNameIds,
                             );
                             if (!solution) {
                                 return false;
@@ -3202,6 +3285,7 @@ class DocSearch {
                                     simplifiedMgens,
                                     solutionCb,
                                     unboxingDepth,
+                                    typeNameIds,
                                 );
                                 if (unifiedGenerics !== null) {
                                     return true;
@@ -3209,6 +3293,7 @@ class DocSearch {
                             }
                         },
                         unboxingDepth,
+                        typeNameIds,
                     );
                     if (fnTypesRemaining) {
                         const highlighted = [fnType, ...fnTypesRemaining];
@@ -3227,6 +3312,7 @@ class DocSearch {
                 whereClause,
                 mgens,
                 unboxingDepth + 1,
+                typeNameIds,
             )) {
                 let highlightedRemaining;
                 if (fnType.id !== null && fnType.id < 0) {
@@ -3248,6 +3334,7 @@ class DocSearch {
                                 mgensScratch,
                                 solutionCb,
                                 unboxingDepth,
+                                typeNameIds,
                             );
                             if (hl) {
                                 highlightedRemaining = hl;
@@ -3255,6 +3342,7 @@ class DocSearch {
                             return hl;
                         },
                         unboxingDepth + 1,
+                        typeNameIds,
                     );
                     if (highlightedGenerics) {
                         return [Object.assign({
@@ -3282,6 +3370,7 @@ class DocSearch {
                                 mgensScratch,
                                 solutionCb,
                                 unboxingDepth,
+                                typeNameIds,
                             );
                             if (hl) {
                                 highlightedRemaining = hl;
@@ -3289,6 +3378,7 @@ class DocSearch {
                             return hl;
                         },
                         unboxingDepth + 1,
+                        typeNameIds,
                     );
                     if (highlightedGenerics) {
                         return [Object.assign({}, fnType, {
@@ -3314,10 +3404,11 @@ class DocSearch {
          *
          * @param {rustdoc.FunctionType} fnType
          * @param {rustdoc.QueryElement} queryElem
+         * @param {rustdoc.TypeNameIds} typeNameIds
          * @param {Map|null} mgensIn - Map query generics to function generics.
          * @returns {boolean}
          */
-        const unifyFunctionTypeIsMatchCandidate = (fnType, queryElem, mgensIn) => {
+        const unifyFunctionTypeIsMatchCandidate = (fnType, queryElem, mgensIn, typeNameIds) => {
             // type filters look like `trait:Read` or `enum:Result`
             if (!typePassesFilter(queryElem.typeFilter, fnType.ty)) {
                 return false;
@@ -3336,21 +3427,23 @@ class DocSearch {
             } else {
                 // For these special cases, matching code need added to the inverted index.
                 // search_index.rs -> convert_render_type does this
-                if (queryElem.id === this.typeNameIdOfArrayOrSlice &&
-                    (fnType.id === this.typeNameIdOfSlice || fnType.id === this.typeNameIdOfArray)
+                if (queryElem.id === typeNameIds.typeNameIdOfArrayOrSlice &&
+                    (fnType.id === typeNameIds.typeNameIdOfSlice ||
+                        fnType.id === typeNameIds.typeNameIdOfArray)
                 ) {
                     // [] matches primitive:array or primitive:slice
                     // if it matches, then we're fine, and this is an appropriate match candidate
-                } else if (queryElem.id === this.typeNameIdOfTupleOrUnit &&
-                    (fnType.id === this.typeNameIdOfTuple || fnType.id === this.typeNameIdOfUnit)
+                } else if (queryElem.id === typeNameIds.typeNameIdOfTupleOrUnit &&
+                    (fnType.id === typeNameIds.typeNameIdOfTuple ||
+                        fnType.id === typeNameIds.typeNameIdOfUnit)
                 ) {
                     // () matches primitive:tuple or primitive:unit
                     // if it matches, then we're fine, and this is an appropriate match candidate
-                } else if (queryElem.id === this.typeNameIdOfHof && (
-                    fnType.id === this.typeNameIdOfFn ||
-                    fnType.id === this.typeNameIdOfFnMut ||
-                    fnType.id === this.typeNameIdOfFnOnce ||
-                    fnType.id === this.typeNameIdOfFnPtr
+                } else if (queryElem.id === typeNameIds.typeNameIdOfHof && (
+                    fnType.id === typeNameIds.typeNameIdOfFn ||
+                    fnType.id === typeNameIds.typeNameIdOfFnMut ||
+                    fnType.id === typeNameIds.typeNameIdOfFnOnce ||
+                    fnType.id === typeNameIds.typeNameIdOfFnPtr
                 )) {
                     // -> matches fn, fnonce, and fnmut
                     // if it matches, then we're fine, and this is an appropriate match candidate
@@ -3414,6 +3507,7 @@ class DocSearch {
          * @param {Map|null} mgensIn - Map query generics to function generics.
          *                                            Never modified.
          * @param {number} unboxingDepth
+         * @param {rustdoc.TypeNameIds} typeNameIds
          * @returns {false|{
          *     mgens: [Map|null], simplifiedGenerics: rustdoc.FunctionType[]
          * }}
@@ -3424,6 +3518,7 @@ class DocSearch {
             whereClause,
             mgensIn,
             unboxingDepth,
+            typeNameIds,
         ) {
             if (fnType.bindings.size < queryElem.bindings.size) {
                 return false;
@@ -3455,6 +3550,7 @@ class DocSearch {
                                 return false;
                             },
                             unboxingDepth,
+                            typeNameIds,
                         );
                         return newSolutions;
                     });
@@ -3486,6 +3582,7 @@ class DocSearch {
          * @param {rustdoc.FunctionType[][]} whereClause - Trait bounds for generic items.
          * @param {Map|null} mgens - Map query generics to function generics.
          * @param {number} unboxingDepth
+         * @param {rustdoc.TypeNameIds} typeNameIds
          * @returns {boolean}
          */
         function unifyFunctionTypeIsUnboxCandidate(
@@ -3494,6 +3591,7 @@ class DocSearch {
             whereClause,
             mgens,
             unboxingDepth,
+            typeNameIds,
         ) {
             if (unboxingDepth >= UNBOXING_LIMIT) {
                 return false;
@@ -3512,6 +3610,7 @@ class DocSearch {
                     whereClause,
                     mgens,
                     unboxingDepth,
+                    typeNameIds,
                 );
             } else if (fnType.unboxFlag &&
                 (fnType.generics.length > 0 || fnType.bindings.size > 0)) {
@@ -3525,6 +3624,7 @@ class DocSearch {
                     whereClause,
                     mgens,
                     unboxingDepth,
+                    typeNameIds,
                 );
             }
             return false;
@@ -3537,14 +3637,15 @@ class DocSearch {
          * @param {rustdoc.QueryElement[]} elems
          * @param {rustdoc.FunctionType[]} list    - A list of function types.
          * @param {rustdoc.FunctionType[][]} where_clause - Trait bounds for generic items.
+         * @param {rustdoc.TypeNameIds} typeNameIds
          */
-        function containsTypeFromQuery(elems, list, where_clause) {
+        function containsTypeFromQuery(elems, list, where_clause, typeNameIds) {
             if (!list) return false;
             for (const ty of elems) {
                 if (ty.id !== null && ty.id < 0) {
                     continue;
                 }
-                if (checkIfInList(list, ty, where_clause, null, 0)) {
+                if (checkIfInList(list, ty, where_clause, null, 0, typeNameIds)) {
                     return true;
                 }
             }
@@ -3560,12 +3661,13 @@ class DocSearch {
          * @param {rustdoc.FunctionType[][]} whereClause - Trait bounds for generic items.
          * @param {Map|null} mgens - Map functions generics to query generics.
          * @param {number} unboxingDepth
+         * @param {rustdoc.TypeNameIds} typeNameIds
          *
          * @return {boolean} - Returns true if found, false otherwise.
          */
-        function checkIfInList(list, elem, whereClause, mgens, unboxingDepth) {
+        function checkIfInList(list, elem, whereClause, mgens, unboxingDepth, typeNameIds) {
             for (const entry of list) {
-                if (checkType(entry, elem, whereClause, mgens, unboxingDepth)) {
+                if (checkType(entry, elem, whereClause, mgens, unboxingDepth, typeNameIds)) {
                     return true;
                 }
             }
@@ -3580,11 +3682,12 @@ class DocSearch {
          * @param {rustdoc.QueryElement} elem          - The element from the parsed query.
          * @param {rustdoc.FunctionType[][]} whereClause - Trait bounds for generic items.
          * @param {Map|null} mgens - Map query generics to function generics.
+         * @param {number} unboxingDepth
+         * @param {rustdoc.TypeNameIds} typeNameIds
          *
          * @return {boolean} - Returns true if the type matches, false otherwise.
          */
-        // @ts-expect-error
-        const checkType = (row, elem, whereClause, mgens, unboxingDepth) => {
+        const checkType = (row, elem, whereClause, mgens, unboxingDepth, typeNameIds) => {
             if (unboxingDepth >= UNBOXING_LIMIT) {
                 return false;
             }
@@ -3593,9 +3696,9 @@ class DocSearch {
                 row.generics.length === 0 && elem.generics.length === 0 &&
                 row.bindings.size === 0 && elem.bindings.size === 0 &&
                 // special case
-                elem.id !== this.typeNameIdOfArrayOrSlice &&
-                elem.id !== this.typeNameIdOfHof &&
-                elem.id !== this.typeNameIdOfTupleOrUnit
+                elem.id !== typeNameIds.typeNameIdOfArrayOrSlice &&
+                elem.id !== typeNameIds.typeNameIdOfHof &&
+                elem.id !== typeNameIds.typeNameIdOfTupleOrUnit
             ) {
                 return row.id === elem.id && typePassesFilter(elem.typeFilter, row.ty);
             } else {
@@ -3607,6 +3710,7 @@ class DocSearch {
                     mgens,
                     () => true,
                     unboxingDepth,
+                    typeNameIds,
                 );
             }
         };
@@ -3673,7 +3777,10 @@ class DocSearch {
         /**
          * Compute an "edit distance" that ignores missing path elements.
          * @param {string[]} contains search query path
-         * @param {rustdoc.Row} row indexed item
+         * @param {{
+         *     modulePath: string,
+         *     parent: { path: rustdoc.PathData, name: string}?,
+         * }} row indexed item
          * @returns {null|number} edit distance
          */
         function checkRowPath(contains, row) {
@@ -3752,7 +3859,7 @@ class DocSearch {
                         is_alias: true,
                         elems: [], // only used in type-based queries
                         returned: [], // only used in type-based queries
-                        original: await this.getRow(alias, false),
+                        item: nonnull(await this.getRow(alias, false)),
                     };
                 };
                 /**
@@ -3834,6 +3941,7 @@ class DocSearch {
                             elems: [], // only used in type-based queries
                             returned: [], // only used in type-based queries
                             is_alias: false,
+                            item: row,
                         } : null;
                     } else {
                         return {
@@ -3848,6 +3956,7 @@ class DocSearch {
                             elems: [], // only used in type-based queries
                             returned: [], // only used in type-based queries
                             is_alias: false,
+                            item: row,
                         };
                     }
                 };
@@ -4359,9 +4468,10 @@ class DocSearch {
                 };
 
                 // finally, we can do the actual unification loop
-                const [allInputs, allOutput] = await Promise.all([
+                const [allInputs, allOutput, typeNameIds] = await Promise.all([
                     unpackPostingsListAll(inputs, "invertedFunctionInputsIndex"),
                     unpackPostingsListAll(output, "invertedFunctionOutputIndex"),
+                    this.getTypeNameIds(),
                 ]);
                 let checkCounter = 0;
                 /**
@@ -4430,12 +4540,18 @@ class DocSearch {
                                             mgens,
                                             checkTypeMgensForConflict,
                                             0, // unboxing depth
+                                            typeNameIds,
                                         );
                                     },
                                     0, // unboxing depth
+                                    typeNameIds,
                                 )) {
                                     return null;
                                 }
+                                const item = await this.getRow(id, true);
+                                if (!item) {
+                                    return null;
+                                }
                                 const result = {
                                     id,
                                     dist: fnData.elemCount,
@@ -4444,8 +4560,9 @@ class DocSearch {
                                     elems: inputs,
                                     returned: output,
                                     is_alias: false,
+                                    item,
                                 };
-                                const entry = await this.getEntryData(id);
+                                const entry = item.entry;
                                 if ((entry && !isFnLikeTy(entry.ty)) ||
                                     (isReturnTypeQuery &&
                                         functionSignature &&
@@ -4453,6 +4570,7 @@ class DocSearch {
                                             output,
                                             functionSignature.inputs,
                                             functionSignature.where_clause,
+                                            typeNameIds,
                                         )
                                     )
                                 ) {
@@ -5273,7 +5391,6 @@ if (ROOT_PATH === null) {
 const database = await Stringdex.loadDatabase(hooks);
 if (typeof window !== "undefined") {
     docSearch = new DocSearch(ROOT_PATH, database);
-    await docSearch.buildIndex();
     onEachLazy(document.querySelectorAll(
         ".search-form.loading",
     ), form => {
@@ -5286,7 +5403,6 @@ if (typeof window !== "undefined") {
     }
 } else if (typeof exports !== "undefined") {
     docSearch = new DocSearch(ROOT_PATH, database);
-    await docSearch.buildIndex();
     return { docSearch, DocSearch };
 }
 };
diff --git a/src/librustdoc/html/static/js/stringdex.d.ts b/src/librustdoc/html/static/js/stringdex.d.ts
index 2eb1fdf95d845..71c6bfdf48145 100644
--- a/src/librustdoc/html/static/js/stringdex.d.ts
+++ b/src/librustdoc/html/static/js/stringdex.d.ts
@@ -29,7 +29,7 @@ declare namespace stringdex {
      */
     interface DataColumn {
         isEmpty(id: number): boolean;
-        at(id: number): Promise;
+        at(id: number): Promise|Uint8Array|undefined;
         search(name: Uint8Array|string): Promise;
         searchLev(name: Uint8Array|string): AsyncGenerator;
         length: number,
diff --git a/src/librustdoc/html/static/js/stringdex.js b/src/librustdoc/html/static/js/stringdex.js
index b7f605a10351d..d8b8c5bd70c13 100644
--- a/src/librustdoc/html/static/js/stringdex.js
+++ b/src/librustdoc/html/static/js/stringdex.js
@@ -1108,22 +1108,39 @@ function loadDatabase(hooks) {
                     const id2 = id1 + ((nodeid[4] << 8) | nodeid[5]);
                     leaves = RoaringBitmap.makeSingleton(id1)
                         .union(RoaringBitmap.makeSingleton(id2));
+                } else if (!isWhole && (nodeid[0] & 0xf0) === 0x80) {
+                    const id1 = ((nodeid[0] & 0x0f) << 16) | (nodeid[1] << 8) | nodeid[2];
+                    const id2 = id1 + ((nodeid[3] << 4) | ((nodeid[4] >> 4) & 0x0f));
+                    const id3 = id2 + (((nodeid[4] & 0x0f) << 8) | nodeid[5]);
+                    leaves = RoaringBitmap.makeSingleton(id1)
+                        .union(RoaringBitmap.makeSingleton(id2))
+                        .union(RoaringBitmap.makeSingleton(id3));
                 } else {
                     leaves = RoaringBitmap.makeSingleton(
                         (nodeid[2] << 24) | (nodeid[3] << 16) |
                         (nodeid[4] << 8) | nodeid[5],
                     );
                 }
-                const data = (nodeid[0] & 0x20) !== 0 ?
-                    Uint8Array.of(((nodeid[0] & 0x0f) << 4) | (nodeid[1] >> 4)) :
-                    EMPTY_UINT8;
-                newPromise = Promise.resolve(new PrefixSearchTree(
-                    EMPTY_SEARCH_TREE_BRANCHES,
-                    EMPTY_SEARCH_TREE_BRANCHES,
-                    data,
-                    isWhole ? leaves : EMPTY_BITMAP,
-                    isWhole ? EMPTY_BITMAP : leaves,
-                ));
+                if (isWhole) {
+                    const data = (nodeid[0] & 0x20) !== 0 ?
+                        Uint8Array.of(((nodeid[0] & 0x0f) << 4) | (nodeid[1] >> 4)) :
+                        EMPTY_UINT8;
+                    newPromise = Promise.resolve(new PrefixSearchTree(
+                        EMPTY_SEARCH_TREE_BRANCHES,
+                        EMPTY_SEARCH_TREE_BRANCHES,
+                        data,
+                        leaves,
+                        EMPTY_BITMAP,
+                    ));
+                } else {
+                    const data = (nodeid[0] & 0xf0) === 0x80 ? 0 : (
+                        ((nodeid[0] & 0x0f) << 4) | (nodeid[1] >> 4));
+                    newPromise = Promise.resolve(new SuffixSearchTree(
+                        EMPTY_SEARCH_TREE_BRANCHES,
+                        data,
+                        leaves,
+                    ));
+                }
             } else {
                 const hashHex = makeHexFromUint8Array(nodeid);
                 newPromise = new Promise((resolve, reject) => {
@@ -1430,7 +1447,7 @@ function loadDatabase(hooks) {
         makeSearchTreeBranchesAlphaBitmapClass(LONG_ALPHABITMAP_CHARS, 4);
 
     /**
-     * @typedef {PrefixSearchTree|SuffixSearchTree} SearchTree
+     * @typedef {PrefixSearchTree|SuffixSearchTree|InlineNeighborsTree} SearchTree
      * @typedef {PrefixTrie|SuffixTrie} Trie
      */
 
@@ -1658,9 +1675,12 @@ function loadDatabase(hooks) {
                         yield leaves;
                     }
                 }
-                /** @type {HashTable<[number, SearchTree][]>} */
+                /** @type {HashTable<[number, PrefixSearchTree|SuffixSearchTree][]>} */
                 const subnodes = new HashTable();
-                for await (const node of current_layer) {
+                for await (const nodeEncoded of current_layer) {
+                    const node = nodeEncoded instanceof InlineNeighborsTree ?
+                        nodeEncoded.decode() :
+                        nodeEncoded;
                     const branches = node.branches;
                     const l = branches.subtrees.length;
                     for (let i = 0; i < l; ++i) {
@@ -1724,7 +1744,10 @@ function loadDatabase(hooks) {
                 // we then yield the smallest ones (can't yield bigger ones
                 // if we want to do them in order)
                 for (const {node, len} of current_layer) {
-                    const tree = await node;
+                    const treeEncoded = await node;
+                    const tree = treeEncoded instanceof InlineNeighborsTree ?
+                        treeEncoded.decode() :
+                        treeEncoded;
                     if (!(tree instanceof PrefixSearchTree)) {
                         continue;
                     }
@@ -1787,7 +1810,10 @@ function loadDatabase(hooks) {
                 /** @type {HashTable<{byte: number, tree: PrefixSearchTree, len: number}[]>} */
                 const subnodes = new HashTable();
                 for await (const {node, len} of current_layer) {
-                    const tree = await node;
+                    const treeEncoded = await node;
+                    const tree = treeEncoded instanceof InlineNeighborsTree ?
+                        treeEncoded.decode() :
+                        treeEncoded;
                     if (!(tree instanceof PrefixSearchTree)) {
                         continue;
                     }
@@ -2149,9 +2175,12 @@ function loadDatabase(hooks) {
                         yield leaves;
                     }
                 }
-                /** @type {HashTable<[number, SearchTree][]>} */
+                /** @type {HashTable<[number, PrefixSearchTree|SuffixSearchTree][]>} */
                 const subnodes = new HashTable();
-                for await (const node of current_layer) {
+                for await (const nodeEncoded of current_layer) {
+                    const node = nodeEncoded instanceof InlineNeighborsTree ?
+                        nodeEncoded.decode() :
+                        nodeEncoded;
                     const branches = node.branches;
                     const l = branches.subtrees.length;
                     for (let i = 0; i < l; ++i) {
@@ -2247,6 +2276,174 @@ function loadDatabase(hooks) {
         }
     }
 
+    /**
+     * Represents a subtree where all transitive leaves
+     * have a shared 16bit prefix and there are no sub-branches.
+     */
+    class InlineNeighborsTree {
+        /**
+         * @param {Uint8Array} encoded
+         * @param {number} start
+         */
+        constructor(
+            encoded,
+            start,
+        ) {
+            this.encoded = encoded;
+            this.start = start;
+        }
+        /**
+         * @return {PrefixSearchTree|SuffixSearchTree}
+         */
+        decode() {
+            let i = this.start;
+            const encoded = this.encoded;
+            const has_branches = (encoded[i] & 0x04) !== 0;
+            /** @type {boolean} */
+            const is_suffixes_only = (encoded[i] & 0x01) !== 0;
+            let leaves_count = ((encoded[i] >> 4) & 0x0f) + 1;
+            i += 1;
+            let branch_count = 0;
+            if (has_branches) {
+                branch_count = encoded[i] + 1;
+                i += 1;
+            }
+            const dlen = encoded[i] & 0x3f;
+            if ((encoded[i] & 0x80) !== 0) {
+                leaves_count = 0;
+            }
+            i += 1;
+            let data = EMPTY_UINT8;
+            if (!is_suffixes_only && dlen !== 0) {
+                data = encoded.subarray(i, i + dlen);
+                i += dlen;
+            }
+            const leaf_value_upper = encoded[i] | (encoded[i + 1] << 8);
+            i += 2;
+            /** @type {Promise[]} */
+            const branch_nodes = [];
+            for (let j = 0; j < branch_count; j += 1) {
+                const branch_dlen = encoded[i] & 0x0f;
+                const branch_leaves_count = ((encoded[i] >> 4) & 0x0f) + 1;
+                i += 1;
+                let branch_data = EMPTY_UINT8;
+                if (!is_suffixes_only && branch_dlen !== 0) {
+                    branch_data = encoded.subarray(i, i + branch_dlen);
+                    i += branch_dlen;
+                }
+                const branch_leaves = new RoaringBitmap(null);
+                branch_leaves.keysAndCardinalities = Uint8Array.of(
+                    leaf_value_upper & 0xff,
+                    (leaf_value_upper >> 8) & 0xff,
+                    (branch_leaves_count - 1) & 0xff,
+                    ((branch_leaves_count - 1) >> 8) & 0xff,
+                );
+                branch_leaves.containers = [
+                    new RoaringBitmapArray(
+                        branch_leaves_count,
+                        encoded.subarray(i, i + (branch_leaves_count * 2)),
+                    ),
+                ];
+                i += branch_leaves_count * 2;
+                branch_nodes.push(Promise.resolve(
+                    is_suffixes_only ?
+                        new SuffixSearchTree(
+                            EMPTY_SEARCH_TREE_BRANCHES,
+                            branch_dlen,
+                            branch_leaves,
+                        ) :
+                        new PrefixSearchTree(
+                            EMPTY_SEARCH_TREE_BRANCHES,
+                            EMPTY_SEARCH_TREE_BRANCHES,
+                            branch_data,
+                            branch_leaves,
+                            EMPTY_BITMAP,
+                        ),
+                ));
+            }
+            /** @type {SearchTreeBranchesArray} */
+            const branches = branch_count === 0 ?
+                EMPTY_SEARCH_TREE_BRANCHES :
+                new SearchTreeBranchesArray(
+                    encoded.subarray(i, i + branch_count),
+                    EMPTY_UINT8,
+                );
+            i += branch_count;
+            branches.subtrees = branch_nodes;
+            let leaves = EMPTY_BITMAP;
+            if (leaves_count !== 0) {
+                leaves = new RoaringBitmap(null);
+                leaves.keysAndCardinalities = Uint8Array.of(
+                    leaf_value_upper & 0xff,
+                    (leaf_value_upper >> 8) & 0xff,
+                    (leaves_count - 1) & 0xff,
+                    ((leaves_count - 1) >> 8) & 0xff,
+                );
+                leaves.containers = [
+                    new RoaringBitmapArray(
+                        leaves_count,
+                        encoded.subarray(i, i + (leaves_count * 2)),
+                    ),
+                ];
+                i += leaves_count * 2;
+            }
+            return is_suffixes_only ?
+                new SuffixSearchTree(
+                    branches,
+                    dlen,
+                    leaves,
+                ) :
+                new PrefixSearchTree(
+                    branches,
+                    branches,
+                    data,
+                    leaves,
+                    EMPTY_BITMAP,
+                );
+        }
+
+        /**
+         * Returns the Trie for the root node.
+         *
+         * A Trie pointer refers to a single node in a logical decompressed search tree
+         * (the real search tree is compressed).
+         *
+         * @param {DataColumn} dataColumn
+         * @param {Uint8ArraySearchPattern} searchPattern
+         * @return {Trie}
+         */
+        trie(dataColumn, searchPattern) {
+            const tree = this.decode();
+            return tree instanceof SuffixSearchTree ?
+                new SuffixTrie(tree, 0, dataColumn, searchPattern) :
+                new PrefixTrie(tree, 0, dataColumn, searchPattern);
+        }
+
+        /**
+         * Return the trie representing `name`
+         * @param {Uint8Array|string} name
+         * @param {DataColumn} dataColumn
+         * @returns {Promise}
+         */
+        search(name, dataColumn) {
+            return this.decode().search(name, dataColumn);
+        }
+
+        /**
+         * @param {Uint8Array|string} name
+         * @param {DataColumn} dataColumn
+         * @returns {AsyncGenerator}
+         */
+        searchLev(name, dataColumn) {
+            return this.decode().searchLev(name, dataColumn);
+        }
+
+        /** @returns {RoaringBitmap} */
+        getCurrentLeaves() {
+            return this.decode().getCurrentLeaves();
+        }
+    }
+
     class DataColumn {
         /**
          * Construct the wrapper object for a data column.
@@ -2261,7 +2458,7 @@ function loadDatabase(hooks) {
             this.hashes = hashes;
             this.emptyset = emptyset;
             this.name = name;
-            /** @type {{"hash": Uint8Array, "data": Promise?, "end": number}[]} */
+            /** @type {{"hash": Uint8Array, "data": Uint8Array[]?, "end": number}[]} */
             this.buckets = [];
             this.bucket_keys = [];
             const l = counts.length;
@@ -2295,64 +2492,75 @@ function loadDatabase(hooks) {
         /**
          * Look up a cell by row ID.
          * @param {number} id
-         * @returns {Promise}
+         * @returns {Promise|Uint8Array|undefined}
          */
-        async at(id) {
+        at(id) {
             if (this.emptyset.contains(id)) {
-                return Promise.resolve(EMPTY_UINT8);
+                return EMPTY_UINT8;
             } else {
                 let idx = -1;
                 while (this.bucket_keys[idx + 1] <= id) {
                     idx += 1;
                 }
                 if (idx === -1 || idx >= this.bucket_keys.length) {
-                    return Promise.resolve(undefined);
+                    return undefined;
                 } else {
                     const start = this.bucket_keys[idx];
-                    const {hash, end} = this.buckets[idx];
-                    let data = this.buckets[idx].data;
+                    const bucket = this.buckets[idx];
+                    const data = this.buckets[idx].data;
                     if (data === null) {
-                        const dataSansEmptysetOrig = await registry.dataLoadByNameAndHash(
-                            this.name,
-                            hash,
-                        );
-                        // After the `await` resolves, another task might fill
-                        // in the data. If so, we should use that.
-                        data = this.buckets[idx].data;
-                        if (data !== null) {
-                            return (await data)[id - start];
-                        }
-                        const dataSansEmptyset = [...dataSansEmptysetOrig];
-                        /** @type {(Uint8Array[])|null} */
-                        let dataWithEmptyset = null;
-                        let pos = start;
-                        let insertCount = 0;
-                        while (pos < end) {
-                            if (this.emptyset.contains(pos)) {
-                                if (dataWithEmptyset === null) {
-                                    dataWithEmptyset = dataSansEmptyset.splice(0, insertCount);
-                                } else if (insertCount !== 0) {
-                                    dataWithEmptyset.push(
-                                        ...dataSansEmptyset.splice(0, insertCount),
-                                    );
-                                }
-                                insertCount = 0;
-                                dataWithEmptyset.push(EMPTY_UINT8);
-                            } else {
-                                insertCount += 1;
-                            }
-                            pos += 1;
-                        }
-                        data = Promise.resolve(
-                            dataWithEmptyset === null ?
-                                dataSansEmptyset :
-                                dataWithEmptyset.concat(dataSansEmptyset),
+                        return this.atAsyncFetch(id, start, bucket);
+                    } else {
+                        return data[id - start];
+                    }
+                }
+            }
+        }
+        /**
+         * Look up a cell by row ID.
+         * @param {number} id
+         * @param {number} start
+         * @param {{hash: Uint8Array, data: Uint8Array[] | null, end: number}} bucket
+         * @returns {Promise}
+         */
+        async atAsyncFetch(id, start, bucket) {
+            const {hash, end} = bucket;
+            const dataSansEmptysetOrig = await registry.dataLoadByNameAndHash(
+                this.name,
+                hash,
+            );
+            // After the `await` resolves, another task might fill
+            // in the data. If so, we should use that.
+            let data = bucket.data;
+            if (data !== null) {
+                return data[id - start];
+            }
+            const dataSansEmptyset = [...dataSansEmptysetOrig];
+            /** @type {(Uint8Array[])|null} */
+            let dataWithEmptyset = null;
+            let pos = start;
+            let insertCount = 0;
+            while (pos < end) {
+                if (this.emptyset.contains(pos)) {
+                    if (dataWithEmptyset === null) {
+                        dataWithEmptyset = dataSansEmptyset.splice(0, insertCount);
+                    } else if (insertCount !== 0) {
+                        dataWithEmptyset.push(
+                            ...dataSansEmptyset.splice(0, insertCount),
                         );
-                        this.buckets[idx].data = data;
                     }
-                    return (await data)[id - start];
+                    insertCount = 0;
+                    dataWithEmptyset.push(EMPTY_UINT8);
+                } else {
+                    insertCount += 1;
                 }
+                pos += 1;
             }
+            data = dataWithEmptyset === null ?
+                dataSansEmptyset :
+                dataWithEmptyset.concat(dataSansEmptyset);
+            bucket.data = data;
+            return data[id - start];
         }
         /**
          * Search by exact substring
@@ -2737,19 +2945,37 @@ function loadDatabase(hooks) {
             // because that's the canonical, hashed version of the data
             let compression_tag = input[i];
             const is_pure_suffixes_only_node = (compression_tag & 0x01) !== 0;
-            if (compression_tag > 1) {
-                // compressed node
-                const is_long_compressed = (compression_tag & 0x04) !== 0;
-                const is_data_compressed = (compression_tag & 0x08) !== 0;
+            const is_long_compressed = (compression_tag & 0x04) !== 0;
+            const is_data_compressed = (compression_tag & 0x08) !== 0;
+            i += 1;
+            if (is_long_compressed) {
+                compression_tag |= input[i] << 8;
                 i += 1;
-                if (is_long_compressed) {
-                    compression_tag |= input[i] << 8;
-                    i += 1;
-                    compression_tag |= input[i] << 16;
-                    i += 1;
-                }
-                let dlen = input[i];
+            }
+            /** @type {number} */
+            let dlen;
+            /** @type {number} */
+            let no_leaves_flag;
+            /** @type {number} */
+            let inline_neighbors_flag;
+            if (is_data_compressed && is_pure_suffixes_only_node) {
+                dlen = 0;
+                no_leaves_flag = 0x80;
+                inline_neighbors_flag = 0;
+            } else {
+                dlen = input[i] & 0x3F;
+                no_leaves_flag = input[i] & 0x80;
+                inline_neighbors_flag = input[i] & 0x40;
                 i += 1;
+            }
+            if (inline_neighbors_flag !== 0) {
+                // node with packed leaves and common 16bit prefix
+                const leaves_count = no_leaves_flag !== 0 ?
+                    0 :
+                    ((compression_tag >> 4) & 0x0f) + 1;
+                const branch_count = is_long_compressed ?
+                    ((compression_tag >> 8) & 0xff) + 1 :
+                    0;
                 if (is_data_compressed) {
                     data = data_history[data_history.length - dlen - 1];
                     dlen = data.length;
@@ -2761,6 +2987,72 @@ function loadDatabase(hooks) {
                         new Uint8Array(input.buffer, i + input.byteOffset, dlen);
                     i += dlen;
                 }
+                const branches_start = i;
+                // leaf_value_upper
+                i += 2;
+                // branch_nodes
+                for (let j = 0; j < branch_count; j += 1) {
+                    const branch_dlen = input[i] & 0x0f;
+                    const branch_leaves_count = ((input[i] >> 4) & 0x0f) + 1;
+                    i += 1;
+                    if (!is_pure_suffixes_only_node) {
+                        i += branch_dlen;
+                    }
+                    i += branch_leaves_count * 2;
+                }
+                // branch keys
+                i += branch_count;
+                // leaves
+                i += leaves_count * 2;
+                if (is_data_compressed) {
+                    const clen = (
+                        1 + // first compression header byte
+                        (is_long_compressed ? 1 : 0) + // branch count
+                        1 + // data length and other flags
+                        dlen + // data
+                        (i - branches_start) // branches and leaves
+                    );
+                    const canonical = new Uint8Array(clen);
+                    let ci = 0;
+                    canonical[ci] = input[start] ^ 0x08;
+                    ci += 1;
+                    if (is_long_compressed) {
+                        canonical[ci] = input[start + ci];
+                        ci += 1;
+                    }
+                    canonical[ci] = dlen | no_leaves_flag | 0x40;
+                    ci += 1;
+                    for (let j = 0; j < dlen; j += 1) {
+                        canonical[ci] = data[j];
+                        ci += 1;
+                    }
+                    for (let j = branches_start; j < i; j += 1) {
+                        canonical[ci] = input[j];
+                        ci += 1;
+                    }
+                    tree = new InlineNeighborsTree(canonical, 0);
+                    siphashOfBytes(canonical, 0, 0, 0, 0, hash);
+                } else {
+                    tree = new InlineNeighborsTree(input, start);
+                    siphashOfBytes(new Uint8Array(
+                        input.buffer,
+                        start + input.byteOffset,
+                        i - start,
+                    ), 0, 0, 0, 0, hash);
+                }
+            } else if (compression_tag > 1) {
+                // compressed node
+                if (is_pure_suffixes_only_node) {
+                    data = EMPTY_UINT8;
+                } else if (is_data_compressed) {
+                    data = data_history[data_history.length - dlen - 1];
+                    dlen = data.length;
+                } else {
+                    data = dlen === 0 ?
+                        EMPTY_UINT8 :
+                        new Uint8Array(input.buffer, i + input.byteOffset, dlen);
+                    i += dlen;
+                }
                 const coffset = i;
                 const {
                     cpbranches,
@@ -2775,29 +3067,42 @@ function loadDatabase(hooks) {
                 let whole;
                 let suffix;
                 if (is_pure_suffixes_only_node) {
-                    suffix = input[i] === 0 ?
-                        EMPTY_BITMAP1 :
-                        new RoaringBitmap(input, i);
-                    i += suffix.consumed_len_bytes;
+                    if (no_leaves_flag) {
+                        whole = EMPTY_BITMAP;
+                        suffix = EMPTY_BITMAP;
+                    } else {
+                        suffix = input[i] === 0 ?
+                            EMPTY_BITMAP1 :
+                            new RoaringBitmap(input, i);
+                        i += suffix.consumed_len_bytes;
+                    }
                     tree = new SuffixSearchTree(
                         branches,
                         dlen,
                         suffix,
                     );
                     const clen = (
-                        3 + // lengths of children and data
+                        // lengths of children and data
+                        (is_data_compressed ? 2 : 3) +
+                        // branches
                         csnodes.length +
                         csbranches.length +
+                        // leaves
                         suffix.consumed_len_bytes
                     );
                     if (canonical.length < clen) {
                         canonical = new Uint8Array(clen);
                     }
                     let ci = 0;
-                    canonical[ci] = 1;
-                    ci += 1;
-                    canonical[ci] = dlen;
-                    ci += 1;
+                    if (is_data_compressed) {
+                        canonical[ci] = 0x09;
+                        ci += 1;
+                    } else {
+                        canonical[ci] = 1;
+                        ci += 1;
+                        canonical[ci] = dlen | no_leaves_flag;
+                        ci += 1;
+                    }
                     canonical[ci] = input[coffset]; // suffix child count
                     ci += 1;
                     canonical.set(csnodes, ci);
@@ -2810,10 +3115,9 @@ function loadDatabase(hooks) {
                     }
                     siphashOfBytes(canonical.subarray(0, clen), 0, 0, 0, 0, hash);
                 } else {
-                    if (input[i] === 0xff) {
+                    if (no_leaves_flag) {
                         whole = EMPTY_BITMAP;
-                        suffix = EMPTY_BITMAP1;
-                        i += 1;
+                        suffix = EMPTY_BITMAP;
                     } else {
                         whole = input[i] === 0 ?
                             EMPTY_BITMAP1 :
@@ -2845,7 +3149,7 @@ function loadDatabase(hooks) {
                     let ci = 0;
                     canonical[ci] = 0;
                     ci += 1;
-                    canonical[ci] = dlen;
+                    canonical[ci] = dlen | no_leaves_flag;
                     ci += 1;
                     canonical.set(data, ci);
                     ci += data.length;
@@ -2867,11 +3171,8 @@ function loadDatabase(hooks) {
                     }
                     siphashOfBytes(canonical.subarray(0, clen), 0, 0, 0, 0, hash);
                 }
-                hash[2] &= 0x7f;
             } else {
                 // uncompressed node
-                const dlen = input [i + 1];
-                i += 2;
                 if (dlen === 0 || is_pure_suffixes_only_node) {
                     data = EMPTY_UINT8;
                 } else {
@@ -2886,16 +3187,15 @@ function loadDatabase(hooks) {
                 i += branches_consumed_len_bytes;
                 let whole;
                 let suffix;
-                if (is_pure_suffixes_only_node) {
+                if (no_leaves_flag) {
+                    whole = EMPTY_BITMAP;
+                    suffix = EMPTY_BITMAP;
+                } else if (is_pure_suffixes_only_node) {
                     whole = EMPTY_BITMAP;
                     suffix = input[i] === 0 ?
                         EMPTY_BITMAP1 :
                         new RoaringBitmap(input, i);
                     i += suffix.consumed_len_bytes;
-                } else if (input[i] === 0xff) {
-                    whole = EMPTY_BITMAP;
-                    suffix = EMPTY_BITMAP;
-                    i += 1;
                 } else {
                     whole = input[i] === 0 ?
                         EMPTY_BITMAP1 :
@@ -2911,7 +3211,6 @@ function loadDatabase(hooks) {
                     start + input.byteOffset,
                     i - start,
                 ), 0, 0, 0, 0, hash);
-                hash[2] &= 0x7f;
                 tree = is_pure_suffixes_only_node ?
                     new SuffixSearchTree(
                         branches,
@@ -2926,30 +3225,33 @@ function loadDatabase(hooks) {
                         suffix,
                     );
             }
+            hash[2] &= 0x7f;
             hash_history.push({hash: truncatedHash.slice(), used: false});
             if (data.length !== 0) {
                 data_history.push(data);
             }
-            const tree_branch_nodeids = tree.branches.nodeids;
-            const tree_branch_subtrees = tree.branches.subtrees;
-            let j = 0;
-            let lb = tree.branches.subtrees.length;
-            while (j < lb) {
-                // node id with a 1 in its most significant bit is inlined, and, so
-                // it won't be in the stash
-                if ((tree_branch_nodeids[j * 6] & 0x80) === 0) {
-                    const subtree = stash.getWithOffsetKey(tree_branch_nodeids, j * 6);
-                    if (subtree !== undefined) {
-                        tree_branch_subtrees[j] = Promise.resolve(subtree);
+            if (!(tree instanceof InlineNeighborsTree)) {
+                const tree_branch_nodeids = tree.branches.nodeids;
+                const tree_branch_subtrees = tree.branches.subtrees;
+                let j = 0;
+                const lb = tree.branches.subtrees.length;
+                while (j < lb) {
+                    // node id with a 1 in its most significant bit is inlined, and, so
+                    // it won't be in the stash
+                    if ((tree_branch_nodeids[j * 6] & 0x80) === 0) {
+                        const subtree = stash.getWithOffsetKey(tree_branch_nodeids, j * 6);
+                        if (subtree !== undefined) {
+                            tree_branch_subtrees[j] = Promise.resolve(subtree);
+                        }
                     }
+                    j += 1;
                 }
-                j += 1;
             }
             if (tree instanceof PrefixSearchTree) {
                 const tree_mhp_branch_nodeids = tree.might_have_prefix_branches.nodeids;
                 const tree_mhp_branch_subtrees = tree.might_have_prefix_branches.subtrees;
-                j = 0;
-                lb = tree.might_have_prefix_branches.subtrees.length;
+                let j = 0;
+                const lb = tree.might_have_prefix_branches.subtrees.length;
                 while (j < lb) {
                     // node id with a 1 in its most significant bit is inlined, and, so
                     // it won't be in the stash
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index f44a5fdf715e5..28a0fbc051158 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -371,9 +371,9 @@ fn parse_len_output<'tcx>(cx: &LateContext<'tcx>, sig: FnSig<'tcx>) -> Option Some(LenOutput::Integral),
-        ty::Adt(adt, subs) if subs.type_at(0).is_integral() => match cx.tcx.get_diagnostic_name(adt.did()) {
-            Some(sym::Option) => Some(LenOutput::Option(adt.did())),
-            Some(sym::Result) => Some(LenOutput::Result(adt.did())),
+        ty::Adt(adt, subs) => match cx.tcx.get_diagnostic_name(adt.did()) {
+            Some(sym::Option) => subs.type_at(0).is_integral().then(|| LenOutput::Option(adt.did())),
+            Some(sym::Result) => subs.type_at(0).is_integral().then(|| LenOutput::Result(adt.did())),
             _ => None,
         },
         _ => None,
diff --git a/src/tools/clippy/tests/ui/crashes/ice-15657.rs b/src/tools/clippy/tests/ui/crashes/ice-15657.rs
new file mode 100644
index 0000000000000..c6f6506cd8d03
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-15657.rs
@@ -0,0 +1,11 @@
+//@check-pass
+#![warn(clippy::len_zero)]
+
+pub struct S1;
+pub struct S2;
+
+impl S1 {
+    pub fn len(&self) -> S2 {
+        S2
+    }
+}
diff --git a/tests/ui/lifetimes/lint-macro-extended-temporary-scopes/extended-super-let-bindings.stderr b/tests/ui/lifetimes/lint-macro-extended-temporary-scopes/extended-super-let-bindings.stderr
index 4dee6f4fc3212..038839eb92409 100644
--- a/tests/ui/lifetimes/lint-macro-extended-temporary-scopes/extended-super-let-bindings.stderr
+++ b/tests/ui/lifetimes/lint-macro-extended-temporary-scopes/extended-super-let-bindings.stderr
@@ -9,6 +9,7 @@ LL |     println!("{:?}{}", (), { format_args!("{:?}", ()) });
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
    = note: `#[warn(macro_extended_temporary_scopes)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning: 1 warning emitted
diff --git a/tests/ui/lifetimes/lint-macro-extended-temporary-scopes/macro-extended-temporary-scopes.e2021.stderr b/tests/ui/lifetimes/lint-macro-extended-temporary-scopes/macro-extended-temporary-scopes.e2021.stderr
index c7a7e1b3238e9..1c890daeaa52b 100644
--- a/tests/ui/lifetimes/lint-macro-extended-temporary-scopes/macro-extended-temporary-scopes.e2021.stderr
+++ b/tests/ui/lifetimes/lint-macro-extended-temporary-scopes/macro-extended-temporary-scopes.e2021.stderr
@@ -9,6 +9,7 @@ LL |     println!("{:?}{:?}", (), if cond() { &format!("") } else { "" });
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
    = note: `#[warn(macro_extended_temporary_scopes)]` (part of `#[warn(future_incompatible)]`) on by default
    = note: this warning originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
 
@@ -23,6 +24,7 @@ LL |     println!("{:?}{:?}", (), if cond() { &"".to_string() } else { "" });
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
 
 warning: temporary lifetime will be shortened in Rust 1.92
   --> $DIR/macro-extended-temporary-scopes.rs:39:43
@@ -35,6 +37,7 @@ LL |     println!("{:?}{:?}", (), if cond() { &("string".to_owned() + "string")
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
 
 warning: temporary lifetime will be shortened in Rust 1.92
   --> $DIR/macro-extended-temporary-scopes.rs:58:17
@@ -48,6 +51,7 @@ LL |         }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
 
 warning: temporary lifetime will be shortened in Rust 1.92
   --> $DIR/macro-extended-temporary-scopes.rs:54:14
@@ -61,6 +65,7 @@ LL |         } else {
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
 
 warning: temporary lifetime will be shortened in Rust 1.92
   --> $DIR/macro-extended-temporary-scopes.rs:50:14
@@ -74,6 +79,7 @@ LL |         } else if cond() {
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
 
 warning: temporary lifetime will be shortened in Rust 1.92
   --> $DIR/macro-extended-temporary-scopes.rs:46:14
@@ -87,6 +93,7 @@ LL |         } else if cond() {
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
 
 warning: 7 warnings emitted
 
diff --git a/tests/ui/lifetimes/lint-macro-extended-temporary-scopes/macro-extended-temporary-scopes.e2024.stderr b/tests/ui/lifetimes/lint-macro-extended-temporary-scopes/macro-extended-temporary-scopes.e2024.stderr
index 0c61fd8d1b0e1..bd086e08956fd 100644
--- a/tests/ui/lifetimes/lint-macro-extended-temporary-scopes/macro-extended-temporary-scopes.e2024.stderr
+++ b/tests/ui/lifetimes/lint-macro-extended-temporary-scopes/macro-extended-temporary-scopes.e2024.stderr
@@ -9,6 +9,7 @@ LL |     println!("{:?}{:?}", { &temp() }, ());
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
    = note: `#[warn(macro_extended_temporary_scopes)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning: temporary lifetime will be shortened in Rust 1.92
@@ -22,6 +23,7 @@ LL |     println!("{:?}{:?}", (), if cond() { &format!("") } else { "" });
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
    = note: this warning originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 warning: temporary lifetime will be shortened in Rust 1.92
@@ -35,6 +37,7 @@ LL |     println!("{:?}{:?}", (), if cond() { &"".to_string() } else { "" });
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
 
 warning: temporary lifetime will be shortened in Rust 1.92
   --> $DIR/macro-extended-temporary-scopes.rs:39:43
@@ -47,6 +50,7 @@ LL |     println!("{:?}{:?}", (), if cond() { &("string".to_owned() + "string")
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
 
 warning: temporary lifetime will be shortened in Rust 1.92
   --> $DIR/macro-extended-temporary-scopes.rs:58:17
@@ -60,6 +64,7 @@ LL |         }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
 
 warning: temporary lifetime will be shortened in Rust 1.92
   --> $DIR/macro-extended-temporary-scopes.rs:54:14
@@ -73,6 +78,7 @@ LL |         } else {
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
 
 warning: temporary lifetime will be shortened in Rust 1.92
   --> $DIR/macro-extended-temporary-scopes.rs:50:14
@@ -86,6 +92,7 @@ LL |         } else if cond() {
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
 
 warning: temporary lifetime will be shortened in Rust 1.92
   --> $DIR/macro-extended-temporary-scopes.rs:46:14
@@ -99,6 +106,7 @@ LL |         } else if cond() {
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
 
 warning: temporary lifetime will be shortened in Rust 1.92
   --> $DIR/macro-extended-temporary-scopes.rs:65:18
@@ -111,6 +119,7 @@ LL |     pin!(pin!({ &temp() }));
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
 
 warning: temporary lifetime will be shortened in Rust 1.92
   --> $DIR/macro-extended-temporary-scopes.rs:96:13
@@ -123,6 +132,7 @@ LL |     pin!({ &(1 / 0) });
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
 
 warning: temporary lifetime will be shortened in Rust 1.92
   --> $DIR/macro-extended-temporary-scopes.rs:99:17
@@ -135,6 +145,7 @@ LL |     pin!({ &mut [()] });
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
 
 warning: temporary lifetime will be shortened in Rust 1.92
   --> $DIR/macro-extended-temporary-scopes.rs:102:13
@@ -147,6 +158,7 @@ LL |     pin!({ &Some(String::new()) });
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
 
 warning: temporary lifetime will be shortened in Rust 1.92
   --> $DIR/macro-extended-temporary-scopes.rs:105:13
@@ -159,6 +171,7 @@ LL |     pin!({ &(|| ())() });
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
 
 warning: temporary lifetime will be shortened in Rust 1.92
   --> $DIR/macro-extended-temporary-scopes.rs:108:13
@@ -171,6 +184,7 @@ LL |     pin!({ &|| &local });
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
 
 warning: temporary lifetime will be shortened in Rust 1.92
   --> $DIR/macro-extended-temporary-scopes.rs:111:13
@@ -183,6 +197,7 @@ LL |     pin!({ &CONST_STRING });
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
 
 warning: 15 warnings emitted
 
diff --git a/tests/ui/lifetimes/lint-macro-extended-temporary-scopes/user-defined-macros.stderr b/tests/ui/lifetimes/lint-macro-extended-temporary-scopes/user-defined-macros.stderr
index b4996952f4f11..313f7a6638150 100644
--- a/tests/ui/lifetimes/lint-macro-extended-temporary-scopes/user-defined-macros.stderr
+++ b/tests/ui/lifetimes/lint-macro-extended-temporary-scopes/user-defined-macros.stderr
@@ -10,6 +10,7 @@ LL |             wrap!(String::new())
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
    = note: `#[warn(macro_extended_temporary_scopes)]` (part of `#[warn(future_incompatible)]`) on by default
 
 warning: temporary lifetime will be shortened in Rust 1.92
@@ -27,6 +28,7 @@ LL |     print_with_internal_wrap!();
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
    = note: this warning originates in the macro `print_with_internal_wrap` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 warning: temporary lifetime will be shortened in Rust 1.92
@@ -41,6 +43,7 @@ LL |         external_macros::wrap!(String::new())
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
 
 warning: temporary lifetime will be shortened in Rust 1.92
   --> $DIR/user-defined-macros.rs:52:5
@@ -54,6 +57,7 @@ LL |     external_macros::print_with_internal_wrap!();
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see 
    = note: consider using a `let` binding to create a longer lived value
+   = note: some temporaries were previously incorrectly lifetime-extended since Rust 1.89 in formatting macros, and since Rust 1.88 in `pin!()`
    = note: this warning originates in the macro `external_macros::print_with_internal_wrap` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 warning: 4 warnings emitted