Auto merge of #140859 - pietroalbini:pa-stable, r=pietroalbini
[stable] Prepare the 1.87.0 release Preparing the stable artifacts as described in the release process. This PR also includes the following last minute backports: * https://github.com/rust-lang/rust/pull/140810 * https://github.com/rust-lang/rust/pull/140601 * https://github.com/rust-lang/rust/pull/140684 r? `@ghost`
This commit is contained in:
commit
17067e9ac6
24 changed files with 551 additions and 139 deletions
289
RELEASES.md
289
RELEASES.md
|
|
@ -1,3 +1,292 @@
|
|||
Version 1.87.0 (2025-05-15)
|
||||
==========================
|
||||
|
||||
<a id="1.87.0-Language"></a>
|
||||
|
||||
Language
|
||||
--------
|
||||
- [Stabilize `asm_goto` feature](https://github.com/rust-lang/rust/pull/133870)
|
||||
- [Allow parsing open beginning ranges (`..EXPR`) after unary operators `!`, `~`, `-`, and `*`}](https://github.com/rust-lang/rust/pull/134900).
|
||||
- [Don't require method impls for methods with `Self: Sized` bounds in `impl`s for unsized types](https://github.com/rust-lang/rust/pull/135480)
|
||||
- [Stabilize `feature(precise_capturing_in_traits)` allowing `use<...>` bounds on return position `impl Trait` in `trait`s](https://github.com/rust-lang/rust/pull/138128)
|
||||
|
||||
<a id="1.87.0-Compiler"></a>
|
||||
|
||||
Compiler
|
||||
--------
|
||||
- [x86: make SSE2 required for i686 targets and use it to pass SIMD types](https://github.com/rust-lang/rust/pull/135408)
|
||||
|
||||
<a id="1.87.0-Platform-Support"></a>
|
||||
|
||||
Platform Support
|
||||
----------------
|
||||
- [Remove `i586-pc-windows-msvc` target](https://github.com/rust-lang/rust/pull/137957)
|
||||
|
||||
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
|
||||
|
||||
<a id="1.87.0-Libraries"></a>
|
||||
|
||||
Libraries
|
||||
---------
|
||||
- [Stabilize the anonymous pipe API](https://github.com/rust-lang/rust/issues/127154)
|
||||
- [Add support for unbounded left/right shift operations](https://github.com/rust-lang/rust/issues/129375)
|
||||
- [Print pointer metadata in `Debug` impl of raw pointers](https://github.com/rust-lang/rust/pull/135080)
|
||||
- [`Vec::with_capacity` guarantees it allocates with the amount requested, even if `Vec::capacity` returns a different number.](https://github.com/rust-lang/rust/pull/135933)
|
||||
- Most `std::arch` intrinsics which don't take pointer arguments can now be called from safe code if the caller has the appropriate target features already enabled (https://github.com/rust-lang/stdarch/pull/1714, https://github.com/rust-lang/stdarch/pull/1716, https://github.com/rust-lang/stdarch/pull/1717)
|
||||
- [Undeprecate `env::home_dir`](https://github.com/rust-lang/rust/pull/137327)
|
||||
- [Denote `ControlFlow` as `#[must_use]`](https://github.com/rust-lang/rust/pull/137449)
|
||||
- [Macros such as `assert_eq!` and `vec!` now support `const {...}` expressions](https://github.com/rust-lang/rust/pull/138162)
|
||||
|
||||
<a id="1.87.0-Stabilized-APIs"></a>
|
||||
|
||||
Stabilized APIs
|
||||
---------------
|
||||
|
||||
- [`Vec::extract_if`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.extract_if)
|
||||
- [`vec::ExtractIf`](https://doc.rust-lang.org/stable/std/vec/struct.ExtractIf.html)
|
||||
- [`LinkedList::extract_if`](https://doc.rust-lang.org/stable/std/collections/struct.LinkedList.html#method.extract_if)
|
||||
- [`linked_list::ExtractIf`](https://doc.rust-lang.org/stable/std/collections/linked_list/struct.ExtractIf.html)
|
||||
- [`<[T]>::split_off`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_off)
|
||||
- [`<[T]>::split_off_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_off_mut)
|
||||
- [`<[T]>::split_off_first`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_off_first)
|
||||
- [`<[T]>::split_off_first_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_off_first_mut)
|
||||
- [`<[T]>::split_off_last`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_off_last)
|
||||
- [`<[T]>::split_off_last_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_off_last_mut)
|
||||
- [`String::extend_from_within`](https://doc.rust-lang.org/stable/alloc/string/struct.String.html#method.extend_from_within)
|
||||
- [`os_str::Display`](https://doc.rust-lang.org/stable/std/ffi/os_str/struct.Display.html)
|
||||
- [`OsString::display`](https://doc.rust-lang.org/stable/std/ffi/struct.OsString.html#method.display)
|
||||
- [`OsStr::display`](https://doc.rust-lang.org/stable/std/ffi/struct.OsStr.html#method.display)
|
||||
- [`io::pipe`](https://doc.rust-lang.org/stable/std/io/fn.pipe.html)
|
||||
- [`io::PipeReader`](https://doc.rust-lang.org/stable/std/io/struct.PipeReader.html)
|
||||
- [`io::PipeWriter`](https://doc.rust-lang.org/stable/std/io/struct.PipeWriter.html)
|
||||
- [`impl From<PipeReader> for OwnedHandle`](https://doc.rust-lang.org/stable/std/os/windows/io/struct.OwnedHandle.html#impl-From%3CPipeReader%3E-for-OwnedHandle)
|
||||
- [`impl From<PipeWriter> for OwnedHandle`](https://doc.rust-lang.org/stable/std/os/windows/io/struct.OwnedHandle.html#impl-From%3CPipeWriter%3E-for-OwnedHandle)
|
||||
- [`impl From<PipeReader> for Stdio`](https://doc.rust-lang.org/stable/std/process/struct.Stdio.html)
|
||||
- [`impl From<PipeWriter> for Stdio`](https://doc.rust-lang.org/stable/std/process/struct.Stdio.html#impl-From%3CPipeWriter%3E-for-Stdio)
|
||||
- [`impl From<PipeReader> for OwnedFd`](https://doc.rust-lang.org/stable/std/os/fd/struct.OwnedFd.html#impl-From%3CPipeReader%3E-for-OwnedFd)
|
||||
- [`impl From<PipeWriter> for OwnedFd`](https://doc.rust-lang.org/stable/std/os/fd/struct.OwnedFd.html#impl-From%3CPipeWriter%3E-for-OwnedFd)
|
||||
- [`Box<MaybeUninit<T>>::write`](https://doc.rust-lang.org/stable/std/boxed/struct.Box.html#method.write)
|
||||
- [`impl TryFrom<Vec<u8>> for String`](https://doc.rust-lang.org/stable/std/string/struct.String.html#impl-TryFrom%3CVec%3Cu8%3E%3E-for-String)
|
||||
- [`<*const T>::offset_from_unsigned`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset_from_unsigned)
|
||||
- [`<*const T>::byte_offset_from_unsigned`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.byte_offset_from_unsigned)
|
||||
- [`<*mut T>::offset_from_unsigned`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset_from_unsigned-1)
|
||||
- [`<*mut T>::byte_offset_from_unsigned`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.byte_offset_from_unsigned-1)
|
||||
- [`NonNull::offset_from_unsigned`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.offset_from_unsigned)
|
||||
- [`NonNull::byte_offset_from_unsigned`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.byte_offset_from_unsigned)
|
||||
- [`<uN>::cast_signed`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.cast_signed)
|
||||
- [`NonZero::<uN>::cast_signed`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html#method.cast_signed-5).
|
||||
- [`<iN>::cast_unsigned`](https://doc.rust-lang.org/stable/std/primitive.isize.html#method.cast_unsigned).
|
||||
- [`NonZero::<iN>::cast_unsigned`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html#method.cast_unsigned-5).
|
||||
- [`<uN>::is_multiple_of`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.is_multiple_of)
|
||||
- [`<uN>::unbounded_shl`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.unbounded_shl)
|
||||
- [`<uN>::unbounded_shr`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.unbounded_shr)
|
||||
- [`<iN>::unbounded_shl`](https://doc.rust-lang.org/stable/std/primitive.isize.html#method.unbounded_shl)
|
||||
- [`<iN>::unbounded_shr`](https://doc.rust-lang.org/stable/std/primitive.isize.html#method.unbounded_shr)
|
||||
- [`<iN>::midpoint`](https://doc.rust-lang.org/stable/std/primitive.isize.html#method.midpoint)
|
||||
- [`<str>::from_utf8`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.from_utf8)
|
||||
- [`<str>::from_utf8_mut`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.from_utf8_mut)
|
||||
- [`<str>::from_utf8_unchecked`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.from_utf8_unchecked)
|
||||
- [`<str>::from_utf8_unchecked_mut`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.from_utf8_unchecked_mut)
|
||||
|
||||
These previously stable APIs are now stable in const contexts:
|
||||
|
||||
- [`core::str::from_utf8_mut`](https://doc.rust-lang.org/stable/std/str/fn.from_utf8_mut.html)
|
||||
- [`<[T]>::copy_from_slice`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.copy_from_slice)
|
||||
- [`SocketAddr::set_ip`](https://doc.rust-lang.org/stable/std/net/enum.SocketAddr.html#method.set_ip)
|
||||
- [`SocketAddr::set_port`](https://doc.rust-lang.org/stable/std/net/enum.SocketAddr.html#method.set_port),
|
||||
- [`SocketAddrV4::set_ip`](https://doc.rust-lang.org/stable/std/net/struct.SocketAddrV4.html#method.set_ip)
|
||||
- [`SocketAddrV4::set_port`](https://doc.rust-lang.org/stable/std/net/struct.SocketAddrV4.html#method.set_port),
|
||||
- [`SocketAddrV6::set_ip`](https://doc.rust-lang.org/stable/std/net/struct.SocketAddrV6.html#method.set_ip)
|
||||
- [`SocketAddrV6::set_port`](https://doc.rust-lang.org/stable/std/net/struct.SocketAddrV6.html#method.set_port)
|
||||
- [`SocketAddrV6::set_flowinfo`](https://doc.rust-lang.org/stable/std/net/struct.SocketAddrV6.html#method.set_flowinfo)
|
||||
- [`SocketAddrV6::set_scope_id`](https://doc.rust-lang.org/stable/std/net/struct.SocketAddrV6.html#method.set_scope_id)
|
||||
- [`char::is_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_digit)
|
||||
- [`char::is_whitespace`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_whitespace)
|
||||
- [`<[[T; N]]>::as_flattened`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_flattened)
|
||||
- [`<[[T; N]]>::as_flattened_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_flattened_mut)
|
||||
- [`String::into_bytes`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.into_bytes)
|
||||
- [`String::as_str`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.as_str)
|
||||
- [`String::capacity`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.capacity)
|
||||
- [`String::as_bytes`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.as_bytes)
|
||||
- [`String::len`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.len)
|
||||
- [`String::is_empty`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.is_empty)
|
||||
- [`String::as_mut_str`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.as_mut_str)
|
||||
- [`String::as_mut_vec`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.as_mut_vec)
|
||||
- [`Vec::as_ptr`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.as_ptr)
|
||||
- [`Vec::as_slice`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.as_slice)
|
||||
- [`Vec::capacity`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.capacity)
|
||||
- [`Vec::len`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.len)
|
||||
- [`Vec::is_empty`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.is_empty)
|
||||
- [`Vec::as_mut_slice`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.as_mut_slice)
|
||||
- [`Vec::as_mut_ptr`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.as_mut_ptr)
|
||||
|
||||
<a id="1.87.0-Cargo"></a>
|
||||
|
||||
Cargo
|
||||
-----
|
||||
- [Add terminal integration via ANSI OSC 9;4 sequences](https://github.com/rust-lang/cargo/pull/14615/)
|
||||
- [chore: bump openssl to v3](https://github.com/rust-lang/cargo/pull/15232/)
|
||||
- [feat(package): add --exclude-lockfile flag](https://github.com/rust-lang/cargo/pull/15234/)
|
||||
|
||||
<a id="1.87.0-Compatibility-Notes"></a>
|
||||
|
||||
Compatibility Notes
|
||||
-------------------
|
||||
- [Rust now raises an error for macro invocations inside the `#![crate_name]` attribute](https://github.com/rust-lang/rust/pull/127581)
|
||||
- [Unstable fields are now always considered to be inhabited](https://github.com/rust-lang/rust/pull/133889)
|
||||
- [Macro arguments of unary operators followed by open beginning ranges may now be matched differently](https://github.com/rust-lang/rust/pull/134900)
|
||||
- [Make `Debug` impl of raw pointers print metadata if present](https://github.com/rust-lang/rust/pull/135080)
|
||||
- [Warn against function pointers using unsupported ABI strings in dependencies](https://github.com/rust-lang/rust/pull/135767)
|
||||
- [Associated types on `dyn` types are no longer deduplicated](https://github.com/rust-lang/rust/pull/136458)
|
||||
- [Forbid attributes on `..` inside of struct patterns (`let Struct { #[attribute] .. }) =`](https://github.com/rust-lang/rust/pull/136490)
|
||||
- [Make `ptr_cast_add_auto_to_object` lint into hard error](https://github.com/rust-lang/rust/pull/136764)
|
||||
- Many `std::arch` intrinsics are now safe to call in some contexts, there may now be new `unused_unsafe` warnings in existing codebases.
|
||||
- [Limit `width` and `precision` formatting options to 16 bits on all targets](https://github.com/rust-lang/rust/pull/136932)
|
||||
- [Turn order dependent trait objects future incompat warning into a hard error](https://github.com/rust-lang/rust/pull/136968)
|
||||
- [Denote `ControlFlow` as `#[must_use]`](https://github.com/rust-lang/rust/pull/137449)
|
||||
- [Windows: The standard library no longer links `advapi32`, except on win7.](https://github.com/rust-lang/rust/pull/138233) Code such as C libraries that were relying on this assumption may need to explicitly link advapi32.
|
||||
- [Proc macros can no longer observe expanded `cfg(true)` attributes.](https://github.com/rust-lang/rust/pull/138844)
|
||||
- [Start changing the internal representation of pasted tokens](https://github.com/rust-lang/rust/pull/124141). Certain invalid declarative macros that were previously accepted in obscure circumstances are now correctly rejected by the compiler. Use of a `tt` fragment specifier can often fix these macros.
|
||||
- [Don't allow flattened format_args in const.](https://github.com/rust-lang/rust/pull/139624)
|
||||
|
||||
<a id="1.87.0-Internal-Changes"></a>
|
||||
|
||||
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 20](https://github.com/rust-lang/rust/pull/135763)
|
||||
|
||||
|
||||
Version 1.86.0 (2025-04-03)
|
||||
==========================
|
||||
|
||||
<a id="1.86.0-Language"></a>
|
||||
|
||||
Language
|
||||
--------
|
||||
- [Stabilize upcasting trait objects to supertraits.](https://github.com/rust-lang/rust/pull/134367)
|
||||
- [Allow safe functions to be marked with the `#[target_feature]` attribute.](https://github.com/rust-lang/rust/pull/134090)
|
||||
- [The `missing_abi` lint now warns-by-default.](https://github.com/rust-lang/rust/pull/132397)
|
||||
- Rust now lints about double negations, to catch cases that might have intended to be a prefix decrement operator (`--x`) as written in other languages. This was previously a clippy lint, `clippy::double_neg`, and is [now available directly in Rust as `double_negations`.](https://github.com/rust-lang/rust/pull/126604)
|
||||
- [More pointers are now detected as definitely not-null based on their alignment in const eval.](https://github.com/rust-lang/rust/pull/133700)
|
||||
- [Empty `repr()` attribute applied to invalid items are now correctly rejected.](https://github.com/rust-lang/rust/pull/133925)
|
||||
- [Inner attributes `#![test]` and `#![rustfmt::skip]` are no longer accepted in more places than intended.](https://github.com/rust-lang/rust/pull/134276)
|
||||
|
||||
<a id="1.86.0-Compiler"></a>
|
||||
|
||||
Compiler
|
||||
--------
|
||||
- [Debug-assert that raw pointers are non-null on access.](https://github.com/rust-lang/rust/pull/134424)
|
||||
- [Change `-O` to mean `-C opt-level=3` instead of `-C opt-level=2` to match Cargo's defaults.](https://github.com/rust-lang/rust/pull/135439)
|
||||
- [Fix emission of `overflowing_literals` under certain macro environments.](https://github.com/rust-lang/rust/pull/136393)
|
||||
|
||||
<a id="1.86.0-Platform-Support"></a>
|
||||
|
||||
Platform Support
|
||||
----------------
|
||||
- [Replace `i686-unknown-redox` target with `i586-unknown-redox`.](https://github.com/rust-lang/rust/pull/136698)
|
||||
- [Increase baseline CPU of `i686-unknown-hurd-gnu` to Pentium 4.](https://github.com/rust-lang/rust/pull/136700)
|
||||
- New tier 3 targets:
|
||||
- [`{aarch64-unknown,x86_64-pc}-nto-qnx710_iosock`](https://github.com/rust-lang/rust/pull/133631).
|
||||
For supporting Neutrino QNX 7.1 with `io-socket` network stack.
|
||||
- [`{aarch64-unknown,x86_64-pc}-nto-qnx800`](https://github.com/rust-lang/rust/pull/133631).
|
||||
For supporting Neutrino QNX 8.0 (`no_std`-only).
|
||||
- [`{x86_64,i686}-win7-windows-gnu`](https://github.com/rust-lang/rust/pull/134609).
|
||||
Intended for backwards compatibility with Windows 7. `{x86_64,i686}-win7-windows-msvc` are the Windows MSVC counterparts that already exist as Tier 3 targets.
|
||||
- [`amdgcn-amd-amdhsa`](https://github.com/rust-lang/rust/pull/134740).
|
||||
- [`x86_64-pc-cygwin`](https://github.com/rust-lang/rust/pull/134999).
|
||||
- [`{mips,mipsel}-mti-none-elf`](https://github.com/rust-lang/rust/pull/135074).
|
||||
Initial bare-metal support.
|
||||
- [`m68k-unknown-none-elf`](https://github.com/rust-lang/rust/pull/135085).
|
||||
- [`armv7a-nuttx-{eabi,eabihf}`, `aarch64-unknown-nuttx`, and `thumbv7a-nuttx-{eabi,eabihf}`](https://github.com/rust-lang/rust/pull/135757).
|
||||
|
||||
Refer to Rust's [platform support page][platform-support-doc]
|
||||
for more information on Rust's tiered platform support.
|
||||
|
||||
<a id="1.86.0-Libraries"></a>
|
||||
|
||||
Libraries
|
||||
---------
|
||||
- The type of `FromBytesWithNulError` in `CStr::from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError>` was [changed from an opaque struct to an enum](https://github.com/rust-lang/rust/pull/134143), allowing users to examine why the conversion failed.
|
||||
- [Remove `RustcDecodable` and `RustcEncodable`.](https://github.com/rust-lang/rust/pull/134272)
|
||||
- [Deprecate libtest's `--logfile` option.](https://github.com/rust-lang/rust/pull/134283)
|
||||
- [On recent versions of Windows, `std::fs::remove_file` will now remove read-only files.](https://github.com/rust-lang/rust/pull/134679)
|
||||
|
||||
<a id="1.86.0-Stabilized-APIs"></a>
|
||||
|
||||
Stabilized APIs
|
||||
---------------
|
||||
|
||||
- [`{float}::next_down`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.next_down)
|
||||
- [`{float}::next_up`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.next_up)
|
||||
- [`<[_]>::get_disjoint_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.get_disjoint_mut)
|
||||
- [`<[_]>::get_disjoint_unchecked_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.get_disjoint_unchecked_mut)
|
||||
- [`slice::GetDisjointMutError`](https://doc.rust-lang.org/stable/std/slice/enum.GetDisjointMutError.html)
|
||||
- [`HashMap::get_disjoint_mut`](https://doc.rust-lang.org/std/collections/hash_map/struct.HashMap.html#method.get_disjoint_mut)
|
||||
- [`HashMap::get_disjoint_unchecked_mut`](https://doc.rust-lang.org/std/collections/hash_map/struct.HashMap.html#method.get_disjoint_unchecked_mut)
|
||||
- [`NonZero::count_ones`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html#method.count_ones)
|
||||
- [`Vec::pop_if`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.pop_if)
|
||||
- [`sync::Once::wait`](https://doc.rust-lang.org/stable/std/sync/struct.Once.html#method.wait)
|
||||
- [`sync::Once::wait_force`](https://doc.rust-lang.org/stable/std/sync/struct.Once.html#method.wait_force)
|
||||
- [`sync::OnceLock::wait`](https://doc.rust-lang.org/stable/std/sync/struct.OnceLock.html#method.wait)
|
||||
|
||||
These APIs are now stable in const contexts:
|
||||
|
||||
- [`hint::black_box`](https://doc.rust-lang.org/stable/std/hint/fn.black_box.html)
|
||||
- [`io::Cursor::get_mut`](https://doc.rust-lang.org/stable/std/io/struct.Cursor.html#method.get_mut)
|
||||
- [`io::Cursor::set_position`](https://doc.rust-lang.org/stable/std/io/struct.Cursor.html#method.set_position)
|
||||
- [`str::is_char_boundary`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.is_char_boundary)
|
||||
- [`str::split_at`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.split_at)
|
||||
- [`str::split_at_checked`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.split_at_checked)
|
||||
- [`str::split_at_mut`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.split_at_mut)
|
||||
- [`str::split_at_mut_checked`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.split_at_mut_checked)
|
||||
|
||||
<a id="1.86.0-Cargo"></a>
|
||||
|
||||
Cargo
|
||||
-----
|
||||
- [When merging, replace rather than combine configuration keys that refer to a program path and its arguments.](https://github.com/rust-lang/cargo/pull/15066/)
|
||||
- [Error if both `--package` and `--workspace` are passed but the requested package is missing.](https://github.com/rust-lang/cargo/pull/15071/) This was previously silently ignored, which was considered a bug since missing packages should be reported.
|
||||
- [Deprecate the token argument in `cargo login` to avoid shell history leaks.](https://github.com/rust-lang/cargo/pull/15057/)
|
||||
- [Simplify the implementation of `SourceID` comparisons.](https://github.com/rust-lang/cargo/pull/14980/) This may potentially change behavior if the canonicalized URL compares differently in alternative registries.
|
||||
|
||||
<a id="1.86.0-Rustdoc"></a>
|
||||
|
||||
Rustdoc
|
||||
-----
|
||||
- [Add a sans-serif font setting.](https://github.com/rust-lang/rust/pull/133636)
|
||||
|
||||
<a id="1.86.0-Compatibility-Notes"></a>
|
||||
|
||||
Compatibility Notes
|
||||
-------------------
|
||||
- [The `wasm_c_abi` future compatibility warning is now a hard error.](https://github.com/rust-lang/rust/pull/133951)
|
||||
Users of `wasm-bindgen` should upgrade to at least version 0.2.89, otherwise compilation will fail.
|
||||
- [Remove long-deprecated no-op attributes `#![no_start]` and `#![crate_id]`.](https://github.com/rust-lang/rust/pull/134300)
|
||||
- [The future incompatibility lint `cenum_impl_drop_cast` has been made into a hard error.](https://github.com/rust-lang/rust/pull/135964) This means it is now an error to cast a field-less enum to an integer if the enum implements `Drop`.
|
||||
- [SSE2 is now required for "i686" 32-bit x86 hard-float targets; disabling it causes a warning that will become a hard error eventually.](https://github.com/rust-lang/rust/pull/137037)
|
||||
To compile for pre-SSE2 32-bit x86, use a "i586" target instead.
|
||||
|
||||
<a id="1.86.0-Internal-Changes"></a>
|
||||
|
||||
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.
|
||||
|
||||
- [Build the rustc on AArch64 Linux with ThinLTO + PGO.](https://github.com/rust-lang/rust/pull/133807)
|
||||
The ARM 64-bit compiler (AArch64) on Linux is now optimized with ThinLTO and PGO, similar to the optimizations we have already performed for the x86-64 compiler on Linux. This should make it up to 30% faster.
|
||||
|
||||
|
||||
Version 1.85.1 (2025-03-18)
|
||||
==========================
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use rustc_ast_pretty::pprust;
|
|||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_hir::{self as hir, AttrPath};
|
||||
use rustc_span::symbol::{Ident, kw, sym};
|
||||
use rustc_span::{ErrorGuaranteed, Span, Symbol};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
pub struct SegmentIterator<'a> {
|
||||
offset: usize,
|
||||
|
|
@ -176,7 +176,7 @@ impl<'a> ArgParser<'a> {
|
|||
pub enum MetaItemOrLitParser<'a> {
|
||||
MetaItemParser(MetaItemParser<'a>),
|
||||
Lit(MetaItemLit),
|
||||
Err(Span, ErrorGuaranteed),
|
||||
Err(Span),
|
||||
}
|
||||
|
||||
impl<'a> MetaItemOrLitParser<'a> {
|
||||
|
|
@ -186,7 +186,7 @@ impl<'a> MetaItemOrLitParser<'a> {
|
|||
generic_meta_item_parser.span()
|
||||
}
|
||||
MetaItemOrLitParser::Lit(meta_item_lit) => meta_item_lit.span,
|
||||
MetaItemOrLitParser::Err(span, _) => *span,
|
||||
MetaItemOrLitParser::Err(span) => *span,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -495,12 +495,9 @@ impl<'a> MetaItemListParserContext<'a> {
|
|||
// where the macro didn't expand to a literal. An error is already given
|
||||
// for this at this point, and then we do continue. This makes this path
|
||||
// reachable...
|
||||
let e = self.dcx.span_delayed_bug(
|
||||
*span,
|
||||
"expr in place where literal is expected (builtin attr parsing)",
|
||||
);
|
||||
|
||||
return Some(MetaItemOrLitParser::Err(*span, e));
|
||||
// NOTE: For backward compatibility we can't emit any error / delayed bug here (yet).
|
||||
// See <https://github.com/rust-lang/rust/issues/140612>
|
||||
return Some(MetaItemOrLitParser::Err(*span));
|
||||
} else {
|
||||
self.next_path()?
|
||||
};
|
||||
|
|
|
|||
|
|
@ -146,7 +146,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
let principal_trait = regular_traits.into_iter().next();
|
||||
|
||||
let mut needed_associated_types = vec![];
|
||||
// A stable ordering of associated types from the principal trait and all its
|
||||
// supertraits. We use this to ensure that different substitutions of a trait
|
||||
// don't result in `dyn Trait` types with different projections lists, which
|
||||
// can be unsound: <https://github.com/rust-lang/rust/pull/136458>.
|
||||
// We achieve a stable ordering by walking over the unsubstituted principal
|
||||
// trait ref.
|
||||
let mut ordered_associated_types = vec![];
|
||||
|
||||
if let Some((principal_trait, ref spans)) = principal_trait {
|
||||
let principal_trait = principal_trait.map_bound(|trait_pred| {
|
||||
assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive);
|
||||
|
|
@ -171,16 +178,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// FIXME(negative_bounds): Handle this correctly...
|
||||
let trait_ref =
|
||||
tcx.anonymize_bound_vars(bound_predicate.rebind(pred.trait_ref));
|
||||
needed_associated_types.extend(
|
||||
ordered_associated_types.extend(
|
||||
tcx.associated_items(pred.trait_ref.def_id)
|
||||
.in_definition_order()
|
||||
// We only care about associated types.
|
||||
.filter(|item| item.kind == ty::AssocKind::Type)
|
||||
// No RPITITs -- they're not dyn-compatible for now.
|
||||
.filter(|item| !item.is_impl_trait_in_trait())
|
||||
// If the associated type has a `where Self: Sized` bound,
|
||||
// we do not need to constrain the associated type.
|
||||
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
|
||||
.map(|item| (item.def_id, trait_ref)),
|
||||
);
|
||||
}
|
||||
|
|
@ -252,14 +256,26 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
}
|
||||
|
||||
// We compute the list of projection bounds taking the ordered associated types,
|
||||
// and check if there was an entry in the collected `projection_bounds`. Those
|
||||
// are computed by first taking the user-written associated types, then elaborating
|
||||
// the principal trait ref, and only using those if there was no user-written.
|
||||
// See note below about how we handle missing associated types with `Self: Sized`,
|
||||
// which are not required to be provided, but are still used if they are provided.
|
||||
let mut missing_assoc_types = FxIndexSet::default();
|
||||
let projection_bounds: Vec<_> = needed_associated_types
|
||||
let projection_bounds: Vec<_> = ordered_associated_types
|
||||
.into_iter()
|
||||
.filter_map(|key| {
|
||||
if let Some(assoc) = projection_bounds.get(&key) {
|
||||
Some(*assoc)
|
||||
} else {
|
||||
missing_assoc_types.insert(key);
|
||||
// If the associated type has a `where Self: Sized` bound, then
|
||||
// we do not need to provide the associated type. This results in
|
||||
// a `dyn Trait` type that has a different number of projection
|
||||
// bounds, which may lead to type mismatches.
|
||||
if !tcx.generics_require_sized_self(key.0) {
|
||||
missing_assoc_types.insert(key);
|
||||
}
|
||||
None
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -720,7 +720,10 @@ impl<'tcx> Ty<'tcx> {
|
|||
repr: DynKind,
|
||||
) -> Ty<'tcx> {
|
||||
if cfg!(debug_assertions) {
|
||||
let projection_count = obj.projection_bounds().count();
|
||||
let projection_count = obj
|
||||
.projection_bounds()
|
||||
.filter(|item| !tcx.generics_require_sized_self(item.item_def_id()))
|
||||
.count();
|
||||
let expected_count: usize = obj
|
||||
.principal_def_id()
|
||||
.into_iter()
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
beta
|
||||
stable
|
||||
|
|
|
|||
|
|
@ -95,14 +95,13 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
|
|||
return;
|
||||
};
|
||||
|
||||
if then_search.is_key_used_and_no_copy || else_search.is_key_used_and_no_copy {
|
||||
span_lint(cx, MAP_ENTRY, expr.span, lint_msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if then_search.edits.is_empty() && else_search.edits.is_empty() {
|
||||
// No insertions
|
||||
return;
|
||||
} else if then_search.is_key_used_and_no_copy || else_search.is_key_used_and_no_copy {
|
||||
// If there are other uses of the key, and the key is not copy,
|
||||
// we cannot perform a fix automatically, but continue to emit a lint.
|
||||
None
|
||||
} else if then_search.edits.is_empty() || else_search.edits.is_empty() {
|
||||
// if .. { insert } else { .. } or if .. { .. } else { insert }
|
||||
let ((then_str, entry_kind), else_str) = match (else_search.edits.is_empty(), contains_expr.negated) {
|
||||
|
|
@ -123,10 +122,10 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
|
|||
snippet_with_applicability(cx, then_expr.span, "{ .. }", &mut app),
|
||||
),
|
||||
};
|
||||
format!(
|
||||
Some(format!(
|
||||
"if let {}::{entry_kind} = {map_str}.entry({key_str}) {then_str} else {else_str}",
|
||||
map_ty.entry_path(),
|
||||
)
|
||||
))
|
||||
} else {
|
||||
// if .. { insert } else { insert }
|
||||
let ((then_str, then_entry), (else_str, else_entry)) = if contains_expr.negated {
|
||||
|
|
@ -142,13 +141,13 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
|
|||
};
|
||||
let indent_str = snippet_indent(cx, expr.span);
|
||||
let indent_str = indent_str.as_deref().unwrap_or("");
|
||||
format!(
|
||||
Some(format!(
|
||||
"match {map_str}.entry({key_str}) {{\n{indent_str} {entry}::{then_entry} => {}\n\
|
||||
{indent_str} {entry}::{else_entry} => {}\n{indent_str}}}",
|
||||
reindent_multiline(&then_str, true, Some(4 + indent_str.len())),
|
||||
reindent_multiline(&else_str, true, Some(4 + indent_str.len())),
|
||||
entry = map_ty.entry_path(),
|
||||
)
|
||||
))
|
||||
}
|
||||
} else {
|
||||
if then_search.edits.is_empty() {
|
||||
|
|
@ -163,17 +162,17 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
|
|||
} else {
|
||||
then_search.snippet_occupied(cx, then_expr.span, &mut app)
|
||||
};
|
||||
format!(
|
||||
Some(format!(
|
||||
"if let {}::{entry_kind} = {map_str}.entry({key_str}) {body_str}",
|
||||
map_ty.entry_path(),
|
||||
)
|
||||
))
|
||||
} else if let Some(insertion) = then_search.as_single_insertion() {
|
||||
let value_str = snippet_with_context(cx, insertion.value.span, then_expr.span.ctxt(), "..", &mut app).0;
|
||||
if contains_expr.negated {
|
||||
if insertion.value.can_have_side_effects() {
|
||||
format!("{map_str}.entry({key_str}).or_insert_with(|| {value_str});")
|
||||
Some(format!("{map_str}.entry({key_str}).or_insert_with(|| {value_str});"))
|
||||
} else {
|
||||
format!("{map_str}.entry({key_str}).or_insert({value_str});")
|
||||
Some(format!("{map_str}.entry({key_str}).or_insert({value_str});"))
|
||||
}
|
||||
} else {
|
||||
// TODO: suggest using `if let Some(v) = map.get_mut(k) { .. }` here.
|
||||
|
|
@ -183,7 +182,7 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
|
|||
} else {
|
||||
let block_str = then_search.snippet_closure(cx, then_expr.span, &mut app);
|
||||
if contains_expr.negated {
|
||||
format!("{map_str}.entry({key_str}).or_insert_with(|| {block_str});")
|
||||
Some(format!("{map_str}.entry({key_str}).or_insert_with(|| {block_str});"))
|
||||
} else {
|
||||
// TODO: suggest using `if let Some(v) = map.get_mut(k) { .. }` here.
|
||||
// This would need to be a different lint.
|
||||
|
|
@ -192,7 +191,11 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
|
|||
}
|
||||
};
|
||||
|
||||
span_lint_and_sugg(cx, MAP_ENTRY, expr.span, lint_msg, "try", sugg, app);
|
||||
if let Some(sugg) = sugg {
|
||||
span_lint_and_sugg(cx, MAP_ENTRY, expr.span, lint_msg, "try", sugg, app);
|
||||
} else {
|
||||
span_lint(cx, MAP_ENTRY, expr.span, lint_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ fn is_variant_or_wildcard(cx: &LateContext<'_>, pat: &Pat<'_>, can_be_wild: bool
|
|||
/// contains `Err(IDENT)`, `None` otherwise.
|
||||
fn is_ok_or_err<'hir>(cx: &LateContext<'_>, pat: &Pat<'hir>) -> Option<(bool, &'hir Ident)> {
|
||||
if let PatKind::TupleStruct(qpath, [arg], _) = &pat.kind
|
||||
&& let PatKind::Binding(BindingMode::NONE, _, ident, _) = &arg.kind
|
||||
&& let PatKind::Binding(BindingMode::NONE, _, ident, None) = &arg.kind
|
||||
&& let res = cx.qpath_res(qpath, pat.hir_id)
|
||||
&& let Res::Def(DefKind::Ctor(..), id) = res
|
||||
&& let id @ Some(_) = cx.tcx.opt_parent(id)
|
||||
|
|
|
|||
|
|
@ -786,9 +786,9 @@ fn check_ptr_eq<'tcx>(
|
|||
}
|
||||
|
||||
// Remove one level of usize conversion if any
|
||||
let (left, right) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) {
|
||||
(Some(lhs), Some(rhs)) => (lhs, rhs),
|
||||
_ => (left, right),
|
||||
let (left, right, usize_peeled) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) {
|
||||
(Some(lhs), Some(rhs)) => (lhs, rhs, true),
|
||||
_ => (left, right, false),
|
||||
};
|
||||
|
||||
// This lint concerns raw pointers
|
||||
|
|
@ -797,10 +797,16 @@ fn check_ptr_eq<'tcx>(
|
|||
return;
|
||||
}
|
||||
|
||||
let (left_var, right_var) = (peel_raw_casts(cx, left, left_ty), peel_raw_casts(cx, right, right_ty));
|
||||
let ((left_var, left_casts_peeled), (right_var, right_casts_peeled)) =
|
||||
(peel_raw_casts(cx, left, left_ty), peel_raw_casts(cx, right, right_ty));
|
||||
|
||||
if let Some(left_snip) = left_var.span.get_source_text(cx)
|
||||
&& let Some(right_snip) = right_var.span.get_source_text(cx)
|
||||
if !(usize_peeled || left_casts_peeled || right_casts_peeled) {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let left_snip = Sugg::hir_with_context(cx, left_var, expr.span.ctxt(), "_", &mut app);
|
||||
let right_snip = Sugg::hir_with_context(cx, right_var, expr.span.ctxt(), "_", &mut app);
|
||||
{
|
||||
let Some(top_crate) = std_or_core(cx) else { return };
|
||||
let invert = if op == BinOpKind::Eq { "" } else { "!" };
|
||||
|
|
@ -811,7 +817,7 @@ fn check_ptr_eq<'tcx>(
|
|||
format!("use `{top_crate}::ptr::eq` when comparing raw pointers"),
|
||||
"try",
|
||||
format!("{invert}{top_crate}::ptr::eq({left_snip}, {right_snip})"),
|
||||
Applicability::MachineApplicable,
|
||||
app,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -819,7 +825,8 @@ fn check_ptr_eq<'tcx>(
|
|||
// If the given expression is a cast to a usize, return the lhs of the cast
|
||||
// E.g., `foo as *const _ as usize` returns `foo as *const _`.
|
||||
fn expr_as_cast_to_usize<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
|
||||
if cx.typeck_results().expr_ty(cast_expr) == cx.tcx.types.usize
|
||||
if !cast_expr.span.from_expansion()
|
||||
&& cx.typeck_results().expr_ty(cast_expr) == cx.tcx.types.usize
|
||||
&& let ExprKind::Cast(expr, _) = cast_expr.kind
|
||||
{
|
||||
Some(expr)
|
||||
|
|
@ -828,16 +835,18 @@ fn expr_as_cast_to_usize<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>
|
|||
}
|
||||
}
|
||||
|
||||
// Peel raw casts if the remaining expression can be coerced to it
|
||||
fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty: Ty<'tcx>) -> &'tcx Expr<'tcx> {
|
||||
if let ExprKind::Cast(inner, _) = expr.kind
|
||||
// Peel raw casts if the remaining expression can be coerced to it, and whether casts have been
|
||||
// peeled or not.
|
||||
fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty: Ty<'tcx>) -> (&'tcx Expr<'tcx>, bool) {
|
||||
if !expr.span.from_expansion()
|
||||
&& let ExprKind::Cast(inner, _) = expr.kind
|
||||
&& let ty::RawPtr(target_ty, _) = expr_ty.kind()
|
||||
&& let inner_ty = cx.typeck_results().expr_ty(inner)
|
||||
&& let ty::RawPtr(inner_target_ty, _) | ty::Ref(_, inner_target_ty, _) = inner_ty.kind()
|
||||
&& target_ty == inner_target_ty
|
||||
{
|
||||
peel_raw_casts(cx, inner, inner_ty)
|
||||
(peel_raw_casts(cx, inner, inner_ty).0, true)
|
||||
} else {
|
||||
expr
|
||||
(expr, false)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -226,4 +226,26 @@ fn issue11976() {
|
|||
}
|
||||
}
|
||||
|
||||
mod issue14449 {
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
pub struct Meow {
|
||||
map: BTreeMap<String, String>,
|
||||
}
|
||||
|
||||
impl Meow {
|
||||
fn pet(&self, _key: &str, _v: u32) -> u32 {
|
||||
42
|
||||
}
|
||||
}
|
||||
|
||||
pub fn f(meow: &Meow, x: String) {
|
||||
if meow.map.contains_key(&x) {
|
||||
let _ = meow.pet(&x, 1);
|
||||
} else {
|
||||
let _ = meow.pet(&x, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -232,4 +232,26 @@ fn issue11976() {
|
|||
}
|
||||
}
|
||||
|
||||
mod issue14449 {
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
pub struct Meow {
|
||||
map: BTreeMap<String, String>,
|
||||
}
|
||||
|
||||
impl Meow {
|
||||
fn pet(&self, _key: &str, _v: u32) -> u32 {
|
||||
42
|
||||
}
|
||||
}
|
||||
|
||||
pub fn f(meow: &Meow, x: String) {
|
||||
if meow.map.contains_key(&x) {
|
||||
let _ = meow.pet(&x, 1);
|
||||
} else {
|
||||
let _ = meow.pet(&x, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -80,6 +80,11 @@ fn no_lint() {
|
|||
Ok(3) => None,
|
||||
Ok(v) => Some(v),
|
||||
};
|
||||
|
||||
let _ = match funcall() {
|
||||
Ok(v @ 1..) => Some(v),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
|
||||
const fn cf(x: Result<u32, &'static str>) -> Option<u32> {
|
||||
|
|
|
|||
|
|
@ -116,6 +116,11 @@ fn no_lint() {
|
|||
Ok(3) => None,
|
||||
Ok(v) => Some(v),
|
||||
};
|
||||
|
||||
let _ = match funcall() {
|
||||
Ok(v @ 1..) => Some(v),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
|
||||
const fn cf(x: Result<u32, &'static str>) -> Option<u32> {
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ LL | | };
|
|||
| |_____^ help: replace with: `(-S).ok()`
|
||||
|
||||
error: manual implementation of `ok`
|
||||
--> tests/ui/manual_ok_err.rs:132:12
|
||||
--> tests/ui/manual_ok_err.rs:137:12
|
||||
|
|
||||
LL | } else if let Ok(n) = "1".parse::<u8>() {
|
||||
| ____________^
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ macro_rules! mac {
|
|||
($a:expr, $b:expr) => {
|
||||
$a as *const _ as usize == $b as *const _ as usize
|
||||
};
|
||||
(cast $a:expr) => {
|
||||
$a as *const [i32; 3]
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! another_mac {
|
||||
|
|
@ -20,23 +23,25 @@ fn main() {
|
|||
//~^ ptr_eq
|
||||
let _ = std::ptr::eq(a, b);
|
||||
//~^ ptr_eq
|
||||
let _ = std::ptr::eq(a.as_ptr(), b as *const _);
|
||||
//~^ ptr_eq
|
||||
let _ = std::ptr::eq(a.as_ptr(), b.as_ptr());
|
||||
//~^ ptr_eq
|
||||
|
||||
// Do not lint: the rhs conversion is needed
|
||||
let _ = a.as_ptr() == b as *const _;
|
||||
|
||||
// Do not lint: we have two raw pointers already
|
||||
let _ = a.as_ptr() == b.as_ptr();
|
||||
|
||||
// Do not lint
|
||||
|
||||
let _ = mac!(a, b);
|
||||
let _ = another_mac!(a, b);
|
||||
|
||||
let a = &mut [1, 2, 3];
|
||||
let b = &mut [1, 2, 3];
|
||||
|
||||
let _ = std::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _);
|
||||
//~^ ptr_eq
|
||||
let _ = std::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr());
|
||||
//~^ ptr_eq
|
||||
// Do not lint: the rhs conversion is needed
|
||||
let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
|
||||
|
||||
// Do not lint: we have two raw pointers already
|
||||
let _ = a.as_mut_ptr() == b.as_mut_ptr();
|
||||
|
||||
let _ = a == b;
|
||||
let _ = core::ptr::eq(a, b);
|
||||
|
|
@ -48,7 +53,11 @@ fn main() {
|
|||
let _ = !std::ptr::eq(x, y);
|
||||
//~^ ptr_eq
|
||||
|
||||
#[allow(clippy::eq_op)]
|
||||
let _issue14337 = std::ptr::eq(main as *const (), main as *const ());
|
||||
#[expect(clippy::eq_op)]
|
||||
// Do not lint: casts are needed to not change type
|
||||
let _issue14337 = main as *const () == main as *const ();
|
||||
|
||||
// Do not peel the content of macros
|
||||
let _ = std::ptr::eq(mac!(cast a), mac!(cast b));
|
||||
//~^ ptr_eq
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ macro_rules! mac {
|
|||
($a:expr, $b:expr) => {
|
||||
$a as *const _ as usize == $b as *const _ as usize
|
||||
};
|
||||
(cast $a:expr) => {
|
||||
$a as *const [i32; 3]
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! another_mac {
|
||||
|
|
@ -20,23 +23,25 @@ fn main() {
|
|||
//~^ ptr_eq
|
||||
let _ = a as *const _ == b as *const _;
|
||||
//~^ ptr_eq
|
||||
|
||||
// Do not lint: the rhs conversion is needed
|
||||
let _ = a.as_ptr() == b as *const _;
|
||||
//~^ ptr_eq
|
||||
|
||||
// Do not lint: we have two raw pointers already
|
||||
let _ = a.as_ptr() == b.as_ptr();
|
||||
//~^ ptr_eq
|
||||
|
||||
// Do not lint
|
||||
|
||||
let _ = mac!(a, b);
|
||||
let _ = another_mac!(a, b);
|
||||
|
||||
let a = &mut [1, 2, 3];
|
||||
let b = &mut [1, 2, 3];
|
||||
|
||||
// Do not lint: the rhs conversion is needed
|
||||
let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
|
||||
//~^ ptr_eq
|
||||
|
||||
// Do not lint: we have two raw pointers already
|
||||
let _ = a.as_mut_ptr() == b.as_mut_ptr();
|
||||
//~^ ptr_eq
|
||||
|
||||
let _ = a == b;
|
||||
let _ = core::ptr::eq(a, b);
|
||||
|
|
@ -48,7 +53,11 @@ fn main() {
|
|||
let _ = x as *const u32 != y as *mut u32 as *const u32;
|
||||
//~^ ptr_eq
|
||||
|
||||
#[allow(clippy::eq_op)]
|
||||
#[expect(clippy::eq_op)]
|
||||
// Do not lint: casts are needed to not change type
|
||||
let _issue14337 = main as *const () == main as *const ();
|
||||
|
||||
// Do not peel the content of macros
|
||||
let _ = mac!(cast a) as *const _ == mac!(cast b) as *const _;
|
||||
//~^ ptr_eq
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error: use `std::ptr::eq` when comparing raw pointers
|
||||
--> tests/ui/ptr_eq.rs:19:13
|
||||
--> tests/ui/ptr_eq.rs:22:13
|
||||
|
|
||||
LL | let _ = a as *const _ as usize == b as *const _ as usize;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a, b)`
|
||||
|
|
@ -8,52 +8,28 @@ LL | let _ = a as *const _ as usize == b as *const _ as usize;
|
|||
= help: to override `-D warnings` add `#[allow(clippy::ptr_eq)]`
|
||||
|
||||
error: use `std::ptr::eq` when comparing raw pointers
|
||||
--> tests/ui/ptr_eq.rs:21:13
|
||||
--> tests/ui/ptr_eq.rs:24:13
|
||||
|
|
||||
LL | let _ = a as *const _ == b as *const _;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a, b)`
|
||||
|
||||
error: use `std::ptr::eq` when comparing raw pointers
|
||||
--> tests/ui/ptr_eq.rs:23:13
|
||||
|
|
||||
LL | let _ = a.as_ptr() == b as *const _;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_ptr(), b as *const _)`
|
||||
|
||||
error: use `std::ptr::eq` when comparing raw pointers
|
||||
--> tests/ui/ptr_eq.rs:25:13
|
||||
|
|
||||
LL | let _ = a.as_ptr() == b.as_ptr();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_ptr(), b.as_ptr())`
|
||||
|
||||
error: use `std::ptr::eq` when comparing raw pointers
|
||||
--> tests/ui/ptr_eq.rs:36:13
|
||||
|
|
||||
LL | let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _)`
|
||||
|
||||
error: use `std::ptr::eq` when comparing raw pointers
|
||||
--> tests/ui/ptr_eq.rs:38:13
|
||||
|
|
||||
LL | let _ = a.as_mut_ptr() == b.as_mut_ptr();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr())`
|
||||
|
||||
error: use `std::ptr::eq` when comparing raw pointers
|
||||
--> tests/ui/ptr_eq.rs:45:13
|
||||
--> tests/ui/ptr_eq.rs:50:13
|
||||
|
|
||||
LL | let _ = x as *const u32 == y as *mut u32 as *const u32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(x, y)`
|
||||
|
||||
error: use `std::ptr::eq` when comparing raw pointers
|
||||
--> tests/ui/ptr_eq.rs:48:13
|
||||
--> tests/ui/ptr_eq.rs:53:13
|
||||
|
|
||||
LL | let _ = x as *const u32 != y as *mut u32 as *const u32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!std::ptr::eq(x, y)`
|
||||
|
||||
error: use `std::ptr::eq` when comparing raw pointers
|
||||
--> tests/ui/ptr_eq.rs:52:23
|
||||
--> tests/ui/ptr_eq.rs:61:13
|
||||
|
|
||||
LL | let _issue14337 = main as *const () == main as *const ();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(main as *const (), main as *const ())`
|
||||
LL | let _ = mac!(cast a) as *const _ == mac!(cast b) as *const _;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(mac!(cast a), mac!(cast b))`
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -32,23 +32,25 @@ fn main() {
|
|||
//~^ ptr_eq
|
||||
let _ = core::ptr::eq(a, b);
|
||||
//~^ ptr_eq
|
||||
let _ = core::ptr::eq(a.as_ptr(), b as *const _);
|
||||
//~^ ptr_eq
|
||||
let _ = core::ptr::eq(a.as_ptr(), b.as_ptr());
|
||||
//~^ ptr_eq
|
||||
|
||||
// Do not lint: the rhs conversion is needed
|
||||
let _ = a.as_ptr() == b as *const _;
|
||||
|
||||
// Do not lint: we have two raw pointers already
|
||||
let _ = a.as_ptr() == b.as_ptr();
|
||||
|
||||
// Do not lint
|
||||
|
||||
let _ = mac!(a, b);
|
||||
let _ = another_mac!(a, b);
|
||||
|
||||
let a = &mut [1, 2, 3];
|
||||
let b = &mut [1, 2, 3];
|
||||
|
||||
let _ = core::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _);
|
||||
//~^ ptr_eq
|
||||
let _ = core::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr());
|
||||
//~^ ptr_eq
|
||||
// Do not lint: the rhs conversion is needed
|
||||
let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
|
||||
|
||||
// Do not lint: we have two raw pointers already
|
||||
let _ = a.as_mut_ptr() == b.as_mut_ptr();
|
||||
|
||||
let _ = a == b;
|
||||
let _ = core::ptr::eq(a, b);
|
||||
|
|
|
|||
|
|
@ -32,23 +32,25 @@ fn main() {
|
|||
//~^ ptr_eq
|
||||
let _ = a as *const _ == b as *const _;
|
||||
//~^ ptr_eq
|
||||
|
||||
// Do not lint: the rhs conversion is needed
|
||||
let _ = a.as_ptr() == b as *const _;
|
||||
//~^ ptr_eq
|
||||
|
||||
// Do not lint: we have two raw pointers already
|
||||
let _ = a.as_ptr() == b.as_ptr();
|
||||
//~^ ptr_eq
|
||||
|
||||
// Do not lint
|
||||
|
||||
let _ = mac!(a, b);
|
||||
let _ = another_mac!(a, b);
|
||||
|
||||
let a = &mut [1, 2, 3];
|
||||
let b = &mut [1, 2, 3];
|
||||
|
||||
// Do not lint: the rhs conversion is needed
|
||||
let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
|
||||
//~^ ptr_eq
|
||||
|
||||
// Do not lint: we have two raw pointers already
|
||||
let _ = a.as_mut_ptr() == b.as_mut_ptr();
|
||||
//~^ ptr_eq
|
||||
|
||||
let _ = a == b;
|
||||
let _ = core::ptr::eq(a, b);
|
||||
|
|
|
|||
|
|
@ -13,29 +13,5 @@ error: use `core::ptr::eq` when comparing raw pointers
|
|||
LL | let _ = a as *const _ == b as *const _;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a, b)`
|
||||
|
||||
error: use `core::ptr::eq` when comparing raw pointers
|
||||
--> tests/ui/ptr_eq_no_std.rs:35:13
|
||||
|
|
||||
LL | let _ = a.as_ptr() == b as *const _;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_ptr(), b as *const _)`
|
||||
|
||||
error: use `core::ptr::eq` when comparing raw pointers
|
||||
--> tests/ui/ptr_eq_no_std.rs:37:13
|
||||
|
|
||||
LL | let _ = a.as_ptr() == b.as_ptr();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_ptr(), b.as_ptr())`
|
||||
|
||||
error: use `core::ptr::eq` when comparing raw pointers
|
||||
--> tests/ui/ptr_eq_no_std.rs:48:13
|
||||
|
|
||||
LL | let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _)`
|
||||
|
||||
error: use `core::ptr::eq` when comparing raw pointers
|
||||
--> tests/ui/ptr_eq_no_std.rs:50:13
|
||||
|
|
||||
LL | let _ = a.as_mut_ptr() == b.as_mut_ptr();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr())`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
extern crate proc_macro;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
#[proc_macro_derive(Derive, attributes(arg))]
|
||||
pub fn derive(_: TokenStream) -> TokenStream {
|
||||
TokenStream::new()
|
||||
}
|
||||
16
tests/ui/attributes/proc_macro_in_macro.rs
Normal file
16
tests/ui/attributes/proc_macro_in_macro.rs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// Regression test for <https://github.com/rust-lang/rust/issues/137687#issuecomment-2816312274>.
|
||||
//@ proc-macro: derive_macro_with_helper.rs
|
||||
//@ edition: 2018
|
||||
//@ check-pass
|
||||
|
||||
macro_rules! call_macro {
|
||||
($text:expr) => {
|
||||
#[derive(derive_macro_with_helper::Derive)]
|
||||
#[arg($text)]
|
||||
pub struct Foo;
|
||||
};
|
||||
}
|
||||
|
||||
call_macro!(1 + 1);
|
||||
|
||||
fn main() {}
|
||||
24
tests/ui/traits/object/constrain-via-unnecessary-bound.rs
Normal file
24
tests/ui/traits/object/constrain-via-unnecessary-bound.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
//@ check-pass
|
||||
|
||||
// Regression test for <https://github.com/rust-lang/rust/issues/140645>.
|
||||
// Test that we lower impossible-to-satisfy associated type bounds, which
|
||||
// may for example constrain impl parameters.
|
||||
|
||||
pub trait Other {}
|
||||
|
||||
pub trait Trait {
|
||||
type Assoc
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
impl Other for dyn Trait {}
|
||||
// `dyn Trait<Assoc = ()>` is a different "nominal type" than `dyn Trait`.
|
||||
impl Other for dyn Trait<Assoc = ()> {}
|
||||
//~^ WARN unnecessary associated type bound for dyn-incompatible associated type
|
||||
|
||||
// I hope it's clear that `dyn Trait` (w/o `Assoc`) wouldn't match this impl.
|
||||
impl<T> dyn Trait<Assoc = T> {}
|
||||
//~^ WARN unnecessary associated type bound for dyn-incompatible associated type
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
warning: unnecessary associated type bound for dyn-incompatible associated type
|
||||
--> $DIR/constrain-via-unnecessary-bound.rs:17:26
|
||||
|
|
||||
LL | impl Other for dyn Trait<Assoc = ()> {}
|
||||
| ^^^^^^^^^^ help: remove this bound
|
||||
|
|
||||
= note: this associated type has a `where Self: Sized` bound, and while the associated type can be specified, it cannot be used because trait objects are never `Sized`
|
||||
= note: `#[warn(unused_associated_type_bounds)]` on by default
|
||||
|
||||
warning: unnecessary associated type bound for dyn-incompatible associated type
|
||||
--> $DIR/constrain-via-unnecessary-bound.rs:21:19
|
||||
|
|
||||
LL | impl<T> dyn Trait<Assoc = T> {}
|
||||
| ^^^^^^^^^ help: remove this bound
|
||||
|
|
||||
= note: this associated type has a `where Self: Sized` bound, and while the associated type can be specified, it cannot be used because trait objects are never `Sized`
|
||||
|
||||
warning: 2 warnings emitted
|
||||
|
||||
|
|
@ -154,12 +154,12 @@ error[E0308]: mismatched types
|
|||
--> $DIR/pretty.rs:41:56
|
||||
|
|
||||
LL | fn dyn_has_gat(x: &dyn HasGat<u8, Assoc<bool> = ()>) { x }
|
||||
| - ^ expected `()`, found `&dyn HasGat<u8>`
|
||||
| - ^ expected `()`, found `&dyn HasGat<u8, Assoc<bool> = ()>`
|
||||
| |
|
||||
| help: try adding a return type: `-> &dyn HasGat<u8>`
|
||||
| help: try adding a return type: `-> &dyn HasGat<u8, Assoc<bool> = ()>`
|
||||
|
|
||||
= note: expected unit type `()`
|
||||
found reference `&dyn HasGat<u8>`
|
||||
found reference `&dyn HasGat<u8, Assoc<bool> = ()>`
|
||||
|
||||
error: aborting due to 14 previous errors; 1 warning emitted
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue