From accf713ca4232759d9cc7a65b141edcd4e713f94 Mon Sep 17 00:00:00 2001 From: Max Dexheimer Date: Thu, 15 Oct 2026 15:30:58 +0200 Subject: [PATCH 01/34] Refactor box downcasting methods --- library/alloc/src/boxed/convert.rs | 86 ++++++++++--------- library/alloc/src/lib.rs | 1 + library/core/src/error.rs | 8 +- tests/ui/privacy/suggest-box-new.stderr | 10 +-- .../suggestions/multi-suggestion.ascii.stderr | 4 +- .../multi-suggestion.unicode.stderr | 4 +- 6 files changed, 61 insertions(+), 52 deletions(-) diff --git a/library/alloc/src/boxed/convert.rs b/library/alloc/src/boxed/convert.rs index 526e8b18a8031..e208c2384a16d 100644 --- a/library/alloc/src/boxed/convert.rs +++ b/library/alloc/src/boxed/convert.rs @@ -2,7 +2,6 @@ use core::any::Any; use core::error::Error; #[cfg(not(no_global_oom_handling))] use core::fmt; -use core::mem; use core::pin::Pin; use crate::alloc::{Allocator, StaticAllocator}; @@ -250,10 +249,8 @@ unsafe fn boxed_slice_as_array_unchecked( ) -> Box<[T; N], A> { debug_assert_eq!(boxed_slice.len(), N); - let (ptr, alloc) = Box::into_raw_with_allocator(boxed_slice); - // SAFETY: Pointer and allocator came from an existing box, - // and our safety condition requires that the length is exactly `N` - unsafe { Box::from_raw_in(ptr as *mut [T; N], alloc) } + // SAFETY: Caller ensures that the length is correct. + unsafe { Box::cast_unchecked(boxed_slice) } } #[stable(feature = "boxed_slice_try_from", since = "1.43.0")] @@ -313,6 +310,28 @@ impl TryFrom> for Box<[T; N], A> { } } +impl Box { + fn downcast_any(this: Self) -> Result, Self> { + if T::type_id(&this) == core::any::TypeId::of::() { + // SAFETY: The type is correct + Ok(unsafe { Self::cast_unchecked(this) }) + } else { + Err(this) + } + } +} +impl Box { + /// Casts a box by converting to a raw pointer and back, whatever that means + /// in the given context. + unsafe fn cast_unchecked(this: Self) -> Box { + // SAFETY: Caller ensures the cast is correct + unsafe { + let (raw, alloc) = Box::into_raw_with_allocator(this); + Box::from_raw_in(raw.cast(), alloc) + } + } +} + impl Box { /// Attempts to downcast the box to a concrete type. /// @@ -334,8 +353,7 @@ impl Box { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn downcast(self) -> Result, Self> { - // SAFETY: Check ensures the type is correct. - if self.is::() { unsafe { Ok(self.downcast_unchecked::()) } } else { Err(self) } + Self::downcast_any(self) } /// Downcasts the box to a concrete type. @@ -367,10 +385,7 @@ impl Box { pub unsafe fn downcast_unchecked(self) -> Box { debug_assert!(self.is::()); // SAFETY: Caller ensures the type is correct. - unsafe { - let (raw, alloc): (*mut dyn Any, _) = Box::into_raw_with_allocator(self); - Box::from_raw_in(raw as *mut T, alloc) - } + unsafe { Self::cast_unchecked(self) } } } @@ -395,8 +410,7 @@ impl Box { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn downcast(self) -> Result, Self> { - // SAFETY: Check ensures the type is correct. - if self.is::() { unsafe { Ok(self.downcast_unchecked::()) } } else { Err(self) } + Self::downcast_any(self) } /// Downcasts the box to a concrete type. @@ -428,10 +442,7 @@ impl Box { pub unsafe fn downcast_unchecked(self) -> Box { debug_assert!(self.is::()); // SAFETY: Caller ensures the type is correct. - unsafe { - let (raw, alloc): (*mut (dyn Any + Send), _) = Box::into_raw_with_allocator(self); - Box::from_raw_in(raw as *mut T, alloc) - } + unsafe { Self::cast_unchecked(self) } } } @@ -456,8 +467,7 @@ impl Box { #[inline] #[stable(feature = "box_send_sync_any_downcast", since = "1.51.0")] pub fn downcast(self) -> Result, Self> { - // SAFETY: Check ensures the type is correct. - if self.is::() { unsafe { Ok(self.downcast_unchecked::()) } } else { Err(self) } + Self::downcast_any(self) } /// Downcasts the box to a concrete type. @@ -489,11 +499,7 @@ impl Box { pub unsafe fn downcast_unchecked(self) -> Box { debug_assert!(self.is::()); // SAFETY: Caller ensures the type is correct. - unsafe { - let (raw, alloc): (*mut (dyn Any + Send + Sync), _) = - Box::into_raw_with_allocator(self); - Box::from_raw_in(raw as *mut T, alloc) - } + unsafe { Self::cast_unchecked(self) } } } @@ -711,21 +717,24 @@ impl<'a, 'b> From> for Box { } } +impl Box { + fn downcast_error(this: Self) -> Result, Self> { + if core::error::error_type_id::(&this) == core::any::TypeId::of::() { + // SAFETY: The type is correct + Ok(unsafe { Self::cast_unchecked(this) }) + } else { + Err(this) + } + } +} + impl dyn Error { /// Attempts to downcast the box to a concrete type. #[inline] #[stable(feature = "error_downcast", since = "1.3.0")] #[rustc_allow_incoherent_impl] pub fn downcast(self: Box) -> Result, Box> { - if self.is::() { - // SAFETY: Check ensures the type is correct. - unsafe { - let raw: *mut dyn Error = Box::into_raw(self); - Ok(Box::from_raw(raw as *mut T)) - } - } else { - Err(self) - } + Box::downcast_error(self) } } @@ -735,10 +744,7 @@ impl dyn Error + Send { #[stable(feature = "error_downcast", since = "1.3.0")] #[rustc_allow_incoherent_impl] pub fn downcast(self: Box) -> Result, Box> { - let err: Box = self; - ::downcast(err) - // SAFETY: Reapplying the `Send` marker we already know to hold. - .map_err(|s| unsafe { mem::transmute::, Box>(s) }) + Box::downcast_error(self) } } @@ -748,10 +754,6 @@ impl dyn Error + Send + Sync { #[stable(feature = "error_downcast", since = "1.3.0")] #[rustc_allow_incoherent_impl] pub fn downcast(self: Box) -> Result, Box> { - let err: Box = self; - // SAFETY: Reapplying the `Send` and `Sync` markers we already know to hold. - ::downcast(err).map_err(|s| unsafe { - mem::transmute::, Box>(s) - }) + Box::downcast_error(self) } } diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index f95cb5c58eaeb..c425fe2988007 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -129,6 +129,7 @@ #![feature(dispatch_from_dyn)] #![feature(ergonomic_clones)] #![feature(error_generic_member_access)] +#![feature(error_type_id_internal)] #![feature(exact_size_is_empty)] #![feature(extend_one)] #![feature(extend_one_unchecked)] diff --git a/library/core/src/error.rs b/library/core/src/error.rs index 1b640f2d99803..b6de3eb1b44e5 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -271,6 +271,12 @@ mod private { #[stable(feature = "never_type", since = "1.100.0")] impl Error for ! {} +#[unstable(feature = "error_type_id_internal", issue = "none")] +#[doc(hidden)] +pub fn error_type_id(err: &E) -> TypeId { + E::type_id(err, private::Internal) +} + // Copied from `any.rs`. impl dyn Error + 'static { /// Returns `true` if the inner type is the same as `T`. @@ -281,7 +287,7 @@ impl dyn Error + 'static { let t = TypeId::of::(); // Get `TypeId` of the type in the trait object (`self`). - let concrete = self.type_id(private::Internal); + let concrete = error_type_id::(self); // Compare both `TypeId`s on equality. t == concrete diff --git a/tests/ui/privacy/suggest-box-new.stderr b/tests/ui/privacy/suggest-box-new.stderr index 32525a41f946c..53578389db95d 100644 --- a/tests/ui/privacy/suggest-box-new.stderr +++ b/tests/ui/privacy/suggest-box-new.stderr @@ -68,7 +68,7 @@ LL - x: (), LL - })), LL + wtf: Some(Box::new_in(_, _)), | - = and 15 other candidates + = and 16 other candidates help: consider using the `Default` trait | LL - wtf: Some(Box(U { @@ -125,7 +125,7 @@ LL + let _ = Box::new_zeroed(); LL - let _ = Box {}; LL + let _ = Box::new_in(_, _); | - = and 16 other candidates + = and 17 other candidates help: consider using the `Default` trait | LL - let _ = Box {}; @@ -147,12 +147,12 @@ LL - let _ = Box:: {}; LL + let _ = Box::::new_in(_, _); | LL - let _ = Box:: {}; -LL + let _ = Box::::into_inner(_); +LL + let _ = Box::::cast_unchecked(_); | LL - let _ = Box:: {}; -LL + let _ = Box::::map(_, _); +LL + let _ = Box::::into_inner(_); | - = and 7 other candidates + = and 8 other candidates help: consider using the `Default` trait | LL - let _ = Box:: {}; diff --git a/tests/ui/suggestions/multi-suggestion.ascii.stderr b/tests/ui/suggestions/multi-suggestion.ascii.stderr index ecc4c5aa7c23b..76fc55177070d 100644 --- a/tests/ui/suggestions/multi-suggestion.ascii.stderr +++ b/tests/ui/suggestions/multi-suggestion.ascii.stderr @@ -68,7 +68,7 @@ LL - x: (), LL - })), LL + wtf: Some(Box::new_in(_, _)), | - = and 15 other candidates + = and 16 other candidates help: consider using the `Default` trait | LL - wtf: Some(Box(U { @@ -125,7 +125,7 @@ LL + let _ = Box::new_zeroed(); LL - let _ = Box {}; LL + let _ = Box::new_in(_, _); | - = and 16 other candidates + = and 17 other candidates help: consider using the `Default` trait | LL - let _ = Box {}; diff --git a/tests/ui/suggestions/multi-suggestion.unicode.stderr b/tests/ui/suggestions/multi-suggestion.unicode.stderr index 1f28a4d8fa289..6bbd95c44a529 100644 --- a/tests/ui/suggestions/multi-suggestion.unicode.stderr +++ b/tests/ui/suggestions/multi-suggestion.unicode.stderr @@ -68,7 +68,7 @@ LL - x: (), LL - })), LL + wtf: Some(Box::new_in(_, _)), │ - ╰ and 15 other candidates + ╰ and 16 other candidates help: consider using the `Default` trait ╭╴ LL - wtf: Some(Box(U { @@ -125,7 +125,7 @@ LL + let _ = Box::new_zeroed(); LL - let _ = Box {}; LL + let _ = Box::new_in(_, _); │ - ╰ and 16 other candidates + ╰ and 17 other candidates help: consider using the `Default` trait ╭╴ LL - let _ = Box {}; From 73d8ca8f6a3649d24c0f02d4a97469cf585899c2 Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas Chirananthavat)" Date: Fri, 16 Oct 2026 09:35:58 +0700 Subject: [PATCH 02/34] Add `let_underscore_drop_guard` lint. This lint is similar to the existing `let_underscore_lock` lint, but applies to `DropGuard` instead of `MutexGuard` and similar types. --- compiler/rustc_lint/src/diagnostics.rs | 7 ++ compiler/rustc_lint/src/let_underscore.rs | 46 +++++++++- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/mem/drop_guard.rs | 1 + .../let_underscore_drop_guard.rs | 23 +++++ .../let_underscore_drop_guard.stderr | 86 +++++++++++++++++++ 6 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 tests/ui/lint/let_underscore/let_underscore_drop_guard.rs create mode 100644 tests/ui/lint/let_underscore/let_underscore_drop_guard.stderr diff --git a/compiler/rustc_lint/src/diagnostics.rs b/compiler/rustc_lint/src/diagnostics.rs index 5167737ac001f..8a9a2525c8a74 100644 --- a/compiler/rustc_lint/src/diagnostics.rs +++ b/compiler/rustc_lint/src/diagnostics.rs @@ -1330,6 +1330,13 @@ pub(crate) enum NonBindingLet { #[subdiagnostic] sub: NonBindingLetSub, }, + #[diag("non-binding let on a `DropGuard`")] + DropGuard { + #[label("this `DropGuard` is not assigned to a binding and is immediately dropped")] + pat: Span, + #[subdiagnostic] + sub: NonBindingLetSub, + }, #[diag("non-binding let on a type that has a destructor")] DropType { #[subdiagnostic] diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index 9d154be832995..7953d5afab41d 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -95,7 +95,43 @@ declare_lint! { "non-binding let on a synchronization lock" } -declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_DROP, LET_UNDERSCORE_LOCK]); +declare_lint! { + /// The `let_underscore_drop_guard` lint checks for statements which don't bind + /// a `DropGuard` to anything, causing its closure to run immediately instead + /// of at end of scope, which is typically incorrect. + /// + /// ### Example + /// ```rust,compile_fail + /// use std::mem::DropGuard; + /// + /// // The closure runs immediately instead of at the end of the scope, + /// // which is probably not intended. + /// let _ = DropGuard::new((), |_| { + /// println!("cleaning up"); + /// }); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Statements which assign an expression to an underscore causes the + /// expression to immediately drop instead of extending the expression's + /// lifetime to the end of the scope. This is usually unintended, + /// especially for types like `DropGuard`, which are typically used to + /// ensure running some cleanup code at the end of a scope. + /// + /// If you want to extend the expression's lifetime to the end of the scope, + /// assign an underscore-prefixed name (such as `_foo`) to the expression. + /// If you do actually want to drop the expression immediately, then + /// calling `std::mem::drop` on the expression is clearer and helps convey + /// intent. + pub LET_UNDERSCORE_DROP_GUARD, + Deny, + "non-binding let on a `DropGuard`" +} + +declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_DROP, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_DROP_GUARD]); const SYNC_GUARD_SYMBOLS: [Symbol; 3] = [ rustc_span::sym::MutexGuard, @@ -144,6 +180,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { .any(|guard_symbol| cx.tcx.is_diagnostic_item(*guard_symbol, adt.did())), _ => false, }; + let is_drop_guard = matches!(ty.kind(), ty::Adt(adt, _) if cx.tcx.is_diagnostic_item(sym::DropGuard, adt.did())); let can_use_init = is_top_level.then_some(local.init).flatten(); @@ -161,6 +198,13 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { span, NonBindingLet::SyncLock { sub, pat: pat.span }, ); + } else if is_drop_guard { + let span = MultiSpan::from_span(pat.span); + cx.emit_span_lint( + LET_UNDERSCORE_DROP_GUARD, + span, + NonBindingLet::DropGuard { sub, pat: pat.span }, + ); // Only emit let_underscore_drop for top-level `_` patterns. } else if can_use_init.is_some() { cx.emit_span_lint(LET_UNDERSCORE_DROP, local.span, NonBindingLet::DropType { sub }); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 963c549ea5ee1..f4b29d9e0a9bd 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -207,6 +207,7 @@ symbols! { Deref, DispatchFromDyn, Display, + DropGuard, Dual, DualOnly, Dualv, diff --git a/library/core/src/mem/drop_guard.rs b/library/core/src/mem/drop_guard.rs index d997ab680e354..f7e610c68ddc9 100644 --- a/library/core/src/mem/drop_guard.rs +++ b/library/core/src/mem/drop_guard.rs @@ -30,6 +30,7 @@ use crate::ops::{Deref, DerefMut}; #[stable(feature = "drop_guard", since = "1.100.0")] #[doc(alias = "ScopeGuard")] #[doc(alias = "defer")] +#[rustc_diagnostic_item = "DropGuard"] pub struct DropGuard<#[rustc_assert_variance(covariant)] T, #[rustc_assert_variance(covariant)] F> where F: FnOnce(T), diff --git a/tests/ui/lint/let_underscore/let_underscore_drop_guard.rs b/tests/ui/lint/let_underscore/let_underscore_drop_guard.rs new file mode 100644 index 0000000000000..b1a82438acdfc --- /dev/null +++ b/tests/ui/lint/let_underscore/let_underscore_drop_guard.rs @@ -0,0 +1,23 @@ +use std::mem::DropGuard; + +struct Struct { + a: T, +} + +fn main() { + let _ = DropGuard::new((), |_| {}); + //~^ERROR non-binding let on a `DropGuard` + _ = DropGuard::new((), |_| {}); + //~^ERROR non-binding let on a `DropGuard` + + let (_, _) = (DropGuard::new((), |_| {}), 1); + //~^ERROR non-binding let on a `DropGuard` + (_, _) = (DropGuard::new((), |_| {}), 1); + //~^ERROR non-binding let on a `DropGuard` + + let (_a, Struct { a: _ }) = (0, Struct { a: DropGuard::new((), |_| {}) }); + //~^ERROR non-binding let on a `DropGuard` + let _b; + (_b, Struct { a: _ }) = (0, Struct { a: DropGuard::new((), |_| {}) }); + //~^ERROR non-binding let on a `DropGuard` +} diff --git a/tests/ui/lint/let_underscore/let_underscore_drop_guard.stderr b/tests/ui/lint/let_underscore/let_underscore_drop_guard.stderr new file mode 100644 index 0000000000000..c4c58fa6b4b95 --- /dev/null +++ b/tests/ui/lint/let_underscore/let_underscore_drop_guard.stderr @@ -0,0 +1,86 @@ +error: non-binding let on a `DropGuard` + --> $DIR/let_underscore_drop_guard.rs:8:9 + | +LL | let _ = DropGuard::new((), |_| {}); + | ^ this `DropGuard` is not assigned to a binding and is immediately dropped + | + = note: `#[deny(let_underscore_drop_guard)]` on by default +help: consider binding to an unused variable to avoid immediately dropping the value + | +LL | let _unused = DropGuard::new((), |_| {}); + | ++++++ +help: consider immediately dropping the value + | +LL - let _ = DropGuard::new((), |_| {}); +LL + drop(DropGuard::new((), |_| {})); + | + +error: non-binding let on a `DropGuard` + --> $DIR/let_underscore_drop_guard.rs:10:5 + | +LL | _ = DropGuard::new((), |_| {}); + | ^ this `DropGuard` is not assigned to a binding and is immediately dropped + | +help: consider binding to an unused variable to avoid immediately dropping the value + | +LL - _ = DropGuard::new((), |_| {}); +LL + let _unused = DropGuard::new((), |_| {}); + | +help: consider immediately dropping the value + | +LL - _ = DropGuard::new((), |_| {}); +LL + drop(DropGuard::new((), |_| {})); + | + +error: non-binding let on a `DropGuard` + --> $DIR/let_underscore_drop_guard.rs:13:10 + | +LL | let (_, _) = (DropGuard::new((), |_| {}), 1); + | ^ this `DropGuard` is not assigned to a binding and is immediately dropped + | + = help: consider immediately dropping the value using `drop(..)` after the `let` statement +help: consider binding to an unused variable to avoid immediately dropping the value + | +LL | let (_unused, _) = (DropGuard::new((), |_| {}), 1); + | ++++++ + +error: non-binding let on a `DropGuard` + --> $DIR/let_underscore_drop_guard.rs:15:6 + | +LL | (_, _) = (DropGuard::new((), |_| {}), 1); + | ^ this `DropGuard` is not assigned to a binding and is immediately dropped + | +help: consider binding to an unused variable to avoid immediately dropping the value + --> $DIR/let_underscore_drop_guard.rs:15:6 + | +LL | (_, _) = (DropGuard::new((), |_| {}), 1); + | ^ + = help: consider immediately dropping the value using `drop(..)` after the `let` statement + +error: non-binding let on a `DropGuard` + --> $DIR/let_underscore_drop_guard.rs:18:26 + | +LL | let (_a, Struct { a: _ }) = (0, Struct { a: DropGuard::new((), |_| {}) }); + | ^ this `DropGuard` is not assigned to a binding and is immediately dropped + | + = help: consider immediately dropping the value using `drop(..)` after the `let` statement +help: consider binding to an unused variable to avoid immediately dropping the value + | +LL | let (_a, Struct { a: _unused }) = (0, Struct { a: DropGuard::new((), |_| {}) }); + | ++++++ + +error: non-binding let on a `DropGuard` + --> $DIR/let_underscore_drop_guard.rs:21:22 + | +LL | (_b, Struct { a: _ }) = (0, Struct { a: DropGuard::new((), |_| {}) }); + | ^ this `DropGuard` is not assigned to a binding and is immediately dropped + | +help: consider binding to an unused variable to avoid immediately dropping the value + --> $DIR/let_underscore_drop_guard.rs:21:22 + | +LL | (_b, Struct { a: _ }) = (0, Struct { a: DropGuard::new((), |_| {}) }); + | ^ + = help: consider immediately dropping the value using `drop(..)` after the `let` statement + +error: aborting due to 6 previous errors + From e4a18a665b4b8d9384bb332eb97af23221b4ff39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 29 Jul 2026 20:26:57 +0000 Subject: [PATCH 03/34] Provide more context when an expected type was a type parameter This becomes particularly confusing when a type parameter has a default. ``` --> $DIR/default-type-parameter.rs:8:17 | LL | fn foo() -> u32 { 0 } | ^^^ expected `()`, found `u32` | note: type in trait --> $DIR/default-type-parameter.rs:2:17 | LL | fn foo() -> T; | ^ = note: expected signature `fn() -> ()` found signature `fn() -> u32` note: expected to match this type parameter --> $DIR/default-type-parameter.rs:1:13 | LL | trait Trait { | ^^^^^^ help: change the output type to match the trait | LL - fn foo() -> u32 { 0 } LL + fn foo() -> () { 0 } ``` --- .../src/check/compare_impl_item.rs | 13 +++++ tests/ui/compare-method/bad-self-type.stderr | 5 ++ .../compare-method/default-type-parameter.rs | 14 +++++ .../default-type-parameter.stderr | 51 +++++++++++++++++++ tests/ui/compare-method/issue-90444.stderr | 2 + .../reordered-type-param.stderr | 5 ++ .../fn-impl-mismatched-param-type.stderr | 6 +++ .../traits/wrong-mul-method-signature.stderr | 4 ++ 8 files changed, 100 insertions(+) create mode 100644 tests/ui/compare-method/default-type-parameter.rs create mode 100644 tests/ui/compare-method/default-type-parameter.stderr diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 8a7ad70f8ebb1..6f8baee71e176 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1092,6 +1092,19 @@ fn report_trait_method_mismatch<'tcx>( None, ); + if let TypeError::ArgumentSorts(_, i) = &terr + && let Some(ty) = + tcx.fn_sig(trait_m.def_id).skip_binder().inputs_and_output().skip_binder().get(*i) + && let ty::Param(param) = ty.kind() + { + // The expected type corresponds to a type parameter, which migh thave a default type or + // have been explicitly set in the `impl` with a different type. + let generics = tcx.generics_of(trait_m.def_id); + let param = generics.type_param(*param, tcx); + let span = tcx.def_span(param.def_id); + diag.span_note(span, format!("expected to match this type parameter")); + } + diag.emit_err() } diff --git a/tests/ui/compare-method/bad-self-type.stderr b/tests/ui/compare-method/bad-self-type.stderr index bc1587883a352..ea5a45214702f 100644 --- a/tests/ui/compare-method/bad-self-type.stderr +++ b/tests/ui/compare-method/bad-self-type.stderr @@ -24,6 +24,11 @@ LL | fn foo(self); | ^^^^ = note: expected signature `fn(MyFuture)` found signature `fn(Box)` +note: expected to match this type parameter + --> $DIR/bad-self-type.rs:16:1 + | +LL | trait T { + | ^^^^^^^ help: change the self-receiver type to match the trait | LL - fn foo(self: Box) {} diff --git a/tests/ui/compare-method/default-type-parameter.rs b/tests/ui/compare-method/default-type-parameter.rs new file mode 100644 index 0000000000000..92746fb4ebcad --- /dev/null +++ b/tests/ui/compare-method/default-type-parameter.rs @@ -0,0 +1,14 @@ +trait Trait { + fn foo() -> T; +} + +struct S; + +impl Trait for S { + fn foo() -> u32 { 0 } //~ ERROR +} +impl Trait for () { + fn foo() -> u32 { 0 } //~ ERROR +} + +fn main() {} diff --git a/tests/ui/compare-method/default-type-parameter.stderr b/tests/ui/compare-method/default-type-parameter.stderr new file mode 100644 index 0000000000000..a97e772dc238d --- /dev/null +++ b/tests/ui/compare-method/default-type-parameter.stderr @@ -0,0 +1,51 @@ +error[E0053]: method `foo` has an incompatible type for trait + --> $DIR/default-type-parameter.rs:8:17 + | +LL | fn foo() -> u32 { 0 } + | ^^^ expected `()`, found `u32` + | +note: type in trait + --> $DIR/default-type-parameter.rs:2:17 + | +LL | fn foo() -> T; + | ^ + = note: expected signature `fn() -> ()` + found signature `fn() -> u32` +note: expected to match this type parameter + --> $DIR/default-type-parameter.rs:1:13 + | +LL | trait Trait { + | ^^^^^^ +help: change the output type to match the trait + | +LL - fn foo() -> u32 { 0 } +LL + fn foo() -> () { 0 } + | + +error[E0053]: method `foo` has an incompatible type for trait + --> $DIR/default-type-parameter.rs:11:17 + | +LL | fn foo() -> u32 { 0 } + | ^^^ expected `i32`, found `u32` + | +note: type in trait + --> $DIR/default-type-parameter.rs:2:17 + | +LL | fn foo() -> T; + | ^ + = note: expected signature `fn() -> i32` + found signature `fn() -> u32` +note: expected to match this type parameter + --> $DIR/default-type-parameter.rs:1:13 + | +LL | trait Trait { + | ^^^^^^ +help: change the output type to match the trait + | +LL - fn foo() -> u32 { 0 } +LL + fn foo() -> i32 { 0 } + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/compare-method/issue-90444.stderr b/tests/ui/compare-method/issue-90444.stderr index c69d63b3e30bc..8071dbc4442d5 100644 --- a/tests/ui/compare-method/issue-90444.stderr +++ b/tests/ui/compare-method/issue-90444.stderr @@ -20,6 +20,8 @@ LL | fn from(_: fn((), (), u64)) -> Self { | = note: expected signature `fn(fn((), (), u32)) -> B` found signature `fn(fn((), (), u64)) -> B` +note: expected to match this type parameter + --> $SRC_DIR/core/src/convert/mod.rs:LL:COL help: change the parameter type to match the trait | LL - fn from(_: fn((), (), u64)) -> Self { diff --git a/tests/ui/compare-method/reordered-type-param.stderr b/tests/ui/compare-method/reordered-type-param.stderr index 536364871a368..8bb88cb185999 100644 --- a/tests/ui/compare-method/reordered-type-param.stderr +++ b/tests/ui/compare-method/reordered-type-param.stderr @@ -16,6 +16,11 @@ LL | fn b(&self, x: C) -> C; found signature `fn(&E, G) -> G` = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters +note: expected to match this type parameter + --> $DIR/reordered-type-param.rs:7:8 + | +LL | fn b(&self, x: C) -> C; + | ^ help: change the parameter type to match the trait | LL - fn b(&self, _x: G) -> G { panic!() } diff --git a/tests/ui/fn_traits/fn-impl-mismatched-param-type.stderr b/tests/ui/fn_traits/fn-impl-mismatched-param-type.stderr index b7aa3d29f0d7d..1e2819d48fb6e 100644 --- a/tests/ui/fn_traits/fn-impl-mismatched-param-type.stderr +++ b/tests/ui/fn_traits/fn-impl-mismatched-param-type.stderr @@ -8,6 +8,8 @@ LL | extern "rust-call" fn call(&self, (_,): (T,)) {} | = note: expected signature `extern "rust-call" fn(&Foo, (&'a _,))` found signature `extern "rust-call" fn(&Foo, (_,))` +note: expected to match this type parameter + --> $SRC_DIR/core/src/ops/function.rs:LL:COL help: change the parameter type to match the trait | LL | extern "rust-call" fn call(&self, (_,): (&'a T,)) {} @@ -23,6 +25,8 @@ LL | extern "rust-call" fn call_mut(&mut self, (_,): (T,)) {} | = note: expected signature `extern "rust-call" fn(&mut Foo, (&'a _,))` found signature `extern "rust-call" fn(&mut Foo, (_,))` +note: expected to match this type parameter + --> $SRC_DIR/core/src/ops/function.rs:LL:COL help: change the parameter type to match the trait | LL | extern "rust-call" fn call_mut(&mut self, (_,): (&'a T,)) {} @@ -39,6 +43,8 @@ LL | extern "rust-call" fn call_once(self, (_,): (T,)) {} | = note: expected signature `extern "rust-call" fn(Foo, (&'a _,))` found signature `extern "rust-call" fn(Foo, (_,))` +note: expected to match this type parameter + --> $SRC_DIR/core/src/ops/function.rs:LL:COL help: change the parameter type to match the trait | LL | extern "rust-call" fn call_once(self, (_,): (&'a T,)) {} diff --git a/tests/ui/traits/wrong-mul-method-signature.stderr b/tests/ui/traits/wrong-mul-method-signature.stderr index bdfc4320631b0..8cef50ef1d6f7 100644 --- a/tests/ui/traits/wrong-mul-method-signature.stderr +++ b/tests/ui/traits/wrong-mul-method-signature.stderr @@ -6,6 +6,8 @@ LL | fn mul(self, s: &f64) -> Vec1 { | = note: expected signature `fn(Vec1, _) -> Vec1` found signature `fn(Vec1, &_) -> Vec1` +note: expected to match this type parameter + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL help: change the parameter type to match the trait | LL - fn mul(self, s: &f64) -> Vec1 { @@ -20,6 +22,8 @@ LL | fn mul(self, s: f64) -> Vec2 { | = note: expected signature `fn(Vec2, Vec2) -> f64` found signature `fn(Vec2, f64) -> Vec2` +note: expected to match this type parameter + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL help: change the parameter type to match the trait | LL - fn mul(self, s: f64) -> Vec2 { From b1476a0e58fb3fdbe6218f3a29853d48a1c5c5e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 5 Oct 2026 20:00:33 +0000 Subject: [PATCH 04/34] Only point at param with default type --- .../rustc_hir_analysis/src/check/compare_impl_item.rs | 10 ++++++---- tests/ui/compare-method/bad-self-type.stderr | 5 ----- tests/ui/compare-method/issue-90444.stderr | 2 -- tests/ui/compare-method/reordered-type-param.stderr | 5 ----- .../ui/fn_traits/fn-impl-mismatched-param-type.stderr | 6 ------ 5 files changed, 6 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 6f8baee71e176..51431672b736b 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1096,12 +1096,14 @@ fn report_trait_method_mismatch<'tcx>( && let Some(ty) = tcx.fn_sig(trait_m.def_id).skip_binder().inputs_and_output().skip_binder().get(*i) && let ty::Param(param) = ty.kind() - { // The expected type corresponds to a type parameter, which migh thave a default type or // have been explicitly set in the `impl` with a different type. - let generics = tcx.generics_of(trait_m.def_id); - let param = generics.type_param(*param, tcx); - let span = tcx.def_span(param.def_id); + && let generics = tcx.generics_of(trait_m.def_id) + && let param = generics.type_param(*param, tcx) + && let GenericParamDefKind::Type { has_default: true, .. } = param.kind + { + let mut span: MultiSpan = tcx.def_span(param.def_id).into(); + span.push_span_context(tcx.def_span(trait_m.container_id(tcx)).shrink_to_lo()); diag.span_note(span, format!("expected to match this type parameter")); } diff --git a/tests/ui/compare-method/bad-self-type.stderr b/tests/ui/compare-method/bad-self-type.stderr index ea5a45214702f..bc1587883a352 100644 --- a/tests/ui/compare-method/bad-self-type.stderr +++ b/tests/ui/compare-method/bad-self-type.stderr @@ -24,11 +24,6 @@ LL | fn foo(self); | ^^^^ = note: expected signature `fn(MyFuture)` found signature `fn(Box)` -note: expected to match this type parameter - --> $DIR/bad-self-type.rs:16:1 - | -LL | trait T { - | ^^^^^^^ help: change the self-receiver type to match the trait | LL - fn foo(self: Box) {} diff --git a/tests/ui/compare-method/issue-90444.stderr b/tests/ui/compare-method/issue-90444.stderr index 8071dbc4442d5..c69d63b3e30bc 100644 --- a/tests/ui/compare-method/issue-90444.stderr +++ b/tests/ui/compare-method/issue-90444.stderr @@ -20,8 +20,6 @@ LL | fn from(_: fn((), (), u64)) -> Self { | = note: expected signature `fn(fn((), (), u32)) -> B` found signature `fn(fn((), (), u64)) -> B` -note: expected to match this type parameter - --> $SRC_DIR/core/src/convert/mod.rs:LL:COL help: change the parameter type to match the trait | LL - fn from(_: fn((), (), u64)) -> Self { diff --git a/tests/ui/compare-method/reordered-type-param.stderr b/tests/ui/compare-method/reordered-type-param.stderr index 8bb88cb185999..536364871a368 100644 --- a/tests/ui/compare-method/reordered-type-param.stderr +++ b/tests/ui/compare-method/reordered-type-param.stderr @@ -16,11 +16,6 @@ LL | fn b(&self, x: C) -> C; found signature `fn(&E, G) -> G` = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters -note: expected to match this type parameter - --> $DIR/reordered-type-param.rs:7:8 - | -LL | fn b(&self, x: C) -> C; - | ^ help: change the parameter type to match the trait | LL - fn b(&self, _x: G) -> G { panic!() } diff --git a/tests/ui/fn_traits/fn-impl-mismatched-param-type.stderr b/tests/ui/fn_traits/fn-impl-mismatched-param-type.stderr index 1e2819d48fb6e..b7aa3d29f0d7d 100644 --- a/tests/ui/fn_traits/fn-impl-mismatched-param-type.stderr +++ b/tests/ui/fn_traits/fn-impl-mismatched-param-type.stderr @@ -8,8 +8,6 @@ LL | extern "rust-call" fn call(&self, (_,): (T,)) {} | = note: expected signature `extern "rust-call" fn(&Foo, (&'a _,))` found signature `extern "rust-call" fn(&Foo, (_,))` -note: expected to match this type parameter - --> $SRC_DIR/core/src/ops/function.rs:LL:COL help: change the parameter type to match the trait | LL | extern "rust-call" fn call(&self, (_,): (&'a T,)) {} @@ -25,8 +23,6 @@ LL | extern "rust-call" fn call_mut(&mut self, (_,): (T,)) {} | = note: expected signature `extern "rust-call" fn(&mut Foo, (&'a _,))` found signature `extern "rust-call" fn(&mut Foo, (_,))` -note: expected to match this type parameter - --> $SRC_DIR/core/src/ops/function.rs:LL:COL help: change the parameter type to match the trait | LL | extern "rust-call" fn call_mut(&mut self, (_,): (&'a T,)) {} @@ -43,8 +39,6 @@ LL | extern "rust-call" fn call_once(self, (_,): (T,)) {} | = note: expected signature `extern "rust-call" fn(Foo, (&'a _,))` found signature `extern "rust-call" fn(Foo, (_,))` -note: expected to match this type parameter - --> $SRC_DIR/core/src/ops/function.rs:LL:COL help: change the parameter type to match the trait | LL | extern "rust-call" fn call_once(self, (_,): (&'a T,)) {} From b1cf8bd33fc05c05941d01010e67c345a462d2b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 5 Oct 2026 20:58:36 +0000 Subject: [PATCH 05/34] Tweak message --- .../src/check/compare_impl_item.rs | 19 +++++++++++++++++-- .../default-type-parameter.stderr | 4 ++-- .../traits/wrong-mul-method-signature.stderr | 4 ++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 51431672b736b..47a623bee8659 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::{ TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Unnormalized, Upcast, }; -use rustc_span::{BytePos, DUMMY_SP, Span, bug, span_bug}; +use rustc_span::{BytePos, DUMMY_SP, Span, bug, kw, span_bug}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::regions::InferCtxtRegionExt; @@ -1104,7 +1104,22 @@ fn report_trait_method_mismatch<'tcx>( { let mut span: MultiSpan = tcx.def_span(param.def_id).into(); span.push_span_context(tcx.def_span(trait_m.container_id(tcx)).shrink_to_lo()); - diag.span_note(span, format!("expected to match this type parameter")); + + let param_name = param.name; + let msg = if let Some(ty) = trait_sig.inputs_and_output.get(*i) + && infcx.can_eq(param_env, *ty, tcx.type_of(param.def_id).skip_binder()) + { + format!("expected to match the default of type parameter `{param_name}`") + } else if let Some(ty) = trait_sig.inputs_and_output.get(*i) + && let ty::Param(p) = tcx.type_of(param.def_id).skip_binder().kind() + && p.name == kw::SelfUpper + && infcx.can_eq(param_env, *ty, impl_trait_ref.self_ty()) + { + format!("expected to match the `Self` default of type parameter `{param_name}`") + } else { + format!("expected to match type parameter `{param_name}`") + }; + diag.span_note(span, msg); } diag.emit_err() diff --git a/tests/ui/compare-method/default-type-parameter.stderr b/tests/ui/compare-method/default-type-parameter.stderr index a97e772dc238d..71952e9274987 100644 --- a/tests/ui/compare-method/default-type-parameter.stderr +++ b/tests/ui/compare-method/default-type-parameter.stderr @@ -11,7 +11,7 @@ LL | fn foo() -> T; | ^ = note: expected signature `fn() -> ()` found signature `fn() -> u32` -note: expected to match this type parameter +note: expected to match the default of type parameter `T` --> $DIR/default-type-parameter.rs:1:13 | LL | trait Trait { @@ -35,7 +35,7 @@ LL | fn foo() -> T; | ^ = note: expected signature `fn() -> i32` found signature `fn() -> u32` -note: expected to match this type parameter +note: expected to match type parameter `T` --> $DIR/default-type-parameter.rs:1:13 | LL | trait Trait { diff --git a/tests/ui/traits/wrong-mul-method-signature.stderr b/tests/ui/traits/wrong-mul-method-signature.stderr index 8cef50ef1d6f7..d119274352f81 100644 --- a/tests/ui/traits/wrong-mul-method-signature.stderr +++ b/tests/ui/traits/wrong-mul-method-signature.stderr @@ -6,7 +6,7 @@ LL | fn mul(self, s: &f64) -> Vec1 { | = note: expected signature `fn(Vec1, _) -> Vec1` found signature `fn(Vec1, &_) -> Vec1` -note: expected to match this type parameter +note: expected to match type parameter `Rhs` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL help: change the parameter type to match the trait | @@ -22,7 +22,7 @@ LL | fn mul(self, s: f64) -> Vec2 { | = note: expected signature `fn(Vec2, Vec2) -> f64` found signature `fn(Vec2, f64) -> Vec2` -note: expected to match this type parameter +note: expected to match the `Self` default of type parameter `Rhs` --> $SRC_DIR/core/src/ops/arith.rs:LL:COL help: change the parameter type to match the trait | From bd34b4d0ade6ba8f13ba8762dbf174f1f3b1fb28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 5 Oct 2026 21:43:49 +0000 Subject: [PATCH 06/34] Provide trait and impl context when an assoc item doesn't agree with the trait ``` error[E0053]: method `foo` has an incompatible type for trait --> $DIR/async-example-desugared-boxed-in-trait.rs:11:28 | LL | impl MyTrait for i32 { LL | async fn foo(&self) -> i32 { | ^^^ expected `Pin>>`, found future | note: type in trait --> $DIR/async-example-desugared-boxed-in-trait.rs:7:22 | LL | trait MyTrait { LL | fn foo(&self) -> Pin + '_>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected signature `fn(&_) -> Pin>>` found signature `fn(&_) -> impl Future` ``` --- .../src/check/compare_eii.rs | 2 +- .../src/check/compare_impl_item.rs | 27 +++++++++++++--- .../src/error_reporting/infer/mod.rs | 31 +++++++++++++------ .../traits/fulfillment_errors.rs | 2 +- ...ssociated-const-generic-obligations.stderr | 2 ++ .../associated-const-impl-wrong-type.stderr | 2 ++ .../defaults-specialization.stderr | 5 +++ ...nc-example-desugared-boxed-in-trait.stderr | 2 ++ ...project-to-specializable-projection.stderr | 2 ++ tests/ui/compare-method/bad-self-type.stderr | 8 +++++ .../default-type-parameter.stderr | 4 +++ tests/ui/compare-method/issue-90444.stderr | 2 ++ .../reordered-type-param.stderr | 3 ++ ...e-const-value-type-mismatch.current.stderr | 4 +++ .../issue-70942-trait-vs-impl-mismatch.stderr | 2 ++ ...eful-error-for-mistyped-assoc-const.stderr | 1 + .../target-expr-removal-defs-inside.stderr | 3 ++ .../unused-target-expr-in-glob-or-list.stderr | 6 +++- ...-gate-unboxed-closures-manual-impls.stderr | 4 +++ ...fn-traits-call-once-signature-15094.stderr | 2 ++ .../apit/impl-generic-mismatch-ab.stderr | 2 ++ .../in-assoc-type-unconstrained.stderr | 3 ++ .../ui/impl-trait/in-trait/deep-match.stderr | 12 ++++--- .../method-signature-matches.lt.stderr | 2 ++ .../method-signature-matches.mismatch.stderr | 2 ++ ...od-signature-matches.mismatch_async.stderr | 2 ++ .../in-trait/specialization-broken.stderr | 1 + ...s-impl-trait-declaration-too-subtle.stderr | 3 ++ tests/ui/impl-trait/trait_type.stderr | 1 + tests/ui/impl-trait/where-allowed.stderr | 3 ++ tests/ui/mir/inline-wrong-abi.stderr | 1 + tests/ui/mismatched_types/E0053.stderr | 6 ++++ tests/ui/mismatched_types/issue-112036.stderr | 1 + tests/ui/mismatched_types/issue-13033.stderr | 2 ++ .../trait-impl-fn-incompatibility.stderr | 6 ++++ tests/ui/mut/mismatch-trait-mut.e2015.stderr | 14 +++++++++ tests/ui/mut/mismatch-trait-mut.e2018.stderr | 14 +++++++++ .../pin-ergonomics/pinned-drop-check.stderr | 8 +++++ .../ui/splat/splat-invalid-trait-impl.stderr | 6 ++++ tests/ui/splat/splat-invalid.stderr | 6 ++++ tests/ui/splat/splat-non-tuple.stderr | 2 ++ .../target-feature/invalid-attribute.stderr | 3 ++ .../const-traits/eval-bad-signature.stderr | 2 ++ .../incompatible-method-multiline.stderr | 2 ++ tests/ui/traits/impl-method-mismatch.stderr | 3 ++ tests/ui/traits/issue-35869.stderr | 14 +++++++++ .../traits/wrong-mul-method-signature.stderr | 6 ++++ .../unnameable_type.stderr | 4 ++- .../typeck/mismatched-map-under-self.stderr | 4 +++ tests/ui/ufcs/ufcs-explicit-self-bad.stderr | 4 +++ tests/ui/unsafe/unsafe-trait-impl.stderr | 2 ++ 51 files changed, 232 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index 6e22ce3d84b76..78944cfff352e 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -511,7 +511,7 @@ fn report_eii_mismatch<'tcx>( infcx.err_ctxt().note_type_err( &mut diag, &cause, - trait_err_span.map(|sp| (sp, Cow::from("type in declaration"), false)), + trait_err_span.map(|sp| (sp.into(), Cow::from("type in declaration"), false)), Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound { expected: ty::Binder::dummy(declaration_sig), found: ty::Binder::dummy(external_impl_sig), diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 47a623bee8659..6c371a9cd1788 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -625,12 +625,16 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( "method `{}` has an incompatible return type for trait", trait_m.name() ); + diag.span_context(tcx.def_span(impl_m.container_id(tcx)).shrink_to_lo()); infcx.err_ctxt().note_type_err( &mut diag, &cause, - tcx.hir_get_if_local(impl_m.def_id) - .and_then(|node| node.fn_decl()) - .map(|decl| (decl.output.span(), Cow::from("return type in trait"), false)), + tcx.hir_get_if_local(trait_m.def_id).and_then(|node| node.fn_decl()).map(|decl| { + let mut span: MultiSpan = decl.output.span().into(); + span.push_span_context(tcx.def_span(trait_m.container_id(tcx)).shrink_to_lo()); + span.push_span_context(tcx.def_span(trait_m.def_id).shrink_to_lo()); + (span, Cow::from("return type in trait"), false) + }), Some(param_env.and(infer::ValuePairs::Terms(ExpectedFound { expected: trait_return_ty.into(), found: impl_return_ty.into(), @@ -1014,6 +1018,7 @@ fn report_trait_method_mismatch<'tcx>( "method `{}` has an incompatible type for trait", trait_m.name() ); + diag.span_context(tcx.def_span(impl_m.container_id(tcx)).shrink_to_lo()); match &terr { TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0) if trait_m.is_method() => @@ -1082,7 +1087,12 @@ fn report_trait_method_mismatch<'tcx>( infcx.err_ctxt().note_type_err( &mut diag, &cause, - trait_err_span.map(|sp| (sp, Cow::from("type in trait"), false)), + trait_err_span.map(|sp| { + let mut span: MultiSpan = sp.into(); + span.push_span_context(tcx.def_span(trait_m.container_id(tcx)).shrink_to_lo()); + span.push_span_context(tcx.def_span(trait_m.def_id).shrink_to_lo()); + (span, Cow::from("type in trait"), false) + }), Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound { expected: ty::Binder::dummy(trait_sig), found: ty::Binder::dummy(impl_sig), @@ -2395,6 +2405,8 @@ fn compare_const_clause_entailment<'tcx>( "implemented const `{}` has an incompatible type for trait", trait_ct.name() ); + diag.span_context(tcx.def_span(impl_ct.container_id(tcx)).shrink_to_lo()); + diag.span_context(tcx.def_span(impl_ct.def_id).shrink_to_lo()); let trait_c_span = trait_ct.def_id.as_local().map(|trait_ct_def_id| { // Add a label to the Span containing just the type of the const @@ -2405,7 +2417,12 @@ fn compare_const_clause_entailment<'tcx>( infcx.err_ctxt().note_type_err( &mut diag, &cause, - trait_c_span.map(|span| (span, Cow::from("type in trait"), false)), + trait_c_span.map(|span| { + let mut span: MultiSpan = span.into(); + span.push_span_context(tcx.def_span(trait_ct.container_id(tcx)).shrink_to_lo()); + span.push_span_context(tcx.def_span(trait_ct.def_id).shrink_to_lo()); + (span, Cow::from("type in trait"), false) + }), Some(param_env.and(infer::ValuePairs::Terms(ExpectedFound { expected: trait_ty.into(), found: impl_ty.into(), diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index eada6d2457e75..c86dcad2b51d4 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -54,7 +54,9 @@ use rustc_abi::ExternAbi; use rustc_attr_ir::diagnostic::{CustomDiagnostic, Directive, FormatArgs}; use rustc_attr_ir::find_attr; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; -use rustc_errors::{Applicability, Diag, DiagStyledString, IntoDiagArg, StringPart, pluralize}; +use rustc_errors::{ + Applicability, Diag, DiagStyledString, IntoDiagArg, MultiSpan, StringPart, pluralize, +}; use rustc_hir as hir; use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_hir::intravisit::Visitor; @@ -1462,7 +1464,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &self, diag: &mut Diag<'_>, cause: &ObligationCause<'tcx>, - secondary_span: Option<(Span, Cow<'static, str>, bool)>, + secondary_span: Option<(MultiSpan, Cow<'static, str>, bool)>, mut values: Option>>, terr: TypeError<'tcx>, prefer_label: bool, @@ -1638,9 +1640,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } }; - let mut label_or_note = |span: Span, msg: Cow<'static, str>| { - if (prefer_label && is_simple_error) || &[span] == diag.span.primary_spans() { - diag.span_label(span, msg); + let mut label_or_note = |span: MultiSpan, msg: Cow<'static, str>| { + if !span.has_span_labels() + && span.span_context().is_empty() + && ((prefer_label && is_simple_error) + || span.primary_spans() == diag.span.primary_spans()) + { + for span in span.primary_spans() { + diag.span_label(*span, msg.clone()); + } } else { diag.span_note(span, msg); } @@ -1656,9 +1664,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { terr.to_string(self.tcx) }; label_or_note(secondary_span, terr); - label_or_note(span, secondary_msg); + label_or_note(span.into(), secondary_msg); } else { - label_or_note(span, terr.to_string(self.tcx)); + label_or_note(span.into(), terr.to_string(self.tcx)); label_or_note(secondary_span, secondary_msg); } } else if let Some(values) = values @@ -1670,12 +1678,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let expected = with_forced_trimmed_paths!(e.sort_string(self.tcx)); let found = with_forced_trimmed_paths!(f.sort_string(self.tcx)); if expected == found { - label_or_note(span, terr.to_string(self.tcx)); + label_or_note(span.into(), terr.to_string(self.tcx)); } else { - label_or_note(span, Cow::from(format!("expected {expected}, found {found}"))); + label_or_note( + span.into(), + Cow::from(format!("expected {expected}, found {found}")), + ); } } else { - label_or_note(span, terr.to_string(self.tcx)); + label_or_note(span.into(), terr.to_string(self.tcx)); } if let Some(param_env) = param_env { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index ca68ee77d67b3..acf1f4c165822 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1919,7 +1919,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .. }), ) => Some(( - ty.span, + ty.span.into(), with_forced_trimmed_paths!(Cow::from(format!( "type mismatch resolving `{}`", self.tcx.short_string( diff --git a/tests/ui/associated-consts/associated-const-generic-obligations.stderr b/tests/ui/associated-consts/associated-const-generic-obligations.stderr index 5ea85ff3b9899..f7431a1e690d7 100644 --- a/tests/ui/associated-consts/associated-const-generic-obligations.stderr +++ b/tests/ui/associated-consts/associated-const-generic-obligations.stderr @@ -1,12 +1,14 @@ error[E0326]: implemented const `FROM` has an incompatible type for trait --> $DIR/associated-const-generic-obligations.rs:14:17 | +LL | impl Bar for T { LL | const FROM: &'static str = "foo"; | ^^^^^^^^^^^^ expected associated type, found `&'static str` | note: type in trait --> $DIR/associated-const-generic-obligations.rs:10:17 | +LL | trait Bar: Foo { LL | const FROM: Self::Out; | ^^^^^^^^^ = note: expected associated type `::Out` diff --git a/tests/ui/associated-consts/associated-const-impl-wrong-type.stderr b/tests/ui/associated-consts/associated-const-impl-wrong-type.stderr index b91b777d5850f..6b517b4a00528 100644 --- a/tests/ui/associated-consts/associated-const-impl-wrong-type.stderr +++ b/tests/ui/associated-consts/associated-const-impl-wrong-type.stderr @@ -1,12 +1,14 @@ error[E0326]: implemented const `BAR` has an incompatible type for trait --> $DIR/associated-const-impl-wrong-type.rs:8:16 | +LL | impl Foo for SignedBar { LL | const BAR: i32 = -1; | ^^^ expected `u32`, found `i32` | note: type in trait --> $DIR/associated-const-impl-wrong-type.rs:2:16 | +LL | trait Foo { LL | const BAR: u32; | ^^^ diff --git a/tests/ui/associated-types/defaults-specialization.stderr b/tests/ui/associated-types/defaults-specialization.stderr index a03296af8a37b..ee0e9878e8e6a 100644 --- a/tests/ui/associated-types/defaults-specialization.stderr +++ b/tests/ui/associated-types/defaults-specialization.stderr @@ -1,12 +1,15 @@ error[E0053]: method `make` has an incompatible type for trait --> $DIR/defaults-specialization.rs:18:18 | +LL | default impl Tr for A { LL | fn make() -> u8 { 0 } | ^^ expected associated type, found `u8` | note: type in trait --> $DIR/defaults-specialization.rs:8:18 | +LL | trait Tr { +... LL | fn make() -> Self::Ty { | ^^^^^^^^ = note: expected signature `fn() -> as Tr>::Ty` @@ -30,6 +33,8 @@ LL | fn make() -> bool { true } note: type in trait --> $DIR/defaults-specialization.rs:8:18 | +LL | trait Tr { +... LL | fn make() -> Self::Ty { | ^^^^^^^^ = note: expected signature `fn() -> as Tr>::Ty` diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr index c98df134072eb..6fcba3870cb0c 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr +++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr @@ -1,12 +1,14 @@ error[E0053]: method `foo` has an incompatible type for trait --> $DIR/async-example-desugared-boxed-in-trait.rs:11:28 | +LL | impl MyTrait for i32 { LL | async fn foo(&self) -> i32 { | ^^^ expected `Pin>>`, found future | note: type in trait --> $DIR/async-example-desugared-boxed-in-trait.rs:7:22 | +LL | trait MyTrait { LL | fn foo(&self) -> Pin + '_>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected signature `fn(&_) -> Pin>>` diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr index d0c11565f4e90..4feaee82fef79 100644 --- a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr +++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr @@ -1,12 +1,14 @@ error[E0053]: method `foo` has an incompatible type for trait --> $DIR/dont-project-to-specializable-projection.rs:14:35 | +LL | impl MyTrait for MyStruct { LL | default async fn foo(_: T) -> &'static str { | ^^^^^^^^^^^^ expected associated type, found future | note: type in trait --> $DIR/dont-project-to-specializable-projection.rs:10:27 | +LL | trait MyTrait { LL | async fn foo(_: T) -> &'static str; | ^^^^^^^^^^^^ = note: expected signature `fn(_) -> impl Future` diff --git a/tests/ui/compare-method/bad-self-type.stderr b/tests/ui/compare-method/bad-self-type.stderr index bc1587883a352..fd5e13e5247ce 100644 --- a/tests/ui/compare-method/bad-self-type.stderr +++ b/tests/ui/compare-method/bad-self-type.stderr @@ -1,6 +1,8 @@ error[E0053]: method `poll` has an incompatible type for trait --> $DIR/bad-self-type.rs:10:13 | +LL | impl Future for MyFuture { +LL | type Output = (); LL | fn poll(self, _: &mut Context<'_>) -> Poll<()> { | ^^^^ expected `Pin<&mut MyFuture>`, found `MyFuture` | @@ -14,12 +16,14 @@ LL | fn poll(self: Pin<&mut MyFuture>, _: &mut Context<'_>) -> Poll<()> { error[E0053]: method `foo` has an incompatible type for trait --> $DIR/bad-self-type.rs:22:18 | +LL | impl T for MyFuture { LL | fn foo(self: Box) {} | ^^^^^^^^^ expected `MyFuture`, found `Box` | note: type in trait --> $DIR/bad-self-type.rs:17:12 | +LL | trait T { LL | fn foo(self); | ^^^^ = note: expected signature `fn(MyFuture)` @@ -33,12 +37,16 @@ LL + fn foo(self) {} error[E0053]: method `bar` has an incompatible type for trait --> $DIR/bad-self-type.rs:24:17 | +LL | impl T for MyFuture { +... LL | fn bar(self) {} | ^ expected `Option<()>`, found `()` | note: type in trait --> $DIR/bad-self-type.rs:18:21 | +LL | trait T { +LL | fn foo(self); LL | fn bar(self) -> Option<()>; | ^^^^^^^^^^ = note: expected signature `fn(MyFuture) -> Option<()>` diff --git a/tests/ui/compare-method/default-type-parameter.stderr b/tests/ui/compare-method/default-type-parameter.stderr index 71952e9274987..6b66aaa804ed0 100644 --- a/tests/ui/compare-method/default-type-parameter.stderr +++ b/tests/ui/compare-method/default-type-parameter.stderr @@ -1,12 +1,14 @@ error[E0053]: method `foo` has an incompatible type for trait --> $DIR/default-type-parameter.rs:8:17 | +LL | impl Trait for S { LL | fn foo() -> u32 { 0 } | ^^^ expected `()`, found `u32` | note: type in trait --> $DIR/default-type-parameter.rs:2:17 | +LL | trait Trait { LL | fn foo() -> T; | ^ = note: expected signature `fn() -> ()` @@ -25,12 +27,14 @@ LL + fn foo() -> () { 0 } error[E0053]: method `foo` has an incompatible type for trait --> $DIR/default-type-parameter.rs:11:17 | +LL | impl Trait for () { LL | fn foo() -> u32 { 0 } | ^^^ expected `i32`, found `u32` | note: type in trait --> $DIR/default-type-parameter.rs:2:17 | +LL | trait Trait { LL | fn foo() -> T; | ^ = note: expected signature `fn() -> i32` diff --git a/tests/ui/compare-method/issue-90444.stderr b/tests/ui/compare-method/issue-90444.stderr index c69d63b3e30bc..233def019ea42 100644 --- a/tests/ui/compare-method/issue-90444.stderr +++ b/tests/ui/compare-method/issue-90444.stderr @@ -1,6 +1,7 @@ error[E0053]: method `from` has an incompatible type for trait --> $DIR/issue-90444.rs:3:16 | +LL | impl From for A { LL | fn from(_: fn((), (), &mut ())) -> Self { | ^^^^^^^^^^^^^^^^^^^ types differ in mutability | @@ -15,6 +16,7 @@ LL + fn from(_: for<'a> fn((), (), &'a ())) -> Self { error[E0053]: method `from` has an incompatible type for trait --> $DIR/issue-90444.rs:11:16 | +LL | impl From for B { LL | fn from(_: fn((), (), u64)) -> Self { | ^^^^^^^^^^^^^^^ expected `u32`, found `u64` | diff --git a/tests/ui/compare-method/reordered-type-param.stderr b/tests/ui/compare-method/reordered-type-param.stderr index 536364871a368..bea7b43de48d0 100644 --- a/tests/ui/compare-method/reordered-type-param.stderr +++ b/tests/ui/compare-method/reordered-type-param.stderr @@ -1,6 +1,8 @@ error[E0053]: method `b` has an incompatible type for trait --> $DIR/reordered-type-param.rs:16:30 | +LL | impl A for E { +LL | // n.b. The error message is awful -- see #3404 LL | fn b(&self, _x: G) -> G { panic!() } | - - ^ expected type parameter `F`, found type parameter `G` | | | @@ -10,6 +12,7 @@ LL | fn b(&self, _x: G) -> G { panic!() } note: type in trait --> $DIR/reordered-type-param.rs:7:29 | +LL | trait A { LL | fn b(&self, x: C) -> C; | ^ = note: expected signature `fn(&E, F) -> F` diff --git a/tests/ui/const-generics/mgca/type-const-value-type-mismatch.current.stderr b/tests/ui/const-generics/mgca/type-const-value-type-mismatch.current.stderr index dc7f73f2549e8..5d0c6b06dfc8b 100644 --- a/tests/ui/const-generics/mgca/type-const-value-type-mismatch.current.stderr +++ b/tests/ui/const-generics/mgca/type-const-value-type-mismatch.current.stderr @@ -1,12 +1,16 @@ error[E0053]: method `arr` has an incompatible type for trait --> $DIR/type-const-value-type-mismatch.rs:24:5 | +LL | impl Array for A { +... LL | fn arr() -> [u8; const { Self::LEN }] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an array with a size of 0, found one with a size of const { Self::LEN } | note: type in trait --> $DIR/type-const-value-type-mismatch.rs:17:5 | +LL | pub trait Array { +... LL | fn arr() -> [u8; Self::LEN]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected signature `fn() -> [u8; 0]` diff --git a/tests/ui/consts/issue-70942-trait-vs-impl-mismatch.stderr b/tests/ui/consts/issue-70942-trait-vs-impl-mismatch.stderr index 0393316f166ba..0e877df4ea553 100644 --- a/tests/ui/consts/issue-70942-trait-vs-impl-mismatch.stderr +++ b/tests/ui/consts/issue-70942-trait-vs-impl-mismatch.stderr @@ -1,12 +1,14 @@ error[E0326]: implemented const `VALUE` has an incompatible type for trait --> $DIR/issue-70942-trait-vs-impl-mismatch.rs:8:18 | +LL | impl Nat for Zero { LL | const VALUE: i32 = 0; | ^^^ expected `usize`, found `i32` | note: type in trait --> $DIR/issue-70942-trait-vs-impl-mismatch.rs:2:18 | +LL | trait Nat { LL | const VALUE: usize; | ^^^^^ diff --git a/tests/ui/cross-crate/graceful-error-for-mistyped-assoc-const.stderr b/tests/ui/cross-crate/graceful-error-for-mistyped-assoc-const.stderr index 18b06462de7b6..67622e28aca7b 100644 --- a/tests/ui/cross-crate/graceful-error-for-mistyped-assoc-const.stderr +++ b/tests/ui/cross-crate/graceful-error-for-mistyped-assoc-const.stderr @@ -1,6 +1,7 @@ error[E0326]: implemented const `CONST` has an incompatible type for trait --> $DIR/graceful-error-for-mistyped-assoc-const.rs:10:18 | +LL | impl issue_41549::Trait for S { LL | const CONST: () = (); | ^^ expected `u32`, found `()` diff --git a/tests/ui/delegation/target-expr-removal-defs-inside.stderr b/tests/ui/delegation/target-expr-removal-defs-inside.stderr index 6fde7fb8a7bdb..9f52c8c137d2a 100644 --- a/tests/ui/delegation/target-expr-removal-defs-inside.stderr +++ b/tests/ui/delegation/target-expr-removal-defs-inside.stderr @@ -183,6 +183,7 @@ LL | | } note: type in trait --> $DIR/target-expr-removal-defs-inside.rs:4:25 | +LL | pub trait Trait: Sized { LL | fn static_self() -> F { F } | ^ = note: expected signature `fn() -> F` @@ -257,6 +258,7 @@ LL | | } note: type in trait --> $DIR/target-expr-removal-defs-inside.rs:4:25 | +LL | pub trait Trait: Sized { LL | fn static_self() -> F { F } | ^ = note: expected signature `fn() -> F` @@ -335,6 +337,7 @@ LL | | } note: type in trait --> $DIR/target-expr-removal-defs-inside.rs:4:25 | +LL | pub trait Trait: Sized { LL | fn static_self() -> F { F } | ^ = note: expected signature `fn() -> F` diff --git a/tests/ui/delegation/unused-target-expr-in-glob-or-list.stderr b/tests/ui/delegation/unused-target-expr-in-glob-or-list.stderr index 330e536f81840..81b13c17a543a 100644 --- a/tests/ui/delegation/unused-target-expr-in-glob-or-list.stderr +++ b/tests/ui/delegation/unused-target-expr-in-glob-or-list.stderr @@ -164,7 +164,8 @@ error[E0053]: method `static_self` has an incompatible type for trait --> $DIR/unused-target-expr-in-glob-or-list.rs:107:37 | LL | macro_rules! delegation { -... +LL | () => { +LL | impl Trait for S { LL | reuse ::static_self { self.0 } | ^^^^^^^^^^^ expected `F`, found `()` ... @@ -174,6 +175,7 @@ LL | delegation!(); note: type in trait --> $DIR/unused-target-expr-in-glob-or-list.rs:4:25 | +LL | pub trait Trait: Sized { LL | fn static_self() -> F { F } | ^ = note: expected signature `fn() -> F` @@ -192,12 +194,14 @@ LL | () => { LL | reuse ::static_self { self.0 } | ^^^^^^^^^^^ expected `F`, found `()` ... +LL | impl Trait for S1 { LL | delegation2!(); | -------------- in this macro invocation | note: type in trait --> $DIR/unused-target-expr-in-glob-or-list.rs:4:25 | +LL | pub trait Trait: Sized { LL | fn static_self() -> F { F } | ^ = note: expected signature `fn() -> F` diff --git a/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr b/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr index f844bdbc2cb21..3a507e5f218b4 100644 --- a/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr +++ b/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr @@ -59,6 +59,8 @@ LL | impl Fn<()> for Foo { error[E0053]: method `call` has an incompatible type for trait --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:13:32 | +LL | impl Fn<()> for Foo { +... LL | extern "rust-call" fn call(self, args: ()) -> () {} | ^^^^ expected `&Foo`, found `Foo` | @@ -151,6 +153,8 @@ LL | impl FnOnce() for Foo1 { error[E0053]: method `call_mut` has an incompatible type for trait --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:30:36 | +LL | impl FnMut<()> for Bar { +... LL | extern "rust-call" fn call_mut(&self, args: ()) -> () {} | ^^^^^ types differ in mutability | diff --git a/tests/ui/fn/fn-traits-call-once-signature-15094.stderr b/tests/ui/fn/fn-traits-call-once-signature-15094.stderr index bb1d336e84842..1a892168c2c16 100644 --- a/tests/ui/fn/fn-traits-call-once-signature-15094.stderr +++ b/tests/ui/fn/fn-traits-call-once-signature-15094.stderr @@ -1,6 +1,8 @@ error[E0053]: method `call_once` has an incompatible type for trait --> $DIR/fn-traits-call-once-signature-15094.rs:13:5 | +LL | impl ops::FnOnce<(),> for Debuger { +LL | type Output = (); LL | fn call_once(self, _args: ()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected "rust-call" fn, found "Rust" fn | diff --git a/tests/ui/impl-trait/apit/impl-generic-mismatch-ab.stderr b/tests/ui/impl-trait/apit/impl-generic-mismatch-ab.stderr index 9db996cf9ce65..a7f67f04c4905 100644 --- a/tests/ui/impl-trait/apit/impl-generic-mismatch-ab.stderr +++ b/tests/ui/impl-trait/apit/impl-generic-mismatch-ab.stderr @@ -1,6 +1,7 @@ error[E0053]: method `foo` has an incompatible type for trait --> $DIR/impl-generic-mismatch-ab.rs:8:32 | +LL | impl Foo for () { LL | fn foo(&self, a: &impl Debug, b: &B) { } | - ^^^^^^^^^^^ expected type parameter `B`, found type parameter `impl Debug` | | @@ -9,6 +10,7 @@ LL | fn foo(&self, a: &impl Debug, b: &B) { } note: type in trait --> $DIR/impl-generic-mismatch-ab.rs:4:32 | +LL | trait Foo { LL | fn foo(&self, a: &A, b: &impl Debug); | ^^ = note: expected signature `fn(&(), &B, &impl Debug)` diff --git a/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr b/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr index 39121c99798bf..5522fea6eb5e2 100644 --- a/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr +++ b/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr @@ -16,6 +16,7 @@ LL | type Ty: IntoIterator; error[E0053]: method `method` has an incompatible type for trait --> $DIR/in-assoc-type-unconstrained.rs:22:24 | +LL | impl Trait for () { LL | type Ty = impl Sized; | ---------- the expected opaque type LL | @@ -25,6 +26,8 @@ LL | fn method() -> () {} note: type in trait --> $DIR/in-assoc-type-unconstrained.rs:17:24 | +LL | trait Trait { +LL | type Ty; LL | fn method() -> Self::Ty; | ^^^^^^^^ = note: expected signature `fn() -> <() as compare_method::Trait>::Ty` diff --git a/tests/ui/impl-trait/in-trait/deep-match.stderr b/tests/ui/impl-trait/in-trait/deep-match.stderr index 8ec30239ea8d7..1433664158b9f 100644 --- a/tests/ui/impl-trait/in-trait/deep-match.stderr +++ b/tests/ui/impl-trait/in-trait/deep-match.stderr @@ -1,12 +1,16 @@ error[E0053]: method `bar` has an incompatible return type for trait --> $DIR/deep-match.rs:8:17 | +LL | impl Foo for () { LL | fn bar() -> i32 { - | ^^^ - | | - | expected `Wrapper<_>`, found `i32` - | return type in trait + | ^^^ expected `Wrapper<_>`, found `i32` | +note: return type in trait + --> $DIR/deep-match.rs:4:17 + | +LL | trait Foo { +LL | fn bar() -> Wrapper; + | ^^^^^^^^^^^^^^^^^^^ = note: expected struct `Wrapper<_>` found type `i32` diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.lt.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.lt.stderr index 97f5b2af862e0..8c3f4300532fe 100644 --- a/tests/ui/impl-trait/in-trait/method-signature-matches.lt.stderr +++ b/tests/ui/impl-trait/in-trait/method-signature-matches.lt.stderr @@ -1,6 +1,7 @@ error[E0053]: method `early` has an incompatible type for trait --> $DIR/method-signature-matches.rs:55:27 | +LL | impl Lifetimes for () { LL | fn early<'late, T>(_: &'late ()) {} | - ^^^^^^^^^ expected type parameter `T`, found `()` | | @@ -9,6 +10,7 @@ LL | fn early<'late, T>(_: &'late ()) {} note: type in trait --> $DIR/method-signature-matches.rs:50:28 | +LL | trait Lifetimes { LL | fn early<'early, T>(x: &'early T) -> impl Sized; | ^^^^^^^^^ = note: expected signature `fn(&'early T)` diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch.stderr index 588b453761003..dd6c906e64255 100644 --- a/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch.stderr +++ b/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch.stderr @@ -1,12 +1,14 @@ error[E0053]: method `owo` has an incompatible type for trait --> $DIR/method-signature-matches.rs:11:15 | +LL | impl Uwu for () { LL | fn owo(_: u8) {} | ^^ expected `()`, found `u8` | note: type in trait --> $DIR/method-signature-matches.rs:6:15 | +LL | trait Uwu { LL | fn owo(x: ()) -> impl Sized; | ^^ = note: expected signature `fn(())` diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch_async.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch_async.stderr index b0530045bea9a..6a834ceed727e 100644 --- a/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch_async.stderr +++ b/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch_async.stderr @@ -1,12 +1,14 @@ error[E0053]: method `owo` has an incompatible type for trait --> $DIR/method-signature-matches.rs:22:21 | +LL | impl AsyncUwu for () { LL | async fn owo(_: u8) {} | ^^ expected `()`, found `u8` | note: type in trait --> $DIR/method-signature-matches.rs:17:21 | +LL | trait AsyncUwu { LL | async fn owo(x: ()) {} | ^^ = note: expected signature `fn(()) -> _` diff --git a/tests/ui/impl-trait/in-trait/specialization-broken.stderr b/tests/ui/impl-trait/in-trait/specialization-broken.stderr index fbbe1ac40b9ef..ab739dae23d7f 100644 --- a/tests/ui/impl-trait/in-trait/specialization-broken.stderr +++ b/tests/ui/impl-trait/in-trait/specialization-broken.stderr @@ -10,6 +10,7 @@ LL | fn bar(&self) -> U { note: type in trait --> $DIR/specialization-broken.rs:8:22 | +LL | trait Foo { LL | fn bar(&self) -> impl Sized; | ^^^^^^^^^^ = note: expected signature `fn(&_) -> impl Sized` diff --git a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr index f921e5a452244..2c99ae95da74f 100644 --- a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr +++ b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr @@ -4,6 +4,8 @@ error[E0053]: method `eq` has an incompatible type for trait LL | type Foo = impl PartialEq<(Foo, i32)>; | -------------------------- the found opaque type ... +LL | impl PartialEq<(Bar, i32)> for Bar { +LL | #[define_opaque(Foo)] LL | fn eq(&self, _other: &(Foo, i32)) -> bool { | ^^^^^^^^^^^ expected `a::Bar`, found opaque type | @@ -21,6 +23,7 @@ error[E0053]: method `eq` has an incompatible type for trait LL | type Foo = impl PartialEq<(Foo, i32)>; | -------------------------- the expected opaque type ... +LL | impl PartialEq<(Foo, i32)> for Bar { LL | fn eq(&self, _other: &(Bar, i32)) -> bool { | ^^^^^^^^^^^ expected opaque type, found `b::Bar` | diff --git a/tests/ui/impl-trait/trait_type.stderr b/tests/ui/impl-trait/trait_type.stderr index 18d914a96a291..ff07297eacff1 100644 --- a/tests/ui/impl-trait/trait_type.stderr +++ b/tests/ui/impl-trait/trait_type.stderr @@ -1,6 +1,7 @@ error[E0053]: method `fmt` has an incompatible type for trait --> $DIR/trait_type.rs:7:21 | +LL | impl std::fmt::Display for MyType { LL | fn fmt(&self, x: &str) -> () { } | ^^^^ types differ in mutability | diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr index a0cdc8ee89382..86573088ed971 100644 --- a/tests/ui/impl-trait/where-allowed.stderr +++ b/tests/ui/impl-trait/where-allowed.stderr @@ -348,6 +348,7 @@ LL | let _in_return_in_local_variable = || -> impl Fn() { || {} }; error[E0053]: method `in_trait_impl_return` has an incompatible type for trait --> $DIR/where-allowed.rs:129:34 | +LL | impl DummyTrait for () { LL | type Out = impl Debug; | ---------- the expected opaque type ... @@ -357,6 +358,8 @@ LL | fn in_trait_impl_return() -> impl Debug { () } note: type in trait --> $DIR/where-allowed.rs:119:34 | +LL | trait DummyTrait { +... LL | fn in_trait_impl_return() -> Self::Out; | ^^^^^^^^^ = note: expected signature `fn() -> <() as DummyTrait>::Out` diff --git a/tests/ui/mir/inline-wrong-abi.stderr b/tests/ui/mir/inline-wrong-abi.stderr index e44899eb92a5c..cade8c22165f7 100644 --- a/tests/ui/mir/inline-wrong-abi.stderr +++ b/tests/ui/mir/inline-wrong-abi.stderr @@ -1,6 +1,7 @@ error[E0053]: method `call` has an incompatible type for trait --> $DIR/inline-wrong-abi.rs:7:5 | +LL | impl Fn<()> for Foo { LL | extern "C" fn call(&self, _: ()) -> T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected "rust-call" fn, found "C" fn | diff --git a/tests/ui/mismatched_types/E0053.stderr b/tests/ui/mismatched_types/E0053.stderr index 32452af5ceda7..6cc5e0b128ee5 100644 --- a/tests/ui/mismatched_types/E0053.stderr +++ b/tests/ui/mismatched_types/E0053.stderr @@ -1,12 +1,14 @@ error[E0053]: method `foo` has an incompatible type for trait --> $DIR/E0053.rs:9:15 | +LL | impl Foo for Bar { LL | fn foo(x: i16) { } | ^^^ expected `u16`, found `i16` | note: type in trait --> $DIR/E0053.rs:2:15 | +LL | trait Foo { LL | fn foo(x: u16); | ^^^ = note: expected signature `fn(u16)` @@ -20,12 +22,16 @@ LL + fn foo(x: u16) { } error[E0053]: method `bar` has an incompatible type for trait --> $DIR/E0053.rs:11:12 | +LL | impl Foo for Bar { +... LL | fn bar(&mut self) { } | ^^^^^^^^^ types differ in mutability | note: type in trait --> $DIR/E0053.rs:3:12 | +LL | trait Foo { +LL | fn foo(x: u16); LL | fn bar(&self); | ^^^^^ = note: expected signature `fn(&Bar)` diff --git a/tests/ui/mismatched_types/issue-112036.stderr b/tests/ui/mismatched_types/issue-112036.stderr index fed6b11a7b292..3a4624d206c48 100644 --- a/tests/ui/mismatched_types/issue-112036.stderr +++ b/tests/ui/mismatched_types/issue-112036.stderr @@ -1,6 +1,7 @@ error[E0053]: method `drop` has an incompatible type for trait --> $DIR/issue-112036.rs:4:13 | +LL | impl Drop for Foo { LL | fn drop(self) {} | ^^^^ expected `&mut Foo`, found `Foo` | diff --git a/tests/ui/mismatched_types/issue-13033.stderr b/tests/ui/mismatched_types/issue-13033.stderr index f21d49eac7284..df83d10e29d9c 100644 --- a/tests/ui/mismatched_types/issue-13033.stderr +++ b/tests/ui/mismatched_types/issue-13033.stderr @@ -1,12 +1,14 @@ error[E0053]: method `bar` has an incompatible type for trait --> $DIR/issue-13033.rs:10:30 | +LL | impl Foo for Baz { LL | fn bar(&mut self, other: &dyn Foo) {} | ^^^^^^^^ types differ in mutability | note: type in trait --> $DIR/issue-13033.rs:4:30 | +LL | trait Foo { LL | fn bar(&mut self, other: &mut dyn Foo); | ^^^^^^^^^^^^ = note: expected signature `fn(&mut Baz, &mut dyn Foo)` diff --git a/tests/ui/mismatched_types/trait-impl-fn-incompatibility.stderr b/tests/ui/mismatched_types/trait-impl-fn-incompatibility.stderr index 4aabf2372e478..02df411583fce 100644 --- a/tests/ui/mismatched_types/trait-impl-fn-incompatibility.stderr +++ b/tests/ui/mismatched_types/trait-impl-fn-incompatibility.stderr @@ -1,12 +1,14 @@ error[E0053]: method `foo` has an incompatible type for trait --> $DIR/trait-impl-fn-incompatibility.rs:9:15 | +LL | impl Foo for Bar { LL | fn foo(x: i16) { } | ^^^ expected `u16`, found `i16` | note: type in trait --> $DIR/trait-impl-fn-incompatibility.rs:2:15 | +LL | trait Foo { LL | fn foo(x: u16); | ^^^ = note: expected signature `fn(u16)` @@ -20,12 +22,16 @@ LL + fn foo(x: u16) { } error[E0053]: method `bar` has an incompatible type for trait --> $DIR/trait-impl-fn-incompatibility.rs:10:28 | +LL | impl Foo for Bar { +LL | fn foo(x: i16) { } LL | fn bar(&mut self, bar: &Bar) { } | ^^^^ types differ in mutability | note: type in trait --> $DIR/trait-impl-fn-incompatibility.rs:3:28 | +LL | trait Foo { +LL | fn foo(x: u16); LL | fn bar(&mut self, bar: &mut Bar); | ^^^^^^^^ = note: expected signature `fn(&mut Bar, &mut Bar)` diff --git a/tests/ui/mut/mismatch-trait-mut.e2015.stderr b/tests/ui/mut/mismatch-trait-mut.e2015.stderr index bc9d60e66bc33..0130f2d9833eb 100644 --- a/tests/ui/mut/mismatch-trait-mut.e2015.stderr +++ b/tests/ui/mut/mismatch-trait-mut.e2015.stderr @@ -1,12 +1,14 @@ error[E0053]: method `f` has an incompatible type for trait --> $DIR/mismatch-trait-mut.rs:30:18 | +LL | impl crate::A for X { LL | fn f(_x: &crate::bar::X) {} | ^^^^^^^^^^^^^^ types differ in mutability | note: type in trait --> $DIR/mismatch-trait-mut.rs:15:14 | +LL | pub trait A { LL | fn f(_x: &mut bar::X) {} | ^^^^^^^^^^^ = note: expected signature `fn(&mut X)` @@ -19,12 +21,16 @@ LL | fn f(_x: &mut crate::bar::X) {} error[E0053]: method `g` has an incompatible type for trait --> $DIR/mismatch-trait-mut.rs:34:22 | +LL | impl crate::A for X { +... LL | fn g<'a>(_x: &'a crate::bar::X) -> &'a () { &() } | ^^^^^^^^^^^^^^^^^ types differ in mutability | note: type in trait --> $DIR/mismatch-trait-mut.rs:17:18 | +LL | pub trait A { +... LL | fn g<'a>(_x: &'a mut bar::X) -> &'a () { &() } | ^^^^^^^^^^^^^^ = note: expected signature `fn(&'a mut X) -> &'a ()` @@ -37,12 +43,16 @@ LL | fn g<'a>(_x: &'a mut crate::bar::X) -> &'a () { &() } error[E0053]: method `f2` has an incompatible type for trait --> $DIR/mismatch-trait-mut.rs:38:19 | +LL | impl crate::A for X { +... LL | fn f2(_x: &mut crate::bar::X) {} | ^^^^^^^^^^^^^^^^^^ types differ in mutability | note: type in trait --> $DIR/mismatch-trait-mut.rs:19:15 | +LL | pub trait A { +... LL | fn f2(_x: &bar::X) {} | ^^^^^^^ = note: expected signature `fn(&X)` @@ -56,12 +66,16 @@ LL + fn f2(_x: &crate::bar::X) {} error[E0053]: method `g2` has an incompatible type for trait --> $DIR/mismatch-trait-mut.rs:42:23 | +LL | impl crate::A for X { +... LL | fn g2<'a>(_x: &'a mut crate::bar::X) -> &'a () { &() } | ^^^^^^^^^^^^^^^^^^^^^ types differ in mutability | note: type in trait --> $DIR/mismatch-trait-mut.rs:21:19 | +LL | pub trait A { +... LL | fn g2<'a>(_x: &'a bar::X) -> &'a () { &() } | ^^^^^^^^^^ = note: expected signature `fn(&'a X) -> &'a ()` diff --git a/tests/ui/mut/mismatch-trait-mut.e2018.stderr b/tests/ui/mut/mismatch-trait-mut.e2018.stderr index bc9d60e66bc33..0130f2d9833eb 100644 --- a/tests/ui/mut/mismatch-trait-mut.e2018.stderr +++ b/tests/ui/mut/mismatch-trait-mut.e2018.stderr @@ -1,12 +1,14 @@ error[E0053]: method `f` has an incompatible type for trait --> $DIR/mismatch-trait-mut.rs:30:18 | +LL | impl crate::A for X { LL | fn f(_x: &crate::bar::X) {} | ^^^^^^^^^^^^^^ types differ in mutability | note: type in trait --> $DIR/mismatch-trait-mut.rs:15:14 | +LL | pub trait A { LL | fn f(_x: &mut bar::X) {} | ^^^^^^^^^^^ = note: expected signature `fn(&mut X)` @@ -19,12 +21,16 @@ LL | fn f(_x: &mut crate::bar::X) {} error[E0053]: method `g` has an incompatible type for trait --> $DIR/mismatch-trait-mut.rs:34:22 | +LL | impl crate::A for X { +... LL | fn g<'a>(_x: &'a crate::bar::X) -> &'a () { &() } | ^^^^^^^^^^^^^^^^^ types differ in mutability | note: type in trait --> $DIR/mismatch-trait-mut.rs:17:18 | +LL | pub trait A { +... LL | fn g<'a>(_x: &'a mut bar::X) -> &'a () { &() } | ^^^^^^^^^^^^^^ = note: expected signature `fn(&'a mut X) -> &'a ()` @@ -37,12 +43,16 @@ LL | fn g<'a>(_x: &'a mut crate::bar::X) -> &'a () { &() } error[E0053]: method `f2` has an incompatible type for trait --> $DIR/mismatch-trait-mut.rs:38:19 | +LL | impl crate::A for X { +... LL | fn f2(_x: &mut crate::bar::X) {} | ^^^^^^^^^^^^^^^^^^ types differ in mutability | note: type in trait --> $DIR/mismatch-trait-mut.rs:19:15 | +LL | pub trait A { +... LL | fn f2(_x: &bar::X) {} | ^^^^^^^ = note: expected signature `fn(&X)` @@ -56,12 +66,16 @@ LL + fn f2(_x: &crate::bar::X) {} error[E0053]: method `g2` has an incompatible type for trait --> $DIR/mismatch-trait-mut.rs:42:23 | +LL | impl crate::A for X { +... LL | fn g2<'a>(_x: &'a mut crate::bar::X) -> &'a () { &() } | ^^^^^^^^^^^^^^^^^^^^^ types differ in mutability | note: type in trait --> $DIR/mismatch-trait-mut.rs:21:19 | +LL | pub trait A { +... LL | fn g2<'a>(_x: &'a bar::X) -> &'a () { &() } | ^^^^^^^^^^ = note: expected signature `fn(&'a X) -> &'a ()` diff --git a/tests/ui/pin-ergonomics/pinned-drop-check.stderr b/tests/ui/pin-ergonomics/pinned-drop-check.stderr index 6087d45dd2900..892413655a229 100644 --- a/tests/ui/pin-ergonomics/pinned-drop-check.stderr +++ b/tests/ui/pin-ergonomics/pinned-drop-check.stderr @@ -113,6 +113,7 @@ LL - #[pin_v2] error[E0053]: method `drop` has an incompatible type for trait --> $DIR/pinned-drop-check.rs:83:17 | +LL | impl Drop for Foo { LL | fn drop(&pin const self) {} | ^^^^^^^^^^^^^^^ expected `&mut drop_pin_const_wrong_type::Foo`, found `Pin<&drop_pin_const_wrong_type::Foo>` | @@ -127,6 +128,7 @@ LL + fn drop(&mut self) {} error[E0053]: method `drop` has an incompatible type for trait --> $DIR/pinned-drop-check.rs:87:17 | +LL | impl Drop for Bar { LL | fn drop(&pin const self) {} | ^^^^^^^^^^^^^^^ expected `&mut drop_pin_const_wrong_type::Bar`, found `Pin<&drop_pin_const_wrong_type::Bar>` | @@ -163,6 +165,7 @@ LL - #[pin_v2] error[E0053]: method `drop` has an incompatible type for trait --> $DIR/pinned-drop-check.rs:99:21 | +LL | impl Drop for Foo { LL | fn drop<'a>(&'a pin mut self) {} | ^^^^^^^^^^^^^^^^ expected `&mut drop_with_lifetime_wrong_type::Foo`, found `Pin<&mut Foo>` | @@ -177,6 +180,7 @@ LL + fn drop<'a>(&mut self) {} error[E0053]: method `drop` has an incompatible type for trait --> $DIR/pinned-drop-check.rs:104:21 | +LL | impl Drop for Bar { LL | fn drop<'a>(&'a pin mut self) {} | ^^^^^^^^^^^^^^^^ expected `&mut drop_with_lifetime_wrong_type::Bar`, found `Pin<&mut Bar>` | @@ -213,6 +217,7 @@ LL - #[pin_v2] error[E0053]: method `drop` has an incompatible type for trait --> $DIR/pinned-drop-check.rs:118:23 | +LL | impl Drop for Foo { LL | fn drop(self: Pin<&mut Self>) {} | ^^^^^^^^^^^^^^ expected `&mut drop_explicit_pin_wrong_type::Foo`, found `Pin<&mut Foo>` | @@ -227,6 +232,7 @@ LL + fn drop(&mut self) {} error[E0053]: method `drop` has an incompatible type for trait --> $DIR/pinned-drop-check.rs:123:23 | +LL | impl Drop for Bar { LL | fn drop(self: Pin<&mut Self>) {} | ^^^^^^^^^^^^^^ expected `&mut drop_explicit_pin_wrong_type::Bar`, found `Pin<&mut Bar>` | @@ -241,6 +247,7 @@ LL + fn drop(&mut self) {} error[E0053]: method `pin_drop` has an incompatible type for trait --> $DIR/pinned-drop-check.rs:135:21 | +LL | impl Drop for Foo { LL | fn pin_drop(&mut self) {} | ^^^^^^^^^ expected `Pin<&mut pin_drop_wrong_type::Foo>`, found `&mut pin_drop_wrong_type::Foo` | @@ -255,6 +262,7 @@ LL + fn pin_drop(self: Pin<&mut pin_drop_wrong_type::Foo>) {} error[E0053]: method `pin_drop` has an incompatible type for trait --> $DIR/pinned-drop-check.rs:139:21 | +LL | impl Drop for Bar { LL | fn pin_drop(&mut self) {} | ^^^^^^^^^ expected `Pin<&mut pin_drop_wrong_type::Bar>`, found `&mut pin_drop_wrong_type::Bar` | diff --git a/tests/ui/splat/splat-invalid-trait-impl.stderr b/tests/ui/splat/splat-invalid-trait-impl.stderr index df414a5e63062..3aafd5e0d5575 100644 --- a/tests/ui/splat/splat-invalid-trait-impl.stderr +++ b/tests/ui/splat/splat-invalid-trait-impl.stderr @@ -1,12 +1,14 @@ error[E0053]: method `method` has an incompatible type for trait --> $DIR/splat-invalid-trait-impl.rs:14:33 | +LL | impl FooTrait for Foo { LL | fn method(#[rustc_splat] _: (u32, f32)) {} | ^^^^^^^^^^ expected `i8`, found `f32` | note: type in trait --> $DIR/splat-invalid-trait-impl.rs:6:33 | +LL | trait FooTrait { LL | fn method(#[rustc_splat] _: (u32, i8)); | ^^^^^^^^^ = note: expected signature `fn(#[rustc_splat] (_, i8))` @@ -20,12 +22,14 @@ LL + fn method(#[rustc_splat] _: (u32, i8)) {} error[E0053]: method `method` has an incompatible type for trait --> $DIR/splat-invalid-trait-impl.rs:19:33 | +LL | impl FooTrait for Foo1 { LL | fn method(#[rustc_splat] _: (f32, i8)) {} | ^^^^^^^^^ expected `u32`, found `f32` | note: type in trait --> $DIR/splat-invalid-trait-impl.rs:6:33 | +LL | trait FooTrait { LL | fn method(#[rustc_splat] _: (u32, i8)); | ^^^^^^^^^ = note: expected signature `fn(#[rustc_splat] (u32, _))` @@ -39,12 +43,14 @@ LL + fn method(#[rustc_splat] _: (u32, i8)) {} error[E0053]: method `method` has an incompatible type for trait --> $DIR/splat-invalid-trait-impl.rs:24:33 | +LL | impl FooTrait for Foo2 { LL | fn method(#[rustc_splat] _: (f32, f64)) {} | ^^^^^^^^^^ expected `u32`, found `f32` | note: type in trait --> $DIR/splat-invalid-trait-impl.rs:6:33 | +LL | trait FooTrait { LL | fn method(#[rustc_splat] _: (u32, i8)); | ^^^^^^^^^ = note: expected signature `fn(#[rustc_splat] (u32, i8))` diff --git a/tests/ui/splat/splat-invalid.stderr b/tests/ui/splat/splat-invalid.stderr index 8681084a3c594..5ef430046ab10 100644 --- a/tests/ui/splat/splat-invalid.stderr +++ b/tests/ui/splat/splat-invalid.stderr @@ -182,12 +182,14 @@ LL | #[rustc_splat] error[E0053]: method `has_splat` has an incompatible type for trait --> $DIR/splat-invalid.rs:59:5 | +LL | impl FooTrait for Foo { LL | fn has_splat(_: ()) {} | ^^^^^^^^^^^^^^^^^^^ expected fn with arg 0 splatted, found fn with no splatted arg | note: type in trait --> $DIR/splat-invalid.rs:51:5 | +LL | trait FooTrait { LL | fn has_splat(#[rustc_splat] _: ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected signature `fn(#[rustc_splat] ())` @@ -196,12 +198,16 @@ LL | fn has_splat(#[rustc_splat] _: ()); error[E0053]: method `no_splat` has an incompatible type for trait --> $DIR/splat-invalid.rs:61:5 | +LL | impl FooTrait for Foo { +... LL | fn no_splat(#[rustc_splat] _: (u32, f64)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn with no splatted arg, found fn with arg 0 splatted | note: type in trait --> $DIR/splat-invalid.rs:53:5 | +LL | trait FooTrait { +... LL | fn no_splat(_: (u32, f64)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected signature `fn((_, _))` diff --git a/tests/ui/splat/splat-non-tuple.stderr b/tests/ui/splat/splat-non-tuple.stderr index b92c257b9b021..21129c92ce6ee 100644 --- a/tests/ui/splat/splat-non-tuple.stderr +++ b/tests/ui/splat/splat-non-tuple.stderr @@ -1,12 +1,14 @@ error[E0053]: method `tuple_1` has an incompatible type for trait --> $DIR/splat-non-tuple.rs:39:5 | +LL | impl FooTrait for Foo { LL | fn tuple_1(_: (u32,)) {} | ^^^^^^^^^^^^^^^^^^^^^ expected fn with arg 0 splatted, found fn with no splatted arg | note: type in trait --> $DIR/splat-non-tuple.rs:17:5 | +LL | trait FooTrait { LL | fn tuple_1(#[rustc_splat] _: (u32,)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected signature `fn(#[rustc_splat] (_,))` diff --git a/tests/ui/target-feature/invalid-attribute.stderr b/tests/ui/target-feature/invalid-attribute.stderr index b6710e5ab28a6..4f8966aa2e6b7 100644 --- a/tests/ui/target-feature/invalid-attribute.stderr +++ b/tests/ui/target-feature/invalid-attribute.stderr @@ -189,12 +189,15 @@ LL | fn foo() {} error[E0053]: method `foo` has an incompatible type for trait --> $DIR/invalid-attribute.rs:92:5 | +LL | impl Quux for Foo { +... LL | fn foo() {} | ^^^^^^^^ expected safe fn, found unsafe fn | note: type in trait --> $DIR/invalid-attribute.rs:84:5 | +LL | trait Quux { LL | fn foo(); | ^^^^^^^^^ = note: expected signature `fn()` diff --git a/tests/ui/traits/const-traits/eval-bad-signature.stderr b/tests/ui/traits/const-traits/eval-bad-signature.stderr index db5f434ee0e98..1230515c79f5c 100644 --- a/tests/ui/traits/const-traits/eval-bad-signature.stderr +++ b/tests/ui/traits/const-traits/eval-bad-signature.stderr @@ -1,12 +1,14 @@ error[E0053]: method `value` has an incompatible type for trait --> $DIR/eval-bad-signature.rs:16:19 | +LL | const impl Value for FortyTwo { LL | fn value() -> i64 { | ^^^ expected `u32`, found `i64` | note: type in trait --> $DIR/eval-bad-signature.rs:6:19 | +LL | const trait Value { LL | fn value() -> u32; | ^^^ = note: expected signature `fn() -> u32` diff --git a/tests/ui/traits/error-reporting/incompatible-method-multiline.stderr b/tests/ui/traits/error-reporting/incompatible-method-multiline.stderr index 4f797dedfa846..ee9a29aa84fd6 100644 --- a/tests/ui/traits/error-reporting/incompatible-method-multiline.stderr +++ b/tests/ui/traits/error-reporting/incompatible-method-multiline.stderr @@ -1,6 +1,8 @@ error[E0053]: method `next` has an incompatible type for trait --> $DIR/incompatible-method-multiline.rs:8:27 | +LL | impl Iterator for S { +LL | type Item = i32; LL | fn next(&mut self) -> Result { Ok(7) } | ^^^^^^^^^^^^^^^^ expected `Option`, found `Result` | diff --git a/tests/ui/traits/impl-method-mismatch.stderr b/tests/ui/traits/impl-method-mismatch.stderr index ca8b35e06c78f..9675edd3d84cb 100644 --- a/tests/ui/traits/impl-method-mismatch.stderr +++ b/tests/ui/traits/impl-method-mismatch.stderr @@ -1,12 +1,15 @@ error[E0053]: method `jumbo` has an incompatible type for trait --> $DIR/impl-method-mismatch.rs:9:5 | +LL | impl Mumbo for usize { +LL | // Cannot have a larger effect than the trait: LL | unsafe fn jumbo(&self, x: &usize) { *self + *x; } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected safe fn, found unsafe fn | note: type in trait --> $DIR/impl-method-mismatch.rs:4:5 | +LL | trait Mumbo { LL | fn jumbo(&self, x: &usize) -> usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected signature `fn(&_, &_) -> usize` diff --git a/tests/ui/traits/issue-35869.stderr b/tests/ui/traits/issue-35869.stderr index 98cbd4650007b..17adad92611cc 100644 --- a/tests/ui/traits/issue-35869.stderr +++ b/tests/ui/traits/issue-35869.stderr @@ -1,12 +1,14 @@ error[E0053]: method `foo` has an incompatible type for trait --> $DIR/issue-35869.rs:11:15 | +LL | impl Foo for Bar { LL | fn foo(_: fn(u16) -> ()) {} | ^^^^^^^^^^^^^ expected `u8`, found `u16` | note: type in trait --> $DIR/issue-35869.rs:2:15 | +LL | trait Foo { LL | fn foo(_: fn(u8) -> ()); | ^^^^^^^^^^^^ = note: expected signature `fn(fn(u8))` @@ -20,12 +22,16 @@ LL + fn foo(_: fn(u8)) {} error[E0053]: method `bar` has an incompatible type for trait --> $DIR/issue-35869.rs:13:15 | +LL | impl Foo for Bar { +... LL | fn bar(_: Option) {} | ^^^^^^^^^^^ expected `u8`, found `u16` | note: type in trait --> $DIR/issue-35869.rs:3:15 | +LL | trait Foo { +LL | fn foo(_: fn(u8) -> ()); LL | fn bar(_: Option); | ^^^^^^^^^^ = note: expected signature `fn(Option)` @@ -39,12 +45,16 @@ LL + fn bar(_: std::option::Option) {} error[E0053]: method `baz` has an incompatible type for trait --> $DIR/issue-35869.rs:15:15 | +LL | impl Foo for Bar { +... LL | fn baz(_: (u16, u16)) {} | ^^^^^^^^^^ expected `u8`, found `u16` | note: type in trait --> $DIR/issue-35869.rs:4:15 | +LL | trait Foo { +... LL | fn baz(_: (u8, u16)); | ^^^^^^^^^ = note: expected signature `fn((u8, _))` @@ -58,12 +68,16 @@ LL + fn baz(_: (u8, u16)) {} error[E0053]: method `qux` has an incompatible type for trait --> $DIR/issue-35869.rs:17:17 | +LL | impl Foo for Bar { +... LL | fn qux() -> u16 { 5u16 } | ^^^ expected `u8`, found `u16` | note: type in trait --> $DIR/issue-35869.rs:5:17 | +LL | trait Foo { +... LL | fn qux() -> u8; | ^^ = note: expected signature `fn() -> u8` diff --git a/tests/ui/traits/wrong-mul-method-signature.stderr b/tests/ui/traits/wrong-mul-method-signature.stderr index d119274352f81..6d520e5b958e5 100644 --- a/tests/ui/traits/wrong-mul-method-signature.stderr +++ b/tests/ui/traits/wrong-mul-method-signature.stderr @@ -1,6 +1,8 @@ error[E0053]: method `mul` has an incompatible type for trait --> $DIR/wrong-mul-method-signature.rs:16:21 | +LL | impl Mul for Vec1 { +... LL | fn mul(self, s: &f64) -> Vec1 { | ^^^^ expected `f64`, found `&f64` | @@ -17,6 +19,8 @@ LL + fn mul(self, s: f64) -> Vec1 { error[E0053]: method `mul` has an incompatible type for trait --> $DIR/wrong-mul-method-signature.rs:33:21 | +LL | impl Mul for Vec2 { +... LL | fn mul(self, s: f64) -> Vec2 { | ^^^ expected `Vec2`, found `f64` | @@ -33,6 +37,8 @@ LL + fn mul(self, s: crate::Vec2) -> Vec2 { error[E0053]: method `mul` has an incompatible type for trait --> $DIR/wrong-mul-method-signature.rs:52:29 | +LL | impl Mul for Vec3 { +... LL | fn mul(self, s: f64) -> f64 { | ^^^ expected `i32`, found `f64` | diff --git a/tests/ui/type-alias-impl-trait/unnameable_type.stderr b/tests/ui/type-alias-impl-trait/unnameable_type.stderr index 48fe7ba275fce..ca55fc350fb3d 100644 --- a/tests/ui/type-alias-impl-trait/unnameable_type.stderr +++ b/tests/ui/type-alias-impl-trait/unnameable_type.stderr @@ -3,13 +3,15 @@ error[E0053]: method `dont_define_this` has an incompatible type for trait | LL | type MyPrivate = impl Sized; | ---------- the found opaque type -... +LL | impl Trait for u32 { +LL | #[define_opaque(MyPrivate)] LL | fn dont_define_this(private: MyPrivate) { | ^^^^^^^^^ expected `Private`, found opaque type | note: type in trait --> $DIR/unnameable_type.rs:10:39 | +LL | pub trait Trait { LL | fn dont_define_this(_private: Private) {} | ^^^^^^^ = note: expected signature `fn(Private)` diff --git a/tests/ui/typeck/mismatched-map-under-self.stderr b/tests/ui/typeck/mismatched-map-under-self.stderr index 541de25749e38..8e5bae258f976 100644 --- a/tests/ui/typeck/mismatched-map-under-self.stderr +++ b/tests/ui/typeck/mismatched-map-under-self.stderr @@ -1,12 +1,16 @@ error[E0053]: method `values` has an incompatible type for trait --> $DIR/mismatched-map-under-self.rs:10:15 | +LL | impl Insertable for Option { +... LL | fn values(self) -> Self::Values { | ^^^^ expected `&Option`, found `Option` | note: type in trait --> $DIR/mismatched-map-under-self.rs:4:15 | +LL | pub trait Insertable { +... LL | fn values(&self) -> Self::Values; | ^^^^^ = note: expected signature `fn(&Option<_>)` diff --git a/tests/ui/ufcs/ufcs-explicit-self-bad.stderr b/tests/ui/ufcs/ufcs-explicit-self-bad.stderr index 7b5f7cd9f7033..e0d6d88fca075 100644 --- a/tests/ui/ufcs/ufcs-explicit-self-bad.stderr +++ b/tests/ui/ufcs/ufcs-explicit-self-bad.stderr @@ -1,12 +1,16 @@ error[E0053]: method `dummy2` has an incompatible type for trait --> $DIR/ufcs-explicit-self-bad.rs:37:21 | +LL | impl<'a, T> SomeTrait for &'a Bar { +LL | fn dummy1(self: &&'a Bar) { } LL | fn dummy2(self: &Bar) {} | ^^^^^^^ expected `&'a Bar`, found `Bar` | note: type in trait --> $DIR/ufcs-explicit-self-bad.rs:31:15 | +LL | trait SomeTrait { +LL | fn dummy1(&self); LL | fn dummy2(&self); | ^^^^^ = note: expected signature `fn(&&'a Bar<_>)` diff --git a/tests/ui/unsafe/unsafe-trait-impl.stderr b/tests/ui/unsafe/unsafe-trait-impl.stderr index 8febbb736634d..250d1f1dcbcf7 100644 --- a/tests/ui/unsafe/unsafe-trait-impl.stderr +++ b/tests/ui/unsafe/unsafe-trait-impl.stderr @@ -1,12 +1,14 @@ error[E0053]: method `len` has an incompatible type for trait --> $DIR/unsafe-trait-impl.rs:10:5 | +LL | impl Foo for u32 { LL | fn len(&self) -> u32 { *self } | ^^^^^^^^^^^^^^^^^^^^ expected unsafe fn, found safe fn | note: type in trait --> $DIR/unsafe-trait-impl.rs:6:5 | +LL | trait Foo { LL | unsafe fn len(&self) -> u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected signature `unsafe fn(&_) -> _` From 7518566f4ddfc60f48c4a48865b59a100a548e82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 5 Oct 2026 21:58:01 +0000 Subject: [PATCH 07/34] Streamline output by moving span label of type parameter default to "type in trait" note ``` error[E0053]: method `foo` has an incompatible type for trait --> $DIR/default-type-parameter.rs:8:17 | LL | impl Trait for S { LL | fn foo() -> u32 { 0 } | ^^^ expected `()`, found `u32` | note: type in trait --> $DIR/default-type-parameter.rs:2:17 | LL | trait Trait { | ------ expected to match the default of type parameter `T` LL | fn foo() -> T; | ^ = note: expected signature `fn() -> ()` found signature `fn() -> u32` help: change the output type to match the trait | LL - fn foo() -> u32 { 0 } LL + fn foo() -> () { 0 } | ``` --- .../src/check/compare_impl_item.rs | 48 +++++++++++-------- .../default-type-parameter.stderr | 12 +---- .../traits/wrong-mul-method-signature.stderr | 4 -- 3 files changed, 30 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 6c371a9cd1788..4a3f71cd311da 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1084,24 +1084,9 @@ fn report_trait_method_mismatch<'tcx>( } cause.span = impl_err_span; - infcx.err_ctxt().note_type_err( - &mut diag, - &cause, - trait_err_span.map(|sp| { - let mut span: MultiSpan = sp.into(); - span.push_span_context(tcx.def_span(trait_m.container_id(tcx)).shrink_to_lo()); - span.push_span_context(tcx.def_span(trait_m.def_id).shrink_to_lo()); - (span, Cow::from("type in trait"), false) - }), - Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound { - expected: ty::Binder::dummy(trait_sig), - found: ty::Binder::dummy(impl_sig), - }))), - terr, - false, - None, - ); + let mut labels = vec![]; + let mut context = vec![]; if let TypeError::ArgumentSorts(_, i) = &terr && let Some(ty) = tcx.fn_sig(trait_m.def_id).skip_binder().inputs_and_output().skip_binder().get(*i) @@ -1112,8 +1097,7 @@ fn report_trait_method_mismatch<'tcx>( && let param = generics.type_param(*param, tcx) && let GenericParamDefKind::Type { has_default: true, .. } = param.kind { - let mut span: MultiSpan = tcx.def_span(param.def_id).into(); - span.push_span_context(tcx.def_span(trait_m.container_id(tcx)).shrink_to_lo()); + context.push(tcx.def_span(trait_m.container_id(tcx)).shrink_to_lo()); let param_name = param.name; let msg = if let Some(ty) = trait_sig.inputs_and_output.get(*i) @@ -1129,9 +1113,33 @@ fn report_trait_method_mismatch<'tcx>( } else { format!("expected to match type parameter `{param_name}`") }; - diag.span_note(span, msg); + labels.push((tcx.def_span(param.def_id), msg)); } + infcx.err_ctxt().note_type_err( + &mut diag, + &cause, + trait_err_span.map(|sp| { + let mut span: MultiSpan = sp.into(); + span.push_span_context(tcx.def_span(trait_m.container_id(tcx)).shrink_to_lo()); + span.push_span_context(tcx.def_span(trait_m.def_id).shrink_to_lo()); + for (sp, label) in labels { + span.push_span_label(sp, label); + } + for sp in context { + span.push_span_context(sp); + } + (span, Cow::from("type in trait"), false) + }), + Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound { + expected: ty::Binder::dummy(trait_sig), + found: ty::Binder::dummy(impl_sig), + }))), + terr, + false, + None, + ); + diag.emit_err() } diff --git a/tests/ui/compare-method/default-type-parameter.stderr b/tests/ui/compare-method/default-type-parameter.stderr index 6b66aaa804ed0..83517ab76729e 100644 --- a/tests/ui/compare-method/default-type-parameter.stderr +++ b/tests/ui/compare-method/default-type-parameter.stderr @@ -9,15 +9,11 @@ note: type in trait --> $DIR/default-type-parameter.rs:2:17 | LL | trait Trait { + | ------ expected to match the default of type parameter `T` LL | fn foo() -> T; | ^ = note: expected signature `fn() -> ()` found signature `fn() -> u32` -note: expected to match the default of type parameter `T` - --> $DIR/default-type-parameter.rs:1:13 - | -LL | trait Trait { - | ^^^^^^ help: change the output type to match the trait | LL - fn foo() -> u32 { 0 } @@ -35,15 +31,11 @@ note: type in trait --> $DIR/default-type-parameter.rs:2:17 | LL | trait Trait { + | ------ expected to match type parameter `T` LL | fn foo() -> T; | ^ = note: expected signature `fn() -> i32` found signature `fn() -> u32` -note: expected to match type parameter `T` - --> $DIR/default-type-parameter.rs:1:13 - | -LL | trait Trait { - | ^^^^^^ help: change the output type to match the trait | LL - fn foo() -> u32 { 0 } diff --git a/tests/ui/traits/wrong-mul-method-signature.stderr b/tests/ui/traits/wrong-mul-method-signature.stderr index 6d520e5b958e5..ea07a07e09de9 100644 --- a/tests/ui/traits/wrong-mul-method-signature.stderr +++ b/tests/ui/traits/wrong-mul-method-signature.stderr @@ -8,8 +8,6 @@ LL | fn mul(self, s: &f64) -> Vec1 { | = note: expected signature `fn(Vec1, _) -> Vec1` found signature `fn(Vec1, &_) -> Vec1` -note: expected to match type parameter `Rhs` - --> $SRC_DIR/core/src/ops/arith.rs:LL:COL help: change the parameter type to match the trait | LL - fn mul(self, s: &f64) -> Vec1 { @@ -26,8 +24,6 @@ LL | fn mul(self, s: f64) -> Vec2 { | = note: expected signature `fn(Vec2, Vec2) -> f64` found signature `fn(Vec2, f64) -> Vec2` -note: expected to match the `Self` default of type parameter `Rhs` - --> $SRC_DIR/core/src/ops/arith.rs:LL:COL help: change the parameter type to match the trait | LL - fn mul(self, s: f64) -> Vec2 { From b6b1d7aa55fe6914bb77b64ef289a2833f8b2c45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 5 Oct 2026 23:20:36 +0000 Subject: [PATCH 08/34] fix test --- tests/ui/compare-method/default-type-parameter.rs | 1 + tests/ui/compare-method/default-type-parameter.stderr | 8 ++++---- .../feature-gate-effective-target-features.default.stderr | 3 +++ .../feature-gate-effective-target-features.feature.stderr | 3 +++ .../ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr | 3 +++ 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/tests/ui/compare-method/default-type-parameter.rs b/tests/ui/compare-method/default-type-parameter.rs index 92746fb4ebcad..612e763f23737 100644 --- a/tests/ui/compare-method/default-type-parameter.rs +++ b/tests/ui/compare-method/default-type-parameter.rs @@ -1,3 +1,4 @@ +// Regression test for https://github.com/rust-lang/rust/issues/67991 trait Trait { fn foo() -> T; } diff --git a/tests/ui/compare-method/default-type-parameter.stderr b/tests/ui/compare-method/default-type-parameter.stderr index 83517ab76729e..a000922b6307d 100644 --- a/tests/ui/compare-method/default-type-parameter.stderr +++ b/tests/ui/compare-method/default-type-parameter.stderr @@ -1,12 +1,12 @@ error[E0053]: method `foo` has an incompatible type for trait - --> $DIR/default-type-parameter.rs:8:17 + --> $DIR/default-type-parameter.rs:9:17 | LL | impl Trait for S { LL | fn foo() -> u32 { 0 } | ^^^ expected `()`, found `u32` | note: type in trait - --> $DIR/default-type-parameter.rs:2:17 + --> $DIR/default-type-parameter.rs:3:17 | LL | trait Trait { | ------ expected to match the default of type parameter `T` @@ -21,14 +21,14 @@ LL + fn foo() -> () { 0 } | error[E0053]: method `foo` has an incompatible type for trait - --> $DIR/default-type-parameter.rs:11:17 + --> $DIR/default-type-parameter.rs:12:17 | LL | impl Trait for () { LL | fn foo() -> u32 { 0 } | ^^^ expected `i32`, found `u32` | note: type in trait - --> $DIR/default-type-parameter.rs:2:17 + --> $DIR/default-type-parameter.rs:3:17 | LL | trait Trait { | ------ expected to match type parameter `T` diff --git a/tests/ui/feature-gates/feature-gate-effective-target-features.default.stderr b/tests/ui/feature-gates/feature-gate-effective-target-features.default.stderr index 1bad811ada64a..7b8ba0e660ece 100644 --- a/tests/ui/feature-gates/feature-gate-effective-target-features.default.stderr +++ b/tests/ui/feature-gates/feature-gate-effective-target-features.default.stderr @@ -20,12 +20,15 @@ LL | fn foo(&self) {} error[E0053]: method `foo` has an incompatible type for trait --> $DIR/feature-gate-effective-target-features.rs:24:5 | +LL | impl Foo for Bar2 { +... LL | fn foo(&self) {} | ^^^^^^^^^^^^^ expected safe fn, found unsafe fn | note: type in trait --> $DIR/feature-gate-effective-target-features.rs:8:5 | +LL | trait Foo { LL | fn foo(&self); | ^^^^^^^^^^^^^^ = note: expected signature `fn(&Bar2)` diff --git a/tests/ui/feature-gates/feature-gate-effective-target-features.feature.stderr b/tests/ui/feature-gates/feature-gate-effective-target-features.feature.stderr index 06090cbbef6fe..d1939e35d4aba 100644 --- a/tests/ui/feature-gates/feature-gate-effective-target-features.feature.stderr +++ b/tests/ui/feature-gates/feature-gate-effective-target-features.feature.stderr @@ -23,12 +23,15 @@ LL | fn foo(&self) {} error[E0053]: method `foo` has an incompatible type for trait --> $DIR/feature-gate-effective-target-features.rs:24:5 | +LL | impl Foo for Bar2 { +... LL | fn foo(&self) {} | ^^^^^^^^^^^^^ expected safe fn, found unsafe fn | note: type in trait --> $DIR/feature-gate-effective-target-features.rs:8:5 | +LL | trait Foo { LL | fn foo(&self); | ^^^^^^^^^^^^^^ = note: expected signature `fn(&Bar2)` diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr index 39b0e5ea18f7d..86634e54aa3e1 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr @@ -10,12 +10,15 @@ LL | fn foo(&self) {} error[E0053]: method `foo` has an incompatible type for trait --> $DIR/trait-impl.rs:13:5 | +LL | impl Foo for Bar { +... LL | fn foo(&self) {} | ^^^^^^^^^^^^^ expected safe fn, found unsafe fn | note: type in trait --> $DIR/trait-impl.rs:4:5 | +LL | trait Foo { LL | fn foo(&self); | ^^^^^^^^^^^^^^ = note: expected signature `fn(&Bar)` From b9b3dbac1edf71a211506bbd161f45e5ec62347c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 20 Oct 2026 20:31:57 +0000 Subject: [PATCH 09/34] Fix rebase --- compiler/rustc_hir_analysis/src/check/compare_impl_item.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 4a3f71cd311da..711c5e366404e 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -2238,7 +2238,8 @@ fn compare_const_generic_param_types<'tcx>( infcx.err_ctxt().note_type_err( &mut diag, &cause, - param_trait_ty_span.map(|span| (span, Cow::from("type in trait"), false)), + param_trait_ty_span + .map(|span| (span.into(), Cow::from("type in trait"), false)), Some(param_env.and(infer::ValuePairs::Terms(ExpectedFound { expected: trait_ty.into(), found: impl_ty.into(), From 2885a3299c964311f670f4628815859d4c45a5b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 25 Oct 2026 16:54:26 +0000 Subject: [PATCH 10/34] Excercise all new diagnostic changes in existing tests --- .../async-example-desugared-boxed-in-trait.rs | 3 +- ...nc-example-desugared-boxed-in-trait.stderr | 9 +- .../compare-method/default-type-parameter.rs | 14 ++- .../default-type-parameter.stderr | 86 ++++++++++++++++--- 4 files changed, 92 insertions(+), 20 deletions(-) diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs index 8d3dbaf6ca1f1..217eadeb26229 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs +++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs @@ -4,7 +4,8 @@ use std::future::Future; use std::pin::Pin; trait MyTrait { - fn foo(&self) -> Pin + '_>>; + fn foo(&self) + -> Pin + '_>>; } impl MyTrait for i32 { diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr index 6fcba3870cb0c..387626907f1f5 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr +++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr @@ -1,16 +1,17 @@ error[E0053]: method `foo` has an incompatible type for trait - --> $DIR/async-example-desugared-boxed-in-trait.rs:11:28 + --> $DIR/async-example-desugared-boxed-in-trait.rs:12:28 | LL | impl MyTrait for i32 { LL | async fn foo(&self) -> i32 { | ^^^ expected `Pin>>`, found future | note: type in trait - --> $DIR/async-example-desugared-boxed-in-trait.rs:7:22 + --> $DIR/async-example-desugared-boxed-in-trait.rs:8:8 | LL | trait MyTrait { -LL | fn foo(&self) -> Pin + '_>>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn foo(&self) +LL | -> Pin + '_>>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected signature `fn(&_) -> Pin>>` found signature `fn(&_) -> impl Future` diff --git a/tests/ui/compare-method/default-type-parameter.rs b/tests/ui/compare-method/default-type-parameter.rs index 612e763f23737..bdf65d1479239 100644 --- a/tests/ui/compare-method/default-type-parameter.rs +++ b/tests/ui/compare-method/default-type-parameter.rs @@ -1,15 +1,25 @@ // Regression test for https://github.com/rust-lang/rust/issues/67991 -trait Trait { - fn foo() -> T; +// The weird indentation is to excercise the span context that shows the enclosing items in the +// diagnostics being emitted. +trait Trait< + T = (), + K = Self, +> { + fn foo() + -> T; + fn bar() + -> K; } struct S; impl Trait for S { fn foo() -> u32 { 0 } //~ ERROR + fn bar() -> u32 { 0 } //~ ERROR } impl Trait for () { fn foo() -> u32 { 0 } //~ ERROR + fn bar() -> u32 { 0 } //~ ERROR } fn main() {} diff --git a/tests/ui/compare-method/default-type-parameter.stderr b/tests/ui/compare-method/default-type-parameter.stderr index a000922b6307d..e3109566d7fac 100644 --- a/tests/ui/compare-method/default-type-parameter.stderr +++ b/tests/ui/compare-method/default-type-parameter.stderr @@ -1,17 +1,20 @@ error[E0053]: method `foo` has an incompatible type for trait - --> $DIR/default-type-parameter.rs:9:17 + --> $DIR/default-type-parameter.rs:17:17 | LL | impl Trait for S { LL | fn foo() -> u32 { 0 } | ^^^ expected `()`, found `u32` | note: type in trait - --> $DIR/default-type-parameter.rs:3:17 + --> $DIR/default-type-parameter.rs:9:8 | -LL | trait Trait { - | ------ expected to match the default of type parameter `T` -LL | fn foo() -> T; - | ^ +LL | trait Trait< +LL | T = (), + | ------ expected to match the default of type parameter `T` +... +LL | fn foo() +LL | -> T; + | ^ = note: expected signature `fn() -> ()` found signature `fn() -> u32` help: change the output type to match the trait @@ -20,20 +23,50 @@ LL - fn foo() -> u32 { 0 } LL + fn foo() -> () { 0 } | +error[E0053]: method `bar` has an incompatible type for trait + --> $DIR/default-type-parameter.rs:18:17 + | +LL | impl Trait for S { +LL | fn foo() -> u32 { 0 } +LL | fn bar() -> u32 { 0 } + | ^^^ expected `S`, found `u32` + | +note: type in trait + --> $DIR/default-type-parameter.rs:11:8 + | +LL | trait Trait< +LL | T = (), +LL | K = Self, + | -------- expected to match the `Self` default of type parameter `K` +... +LL | fn bar() +LL | -> K; + | ^ + = note: expected signature `fn() -> S` + found signature `fn() -> u32` +help: change the output type to match the trait + | +LL - fn bar() -> u32 { 0 } +LL + fn bar() -> S { 0 } + | + error[E0053]: method `foo` has an incompatible type for trait - --> $DIR/default-type-parameter.rs:12:17 + --> $DIR/default-type-parameter.rs:21:17 | LL | impl Trait for () { LL | fn foo() -> u32 { 0 } | ^^^ expected `i32`, found `u32` | note: type in trait - --> $DIR/default-type-parameter.rs:3:17 + --> $DIR/default-type-parameter.rs:9:8 | -LL | trait Trait { - | ------ expected to match type parameter `T` -LL | fn foo() -> T; - | ^ +LL | trait Trait< +LL | T = (), + | ------ expected to match type parameter `T` +... +LL | fn foo() +LL | -> T; + | ^ = note: expected signature `fn() -> i32` found signature `fn() -> u32` help: change the output type to match the trait @@ -42,6 +75,33 @@ LL - fn foo() -> u32 { 0 } LL + fn foo() -> i32 { 0 } | -error: aborting due to 2 previous errors +error[E0053]: method `bar` has an incompatible type for trait + --> $DIR/default-type-parameter.rs:22:17 + | +LL | impl Trait for () { +LL | fn foo() -> u32 { 0 } +LL | fn bar() -> u32 { 0 } + | ^^^ expected `()`, found `u32` + | +note: type in trait + --> $DIR/default-type-parameter.rs:11:8 + | +LL | trait Trait< +LL | T = (), +LL | K = Self, + | -------- expected to match the `Self` default of type parameter `K` +... +LL | fn bar() +LL | -> K; + | ^ + = note: expected signature `fn() -> ()` + found signature `fn() -> u32` +help: change the output type to match the trait + | +LL - fn bar() -> u32 { 0 } +LL + fn bar() -> () { 0 } + | + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0053`. From 7f7c0b33d8bc7cc8804d0904905430c7611583eb Mon Sep 17 00:00:00 2001 From: Nag Date: Wed, 28 Oct 2026 20:36:53 +0530 Subject: [PATCH 11/34] Improve mem::take wording --- library/core/src/mem/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index a22e52f3a3bc7..b38557779092c 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -837,7 +837,7 @@ pub const fn swap(x: &mut T, y: &mut T) { /// Replaces `dest` with the default value of `T`, returning the previous `dest` value. /// -/// * If you want to replace the values of two variables, see [`swap`]. +/// * If you want to switch the values of two variables, see [`swap`]. /// * If you want to replace with a passed value instead of the default value, see [`replace`]. /// /// # Examples From 9fe3d9e3b28802cc44b89f2405343ef282df6e46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 28 Oct 2026 15:19:14 +0000 Subject: [PATCH 12/34] Make incorrect struct literal syntax suggestion verbose Verbose suggestions are much easier to read for people, at the cost of marginal additional vertical real estate in some cases. ``` error[E0423]: cannot find value `SomeStruct` in crate `remapped_dep` --> $DIR/remap-path-prefix-reverse.rs:15:27 | LL | let _ = remapped_dep::SomeStruct; | ^^^^^^^^^^ | ::: remapped-aux/remapped_dep.rs:4:1 | LL | pub struct SomeStruct {} // This line should be show as part of the error. | --------------------- `remapped_dep::SomeStruct` defined here | = note: a struct named `remapped_dep::SomeStruct` exists in another namespace help: use struct literal syntax instead | LL | let _ = remapped_dep::SomeStruct {}; | ++ ``` instead of ``` error[E0423]: cannot find value `SomeStruct` in crate `remapped_dep` --> $DIR/remap-path-prefix-reverse.rs:15:27 | LL | let _ = remapped_dep::SomeStruct; | --------------^^^^^^^^^^ | | | help: use struct literal syntax instead: `remapped_dep::SomeStruct {}` | ::: remapped-aux/remapped_dep.rs:4:1 | LL | pub struct SomeStruct {} // This line should be show as part of the error. | --------------------- `remapped_dep::SomeStruct` defined here | = note: a struct named `remapped_dep::SomeStruct` exists in another namespace ``` --- .../rustc_resolve/src/late/diagnostics.rs | 2 +- tests/ui/cross-crate/unit-struct.stderr | 8 +++-- ...emap-path-prefix-reverse.local-self.stderr | 8 +++-- ...p-path-prefix-reverse.remapped-self.stderr | 8 +++-- ...e-string-literal-syntax-error-64792.stderr | 7 +++- tests/ui/pattern/issue-106862.stderr | 35 ++++++++++++++++--- ...tch-tuple-variant-self-ctor.struct_.stderr | 6 +++- .../struct-variant-as-tuple-variant.stderr | 7 +++- tests/ui/resolve/issue-6702.stderr | 7 +++- tests/ui/resolve/privacy-struct-ctor.stderr | 6 +++- ...ct-construct-with-call-issue-138931.stderr | 7 +++- tests/ui/suggestions/issue-61226.stderr | 6 +++- 12 files changed, 85 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index df1155bd3208c..5aab574c48c6a 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2646,7 +2646,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { &expression, applicability, ) { - err.span_suggestion( + err.span_suggestion_verbose( span, format!("use struct {descr} syntax instead"), expression, diff --git a/tests/ui/cross-crate/unit-struct.stderr b/tests/ui/cross-crate/unit-struct.stderr index f158602456cea..447b345cafb0b 100644 --- a/tests/ui/cross-crate/unit-struct.stderr +++ b/tests/ui/cross-crate/unit-struct.stderr @@ -2,9 +2,7 @@ error[E0423]: cannot find value `StructWithFields` in crate `xcrate_unit_struct` --> $DIR/unit-struct.rs:9:33 | LL | let _ = xcrate_unit_struct::StructWithFields; - | --------------------^^^^^^^^^^^^^^^^ - | | - | help: use struct literal syntax instead: `xcrate_unit_struct::StructWithFields { foo: val }` + | ^^^^^^^^^^^^^^^^ | ::: $DIR/auxiliary/xcrate_unit_struct.rs:20:1 | @@ -12,6 +10,10 @@ LL | pub struct StructWithFields { | --------------------------- `xcrate_unit_struct::StructWithFields` defined here | = note: a struct named `xcrate_unit_struct::StructWithFields` exists in another namespace +help: use struct literal syntax instead + | +LL | let _ = xcrate_unit_struct::StructWithFields { foo: val }; + | ++++++++++++ error[E0423]: cannot find value `StructWithPrivFields` in crate `xcrate_unit_struct` --> $DIR/unit-struct.rs:11:33 diff --git a/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr b/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr index 047916bb7cace..eabf17c25c902 100644 --- a/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr +++ b/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr @@ -2,9 +2,7 @@ error[E0423]: cannot find value `SomeStruct` in crate `remapped_dep` --> $DIR/remap-path-prefix-reverse.rs:15:27 | LL | let _ = remapped_dep::SomeStruct; - | --------------^^^^^^^^^^ - | | - | help: use struct literal syntax instead: `remapped_dep::SomeStruct {}` + | ^^^^^^^^^^ | ::: remapped-aux/remapped_dep.rs:4:1 | @@ -12,6 +10,10 @@ LL | pub struct SomeStruct {} // This line should be show as part of the error. | --------------------- `remapped_dep::SomeStruct` defined here | = note: a struct named `remapped_dep::SomeStruct` exists in another namespace +help: use struct literal syntax instead + | +LL | let _ = remapped_dep::SomeStruct {}; + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr b/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr index 047916bb7cace..eabf17c25c902 100644 --- a/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr +++ b/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr @@ -2,9 +2,7 @@ error[E0423]: cannot find value `SomeStruct` in crate `remapped_dep` --> $DIR/remap-path-prefix-reverse.rs:15:27 | LL | let _ = remapped_dep::SomeStruct; - | --------------^^^^^^^^^^ - | | - | help: use struct literal syntax instead: `remapped_dep::SomeStruct {}` + | ^^^^^^^^^^ | ::: remapped-aux/remapped_dep.rs:4:1 | @@ -12,6 +10,10 @@ LL | pub struct SomeStruct {} // This line should be show as part of the error. | --------------------- `remapped_dep::SomeStruct` defined here | = note: a struct named `remapped_dep::SomeStruct` exists in another namespace +help: use struct literal syntax instead + | +LL | let _ = remapped_dep::SomeStruct {}; + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/parser/unicode-string-literal-syntax-error-64792.stderr b/tests/ui/parser/unicode-string-literal-syntax-error-64792.stderr index bdb2e412f0211..3ccca2e8a46e1 100644 --- a/tests/ui/parser/unicode-string-literal-syntax-error-64792.stderr +++ b/tests/ui/parser/unicode-string-literal-syntax-error-64792.stderr @@ -5,9 +5,14 @@ LL | struct X {} | ----------- `X` defined here LL | LL | const Y: X = X("ö"); - | ^^^^^^ help: use struct literal syntax instead: `X {}` + | ^^^^^^ | = note: a struct named `X` exists in another namespace +help: use struct literal syntax instead + | +LL - const Y: X = X("ö"); +LL + const Y: X = X {}; + | error: aborting due to 1 previous error diff --git a/tests/ui/pattern/issue-106862.stderr b/tests/ui/pattern/issue-106862.stderr index fc613f3d39156..d075f6252c915 100644 --- a/tests/ui/pattern/issue-106862.stderr +++ b/tests/ui/pattern/issue-106862.stderr @@ -5,9 +5,14 @@ LL | FooB { x: i32, y: i32 } | ----------------------- `FooB` defined here ... LL | FooB(a, b) => println!("{} {}", a, b), - | ^^^^^^^^^^ help: use struct pattern syntax instead: `FooB { x: a, y: b }` + | ^^^^^^^^^^ | = note: a variant named `FooB` exists in another namespace +help: use struct pattern syntax instead + | +LL - FooB(a, b) => println!("{} {}", a, b), +LL + FooB { x: a, y: b } => println!("{} {}", a, b), + | error[E0532]: cannot find tuple struct or tuple variant `FooB` in this scope --> $DIR/issue-106862.rs:22:9 @@ -16,9 +21,14 @@ LL | FooB { x: i32, y: i32 } | ----------------------- `FooB` defined here ... LL | FooB(x, y) => println!("{} {}", x, y), - | ^^^^^^^^^^ help: use struct pattern syntax instead: `FooB { x, y }` + | ^^^^^^^^^^ | = note: a variant named `FooB` exists in another namespace +help: use struct pattern syntax instead + | +LL - FooB(x, y) => println!("{} {}", x, y), +LL + FooB { x, y } => println!("{} {}", x, y), + | error[E0532]: cannot find tuple struct or tuple variant `FooA` in this scope --> $DIR/issue-106862.rs:28:9 @@ -27,9 +37,14 @@ LL | FooA { opt_x: Option, y: i32 }, | ----------------------------------- `FooA` defined here ... LL | FooA(Some(x), y) => println!("{} {}", x, y), - | ^^^^^^^^^^^^^^^^ help: use struct pattern syntax instead: `FooA { opt_x: Some(x), y }` + | ^^^^^^^^^^^^^^^^ | = note: a variant named `FooA` exists in another namespace +help: use struct pattern syntax instead + | +LL - FooA(Some(x), y) => println!("{} {}", x, y), +LL + FooA { opt_x: Some(x), y } => println!("{} {}", x, y), + | error[E0532]: cannot find tuple struct or tuple variant `FooB` in this scope --> $DIR/issue-106862.rs:34:9 @@ -38,9 +53,14 @@ LL | FooB { x: i32, y: i32 } | ----------------------- `FooB` defined here ... LL | FooB(a, _, _) => println!("{}", a), - | ^^^^^^^^^^^^^ help: use struct pattern syntax instead: `FooB { x: a, y: _ }` + | ^^^^^^^^^^^^^ | = note: a variant named `FooB` exists in another namespace +help: use struct pattern syntax instead + | +LL - FooB(a, _, _) => println!("{}", a), +LL + FooB { x: a, y: _ } => println!("{}", a), + | error[E0532]: cannot find tuple struct or tuple variant `FooB` in this scope --> $DIR/issue-106862.rs:40:9 @@ -49,9 +69,14 @@ LL | FooB { x: i32, y: i32 } | ----------------------- `FooB` defined here ... LL | FooB() => (), - | ^^^^^^ help: use struct pattern syntax instead: `FooB { x, y }` + | ^^^^^^ | = note: a variant named `FooB` exists in another namespace +help: use struct pattern syntax instead + | +LL - FooB() => (), +LL + FooB { x, y } => (), + | error: aborting due to 5 previous errors diff --git a/tests/ui/pattern/no-match-tuple-variant-self-ctor.struct_.stderr b/tests/ui/pattern/no-match-tuple-variant-self-ctor.struct_.stderr index 0627e2b202f63..6a7560c3d5a75 100644 --- a/tests/ui/pattern/no-match-tuple-variant-self-ctor.struct_.stderr +++ b/tests/ui/pattern/no-match-tuple-variant-self-ctor.struct_.stderr @@ -5,9 +5,13 @@ LL | struct S {} | ----------- `S` defined here ... LL | let Self = S; - | ^ help: use struct literal syntax instead: `S {}` + | ^ | = note: a struct named `S` exists in another namespace +help: use struct literal syntax instead + | +LL | let Self = S {}; + | ++ error[E0533]: expected unit struct, found self constructor `Self` --> $DIR/no-match-tuple-variant-self-ctor.rs:30:17 diff --git a/tests/ui/pattern/struct-variant-as-tuple-variant.stderr b/tests/ui/pattern/struct-variant-as-tuple-variant.stderr index 821ca297802a3..88d3641d0e81e 100644 --- a/tests/ui/pattern/struct-variant-as-tuple-variant.stderr +++ b/tests/ui/pattern/struct-variant-as-tuple-variant.stderr @@ -5,9 +5,14 @@ LL | FooB { x: i32, y: i32 } | ----------------------- `FooB` defined here ... LL | FooB(a, b) => println!("{} {}", a, b), - | ^^^^^^^^^^ help: use struct pattern syntax instead: `FooB { x: a, y: b }` + | ^^^^^^^^^^ | = note: a variant named `FooB` exists in another namespace +help: use struct pattern syntax instead + | +LL - FooB(a, b) => println!("{} {}", a, b), +LL + FooB { x: a, y: b } => println!("{} {}", a, b), + | error: aborting due to 1 previous error diff --git a/tests/ui/resolve/issue-6702.stderr b/tests/ui/resolve/issue-6702.stderr index dd1f2c5d7f819..865c07812e56c 100644 --- a/tests/ui/resolve/issue-6702.stderr +++ b/tests/ui/resolve/issue-6702.stderr @@ -7,9 +7,14 @@ LL | | } | |_- `Monster` defined here ... LL | let _m = Monster(); - | ^^^^^^^^^ help: use struct literal syntax instead: `Monster { damage: val }` + | ^^^^^^^^^ | = note: a struct named `Monster` exists in another namespace +help: use struct literal syntax instead + | +LL - let _m = Monster(); +LL + let _m = Monster { damage: val }; + | error: aborting due to 1 previous error diff --git a/tests/ui/resolve/privacy-struct-ctor.stderr b/tests/ui/resolve/privacy-struct-ctor.stderr index e948c6fdae9eb..6f8843a24b5de 100644 --- a/tests/ui/resolve/privacy-struct-ctor.stderr +++ b/tests/ui/resolve/privacy-struct-ctor.stderr @@ -33,9 +33,13 @@ LL | | } | |_____- `S2` defined here ... LL | S2; - | ^^ help: use struct literal syntax instead: `S2 { s: val }` + | ^^ | = note: a struct named `S2` exists in another namespace +help: use struct literal syntax instead + | +LL | S2 { s: val }; + | ++++++++++ error[E0423]: cannot find value `S` in crate `xcrate` --> $DIR/privacy-struct-ctor.rs:44:13 diff --git a/tests/ui/structs/struct-construct-with-call-issue-138931.stderr b/tests/ui/structs/struct-construct-with-call-issue-138931.stderr index 9248eebbae3ae..83266161c5206 100644 --- a/tests/ui/structs/struct-construct-with-call-issue-138931.stderr +++ b/tests/ui/structs/struct-construct-with-call-issue-138931.stderr @@ -53,9 +53,14 @@ LL | | } | |_- `PersonWithAge` defined here ... LL | let person = PersonWithAge("Name3".to_owned()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `PersonWithAge { name: val, age: val, height: val }` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: a struct named `PersonWithAge` exists in another namespace +help: use struct literal syntax instead + | +LL - let person = PersonWithAge("Name3".to_owned()); +LL + let person = PersonWithAge { name: val, age: val, height: val }; + | error: aborting due to 3 previous errors diff --git a/tests/ui/suggestions/issue-61226.stderr b/tests/ui/suggestions/issue-61226.stderr index cf21435cc3cbc..ba8ca5c315018 100644 --- a/tests/ui/suggestions/issue-61226.stderr +++ b/tests/ui/suggestions/issue-61226.stderr @@ -5,9 +5,13 @@ LL | struct X {} | ----------- `X` defined here LL | fn main() { LL | let _ = vec![X]; //… - | ^ help: use struct literal syntax instead: `X {}` + | ^ | = note: a struct named `X` exists in another namespace +help: use struct literal syntax instead + | +LL | let _ = vec![X {}]; //… + | ++ error: aborting due to 1 previous error From 4cab988e273f1918262b3dbe4376d39a20db5a98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 28 Oct 2026 15:38:45 +0000 Subject: [PATCH 13/34] Do not incorrectly suggest changing tuple struct to local binding When encountering a tuple struct that can't be constructed because of private fields, do not suggest local binding typo, as the only valid case would be a local closure but during resolve we can't confirm that is the case. --- .../rustc_resolve/src/late/diagnostics.rs | 21 +++++++++++++++-- ...ate-fields-doesnt-suggest-local-typo.fixed | 18 +++++++++++++++ ...rivate-fields-doesnt-suggest-local-typo.rs | 18 +++++++++++++++ ...te-fields-doesnt-suggest-local-typo.stderr | 23 +++++++++++++++++++ 4 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 tests/ui/resolve/tuple-struct-with-private-fields-doesnt-suggest-local-typo.fixed create mode 100644 tests/ui/resolve/tuple-struct-with-private-fields-doesnt-suggest-local-typo.rs create mode 100644 tests/ui/resolve/tuple-struct-with-private-fields-doesnt-suggest-local-typo.stderr diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 5aab574c48c6a..65a40f8922c1f 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1252,8 +1252,25 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { &path_str, &base_error.fallback_label, ) { - // We do this to avoid losing a secondary span when we override the main error span. - self.r.add_typo_suggestion(err, typo_sugg, ident_span, None); + if let Some(sugg) = &typo_sugg + && let Res::Local(_) = sugg.res + { + if let PathSource::Expr(Some(expr)) = source + && let ExprKind::Call(..) = expr.kind + { + // Do not suggest typo changes for calling a local. This would only be valid + // for closures, but during resolve we can't check the bindings type. This + // avoids cases like the one in #66067. + } else if path.len() == 1 { + // Only paths with a single segment would realistically be a typo of a + // local binding. + // We add a suggestion to avoid losing a secondary span when we override + // the main error span. + self.r.add_typo_suggestion(err, typo_sugg, ident_span, None); + } + } else { + self.r.add_typo_suggestion(err, typo_sugg, ident_span, None); + } return (true, suggested_candidates, candidates); } } diff --git a/tests/ui/resolve/tuple-struct-with-private-fields-doesnt-suggest-local-typo.fixed b/tests/ui/resolve/tuple-struct-with-private-fields-doesnt-suggest-local-typo.fixed new file mode 100644 index 0000000000000..6cbc5833ee2ac --- /dev/null +++ b/tests/ui/resolve/tuple-struct-with-private-fields-doesnt-suggest-local-typo.fixed @@ -0,0 +1,18 @@ +//@ run-rustfix +// Issue #66067. +#![allow(unused)] +mod outer { + mod a { + // This struct can't be constructed from `crate::` because of the private fields. + pub struct Triplet(pub usize, pub usize, pub f64); + } + pub use self::a::Triplet; +} + +use outer::Triplet; + +fn main() { + let mut triplets = Vec::new(); + // Ensure that we do not suggest changing `Triplet` to `triplets`: + triplets.push(Triplet(0, 0, 1.0)); //~ ERROR: E0423 +} diff --git a/tests/ui/resolve/tuple-struct-with-private-fields-doesnt-suggest-local-typo.rs b/tests/ui/resolve/tuple-struct-with-private-fields-doesnt-suggest-local-typo.rs new file mode 100644 index 0000000000000..727220d7ae5b5 --- /dev/null +++ b/tests/ui/resolve/tuple-struct-with-private-fields-doesnt-suggest-local-typo.rs @@ -0,0 +1,18 @@ +//@ run-rustfix +// Issue #66067. +#![allow(unused)] +mod outer { + mod a { + // This struct can't be constructed from `crate::` because of the private fields. + pub struct Triplet(usize, usize, f64); + } + pub use self::a::Triplet; +} + +use outer::Triplet; + +fn main() { + let mut triplets = Vec::new(); + // Ensure that we do not suggest changing `Triplet` to `triplets`: + triplets.push(Triplet(0, 0, 1.0)); //~ ERROR: E0423 +} diff --git a/tests/ui/resolve/tuple-struct-with-private-fields-doesnt-suggest-local-typo.stderr b/tests/ui/resolve/tuple-struct-with-private-fields-doesnt-suggest-local-typo.stderr new file mode 100644 index 0000000000000..ccbad1a2bdf5c --- /dev/null +++ b/tests/ui/resolve/tuple-struct-with-private-fields-doesnt-suggest-local-typo.stderr @@ -0,0 +1,23 @@ +error[E0423]: cannot initialize a tuple struct which contains private fields + --> $DIR/tuple-struct-with-private-fields-doesnt-suggest-local-typo.rs:17:19 + | +LL | triplets.push(Triplet(0, 0, 1.0)); + | ^^^^^^^ + | + = note: a struct named `Triplet` exists in another namespace +note: constructor is not visible here due to private fields + --> $DIR/tuple-struct-with-private-fields-doesnt-suggest-local-typo.rs:7:28 + | +LL | pub struct Triplet(usize, usize, f64); + | ^^^^^ ^^^^^ ^^^ private field + | | | + | | private field + | private field +help: consider making the fields publicly accessible + | +LL | pub struct Triplet(pub usize, pub usize, pub f64); + | +++ +++ +++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0423`. From 67300e324c0105d6e687f78f438088506b0a1f65 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 31 Oct 2026 19:05:44 +0100 Subject: [PATCH 14/34] Mostly restore apple jobs --- src/ci/github-actions/jobs.yml | 91 +++++++++++++++++----------------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 8ee042c415322..3bb8e939a9b0e 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -561,51 +561,52 @@ auto: CODEGEN_BACKENDS: llvm,cranelift <<: *job-macos-15 -# - name: test-aarch64-apple-1 -# env: -# # NOTE: keep in sync with `src/ci/docker/scripts/stage_2_test_set1.sh` -# SCRIPT: >- -# ./x.py --stage 2 test -# --host=aarch64-apple-darwin -# --target=aarch64-apple-darwin -# --skip compiler -# --skip src -# RUST_CONFIGURE_ARGS: >- -# --enable-sanitizers -# --enable-profiler -# --set build.allocator=jemalloc -# DEVELOPER_DIR: /Applications/Xcode_26.2.app/Contents/Developer -# # Aarch64 tooling only needs to support macOS 11.0 and up as nothing else -# # supports the hardware, so only need to test it there. -# MACOSX_DEPLOYMENT_TARGET: 11.0 -# MACOSX_STD_DEPLOYMENT_TARGET: 11.0 -# <<: *job-macos-15 -# -# - name: test-aarch64-apple-2 -# env: -# # NOTE: keep in sync with `src/ci/docker/scripts/stage_2_test_set2.sh`, -# # union `src/tools/cargo` specifically. -# SCRIPT: >- -# ./x.py --stage 2 test -# --host=aarch64-apple-darwin -# --target=aarch64-apple-darwin -# --skip tests -# --skip library -# --skip tidyselftest -# && ./x.py --stage 2 test -# --host=aarch64-apple-darwin -# --target=aarch64-apple-darwin -# src/tools/cargo -# RUST_CONFIGURE_ARGS: >- -# --enable-sanitizers -# --enable-profiler -# --set build.allocator=jemalloc -# DEVELOPER_DIR: /Applications/Xcode_26.2.app/Contents/Developer -# # Aarch64 tooling only needs to support macOS 11.0 and up as nothing else -# # supports the hardware, so only need to test it there. -# MACOSX_DEPLOYMENT_TARGET: 11.0 -# MACOSX_STD_DEPLOYMENT_TARGET: 11.0 -# <<: *job-macos-15 + - name: test-aarch64-apple-1 + env: + # NOTE: keep in sync with `src/ci/docker/scripts/stage_2_test_set1.sh` + SCRIPT: >- + ./x.py --stage 2 test + --host=aarch64-apple-darwin + --target=aarch64-apple-darwin + --skip compiler + --skip src + RUST_CONFIGURE_ARGS: >- + --enable-sanitizers + --enable-profiler + --set build.allocator=jemalloc + DEVELOPER_DIR: /Applications/Xcode_26.2.app/Contents/Developer + # Aarch64 tooling only needs to support macOS 11.0 and up as nothing else + # supports the hardware, so only need to test it there. + MACOSX_DEPLOYMENT_TARGET: 11.0 + MACOSX_STD_DEPLOYMENT_TARGET: 11.0 + <<: *job-macos-15 + + - name: test-aarch64-apple-2 + env: + # NOTE: keep in sync with `src/ci/docker/scripts/stage_2_test_set2.sh`, + # union `src/tools/cargo` specifically. + SCRIPT: >- + ./x.py --stage 2 test + --host=aarch64-apple-darwin + --target=aarch64-apple-darwin + --skip tests + --skip library + --skip tidyselftest + --skip src/tools/rust-analyzer + && ./x.py --stage 2 test + --host=aarch64-apple-darwin + --target=aarch64-apple-darwin + src/tools/cargo + RUST_CONFIGURE_ARGS: >- + --enable-sanitizers + --enable-profiler + --set build.allocator=jemalloc + DEVELOPER_DIR: /Applications/Xcode_26.2.app/Contents/Developer + # Aarch64 tooling only needs to support macOS 11.0 and up as nothing else + # supports the hardware, so only need to test it there. + MACOSX_DEPLOYMENT_TARGET: 11.0 + MACOSX_STD_DEPLOYMENT_TARGET: 11.0 + <<: *job-macos-15 ###################### # Windows Builders # From 5f8395784f2cfd94c643368b79143500e92c5006 Mon Sep 17 00:00:00 2001 From: Ubiratan Soares Date: Thu, 29 Oct 2026 17:45:35 +0100 Subject: [PATCH 15/34] ci: increase free disk space on macos-26 jobs --- .github/workflows/ci.yml | 4 +-- src/ci/github-actions/jobs.yml | 5 ++++ src/ci/scripts/free-disk-space-mac.sh | 35 +++++++++++++++++++++++++++ src/ci/scripts/free-disk-space.sh | 18 ++++++++++++++ 4 files changed, 60 insertions(+), 2 deletions(-) create mode 100755 src/ci/scripts/free-disk-space-mac.sh create mode 100755 src/ci/scripts/free-disk-space.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f15a9fcd59124..9d04846c7c872 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -121,12 +121,12 @@ jobs: with: fetch-depth: 2 - # Free up disk space on Linux by removing preinstalled components that + # Free up disk space on Linux or macOS by removing preinstalled components that # we do not need. We do this to enable some of the less resource # intensive jobs to run on free runners, which however also have # less disk space. - name: free up disk space - run: src/ci/scripts/free-disk-space-linux.sh + run: src/ci/scripts/free-disk-space.sh if: matrix.free_disk # If we don't need to free up disk space then just report how much space we have diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 3bb8e939a9b0e..92c47a7306fb3 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -19,6 +19,11 @@ runners: os: macos-15 # macOS 15 Arm64 <<: *base-job + - &job-macos-26 + os: macos-26 # macOS 26 Arm64 + free_disk: true # See https://github.com/rust-lang/infra-team/issues/307 + <<: *base-job + - &job-windows os: windows-2025 <<: *base-job diff --git a/src/ci/scripts/free-disk-space-mac.sh b/src/ci/scripts/free-disk-space-mac.sh new file mode 100755 index 0000000000000..a08d8169e67c0 --- /dev/null +++ b/src/ci/scripts/free-disk-space-mac.sh @@ -0,0 +1,35 @@ +#!/bin/bash +set -euo pipefail +# ignore-tidy-file-linelength + +# Free disk space on macOS GitHub action runners +# Achieved by removing all iOS simulator instance files and runtimes +# See https://developer.apple.com/documentation/xcode/xcode-command-line-tool-reference#Manage-the-Simulator + +space_before=$(df -k "$GITHUB_WORKSPACE" | awk 'NR == 2 {print $4}') + +xcrun simctl shutdown all +xcrun simctl delete all + +# This subcommand runs asynchronously +xcrun simctl runtime delete all + +# Wait a max of 60 seconds to ensure the clean-up is done before any subsequential build steps +for ((attempt = 0; attempt < 30; attempt++)); do + remaining=$(xcrun simctl runtime list -j | jq 'length') + echo "Remaining runtime iOS simulator images : $remaining" + + if [[ "$remaining" == 0 ]]; then + break + fi + sleep 2 +done + +if [[ "$remaining" != 0 ]]; then + echo "::warning::Runtime deletion did not finish within the polling period." +fi + +# Report net increase in available disk space +space_after=$(df -k "$GITHUB_WORKSPACE" | awk 'NR == 2 {print $4}') +extra_space=$(awk -v b="$space_before" -v a="$space_after" 'BEGIN { printf "%.2f", (a - b) / 1048576 }') +echo "Increase in available disk space: $extra_space GiB" diff --git a/src/ci/scripts/free-disk-space.sh b/src/ci/scripts/free-disk-space.sh new file mode 100755 index 0000000000000..16e1247ca6a53 --- /dev/null +++ b/src/ci/scripts/free-disk-space.sh @@ -0,0 +1,18 @@ +#!/bin/bash +set -euo pipefail + +script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) + +# dispatch according to the Github Runner +case "${RUNNER_OS:-}" in + Linux) + exec "${script_dir}/free-disk-space-linux.sh" + ;; + macOS) + exec "${script_dir}/free-disk-space-mac.sh" + ;; + *) + echo "::error:: freeing disk space not supported for : '${RUNNER_OS:-unset}'" + exit 1 + ;; +esac From fca19329bf91c471a1241be0b7da27ce2eebcd9c Mon Sep 17 00:00:00 2001 From: Ubiratan Soares Date: Fri, 30 Oct 2026 00:14:47 +0100 Subject: [PATCH 16/34] ci: add minor improvements to scripts --- src/ci/scripts/free-disk-space-mac.sh | 8 +++++--- src/ci/scripts/free-disk-space.sh | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/ci/scripts/free-disk-space-mac.sh b/src/ci/scripts/free-disk-space-mac.sh index a08d8169e67c0..b2ead34a4dc8b 100755 --- a/src/ci/scripts/free-disk-space-mac.sh +++ b/src/ci/scripts/free-disk-space-mac.sh @@ -3,9 +3,11 @@ set -euo pipefail # ignore-tidy-file-linelength # Free disk space on macOS GitHub action runners -# Achieved by removing all iOS simulator instance files and runtimes +# Achieved by removing all iOS simulator instance files and runtime images # See https://developer.apple.com/documentation/xcode/xcode-command-line-tool-reference#Manage-the-Simulator +echo "deleting iOS simulator instance files and runtime images" + space_before=$(df -k "$GITHUB_WORKSPACE" | awk 'NR == 2 {print $4}') xcrun simctl shutdown all @@ -17,7 +19,7 @@ xcrun simctl runtime delete all # Wait a max of 60 seconds to ensure the clean-up is done before any subsequential build steps for ((attempt = 0; attempt < 30; attempt++)); do remaining=$(xcrun simctl runtime list -j | jq 'length') - echo "Remaining runtime iOS simulator images : $remaining" + echo "Remaining simulator runtime images : $remaining" if [[ "$remaining" == 0 ]]; then break @@ -26,7 +28,7 @@ for ((attempt = 0; attempt < 30; attempt++)); do done if [[ "$remaining" != 0 ]]; then - echo "::warning::Runtime deletion did not finish within the polling period." + echo "::warning::Simlator runtime deletion did not finish within the polling period." fi # Report net increase in available disk space diff --git a/src/ci/scripts/free-disk-space.sh b/src/ci/scripts/free-disk-space.sh index 16e1247ca6a53..162f3da89a483 100755 --- a/src/ci/scripts/free-disk-space.sh +++ b/src/ci/scripts/free-disk-space.sh @@ -1,7 +1,7 @@ #!/bin/bash set -euo pipefail -script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) +script_dir=$(cd -- "$(dirname -- "$0")" && pwd) # dispatch according to the Github Runner case "${RUNNER_OS:-}" in From 009ca55215e7c084f667cafac2a2871cc49a01f9 Mon Sep 17 00:00:00 2001 From: Ubiratan Soares Date: Fri, 30 Oct 2026 00:26:48 +0100 Subject: [PATCH 17/34] ci: restore macos-26 jobs --- src/ci/github-actions/jobs.yml | 54 ++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 92c47a7306fb3..88e61ea2bdcbb 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -613,6 +613,60 @@ auto: MACOSX_STD_DEPLOYMENT_TARGET: 11.0 <<: *job-macos-15 + # EXPERIMENT(#157687): we will try to run `aarch64-apple`-equivalent workload + # on `macos-26` runner images in parallel to evaluate the running times, since + # previous attempts have timed out multiple times. Remove/revert this job if + # this hangs or times out, or if it becomes the slowest Merge CI job, and let + # T-infra know. + # See also #165148 + - name: test-aarch64-apple-macos-26-1 + doc_url: https://github.com/rust-lang/rust/issues/157687 + env: + # NOTE: keep in sync with `src/ci/docker/scripts/stage_2_test_set1.sh` + SCRIPT: >- + ./x.py --stage 2 test + --host=aarch64-apple-darwin + --target=aarch64-apple-darwin + --skip compiler + --skip src + RUST_CONFIGURE_ARGS: >- + --enable-sanitizers + --enable-profiler + --set rust.jemalloc + DEVELOPER_DIR: /Applications/Xcode_26.2.app/Contents/Developer + # Aarch64 tooling only needs to support macOS 11.0 and up as nothing else + # supports the hardware, so only need to test it there. + MACOSX_DEPLOYMENT_TARGET: 11.0 + MACOSX_STD_DEPLOYMENT_TARGET: 11.0 + <<: *job-macos-26 + + - name: test-aarch64-apple-macos-26-2 + doc_url: https://github.com/rust-lang/rust/issues/157687 + env: + # NOTE: keep in sync with `src/ci/docker/scripts/stage_2_test_set2.sh`, + # union `src/tools/cargo` specifically. + SCRIPT: >- + ./x.py --stage 2 test + --host=aarch64-apple-darwin + --target=aarch64-apple-darwin + --skip tests + --skip library + --skip tidyselftest + && ./x.py --stage 2 test + --host=aarch64-apple-darwin + --target=aarch64-apple-darwin + src/tools/cargo + RUST_CONFIGURE_ARGS: >- + --enable-sanitizers + --enable-profiler + --set rust.jemalloc + DEVELOPER_DIR: /Applications/Xcode_26.2.app/Contents/Developer + # Aarch64 tooling only needs to support macOS 11.0 and up as nothing else + # supports the hardware, so only need to test it there. + MACOSX_DEPLOYMENT_TARGET: 11.0 + MACOSX_STD_DEPLOYMENT_TARGET: 11.0 + <<: *job-macos-26 + ###################### # Windows Builders # ###################### From 44acbcf3da710ebae98ad54bfa535f04fc520dd8 Mon Sep 17 00:00:00 2001 From: Ubiratan Soares Date: Fri, 30 Oct 2026 09:12:31 +0100 Subject: [PATCH 18/34] ci: output df stats before and after clean-up --- .github/workflows/ci.yml | 4 +--- src/ci/scripts/free-disk-space-mac.sh | 12 +++++++++--- src/ci/scripts/free-disk-space.sh | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9d04846c7c872..3e45ac01331ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -122,9 +122,7 @@ jobs: fetch-depth: 2 # Free up disk space on Linux or macOS by removing preinstalled components that - # we do not need. We do this to enable some of the less resource - # intensive jobs to run on free runners, which however also have - # less disk space. + # we do not need. - name: free up disk space run: src/ci/scripts/free-disk-space.sh if: matrix.free_disk diff --git a/src/ci/scripts/free-disk-space-mac.sh b/src/ci/scripts/free-disk-space-mac.sh index b2ead34a4dc8b..b67222ef9210c 100755 --- a/src/ci/scripts/free-disk-space-mac.sh +++ b/src/ci/scripts/free-disk-space-mac.sh @@ -6,6 +6,9 @@ set -euo pipefail # Achieved by removing all iOS simulator instance files and runtime images # See https://developer.apple.com/documentation/xcode/xcode-command-line-tool-reference#Manage-the-Simulator +echo "Before clean-up:" +df -h + echo "deleting iOS simulator instance files and runtime images" space_before=$(df -k "$GITHUB_WORKSPACE" | awk 'NR == 2 {print $4}') @@ -18,8 +21,8 @@ xcrun simctl runtime delete all # Wait a max of 60 seconds to ensure the clean-up is done before any subsequential build steps for ((attempt = 0; attempt < 30; attempt++)); do - remaining=$(xcrun simctl runtime list -j | jq 'length') - echo "Remaining simulator runtime images : $remaining" + remaining=$(xcrun simctl runtime list -j | jq -e 'length') + echo "Remaining simulator runtime images: $remaining" if [[ "$remaining" == 0 ]]; then break @@ -28,10 +31,13 @@ for ((attempt = 0; attempt < 30; attempt++)); do done if [[ "$remaining" != 0 ]]; then - echo "::warning::Simlator runtime deletion did not finish within the polling period." + echo "::warning::Simulator runtime deletion did not finish within the polling period." fi # Report net increase in available disk space space_after=$(df -k "$GITHUB_WORKSPACE" | awk 'NR == 2 {print $4}') extra_space=$(awk -v b="$space_before" -v a="$space_after" 'BEGIN { printf "%.2f", (a - b) / 1048576 }') echo "Increase in available disk space: $extra_space GiB" + +echo "After clean-up:" +df -h diff --git a/src/ci/scripts/free-disk-space.sh b/src/ci/scripts/free-disk-space.sh index 162f3da89a483..76e0140806e93 100755 --- a/src/ci/scripts/free-disk-space.sh +++ b/src/ci/scripts/free-disk-space.sh @@ -12,7 +12,7 @@ case "${RUNNER_OS:-}" in exec "${script_dir}/free-disk-space-mac.sh" ;; *) - echo "::error:: freeing disk space not supported for : '${RUNNER_OS:-unset}'" + echo "::error:: freeing disk space not supported for: '${RUNNER_OS:-unset}'" exit 1 ;; esac From 547b0bb799c93026b22082b6c6e23890ca7b5644 Mon Sep 17 00:00:00 2001 From: Ubiratan Soares Date: Fri, 30 Oct 2026 16:01:39 +0100 Subject: [PATCH 19/34] ci: free disk space also on macos-15 --- src/ci/github-actions/jobs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 88e61ea2bdcbb..210c139dd2b56 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -17,6 +17,7 @@ runners: - &job-macos-15 os: macos-15 # macOS 15 Arm64 + free_disk: true <<: *base-job - &job-macos-26 From 2a91b501ccaa328b83f702b8915ee32a1b90ef21 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Thu, 6 Mar 2025 16:54:55 -0800 Subject: [PATCH 20/34] Add TypeScript type for `window.ALL_CRATES`. --- src/librustdoc/html/static/js/main.js | 2 -- src/librustdoc/html/static/js/rustdoc.d.ts | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index e957a13a2b038..24aa8e8966ae6 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1124,7 +1124,6 @@ function preLoadCss(cssUrl) { } function addSidebarCrates() { - // @ts-expect-error if (!window.ALL_CRATES) { return; } @@ -1138,7 +1137,6 @@ function preLoadCss(cssUrl) { const ul = document.createElement("ul"); ul.className = "block crate"; - // @ts-expect-error for (const crate of window.ALL_CRATES) { const link = document.createElement("a"); link.href = window.rootPath + crate + "/index.html"; diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts index fef93a01a26cb..ba4b5ce87eeac 100644 --- a/src/librustdoc/html/static/js/rustdoc.d.ts +++ b/src/librustdoc/html/static/js/rustdoc.d.ts @@ -31,6 +31,8 @@ declare global { /** Notable trait data */ NOTABLE_TRAITS?: { [key: string]: string }; CURRENT_TOOLTIP_ELEMENT?: HTMLElement & { TOOLTIP_BASE: HTMLElement }; + /** List of all documented crates. Generated in `render/write_shared.rs`. */ + ALL_CRATES: string[]|undefined; /** Used by the popover tooltip code. */ RUSTDOC_TOOLTIP_HOVER_MS: number; /** Used by the popover tooltip code. */ From bc22034eb8bcf62c84e809015f50e3acd27d9995 Mon Sep 17 00:00:00 2001 From: Bee Date: Sun, 1 Nov 2026 01:10:26 +0000 Subject: [PATCH 21/34] Replace `AbiAlign` with `Align` in `pointer_align{,_in}` --- compiler/rustc_abi/src/lib.rs | 12 +++++------ .../src/abi/pass_mode.rs | 2 +- compiler/rustc_codegen_llvm/src/consts.rs | 8 ++++---- .../src/debuginfo/metadata.rs | 8 +++----- compiler/rustc_codegen_llvm/src/intrinsic.rs | 2 +- compiler/rustc_codegen_llvm/src/va_arg.rs | 20 +++++++++---------- compiler/rustc_codegen_ssa/src/base.rs | 2 +- compiler/rustc_codegen_ssa/src/meth.rs | 2 +- .../rustc_middle/src/mir/interpret/mod.rs | 2 +- compiler/rustc_middle/src/ty/vtable.rs | 2 +- compiler/rustc_session/src/config/cfg.rs | 2 +- 11 files changed, 30 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 0b8203f955766..a06e84b22e013 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -781,20 +781,20 @@ impl TargetDataLayout { /// Get the pointer alignment in the default data address space. #[inline] - pub fn pointer_align(&self) -> AbiAlign { - AbiAlign::new(self.default_address_space_pointer_spec.pointer_align) + pub fn pointer_align(&self) -> Align { + self.default_address_space_pointer_spec.pointer_align } /// Get the pointer alignment in a specific address space. #[inline] - pub fn pointer_align_in(&self, c: AddressSpace) -> AbiAlign { - AbiAlign::new(if c == self.default_address_space { + pub fn pointer_align_in(&self, c: AddressSpace) -> Align { + if c == self.default_address_space { self.default_address_space_pointer_spec.pointer_align } else if let Some(e) = self.address_space_info.iter().find(|(a, _)| a == &c) { e.1.pointer_align } else { panic!("Use of unknown address space {c:?}"); - }) + } } } @@ -1574,7 +1574,7 @@ impl Primitive { match self { Int(i, _) => i.align(dl), Float(f) => f.align(dl), - Pointer(a) => dl.pointer_align_in(a), + Pointer(a) => AbiAlign::new(dl.pointer_align_in(a)), } } } diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs index 9a6854399dde6..a83592248a512 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs @@ -133,7 +133,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { ); if mode == IndirectMode::OnStack { // Abi requires aligning struct size to pointer size - let size = self.layout.size.align_to(tcx.data_layout.pointer_align().abi); + let size = self.layout.size.align_to(tcx.data_layout.pointer_align()); let size = u32::try_from(size.bytes()).unwrap(); smallvec![apply_attrs_to_abi_param( AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructArgument(size),), diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 6513cc0542ea5..2089f2b2008be 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -758,7 +758,7 @@ impl<'ll> CodegenCx<'ll, '_> { let g = self.define_global(&sym, llty).unwrap_or_else(|| { bug!("symbol `{}` is already defined", sym); }); - set_global_alignment(self, g, self.tcx.data_layout.pointer_align().abi); + set_global_alignment(self, g, self.tcx.data_layout.pointer_align()); llvm::set_initializer(g, llval); llvm::set_linkage(g, llvm::Linkage::PrivateLinkage); llvm::set_section(g, c"__OBJC,__cls_refs,literal_pointers,no_dead_strip"); @@ -778,7 +778,7 @@ impl<'ll> CodegenCx<'ll, '_> { let g = self.define_global(&sym, llty).unwrap_or_else(|| { bug!("symbol `{}` is already defined", sym); }); - set_global_alignment(self, g, self.tcx.data_layout.pointer_align().abi); + set_global_alignment(self, g, self.tcx.data_layout.pointer_align()); llvm::set_initializer(g, llval); llvm::set_linkage(g, llvm::Linkage::InternalLinkage); llvm::set_section(g, c"__DATA,__objc_classrefs,regular,no_dead_strip"); @@ -841,7 +841,7 @@ impl<'ll> CodegenCx<'ll, '_> { let selref_g = self.define_global(&selref_sym, selref_llty).unwrap_or_else(|| { bug!("symbol `{}` is already defined", selref_sym); }); - set_global_alignment(self, selref_g, self.tcx.data_layout.pointer_align().abi); + set_global_alignment(self, selref_g, self.tcx.data_layout.pointer_align()); llvm::set_initializer(selref_g, selref_llval); llvm::set_externally_initialized(selref_g, true); llvm::set_linkage( @@ -897,7 +897,7 @@ impl<'ll> CodegenCx<'ll, '_> { let g = self.define_global(&sym, llty).unwrap_or_else(|| { bug!("symbol `{}` is already defined", sym); }); - set_global_alignment(self, g, self.tcx.data_layout.pointer_align().abi); + set_global_alignment(self, g, self.tcx.data_layout.pointer_align()); llvm::set_initializer(g, llval); llvm::set_linkage(g, llvm::Linkage::PrivateLinkage); llvm::set_section(g, c"__OBJC,__module_info,regular,no_dead_strip"); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 87e0612bc102d..8c7e21666aa41 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -180,7 +180,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( None => { // This is a thin pointer. Create a regular pointer type and give it the correct name. assert_eq!( - (pointer_size, pointer_align.abi), + (pointer_size, pointer_align), cx.size_and_align_of(ptr_type), "ptr_type={ptr_type}, pointee_type={pointee_type}", ); @@ -189,7 +189,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( cx, pointee_type_di_node, pointer_size, - pointer_align.abi, + pointer_align, &ptr_type_debuginfo_name, ); @@ -326,9 +326,7 @@ fn build_subroutine_type_di_node<'ll, 'tcx>( let name = compute_debuginfo_type_name(cx.tcx, fn_ty, false); let (size, align) = match fn_ty.kind() { ty::FnDef(..) => (Size::ZERO, Align::ONE), - ty::FnPtr(..) => { - (cx.tcx.data_layout.pointer_size(), cx.tcx.data_layout.pointer_align().abi) - } + ty::FnPtr(..) => (cx.tcx.data_layout.pointer_size(), cx.tcx.data_layout.pointer_align()), _ => unreachable!(), }; let di_node = create_pointer_type(cx, fn_di_node, size, align, &name); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 23aef47bceead..5de8d85e1af2c 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1398,7 +1398,7 @@ fn codegen_msvc_try<'ll, 'tcx>( // // More information can be found in libstd's seh.rs implementation. let ptr_size = bx.tcx().data_layout.pointer_size(); - let ptr_align = bx.tcx().data_layout.pointer_align().abi; + let ptr_align = bx.tcx().data_layout.pointer_align(); let slot = bx.alloca(ptr_size, ptr_align); let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void()); bx.invoke( diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index c74ea60ac11f3..74be2c92dcb0e 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -51,7 +51,7 @@ fn emit_direct_ptr_va_arg<'ll, 'tcx>( let va_list_ty = bx.type_ptr(); let va_list_addr = list.immediate(); - let ptr_align_abi = bx.tcx().data_layout.pointer_align().abi; + let ptr_align_abi = bx.tcx().data_layout.pointer_align(); let ptr = bx.load(va_list_ty, va_list_addr, ptr_align_abi); let (addr, addr_align) = if allow_higher_align && align > slot_size { @@ -171,7 +171,7 @@ fn emit_ptr_va_arg<'ll, 'tcx>( ( bx.cx.layout_of(Ty::new_imm_ptr(bx.cx.tcx, layout.ty)).llvm_type(bx.cx), bx.cx.data_layout().pointer_size(), - bx.cx.data_layout().pointer_align().abi, + bx.cx.data_layout().pointer_align(), ) } else { (layout.llvm_type(bx.cx), layout.size, get_param_type_alignment(bx, layout)) @@ -264,7 +264,7 @@ fn emit_aapcs_va_arg<'ll, 'tcx>( bx.switch_to_block(in_reg); let top_type = bx.type_ptr(); - let top = bx.load(top_type, reg_top, dl.pointer_align().abi); + let top = bx.load(top_type, reg_top, dl.pointer_align()); // reg_value = *(@top + reg_off_v); let mut reg_addr = bx.ptradd(top, reg_off_v); @@ -361,7 +361,7 @@ fn emit_powerpc_va_arg<'ll, 'tcx>( let reg_incr = layout.size.bytes().div_ceil(u64::from(reg_size)) as u8; let use_regs = bx.icmp(IntPredicate::IntULE, num_regs, bx.const_u8(max_regs - reg_incr)); - let ptr_align_abi = bx.tcx().data_layout.pointer_align().abi; + let ptr_align_abi = bx.tcx().data_layout.pointer_align(); let in_reg = bx.append_sibling_block("va_arg.in_reg"); let in_mem = bx.append_sibling_block("va_arg.in_mem"); @@ -469,7 +469,7 @@ fn emit_s390x_va_arg<'ll, 'tcx>( let in_reg = bx.append_sibling_block("va_arg.in_reg"); let in_mem = bx.append_sibling_block("va_arg.in_mem"); let end = bx.append_sibling_block("va_arg.end"); - let ptr_align_abi = dl.pointer_align().abi; + let ptr_align_abi = dl.pointer_align(); // FIXME: vector ABI not yet supported. let target_ty_size = layout.size.bytes(); @@ -675,7 +675,7 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>( // loads than necessary. Can we clean this up? let reg_save_area_ptr = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(2 * unsigned_int_offset + ptr_offset)); - let reg_save_area_v = bx.load(bx.type_ptr(), reg_save_area_ptr, dl.pointer_align().abi); + let reg_save_area_v = bx.load(bx.type_ptr(), reg_save_area_ptr, dl.pointer_align()); let reg_addr = match layout.layout.backend_repr() { BackendRepr::Scalar(scalar) => match scalar.primitive() { @@ -814,7 +814,7 @@ fn x86_64_sysv64_va_arg_from_memory<'ll, 'tcx>( layout: TyAndLayout<'tcx>, ) -> &'ll Value { let dl = bx.cx.data_layout(); - let ptr_align_abi = dl.data_layout().pointer_align().abi; + let ptr_align_abi = dl.data_layout().pointer_align(); let overflow_arg_area_ptr = bx.inbounds_ptradd(va_list_addr, bx.const_usize(8)); @@ -864,7 +864,7 @@ fn emit_hexagon_va_arg_musl<'ll, 'tcx>( // All variadic arguments are passed on the stack, but the musl implementation // uses a register save area for compatibility. let va_list_addr = list.immediate(); - let ptr_align_abi = bx.tcx().data_layout.pointer_align().abi; + let ptr_align_abi = bx.tcx().data_layout.pointer_align(); let ptr_size = bx.tcx().data_layout.pointer_size().bytes(); // Check if argument fits in register save area @@ -936,7 +936,7 @@ fn emit_hexagon_va_arg_bare_metal<'ll, 'tcx>( // // va_list is a simple pointer (char *) let va_list_addr = list.immediate(); - let ptr_align_abi = bx.tcx().data_layout.pointer_align().abi; + let ptr_align_abi = bx.tcx().data_layout.pointer_align(); // Load current pointer from va_list let current_ptr = bx.load(bx.type_ptr(), va_list_addr, ptr_align_abi); @@ -989,7 +989,7 @@ fn emit_xtensa_va_arg<'ll, 'tcx>( let from_stack = bx.append_sibling_block("va_arg.from_stack"); let from_regsave = bx.append_sibling_block("va_arg.from_regsave"); let end = bx.append_sibling_block("va_arg.end"); - let ptr_align_abi = bx.tcx().data_layout.pointer_align().abi; + let ptr_align_abi = bx.tcx().data_layout.pointer_align(); // (*va).va_ndx let va_reg_offset = 4; diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index e5d790e15f7a4..ed2c05a20b9d4 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -611,7 +611,7 @@ fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(bx: &mut Bx) -> (Bx::Va let param_handle = bx.get_param(0); let param_system_table = bx.get_param(1); let ptr_size = bx.tcx().data_layout.pointer_size(); - let ptr_align = bx.tcx().data_layout.pointer_align().abi; + let ptr_align = bx.tcx().data_layout.pointer_align(); let arg_argc = bx.const_int(bx.cx().type_isize(), 2); let arg_argv = bx.alloca(2 * ptr_size, ptr_align); bx.store(param_handle, arg_argv, ptr_align); diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index dd0bf6d0a2287..5b945fc3c2763 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -27,7 +27,7 @@ impl<'a, 'tcx> VirtualIndex { let vtable_byte_offset = self.0 * ptr_size.bytes(); let gep = bx.inbounds_ptradd(llvtable, bx.const_usize(vtable_byte_offset)); - let ptr_align = bx.data_layout().pointer_align().abi; + let ptr_align = bx.data_layout().pointer_align(); let ptr = bx.load(llty, gep, ptr_align); // VTable loads are invariant. diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 10aa9532bea0b..c583383414392 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -400,7 +400,7 @@ impl<'tcx> GlobalAlloc<'tcx> { GlobalAlloc::Function { .. } => (Size::ZERO, Align::ONE), GlobalAlloc::VTable(..) => { // No data to be accessed here. But vtables are pointer-aligned. - (Size::ZERO, tcx.data_layout.pointer_align().abi) + (Size::ZERO, tcx.data_layout.pointer_align()) } // Fake allocation, there's nothing to access here. GlobalAlloc::TypeId { .. } => (Size::ZERO, Align::ONE), diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index fb56bda7d4562..f3c4940e60b82 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -108,7 +108,7 @@ pub(super) fn vtable_allocation_provider<'tcx>( let align = layout.align.bytes(); let ptr_size = tcx.data_layout.pointer_size(); - let ptr_align = tcx.data_layout.pointer_align().abi; + let ptr_align = tcx.data_layout.pointer_align(); let vtable_size = ptr_size * u64::try_from(vtable_entries.len()).unwrap(); let mut vtable = Allocation::new(vtable_size, ptr_align, AllocInit::Uninit, ()); diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs index d0d97592f0e4b..7df6549a07a70 100644 --- a/compiler/rustc_session/src/config/cfg.rs +++ b/compiler/rustc_session/src/config/cfg.rs @@ -297,7 +297,7 @@ pub(crate) fn default_configuration(sess: &Session) -> Cfg { }; insert_atomic(sym::integer(i), align); if sess.target.pointer_width as u64 == i { - insert_atomic(sym::ptr, layout.pointer_align().abi); + insert_atomic(sym::ptr, layout.pointer_align()); } } } From df86f6ec8727485ceb80fa31f46f0f9aace92000 Mon Sep 17 00:00:00 2001 From: Bee Date: Sun, 1 Nov 2026 01:16:47 +0000 Subject: [PATCH 22/34] Replace `AbiAlign` with `Align` in `Integer::align` --- compiler/rustc_abi/src/layout.rs | 2 +- compiler/rustc_abi/src/lib.rs | 12 ++++++------ compiler/rustc_codegen_ssa/src/mir/retag.rs | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index f2e3f8431c105..3557ae6f32b3e 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -810,7 +810,7 @@ impl LayoutCalculator { // the alignment of the union. (This value is used both for // determining the alignment of the overall enum, and the // determining the alignment of the payload after the tag.) - let mut prefix_align = min_ity.align(dl).abi; + let mut prefix_align = min_ity.align(dl); if repr.c() { for fields in variants { for field in fields { diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index a06e84b22e013..2ebc83a609fd7 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1312,17 +1312,17 @@ impl Integer { } } - pub fn align(self, cx: &C) -> AbiAlign { + pub fn align(self, cx: &C) -> Align { use Integer::*; let dl = cx.data_layout(); - AbiAlign::new(match self { + match self { I8 => dl.i8_align, I16 => dl.i16_align, I32 => dl.i32_align, I64 => dl.i64_align, I128 => dl.i128_align, - }) + } } /// Returns the largest signed value that can be represented by this Integer. @@ -1383,7 +1383,7 @@ impl Integer { let dl = cx.data_layout(); [I8, I16, I32, I64, I128].into_iter().find(|&candidate| { - wanted == candidate.align(dl).abi && wanted.bytes() == candidate.size().bytes() + wanted == candidate.align(dl) && wanted.bytes() == candidate.size().bytes() }) } @@ -1394,7 +1394,7 @@ impl Integer { // FIXME(eddyb) maybe include I128 in the future, when it works everywhere. for candidate in [I64, I32, I16] { - if wanted >= candidate.align(dl).abi && wanted.bytes() >= candidate.size().bytes() { + if wanted >= candidate.align(dl) && wanted.bytes() >= candidate.size().bytes() { return candidate; } } @@ -1572,7 +1572,7 @@ impl Primitive { let dl = cx.data_layout(); match self { - Int(i, _) => i.align(dl), + Int(i, _) => AbiAlign::new(i.align(dl)), Float(f) => f.align(dl), Pointer(a) => AbiAlign::new(dl.pointer_align_in(a)), } diff --git a/compiler/rustc_codegen_ssa/src/mir/retag.rs b/compiler/rustc_codegen_ssa/src/mir/retag.rs index 483df05e4d14f..bce15781e89dd 100644 --- a/compiler/rustc_codegen_ssa/src/mir/retag.rs +++ b/compiler/rustc_codegen_ssa/src/mir/retag.rs @@ -283,7 +283,7 @@ impl<'a, 'tcx, V> RetagPlan { } let intptr_ty = data_layout.ptr_sized_integer(); - let align = intptr_ty.align(data_layout).abi; + let align = intptr_ty.align(data_layout); let alloc = Allocation::from_bytes(&bytes, align, Mutability::Not, ()); let const_alloc = tcx.mk_const_alloc(alloc); From 0eff598e9479acff381c0b6717c5e0fdd0033af2 Mon Sep 17 00:00:00 2001 From: Bee Date: Sun, 1 Nov 2026 01:22:05 +0000 Subject: [PATCH 23/34] Replace `AbiAlign` with `Align` in `Float::align` --- compiler/rustc_abi/src/lib.rs | 8 ++++---- compiler/rustc_target/src/callconv/sparc64.rs | 2 +- compiler/rustc_ty_utils/src/layout.rs | 11 +++++------ 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 2ebc83a609fd7..4ef9aeddfcbd0 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1448,17 +1448,17 @@ impl Float { } } - pub fn align(self, cx: &C) -> AbiAlign { + pub fn align(self, cx: &C) -> Align { use Float::*; let dl = cx.data_layout(); - AbiAlign::new(match self { + match self { F16 | F16B => dl.f16_align, F32 => dl.f32_align, F64 => dl.f64_align, F128 => dl.f128_align, PpcF128 => dl.f128_align, - }) + } } pub fn ty_str(self) -> &'static str { @@ -1573,7 +1573,7 @@ impl Primitive { match self { Int(i, _) => AbiAlign::new(i.align(dl)), - Float(f) => f.align(dl), + Float(f) => AbiAlign::new(f.align(dl)), Pointer(a) => AbiAlign::new(dl.pointer_align_in(a)), } } diff --git a/compiler/rustc_target/src/callconv/sparc64.rs b/compiler/rustc_target/src/callconv/sparc64.rs index bfe7f0cca3cc7..61a0ae982d050 100644 --- a/compiler/rustc_target/src/callconv/sparc64.rs +++ b/compiler/rustc_target/src/callconv/sparc64.rs @@ -39,7 +39,7 @@ fn classify<'a, Ty, C>( match arg_layout.backend_repr { BackendRepr::Scalar(scalar) => match scalar.primitive() { Primitive::Float(float) => { - if offset.is_aligned(Ord::min(*float.align(cx), Align::EIGHT)) { + if offset.is_aligned(Ord::min(float.align(cx), Align::EIGHT)) { let index = offset.bytes_usize() / 8; match float { Float::F128 => { diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 5d680b26c0221..7e202d8614034 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -1,12 +1,11 @@ use std::range::{RangeFrom, RangeToInclusive}; -use rustc_abi as abi; use rustc_abi::Integer::{I8, I32}; use rustc_abi::Primitive::{self, Float, Int, Pointer}; use rustc_abi::{ - AddressSpace, BackendRepr, FIRST_VARIANT, FieldIdx, FieldsShape, HasDataLayout, Layout, - LayoutCalculatorError, LayoutData, Niche, NicheOptimizations, ReprOptions, Scalar, Size, - StructKind, TagEncoding, VariantIdx, Variants, WrappingRange, + self as abi, AbiAlign, AddressSpace, BackendRepr, FIRST_VARIANT, FieldIdx, FieldsShape, + HasDataLayout, Layout, LayoutCalculatorError, LayoutData, Niche, NicheOptimizations, + ReprOptions, Scalar, Size, StructKind, TagEncoding, VariantIdx, Variants, WrappingRange, }; use rustc_attr_ir::find_attr; use rustc_attr_ir::lang_items::LangItem; @@ -820,14 +819,14 @@ fn layout_of_uncached<'tcx>( if tcx.is_lang_item(def.did(), LangItem::F16B) { let bfloat = scalar_unit(Primitive::Float(abi::Float::F16B)); assert_eq!(layout.size, abi::Float::F16B.size()); - layout.align = abi::Float::F16B.align(cx); + layout.align = AbiAlign::new(abi::Float::F16B.align(cx)); layout.backend_repr = BackendRepr::Scalar(bfloat); } if tcx.is_lang_item(def.did(), LangItem::PpcF128) { let ppcf128 = scalar_unit(Primitive::Float(abi::Float::PpcF128)); assert_eq!(layout.size, abi::Float::PpcF128.size()); - layout.align = abi::Float::PpcF128.align(cx); + layout.align = AbiAlign::new(abi::Float::PpcF128.align(cx)); layout.backend_repr = BackendRepr::Scalar(ppcf128); } From c30cee08c6d77538e544a949dfdf8f418a0d262a Mon Sep 17 00:00:00 2001 From: Bee Date: Sun, 1 Nov 2026 01:31:31 +0000 Subject: [PATCH 24/34] Replace `AbiAlign` with `Align` in `{Primitive,Scalar}::default_align` --- compiler/rustc_abi/src/layout.rs | 2 +- compiler/rustc_abi/src/layout/simple.rs | 8 ++++---- compiler/rustc_abi/src/lib.rs | 14 +++++++------- compiler/rustc_ty_utils/src/layout/invariant.rs | 6 +++--- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 3557ae6f32b3e..c272d2685cfa8 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -485,7 +485,7 @@ impl LayoutCalculator { } // Vectors require at least element alignment, else disable the opt BackendRepr::SimdVector { element, count: _ } - if element.default_align(dl).abi > align => + if element.default_align(dl) > align => { BackendRepr::Memory { sized: true } } diff --git a/compiler/rustc_abi/src/layout/simple.rs b/compiler/rustc_abi/src/layout/simple.rs index da7260fe6160e..a4636ea1b116f 100644 --- a/compiler/rustc_abi/src/layout/simple.rs +++ b/compiler/rustc_abi/src/layout/simple.rs @@ -83,9 +83,9 @@ impl LayoutData { largest_niche, uninhabited: false, size, - align, + align: AbiAlign::new(align), max_repr_align: None, - unadjusted_abi_align: align.abi, + unadjusted_abi_align: align, repr_c: false, randomization_seed: Hash64::new(randomization_seed), } @@ -93,8 +93,8 @@ impl LayoutData { pub fn scalar_pair(cx: &C, a: Scalar, b: Scalar) -> Self { let dl = cx.data_layout(); - let b_align = b.default_align(dl).abi; - let align = a.default_align(dl).abi.max(b_align).max(dl.aggregate_align); + let b_align = b.default_align(dl); + let align = a.default_align(dl).max(b_align).max(dl.aggregate_align); let b_offset = a.size(dl).align_to(b_align); let size = (b_offset + b.size(dl)).align_to(align); diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 4ef9aeddfcbd0..38c82a4f55a1b 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1567,14 +1567,14 @@ impl Primitive { /// /// This is the type alignment for the corresponding built-in. /// In other contexts it might have different alignment. - pub fn default_align(self, cx: &C) -> AbiAlign { + pub fn default_align(self, cx: &C) -> Align { use Primitive::*; let dl = cx.data_layout(); match self { - Int(i, _) => AbiAlign::new(i.align(dl)), - Float(f) => AbiAlign::new(f.align(dl)), - Pointer(a) => AbiAlign::new(dl.pointer_align_in(a)), + Int(i, _) => i.align(dl), + Float(f) => f.align(dl), + Pointer(a) => dl.pointer_align_in(a), } } } @@ -1644,7 +1644,7 @@ impl Scalar { /// /// This is the type alignment for the corresponding built-in. /// This is *not* necessarily the correct alignment for a type that has this `BackendRepr::Scalar`! - pub fn default_align(self, cx: &impl HasDataLayout) -> AbiAlign { + pub fn default_align(self, cx: &impl HasDataLayout) -> Align { self.primitive().default_align(cx) } @@ -1957,9 +1957,9 @@ impl BackendRepr { /// not calculating something from the `Scalar`s. pub fn scalar_platform_align(&self, cx: &C) -> Option { match *self { - BackendRepr::Scalar(s) => Some(s.default_align(cx).abi), + BackendRepr::Scalar(s) => Some(s.default_align(cx)), BackendRepr::ScalarPair { a: s1, b: s2, b_offset: _ } => { - Some(s1.default_align(cx).max(s2.default_align(cx)).abi) + Some(s1.default_align(cx).max(s2.default_align(cx))) } // The align of a Vector can vary in surprising ways BackendRepr::SimdVector { .. } diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs index a244c597eef3d..0249167fbc7a7 100644 --- a/compiler/rustc_ty_utils/src/layout/invariant.rs +++ b/compiler/rustc_ty_utils/src/layout/invariant.rs @@ -225,9 +225,9 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou }; // The fields should be at the right offset, and match the `scalar` layout. let size1 = scalar1.size(cx); - let align1 = scalar1.default_align(cx).abi; + let align1 = scalar1.default_align(cx); let size2 = scalar2.size(cx); - let align2 = scalar2.default_align(cx).abi; + let align2 = scalar2.default_align(cx); assert_eq!( offset1, Size::ZERO, @@ -272,7 +272,7 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou BackendRepr::SimdVector { element, count } => { let align = layout.align.abi; let size = layout.size; - let element_align = element.default_align(cx).abi; + let element_align = element.default_align(cx); let element_size = element.size(cx); // Currently, vectors must always be aligned to at least their elements: assert!(align >= element_align); From 6d0b049d09c2d9b51267bd8dac0e3d6b88709da6 Mon Sep 17 00:00:00 2001 From: Bee Date: Sun, 1 Nov 2026 01:37:45 +0000 Subject: [PATCH 25/34] Replace `AbiAlign` with `Align` in `Layout::align` --- compiler/rustc_abi/src/layout/ty.rs | 8 ++++---- compiler/rustc_codegen_llvm/src/intrinsic.rs | 4 ++-- compiler/rustc_codegen_llvm/src/va_arg.rs | 6 +++--- compiler/rustc_ty_utils/src/layout/invariant.rs | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs index 58d20b9bd3532..821fa54e29fa7 100644 --- a/compiler/rustc_abi/src/layout/ty.rs +++ b/compiler/rustc_abi/src/layout/ty.rs @@ -7,8 +7,8 @@ use rustc_macros::StableHash; use crate::layout::{FieldIdx, VariantIdx}; use crate::{ - AbiAlign, Align, BackendRepr, FieldsShape, Float, HasDataLayout, LayoutData, Niche, Numeric, - PointeeInfo, Primitive, Size, Variants, + Align, BackendRepr, FieldsShape, Float, HasDataLayout, LayoutData, Niche, Numeric, PointeeInfo, + Primitive, Size, Variants, }; // Explicitly import `Float` to avoid ambiguity with `Primitive::Float`. @@ -48,8 +48,8 @@ impl<'a> Layout<'a> { self.0.0.largest_niche } - pub fn align(self) -> AbiAlign { - self.0.0.align + pub fn align(self) -> Align { + self.0.0.align.abi } pub fn size(self) -> Size { diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 5de8d85e1af2c..891a48c6701e3 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -596,8 +596,8 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { self.const_bool(true) } else if use_integer_compare { let integer_ty = self.type_ix(layout.size().bits()); - let a_val = self.load(integer_ty, a, layout.align().abi); - let b_val = self.load(integer_ty, b, layout.align().abi); + let a_val = self.load(integer_ty, a, layout.align()); + let b_val = self.load(integer_ty, b, layout.align()); self.icmp(IntPredicate::IntEQ, a_val, b_val) } else { let n = self.const_usize(layout.size().bytes()); diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index 74be2c92dcb0e..1590a33850c16 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -692,8 +692,8 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>( let ty_lo = bx.cx().scalar_pair_element_backend_type(layout, 0, false); let ty_hi = bx.cx().scalar_pair_element_backend_type(layout, 1, false); - let align_lo = layout.field(bx.cx, 0).layout.align().abi; - let align_hi = layout.field(bx.cx, 1).layout.align().abi; + let align_lo = layout.field(bx.cx, 0).layout.align(); + let align_hi = layout.field(bx.cx, 1).layout.align(); match (scalar1.primitive(), scalar2.primitive()) { (Primitive::Float(_), Primitive::Float(_)) => { @@ -706,7 +706,7 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>( let reg_lo_addr = bx.inbounds_ptradd(reg_save_area_v, fp_offset_v); let reg_hi_addr = bx.inbounds_ptradd(reg_lo_addr, bx.const_i32(16)); - let align = layout.layout.align().abi; + let align = layout.layout.align(); let tmp = bx.alloca(layout.size, layout.align.abi); let reg_lo = bx.load(ty_lo, reg_lo_addr, align_lo); diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs index 0249167fbc7a7..29e1407e0211f 100644 --- a/compiler/rustc_ty_utils/src/layout/invariant.rs +++ b/compiler/rustc_ty_utils/src/layout/invariant.rs @@ -99,7 +99,7 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou let size = layout.backend_repr.scalar_size(cx); if let Some(align) = align { assert_eq!( - layout.layout.align().abi, + layout.layout.align(), align, "alignment mismatch between ABI and layout in {layout:#?}" ); From 8851c93e843d11e73776a581b6ec2e15e21967ee Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Thu, 6 Mar 2025 17:30:55 -0800 Subject: [PATCH 26/34] Add unstable rustdoc option `--crate-list-heading`. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When used, this option creates a subheading within the sidebar “Crates” list for this crate and all crates which pass the same value. These headings are displayed in alphabetical order; crates without the option, or with it set to the empty string, always appear first. The intended use of this option is to allow Cargo to automatically separate a workspace’s crate list into the workspace’s own crates and their external dependencies. Authors could also use RUSTDOCFLAGS or other means to create custom headings for their documentation builds. --- src/librustdoc/config.rs | 6 ++ src/librustdoc/html/render/write_shared.rs | 30 +++++++-- .../html/render/write_shared/tests.rs | 3 +- src/librustdoc/html/static/js/main.js | 66 ++++++++++++++----- src/librustdoc/html/static/js/rustdoc.d.ts | 14 +++- src/librustdoc/lib.rs | 8 +++ .../default-output/output-default.stdout | 3 + tests/rustdoc-gui/sidebar.goml | 4 +- tests/rustdoc-html/crate-list-heading.rs | 5 ++ 9 files changed, 116 insertions(+), 23 deletions(-) create mode 100644 tests/rustdoc-html/crate-list-heading.rs diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 597c648c1106a..9acf150b3b354 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -241,6 +241,10 @@ pub(crate) struct RenderOptions { /// What sorting mode to use for module pages. /// `ModuleSorting::Alphabetical` by default. pub(crate) module_sorting: ModuleSorting, + /// In the sidebar list of all crates, put the current crate(s) under this heading. + /// To put a crate under the unnamed primary heading, which is always listed first, + /// make this the empty string. + pub(crate) crate_list_heading: String, /// List of themes to extend the docs with. Original argument name is included to assist in /// displaying errors if it fails a theme check. pub(crate) themes: Vec, @@ -845,6 +849,7 @@ impl Options { } else { ModuleSorting::Alphabetical }; + let crate_list_heading = matches.opt_str("crate-list-heading").unwrap_or_default(); let resource_suffix = matches.opt_str("resource-suffix").unwrap_or_default(); let markdown_no_toc = matches.opt_present("markdown-no-toc"); let markdown_css = matches.opt_strs("markdown-css"); @@ -954,6 +959,7 @@ impl Options { id_map, playground_url, module_sorting, + crate_list_heading, themes, extension_css, extern_html_root_urls, diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 258970bbb3b8f..ae040553f5ffa 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -13,6 +13,7 @@ //! --resource-suffix flag and are emitted when --emit-type is empty (default) //! or contains "html-non-static-files". +use std::borrow::Cow; use std::cell::RefCell; use std::ffi::{OsStr, OsString}; use std::fs::File; @@ -80,14 +81,20 @@ pub(crate) fn write_shared( )?; let crate_name = krate.name(cx.tcx()); - let crate_name = crate_name.as_str(); // rand + let crate_name = crate_name.as_str(); // e.g. rand let crate_name_json = OrderedJson::serialize(crate_name).unwrap(); // "rand" + let all_crates_entry_json = OrderedJson::serialize(AllCratesEntry { + heading: Cow::Borrowed(&opt.crate_list_heading), + crate_name: Cow::Borrowed(crate_name), + }) + .unwrap(); // e.g. {"c":"rand","h":"Some User-Specified Heading"} + let external_crates = hack_get_external_crate_names(&cx.dst, &cx.shared.resource_suffix)?; let info = CrateInfo { version: CrateInfoVersion::V2, src_files_js: SourcesPart::get(cx, &crate_name_json)?, search_index, - all_crates: AllCratesPart::get(crate_name_json.clone(), &cx.shared.resource_suffix)?, + all_crates: AllCratesPart::get(all_crates_entry_json, &cx.shared.resource_suffix)?, crates_index: CratesIndexPart::get(crate_name, &external_crates)?, trait_impl: TraitAliasPart::get(cx, &crate_name_json)?, type_impl: TypeAliasPart::get(cx, krate, &crate_name_json)?, @@ -489,6 +496,19 @@ impl AllCratesPart { } } +/// Type of a serialized entry in the [`AllCratesPart`] JSON. +#[derive(Serialize, Deserialize, Clone, Default, Debug)] +struct AllCratesEntry<'a> { + #[serde(rename = "c")] + crate_name: Cow<'a, str>, + + /// If non-absent and non-empty, is the name of a section heading in the crate sidebar. + #[serde(rename = "h")] + #[serde(default)] + #[serde(skip_serializing_if = "str::is_empty")] + heading: Cow<'a, str>, +} + /// Reads `crates.js`, which seems like the best /// place to obtain the list of externally documented crates if the index /// page was disabled when documenting the deps. @@ -509,9 +529,11 @@ fn hack_get_external_crate_names( if let Some(start) = content.find('[') && let Some(end) = content[start..].find(']') { - let content: Vec = + let content: Vec> = try_err!(serde_json::from_str(&content[start..=start + end]), &path); - Ok(content) + let crate_names: Vec = + content.into_iter().map(|entry| entry.crate_name.into_owned()).collect(); + Ok(crate_names) } else { Err(Error::new("could not find crates list in crates.js", path)) } diff --git a/src/librustdoc/html/render/write_shared/tests.rs b/src/librustdoc/html/render/write_shared/tests.rs index 48d592c22f6f0..3ac9e3a2a5a80 100644 --- a/src/librustdoc/html/render/write_shared/tests.rs +++ b/src/librustdoc/html/render/write_shared/tests.rs @@ -9,7 +9,8 @@ fn hack_external_crate_names() { let path = path.path(); let crates = hack_get_external_crate_names(&path, "").unwrap(); assert!(crates.is_empty()); - fs::write(path.join("crates.js"), r#"window.ALL_CRATES = ["a","b","c"];"#).unwrap(); + fs::write(path.join("crates.js"), r#"window.ALL_CRATES = [{"c":"a"},{"c":"b"},{"c":"c"}];"#) + .unwrap(); let crates = hack_get_external_crate_names(&path, "").unwrap(); assert_eq!(crates, ["a".to_string(), "b".to_string(), "c".to_string()]); } diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 24aa8e8966ae6..11bf38b1e4084 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1123,6 +1123,7 @@ function preLoadCss(cssUrl) { window.register_type_impls(window.pending_type_impls); } + // Draw a convenient sidebar of known crates if we have a listing function addSidebarCrates() { if (!window.ALL_CRATES) { return; @@ -1131,26 +1132,59 @@ function preLoadCss(cssUrl) { if (!sidebarElems) { return; } - // Draw a convenient sidebar of known crates if we have a listing - const h3 = document.createElement("h3"); - h3.innerHTML = "Crates"; - const ul = document.createElement("ul"); - ul.className = "block crate"; - for (const crate of window.ALL_CRATES) { - const link = document.createElement("a"); - link.href = window.rootPath + crate + "/index.html"; - link.textContent = crate; + // h2 puts this on the same level as the current crate name heading at the top + const allCratesHeading = document.createElement("h2"); + allCratesHeading.textContent = "Crates"; - const li = document.createElement("li"); - if (window.rootPath !== "./" && crate === window.currentCrate) { - li.className = "current"; + const allCratesSection = document.createElement("section"); + + // window.ALL_CRATES is in unsorted array-of-structs format; reorganize so crates with the + // same heading are grouped. + const cratesGroupedByHeading = new Map(); + for (const entry of window.ALL_CRATES) { + const heading = entry.h || ""; + const crateName = entry.c; + let group = cratesGroupedByHeading.get(heading); + if (group === undefined) { + group = []; + cratesGroupedByHeading.set(heading, group); + } + group.push(crateName); + } + const headings = Array.from(cratesGroupedByHeading.keys()); + headings.sort(); + + // Generate HTML for grouped crates. + for (const headingText of headings) { + // Empty string denotes a group with no named heading. + if (headingText !== "") { + const crateCategoryHeading = document.createElement("h3"); + crateCategoryHeading.textContent = headingText; + allCratesSection.appendChild(crateCategoryHeading); + } + + const cratesUl = document.createElement("ul"); + cratesUl.className = "block crate"; + + for (const crateName of cratesGroupedByHeading.get(headingText)) { + const link = document.createElement("a"); + link.href = window.rootPath + crateName + "/index.html"; + link.textContent = crateName; + + const li = document.createElement("li"); + if (window.rootPath !== "./" && crateName === window.currentCrate) { + li.className = "current"; + } + li.appendChild(link); + cratesUl.appendChild(li); } - li.appendChild(link); - ul.appendChild(li); + + allCratesSection.appendChild(cratesUl); } - sidebarElems.appendChild(h3); - sidebarElems.appendChild(ul); + + sidebarElems.appendChild(allCratesHeading); + sidebarElems.appendChild(allCratesSection); } function expandAllDocs() { diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts index ba4b5ce87eeac..49580c7870a97 100644 --- a/src/librustdoc/html/static/js/rustdoc.d.ts +++ b/src/librustdoc/html/static/js/rustdoc.d.ts @@ -32,7 +32,7 @@ declare global { NOTABLE_TRAITS?: { [key: string]: string }; CURRENT_TOOLTIP_ELEMENT?: HTMLElement & { TOOLTIP_BASE: HTMLElement }; /** List of all documented crates. Generated in `render/write_shared.rs`. */ - ALL_CRATES: string[]|undefined; + ALL_CRATES: rustdoc.AllCratesEntry[]|undefined; /** Used by the popover tooltip code. */ RUSTDOC_TOOLTIP_HOVER_MS: number; /** Used by the popover tooltip code. */ @@ -540,6 +540,18 @@ declare namespace rustdoc { bindings: Map; }; + /** Member of ALL_CRATES. */ + interface AllCratesEntry { + /** + * Heading under which the crate should be listed. + * + * May be empty to specify the first, primary heading. + */ + h?: string, + /** Crate name. */ + c: string, + } + type VlqData = VlqData[] | number; /** diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index f461bace093a1..3674e6e2a9cf2 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -365,6 +365,14 @@ fn opts() -> Vec { "sort modules by where they appear in the program, rather than alphabetically", "", ), + opt( + Unstable, + Opt, + "", + "crate-list-heading", + "heading under which to list this crate in the sidebar crate list", + "TEXT", + ), opt( Stable, Opt, diff --git a/tests/run-make/rustdoc/default-output/output-default.stdout b/tests/run-make/rustdoc/default-output/output-default.stdout index 3093a01ec79f7..346140b2d921c 100644 --- a/tests/run-make/rustdoc/default-output/output-default.stdout +++ b/tests/run-make/rustdoc/default-output/output-default.stdout @@ -82,6 +82,9 @@ Options: --sort-modules-by-appearance sort modules by where they appear in the program, rather than alphabetically + --crate-list-heading TEXT + heading under which to list this crate in the sidebar + crate list --default-theme THEME Set the default theme. THEME should be the theme name, generally lowercase. If an unknown default theme is diff --git a/tests/rustdoc-gui/sidebar.goml b/tests/rustdoc-gui/sidebar.goml index 0d371c8c6a46f..7d1067b8a25f3 100644 --- a/tests/rustdoc-gui/sidebar.goml +++ b/tests/rustdoc-gui/sidebar.goml @@ -50,7 +50,9 @@ call-function: ("switch-theme", {"theme": "light"}) assert-text: (".sidebar > .sidebar-crate > h2 > a", "test_docs") // Crate root has no "location" element assert-count: (".sidebar .location", 0) -assert-count: (".sidebar h2", 1) +// Crate root has two h2s, the second of which is the the crate list +assert-count: (".sidebar h2", 2) +assert-text: (".sidebar #rustdoc-modnav h2", "Crates") assert-text: ("#all-types", "All Items") assert-css: ("#all-types", {"color": "#356da4"}) // We check that we have the crates list and that the "current" on is "test_docs". diff --git a/tests/rustdoc-html/crate-list-heading.rs b/tests/rustdoc-html/crate-list-heading.rs new file mode 100644 index 0000000000000..8b7e372c42dce --- /dev/null +++ b/tests/rustdoc-html/crate-list-heading.rs @@ -0,0 +1,5 @@ +//@ compile-flags: -Zunstable-options --crate-list-heading=helloworld +#![crate_name = "foo"] + +//@ hasraw crates.js '"h":"helloworld"' +//@ hasraw crates.js '"c":"foo"' From 9ec792396efd6ef6219aee4e8d875f68c96724c1 Mon Sep 17 00:00:00 2001 From: tiif Date: Sun, 1 Nov 2026 11:58:30 +0800 Subject: [PATCH 27/34] Fix typo in test description --- tests/ui/compare-method/default-type-parameter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/compare-method/default-type-parameter.rs b/tests/ui/compare-method/default-type-parameter.rs index bdf65d1479239..7b72c4eff03d5 100644 --- a/tests/ui/compare-method/default-type-parameter.rs +++ b/tests/ui/compare-method/default-type-parameter.rs @@ -1,5 +1,5 @@ // Regression test for https://github.com/rust-lang/rust/issues/67991 -// The weird indentation is to excercise the span context that shows the enclosing items in the +// The weird indentation is to exercise the span context that shows the enclosing items in the // diagnostics being emitted. trait Trait< T = (), From 79ecc0d242186d3d9b5169df2156b445a852faa5 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Sun, 1 Nov 2026 01:20:46 -0400 Subject: [PATCH 28/34] Bless mir-opt tests again, again --- ...op.runtime-optimized.after.panic-abort.mir | 115 ++++++++---------- 1 file changed, 53 insertions(+), 62 deletions(-) diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.runtime-optimized.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.runtime-optimized.after.panic-abort.mir index 40384e1ee7472..6696c91a0e67a 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.runtime-optimized.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.runtime-optimized.after.panic-abort.mir @@ -5,41 +5,38 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { debug f => _2; let mut _0: (); let mut _12: usize; - let mut _32: std::option::Option<(usize, &T)>; - let mut _35: &impl Fn(usize, &T); - let mut _36: (usize, &T); - let _37: (); + let mut _29: std::option::Option<(usize, &T)>; + let mut _32: &impl Fn(usize, &T); + let mut _33: (usize, &T); + let _34: (); scope 1 { debug (((iter: Enumerate>).0: std::slice::Iter<'_, T>).0: std::ptr::NonNull) => _8; debug (((iter: Enumerate>).0: std::slice::Iter<'_, T>).1: *const T) => _11; debug (((iter: Enumerate>).0: std::slice::Iter<'_, T>).2: std::marker::PhantomData<&T>) => const ZeroSized: PhantomData<&T>; debug ((iter: Enumerate>).1: usize) => _12; - let _33: usize; - let _34: &T; + let _30: usize; + let _31: &T; scope 2 { - debug i => _33; - debug x => _34; + debug i => _30; + debug x => _31; } scope 18 (inlined > as Iterator>::next) { - let mut _22: std::option::Option; - let mut _27: std::option::Option<&T>; - let mut _30: (usize, bool); - let mut _31: (usize, &T); + let mut _24: std::option::Option<&T>; + let mut _27: (usize, bool); + let mut _28: (usize, &T); scope 19 { - let _29: usize; + let _26: usize; scope 22 { } } scope 20 { scope 25 (inlined as FromResidual>>::from_residual) { - let mut _21: isize; - let mut _23: bool; } } scope 21 { } scope 23 (inlined as Try>::branch) { - let _28: &T; + let _25: &T; scope 24 { } } @@ -48,8 +45,8 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { let _13: std::ptr::NonNull; let _15: std::ptr::NonNull; let mut _18: bool; - let mut _24: usize; - let _26: &T; + let mut _21: usize; + let _23: &T; scope 27 { let _14: *const T; scope 28 { @@ -82,7 +79,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } } scope 41 (inlined NonNull::::as_ref::<'_>) { - let _25: *const T; + let _22: *const T; scope 42 (inlined NonNull::::as_ptr) { } scope 43 (inlined std::ptr::mut_ptr::::cast_const) { @@ -175,10 +172,10 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb4: { - StorageLive(_32); - StorageLive(_30); + StorageLive(_29); StorageLive(_27); StorageLive(_24); + StorageLive(_21); StorageLive(_16); StorageLive(_13); _13 = copy _8; @@ -230,17 +227,11 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { StorageDead(_14); StorageDead(_13); StorageDead(_16); + StorageDead(_21); StorageDead(_24); StorageDead(_27); - StorageLive(_21); - StorageLive(_23); - _21 = discriminant(_22); - _23 = Eq(copy _21, const 0_isize); - assume(move _23); - StorageDead(_23); - StorageDead(_21); - StorageDead(_30); - StorageDead(_32); + _0 = const (); + StorageDead(_29); StorageDead(_12); drop(_2) -> [return: bb11, unwind unreachable]; } @@ -250,57 +241,57 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb12: { - _24 = SubUnchecked(copy _20, const 1_usize); - _11 = copy _24 as *const T (Transmute); + _21 = SubUnchecked(copy _20, const 1_usize); + _11 = copy _21 as *const T (Transmute); StorageDead(_20); goto -> bb13; } bb13: { - StorageLive(_26); - StorageLive(_25); - _25 = copy _13 as *const T (Transmute); - _26 = &(*_25); - StorageDead(_25); - _27 = Option::<&T>::Some(copy _26); - StorageDead(_26); + StorageLive(_23); + StorageLive(_22); + _22 = copy _13 as *const T (Transmute); + _23 = &(*_22); + StorageDead(_22); + _24 = Option::<&T>::Some(copy _23); + StorageDead(_23); StorageDead(_14); StorageDead(_13); StorageDead(_16); + StorageDead(_21); + _25 = copy ((_24 as Some).0: &T); StorageDead(_24); - _28 = copy ((_27 as Some).0: &T); - StorageDead(_27); - StorageLive(_29); - _29 = copy _12; - _30 = AddWithOverflow(copy _12, const 1_usize); - assert(!move (_30.1: bool), "attempt to compute `{} + {}`, which would overflow", copy _12, const 1_usize) -> [success: bb14, unwind unreachable]; + StorageLive(_26); + _26 = copy _12; + _27 = AddWithOverflow(copy _12, const 1_usize); + assert(!move (_27.1: bool), "attempt to compute `{} + {}`, which would overflow", copy _12, const 1_usize) -> [success: bb14, unwind unreachable]; } bb14: { - _12 = move (_30.0: usize); + _12 = move (_27.0: usize); + StorageLive(_28); + _28 = (copy _26, copy _25); + _29 = Option::<(usize, &T)>::Some(move _28); + StorageDead(_28); + StorageDead(_26); + StorageDead(_27); + StorageLive(_30); + _30 = copy (((_29 as Some).0: (usize, &T)).0: usize); StorageLive(_31); - _31 = (copy _29, copy _28); - _32 = Option::<(usize, &T)>::Some(move _31); - StorageDead(_31); - StorageDead(_29); - StorageDead(_30); + _31 = copy (((_29 as Some).0: (usize, &T)).1: &T); + StorageLive(_32); + _32 = &_2; StorageLive(_33); - _33 = copy (((_32 as Some).0: (usize, &T)).0: usize); - StorageLive(_34); - _34 = copy (((_32 as Some).0: (usize, &T)).1: &T); - StorageLive(_35); - _35 = &_2; - StorageLive(_36); - _36 = (copy _33, copy _34); - _37 = >::call(move _35, move _36) -> [return: bb15, unwind unreachable]; + _33 = (copy _30, copy _31); + _34 = >::call(move _32, move _33) -> [return: bb15, unwind unreachable]; } bb15: { - StorageDead(_36); - StorageDead(_35); - StorageDead(_34); StorageDead(_33); StorageDead(_32); + StorageDead(_31); + StorageDead(_30); + StorageDead(_29); goto -> bb4; } } From 220acce8b23e486cd49b2cd639b071a4b17fd501 Mon Sep 17 00:00:00 2001 From: Max Dexheimer Date: Sun, 1 Nov 2026 07:45:56 +0100 Subject: [PATCH 29/34] Revert "use adt_async_drop_tys for nested ADTs in needs_async_drop" --- compiler/rustc_ty_utils/src/needs_drop.rs | 24 +- tests/crashes/142155.rs | 12 + ...utine.main-{closure#0}.StateTransform.diff | 113 +++++----- ...utine.main-{closure#1}.StateTransform.diff | 113 +++++----- ...d_in_vec.build-{closure#0}.built.after.mir | 213 ++++++++++++------ ...ncelled-future-drops-sync-fields-164901.rs | 56 ----- ...op_order-on-async-block-with-drop-field.rs | 15 -- 7 files changed, 283 insertions(+), 263 deletions(-) create mode 100644 tests/crashes/142155.rs delete mode 100644 tests/ui/async-await/async-drop/cancelled-future-drops-sync-fields-164901.rs delete mode 100644 tests/ui/drop/tail_expr_drop_order-on-async-block-with-drop-field.rs diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 05514b2c712f9..522444651778d 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -52,7 +52,7 @@ fn needs_async_drop_raw<'tcx>( query.value, query.typing_env, adt_has_async_dtor, - DropTysOptions::default().async_drop(), + DropTysOptions::default().recurse_into_box_for_async_drop(), ) .filter(filter_array_elements_async(tcx, query.typing_env)) .next() @@ -335,9 +335,7 @@ enum DtorType { struct DropTysOptions { only_significant: bool, exhaustive: bool, - /// Compute async drop components: query `adt_async_drop_tys` for nested - /// ADTs and recurse into `Box`. - async_drop: bool, + async_drop_recurses_into_box: bool, } impl DropTysOptions { @@ -351,8 +349,8 @@ impl DropTysOptions { self } - fn async_drop(mut self) -> Self { - self.async_drop = true; + fn recurse_into_box_for_async_drop(mut self) -> Self { + self.async_drop_recurses_into_box = true; self } } @@ -371,17 +369,11 @@ fn drop_tys_helper<'tcx>( fn with_query_cache<'tcx>( tcx: TyCtxt<'tcx>, iter: impl IntoIterator>, - async_drop: bool, ) -> NeedsDropResult>> { iter.into_iter().try_fold(Vec::new(), |mut vec, subty| { match subty.kind() { ty::Adt(adt_id, args) => { - let adt_tys = if async_drop { - tcx.adt_async_drop_tys(adt_id.did())? - } else { - tcx.adt_drop_tys(adt_id.did())? - }; - for subty in adt_tys { + for subty in tcx.adt_drop_tys(adt_id.did())? { vec.push( EarlyBinder::bind(tcx, subty).instantiate(tcx, args).skip_norm_wip(), ); @@ -397,7 +389,7 @@ fn drop_tys_helper<'tcx>( if adt_def.is_manually_drop() { debug!("drop_tys_helper: `{:?}` is manually drop", adt_def); Ok(Vec::new()) - } else if options.async_drop && adt_def.is_box() { + } else if options.async_drop_recurses_into_box && adt_def.is_box() { let box_components = match args.as_slice() { [boxed_ty, allocator_ty] => { let boxed_ty = boxed_ty.expect_ty(); @@ -450,7 +442,7 @@ fn drop_tys_helper<'tcx>( // ADTs are `needs_drop` exactly if they `impl Drop` or if any of their "transitive" // fields do. There can be no cycles here, because ADTs cannot contain themselves as // fields. - with_query_cache(tcx, field_tys, options.async_drop) + with_query_cache(tcx, field_tys) } } .map(|v| v.into_iter()) @@ -514,7 +506,7 @@ fn adt_async_drop_tys<'tcx>( tcx.type_of(def_id).instantiate_identity().skip_norm_wip(), ty::TypingEnv::non_body_analysis(tcx, def_id), adt_has_dtor, - DropTysOptions::default().async_drop(), + DropTysOptions::default().recurse_into_box_for_async_drop(), ) .collect::, _>>() .map(|components| tcx.mk_type_list(&components)) diff --git a/tests/crashes/142155.rs b/tests/crashes/142155.rs new file mode 100644 index 0000000000000..8c0769bf2b586 --- /dev/null +++ b/tests/crashes/142155.rs @@ -0,0 +1,12 @@ +//@ known-bug: #142155 +//@ needs-rustc-debug-assertions +//@ edition: 2021 + +#![warn(tail_expr_drop_order)] +use core::future::Future; + +fn f() -> impl Future> { + async { Some("nope".into()) } +} + +fn main() {} diff --git a/tests/mir-opt/coroutine/coroutine.main-{closure#0}.StateTransform.diff b/tests/mir-opt/coroutine/coroutine.main-{closure#0}.StateTransform.diff index 70d5034fc50e0..d9d65147e1e83 100644 --- a/tests/mir-opt/coroutine/coroutine.main-{closure#0}.StateTransform.diff +++ b/tests/mir-opt/coroutine/coroutine.main-{closure#0}.StateTransform.diff @@ -44,7 +44,7 @@ - StorageLive(_5); - StorageLive(_6); - _6 = &_2; -- _5 = ::clone(move _6) -> [return: bb1, unwind: bb29]; +- _5 = ::clone(move _6) -> [return: bb1, unwind: bb31]; + _18 = copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:19:5: 19:18}); + _17 = discriminant((*_18)); + switchInt(move _17) -> [0: bb35, 1: bb33, 2: bb32, 3: bb30, 4: bb31, otherwise: bb34]; @@ -53,7 +53,7 @@ bb1: { StorageDead(_6); StorageLive(_7); -- _7 = Location::<'_>::caller() -> [return: bb2, unwind: bb28]; +- _7 = Location::<'_>::caller() -> [return: bb2, unwind: bb30]; + _7 = Location::<'_>::caller() -> [return: bb2, unwind: bb21]; } @@ -65,7 +65,7 @@ bb3: { StorageDead(_5); -- _3 = yield(move _4) -> [resume: bb4, drop: bb17]; +- _3 = yield(move _4) -> [resume: bb4, drop: bb18]; + _0 = CoroutineState::<(&str, String, &Location<'_>), ()>::Yielded(move _4); + StorageDead(_3); + StorageDead(_4); @@ -79,7 +79,7 @@ bb5: { StorageDead(_4); -- drop(_3) -> [return: bb6, unwind: bb32]; +- drop(_3) -> [return: bb6, unwind: bb34]; + drop(_3) -> [return: bb6, unwind: bb25]; } @@ -94,7 +94,7 @@ StorageLive(_12); StorageLive(_13); - _13 = &_2; -- _12 = ::clone(move _13) -> [return: bb7, unwind: bb26]; +- _12 = ::clone(move _13) -> [return: bb7, unwind: bb28]; + _13 = &(((*_18) as variant#4).0: std::string::String); + _12 = ::clone(move _13) -> [return: bb7, unwind: bb19]; } @@ -103,7 +103,7 @@ StorageDead(_13); StorageLive(_14); StorageLive(_15); -- _15 = Location::<'_>::caller() -> [return: bb8, unwind: bb22]; +- _15 = Location::<'_>::caller() -> [return: bb8, unwind: bb24]; + _15 = Location::<'_>::caller() -> [return: bb8, unwind: bb15]; } @@ -133,7 +133,7 @@ bb11: { StorageDead(_9); -- drop(_8) -> [return: bb12, unwind: bb25]; +- drop(_8) -> [return: bb12, unwind: bb27]; + drop(_8) -> [return: bb12, unwind: bb18]; } @@ -142,13 +142,13 @@ StorageDead(_11); StorageDead(_8); - _0 = const (); -- drop(_2) -> [return: bb13, unwind: bb34]; +- drop(_2) -> [return: bb13, unwind: bb36]; + _16 = const (); + drop((((*_18) as variant#4).0: std::string::String)) -> [return: bb13, unwind: bb27]; } bb13: { -- drop(_1) -> [return: bb14, unwind: bb35]; +- drop(_1) -> [return: bb14, unwind: bb37]; + goto -> bb14; } @@ -167,25 +167,23 @@ - bb16: { - StorageDead(_9); -- StorageDead(_15); -- StorageDead(_11); -- StorageDead(_8); -- goto -> bb19; + bb16 (cleanup): { + StorageDead(_12); + StorageDead(_10); -+ goto -> bb17; + goto -> bb17; } - bb17: { +- StorageDead(_15); +- StorageDead(_11); +- StorageDead(_8); +- goto -> bb21; + bb17 (cleanup): { + StorageDead(_9); - goto -> bb18; ++ goto -> bb18; } - bb18: { -- StorageDead(_4); -- StorageDead(_3); - goto -> bb19; + bb18 (cleanup): { + StorageDead(_15); @@ -193,17 +191,18 @@ } - bb19: { -- drop(_2) -> [return: bb20, unwind: bb36]; +- StorageDead(_4); + bb19 (cleanup): { + StorageDead(_13); + StorageDead(_12); + StorageDead(_10); + StorageDead(_9); -+ goto -> bb20; + goto -> bb20; } - bb20: { -- drop(_1) -> [return: bb21, unwind: bb35]; +- StorageDead(_3); +- goto -> bb21; + bb20 (cleanup): { + StorageDead(_11); + StorageDead(_8); @@ -211,71 +210,71 @@ } - bb21: { -- coroutine_drop; +- drop(_2) -> [return: bb22, unwind: bb38]; + bb21 (cleanup): { + StorageDead(_7); + drop(_5) -> [return: bb23, unwind terminate(cleanup)]; } - bb22 (cleanup): { -- StorageDead(_14); -- drop(_12) -> [return: bb23, unwind terminate(cleanup)]; +- bb22: { +- drop(_1) -> [return: bb23, unwind: bb37]; ++ bb22 (cleanup): { + StorageDead(_6); + goto -> bb23; } - bb23 (cleanup): { -- StorageDead(_12); -- StorageDead(_10); +- bb23: { +- coroutine_drop; ++ bb23 (cleanup): { + StorageDead(_5); - goto -> bb24; ++ goto -> bb24; } bb24 (cleanup): { -- StorageDead(_9); +- StorageDead(_14); +- drop(_12) -> [return: bb25, unwind terminate(cleanup)]; + StorageDead(_4); - goto -> bb25; ++ goto -> bb25; } bb25 (cleanup): { -- StorageDead(_15); -- goto -> bb27; +- StorageDead(_12); +- StorageDead(_10); + StorageDead(_3); -+ goto -> bb26; + goto -> bb26; } bb26 (cleanup): { -- StorageDead(_13); -- StorageDead(_12); -- StorageDead(_10); - StorageDead(_9); - goto -> bb27; + drop((((*_18) as variant#4).0: std::string::String)) -> [return: bb27, unwind terminate(cleanup)]; } bb27 (cleanup): { -- StorageDead(_11); -- StorageDead(_8); -- goto -> bb33; +- StorageDead(_15); +- goto -> bb29; + goto -> bb28; } bb28 (cleanup): { -- StorageDead(_7); -- drop(_5) -> [return: bb30, unwind terminate(cleanup)]; -+ goto -> bb29; +- StorageDead(_13); +- StorageDead(_12); +- StorageDead(_10); +- StorageDead(_9); + goto -> bb29; } bb29 (cleanup): { -- StorageDead(_6); -- goto -> bb30; +- StorageDead(_11); +- StorageDead(_8); +- goto -> bb35; + discriminant((*_18)) = 2; + resume; } - bb30 (cleanup): { -- StorageDead(_5); -- goto -> bb31; +- StorageDead(_7); +- drop(_5) -> [return: bb32, unwind terminate(cleanup)]; + bb30: { + StorageLive(_3); + StorageLive(_4); @@ -284,7 +283,7 @@ } - bb31 (cleanup): { -- StorageDead(_4); +- StorageDead(_6); - goto -> bb32; + bb31: { + StorageLive(_8); @@ -296,30 +295,40 @@ } - bb32 (cleanup): { -- StorageDead(_3); +- StorageDead(_5); - goto -> bb33; + bb32: { + assert(const false, "coroutine resumed after panicking") -> [success: bb32, unwind continue]; } - bb33 (cleanup): { -- drop(_2) -> [return: bb34, unwind terminate(cleanup)]; +- StorageDead(_4); +- goto -> bb34; + bb33: { + assert(const false, "coroutine resumed after completion") -> [success: bb33, unwind continue]; } - bb34 (cleanup): { -- drop(_1) -> [return: bb35, unwind terminate(cleanup)]; +- StorageDead(_3); +- goto -> bb35; + bb34: { + unreachable; } - bb35 (cleanup): { -- resume; +- drop(_2) -> [return: bb36, unwind terminate(cleanup)]; - } - - bb36 (cleanup): { -- drop(_1) -> [return: bb35, unwind terminate(cleanup)]; +- drop(_1) -> [return: bb37, unwind terminate(cleanup)]; +- } +- +- bb37 (cleanup): { +- resume; +- } +- +- bb38 (cleanup): { +- drop(_1) -> [return: bb37, unwind terminate(cleanup)]; + bb35: { + (((*_18) as variant#4).0: std::string::String) = move _2; + StorageLive(_3); diff --git a/tests/mir-opt/coroutine/coroutine.main-{closure#1}.StateTransform.diff b/tests/mir-opt/coroutine/coroutine.main-{closure#1}.StateTransform.diff index 25b60ef5698ff..d25c2f61b722a 100644 --- a/tests/mir-opt/coroutine/coroutine.main-{closure#1}.StateTransform.diff +++ b/tests/mir-opt/coroutine/coroutine.main-{closure#1}.StateTransform.diff @@ -44,7 +44,7 @@ - StorageLive(_5); - StorageLive(_6); - _6 = &_2; -- _5 = ::clone(move _6) -> [return: bb1, unwind: bb29]; +- _5 = ::clone(move _6) -> [return: bb1, unwind: bb31]; + _18 = copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:26:5: 26:18}); + _17 = discriminant((*_18)); + switchInt(move _17) -> [0: bb35, 1: bb33, 2: bb32, 3: bb30, 4: bb31, otherwise: bb34]; @@ -53,7 +53,7 @@ bb1: { StorageDead(_6); StorageLive(_7); -- _7 = Location::<'_>::caller() -> [return: bb2, unwind: bb28]; +- _7 = Location::<'_>::caller() -> [return: bb2, unwind: bb30]; + _7 = Location::<'_>::caller() -> [return: bb2, unwind: bb21]; } @@ -65,7 +65,7 @@ bb3: { StorageDead(_5); -- _3 = yield(move _4) -> [resume: bb4, drop: bb17]; +- _3 = yield(move _4) -> [resume: bb4, drop: bb18]; + _0 = CoroutineState::<(&str, String, &Location<'_>), ()>::Yielded(move _4); + StorageDead(_3); + StorageDead(_4); @@ -79,7 +79,7 @@ bb5: { StorageDead(_4); -- drop(_3) -> [return: bb6, unwind: bb32]; +- drop(_3) -> [return: bb6, unwind: bb34]; + drop(_3) -> [return: bb6, unwind: bb25]; } @@ -94,7 +94,7 @@ StorageLive(_12); StorageLive(_13); - _13 = &_2; -- _12 = ::clone(move _13) -> [return: bb7, unwind: bb26]; +- _12 = ::clone(move _13) -> [return: bb7, unwind: bb28]; + _13 = &(((*_18) as variant#4).0: std::string::String); + _12 = ::clone(move _13) -> [return: bb7, unwind: bb19]; } @@ -103,7 +103,7 @@ StorageDead(_13); StorageLive(_14); StorageLive(_15); -- _15 = Location::<'_>::caller() -> [return: bb8, unwind: bb22]; +- _15 = Location::<'_>::caller() -> [return: bb8, unwind: bb24]; + _15 = Location::<'_>::caller() -> [return: bb8, unwind: bb15]; } @@ -133,7 +133,7 @@ bb11: { StorageDead(_9); -- drop(_8) -> [return: bb12, unwind: bb25]; +- drop(_8) -> [return: bb12, unwind: bb27]; + drop(_8) -> [return: bb12, unwind: bb18]; } @@ -142,13 +142,13 @@ StorageDead(_11); StorageDead(_8); - _0 = const (); -- drop(_2) -> [return: bb13, unwind: bb34]; +- drop(_2) -> [return: bb13, unwind: bb36]; + _16 = const (); + drop((((*_18) as variant#4).0: std::string::String)) -> [return: bb13, unwind: bb27]; } bb13: { -- drop(_1) -> [return: bb14, unwind: bb35]; +- drop(_1) -> [return: bb14, unwind: bb37]; + goto -> bb14; } @@ -167,25 +167,23 @@ - bb16: { - StorageDead(_9); -- StorageDead(_15); -- StorageDead(_11); -- StorageDead(_8); -- goto -> bb19; + bb16 (cleanup): { + StorageDead(_12); + StorageDead(_10); -+ goto -> bb17; + goto -> bb17; } - bb17: { +- StorageDead(_15); +- StorageDead(_11); +- StorageDead(_8); +- goto -> bb21; + bb17 (cleanup): { + StorageDead(_9); - goto -> bb18; ++ goto -> bb18; } - bb18: { -- StorageDead(_4); -- StorageDead(_3); - goto -> bb19; + bb18 (cleanup): { + StorageDead(_15); @@ -193,17 +191,18 @@ } - bb19: { -- drop(_2) -> [return: bb20, unwind: bb36]; +- StorageDead(_4); + bb19 (cleanup): { + StorageDead(_13); + StorageDead(_12); + StorageDead(_10); + StorageDead(_9); -+ goto -> bb20; + goto -> bb20; } - bb20: { -- drop(_1) -> [return: bb21, unwind: bb35]; +- StorageDead(_3); +- goto -> bb21; + bb20 (cleanup): { + StorageDead(_11); + StorageDead(_8); @@ -211,71 +210,71 @@ } - bb21: { -- coroutine_drop; +- drop(_2) -> [return: bb22, unwind: bb38]; + bb21 (cleanup): { + StorageDead(_7); + drop(_5) -> [return: bb23, unwind terminate(cleanup)]; } - bb22 (cleanup): { -- StorageDead(_14); -- drop(_12) -> [return: bb23, unwind terminate(cleanup)]; +- bb22: { +- drop(_1) -> [return: bb23, unwind: bb37]; ++ bb22 (cleanup): { + StorageDead(_6); + goto -> bb23; } - bb23 (cleanup): { -- StorageDead(_12); -- StorageDead(_10); +- bb23: { +- coroutine_drop; ++ bb23 (cleanup): { + StorageDead(_5); - goto -> bb24; ++ goto -> bb24; } bb24 (cleanup): { -- StorageDead(_9); +- StorageDead(_14); +- drop(_12) -> [return: bb25, unwind terminate(cleanup)]; + StorageDead(_4); - goto -> bb25; ++ goto -> bb25; } bb25 (cleanup): { -- StorageDead(_15); -- goto -> bb27; +- StorageDead(_12); +- StorageDead(_10); + StorageDead(_3); -+ goto -> bb26; + goto -> bb26; } bb26 (cleanup): { -- StorageDead(_13); -- StorageDead(_12); -- StorageDead(_10); - StorageDead(_9); - goto -> bb27; + drop((((*_18) as variant#4).0: std::string::String)) -> [return: bb27, unwind terminate(cleanup)]; } bb27 (cleanup): { -- StorageDead(_11); -- StorageDead(_8); -- goto -> bb33; +- StorageDead(_15); +- goto -> bb29; + goto -> bb28; } bb28 (cleanup): { -- StorageDead(_7); -- drop(_5) -> [return: bb30, unwind terminate(cleanup)]; -+ goto -> bb29; +- StorageDead(_13); +- StorageDead(_12); +- StorageDead(_10); +- StorageDead(_9); + goto -> bb29; } bb29 (cleanup): { -- StorageDead(_6); -- goto -> bb30; +- StorageDead(_11); +- StorageDead(_8); +- goto -> bb35; + discriminant((*_18)) = 2; + resume; } - bb30 (cleanup): { -- StorageDead(_5); -- goto -> bb31; +- StorageDead(_7); +- drop(_5) -> [return: bb32, unwind terminate(cleanup)]; + bb30: { + StorageLive(_3); + StorageLive(_4); @@ -284,7 +283,7 @@ } - bb31 (cleanup): { -- StorageDead(_4); +- StorageDead(_6); - goto -> bb32; + bb31: { + StorageLive(_8); @@ -296,30 +295,40 @@ } - bb32 (cleanup): { -- StorageDead(_3); +- StorageDead(_5); - goto -> bb33; + bb32: { + assert(const false, "coroutine resumed after panicking") -> [success: bb32, unwind continue]; } - bb33 (cleanup): { -- drop(_2) -> [return: bb34, unwind terminate(cleanup)]; +- StorageDead(_4); +- goto -> bb34; + bb33: { + assert(const false, "coroutine resumed after completion") -> [success: bb33, unwind continue]; } - bb34 (cleanup): { -- drop(_1) -> [return: bb35, unwind terminate(cleanup)]; +- StorageDead(_3); +- goto -> bb35; + bb34: { + unreachable; } - bb35 (cleanup): { -- resume; +- drop(_2) -> [return: bb36, unwind terminate(cleanup)]; - } - - bb36 (cleanup): { -- drop(_1) -> [return: bb35, unwind terminate(cleanup)]; +- drop(_1) -> [return: bb37, unwind terminate(cleanup)]; +- } +- +- bb37 (cleanup): { +- resume; +- } +- +- bb38 (cleanup): { +- drop(_1) -> [return: bb37, unwind terminate(cleanup)]; + bb35: { + (((*_18) as variant#4).0: std::string::String) = move _2; + StorageLive(_3); diff --git a/tests/mir-opt/coroutine/unwind_in_vec.build-{closure#0}.built.after.mir b/tests/mir-opt/coroutine/unwind_in_vec.build-{closure#0}.built.after.mir index 663d954d9b545..db46970999856 100644 --- a/tests/mir-opt/coroutine/unwind_in_vec.build-{closure#0}.built.after.mir +++ b/tests/mir-opt/coroutine/unwind_in_vec.build-{closure#0}.built.after.mir @@ -37,7 +37,7 @@ yields () FakeRead(ForLet(None), _3); StorageLive(_4); StorageLive(_5); - _5 = Box::<[String; 5]>::new_uninit() -> [return: bb1, unwind: bb44]; + _5 = Box::<[String; 5]>::new_uninit() -> [return: bb1, unwind: bb50]; } bb1: { @@ -46,7 +46,7 @@ yields () StorageLive(_8); _8 = const "0"; _7 = &(*_8); - _6 = ::to_string(move _7) -> [return: bb2, unwind: bb41]; + _6 = ::to_string(move _7) -> [return: bb2, unwind: bb47]; } bb2: { @@ -56,7 +56,7 @@ yields () StorageLive(_11); _11 = const "1"; _10 = &(*_11); - _9 = ::to_string(move _10) -> [return: bb3, unwind: bb37]; + _9 = ::to_string(move _10) -> [return: bb3, unwind: bb43]; } bb3: { @@ -66,7 +66,7 @@ yields () StorageLive(_14); _14 = const "2"; _13 = &(*_14); - _12 = ::to_string(move _13) -> [return: bb4, unwind: bb32]; + _12 = ::to_string(move _13) -> [return: bb4, unwind: bb38]; } bb4: { @@ -76,7 +76,7 @@ yields () StorageLive(_17); _17 = const "3"; _16 = &(*_17); - _15 = ::to_string(move _16) -> [return: bb5, unwind: bb26]; + _15 = ::to_string(move _16) -> [return: bb5, unwind: bb32]; } bb5: { @@ -86,44 +86,44 @@ yields () StorageLive(_20); _20 = const "4"; _19 = &(*_20); - _18 = ::to_string(move _19) -> [return: bb6, unwind: bb18]; + _18 = ::to_string(move _19) -> [return: bb6, unwind: bb24]; } bb6: { StorageDead(_19); (((*_5).1: std::mem::ManuallyDrop<[std::string::String; 5]>).0: [std::string::String; 5]) = [move _6, move _9, move _12, move _15, move _18]; - drop(_18) -> [return: bb7, unwind: bb19]; + drop(_18) -> [return: bb7, unwind: bb25, drop: bb15]; } bb7: { StorageDead(_18); - drop(_15) -> [return: bb8, unwind: bb20]; + drop(_15) -> [return: bb8, unwind: bb26, drop: bb16]; } bb8: { StorageDead(_15); - drop(_12) -> [return: bb9, unwind: bb21]; + drop(_12) -> [return: bb9, unwind: bb27, drop: bb17]; } bb9: { StorageDead(_12); - drop(_9) -> [return: bb10, unwind: bb22]; + drop(_9) -> [return: bb10, unwind: bb28, drop: bb18]; } bb10: { StorageDead(_9); - drop(_6) -> [return: bb11, unwind: bb23]; + drop(_6) -> [return: bb11, unwind: bb29, drop: bb19]; } bb11: { StorageDead(_6); _4 = move _5; - drop(_5) -> [return: bb12, unwind: bb16]; + drop(_5) -> [return: bb12, unwind: bb22]; } bb12: { StorageDead(_5); - _0 = std::boxed::box_assume_init_into_vec_unsafe::(move _4) -> [return: bb13, unwind: bb17]; + _0 = std::boxed::box_assume_init_into_vec_unsafe::(move _4) -> [return: bb13, unwind: bb23]; } bb13: { @@ -134,7 +134,7 @@ yields () StorageDead(_11); StorageDead(_8); StorageDead(_3); - drop(_1) -> [return: bb14, unwind: bb46, drop: bb15]; + drop(_1) -> [return: bb14, unwind: bb52, drop: bb21]; } bb14: { @@ -142,61 +142,66 @@ yields () } bb15: { - coroutine_drop; + StorageDead(_18); + drop(_15) -> [return: bb16, unwind: bb53]; } - bb16 (cleanup): { - StorageDead(_5); - goto -> bb17; + bb16: { + StorageDead(_15); + drop(_12) -> [return: bb17, unwind: bb54]; } - bb17 (cleanup): { - drop(_4) -> [return: bb25, unwind terminate(cleanup)]; + bb17: { + StorageDead(_12); + drop(_9) -> [return: bb18, unwind: bb55]; } - bb18 (cleanup): { - StorageDead(_19); - goto -> bb19; + bb18: { + StorageDead(_9); + drop(_6) -> [return: bb19, unwind: bb56]; } - bb19 (cleanup): { - StorageDead(_18); - drop(_15) -> [return: bb20, unwind terminate(cleanup)]; + bb19: { + StorageDead(_6); + drop(_5) -> [return: bb20, unwind: bb57]; } - bb20 (cleanup): { - StorageDead(_15); - drop(_12) -> [return: bb21, unwind terminate(cleanup)]; + bb20: { + StorageDead(_5); + StorageDead(_4); + StorageDead(_20); + StorageDead(_17); + StorageDead(_14); + StorageDead(_11); + StorageDead(_8); + StorageDead(_3); + drop(_1) -> [return: bb21, unwind: bb52]; } - bb21 (cleanup): { - StorageDead(_12); - drop(_9) -> [return: bb22, unwind terminate(cleanup)]; + bb21: { + coroutine_drop; } bb22 (cleanup): { - StorageDead(_9); - drop(_6) -> [return: bb23, unwind terminate(cleanup)]; + StorageDead(_5); + goto -> bb23; } bb23 (cleanup): { - StorageDead(_6); - drop(_5) -> [return: bb24, unwind terminate(cleanup)]; + drop(_4) -> [return: bb31, unwind terminate(cleanup)]; } bb24 (cleanup): { - StorageDead(_5); + StorageDead(_19); goto -> bb25; } bb25 (cleanup): { - StorageDead(_4); - StorageDead(_20); - goto -> bb31; + StorageDead(_18); + drop(_15) -> [return: bb26, unwind terminate(cleanup)]; } bb26 (cleanup): { - StorageDead(_16); StorageDead(_15); drop(_12) -> [return: bb27, unwind terminate(cleanup)]; } @@ -218,95 +223,159 @@ yields () bb30 (cleanup): { StorageDead(_5); - StorageDead(_4); goto -> bb31; } bb31 (cleanup): { - StorageDead(_17); - goto -> bb36; + StorageDead(_4); + StorageDead(_20); + goto -> bb37; } bb32 (cleanup): { + StorageDead(_16); + StorageDead(_15); + drop(_12) -> [return: bb33, unwind terminate(cleanup)]; + } + + bb33 (cleanup): { + StorageDead(_12); + drop(_9) -> [return: bb34, unwind terminate(cleanup)]; + } + + bb34 (cleanup): { + StorageDead(_9); + drop(_6) -> [return: bb35, unwind terminate(cleanup)]; + } + + bb35 (cleanup): { + StorageDead(_6); + drop(_5) -> [return: bb36, unwind terminate(cleanup)]; + } + + bb36 (cleanup): { + StorageDead(_5); + StorageDead(_4); + goto -> bb37; + } + + bb37 (cleanup): { + StorageDead(_17); + goto -> bb42; + } + + bb38 (cleanup): { StorageDead(_13); StorageDead(_12); - drop(_9) -> [return: bb33, unwind terminate(cleanup)]; + drop(_9) -> [return: bb39, unwind terminate(cleanup)]; } - bb33 (cleanup): { + bb39 (cleanup): { StorageDead(_9); - drop(_6) -> [return: bb34, unwind terminate(cleanup)]; + drop(_6) -> [return: bb40, unwind terminate(cleanup)]; } - bb34 (cleanup): { + bb40 (cleanup): { StorageDead(_6); - drop(_5) -> [return: bb35, unwind terminate(cleanup)]; + drop(_5) -> [return: bb41, unwind terminate(cleanup)]; } - bb35 (cleanup): { + bb41 (cleanup): { StorageDead(_5); StorageDead(_4); - goto -> bb36; + goto -> bb42; } - bb36 (cleanup): { + bb42 (cleanup): { StorageDead(_14); - goto -> bb40; + goto -> bb46; } - bb37 (cleanup): { + bb43 (cleanup): { StorageDead(_10); StorageDead(_9); - drop(_6) -> [return: bb38, unwind terminate(cleanup)]; + drop(_6) -> [return: bb44, unwind terminate(cleanup)]; } - bb38 (cleanup): { + bb44 (cleanup): { StorageDead(_6); - drop(_5) -> [return: bb39, unwind terminate(cleanup)]; + drop(_5) -> [return: bb45, unwind terminate(cleanup)]; } - bb39 (cleanup): { + bb45 (cleanup): { StorageDead(_5); StorageDead(_4); - goto -> bb40; + goto -> bb46; } - bb40 (cleanup): { + bb46 (cleanup): { StorageDead(_11); - goto -> bb43; + goto -> bb49; } - bb41 (cleanup): { + bb47 (cleanup): { StorageDead(_7); StorageDead(_6); - drop(_5) -> [return: bb42, unwind terminate(cleanup)]; + drop(_5) -> [return: bb48, unwind terminate(cleanup)]; } - bb42 (cleanup): { + bb48 (cleanup): { StorageDead(_5); StorageDead(_4); - goto -> bb43; + goto -> bb49; } - bb43 (cleanup): { + bb49 (cleanup): { StorageDead(_8); - goto -> bb45; + goto -> bb51; } - bb44 (cleanup): { + bb50 (cleanup): { StorageDead(_5); StorageDead(_4); - goto -> bb45; + goto -> bb51; } - bb45 (cleanup): { + bb51 (cleanup): { StorageDead(_3); - drop(_1) -> [return: bb46, unwind terminate(cleanup)]; + drop(_1) -> [return: bb52, unwind terminate(cleanup)]; } - bb46 (cleanup): { + bb52 (cleanup): { resume; } + + bb53 (cleanup): { + StorageDead(_15); + drop(_12) -> [return: bb54, unwind terminate(cleanup)]; + } + + bb54 (cleanup): { + StorageDead(_12); + drop(_9) -> [return: bb55, unwind terminate(cleanup)]; + } + + bb55 (cleanup): { + StorageDead(_9); + drop(_6) -> [return: bb56, unwind terminate(cleanup)]; + } + + bb56 (cleanup): { + StorageDead(_6); + drop(_5) -> [return: bb57, unwind terminate(cleanup)]; + } + + bb57 (cleanup): { + StorageDead(_5); + StorageDead(_4); + StorageDead(_20); + StorageDead(_17); + StorageDead(_14); + StorageDead(_11); + StorageDead(_8); + StorageDead(_3); + drop(_1) -> [return: bb52, unwind terminate(cleanup)]; + } } ALLOC0 (size: 1, align: 1) { diff --git a/tests/ui/async-await/async-drop/cancelled-future-drops-sync-fields-164901.rs b/tests/ui/async-await/async-drop/cancelled-future-drops-sync-fields-164901.rs deleted file mode 100644 index 280e123eb0b78..0000000000000 --- a/tests/ui/async-await/async-drop/cancelled-future-drops-sync-fields-164901.rs +++ /dev/null @@ -1,56 +0,0 @@ -//@ run-pass -//@ edition: 2024 - -// Regression test for . -// Types with only a sync `Drop` impl nested inside another ADT were treated -// as needing async drop, so a cancelled future leaked them. - -#![feature(async_drop)] -#![allow(incomplete_features)] - -use std::future::Future; -use std::pin::pin; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::task::{Context, Waker}; - -static DROPS: AtomicUsize = AtomicUsize::new(0); - -struct D; -impl Drop for D { - fn drop(&mut self) { - DROPS.fetch_add(1, Ordering::Relaxed); - } -} - -struct Wrapper(T); - -fn poll_once_then_drop(f: impl Future) { - let mut f = Box::pin(f); - let _ = f.as_mut().poll(&mut Context::from_waker(Waker::noop())); -} - -fn main() { - poll_once_then_drop(async { - let _d = D; - std::future::pending::<()>().await - }); - assert_eq!(DROPS.load(Ordering::Relaxed), 1); - - poll_once_then_drop(async { - let _o = Some(D); - std::future::pending::<()>().await - }); - assert_eq!(DROPS.load(Ordering::Relaxed), 2); - - poll_once_then_drop(async { - let _w = Wrapper(D); - std::future::pending::<()>().await - }); - assert_eq!(DROPS.load(Ordering::Relaxed), 3); - - poll_once_then_drop(async { - let _p = pin!(D); - std::future::pending::<()>().await - }); - assert_eq!(DROPS.load(Ordering::Relaxed), 4); -} diff --git a/tests/ui/drop/tail_expr_drop_order-on-async-block-with-drop-field.rs b/tests/ui/drop/tail_expr_drop_order-on-async-block-with-drop-field.rs deleted file mode 100644 index 69e9a8e06dc86..0000000000000 --- a/tests/ui/drop/tail_expr_drop_order-on-async-block-with-drop-field.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ edition: 2021 -//@ check-pass - -// Regression test for . -// The tail expr drop order lint used to ICE on this async block. It stopped -// once types with only a sync `Drop` were no longer treated as needing async drop. - -#![warn(tail_expr_drop_order)] -use core::future::Future; - -fn f() -> impl Future> { - async { Some("nope".into()) } -} - -fn main() {} From 78496e5ba3061551d169d60688c8f0e53f71e256 Mon Sep 17 00:00:00 2001 From: Max Dexheimer Date: Sun, 1 Nov 2026 07:58:48 +0100 Subject: [PATCH 30/34] Add regression test for issue 165263 --- .../ui/drop/async-drop-cycle-issue-165263.rs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/ui/drop/async-drop-cycle-issue-165263.rs diff --git a/tests/ui/drop/async-drop-cycle-issue-165263.rs b/tests/ui/drop/async-drop-cycle-issue-165263.rs new file mode 100644 index 0000000000000..3add37ecf990a --- /dev/null +++ b/tests/ui/drop/async-drop-cycle-issue-165263.rs @@ -0,0 +1,22 @@ +//@ build-pass +//@ edition: 2024 +// test that a recursive type in an async block does +// not cause a cycle. + +pub struct A(Box); +pub struct B(A); +pub async fn run(_: A) {} + +pub enum A2 { + X(Box), +} + +pub enum B2 { + Y(A2), +} +pub async fn run2(a: Option) { + async {}.await; + drop(a); +} + +fn main() {} From 3b0fcf64598869b96a3cfe83e042921753838cc0 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 1 Nov 2026 09:39:24 +0100 Subject: [PATCH 31/34] Remove the `-2` jobs --- src/ci/github-actions/jobs.yml | 103 ++++++++++++++++----------------- 1 file changed, 51 insertions(+), 52 deletions(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 210c139dd2b56..a63cfd7465e0f 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -587,32 +587,31 @@ auto: MACOSX_STD_DEPLOYMENT_TARGET: 11.0 <<: *job-macos-15 - - name: test-aarch64-apple-2 - env: - # NOTE: keep in sync with `src/ci/docker/scripts/stage_2_test_set2.sh`, - # union `src/tools/cargo` specifically. - SCRIPT: >- - ./x.py --stage 2 test - --host=aarch64-apple-darwin - --target=aarch64-apple-darwin - --skip tests - --skip library - --skip tidyselftest - --skip src/tools/rust-analyzer - && ./x.py --stage 2 test - --host=aarch64-apple-darwin - --target=aarch64-apple-darwin - src/tools/cargo - RUST_CONFIGURE_ARGS: >- - --enable-sanitizers - --enable-profiler - --set build.allocator=jemalloc - DEVELOPER_DIR: /Applications/Xcode_26.2.app/Contents/Developer - # Aarch64 tooling only needs to support macOS 11.0 and up as nothing else - # supports the hardware, so only need to test it there. - MACOSX_DEPLOYMENT_TARGET: 11.0 - MACOSX_STD_DEPLOYMENT_TARGET: 11.0 - <<: *job-macos-15 +# - name: test-aarch64-apple-2 +# env: +# # NOTE: keep in sync with `src/ci/docker/scripts/stage_2_test_set2.sh`, +# # union `src/tools/cargo` specifically. +# SCRIPT: >- +# ./x.py --stage 2 test +# --host=aarch64-apple-darwin +# --target=aarch64-apple-darwin +# --skip tests +# --skip library +# --skip tidyselftest +# && ./x.py --stage 2 test +# --host=aarch64-apple-darwin +# --target=aarch64-apple-darwin +# src/tools/cargo +# RUST_CONFIGURE_ARGS: >- +# --enable-sanitizers +# --enable-profiler +# --set build.allocator=jemalloc +# DEVELOPER_DIR: /Applications/Xcode_26.2.app/Contents/Developer +# # Aarch64 tooling only needs to support macOS 11.0 and up as nothing else +# # supports the hardware, so only need to test it there. +# MACOSX_DEPLOYMENT_TARGET: 11.0 +# MACOSX_STD_DEPLOYMENT_TARGET: 11.0 +# <<: *job-macos-15 # EXPERIMENT(#157687): we will try to run `aarch64-apple`-equivalent workload # on `macos-26` runner images in parallel to evaluate the running times, since @@ -641,32 +640,32 @@ auto: MACOSX_STD_DEPLOYMENT_TARGET: 11.0 <<: *job-macos-26 - - name: test-aarch64-apple-macos-26-2 - doc_url: https://github.com/rust-lang/rust/issues/157687 - env: - # NOTE: keep in sync with `src/ci/docker/scripts/stage_2_test_set2.sh`, - # union `src/tools/cargo` specifically. - SCRIPT: >- - ./x.py --stage 2 test - --host=aarch64-apple-darwin - --target=aarch64-apple-darwin - --skip tests - --skip library - --skip tidyselftest - && ./x.py --stage 2 test - --host=aarch64-apple-darwin - --target=aarch64-apple-darwin - src/tools/cargo - RUST_CONFIGURE_ARGS: >- - --enable-sanitizers - --enable-profiler - --set rust.jemalloc - DEVELOPER_DIR: /Applications/Xcode_26.2.app/Contents/Developer - # Aarch64 tooling only needs to support macOS 11.0 and up as nothing else - # supports the hardware, so only need to test it there. - MACOSX_DEPLOYMENT_TARGET: 11.0 - MACOSX_STD_DEPLOYMENT_TARGET: 11.0 - <<: *job-macos-26 +# - name: test-aarch64-apple-macos-26-2 +# doc_url: https://github.com/rust-lang/rust/issues/157687 +# env: +# # NOTE: keep in sync with `src/ci/docker/scripts/stage_2_test_set2.sh`, +# # union `src/tools/cargo` specifically. +# SCRIPT: >- +# ./x.py --stage 2 test +# --host=aarch64-apple-darwin +# --target=aarch64-apple-darwin +# --skip tests +# --skip library +# --skip tidyselftest +# && ./x.py --stage 2 test +# --host=aarch64-apple-darwin +# --target=aarch64-apple-darwin +# src/tools/cargo +# RUST_CONFIGURE_ARGS: >- +# --enable-sanitizers +# --enable-profiler +# --set rust.jemalloc +# DEVELOPER_DIR: /Applications/Xcode_26.2.app/Contents/Developer +# # Aarch64 tooling only needs to support macOS 11.0 and up as nothing else +# # supports the hardware, so only need to test it there. +# MACOSX_DEPLOYMENT_TARGET: 11.0 +# MACOSX_STD_DEPLOYMENT_TARGET: 11.0 +# <<: *job-macos-26 ###################### # Windows Builders # From 33b5a0d90cf74401a615cc619f5be236bce37772 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sun, 1 Nov 2026 10:27:09 +0100 Subject: [PATCH 32/34] Fix allocator flag --- src/ci/github-actions/jobs.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index a63cfd7465e0f..68298870cf739 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -632,7 +632,7 @@ auto: RUST_CONFIGURE_ARGS: >- --enable-sanitizers --enable-profiler - --set rust.jemalloc + --set build.allocator=jemalloc DEVELOPER_DIR: /Applications/Xcode_26.2.app/Contents/Developer # Aarch64 tooling only needs to support macOS 11.0 and up as nothing else # supports the hardware, so only need to test it there. @@ -659,7 +659,7 @@ auto: # RUST_CONFIGURE_ARGS: >- # --enable-sanitizers # --enable-profiler -# --set rust.jemalloc +# --set build.allocator=jemalloc # DEVELOPER_DIR: /Applications/Xcode_26.2.app/Contents/Developer # # Aarch64 tooling only needs to support macOS 11.0 and up as nothing else # # supports the hardware, so only need to test it there. From 3cbd10bd35f9cf1205f09eab60eafe88339b6693 Mon Sep 17 00:00:00 2001 From: Voxell Paladynee Date: Sun, 4 Oct 2026 15:52:13 +0300 Subject: [PATCH 33/34] specialize vec extend_with --- library/alloc/src/vec/mod.rs | 33 ++---- library/alloc/src/vec/spec_extend_with.rs | 110 ++++++++++++++++++ .../vec-spec-extend-with-correct-drop.rs | 85 ++++++++++++++ 3 files changed, 202 insertions(+), 26 deletions(-) create mode 100644 library/alloc/src/vec/spec_extend_with.rs create mode 100644 tests/ui/array-slice-vec/vec-spec-extend-with-correct-drop.rs diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 8bcad62226a0b..1651eedf42bc0 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -170,6 +170,12 @@ use self::spec_extend::SpecExtend; #[cfg(not(no_global_oom_handling))] mod spec_extend; +#[cfg(not(no_global_oom_handling))] +use self::spec_extend_with::SpecExtendWith; + +#[cfg(not(no_global_oom_handling))] +mod spec_extend_with; + #[cfg(all(target_arch = "aarch64", target_feature = "sve"))] mod sve_retain; @@ -3741,32 +3747,7 @@ impl Vec { #[cfg(not(no_global_oom_handling))] /// Extend the vector by `n` clones of value. fn extend_with(&mut self, n: usize, value: T) { - self.reserve(n); - - // ignore-tidy-undocumented-unsafe - unsafe { - let mut ptr = self.as_mut_ptr().add(self.len()); - // Use SetLenOnDrop to work around bug where compiler - // might not realize the store through `ptr` through self.set_len() - // don't alias. - let mut local_len = SetLenOnDrop::new(&mut self.len); - - // Write all elements except the last one - for _ in 1..n { - ptr::write(ptr, value.clone()); - ptr = ptr.add(1); - // Increment the length in every step in case clone() panics - local_len.increment_len(1); - } - - if n > 0 { - // We can write the last element directly without cloning needlessly - ptr::write(ptr, value); - local_len.increment_len(1); - } - - // len set by scope guard - } + self.spec_extend_with(n, value); } } diff --git a/library/alloc/src/vec/spec_extend_with.rs b/library/alloc/src/vec/spec_extend_with.rs new file mode 100644 index 0000000000000..846d77bc1956c --- /dev/null +++ b/library/alloc/src/vec/spec_extend_with.rs @@ -0,0 +1,110 @@ +use core::clone::TrivialClone; +use core::{mem, ptr}; + +use crate::alloc::Allocator; +use crate::vec::{SetLenOnDrop, Vec}; + +pub(super) trait SpecExtendWith { + /// Extend the vector by `n` clones of value. + fn spec_extend_with(&mut self, n: usize, value: T); +} + +impl SpecExtendWith for Vec { + default fn spec_extend_with(&mut self, n: usize, value: T) { + self.reserve(n); + + // SAFETY: Since `reserve` guarantees `self.len() + n` <= `capacity`, this + // pointer is always within bounds, and valid for writes for the next `n` items. + let mut ptr = unsafe { self.as_mut_ptr().add(self.len()) }; + // Use SetLenOnDrop to work around bug where compiler + // might not realize the store through `ptr` through self.set_len() + // don't alias. + let mut local_len = SetLenOnDrop::new(&mut self.len); + + // Write all elements except the last one + for _ in 1..n { + // three things have been taken into consideration: + // - `T::clone` can be provided by the user, and can panic. + // - `T` may implement Drop. + // - Since we already have a `value: T`, we can clone `n - 1` times. + + // This loop runs at most `n - 1` times, for all slots except the last one. + // As per the guarantee of `reserve`, increments to `ptr` within this range won't wrap around. + + // if clone() panics and starts unwinding; + // - the write has not been done yet + // - the length will be set by SetLenOnDrop, to the amount of initialized elements + // - later, when the Vec is dropped, only initialized elements are dropped. + // SAFETY: According to the diagram above, this write is within bounds. + unsafe { ptr::write(ptr, value.clone()) }; + // SAFETY: According to the diagram above, this increment is within bounds of the + // allocation and won't wrap around + ptr = unsafe { ptr.add(1) }; + // Increment the length of SetLenOnDrop in every step in case clone() panics to drop the + // already-initialized elements. + local_len.increment_len(1); + } + + if n > 0 { + // We can write the last element directly without cloning needlessly + + // SAFETY: According to the diagram above, the last element is not yet written, + // so this write is within bounds. + unsafe { ptr::write(ptr, value) }; + local_len.increment_len(1); + } + + // len set by scope guard + } +} + +impl SpecExtendWith for Vec { + fn spec_extend_with(&mut self, n: usize, value: T) { + // The `n == 0` check is already being inserted by the loop canonicalization pass, + // so this costs nothing. + // https://llvm.org/docs/LoopTerminology.html#more-canonical-loops + if n == 0 { + // three things: + // `self.reserve(0)` does not need to be run, since reserving space for 0 elements + // is a no-op. since the `value` argument did not have anywhere to be moved to, it is + // dropped here. with this branch present here, we can elide the write through self.len, + // since `self.len += 0` would be a no-op. + return; + } + + self.reserve(n); + + // SAFETY: Since `reserve` guarantees `self.len() + n` <= `capacity`, this + // pointer is always within bounds, and valid for writes for the next `n` items. + let ptr = unsafe { self.as_mut_ptr().add(self.len()) }; + + let mut i = 0; + // Write all the elements by copying `value`. + // We use an incrementing index here instead of incrementing pointer because the former + // has been observed to have less register pressure in the loop initialization. + // https://llvm.org/docs/Vectorizers.html#inductions + while i < n { + // SAFETY: `TrivialClone` indicates that copying `value` is equivalent to + // calling `Clone::clone` for `T`. As per the safety comment for `ptr`, this pointer + // is within bounds, won't wrap around while `i < n`, and valid for writes. The values + // do not overlap since `value` is stored as a function argument, and the target is + // in the Vec. + unsafe { ptr.add(i).copy_from_nonoverlapping(&value, 1) }; + + // Because above is infallible, we don't need to worry about setting the len + // in this loop, and instead we just increment the loop induction variable. + i += 1; + } + + // Above, `n` items have been infallibly copied into the vector + self.len += n; + + // The reason we did not treat the last position in the vector specially by doing + // `n - 1` copies and semantically moving `value` into it is that we are forced to do `n` + // copies of the value no matter what, and it's better to do it in the above loop than + // by manually writing since it can be vectorized. + // Then, `value` was never semantically moved into the vec, only copied from, + // so we forget it here to prevent the Drop. + mem::forget(value); + } +} diff --git a/tests/ui/array-slice-vec/vec-spec-extend-with-correct-drop.rs b/tests/ui/array-slice-vec/vec-spec-extend-with-correct-drop.rs new file mode 100644 index 0000000000000..7affe9826f9b5 --- /dev/null +++ b/tests/ui/array-slice-vec/vec-spec-extend-with-correct-drop.rs @@ -0,0 +1,85 @@ +//@ run-pass +#![feature(trivial_clone)] + +use std::cell::Cell; +use std::clone::TrivialClone; +use std::vec::from_elem; + +#[derive(Clone)] +struct DropCounter<'a>(&'a Cell); + +unsafe impl<'a> TrivialClone for DropCounter<'a> {} + +impl Drop for DropCounter<'_> { + fn drop(&mut self) { + self.0.set(self.0.get() + 1); + } +} + +struct CloneCounter<'a> { + clones: &'a Cell, + drops: &'a Cell, +} + +impl<'a> CloneCounter<'a> { + fn new(clones: &'a Cell, drops: &'a Cell) -> Self { + Self { clones, drops } + } +} + +impl<'a> Clone for CloneCounter<'a> { + fn clone(&self) -> Self { + self.clones.set(self.clones.get() + 1); + Self::new(self.clones, self.drops) + } +} + +impl<'a> Drop for CloneCounter<'a> { + fn drop(&mut self) { + self.drops.set(self.drops.get() + 1); + } +} + +fn main() { + // TrivialClone + let c = Cell::new(0); + + let mut vec = from_elem(DropCounter(&c), 3); + vec.clear(); + + assert_eq!(c.get(), 3); + vec = from_elem(DropCounter(&c), 6); + vec.clear(); + + assert_eq!(c.get(), 9); + + vec = from_elem(DropCounter(&c), 0); + assert_eq!(c.get(), 10); + vec.clear(); + assert_eq!(c.get(), 10); + + // nontrivial clone + let clones = Cell::new(0); + let drops = Cell::new(0); + + let mut vec = from_elem(CloneCounter::new(&clones, &drops), 3); + assert_eq!(clones.get(), 2); + assert_eq!(drops.get(), 0); + vec.clear(); + assert_eq!(clones.get(), 2); + assert_eq!(drops.get(), 3); + + vec = from_elem(CloneCounter::new(&clones, &drops), 6); + assert_eq!(clones.get(), 7); + assert_eq!(drops.get(), 3); + vec.clear(); + assert_eq!(clones.get(), 7); + assert_eq!(drops.get(), 9); + + vec = from_elem(CloneCounter::new(&clones, &drops), 0); + assert_eq!(clones.get(), 7); + assert_eq!(drops.get(), 10); + vec.clear(); + assert_eq!(clones.get(), 7); + assert_eq!(drops.get(), 10); +} From 9e520f41cc01d8c782975f079d4a06cc01f9bd99 Mon Sep 17 00:00:00 2001 From: "Tim (Theemathas) Chirananthavat" Date: Sun, 1 Nov 2026 20:13:47 +0700 Subject: [PATCH 34/34] Fix FCW issue template labels Previously, creating an issue with this template would produce an issue with no labels. --- .github/ISSUE_TEMPLATE/tracking_issue_future.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/tracking_issue_future.md b/.github/ISSUE_TEMPLATE/tracking_issue_future.md index c9da81371e151..62584fa2a9a59 100644 --- a/.github/ISSUE_TEMPLATE/tracking_issue_future.md +++ b/.github/ISSUE_TEMPLATE/tracking_issue_future.md @@ -2,7 +2,7 @@ name: Future Incompatibility Tracking Issue about: A tracking issue for a future-incompatible lint title: Tracking Issue for future-incompatibility lint XXX -labels: C-tracking-issue C-future-incompatibility T-compiler A-lints +labels: C-tracking-issue, C-future-incompatibility, T-compiler, A-lints ---