From eb2913b01b3e423b2bcd73cc62406ffecbe59ea3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?=
Date: Thu, 19 Jun 2025 21:55:55 +0200
Subject: [PATCH 01/17] Fix unsoundness in some tests
---
library/coretests/tests/io/borrowed_buf.rs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/library/coretests/tests/io/borrowed_buf.rs b/library/coretests/tests/io/borrowed_buf.rs
index fbd3864dcac14..8fbf9c3e8a2ad 100644
--- a/library/coretests/tests/io/borrowed_buf.rs
+++ b/library/coretests/tests/io/borrowed_buf.rs
@@ -66,7 +66,7 @@ fn clear() {
#[test]
fn set_init() {
- let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16];
+ let buf: &mut [_] = &mut [MaybeUninit::zeroed(); 16];
let mut rbuf: BorrowedBuf<'_> = buf.into();
unsafe {
@@ -134,7 +134,7 @@ fn reborrow_written() {
#[test]
fn cursor_set_init() {
- let buf: &mut [_] = &mut [MaybeUninit::uninit(); 16];
+ let buf: &mut [_] = &mut [MaybeUninit::zeroed(); 16];
let mut rbuf: BorrowedBuf<'_> = buf.into();
unsafe {
From 7ead5764a88d91803db898e679dd49f2520cdae6 Mon Sep 17 00:00:00 2001
From: Scott McMurray
Date: Sat, 26 Jul 2025 13:22:24 -0700
Subject: [PATCH 02/17] Implement `ptr_cast_array`
---
library/core/src/ptr/const_ptr.rs | 9 +++++++++
library/core/src/ptr/mut_ptr.rs | 9 +++++++++
library/core/src/ptr/non_null.rs | 7 +++++++
3 files changed, 25 insertions(+)
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 2ad520b7ead72..90d08f60a0451 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -1547,6 +1547,15 @@ impl *const [T] {
}
}
+impl *const T {
+ /// Casts from a pointer-to-`T` to a pointer-to-`[T; N]`.
+ #[inline]
+ #[unstable(feature = "ptr_cast_array", issue = "144514")]
+ pub const fn cast_array(self) -> *const [T; N] {
+ self.cast()
+ }
+}
+
impl *const [T; N] {
/// Returns a raw pointer to the array's buffer.
///
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 579e2461103d8..dec212d04c96f 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -1965,6 +1965,15 @@ impl *mut [T] {
}
}
+impl *mut T {
+ /// Casts from a pointer-to-`T` to a pointer-to-`[T; N]`.
+ #[inline]
+ #[unstable(feature = "ptr_cast_array", issue = "144514")]
+ pub const fn cast_array(self) -> *mut [T; N] {
+ self.cast()
+ }
+}
+
impl *mut [T; N] {
/// Returns a raw pointer to the array's buffer.
///
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 62da6567cca75..245a0a08321cf 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -193,6 +193,13 @@ impl NonNull {
// requirements for a reference.
unsafe { &mut *self.cast().as_ptr() }
}
+
+ /// Casts from a pointer-to-`T` to a pointer-to-`[T; N]`.
+ #[inline]
+ #[unstable(feature = "ptr_cast_array", issue = "144514")]
+ pub const fn cast_array(self) -> NonNull<[T; N]> {
+ self.cast()
+ }
}
impl NonNull {
From 51b0416c19f436393b3c070cc037a8f062bcbd83 Mon Sep 17 00:00:00 2001
From: Scott McMurray
Date: Sat, 26 Jul 2025 13:26:53 -0700
Subject: [PATCH 03/17] Use `cast_array` in core
---
library/core/src/slice/mod.rs | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 6fe5affc48be7..13e182b5f87a4 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -330,7 +330,7 @@ impl [T] {
} else {
// SAFETY: We explicitly check for the correct number of elements,
// and do not let the reference outlive the slice.
- Some(unsafe { &*(self.as_ptr().cast::<[T; N]>()) })
+ Some(unsafe { &*(self.as_ptr().cast_array()) })
}
}
@@ -361,7 +361,7 @@ impl [T] {
// SAFETY: We explicitly check for the correct number of elements,
// do not let the reference outlive the slice,
// and require exclusive access to the entire slice to mutate the chunk.
- Some(unsafe { &mut *(self.as_mut_ptr().cast::<[T; N]>()) })
+ Some(unsafe { &mut *(self.as_mut_ptr().cast_array()) })
}
}
@@ -389,7 +389,7 @@ impl [T] {
// SAFETY: We explicitly check for the correct number of elements,
// and do not let the references outlive the slice.
- Some((unsafe { &*(first.as_ptr().cast::<[T; N]>()) }, tail))
+ Some((unsafe { &*(first.as_ptr().cast_array()) }, tail))
}
/// Returns a mutable array reference to the first `N` items in the slice and the remaining
@@ -422,7 +422,7 @@ impl [T] {
// SAFETY: We explicitly check for the correct number of elements,
// do not let the reference outlive the slice,
// and enforce exclusive mutability of the chunk by the split.
- Some((unsafe { &mut *(first.as_mut_ptr().cast::<[T; N]>()) }, tail))
+ Some((unsafe { &mut *(first.as_mut_ptr().cast_array()) }, tail))
}
/// Returns an array reference to the last `N` items in the slice and the remaining slice.
@@ -450,7 +450,7 @@ impl [T] {
// SAFETY: We explicitly check for the correct number of elements,
// and do not let the references outlive the slice.
- Some((init, unsafe { &*(last.as_ptr().cast::<[T; N]>()) }))
+ Some((init, unsafe { &*(last.as_ptr().cast_array()) }))
}
/// Returns a mutable array reference to the last `N` items in the slice and the remaining
@@ -484,7 +484,7 @@ impl [T] {
// SAFETY: We explicitly check for the correct number of elements,
// do not let the reference outlive the slice,
// and enforce exclusive mutability of the chunk by the split.
- Some((init, unsafe { &mut *(last.as_mut_ptr().cast::<[T; N]>()) }))
+ Some((init, unsafe { &mut *(last.as_mut_ptr().cast_array()) }))
}
/// Returns an array reference to the last `N` items in the slice.
@@ -513,7 +513,7 @@ impl [T] {
// SAFETY: We explicitly check for the correct number of elements,
// and do not let the references outlive the slice.
- Some(unsafe { &*(last.as_ptr().cast::<[T; N]>()) })
+ Some(unsafe { &*(last.as_ptr().cast_array()) })
}
/// Returns a mutable array reference to the last `N` items in the slice.
@@ -544,7 +544,7 @@ impl [T] {
// SAFETY: We explicitly check for the correct number of elements,
// do not let the reference outlive the slice,
// and require exclusive access to the entire slice to mutate the chunk.
- Some(unsafe { &mut *(last.as_mut_ptr().cast::<[T; N]>()) })
+ Some(unsafe { &mut *(last.as_mut_ptr().cast_array()) })
}
/// Returns a reference to an element or subslice depending on the type of
@@ -848,7 +848,7 @@ impl [T] {
#[must_use]
pub const fn as_array(&self) -> Option<&[T; N]> {
if self.len() == N {
- let ptr = self.as_ptr() as *const [T; N];
+ let ptr = self.as_ptr().cast_array();
// SAFETY: The underlying array of a slice can be reinterpreted as an actual array `[T; N]` if `N` is not greater than the slice's length.
let me = unsafe { &*ptr };
@@ -866,7 +866,7 @@ impl [T] {
#[must_use]
pub const fn as_mut_array(&mut self) -> Option<&mut [T; N]> {
if self.len() == N {
- let ptr = self.as_mut_ptr() as *mut [T; N];
+ let ptr = self.as_mut_ptr().cast_array();
// SAFETY: The underlying array of a slice can be reinterpreted as an actual array `[T; N]` if `N` is not greater than the slice's length.
let me = unsafe { &mut *ptr };
From f7e46f9d603010be83b3302500c65130a5186782 Mon Sep 17 00:00:00 2001
From: Marco Cavenati
Date: Tue, 5 Aug 2025 15:35:59 +0200
Subject: [PATCH 04/17] fix(unicode-table-generator): fix duplicated unique
indices
unicode-table-generator panicked while populating distinct_indices
because of duplicated indices. This was introduced by swapping the
order of canonical_words.push(...) and canonical_words.len().
---
src/tools/unicode-table-generator/src/raw_emitter.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/tools/unicode-table-generator/src/raw_emitter.rs b/src/tools/unicode-table-generator/src/raw_emitter.rs
index e9e0efc459442..03ed9499e26c5 100644
--- a/src/tools/unicode-table-generator/src/raw_emitter.rs
+++ b/src/tools/unicode-table-generator/src/raw_emitter.rs
@@ -341,7 +341,7 @@ impl Canonicalized {
for &w in unique_words {
unique_mapping.entry(w).or_insert_with(|| {
canonical_words.push(w);
- UniqueMapping::Canonical(canonical_words.len())
+ UniqueMapping::Canonical(canonical_words.len() - 1)
});
}
assert_eq!(canonicalized_words.len() + canonical_words.len(), unique_words.len());
From c503487a6f1402ed37051e435af0c410a3815b14 Mon Sep 17 00:00:00 2001
From: Josh Triplett
Date: Sat, 9 Aug 2025 11:53:30 -0700
Subject: [PATCH 05/17] Avoid abbreviating "numerator" as "numer", to allow
catching typo "numer" elsewhere
`typos.toml` has an exception for "numer", to avoid flagging its use as
an abbreviation for "numerator". Remove the use of that abbrevation,
spelling out "numerator" instead, and remove the exception, so that typo
checks can find future instances of "numer" as a typo for "number".
---
library/std/src/sys_common/mod.rs | 13 ++++++-------
src/tools/miri/src/shims/time.rs | 4 ++--
typos.toml | 1 -
3 files changed, 8 insertions(+), 10 deletions(-)
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index cce88d936b71b..24b6cff130974 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -51,17 +51,16 @@ pub trait FromInner {
fn from_inner(inner: Inner) -> Self;
}
-// Computes (value*numer)/denom without overflow, as long as both
-// (numer*denom) and the overall result fit into i64 (which is the case
-// for our time conversions).
+// Computes (value*numerator)/denom without overflow, as long as both (numerator*denom) and the
+// overall result fit into i64 (which is the case for our time conversions).
#[allow(dead_code)] // not used on all platforms
-pub fn mul_div_u64(value: u64, numer: u64, denom: u64) -> u64 {
+pub fn mul_div_u64(value: u64, numerator: u64, denom: u64) -> u64 {
let q = value / denom;
let r = value % denom;
// Decompose value as (value/denom*denom + value%denom),
- // substitute into (value*numer)/denom and simplify.
- // r < denom, so (denom*numer) is the upper bound of (r*numer)
- q * numer + r * numer / denom
+ // substitute into (value*numerator)/denom and simplify.
+ // r < denom, so (denom*numerator) is the upper bound of (r*numerator)
+ q * numerator + r * numerator / denom
}
pub fn ignore_notfound(result: crate::io::Result) -> crate::io::Result<()> {
diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs
index b5b35797fec2f..6e56fdfe35aef 100644
--- a/src/tools/miri/src/shims/time.rs
+++ b/src/tools/miri/src/shims/time.rs
@@ -322,8 +322,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Since our emulated ticks in `mach_absolute_time` *are* nanoseconds,
// no scaling needs to happen.
- let (numer, denom) = (1, 1);
- this.write_int_fields(&[numer.into(), denom.into()], &info)?;
+ let (numerator, denom) = (1, 1);
+ this.write_int_fields(&[numerator.into(), denom.into()], &info)?;
interp_ok(Scalar::from_i32(0)) // KERN_SUCCESS
}
diff --git a/typos.toml b/typos.toml
index 4035f206a4663..317aafc861565 100644
--- a/typos.toml
+++ b/typos.toml
@@ -52,7 +52,6 @@ ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC = "ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC"
ERROR_MCA_OCCURED = "ERROR_MCA_OCCURED"
ERRNO_ACCES = "ERRNO_ACCES"
tolen = "tolen"
-numer = "numer"
[default]
extend-ignore-words-re = [
From 99769bc301d6e9187d0e7881bb36162fd48fd573 Mon Sep 17 00:00:00 2001
From: Stypox
Date: Thu, 31 Jul 2025 12:16:18 +0200
Subject: [PATCH 06/17] Add tracing to resolve-related functions
---
.../rustc_const_eval/src/interpret/call.rs | 23 ++++++++-----
.../rustc_const_eval/src/interpret/cast.rs | 34 +++++++++++--------
.../src/interpret/eval_context.rs | 1 +
.../rustc_const_eval/src/interpret/step.rs | 6 +++-
src/tools/miri/src/helpers.rs | 2 ++
5 files changed, 43 insertions(+), 23 deletions(-)
diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs
index a0160d1188d08..18c145db6afb1 100644
--- a/compiler/rustc_const_eval/src/interpret/call.rs
+++ b/compiler/rustc_const_eval/src/interpret/call.rs
@@ -736,13 +736,16 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let existential_trait_ref = ty::ExistentialTraitRef::erase_self_ty(tcx, virtual_trait_ref);
let concrete_trait_ref = existential_trait_ref.with_self_ty(tcx, dyn_ty);
- let concrete_method = Instance::expect_resolve_for_vtable(
- tcx,
- self.typing_env,
- def_id,
- virtual_instance.args.rebase_onto(tcx, trait_def_id, concrete_trait_ref.args),
- self.cur_span(),
- );
+ let concrete_method = {
+ let _trace = enter_trace_span!(M, resolve::expect_resolve_for_vtable, ?def_id);
+ Instance::expect_resolve_for_vtable(
+ tcx,
+ self.typing_env,
+ def_id,
+ virtual_instance.args.rebase_onto(tcx, trait_def_id, concrete_trait_ref.args),
+ self.cur_span(),
+ )
+ };
assert_eq!(concrete_instance, concrete_method);
}
@@ -825,7 +828,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
place
}
};
- let instance = ty::Instance::resolve_drop_in_place(*self.tcx, place.layout.ty);
+ let instance = {
+ let _trace =
+ enter_trace_span!(M, resolve::resolve_drop_in_place, ty = ?place.layout.ty);
+ ty::Instance::resolve_drop_in_place(*self.tcx, place.layout.ty)
+ };
let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?;
let arg = self.mplace_to_ref(&place)?;
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index de4fbc7b4752e..e3afeda5b7c97 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -16,8 +16,8 @@ use super::{
FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy, err_inval, interp_ok, throw_ub,
throw_ub_custom,
};
-use crate::fluent_generated as fluent;
use crate::interpret::Writeable;
+use crate::{enter_trace_span, fluent_generated as fluent};
impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
pub fn cast(
@@ -81,13 +81,16 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// The src operand does not matter, just its type
match *src.layout.ty.kind() {
ty::FnDef(def_id, args) => {
- let instance = ty::Instance::resolve_for_fn_ptr(
- *self.tcx,
- self.typing_env,
- def_id,
- args,
- )
- .ok_or_else(|| err_inval!(TooGeneric))?;
+ let instance = {
+ let _trace = enter_trace_span!(M, resolve::resolve_for_fn_ptr, ?def_id);
+ ty::Instance::resolve_for_fn_ptr(
+ *self.tcx,
+ self.typing_env,
+ def_id,
+ args,
+ )
+ .ok_or_else(|| err_inval!(TooGeneric))?
+ };
let fn_ptr = self.fn_ptr(FnVal::Instance(instance));
self.write_pointer(fn_ptr, dest)?;
@@ -114,12 +117,15 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// The src operand does not matter, just its type
match *src.layout.ty.kind() {
ty::Closure(def_id, args) => {
- let instance = ty::Instance::resolve_closure(
- *self.tcx,
- def_id,
- args,
- ty::ClosureKind::FnOnce,
- );
+ let instance = {
+ let _trace = enter_trace_span!(M, resolve::resolve_closure, ?def_id);
+ ty::Instance::resolve_closure(
+ *self.tcx,
+ def_id,
+ args,
+ ty::ClosureKind::FnOnce,
+ )
+ };
let fn_ptr = self.fn_ptr(FnVal::Instance(instance));
self.write_pointer(fn_ptr, dest)?;
}
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index c4b705d7124ed..d0e9b5c71c6e2 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -344,6 +344,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
def: DefId,
args: GenericArgsRef<'tcx>,
) -> InterpResult<'tcx, ty::Instance<'tcx>> {
+ let _trace = enter_trace_span!(M, resolve::try_resolve, def = ?def);
trace!("resolve: {:?}, {:#?}", def, args);
trace!("typing_env: {:#?}", self.typing_env);
trace!("args: {:#?}", args);
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 9df49c0f4ccdf..04871faa3e621 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -560,7 +560,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
"Async Drop must be expanded or reset to sync in runtime MIR"
);
let place = self.eval_place(place)?;
- let instance = Instance::resolve_drop_in_place(*self.tcx, place.layout.ty);
+ let instance = {
+ let _trace =
+ enter_trace_span!(M, resolve::resolve_drop_in_place, ty = ?place.layout.ty);
+ Instance::resolve_drop_in_place(*self.tcx, place.layout.ty)
+ };
if let ty::InstanceKind::DropGlue(_, None) = instance.def {
// This is the branch we enter if and only if the dropped type has no drop glue
// whatsoever. This can happen as a result of monomorphizing a drop of a
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index 43cb1c9ae053c..20b95f3b03490 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -32,6 +32,8 @@ pub enum AccessKind {
///
/// A `None` namespace indicates we are looking for a module.
fn try_resolve_did(tcx: TyCtxt<'_>, path: &[&str], namespace: Option) -> Option {
+ let _trace = enter_trace_span!("try_resolve_did", ?path);
+
/// Yield all children of the given item, that have the given name.
fn find_children<'tcx: 'a, 'a>(
tcx: TyCtxt<'tcx>,
From a0eea23317e60ef1b648abd0fe76ca89362ac44d Mon Sep 17 00:00:00 2001
From: Eval EXEC
Date: Tue, 12 Aug 2025 18:36:16 +0800
Subject: [PATCH 07/17] doc test: fix mpsc.rs try_send doc test
Signed-off-by: Eval EXEC
---
library/std/src/sync/mpsc.rs | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/library/std/src/sync/mpsc.rs b/library/std/src/sync/mpsc.rs
index 41d1dd3ce674b..03d7fddc2faef 100644
--- a/library/std/src/sync/mpsc.rs
+++ b/library/std/src/sync/mpsc.rs
@@ -697,14 +697,14 @@ impl SyncSender {
/// let sync_sender2 = sync_sender.clone();
///
/// // First thread owns sync_sender
- /// thread::spawn(move || {
+ /// let handle1 = thread::spawn(move || {
/// sync_sender.send(1).unwrap();
/// sync_sender.send(2).unwrap();
/// // Thread blocked
/// });
///
/// // Second thread owns sync_sender2
- /// thread::spawn(move || {
+ /// let handle2 = thread::spawn(move || {
/// // This will return an error and send
/// // no message if the buffer is full
/// let _ = sync_sender2.try_send(3);
@@ -722,6 +722,10 @@ impl SyncSender {
/// Ok(msg) => println!("message {msg} received"),
/// Err(_) => println!("the third message was never sent"),
/// }
+ ///
+ /// // Wait for threads to complete
+ /// handle1.join().unwrap();
+ /// handle2.join().unwrap();
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn try_send(&self, t: T) -> Result<(), TrySendError> {
From d4eb0947f133d8f44594d7551d99a48daff21c02 Mon Sep 17 00:00:00 2001
From: Cameron Steffen
Date: Tue, 12 Aug 2025 17:57:02 -0500
Subject: [PATCH 08/17] Cleanup assoc parent utils
---
.../src/diagnostics/mutability_errors.rs | 3 +-
compiler/rustc_borrowck/src/type_check/mod.rs | 5 +--
.../rustc_codegen_llvm/src/debuginfo/mod.rs | 43 ++++++++-----------
.../rustc_const_eval/src/interpret/call.rs | 2 +-
.../src/check/compare_impl_item.rs | 6 +--
.../rustc_hir_analysis/src/check/wfcheck.rs | 3 +-
compiler/rustc_lint/src/pass_by_value.rs | 6 +--
compiler/rustc_lint/src/types.rs | 5 +--
compiler/rustc_middle/src/middle/privacy.rs | 6 +--
compiler/rustc_middle/src/ty/mod.rs | 39 ++++++++++++++---
.../src/check_call_recursion.rs | 4 +-
.../src/check_packed_ref.rs | 2 +-
compiler/rustc_mir_transform/src/shim.rs | 2 +-
.../rustc_monomorphize/src/partitioning.rs | 13 +++---
compiler/rustc_passes/src/dead.rs | 2 +-
.../src/traits/project.rs | 2 +-
16 files changed, 79 insertions(+), 64 deletions(-)
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 5d9416b59fcec..c0ca35f9ff83a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -677,12 +677,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
/// - is the trait from the local crate? If not, we can't suggest changing signatures
/// - `Span` of the argument in the trait definition
fn is_error_in_trait(&self, local: Local) -> (bool, bool, Option) {
+ let tcx = self.infcx.tcx;
if self.body.local_kind(local) != LocalKind::Arg {
return (false, false, None);
}
let my_def = self.body.source.def_id();
let Some(td) =
- self.infcx.tcx.impl_of_assoc(my_def).and_then(|x| self.infcx.tcx.trait_id_of_impl(x))
+ tcx.trait_impl_of_assoc(my_def).and_then(|id| self.infcx.tcx.trait_id_of_impl(id))
else {
return (false, false, None);
};
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index c3aa205d5aab3..a960b96b91c20 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -1773,10 +1773,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
locations,
);
- assert!(!matches!(
- tcx.impl_of_assoc(def_id).map(|imp| tcx.def_kind(imp)),
- Some(DefKind::Impl { of_trait: true })
- ));
+ assert_eq!(tcx.trait_impl_of_assoc(def_id), None);
self.prove_predicates(
args.types().map(|ty| ty::ClauseKind::WellFormed(ty.into())),
locations,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 6cbf2dbf7d3fd..2c3a84499ac55 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -533,31 +533,26 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
// First, let's see if this is a method within an inherent impl. Because
// if yes, we want to make the result subroutine DIE a child of the
// subroutine's self-type.
- if let Some(impl_def_id) = cx.tcx.impl_of_assoc(instance.def_id()) {
- // If the method does *not* belong to a trait, proceed
- if cx.tcx.trait_id_of_impl(impl_def_id).is_none() {
- let impl_self_ty = cx.tcx.instantiate_and_normalize_erasing_regions(
- instance.args,
- cx.typing_env(),
- cx.tcx.type_of(impl_def_id),
- );
-
- // Only "class" methods are generally understood by LLVM,
- // so avoid methods on other types (e.g., `<*mut T>::null`).
- if let ty::Adt(def, ..) = impl_self_ty.kind()
- && !def.is_box()
- {
- // Again, only create type information if full debuginfo is enabled
- if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param()
- {
- return (type_di_node(cx, impl_self_ty), true);
- } else {
- return (namespace::item_namespace(cx, def.did()), false);
- }
+ // For trait method impls we still use the "parallel namespace"
+ // strategy
+ if let Some(imp_def_id) = cx.tcx.inherent_impl_of_assoc(instance.def_id()) {
+ let impl_self_ty = cx.tcx.instantiate_and_normalize_erasing_regions(
+ instance.args,
+ cx.typing_env(),
+ cx.tcx.type_of(imp_def_id),
+ );
+
+ // Only "class" methods are generally understood by LLVM,
+ // so avoid methods on other types (e.g., `<*mut T>::null`).
+ if let ty::Adt(def, ..) = impl_self_ty.kind()
+ && !def.is_box()
+ {
+ // Again, only create type information if full debuginfo is enabled
+ if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param() {
+ return (type_di_node(cx, impl_self_ty), true);
+ } else {
+ return (namespace::item_namespace(cx, def.did()), false);
}
- } else {
- // For trait method impls we still use the "parallel namespace"
- // strategy
}
}
diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs
index b1cc0cc2878aa..21237cfe49216 100644
--- a/compiler/rustc_const_eval/src/interpret/call.rs
+++ b/compiler/rustc_const_eval/src/interpret/call.rs
@@ -731,7 +731,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
) {
let tcx = *self.tcx;
- let trait_def_id = tcx.trait_of_assoc(def_id).unwrap();
+ let trait_def_id = tcx.parent(def_id);
let virtual_trait_ref = ty::TraitRef::from_assoc(tcx, trait_def_id, virtual_instance.args);
let existential_trait_ref = ty::ExistentialTraitRef::erase_self_ty(tcx, virtual_trait_ref);
let concrete_trait_ref = existential_trait_ref.with_self_ty(tcx, dyn_ty);
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 6767e5ed88d4d..e482725619398 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -445,10 +445,10 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
tcx: TyCtxt<'tcx>,
impl_m_def_id: LocalDefId,
) -> Result<&'tcx DefIdMap>>, ErrorGuaranteed> {
- let impl_m = tcx.opt_associated_item(impl_m_def_id.to_def_id()).unwrap();
- let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap();
+ let impl_m = tcx.associated_item(impl_m_def_id.to_def_id());
+ let trait_m = tcx.associated_item(impl_m.trait_item_def_id.unwrap());
let impl_trait_ref =
- tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap().instantiate_identity();
+ tcx.impl_trait_ref(tcx.parent(impl_m_def_id.to_def_id())).unwrap().instantiate_identity();
// First, check a few of the same things as `compare_impl_method`,
// just so we don't ICE during instantiation later.
check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, true)?;
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index c642435b9893c..e6a1f6d8d8bb7 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -2287,8 +2287,7 @@ fn lint_redundant_lifetimes<'tcx>(
// Proceed
}
DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => {
- let parent_def_id = tcx.local_parent(owner_id);
- if matches!(tcx.def_kind(parent_def_id), DefKind::Impl { of_trait: true }) {
+ if tcx.trait_impl_of_assoc(owner_id.to_def_id()).is_some() {
// Don't check for redundant lifetimes for associated items of trait
// implementations, since the signature is required to be compatible
// with the trait, even if the implementation implies some lifetimes
diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs
index 4f65acd8001ed..29006732aade5 100644
--- a/compiler/rustc_lint/src/pass_by_value.rs
+++ b/compiler/rustc_lint/src/pass_by_value.rs
@@ -24,10 +24,8 @@ impl<'tcx> LateLintPass<'tcx> for PassByValue {
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
match &ty.kind {
TyKind::Ref(_, hir::MutTy { ty: inner_ty, mutbl: hir::Mutability::Not }) => {
- if let Some(impl_did) = cx.tcx.impl_of_assoc(ty.hir_id.owner.to_def_id()) {
- if cx.tcx.impl_trait_ref(impl_did).is_some() {
- return;
- }
+ if cx.tcx.trait_impl_of_assoc(ty.hir_id.owner.to_def_id()).is_some() {
+ return;
}
if let Some(t) = path_for_pass_by_value(cx, inner_ty) {
cx.emit_span_lint(
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index b0afc333ebe2f..f8a692313f030 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1904,10 +1904,9 @@ impl InvalidAtomicOrdering {
if let ExprKind::MethodCall(method_path, _, args, _) = &expr.kind
&& recognized_names.contains(&method_path.ident.name)
&& let Some(m_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
- && let Some(impl_did) = cx.tcx.impl_of_assoc(m_def_id)
- && let Some(adt) = cx.tcx.type_of(impl_did).instantiate_identity().ty_adt_def()
// skip extension traits, only lint functions from the standard library
- && cx.tcx.trait_id_of_impl(impl_did).is_none()
+ && let Some(impl_did) = cx.tcx.inherent_impl_of_assoc(m_def_id)
+ && let Some(adt) = cx.tcx.type_of(impl_did).instantiate_identity().ty_adt_def()
&& let parent = cx.tcx.parent(adt.did())
&& cx.tcx.is_diagnostic_item(sym::atomic_mod, parent)
&& ATOMIC_TYPES.contains(&cx.tcx.item_name(adt.did()))
diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs
index 785ddd1ee2980..e3e04c9d1800b 100644
--- a/compiler/rustc_middle/src/middle/privacy.rs
+++ b/compiler/rustc_middle/src/middle/privacy.rs
@@ -181,11 +181,7 @@ impl EffectiveVisibilities {
// nominal visibility. For some items nominal visibility doesn't make sense so we
// don't check this condition for them.
let is_impl = matches!(tcx.def_kind(def_id), DefKind::Impl { .. });
- let is_associated_item_in_trait_impl = tcx
- .impl_of_assoc(def_id.to_def_id())
- .and_then(|impl_id| tcx.trait_id_of_impl(impl_id))
- .is_some();
- if !is_impl && !is_associated_item_in_trait_impl {
+ if !is_impl && tcx.trait_impl_of_assoc(def_id.to_def_id()).is_none() {
let nominal_vis = tcx.visibility(def_id);
if !nominal_vis.is_at_least(ev.reachable, tcx) {
span_bug!(
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 73e1661106eaf..e70c98ab70425 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1925,21 +1925,50 @@ impl<'tcx> TyCtxt<'tcx> {
self.impl_trait_ref(def_id).map(|tr| tr.skip_binder().def_id)
}
- /// If the given `DefId` is an associated item, returns the `DefId` of the parent trait or impl.
- pub fn assoc_parent(self, def_id: DefId) -> Option {
- self.def_kind(def_id).is_assoc().then(|| self.parent(def_id))
+ /// If the given `DefId` is an associated item, returns the `DefId` and `DefKind` of the parent trait or impl.
+ pub fn assoc_parent(self, def_id: DefId) -> Option<(DefId, DefKind)> {
+ if !self.def_kind(def_id).is_assoc() {
+ return None;
+ }
+ let parent = self.parent(def_id);
+ let def_kind = self.def_kind(parent);
+ Some((parent, def_kind))
}
/// If the given `DefId` is an associated item of a trait,
/// returns the `DefId` of the trait; otherwise, returns `None`.
pub fn trait_of_assoc(self, def_id: DefId) -> Option {
- self.assoc_parent(def_id).filter(|id| self.def_kind(id) == DefKind::Trait)
+ match self.assoc_parent(def_id) {
+ Some((id, DefKind::Trait)) => Some(id),
+ _ => None,
+ }
}
/// If the given `DefId` is an associated item of an impl,
/// returns the `DefId` of the impl; otherwise returns `None`.
pub fn impl_of_assoc(self, def_id: DefId) -> Option {
- self.assoc_parent(def_id).filter(|id| matches!(self.def_kind(id), DefKind::Impl { .. }))
+ match self.assoc_parent(def_id) {
+ Some((id, DefKind::Impl { .. })) => Some(id),
+ _ => None,
+ }
+ }
+
+ /// If the given `DefId` is an associated item of an inherent impl,
+ /// returns the `DefId` of the impl; otherwise, returns `None`.
+ pub fn inherent_impl_of_assoc(self, def_id: DefId) -> Option {
+ match self.assoc_parent(def_id) {
+ Some((id, DefKind::Impl { of_trait: false })) => Some(id),
+ _ => None,
+ }
+ }
+
+ /// If the given `DefId` is an associated item of a trait impl,
+ /// returns the `DefId` of the impl; otherwise, returns `None`.
+ pub fn trait_impl_of_assoc(self, def_id: DefId) -> Option {
+ match self.assoc_parent(def_id) {
+ Some((id, DefKind::Impl { of_trait: true })) => Some(id),
+ _ => None,
+ }
}
pub fn is_exportable(self, def_id: DefId) -> bool {
diff --git a/compiler/rustc_mir_transform/src/check_call_recursion.rs b/compiler/rustc_mir_transform/src/check_call_recursion.rs
index 6d61ac2dd8037..a9acb1da5a3e0 100644
--- a/compiler/rustc_mir_transform/src/check_call_recursion.rs
+++ b/compiler/rustc_mir_transform/src/check_call_recursion.rs
@@ -43,8 +43,8 @@ impl<'tcx> MirLint<'tcx> for CheckDropRecursion {
// First check if `body` is an `fn drop()` of `Drop`
if let DefKind::AssocFn = tcx.def_kind(def_id)
- && let Some(trait_ref) =
- tcx.impl_of_assoc(def_id.to_def_id()).and_then(|def_id| tcx.impl_trait_ref(def_id))
+ && let Some(impl_id) = tcx.trait_impl_of_assoc(def_id.to_def_id())
+ && let trait_ref = tcx.impl_trait_ref(impl_id).unwrap()
&& tcx.is_lang_item(trait_ref.instantiate_identity().def_id, LangItem::Drop)
// avoid erroneous `Drop` impls from causing ICEs below
&& let sig = tcx.fn_sig(def_id).instantiate_identity()
diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs
index dcb812c78993e..100104e9de03e 100644
--- a/compiler/rustc_mir_transform/src/check_packed_ref.rs
+++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs
@@ -40,7 +40,7 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
if context.is_borrow() && util::is_disaligned(self.tcx, self.body, self.typing_env, *place)
{
let def_id = self.body.source.instance.def_id();
- if let Some(impl_def_id) = self.tcx.impl_of_assoc(def_id)
+ if let Some(impl_def_id) = self.tcx.trait_impl_of_assoc(def_id)
&& self.tcx.is_builtin_derived(impl_def_id)
{
// If we ever reach here it means that the generated derive
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index c687036f544dc..c6760b3583f20 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -75,7 +75,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body<
build_call_shim(tcx, instance, Some(adjustment), CallKind::Direct(def_id))
}
ty::InstanceKind::FnPtrShim(def_id, ty) => {
- let trait_ = tcx.trait_of_assoc(def_id).unwrap();
+ let trait_ = tcx.parent(def_id);
// Supports `Fn` or `async Fn` traits.
let adjustment = match tcx
.fn_trait_kind_from_def_id(trait_)
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index d76b27d9970b6..54d77b182f8d8 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -650,17 +650,18 @@ fn characteristic_def_id_of_mono_item<'tcx>(
// its self-type. If the self-type does not provide a characteristic
// DefId, we use the location of the impl after all.
- if tcx.trait_of_assoc(def_id).is_some() {
+ let assoc_parent = tcx.assoc_parent(def_id);
+
+ if let Some((_, DefKind::Trait)) = assoc_parent {
let self_ty = instance.args.type_at(0);
// This is a default implementation of a trait method.
return characteristic_def_id_of_type(self_ty).or(Some(def_id));
}
- if let Some(impl_def_id) = tcx.impl_of_assoc(def_id) {
- if tcx.sess.opts.incremental.is_some()
- && tcx
- .trait_id_of_impl(impl_def_id)
- .is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Drop))
+ if let Some((impl_def_id, DefKind::Impl { of_trait })) = assoc_parent {
+ if of_trait
+ && tcx.sess.opts.incremental.is_some()
+ && tcx.is_lang_item(tcx.trait_id_of_impl(impl_def_id).unwrap(), LangItem::Drop)
{
// Put `Drop::drop` into the same cgu as `drop_in_place`
// since `drop_in_place` is the only thing that can
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index de52973acbb4a..08d06402000ae 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -371,7 +371,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
/// will be ignored for the purposes of dead code analysis (see PR #85200
/// for discussion).
fn should_ignore_item(&mut self, def_id: DefId) -> bool {
- if let Some(impl_of) = self.tcx.impl_of_assoc(def_id) {
+ if let Some(impl_of) = self.tcx.trait_impl_of_assoc(def_id) {
if !self.tcx.is_automatically_derived(impl_of) {
return false;
}
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 581191b2036d2..884d53732fe2a 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1507,7 +1507,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
let tcx = selcx.tcx();
let self_ty = obligation.predicate.self_ty();
let item_def_id = obligation.predicate.def_id;
- let trait_def_id = tcx.trait_of_assoc(item_def_id).unwrap();
+ let trait_def_id = tcx.parent(item_def_id);
let args = tcx.mk_args(&[self_ty.into()]);
let (term, obligations) = if tcx.is_lang_item(trait_def_id, LangItem::DiscriminantKind) {
let discriminant_def_id =
From 12d1665d1163d62de0dd2c2fcb2f508fea8123f1 Mon Sep 17 00:00:00 2001
From: xizheyin
Date: Wed, 13 Aug 2025 23:17:29 +0800
Subject: [PATCH 09/17] Add test suggest-add-wrapper-issue-145294
Signed-off-by: xizheyin
---
.../suggest-add-wrapper-issue-145294.rs | 26 +++++++++++++++++
.../suggest-add-wrapper-issue-145294.stderr | 29 +++++++++++++++++++
2 files changed, 55 insertions(+)
create mode 100644 tests/ui/typeck/suggestions/suggest-add-wrapper-issue-145294.rs
create mode 100644 tests/ui/typeck/suggestions/suggest-add-wrapper-issue-145294.stderr
diff --git a/tests/ui/typeck/suggestions/suggest-add-wrapper-issue-145294.rs b/tests/ui/typeck/suggestions/suggest-add-wrapper-issue-145294.rs
new file mode 100644
index 0000000000000..cfe167cf88d76
--- /dev/null
+++ b/tests/ui/typeck/suggestions/suggest-add-wrapper-issue-145294.rs
@@ -0,0 +1,26 @@
+// Suppress the suggestion that adding a wrapper.
+// When expected_ty and expr_ty are the same ADT,
+// we prefer to compare their internal generic params,
+// so when the current variant corresponds to an unresolved infer,
+// the suggestion is rejected.
+// e.g. `Ok(Some("hi"))` is type of `Result
");
}
diff --git a/tests/rustdoc/footnote-reference-ids.rs b/tests/rustdoc/footnote-reference-ids.rs
new file mode 100644
index 0000000000000..ffa04e1d7675d
--- /dev/null
+++ b/tests/rustdoc/footnote-reference-ids.rs
@@ -0,0 +1,23 @@
+// This test ensures that multiple references to a single footnote and
+// corresponding back links work as expected.
+
+#![crate_name = "foo"]
+
+//@ has 'foo/index.html'
+//@ has - '//*[@class="docblock"]/p/sup[@id="fnref1"]/a[@href="#fn1"]' '1'
+//@ has - '//*[@class="docblock"]/p/sup[@id="fnref2"]/a[@href="#fn2"]' '2'
+//@ has - '//*[@class="docblock"]/p/sup[@id="fnref2-2"]/a[@href="#fn2"]' '2'
+//@ has - '//li[@id="fn1"]/p' 'meow'
+//@ has - '//li[@id="fn1"]/p/a[@href="#fnref1"]' '↩'
+//@ has - '//li[@id="fn2"]/p' 'uwu'
+//@ has - '//li[@id="fn2"]/p/a[@href="#fnref2"]/sup' '1'
+//@ has - '//li[@id="fn2"]/p/sup/a[@href="#fnref2-2"]' '2'
+
+//! # Footnote, references and back links
+//!
+//! Single: [^a].
+//!
+//! Double: [^b] [^b].
+//!
+//! [^a]: meow
+//! [^b]: uwu
diff --git a/tests/rustdoc/footnote-reference-in-footnote-def.rs b/tests/rustdoc/footnote-reference-in-footnote-def.rs
index db3f9a59ef830..504d0bdb8f79f 100644
--- a/tests/rustdoc/footnote-reference-in-footnote-def.rs
+++ b/tests/rustdoc/footnote-reference-in-footnote-def.rs
@@ -9,7 +9,7 @@
//@ has - '//li[@id="fn1"]/p/sup[@id="fnref2"]/a[@href="#fn2"]' '2'
//@ has - '//li[@id="fn1"]//a[@href="#fn2"]' '2'
//@ has - '//li[@id="fn2"]/p' 'uwu'
-//@ has - '//li[@id="fn2"]/p/sup[@id="fnref1"]/a[@href="#fn1"]' '1'
+//@ has - '//li[@id="fn2"]/p/sup[@id="fnref1-2"]/a[@href="#fn1"]' '1'
//@ has - '//li[@id="fn2"]//a[@href="#fn1"]' '1'
//! # footnote-hell
From 51eb5ed8f099cb8169ca48eb684ea98030988849 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov
Date: Fri, 8 Aug 2025 19:54:27 +0300
Subject: [PATCH 15/17] resolve: Do not call `resolve_macro_path` from late
resolution
`maybe_resolve_path` is less precise in corner cases, but it's only used for diagnostics and error recovery, so it's good enough.
---
compiler/rustc_resolve/src/diagnostics.rs | 2 +-
compiler/rustc_resolve/src/ident.rs | 2 +-
compiler/rustc_resolve/src/late.rs | 22 +++++-----------------
compiler/rustc_resolve/src/macros.rs | 15 ++++++---------
4 files changed, 13 insertions(+), 28 deletions(-)
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 8526b233ba222..f294ec748e7df 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1047,7 +1047,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
let parent_scope = &ParentScope { derives: &[], ..*parent_scope };
let Ok((Some(ext), _)) = this.reborrow().resolve_macro_path(
derive,
- Some(MacroKind::Derive),
+ MacroKind::Derive,
parent_scope,
false,
false,
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 7ab932d9f2a03..5b430a18c04ec 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -469,7 +469,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
let parent_scope = &ParentScope { derives: &[], ..*parent_scope };
match this.reborrow().resolve_macro_path(
derive,
- Some(MacroKind::Derive),
+ MacroKind::Derive,
parent_scope,
true,
force,
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index e52cbeb733ac0..1e4ab57a3160a 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -4315,7 +4315,6 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
qself,
path,
ns,
- path_span,
source.defer_to_typeck(),
finalize,
source,
@@ -4438,7 +4437,6 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
qself: &Option>,
path: &[Segment],
primary_ns: Namespace,
- span: Span,
defer_to_typeck: bool,
finalize: Finalize,
source: PathSource<'_, 'ast, 'ra>,
@@ -4463,21 +4461,11 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
}
assert!(primary_ns != MacroNS);
-
- if qself.is_none() {
- let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident);
- let path = Path { segments: path.iter().map(path_seg).collect(), span, tokens: None };
- if let Ok((_, res)) = self.r.cm().resolve_macro_path(
- &path,
- None,
- &self.parent_scope,
- false,
- false,
- None,
- None,
- ) {
- return Ok(Some(PartialRes::new(res)));
- }
+ if qself.is_none()
+ && let PathResult::NonModule(res) =
+ self.r.cm().maybe_resolve_path(path, Some(MacroNS), &self.parent_scope, None)
+ {
+ return Ok(Some(res));
}
Ok(fin_res)
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 9f25635f1fd1a..72ed899024168 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -398,7 +398,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
resolution.exts = Some(
match self.cm().resolve_macro_path(
&resolution.path,
- Some(MacroKind::Derive),
+ MacroKind::Derive,
&parent_scope,
true,
force,
@@ -563,7 +563,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
) -> Result<(Arc, Res), Indeterminate> {
let (ext, res) = match self.cm().resolve_macro_or_delegation_path(
path,
- Some(kind),
+ kind,
parent_scope,
true,
force,
@@ -710,7 +710,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
pub(crate) fn resolve_macro_path<'r>(
self: CmResolver<'r, 'ra, 'tcx>,
path: &ast::Path,
- kind: Option,
+ kind: MacroKind,
parent_scope: &ParentScope<'ra>,
trace: bool,
force: bool,
@@ -733,7 +733,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
fn resolve_macro_or_delegation_path<'r>(
mut self: CmResolver<'r, 'ra, 'tcx>,
ast_path: &ast::Path,
- kind: Option,
+ kind: MacroKind,
parent_scope: &ParentScope<'ra>,
trace: bool,
force: bool,
@@ -747,7 +747,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
// Possibly apply the macro helper hack
if deleg_impl.is_none()
- && kind == Some(MacroKind::Bang)
+ && kind == MacroKind::Bang
&& let [segment] = path.as_slice()
&& segment.ident.span.ctxt().outer_expn_data().local_inner_macros
{
@@ -775,7 +775,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
};
if trace {
- let kind = kind.expect("macro kind must be specified if tracing is enabled");
// FIXME: Should be an output of Speculative Resolution.
self.multi_segment_macro_resolutions.borrow_mut().push((
path,
@@ -790,10 +789,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
self.prohibit_imported_non_macro_attrs(None, res.ok(), path_span);
res
} else {
- let scope_set = kind.map_or(ScopeSet::All(MacroNS), ScopeSet::Macro);
let binding = self.reborrow().early_resolve_ident_in_lexical_scope(
path[0].ident,
- scope_set,
+ ScopeSet::Macro(kind),
parent_scope,
None,
force,
@@ -805,7 +803,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
if trace {
- let kind = kind.expect("macro kind must be specified if tracing is enabled");
// FIXME: Should be an output of Speculative Resolution.
self.single_segment_macro_resolutions.borrow_mut().push((
path[0].ident,
From d682943396fdc0a8fcf907c570435d01a3035fe2 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov
Date: Fri, 8 Aug 2025 21:26:50 +0300
Subject: [PATCH 16/17] resolve: Do not show deprecated helper attributes in
typo recommendations
Remove one FIXME, addressing it does not reduce the hacky-ness much, and the logic is going to be removed anyway together with the `legacy_derive_helpers` deprecation lint.
---
compiler/rustc_resolve/src/diagnostics.rs | 23 +------------------
compiler/rustc_resolve/src/ident.rs | 5 ----
.../proc-macro/proc-macro-attributes.stderr | 8 ++++++-
3 files changed, 8 insertions(+), 28 deletions(-)
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index f294ec748e7df..5f54411b463a5 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1041,28 +1041,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
}
Scope::DeriveHelpersCompat => {
- let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat);
- if filter_fn(res) {
- for derive in parent_scope.derives {
- let parent_scope = &ParentScope { derives: &[], ..*parent_scope };
- let Ok((Some(ext), _)) = this.reborrow().resolve_macro_path(
- derive,
- MacroKind::Derive,
- parent_scope,
- false,
- false,
- None,
- None,
- ) else {
- continue;
- };
- suggestions.extend(
- ext.helper_attrs
- .iter()
- .map(|name| TypoSuggestion::typo_from_name(*name, res)),
- );
- }
- }
+ // Never recommend deprecated helper attributes.
}
Scope::MacroRules(macro_rules_scope) => {
if let MacroRulesScope::Binding(macro_rules_binding) = macro_rules_scope.get() {
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 5b430a18c04ec..dc01c94af5729 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -459,11 +459,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
}
Scope::DeriveHelpersCompat => {
- // FIXME: Try running this logic earlier, to allocate name bindings for
- // legacy derive helpers when creating an attribute invocation with
- // following derives. Legacy derive helpers are not common, so it shouldn't
- // affect performance. It should also allow to remove the `derives`
- // component from `ParentScope`.
let mut result = Err(Determinacy::Determined);
for derive in parent_scope.derives {
let parent_scope = &ParentScope { derives: &[], ..*parent_scope };
diff --git a/tests/ui/proc-macro/proc-macro-attributes.stderr b/tests/ui/proc-macro/proc-macro-attributes.stderr
index 2cc57383eb39c..892728901fb99 100644
--- a/tests/ui/proc-macro/proc-macro-attributes.stderr
+++ b/tests/ui/proc-macro/proc-macro-attributes.stderr
@@ -2,7 +2,13 @@ error: cannot find attribute `C` in this scope
--> $DIR/proc-macro-attributes.rs:9:3
|
LL | #[C]
- | ^ help: a derive helper attribute with a similar name exists: `B`
+ | ^
+ |
+help: the derive macro `B` accepts the similarly named `B` attribute
+ |
+LL - #[C]
+LL + #[B]
+ |
error[E0659]: `B` is ambiguous
--> $DIR/proc-macro-attributes.rs:6:3
From 9b797b9f7ac12a8ad6a2a5097b69e0216958709e Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov
Date: Wed, 13 Aug 2025 22:01:02 +0300
Subject: [PATCH 17/17] resolve: Improve code reuse in typo candidate
collection
---
compiler/rustc_resolve/src/diagnostics.rs | 25 ++++++---
.../rustc_resolve/src/late/diagnostics.rs | 51 +++++++------------
tests/ui/hygiene/arguments.stderr | 3 ++
.../hygiene/cross-crate-name-hiding-2.stderr | 5 ++
tests/ui/hygiene/globs.stderr | 14 ++---
5 files changed, 52 insertions(+), 46 deletions(-)
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 5f54411b463a5..c5fcbdfb42fe7 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1016,16 +1016,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
.emit()
}
- /// Lookup typo candidate in scope for a macro or import.
- fn early_lookup_typo_candidate(
+ pub(crate) fn add_scope_set_candidates(
&mut self,
+ suggestions: &mut Vec,
scope_set: ScopeSet<'ra>,
parent_scope: &ParentScope<'ra>,
- ident: Ident,
+ ctxt: SyntaxContext,
filter_fn: &impl Fn(Res) -> bool,
- ) -> Option {
- let mut suggestions = Vec::new();
- let ctxt = ident.span.ctxt();
+ ) {
self.cm().visit_scopes(scope_set, parent_scope, ctxt, |this, scope, use_prelude, _| {
match scope {
Scope::DeriveHelpers(expn_id) => {
@@ -1055,7 +1053,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
}
Scope::Module(module, _) => {
- this.add_module_candidates(module, &mut suggestions, filter_fn, None);
+ this.add_module_candidates(module, suggestions, filter_fn, None);
}
Scope::MacroUsePrelude => {
suggestions.extend(this.macro_use_prelude.iter().filter_map(
@@ -1113,6 +1111,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
None::<()>
});
+ }
+
+ /// Lookup typo candidate in scope for a macro or import.
+ fn early_lookup_typo_candidate(
+ &mut self,
+ scope_set: ScopeSet<'ra>,
+ parent_scope: &ParentScope<'ra>,
+ ident: Ident,
+ filter_fn: &impl Fn(Res) -> bool,
+ ) -> Option {
+ let mut suggestions = Vec::new();
+ let ctxt = ident.span.ctxt();
+ self.add_scope_set_candidates(&mut suggestions, scope_set, parent_scope, ctxt, filter_fn);
// Make sure error reporting is deterministic.
suggestions.sort_by(|a, b| a.candidate.as_str().cmp(b.candidate.as_str()));
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index c8cab5a0fe9a1..6a753b380359f 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -38,8 +38,8 @@ use crate::late::{
};
use crate::ty::fast_reject::SimplifiedType;
use crate::{
- Module, ModuleKind, ModuleOrUniformRoot, PathResult, PathSource, Resolver, Segment, errors,
- path_names_to_string,
+ Module, ModuleKind, ModuleOrUniformRoot, PathResult, PathSource, Resolver, ScopeSet, Segment,
+ errors, path_names_to_string,
};
type Res = def::Res;
@@ -2458,45 +2458,30 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
}
}
+ if let RibKind::Module(module) = rib.kind
+ && let ModuleKind::Block = module.kind
+ {
+ self.r.add_module_candidates(module, &mut names, &filter_fn, Some(ctxt));
+ } else if let RibKind::Module(module) = rib.kind {
+ // Encountered a module item, abandon ribs and look into that module and preludes.
+ self.r.add_scope_set_candidates(
+ &mut names,
+ ScopeSet::Late(ns, module, None),
+ &self.parent_scope,
+ ctxt,
+ filter_fn,
+ );
+ break;
+ }
+
if let RibKind::MacroDefinition(def) = rib.kind
&& def == self.r.macro_def(ctxt)
{
// If an invocation of this macro created `ident`, give up on `ident`
// and switch to `ident`'s source from the macro definition.
ctxt.remove_mark();
- continue;
- }
-
- // Items in scope
- if let RibKind::Module(module) = rib.kind {
- // Items from this module
- self.r.add_module_candidates(module, &mut names, &filter_fn, Some(ctxt));
-
- if let ModuleKind::Block = module.kind {
- // We can see through blocks
- } else {
- // Items from the prelude
- if !module.no_implicit_prelude {
- names.extend(self.r.extern_prelude.keys().flat_map(|ident| {
- let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id());
- filter_fn(res)
- .then_some(TypoSuggestion::typo_from_ident(ident.0, res))
- }));
-
- if let Some(prelude) = self.r.prelude {
- self.r.add_module_candidates(prelude, &mut names, &filter_fn, None);
- }
- }
- break;
- }
}
}
- // Add primitive types to the mix
- if filter_fn(Res::PrimTy(PrimTy::Bool)) {
- names.extend(PrimTy::ALL.iter().map(|prim_ty| {
- TypoSuggestion::typo_from_name(prim_ty.name(), Res::PrimTy(*prim_ty))
- }))
- }
} else {
// Search in module.
let mod_path = &path[..path.len() - 1];
diff --git a/tests/ui/hygiene/arguments.stderr b/tests/ui/hygiene/arguments.stderr
index 0d8d652b6f33d..fe92daf643796 100644
--- a/tests/ui/hygiene/arguments.stderr
+++ b/tests/ui/hygiene/arguments.stderr
@@ -1,6 +1,9 @@
error[E0412]: cannot find type `S` in this scope
--> $DIR/arguments.rs:14:8
|
+LL | struct S;
+ | - you might have meant to refer to this struct
+...
LL | m!(S, S);
| ^ not found in this scope
diff --git a/tests/ui/hygiene/cross-crate-name-hiding-2.stderr b/tests/ui/hygiene/cross-crate-name-hiding-2.stderr
index a5d509fab996f..fe3a12e93a7e7 100644
--- a/tests/ui/hygiene/cross-crate-name-hiding-2.stderr
+++ b/tests/ui/hygiene/cross-crate-name-hiding-2.stderr
@@ -3,6 +3,11 @@ error[E0422]: cannot find struct, variant or union type `MyStruct` in this scope
|
LL | let x = MyStruct {};
| ^^^^^^^^ not found in this scope
+ |
+ ::: $DIR/auxiliary/use_by_macro.rs:15:1
+ |
+LL | x!(my_struct);
+ | ------------- you might have meant to refer to this struct
error: aborting due to 1 previous error
diff --git a/tests/ui/hygiene/globs.stderr b/tests/ui/hygiene/globs.stderr
index 31f25b182f1f5..85946bf34bc53 100644
--- a/tests/ui/hygiene/globs.stderr
+++ b/tests/ui/hygiene/globs.stderr
@@ -48,7 +48,10 @@ error[E0425]: cannot find function `f` in this scope
--> $DIR/globs.rs:61:12
|
LL | n!(f);
- | ----- in this macro invocation
+ | -----
+ | | |
+ | | you might have meant to refer to this function
+ | in this macro invocation
...
LL | $j();
| -- due to this macro variable
@@ -56,15 +59,16 @@ LL | $j();
LL | n!(f);
| ^ not found in this scope
|
- = help: consider importing this function:
- foo::f
= note: this error originates in the macro `n` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0425]: cannot find function `f` in this scope
--> $DIR/globs.rs:65:17
|
LL | n!(f);
- | ----- in this macro invocation
+ | -----
+ | | |
+ | | you might have meant to refer to this function
+ | in this macro invocation
...
LL | $j();
| -- due to this macro variable
@@ -72,8 +76,6 @@ LL | $j();
LL | f
| ^ not found in this scope
|
- = help: consider importing this function:
- foo::f
= note: this error originates in the macro `n` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 4 previous errors