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