From 9064d17405e21924fd87cd187ce64a7fbf17c63f Mon Sep 17 00:00:00 2001 From: nataliakokoromyti Date: Sat, 18 Apr 2026 10:51:16 -0700 Subject: [PATCH 01/12] Do not suggest borrowing enclosing calls for nested where-clause obligations --- .../src/error_reporting/traits/ambiguity.rs | 1 + .../traits/fulfillment_errors.rs | 17 ++++++++ .../src/error_reporting/traits/suggestions.rs | 42 +++++++++++++++++++ ...-suggest-borrow-whole-call-issue-155088.rs | 8 ++++ ...gest-borrow-whole-call-issue-155088.stderr | 15 +++++++ 5 files changed, 83 insertions(+) create mode 100644 tests/ui/suggestions/dont-suggest-borrow-whole-call-issue-155088.rs create mode 100644 tests/ui/suggestions/dont-suggest-borrow-whole-call-issue-155088.stderr diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index 7f5ed9ecb6d11..cff842d9d316f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -349,6 +349,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if impl_candidates.len() < 40 { self.report_similar_impl_candidates( impl_candidates.as_slice(), + obligation, trait_pred, obligation.cause.body_id, &mut err, 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 43ab4a64fbedc..7a02cdadc735b 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 @@ -2008,6 +2008,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { pub(super) fn report_similar_impl_candidates( &self, impl_candidates: &[ImplCandidate<'tcx>], + obligation: &PredicateObligation<'tcx>, trait_pred: ty::PolyTraitPredicate<'tcx>, body_def_id: LocalDefId, err: &mut Diag<'_>, @@ -2072,6 +2073,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; if let [single] = &impl_candidates { + let self_ty = trait_pred.skip_binder().self_ty(); + if !self_ty.has_escaping_bound_vars() { + let self_ty = self.tcx.instantiate_bound_regions_with_erased(trait_pred.self_ty()); + if let ty::Ref(_, inner_ty, _) = self_ty.kind() + && self.can_eq(param_env, single.trait_ref.self_ty(), *inner_ty) + && !self.where_clause_expr_matches_failed_self_ty(obligation, self_ty) + { + // Avoid pointing at a nearby impl like `String: Borrow` when the + // failing obligation comes from something nested inside an enclosing call + // expression such as `foo(&[String::from("a")])`. + return true; + } + } + // If we have a single implementation, try to unify it with the trait ref // that failed. This should uncover a better hint for what *is* implemented. if self.probe(|_| { @@ -2491,6 +2506,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let impl_candidates = self.find_similar_impl_candidates(trait_pred); self.report_similar_impl_candidates( &impl_candidates, + obligation, trait_pred, body_def_id, err, @@ -3165,6 +3181,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let impl_candidates = self.find_similar_impl_candidates(trait_predicate); if !self.report_similar_impl_candidates( &impl_candidates, + obligation, trait_predicate, body_def_id, err, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 62f6b87c9e98c..6946c17f62e53 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -1467,6 +1467,39 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) } } + pub(super) fn where_clause_expr_matches_failed_self_ty( + &self, + obligation: &PredicateObligation<'tcx>, + old_self_ty: Ty<'tcx>, + ) -> bool { + let ObligationCauseCode::WhereClauseInExpr(..) = obligation.cause.code() else { + return true; + }; + let (Some(typeck_results), Some(body)) = ( + self.typeck_results.as_ref(), + self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id), + ) else { + return true; + }; + + let mut expr_finder = FindExprBySpan::new(obligation.cause.span, self.tcx); + expr_finder.visit_expr(body.value); + let Some(expr) = expr_finder.result else { + return true; + }; + + let inner_old_self_ty = match old_self_ty.kind() { + ty::Ref(_, inner_ty, _) => Some(*inner_ty), + _ => None, + }; + + [typeck_results.expr_ty_adjusted_opt(expr)].into_iter().flatten().any(|expr_ty| { + self.can_eq(obligation.param_env, expr_ty, old_self_ty) + || inner_old_self_ty + .is_some_and(|inner_ty| self.can_eq(obligation.param_env, expr_ty, inner_ty)) + }) + } + pub(super) fn suggest_add_reference_to_arg( &self, obligation: &PredicateObligation<'tcx>, @@ -1740,6 +1773,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let hir::ExprKind::AddrOf(_, _, _) = expr.kind { return false; } + let old_self_ty = old_pred.skip_binder().self_ty(); + if !old_self_ty.has_escaping_bound_vars() + && !self.where_clause_expr_matches_failed_self_ty( + obligation, + self.tcx.instantiate_bound_regions_with_erased(old_pred.self_ty()), + ) + { + return false; + } let needs_parens_post = expr_needs_parens(expr); let needs_parens_pre = match self.tcx.parent_hir_node(expr.hir_id) { Node::Expr(e) diff --git a/tests/ui/suggestions/dont-suggest-borrow-whole-call-issue-155088.rs b/tests/ui/suggestions/dont-suggest-borrow-whole-call-issue-155088.rs new file mode 100644 index 0000000000000..d8e2e7091d6e0 --- /dev/null +++ b/tests/ui/suggestions/dont-suggest-borrow-whole-call-issue-155088.rs @@ -0,0 +1,8 @@ +use std::borrow::Borrow; + +fn foo(_v: impl IntoIterator>) {} + +fn main() { + foo(&[String::from("a")]); + //~^ ERROR the trait bound `&String: Borrow` is not satisfied +} diff --git a/tests/ui/suggestions/dont-suggest-borrow-whole-call-issue-155088.stderr b/tests/ui/suggestions/dont-suggest-borrow-whole-call-issue-155088.stderr new file mode 100644 index 0000000000000..8910ed892ec03 --- /dev/null +++ b/tests/ui/suggestions/dont-suggest-borrow-whole-call-issue-155088.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `&String: Borrow` is not satisfied + --> $DIR/dont-suggest-borrow-whole-call-issue-155088.rs:6:5 + | +LL | foo(&[String::from("a")]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Borrow` is not implemented for `&String` + | +note: required by a bound in `foo` + --> $DIR/dont-suggest-borrow-whole-call-issue-155088.rs:3:42 + | +LL | fn foo(_v: impl IntoIterator>) {} + | ^^^^^^^^^^^ required by this bound in `foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. From 70cf3f4fda39193c8d78979144b7aaeafae3e97d Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Tue, 21 Apr 2026 23:42:33 +0200 Subject: [PATCH 02/12] Put `#[diagnostic::on_move]` on `File` --- library/std/src/fs.rs | 1 + library/std/src/lib.rs | 1 + .../diagnostic_namespace/on_move/std_impls.rs | 25 ++++++++++ .../on_move/std_impls.stderr | 49 +++++++++++++++++++ 4 files changed, 76 insertions(+) create mode 100644 tests/ui/diagnostic_namespace/on_move/std_impls.rs create mode 100644 tests/ui/diagnostic_namespace/on_move/std_impls.stderr diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index c75f005f18021..5192343ea4300 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -132,6 +132,7 @@ use crate::{error, fmt}; /// [`read`]: File::read #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "File")] +#[diagnostic::on_move(note = "you can use `File::try_clone` to duplicate a `File` instance")] pub struct File { inner: fs_imp::File, } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index faac8d9e51fd2..976577156c5bd 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -278,6 +278,7 @@ #![feature(const_trait_impl)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] +#![feature(diagnostic_on_move)] #![feature(doc_cfg)] #![feature(doc_masked)] #![feature(doc_notable_trait)] diff --git a/tests/ui/diagnostic_namespace/on_move/std_impls.rs b/tests/ui/diagnostic_namespace/on_move/std_impls.rs new file mode 100644 index 0000000000000..ea63d731a3434 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/std_impls.rs @@ -0,0 +1,25 @@ +//@ dont-require-annotations: NOTE + +use std::fs::File; +use std::sync::Arc; +use std::rc::Rc; + +fn main(){ + let file = File::open("foo.txt").unwrap(); + (file, file); + //~^ ERROR use of moved value: `file` + //~| NOTE you can use `File::try_clone` to duplicate a `File` instance + + let arc = Arc::new(42); + //~^ NOTE this move could be avoided by cloning the original `Arc`, which is inexpensive + (arc, arc); + //~^ ERROR the type `Arc` does not implement `Copy` + //~| NOTE consider using `Arc::clone` + + + let rc = Rc::new(12); + //~^ NOTE this move could be avoided by cloning the original `Rc`, which is inexpensive + (rc, rc); + //~^ ERROR the type `Rc` does not implement `Copy` + //~| NOTE consider using `Rc::clone` +} diff --git a/tests/ui/diagnostic_namespace/on_move/std_impls.stderr b/tests/ui/diagnostic_namespace/on_move/std_impls.stderr new file mode 100644 index 0000000000000..ba8869d9c73fb --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/std_impls.stderr @@ -0,0 +1,49 @@ +error[E0382]: use of moved value: `file` + --> $DIR/std_impls.rs:9:12 + | +LL | let file = File::open("foo.txt").unwrap(); + | ---- move occurs because `file` has type `File`, which does not implement the `Copy` trait +LL | (file, file); + | ---- ^^^^ value used here after move + | | + | value moved here + | + = note: you can use `File::try_clone` to duplicate a `File` instance + +error[E0382]: the type `Arc` does not implement `Copy` + --> $DIR/std_impls.rs:15:11 + | +LL | let arc = Arc::new(42); + | --- this move could be avoided by cloning the original `Arc`, which is inexpensive +LL | +LL | (arc, arc); + | --- ^^^ value used here after move + | | + | value moved here + | + = note: consider using `Arc::clone` +help: clone the value to increment its reference count + | +LL | (arc.clone(), arc); + | ++++++++ + +error[E0382]: the type `Rc` does not implement `Copy` + --> $DIR/std_impls.rs:22:10 + | +LL | let rc = Rc::new(12); + | -- this move could be avoided by cloning the original `Rc`, which is inexpensive +LL | +LL | (rc, rc); + | -- ^^ value used here after move + | | + | value moved here + | + = note: consider using `Rc::clone` +help: clone the value to increment its reference count + | +LL | (rc.clone(), rc); + | ++++++++ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0382`. From da2ed7788886d9afca74a230f2447993cb85bcdc Mon Sep 17 00:00:00 2001 From: Arjun Ramesh Date: Wed, 22 Apr 2026 12:50:24 -0400 Subject: [PATCH 03/12] Change to LLVM 22 WALI target --- .../rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs b/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs index 9e4121d97eb8d..3c64948ad4a5f 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs @@ -13,7 +13,7 @@ pub(crate) fn target() -> Target { options.add_pre_link_args( LinkerFlavor::WasmLld(Cc::Yes), &[ - "--target=wasm32-wasi-threads", + "--target=wasm32-linux-muslwali", "-Wl,--export-memory,", "-Wl,--shared-memory", "-Wl,--max-memory=1073741824", @@ -21,7 +21,7 @@ pub(crate) fn target() -> Target { ); Target { - llvm_target: "wasm32-wasi".into(), + llvm_target: "wasm32-linux-muslwali".into(), metadata: TargetMetadata { description: Some("WebAssembly Linux Interface with musl-libc".into()), tier: Some(3), From c0441d42ed38ad5b59a8f62bdda53b89d21949f4 Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 17 Apr 2026 06:45:59 +1000 Subject: [PATCH 04/12] Fix Mlibc env pretty print to Managarm C Library --- src/librustdoc/clean/cfg.rs | 2 +- tests/rustdoc-html/doc-cfg/all-targets.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 631a3b47b5574..2fca37b034a87 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -593,7 +593,7 @@ fn human_readable_target_env(env: Symbol) -> Option<&'static str> { // tidy-alphabetical-start Gnu => "GNU", MacAbi => "Catalyst", - Mlibc => "mac ABI", + Mlibc => "Managarm C Library", Msvc => "MSVC", Musl => "musl", Newlib => "Newlib", diff --git a/tests/rustdoc-html/doc-cfg/all-targets.rs b/tests/rustdoc-html/doc-cfg/all-targets.rs index 048d0d4c73d2b..5b61d6164ee56 100644 --- a/tests/rustdoc-html/doc-cfg/all-targets.rs +++ b/tests/rustdoc-html/doc-cfg/all-targets.rs @@ -2,7 +2,7 @@ //@ has all_targets/fn.foo.html \ // '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ -// 'Available on GNU or Catalyst or mac ABI or MSVC or musl or Newlib or \ +// 'Available on GNU or Catalyst or Managarm C Library or MSVC or musl or Newlib or \ // Neutrino 7.0 or Neutrino 7.1 or Neutrino 7.1 with io-sock or Neutrino 8.0 or \ // OpenHarmony or relibc or SGX or Simulator or WASIp1 or WASIp2 or WASIp3 or \ // uClibc or V5 or target_env=fake_env only.' From 140dad0080cfc9968e57b57ef13d106afe91439f Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 17 Apr 2026 07:01:34 +1000 Subject: [PATCH 05/12] Resolve FIXME: os = none is bare metal --- src/librustdoc/clean/cfg.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 2fca37b034a87..ec3407d361ebd 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -516,7 +516,7 @@ fn human_readable_target_os(os: Symbol) -> Option<&'static str> { Managarm => "Managarm", Motor => "Motor OS", NetBsd => "NetBSD", - None => "bare-metal", // FIXME(scrabsha): is this appropriate? + None => "bare-metal", Nto => "QNX Neutrino", NuttX => "NuttX", OpenBsd => "OpenBSD", From 34c0fe87784fdf0ad01aa2cea89e0605c9008818 Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 17 Apr 2026 07:01:53 +1000 Subject: [PATCH 06/12] Fix some typos --- compiler/rustc_target/src/spec/targets/wasm32v1_none.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs b/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs index 8c5a253b0e2f2..629560af0156f 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs @@ -10,7 +10,7 @@ //! those target flags doesn't automatically rebuild libcore / liballoc with //! them, and in order to get those libraries rebuilt you need to use the //! nightly Rust feature `-Zbuild-std`. This target is for people who want to -//! use stable Rust, and target a stable set pf WebAssembly features. +//! use stable Rust, and target a stable set of WebAssembly features. use crate::spec::{Arch, Cc, LinkerFlavor, Os, Target, TargetMetadata, base}; From ce880a47fd5b544e7b23da2066c3ff35796a4074 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Thu, 23 Apr 2026 13:40:45 +0200 Subject: [PATCH 07/12] Document `#[diagnostic::on_move]` in the unstable book --- .../language-features/diagnostic-on-move.md | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 src/doc/unstable-book/src/language-features/diagnostic-on-move.md diff --git a/src/doc/unstable-book/src/language-features/diagnostic-on-move.md b/src/doc/unstable-book/src/language-features/diagnostic-on-move.md new file mode 100644 index 0000000000000..ba35b07361416 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/diagnostic-on-move.md @@ -0,0 +1,92 @@ +# `diagnostic_on_move` + +The tracking issue for this feature is: [#154181] + +------------------------ + +The `diagnostic_on_move` feature allows use of the `#[diagnostic::on_move]` attribute. It should be +placed on struct, enum and union declarations, though it is not an error to be located in other +positions. This attribute is a hint to the compiler to supplement the error message when the +annotated type is involved in a borrowcheck error. + +For example, [`File`] is annotated as such: +```rust +#![feature(diagnostic_on_move)] + +#[diagnostic::on_move(note = "you can use `File::try_clone` \ + to duplicate a `File` instance")] +pub struct File { + // ... +} +``` + +When you try to use a `File` after it's already been moved, it will helpfully tell you about `try_clone`. + +The message and label can also be customized: + +```rust +#![feature(diagnostic_on_move)] + +use std::marker::PhantomData; + +#[diagnostic::on_move( + message = "`{Self}` cannot be used multiple times", + label = "this token may only be used once", + note = "you can create a new `Token` with `Token::conjure()`" +)] +pub struct Token<'brand> { + spooky: PhantomData<&'brand ()>, +} + +impl Token<'_> { + pub fn conjure<'u>() -> Token<'u> { + Token { + spooky: PhantomData, + } + } +} +``` +The user may try to use it like this: +```rust,compile_fail,E0382 +# #![feature(diagnostic_on_move)] +# +# use std::marker::PhantomData; +# +# #[diagnostic::on_move( +# message = "`{Self}` cannot be used multiple times", +# label = "this token may only be used once", +# note = "you can create a new `Token` with `Token::conjure()`" +# )] +# pub struct Token<'brand> { +# spooky: PhantomData<&'brand ()>, +# } +# +# impl Token<'_> { +# pub fn conjure<'u>() -> Token<'u> { +# Token { +# spooky: PhantomData, +# } +# } +# } +# fn main() { +let token = Token::conjure(); +let _ = (token, token); +# } +``` +This will result in the following error: +```text +error[E0382]: `Token` cannot be used multiple times + --> src/main.rs:24:21 + | + 1 | let token = Token::conjure(); + | ----- this token may only be used once + 2 | let _ = (token, token); + | ----- ^^^^^ value used here after move + | | + | value moved here + | + = note: you can create a new `Token` with `Token::conjure()` +``` + +[`File`]: https://doc.rust-lang.org/nightly/std/fs/struct.File.html "File in std::fs" +[#154181]: https://github.com/rust-lang/rust/issues/154181 "Tracking Issue for #[diagnostic::on_move]" From 7f2a98d1fc32aca890c44f1b62e815b09284f9f9 Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Fri, 24 Apr 2026 09:59:20 +0300 Subject: [PATCH 08/12] Rename Self generic param to This in recursive delegations --- compiler/rustc_ast_lowering/src/delegation.rs | 15 ++-- .../src/delegation/generics.rs | 83 +++++++++++++++---- tests/pretty/delegation-self-rename.pp | 55 ++++++++++++ tests/pretty/delegation-self-rename.rs | 32 +++++++ tests/ui/delegation/generics/self-rename.rs | 45 ++++++++++ .../generics/synth-params-ice-154780.rs | 71 +++++++++------- 6 files changed, 242 insertions(+), 59 deletions(-) create mode 100644 tests/pretty/delegation-self-rename.pp create mode 100644 tests/pretty/delegation-self-rename.rs create mode 100644 tests/ui/delegation/generics/self-rename.rs diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 593eac2df4893..3a5b6ad608aa2 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -508,7 +508,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { // FIXME(fn_delegation): proper support for parent generics propagation // in method call scenario. - let segment = self.process_segment(span, &segment, &mut generics.child, false); + let segment = self.process_segment(span, &segment, &mut generics.child); let segment = self.arena.alloc(segment); self.arena.alloc(hir::Expr { @@ -534,14 +534,10 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { new_path.segments = self.arena.alloc_from_iter( new_path.segments.iter().enumerate().map(|(idx, segment)| { - let mut process_segment = |result, add_lifetimes| { - self.process_segment(span, segment, result, add_lifetimes) - }; - if idx + 2 == len { - process_segment(&mut generics.parent, true) + self.process_segment(span, segment, &mut generics.parent) } else if idx + 1 == len { - process_segment(&mut generics.child, false) + self.process_segment(span, segment, &mut generics.child) } else { segment.clone() } @@ -551,7 +547,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { hir::QPath::Resolved(ty, self.arena.alloc(new_path)) } hir::QPath::TypeRelative(ty, segment) => { - let segment = self.process_segment(span, segment, &mut generics.child, false); + let segment = self.process_segment(span, segment, &mut generics.child); hir::QPath::TypeRelative(ty, self.arena.alloc(segment)) } @@ -584,13 +580,12 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { span: Span, segment: &hir::PathSegment<'hir>, result: &mut GenericsGenerationResult<'hir>, - add_lifetimes: bool, ) -> hir::PathSegment<'hir> { let details = result.generics.args_propagation_details(); let segment = if details.should_propagate { let generics = result.generics.into_hir_generics(self, span); - let args = generics.into_generic_args(self, add_lifetimes, span); + let args = generics.into_generic_args(self, span); // Needed for better error messages (`trait-impl-wrong-args-count.rs` test). let args = if args.is_empty() { None } else { Some(args) }; diff --git a/compiler/rustc_ast_lowering/src/delegation/generics.rs b/compiler/rustc_ast_lowering/src/delegation/generics.rs index 201f6bfb4bd63..503877cff9785 100644 --- a/compiler/rustc_ast_lowering/src/delegation/generics.rs +++ b/compiler/rustc_ast_lowering/src/delegation/generics.rs @@ -6,7 +6,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::ty::GenericParamDefKind; use rustc_middle::{bug, ty}; use rustc_span::symbol::kw; -use rustc_span::{Ident, Span}; +use rustc_span::{Ident, Span, sym}; use crate::{LoweringContext, ResolverAstLoweringExt}; @@ -25,22 +25,37 @@ pub(super) enum DelegationGenericsKind { TraitImpl(bool /* Has user-specified args */), } +#[derive(Debug, Clone, Copy)] +pub(super) enum GenericsPosition { + Parent, + Child, +} + pub(super) struct DelegationGenerics { generics: T, kind: DelegationGenericsKind, + pos: GenericsPosition, } impl<'hir> DelegationGenerics<&'hir [ty::GenericParamDef]> { - fn default(generics: &'hir [ty::GenericParamDef]) -> Self { - DelegationGenerics { generics, kind: DelegationGenericsKind::Default } + fn default(generics: &'hir [ty::GenericParamDef], pos: GenericsPosition) -> Self { + DelegationGenerics { generics, pos, kind: DelegationGenericsKind::Default } } - fn user_specified(generics: &'hir [ty::GenericParamDef]) -> Self { - DelegationGenerics { generics, kind: DelegationGenericsKind::UserSpecified } + fn user_specified(generics: &'hir [ty::GenericParamDef], pos: GenericsPosition) -> Self { + DelegationGenerics { generics, pos, kind: DelegationGenericsKind::UserSpecified } } - fn trait_impl(generics: &'hir [ty::GenericParamDef], user_specified: bool) -> Self { - DelegationGenerics { generics, kind: DelegationGenericsKind::TraitImpl(user_specified) } + fn trait_impl( + generics: &'hir [ty::GenericParamDef], + user_specified: bool, + pos: GenericsPosition, + ) -> Self { + DelegationGenerics { + generics, + pos, + kind: DelegationGenericsKind::TraitImpl(user_specified), + } } } @@ -103,8 +118,14 @@ impl<'hir> HirOrTyGenerics<'hir> { span: Span, ) -> &mut HirOrTyGenerics<'hir> { if let HirOrTyGenerics::Ty(ty) = self { - let params = ctx.uplift_delegation_generic_params(span, ty.generics); - *self = HirOrTyGenerics::Hir(DelegationGenerics { generics: params, kind: ty.kind }); + let rename_self = matches!(ty.pos, GenericsPosition::Child); + let params = ctx.uplift_delegation_generic_params(span, ty.generics, rename_self); + + *self = HirOrTyGenerics::Hir(DelegationGenerics { + generics: params, + kind: ty.kind, + pos: ty.pos, + }); } self @@ -120,7 +141,6 @@ impl<'hir> HirOrTyGenerics<'hir> { pub(super) fn into_generic_args( &self, ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>, - add_lifetimes: bool, span: Span, ) -> &'hir hir::GenericArgs<'hir> { match self { @@ -128,6 +148,7 @@ impl<'hir> HirOrTyGenerics<'hir> { bug!("Attempting to get generic args before uplifting to HIR") } HirOrTyGenerics::Hir(hir) => { + let add_lifetimes = matches!(hir.pos, GenericsPosition::Parent); ctx.create_generics_args_from_params(hir.generics.params, add_lifetimes, span) } } @@ -227,10 +248,15 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { if matches!(delegation_parent_kind, DefKind::Impl { of_trait: true }) { // Considering parent generics, during signature inheritance // we will take those args that are in trait impl header trait ref. - let parent = DelegationGenerics::trait_impl(&[], true); + let parent = DelegationGenerics::trait_impl(&[], true, GenericsPosition::Parent); let parent = GenericsGenerationResult::new(parent); - let child = DelegationGenerics::trait_impl(sig_params, child_user_specified); + let child = DelegationGenerics::trait_impl( + sig_params, + child_user_specified, + GenericsPosition::Child, + ); + let child = GenericsGenerationResult::new(child); return GenericsGenerationResults { @@ -263,25 +289,32 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { DelegationGenerics { kind: DelegationGenericsKind::SelfAndUserSpecified, generics: &sig_parent_params[..1], + pos: GenericsPosition::Parent, } } else { - DelegationGenerics::user_specified(&[]) + DelegationGenerics::user_specified(&[], GenericsPosition::Parent) } } else { let skip_self = usize::from(!generate_self); - DelegationGenerics::default(&sig_parent_params[skip_self..]) + DelegationGenerics::default( + &sig_parent_params[skip_self..], + GenericsPosition::Parent, + ) } } else { - DelegationGenerics::default(&[]) + DelegationGenerics::default(&[], GenericsPosition::Parent) }; let child_generics = if child_user_specified { let synth_params_index = sig_params.iter().position(|p| p.kind.is_synthetic()).unwrap_or(sig_params.len()); - DelegationGenerics::user_specified(&sig_params[synth_params_index..]) + DelegationGenerics::user_specified( + &sig_params[synth_params_index..], + GenericsPosition::Child, + ) } else { - DelegationGenerics::default(sig_params) + DelegationGenerics::default(sig_params, GenericsPosition::Child) }; GenericsGenerationResults { @@ -296,6 +329,7 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { &mut self, span: Span, params: &'hir [ty::GenericParamDef], + rename_self: bool, ) -> &'hir hir::Generics<'hir> { let params = self.arena.alloc_from_iter(params.iter().map(|p| { let def_kind = match p.kind { @@ -304,7 +338,20 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> { GenericParamDefKind::Const { .. } => DefKind::ConstParam, }; - let param_ident = Ident::new(p.name, span); + // Rename Self generic param to This so it is properly propagated. + // If the user will create a function `fn foo() {}` with generic + // param "Self" then it will not be generated in HIR, the same thing + // applies to traits, `trait Trait {}` will be represented as + // `trait Trait {}` in HIR and "unexpected keyword `Self` in generic parameters" + // error will be emitted. + // Note that we do not rename `Self` to `This` after non-recursive reuse + // from Trait, in this case the `Self` should not be propagated + // (we rely that implicit `Self` generic param of a trait is named "Self") + // and it is OK to have Self generic param generated during lowering. + let param_name = + if rename_self && p.name == kw::SelfUpper { sym::This } else { p.name }; + + let param_ident = Ident::new(param_name, span); let def_name = Some(param_ident.name); let node_id = self.next_node_id(); diff --git a/tests/pretty/delegation-self-rename.pp b/tests/pretty/delegation-self-rename.pp new file mode 100644 index 0000000000000..59a07315185c7 --- /dev/null +++ b/tests/pretty/delegation-self-rename.pp @@ -0,0 +1,55 @@ +#![attr = Feature([fn_delegation#0])] +extern crate std; +#[attr = PreludeImport] +use ::std::prelude::rust_2015::*; +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:delegation-self-rename.pp + + +trait Trait<'a, A, const B: bool> { + fn foo<'b, const B2: bool, T, U, + impl FnOnce() -> usize>(&self, f: impl FnOnce() -> usize) -> usize + where impl FnOnce() -> usize: FnOnce() -> usize { f() + 1 } +} + +struct X; +impl <'a, A, const B: bool> Trait<'a, A, B> for X { } + +#[attr = Inline(Hint)] +fn foo<'a, Self, A, const B: _, const B2: _, T, U, + impl FnOnce() -> usize>(self: _, arg1: _) -> _ where + 'a:'a { self.foo::(arg1) } +#[attr = Inline(Hint)] +fn bar usize>(self: _, arg1: _) + -> _ { Trait::<'static, (), true>::foo::(self, arg1) } + +#[attr = Inline(Hint)] +fn foo2<'a, This, A, const B: _, const B2: _, T, U, + impl FnOnce() -> usize>(arg0: _, arg1: _) -> _ where + 'a:'a { foo::(arg0, arg1) } +#[attr = Inline(Hint)] +fn bar2 usize>(arg0: _, arg1: _) + -> _ { bar::(arg0, arg1) } + +trait Trait2 { + #[attr = Inline(Hint)] + fn foo3<'a, This, A, const B: _, const B2: _, T, U, + impl FnOnce() -> usize>(arg0: _, arg1: _) -> _ where + 'a:'a { foo2::(arg0, arg1) } + #[attr = Inline(Hint)] + fn bar3 usize>(arg0: _, arg1: _) + -> _ { bar2::(arg0, arg1) } +} + +impl Trait2 for () { } + +#[attr = Inline(Hint)] +fn foo4<'a, This, A, const B: _, const B2: _, T, U, + impl FnOnce() -> usize>(arg0: _, arg1: _) -> _ where + 'a:'a { <() as Trait2>::foo3::(arg0, arg1) } +#[attr = Inline(Hint)] +fn bar4 usize>(arg0: _, arg1: _) + -> _ { <() as Trait2>::bar3::(arg0, arg1) } + +fn main() { } diff --git a/tests/pretty/delegation-self-rename.rs b/tests/pretty/delegation-self-rename.rs new file mode 100644 index 0000000000000..9054bb2b89571 --- /dev/null +++ b/tests/pretty/delegation-self-rename.rs @@ -0,0 +1,32 @@ +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:delegation-self-rename.pp + +#![feature(fn_delegation)] + +trait Trait<'a, A, const B: bool> { + fn foo<'b, const B2: bool, T, U>(&self, f: impl FnOnce() -> usize) -> usize { + f() + 1 + } +} + +struct X; +impl<'a, A, const B: bool> Trait<'a, A, B> for X {} + +reuse Trait::foo; +reuse Trait::<'static, (), true>::foo:: as bar; + +reuse foo as foo2; +reuse bar as bar2; + +trait Trait2 { + reuse foo2 as foo3; + reuse bar2 as bar3; +} + +impl Trait2 for () {} + +reuse <() as Trait2>::foo3 as foo4; +reuse <() as Trait2>::bar3 as bar4; + +fn main() {} diff --git a/tests/ui/delegation/generics/self-rename.rs b/tests/ui/delegation/generics/self-rename.rs new file mode 100644 index 0000000000000..a4c92cecb5c6b --- /dev/null +++ b/tests/ui/delegation/generics/self-rename.rs @@ -0,0 +1,45 @@ +//@ run-pass + +#![feature(fn_delegation)] + +trait Trait<'a, A, const B: bool> { + fn foo<'b, const B2: bool, T, U>(&self, f: impl FnOnce() -> usize) -> usize { + f() + 1 + } +} + +struct X; +impl<'a, A, const B: bool> Trait<'a, A, B> for X {} + +reuse Trait::foo; +reuse Trait::<'static, (), true>::foo:: as bar; + +reuse foo as foo2; +reuse bar as bar2; + +trait Trait2 { + reuse foo2 as foo3; + reuse bar2 as bar3; +} + +impl Trait2 for () {} + +reuse <() as Trait2>::foo3 as foo4; +reuse <() as Trait2>::bar3 as bar4; + +fn main() { + assert_eq!(foo::<'static, X, (), true, false, (), ()>(&X, || 123), 124); + assert_eq!(foo2::<'static, X, (), true, false, (), ()>(&X, || 123), 124); + assert_eq!(<()>::foo3::<'static, X, (), true, false, (), ()>(&X, || 123), 124); + assert_eq!(foo4::<'static, X, (), true, false, (), ()>(&X, || 123), 124); + + assert_eq!(bar::(&X, || 123), 124); + assert_eq!(bar2::(&X, || 123), 124); + assert_eq!(<()>::bar3::(&X, || 123), 124); + assert_eq!(bar4::(&X, || 123), 124); + + assert_eq!(bar(&X, || 123), 124); + assert_eq!(bar2(&X, || 123), 124); + assert_eq!(<()>::bar3(&X, || 123), 124); + assert_eq!(bar4::(&X, || 123), 124); +} diff --git a/tests/ui/delegation/generics/synth-params-ice-154780.rs b/tests/ui/delegation/generics/synth-params-ice-154780.rs index 3ea52818a8f08..ef8684698612f 100644 --- a/tests/ui/delegation/generics/synth-params-ice-154780.rs +++ b/tests/ui/delegation/generics/synth-params-ice-154780.rs @@ -62,40 +62,49 @@ mod test_3 { } } -// FIXME(fn_delegation): rename Self generic param in recursive delegations -// mod test_4 { -// trait Trait<'a, A, const B: bool> { -// fn foo<'b, const B2: bool, T, U>(&self, f: impl FnOnce() -> usize) -> usize { -// f() -// } -// } - -// struct X; -// impl<'a, A, const B: bool> Trait<'a, A, B> for X {} - -// reuse Trait::foo; -// reuse Trait::<'static, (), true>::foo:: as bar; - -// trait Trait2 { -// reuse foo; -// reuse bar; -// } - -// reuse Trait2::foo as foo2; -// reuse Trait2::foo::<'static, X, (), true, false, (), ()> as foo3; -// reuse Trait2::bar as bar2; -// reuse Trait2::bar:: as bar3; - -// pub fn check() { -// assert_eq!(foo::<'static, X, (), true, false, (), ()>(&X, || 123), 123); -// assert_eq!(bar::(&X, || 123), 123); -// assert_eq!(bar(&X, || 123), 123); -// } -// } +// Test recursive delegation through trait +mod test_4 { + trait Trait<'a, A, const B: bool> { + fn foo<'b, const B2: bool, T, U>(&self, f: impl FnOnce() -> usize) -> usize { + f() + } + } + + struct X; + impl<'a, A, const B: bool> Trait<'a, A, B> for X {} + + reuse Trait::foo; + reuse Trait::<'static, (), true>::foo:: as bar; + + trait Trait2 { + reuse foo; + reuse bar; + } + + impl Trait2 for () {} + + reuse <() as Trait2>::foo as foo2; + reuse <() as Trait2>::foo::<'static, X, (), true, false, (), ()> as foo3; + reuse <() as Trait2>::bar as bar2; + reuse <() as Trait2>::bar:: as bar3; + + pub fn check() { + assert_eq!(foo::<'static, X, (), true, false, (), ()>(&X, || 123), 123); + assert_eq!(bar::(&X, || 123), 123); + assert_eq!(bar(&X, || 123), 123); + + assert_eq!(foo2::<'static, X, (), true, false, (), ()>(&X, || 123), 123); + assert_eq!(bar2::(&X, || 123), 123); + assert_eq!(bar2(&X, || 123), 123); + + assert_eq!(foo3(&X, || 123), 123); + assert_eq!(bar3(&X, || 123), 123); + } +} fn main() { test_1::check(); test_2::check(); test_3::check(); - // test_4::check(); + test_4::check(); } From 150905c3de2608e3ad793dda07f81ec25670e872 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 24 Apr 2026 02:10:49 +0000 Subject: [PATCH 09/12] test: Add a regression test for Apple platforms aborting on `free` Add a regression test for RUST-150898 to make users aware that if this test fails, they may encounter unusual behavior elsewhere. Original repro authored by dianqk. --- .../regression-abort-on-free-issue-150898.rs | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 tests/ui/allocator/regression-abort-on-free-issue-150898.rs diff --git a/tests/ui/allocator/regression-abort-on-free-issue-150898.rs b/tests/ui/allocator/regression-abort-on-free-issue-150898.rs new file mode 100644 index 0000000000000..41a7695bee77c --- /dev/null +++ b/tests/ui/allocator/regression-abort-on-free-issue-150898.rs @@ -0,0 +1,59 @@ +// Regression test for https://github.com/rust-lang/rust/issues/150898 +// +// This test fails on Apple platforms with versions containing an allocator +// bug. If this fails with SIGABRT, you may need to upgrade your system to +// avoid other unexpected behavior. +// +// Note that the failure is non-deterministic so this test may pass even in +// conditions where the bug is present. That being said, on the author's +// machine this has a 100% rate of hitting the crash on at least a couple +// threads. +// +// The bug was resolved by macOS 26.4. + +//@ run-pass +//@ only-aarch64-apple-darwin +//@ compile-flags: -C opt-level=1 -C codegen-units=1 + +use std::thread; + +fn main() { + // Running with multiple threads substantially increases the change of + // hitting the bug. + thread::scope(|s| { + for _ in 0..10 { + s.spawn(run); + } + }); +} + +fn run() { + // This doesn't always fail, so rerun a few times + for _ in 0..100 { + unsafe { + core::arch::asm!( + " + // Alloc 18 bytes + mov x0, #18 + bl _malloc + // Save the pointer to x21 + mov x21, x0 + // Alloc 18 bytes again + mov x0, #18 + bl _malloc + // Store the contents of `x13` to the second allocation. `x13` is the + // magic register to cause the crash, other registers work well. + str x13, [x0] + // Free the pointers + bl _free + mov x0, x21 + bl _free + ", + out("x0") _, + out("x13") _, + out("x21") _, + clobber_abi("C"), + ) + } + } +} From e90878b9f25133c727b434b9002b26c0ec63e5b6 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 21 Apr 2026 12:44:13 +0200 Subject: [PATCH 10/12] All nested statics in a single interning run have the same parent So we do not need to disambiguate considering parents --- .../rustc_const_eval/src/interpret/intern.rs | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 57139d077d493..2f27b7e5082f2 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -16,10 +16,7 @@ use hir::def::DefKind; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; -use rustc_hir::def_id::LocalDefIdMap; -use rustc_hir::definitions::{ - DefPathData, PerParentDisambiguatorState, PerParentDisambiguatorsMap, -}; +use rustc_hir::definitions::{DefPathData, PerParentDisambiguatorState}; use rustc_hir::{self as hir}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::mir::interpret::{ @@ -108,7 +105,7 @@ fn intern_shallow<'tcx, M: CompileTimeMachine<'tcx>>( ecx: &mut InterpCx<'tcx, M>, alloc_id: AllocId, mutability: Mutability, - disambiguators: Option<&mut LocalDefIdMap>, + disambiguator: Option<&mut PerParentDisambiguatorState>, ) -> Result + 'tcx, InternError> { trace!("intern_shallow {:?}", alloc_id); // remove allocation @@ -132,7 +129,7 @@ fn intern_shallow<'tcx, M: CompileTimeMachine<'tcx>>( static_id, alloc_id, alloc, - disambiguators.expect("disambiguators needed"), + disambiguator.expect("disambiguator needed"), ); } else { ecx.tcx.set_alloc_id_memory(alloc_id, alloc); @@ -147,19 +144,18 @@ fn intern_as_new_static<'tcx>( static_id: LocalDefId, alloc_id: AllocId, alloc: ConstAllocation<'tcx>, - disambiguators: &mut LocalDefIdMap, + disambiguator: &mut PerParentDisambiguatorState, ) { - // `intern_const_alloc_recursive` is called once per static and it contains the `DisambiguatorState`. + // `intern_const_alloc_recursive` is called once per static and it contains the `PerParentDisambiguatorState`. // The `::{{nested}}` path is thus unique to `intern_const_alloc_recursive` and the - // `DisambiguatorState` ensures the generated path is unique for this call as we generate + // `PerParentDisambiguatorState` ensures the generated path is unique for this call as we generate // `::{{nested#n}}` where `n` is the `n`th `intern_as_new_static` call. let feed = tcx.create_def( static_id, None, DefKind::Static { safety: hir::Safety::Safe, mutability: alloc.0.mutability, nested: true }, Some(DefPathData::NestedStatic), - //FIXME(oli-obk): cleanup (https://github.com/rust-lang/rust/pull/155547#discussion_r3110792640) - disambiguators.get_or_create(static_id), + disambiguator, ); tcx.set_nested_alloc_id_static(alloc_id, feed.def_id()); @@ -209,7 +205,9 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx>>( intern_kind: InternKind, ret: &MPlaceTy<'tcx>, ) -> Result<(), InternError> { - let mut disambiguators = Default::default(); + let mut disambiguator = + ecx.machine.static_def_id().map(|id| PerParentDisambiguatorState::new(id)); + let mut disambiguator = disambiguator.as_mut(); // We are interning recursively, and for mutability we are distinguishing the "root" allocation // that we are starting in, and all other allocations that we are encountering recursively. @@ -248,13 +246,15 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx>>( // This gives us the initial set of nested allocations, which will then all be processed // recursively in the loop below. let mut todo: Vec<_> = if is_static { + assert!(disambiguator.is_some()); // Do not steal the root allocation, we need it later to create the return value of `eval_static_initializer`. // But still change its mutability to match the requested one. let (kind, alloc) = ecx.memory.alloc_map.get_mut(&base_alloc_id).unwrap(); prepare_alloc(*ecx.tcx, *kind, alloc, base_mutability)?; alloc.provenance().ptrs().iter().map(|&(_, prov)| prov).collect() } else { - intern_shallow(ecx, base_alloc_id, base_mutability, Some(&mut disambiguators))?.collect() + assert!(disambiguator.is_none()); + intern_shallow(ecx, base_alloc_id, base_mutability, None)?.collect() }; // We need to distinguish "has just been interned" from "was already in `tcx`", // so we track this in a separate set. @@ -336,7 +336,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx>>( // okay with losing some potential for immutability here. This can anyway only affect // `static mut`. just_interned.insert(alloc_id); - let next = intern_shallow(ecx, alloc_id, inner_mutability, Some(&mut disambiguators))?; + let next = intern_shallow(ecx, alloc_id, inner_mutability, disambiguator.as_deref_mut())?; todo.extend(next); } if found_bad_mutable_ptr { From bfb085da9fa218a45a7bae9f68d731aa48b2ae77 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 24 Apr 2026 12:50:21 +0200 Subject: [PATCH 11/12] All generated associated types for opaque types in traits/impls have the same parent --- compiler/rustc_ty_utils/src/assoc.rs | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 1d24a207103c8..443f33aaa0b01 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -1,8 +1,6 @@ use rustc_hir::def::DefKind; -use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LocalDefIdMap}; -use rustc_hir::definitions::{ - DefPathData, PerParentDisambiguatorState, PerParentDisambiguatorsMap, -}; +use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; +use rustc_hir::definitions::{DefPathData, PerParentDisambiguatorState}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self as hir, ConstItemRhs, ImplItemImplKind, ItemKind}; use rustc_middle::query::Providers; @@ -131,7 +129,7 @@ struct RPITVisitor<'a, 'tcx> { tcx: TyCtxt<'tcx>, synthetics: Vec, data: DefPathData, - disambiguators: &'a mut LocalDefIdMap, + disambiguator: &'a mut PerParentDisambiguatorState, } impl<'tcx> Visitor<'tcx> for RPITVisitor<'_, 'tcx> { @@ -140,7 +138,7 @@ impl<'tcx> Visitor<'tcx> for RPITVisitor<'_, 'tcx> { self.tcx, opaque.def_id, self.data, - &mut self.disambiguators, + &mut self.disambiguator, )); intravisit::walk_opaque_ty(self, opaque) } @@ -151,7 +149,7 @@ fn associated_types_for_impl_traits_in_trait_or_impl<'tcx>( def_id: LocalDefId, ) -> DefIdMap> { let item = tcx.hir_expect_item(def_id); - let disambiguators = &mut Default::default(); + let disambiguator = &mut PerParentDisambiguatorState::new(def_id); match item.kind { ItemKind::Trait(.., trait_item_refs) => trait_item_refs .iter() @@ -165,7 +163,7 @@ fn associated_types_for_impl_traits_in_trait_or_impl<'tcx>( }; let def_name = tcx.item_name(fn_def_id.to_def_id()); let data = DefPathData::AnonAssocTy(def_name); - let mut visitor = RPITVisitor { tcx, synthetics: vec![], data, disambiguators }; + let mut visitor = RPITVisitor { tcx, synthetics: vec![], data, disambiguator }; visitor.visit_fn_ret_ty(output); let defs = visitor .synthetics @@ -199,7 +197,7 @@ fn associated_types_for_impl_traits_in_trait_or_impl<'tcx>( return Some((did, vec![])); }; let iter = in_trait_def[&trait_item_def_id].iter().map(|&id| { - associated_type_for_impl_trait_in_impl(tcx, id, item, disambiguators) + associated_type_for_impl_trait_in_impl(tcx, id, item, disambiguator) .to_def_id() }); Some((did, iter.collect())) @@ -223,7 +221,7 @@ fn associated_type_for_impl_trait_in_trait( tcx: TyCtxt<'_>, opaque_ty_def_id: LocalDefId, data: DefPathData, - disambiguators: &mut LocalDefIdMap, + disambiguator: &mut PerParentDisambiguatorState, ) -> LocalDefId { let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. } | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. }) = @@ -242,7 +240,7 @@ fn associated_type_for_impl_trait_in_trait( None, DefKind::AssocTy, Some(data), - disambiguators.get_or_create(trait_def_id), + disambiguator, ); let local_def_id = trait_assoc_ty.def_id(); @@ -285,7 +283,7 @@ fn associated_type_for_impl_trait_in_impl( tcx: TyCtxt<'_>, trait_assoc_def_id: DefId, impl_fn: &hir::ImplItem<'_>, - disambiguators: &mut LocalDefIdMap, + disambiguator: &mut PerParentDisambiguatorState, ) -> LocalDefId { let impl_local_def_id = tcx.local_parent(impl_fn.owner_id.def_id); @@ -308,7 +306,7 @@ fn associated_type_for_impl_trait_in_impl( None, DefKind::AssocTy, Some(data), - disambiguators.get_or_create(impl_local_def_id), + disambiguator, ); let local_def_id = impl_assoc_ty.def_id(); From ece632c9f7afdf4b5c07ee2e48c347ed0a71d401 Mon Sep 17 00:00:00 2001 From: Makai Date: Fri, 24 Apr 2026 21:25:20 +0800 Subject: [PATCH 12/12] Remove `AllVariants` workaround for rust-analyzer --- compiler/rustc_session/src/config/print_request.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/compiler/rustc_session/src/config/print_request.rs b/compiler/rustc_session/src/config/print_request.rs index dc53fcc6955f7..b87236cef7646 100644 --- a/compiler/rustc_session/src/config/print_request.rs +++ b/compiler/rustc_session/src/config/print_request.rs @@ -50,11 +50,6 @@ pub enum PrintKind { } impl PrintKind { - /// FIXME: rust-analyzer doesn't support `#![feature(macro_derive)]` yet - /// (), which breaks autocomplete. - /// Work around that by aliasing the trait constant to a regular constant. - const ALL_VARIANTS: &[Self] = ::ALL_VARIANTS; - fn name(self) -> &'static str { use PrintKind::*; match self {