diff --git a/RELEASES.md b/RELEASES.md
index 755e73a34c6bf..83eb49a3fe64c 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,292 @@
+Version 1.87.0 (2025-05-15)
+==========================
+
+
+
+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)
+
+
+
+Compiler
+--------
+- [x86: make SSE2 required for i686 targets and use it to pass SIMD types](https://github.com/rust-lang/rust/pull/135408)
+
+
+
+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
+
+
+
+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)
+
+
+
+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 for OwnedHandle`](https://doc.rust-lang.org/stable/std/os/windows/io/struct.OwnedHandle.html#impl-From%3CPipeReader%3E-for-OwnedHandle)
+- [`impl From for OwnedHandle`](https://doc.rust-lang.org/stable/std/os/windows/io/struct.OwnedHandle.html#impl-From%3CPipeWriter%3E-for-OwnedHandle)
+- [`impl From for Stdio`](https://doc.rust-lang.org/stable/std/process/struct.Stdio.html)
+- [`impl From for Stdio`](https://doc.rust-lang.org/stable/std/process/struct.Stdio.html#impl-From%3CPipeWriter%3E-for-Stdio)
+- [`impl From for OwnedFd`](https://doc.rust-lang.org/stable/std/os/fd/struct.OwnedFd.html#impl-From%3CPipeReader%3E-for-OwnedFd)
+- [`impl From for OwnedFd`](https://doc.rust-lang.org/stable/std/os/fd/struct.OwnedFd.html#impl-From%3CPipeWriter%3E-for-OwnedFd)
+- [`Box>::write`](https://doc.rust-lang.org/stable/std/boxed/struct.Box.html#method.write)
+- [`impl TryFrom> 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)
+- [`::cast_signed`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.cast_signed)
+- [`NonZero::::cast_signed`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html#method.cast_signed-5).
+- [`::cast_unsigned`](https://doc.rust-lang.org/stable/std/primitive.isize.html#method.cast_unsigned).
+- [`NonZero::::cast_unsigned`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html#method.cast_unsigned-5).
+- [`::is_multiple_of`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.is_multiple_of)
+- [`::unbounded_shl`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.unbounded_shl)
+- [`::unbounded_shr`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.unbounded_shr)
+- [`::unbounded_shl`](https://doc.rust-lang.org/stable/std/primitive.isize.html#method.unbounded_shl)
+- [`::unbounded_shr`](https://doc.rust-lang.org/stable/std/primitive.isize.html#method.unbounded_shr)
+- [`::midpoint`](https://doc.rust-lang.org/stable/std/primitive.isize.html#method.midpoint)
+- [`::from_utf8`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.from_utf8)
+- [`::from_utf8_mut`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.from_utf8_mut)
+- [`::from_utf8_unchecked`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.from_utf8_unchecked)
+- [`::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)
+
+
+
+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/)
+
+
+
+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)
+
+
+
+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)
+==========================
+
+
+
+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)
+
+
+
+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)
+
+
+
+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.
+
+
+
+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)
+
+
+
+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)
+
+
+
+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.
+
+
+
+Rustdoc
+-----
+- [Add a sans-serif font setting.](https://github.com/rust-lang/rust/pull/133636)
+
+
+
+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.
+
+
+
+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)
==========================
diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs
index a8a1460591cf3..e84bac945dc7f 100644
--- a/compiler/rustc_attr_parsing/src/parser.rs
+++ b/compiler/rustc_attr_parsing/src/parser.rs
@@ -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
+ return Some(MetaItemOrLitParser::Err(*span));
} else {
self.next_path()?
};
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index 27643e715e6b1..8be8ea1cc1c10 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -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: .
+ // 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
}
})
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 74a94d8278453..c7193c6f6df88 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -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()
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/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs
index dcfee0b6d3c62..182cb4e46d2bd 100644
--- a/src/tools/clippy/clippy_lints/src/entry.rs
+++ b/src/tools/clippy/clippy_lints/src/entry.rs
@@ -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);
+ }
}
}
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs b/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
index 576e42a564c2b..026b00e3aa2a2 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
@@ -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)
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 55f1ece05593f..596f1e3471fc5 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -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)
}
}
diff --git a/src/tools/clippy/tests/ui/entry.fixed b/src/tools/clippy/tests/ui/entry.fixed
index 69452a8d9a671..f2df9f0204ea6 100644
--- a/src/tools/clippy/tests/ui/entry.fixed
+++ b/src/tools/clippy/tests/ui/entry.fixed
@@ -226,4 +226,26 @@ fn issue11976() {
}
}
+mod issue14449 {
+ use std::collections::BTreeMap;
+
+ pub struct Meow {
+ map: BTreeMap,
+ }
+
+ 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() {}
diff --git a/src/tools/clippy/tests/ui/entry.rs b/src/tools/clippy/tests/ui/entry.rs
index 3578324f01c58..166eea417ac23 100644
--- a/src/tools/clippy/tests/ui/entry.rs
+++ b/src/tools/clippy/tests/ui/entry.rs
@@ -232,4 +232,26 @@ fn issue11976() {
}
}
+mod issue14449 {
+ use std::collections::BTreeMap;
+
+ pub struct Meow {
+ map: BTreeMap,
+ }
+
+ 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() {}
diff --git a/src/tools/clippy/tests/ui/manual_ok_err.fixed b/src/tools/clippy/tests/ui/manual_ok_err.fixed
index bc169b64be9fd..e6f799aa58d61 100644
--- a/src/tools/clippy/tests/ui/manual_ok_err.fixed
+++ b/src/tools/clippy/tests/ui/manual_ok_err.fixed
@@ -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) -> Option {
diff --git a/src/tools/clippy/tests/ui/manual_ok_err.rs b/src/tools/clippy/tests/ui/manual_ok_err.rs
index 03c730d4b4e46..972b2c41ee7aa 100644
--- a/src/tools/clippy/tests/ui/manual_ok_err.rs
+++ b/src/tools/clippy/tests/ui/manual_ok_err.rs
@@ -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) -> Option {
diff --git a/src/tools/clippy/tests/ui/manual_ok_err.stderr b/src/tools/clippy/tests/ui/manual_ok_err.stderr
index 13fceacda1074..040e170f397e2 100644
--- a/src/tools/clippy/tests/ui/manual_ok_err.stderr
+++ b/src/tools/clippy/tests/ui/manual_ok_err.stderr
@@ -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::() {
| ____________^
diff --git a/src/tools/clippy/tests/ui/ptr_eq.fixed b/src/tools/clippy/tests/ui/ptr_eq.fixed
index df6305ed497e8..f0150e6784b48 100644
--- a/src/tools/clippy/tests/ui/ptr_eq.fixed
+++ b/src/tools/clippy/tests/ui/ptr_eq.fixed
@@ -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
+ // 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
}
diff --git a/src/tools/clippy/tests/ui/ptr_eq.rs b/src/tools/clippy/tests/ui/ptr_eq.rs
index 0ed0ff0d13716..3fb89257cf1b3 100644
--- a/src/tools/clippy/tests/ui/ptr_eq.rs
+++ b/src/tools/clippy/tests/ui/ptr_eq.rs
@@ -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
}
diff --git a/src/tools/clippy/tests/ui/ptr_eq.stderr b/src/tools/clippy/tests/ui/ptr_eq.stderr
index 33190df284a3f..f613e164b879f 100644
--- a/src/tools/clippy/tests/ui/ptr_eq.stderr
+++ b/src/tools/clippy/tests/ui/ptr_eq.stderr
@@ -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
diff --git a/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed b/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed
index d8ee4ea88f843..48cbad62e1a36 100644
--- a/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed
+++ b/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed
@@ -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
+ // 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);
diff --git a/src/tools/clippy/tests/ui/ptr_eq_no_std.rs b/src/tools/clippy/tests/ui/ptr_eq_no_std.rs
index a236314c29b77..3827178640eea 100644
--- a/src/tools/clippy/tests/ui/ptr_eq_no_std.rs
+++ b/src/tools/clippy/tests/ui/ptr_eq_no_std.rs
@@ -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);
diff --git a/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr b/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr
index 5b8135dc8e8bc..8c7b1ff76661f 100644
--- a/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr
+++ b/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr
@@ -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
diff --git a/tests/ui/attributes/auxiliary/derive_macro_with_helper.rs b/tests/ui/attributes/auxiliary/derive_macro_with_helper.rs
new file mode 100644
index 0000000000000..128af50ce3691
--- /dev/null
+++ b/tests/ui/attributes/auxiliary/derive_macro_with_helper.rs
@@ -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()
+}
diff --git a/tests/ui/attributes/proc_macro_in_macro.rs b/tests/ui/attributes/proc_macro_in_macro.rs
new file mode 100644
index 0000000000000..ebe67d2a321bc
--- /dev/null
+++ b/tests/ui/attributes/proc_macro_in_macro.rs
@@ -0,0 +1,16 @@
+// Regression test for .
+//@ 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() {}
diff --git a/tests/ui/traits/object/constrain-via-unnecessary-bound.rs b/tests/ui/traits/object/constrain-via-unnecessary-bound.rs
new file mode 100644
index 0000000000000..4640d6b3ed593
--- /dev/null
+++ b/tests/ui/traits/object/constrain-via-unnecessary-bound.rs
@@ -0,0 +1,24 @@
+//@ check-pass
+
+// Regression test for .
+// 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` is a different "nominal type" than `dyn Trait`.
+impl Other for dyn Trait {}
+//~^ 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 dyn Trait {}
+//~^ WARN unnecessary associated type bound for dyn-incompatible associated type
+
+fn main() {}
diff --git a/tests/ui/traits/object/constrain-via-unnecessary-bound.stderr b/tests/ui/traits/object/constrain-via-unnecessary-bound.stderr
new file mode 100644
index 0000000000000..4383ca869eacc
--- /dev/null
+++ b/tests/ui/traits/object/constrain-via-unnecessary-bound.stderr
@@ -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 {}
+ | ^^^^^^^^^^ 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 dyn Trait {}
+ | ^^^^^^^^^ 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
+
diff --git a/tests/ui/traits/object/pretty.stderr b/tests/ui/traits/object/pretty.stderr
index 37fe142951d89..2f9fdf151f08c 100644
--- a/tests/ui/traits/object/pretty.stderr
+++ b/tests/ui/traits/object/pretty.stderr
@@ -154,12 +154,12 @@ error[E0308]: mismatched types
--> $DIR/pretty.rs:41:56
|
LL | fn dyn_has_gat(x: &dyn HasGat = ()>) { x }
- | - ^ expected `()`, found `&dyn HasGat`
+ | - ^ expected `()`, found `&dyn HasGat = ()>`
| |
- | help: try adding a return type: `-> &dyn HasGat`
+ | help: try adding a return type: `-> &dyn HasGat = ()>`
|
= note: expected unit type `()`
- found reference `&dyn HasGat`
+ found reference `&dyn HasGat = ()>`
error: aborting due to 14 previous errors; 1 warning emitted