From 189b301fec6df44fc76cf1f3214de966f75a281a Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sun, 26 Oct 2025 17:56:39 +0100 Subject: [PATCH 01/19] CI: use alternative disks if available cleaning up disk space takes a lot of time --- src/ci/docker/run.sh | 1 + src/ci/scripts/free-disk-space-linux.sh | 46 +++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index 044f5a8fff322..bff1a2217f26c 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -347,6 +347,7 @@ docker \ --env DEPLOY \ --env DEPLOY_ALT \ --env CI \ + --env GIT_DISCOVERY_ACROSS_FILESYSTEM=1 \ --env GITHUB_ACTIONS \ --env GITHUB_REF \ --env GITHUB_STEP_SUMMARY="/checkout/obj/${SUMMARY_FILE}" \ diff --git a/src/ci/scripts/free-disk-space-linux.sh b/src/ci/scripts/free-disk-space-linux.sh index ac3c9cfb28b87..ee831b474df03 100755 --- a/src/ci/scripts/free-disk-space-linux.sh +++ b/src/ci/scripts/free-disk-space-linux.sh @@ -247,12 +247,58 @@ cleanSwap() { free -h } +# Try to find a different drive to put our data on so we don't need to run cleanup. +# The availability of the disks we're probing isn't guaranteed, +# so this is opportunistic. +checkAlternative() { + local gha_alt_disk="/mnt" + + # we need ~50GB of space + local space_target_kb=$((50 * 1024 * 1024)) + local available_space_kb=$(df -k "$gha_alt_disk" --output=avail | tail -n 1) + + # ignore-tidy-linelength + local mntopts="defaults,discard,journal_async_commit,barrier=0,noauto_da_alloc,lazytime,data=writeback" + + # GHA has a 2nd disk mounted at /mnt that is almost empty. + if mountpoint "$gha_alt_disk" && [ "$available_space_kb" -ge "$space_target_kb" ]; then + local blkdev=$(df -k "$gha_alt_disk" --output=source | tail -n 1) + echo "Sufficient space available on $blkdev mounted at $gha_alt_disk" + sudo swapoff -a || true + sudo umount "$gha_alt_disk" + mkdir ./obj + # remount with O_EATMYDATA while we're at it + sudo mount $blkdev ./obj -o $mntopts || (sudo dmesg | tail -n 20 ; exit 1) + sudo chown -R "$USER":"$USER" ./obj + + exit 0 + fi + + # ephemeral NVMe drives on AWS + for dev in /dev/nvme*n1; do + if [ -b "$dev" ] && [ "$(mount | grep "$dev" | wc -l)" -eq 0 ]; then + echo "Found unused block device $dev, creating filesystem" + sudo mkfs.ext4 -E lazy_itable_init=1,lazy_journal_init=1 "$dev" + mkdir ./obj + sudo mount "$dev" ./obj -o $mntopts + sudo chown -R "$USER":"$USER" ./obj + + exit 0 + fi + done +} + + + # Display initial disk space stats AVAILABLE_INITIAL=$(getAvailableSpace) printDF "BEFORE CLEAN-UP:" echo "" + +checkAlternative + execAndMeasureSpaceChange cleanPackages "Unused packages" execAndMeasureSpaceChange cleanDocker "Docker images" execAndMeasureSpaceChange cleanSwap "Swap storage" From 1787491550da47b4695c3a947762ca73b8aac054 Mon Sep 17 00:00:00 2001 From: the8472 Date: Mon, 27 Oct 2025 23:37:04 +0100 Subject: [PATCH 02/19] [review] add more comments Co-authored-by: Marco Ieni <11428655+marcoieni@users.noreply.github.com> --- src/ci/scripts/free-disk-space-linux.sh | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/ci/scripts/free-disk-space-linux.sh b/src/ci/scripts/free-disk-space-linux.sh index ee831b474df03..d421b4b49c466 100755 --- a/src/ci/scripts/free-disk-space-linux.sh +++ b/src/ci/scripts/free-disk-space-linux.sh @@ -257,25 +257,38 @@ checkAlternative() { local space_target_kb=$((50 * 1024 * 1024)) local available_space_kb=$(df -k "$gha_alt_disk" --output=avail | tail -n 1) + # mount options that trade durability for performance # ignore-tidy-linelength local mntopts="defaults,discard,journal_async_commit,barrier=0,noauto_da_alloc,lazytime,data=writeback" # GHA has a 2nd disk mounted at /mnt that is almost empty. + # Check if it's a valid mountpoint and it has enough available space. if mountpoint "$gha_alt_disk" && [ "$available_space_kb" -ge "$space_target_kb" ]; then local blkdev=$(df -k "$gha_alt_disk" --output=source | tail -n 1) echo "Sufficient space available on $blkdev mounted at $gha_alt_disk" + # see cleanSwap(), swapfile may be mounted under /mnt sudo swapoff -a || true + + # unmount from original location sudo umount "$gha_alt_disk" + + # remount under the obj dir which is used by docker scripts to write most + # of our build output. And apply optimized mount options while we're at it. mkdir ./obj - # remount with O_EATMYDATA while we're at it sudo mount $blkdev ./obj -o $mntopts || (sudo dmesg | tail -n 20 ; exit 1) + + # ensure current user can access everything. + # later scripts assume they have recursive access to obj sudo chown -R "$USER":"$USER" ./obj + # Exit from this script to avoid wasting time removing disk space, + # as we already have enough disk space in the alternative drive. exit 0 fi # ephemeral NVMe drives on AWS for dev in /dev/nvme*n1; do + # check that it's a blockdev and not mounted. if [ -b "$dev" ] && [ "$(mount | grep "$dev" | wc -l)" -eq 0 ]; then echo "Found unused block device $dev, creating filesystem" sudo mkfs.ext4 -E lazy_itable_init=1,lazy_journal_init=1 "$dev" From dd2d7c01fd3c56e5e8b53fcd63a645d4b32ec570 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Thu, 13 Nov 2025 22:46:39 +0100 Subject: [PATCH 03/19] print a warning and fallback instead of failing ci we assume the disks are ext4, but GH doesn't guarantee that. --- src/ci/scripts/free-disk-space-linux.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ci/scripts/free-disk-space-linux.sh b/src/ci/scripts/free-disk-space-linux.sh index d421b4b49c466..8a8f15636de2d 100755 --- a/src/ci/scripts/free-disk-space-linux.sh +++ b/src/ci/scripts/free-disk-space-linux.sh @@ -275,7 +275,11 @@ checkAlternative() { # remount under the obj dir which is used by docker scripts to write most # of our build output. And apply optimized mount options while we're at it. mkdir ./obj - sudo mount $blkdev ./obj -o $mntopts || (sudo dmesg | tail -n 20 ; exit 1) + if ! sudo mount $blkdev ./obj -o $mntopts; then + sudo dmesg | tail -n 20 # kernel log should have more details for mount failures + echo "::warning::Failed to remount $blkdev to ./obj with options: $mntopts" + return + fi # ensure current user can access everything. # later scripts assume they have recursive access to obj From dcbcedfec0d8439cb48cc247810afb258d283541 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Mon, 1 Dec 2025 22:41:07 +0100 Subject: [PATCH 04/19] AWS runners have enough disk, no need for cleanup or mount shenanigans --- src/ci/scripts/free-disk-space-linux.sh | 27 ++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/ci/scripts/free-disk-space-linux.sh b/src/ci/scripts/free-disk-space-linux.sh index 8a8f15636de2d..ac06f3fad88c0 100755 --- a/src/ci/scripts/free-disk-space-linux.sh +++ b/src/ci/scripts/free-disk-space-linux.sh @@ -4,6 +4,11 @@ set -euo pipefail # Free disk space on Linux GitHub action runners # Script inspired by https://github.com/jlumbroso/free-disk-space + +# we need ~50GB of space +space_target_kb=$((50 * 1024 * 1024)) + + isX86() { local arch arch=$(uname -m) @@ -247,14 +252,21 @@ cleanSwap() { free -h } +sufficientSpaceEarlyExit() { + local available_space_kb=$(df -k . --output=avail | tail -n 1) + + if [ "$available_space_kb" -ge "$space_target_kb" ]; then + echo "Sufficient disk space available (${available_space_kb}KB >= ${space_target_kb}KB). Skipping cleanup." + exit 0 + fi +} + # Try to find a different drive to put our data on so we don't need to run cleanup. # The availability of the disks we're probing isn't guaranteed, # so this is opportunistic. checkAlternative() { local gha_alt_disk="/mnt" - # we need ~50GB of space - local space_target_kb=$((50 * 1024 * 1024)) local available_space_kb=$(df -k "$gha_alt_disk" --output=avail | tail -n 1) # mount options that trade durability for performance @@ -292,10 +304,14 @@ checkAlternative() { # ephemeral NVMe drives on AWS for dev in /dev/nvme*n1; do - # check that it's a blockdev and not mounted. - if [ -b "$dev" ] && [ "$(mount | grep "$dev" | wc -l)" -eq 0 ]; then + # check that it's a blockdev, not mounted and doesn't have partitions + if [ -b "$dev" ] && [ "$(mount | grep "$dev" | wc -l)" -eq 0 ] && [ "$(lsblk -no PARTTYPE "$dev" | grep . | wc -l)" -eq 0 ]; then echo "Found unused block device $dev, creating filesystem" - sudo mkfs.ext4 -E lazy_itable_init=1,lazy_journal_init=1 "$dev" + if ! sudo mkfs.ext4 -E lazy_itable_init=1,lazy_journal_init=1 "$dev" ; then + sudo dmesg | tail -n 5 # kernel log should have more details for mkfs failures + echo "Failed to create ext4 filesystem on $dev" + continue + fi mkdir ./obj sudo mount "$dev" ./obj -o $mntopts sudo chown -R "$USER":"$USER" ./obj @@ -314,6 +330,7 @@ AVAILABLE_INITIAL=$(getAvailableSpace) printDF "BEFORE CLEAN-UP:" echo "" +sufficientSpaceEarlyExit checkAlternative execAndMeasureSpaceChange cleanPackages "Unused packages" From d501f960a3950983725a94f4ec7e83f3149e13f2 Mon Sep 17 00:00:00 2001 From: Aelin Reidel Date: Tue, 24 Feb 2026 07:37:34 +0100 Subject: [PATCH 05/19] rustc_target: callconv: powerpc64: Use llvm_abiname rather than target_abi for ABI determination Currently on PowerPC64 targets, llvm_abiname and target_abi will be the same unless we're on AIX. Since llvm_abiname is what we pass on to LLVM, it is preferable to use the value of that to determine the calling convention rather than target_abi. All PowerPC64 targets set both llvm_abiname and target_abi to the respective ELF ABIs, with the exception of AIX. This is a non-functional change. --- compiler/rustc_target/src/callconv/powerpc64.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_target/src/callconv/powerpc64.rs b/compiler/rustc_target/src/callconv/powerpc64.rs index 1d83799d7dab1..683b615eec83b 100644 --- a/compiler/rustc_target/src/callconv/powerpc64.rs +++ b/compiler/rustc_target/src/callconv/powerpc64.rs @@ -5,7 +5,7 @@ use rustc_abi::{Endian, HasDataLayout, TyAbiInterface}; use crate::callconv::{Align, ArgAbi, FnAbi, Reg, RegKind, Uniform}; -use crate::spec::{Abi, HasTargetSpec, Os}; +use crate::spec::{HasTargetSpec, Os}; #[derive(Debug, Clone, Copy, PartialEq)] enum ABI { @@ -106,9 +106,9 @@ where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout + HasTargetSpec, { - let abi = if cx.target_spec().options.abi == Abi::ElfV2 { + let abi = if cx.target_spec().options.llvm_abiname == "elfv2" { ELFv2 - } else if cx.target_spec().options.abi == Abi::ElfV1 { + } else if cx.target_spec().options.llvm_abiname == "elfv1" { ELFv1 } else if cx.target_spec().os == Os::Aix { AIX From acbfd79acf662be04745dc0675558e75e0d30d87 Mon Sep 17 00:00:00 2001 From: Hood Chatham Date: Mon, 26 Jan 2026 16:58:31 -0800 Subject: [PATCH 06/19] Fix: On wasm targets, call `panic_in_cleanup` if panic occurs in cleanup Previously this was not correctly implemented. Each funclet may need its own terminate block, so this changes the `terminate_block` into a `terminate_blocks` `IndexVec` which can have a terminate_block for each funclet. We key on the first basic block of the funclet -- in particular, this is the start block for the old case of the top level terminate function. Rather than using a catchswitch/catchpad pair, I used a cleanuppad. The reason for the pair is to avoid catching foreign exceptions on MSVC. On wasm, it seems that the catchswitch/catchpad pair is optimized back into a single cleanuppad and a catch_all instruction is emitted which will catch foreign exceptions. Because the new logic is only used on wasm, it seemed better to take the simpler approach seeing as they do the same thing. --- compiler/rustc_codegen_gcc/src/builder.rs | 4 + compiler/rustc_codegen_llvm/src/builder.rs | 4 + compiler/rustc_codegen_ssa/src/mir/block.rs | 96 +++++++++++++++---- compiler/rustc_codegen_ssa/src/mir/mod.rs | 9 +- .../rustc_codegen_ssa/src/traits/builder.rs | 5 +- tests/codegen-llvm/double_panic_wasm.rs | 34 +++++++ tests/codegen-llvm/terminating-catchpad.rs | 10 ++ 7 files changed, 138 insertions(+), 24 deletions(-) create mode 100644 tests/codegen-llvm/double_panic_wasm.rs diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 3def9a5c015cc..1b0a4e0b67959 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -1653,6 +1653,10 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { unimplemented!(); } + fn get_funclet_cleanuppad(&self, _funclet: &Funclet) -> RValue<'gcc> { + unimplemented!(); + } + // Atomic Operations fn atomic_cmpxchg( &mut self, diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index ca4805a93e017..c3e15eadfced1 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1309,6 +1309,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { ret } + fn get_funclet_cleanuppad(&self, funclet: &Funclet<'ll>) -> &'ll Value { + funclet.cleanuppad() + } + // Atomic Operations fn atomic_cmpxchg( &mut self, diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 35de8b5e1486b..4859380daa662 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -215,19 +215,18 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { mir::UnwindAction::Continue => None, mir::UnwindAction::Unreachable => None, mir::UnwindAction::Terminate(reason) => { - if fx.mir[self.bb].is_cleanup && base::wants_new_eh_instructions(fx.cx.tcx().sess) { + if fx.mir[self.bb].is_cleanup && base::wants_wasm_eh(fx.cx.tcx().sess) { + // For wasm, we need to generate a nested `cleanuppad within %outer_pad` + // to catch exceptions during cleanup and call `panic_in_cleanup`. + Some(fx.terminate_block(reason, Some(self.bb))) + } else if fx.mir[self.bb].is_cleanup + && base::wants_new_eh_instructions(fx.cx.tcx().sess) + { // MSVC SEH will abort automatically if an exception tries to // propagate out from cleanup. - - // FIXME(@mirkootter): For wasm, we currently do not support terminate during - // cleanup, because this requires a few more changes: The current code - // caches the `terminate_block` for each function; funclet based code - however - - // requires a different terminate_block for each funclet - // Until this is implemented, we just do not unwind inside cleanup blocks - None } else { - Some(fx.terminate_block(reason)) + Some(fx.terminate_block(reason, None)) } } }; @@ -239,7 +238,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { if let Some(unwind_block) = unwind_block { let ret_llbb = if let Some((_, target)) = destination { - fx.llbb(target) + self.llbb_with_cleanup(fx, target) } else { fx.unreachable_block() }; @@ -310,7 +309,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { ) -> MergingSucc { let unwind_target = match unwind { mir::UnwindAction::Cleanup(cleanup) => Some(self.llbb_with_cleanup(fx, cleanup)), - mir::UnwindAction::Terminate(reason) => Some(fx.terminate_block(reason)), + mir::UnwindAction::Terminate(reason) => Some(fx.terminate_block(reason, None)), mir::UnwindAction::Continue => None, mir::UnwindAction::Unreachable => None, }; @@ -318,7 +317,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { if operands.iter().any(|x| matches!(x, InlineAsmOperandRef::Label { .. })) { assert!(unwind_target.is_none()); let ret_llbb = if let Some(target) = destination { - fx.llbb(target) + self.llbb_with_cleanup(fx, target) } else { fx.unreachable_block() }; @@ -335,7 +334,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { MergingSucc::False } else if let Some(cleanup) = unwind_target { let ret_llbb = if let Some(target) = destination { - fx.llbb(target) + self.llbb_with_cleanup(fx, target) } else { fx.unreachable_block() }; @@ -1830,8 +1829,39 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }) } - fn terminate_block(&mut self, reason: UnwindTerminateReason) -> Bx::BasicBlock { - if let Some((cached_bb, cached_reason)) = self.terminate_block + fn terminate_block( + &mut self, + reason: UnwindTerminateReason, + outer_catchpad_bb: Option, + ) -> Bx::BasicBlock { + // mb_funclet_bb should be present if and only if the target is wasm and + // we're terminating because of an unwind in a cleanup block. In that + // case we have nested funclets and the inner catch_switch needs to know + // what outer catch_pad it is contained in. + debug_assert!( + outer_catchpad_bb.is_some() + == (base::wants_wasm_eh(self.cx.tcx().sess) + && reason == UnwindTerminateReason::InCleanup) + ); + + // When we aren't in a wasm InCleanup block, there's only one terminate + // block needed so we cache at START_BLOCK index. + let mut cache_bb = mir::START_BLOCK; + // In wasm eh InCleanup, use the outer funclet's cleanup BB as the cache + // key. + if let Some(outer_bb) = outer_catchpad_bb { + let cleanup_kinds = + self.cleanup_kinds.as_ref().expect("cleanup_kinds required for funclets"); + cache_bb = cleanup_kinds[outer_bb] + .funclet_bb(outer_bb) + .expect("funclet_bb should be in a funclet"); + + // Ensure the outer funclet is created first + if self.funclets[cache_bb].is_none() { + self.landing_pad_for(cache_bb); + } + } + if let Some((cached_bb, cached_reason)) = self.terminate_blocks[cache_bb] && reason == cached_reason { return cached_bb; @@ -1869,12 +1899,35 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // cp_terminate: // %cp = catchpad within %cs [null, i32 64, null] // ... + // + // By contrast, on WebAssembly targets, we specifically _do_ want to + // catch foreign exceptions. The situation with MSVC is a + // regrettable hack which we don't want to extend to other targets + // unless necessary. For WebAssembly, to generate catch(...) and + // catch only C++ exception instead of generating a catch_all, we + // need to call the intrinsics @llvm.wasm.get.exception and + // @llvm.wasm.get.ehselector in the catch pad. Since we don't do + // this, we generate a catch_all. We originally got this behavior + // by accident but it luckily matches our intention. llbb = Bx::append_block(self.cx, self.llfn, "cs_terminate"); - let cp_llbb = Bx::append_block(self.cx, self.llfn, "cp_terminate"); let mut cs_bx = Bx::build(self.cx, llbb); - let cs = cs_bx.catch_switch(None, None, &[cp_llbb]); + + // For wasm InCleanup blocks, our catch_switch is nested within the + // outer catchpad, so we need to provide it as the parent value to + // catch_switch. + let mut outer_cleanuppad = None; + if outer_catchpad_bb.is_some() { + // Get the outer funclet's catchpad + let outer_funclet = self.funclets[cache_bb] + .as_ref() + .expect("landing_pad_for didn't create funclet"); + outer_cleanuppad = Some(cs_bx.get_funclet_cleanuppad(outer_funclet)); + } + let cp_llbb = Bx::append_block(self.cx, self.llfn, "cp_terminate"); + let cs = cs_bx.catch_switch(outer_cleanuppad, None, &[cp_llbb]); + drop(cs_bx); bx = Bx::build(self.cx, cp_llbb); let null = @@ -1895,13 +1948,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } else { // Specifying more arguments than necessary usually doesn't // hurt, but the `WasmEHPrepare` LLVM pass does not recognize - // anything other than a single `null` as a `catch (...)` block, + // anything other than a single `null` as a `catch_all` block, // leading to problems down the line during instruction // selection. &[null] as &[_] }; funclet = Some(bx.catch_pad(cs, args)); + // On wasm, if we wanted to generate a catch(...) and only catch C++ + // exceptions, we'd call @llvm.wasm.get.exception and + // @llvm.wasm.get.ehselector selectors here. We want a catch_all so + // we leave them out. This is intentionally diverging from the MSVC + // behavior. } else { llbb = Bx::append_block(self.cx, self.llfn, "terminate"); bx = Bx::build(self.cx, llbb); @@ -1927,7 +1985,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.unreachable(); - self.terminate_block = Some((llbb, reason)); + self.terminate_blocks[cache_bb] = Some((llbb, reason)); llbb } diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 819abb9ae644d..1a0f66d31cca4 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -90,8 +90,11 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { /// Cached unreachable block unreachable_block: Option, - /// Cached terminate upon unwinding block and its reason - terminate_block: Option<(Bx::BasicBlock, UnwindTerminateReason)>, + /// Cached terminate upon unwinding block and its reason. For non-wasm + /// targets, there is at most one such block per function, stored at index + /// `START_BLOCK`. For wasm targets, each funclet needs its own terminate + /// block, indexed by the cleanup block that is the funclet's head. + terminate_blocks: IndexVec>, /// A bool flag for each basic block indicating whether it is a cold block. /// A cold block is a block that is unlikely to be executed at runtime. @@ -227,7 +230,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( personality_slot: None, cached_llbbs, unreachable_block: None, - terminate_block: None, + terminate_blocks: IndexVec::from_elem(None, &mir.basic_blocks), cleanup_kinds, landing_pads: IndexVec::from_elem(None, &mir.basic_blocks), funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()), diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 3486bd140eceb..edabd8188a3b6 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -552,12 +552,12 @@ pub trait BuilderMethods<'a, 'tcx>: fn set_personality_fn(&mut self, personality: Self::Function); - // These are used by everyone except msvc + // These are used by everyone except msvc and wasm EH fn cleanup_landing_pad(&mut self, pers_fn: Self::Function) -> (Self::Value, Self::Value); fn filter_landing_pad(&mut self, pers_fn: Self::Function); fn resume(&mut self, exn0: Self::Value, exn1: Self::Value); - // These are used only by msvc + // These are used by msvc and wasm EH fn cleanup_pad(&mut self, parent: Option, args: &[Self::Value]) -> Self::Funclet; fn cleanup_ret(&mut self, funclet: &Self::Funclet, unwind: Option); fn catch_pad(&mut self, parent: Self::Value, args: &[Self::Value]) -> Self::Funclet; @@ -567,6 +567,7 @@ pub trait BuilderMethods<'a, 'tcx>: unwind: Option, handlers: &[Self::BasicBlock], ) -> Self::Value; + fn get_funclet_cleanuppad(&self, funclet: &Self::Funclet) -> Self::Value; fn atomic_cmpxchg( &mut self, diff --git a/tests/codegen-llvm/double_panic_wasm.rs b/tests/codegen-llvm/double_panic_wasm.rs new file mode 100644 index 0000000000000..1eafe60503809 --- /dev/null +++ b/tests/codegen-llvm/double_panic_wasm.rs @@ -0,0 +1,34 @@ +//@ compile-flags: -C panic=unwind -Copt-level=0 +//@ needs-unwind +//@ only-wasm32 + +#![crate_type = "lib"] + +// Test that `panic_in_cleanup` is called on webassembly targets when a panic +// occurs in a destructor during unwinding. + +extern "Rust" { + fn may_panic(); +} + +struct PanicOnDrop; + +impl Drop for PanicOnDrop { + fn drop(&mut self) { + unsafe { may_panic() } + } +} + +// CHECK-LABEL: @double_panic +// CHECK: invoke void @may_panic() +// CHECK: invoke void @{{.+}}drop_in_place{{.+}} +// CHECK: unwind label %[[TERMINATE:.*]] +// +// CHECK: [[TERMINATE]]: +// CHECK: call void @{{.*panic_in_cleanup}} +// CHECK: unreachable +#[no_mangle] +pub fn double_panic() { + let _guard = PanicOnDrop; + unsafe { may_panic() } +} diff --git a/tests/codegen-llvm/terminating-catchpad.rs b/tests/codegen-llvm/terminating-catchpad.rs index a2ec19871d1fc..7c98ea94fdc13 100644 --- a/tests/codegen-llvm/terminating-catchpad.rs +++ b/tests/codegen-llvm/terminating-catchpad.rs @@ -9,6 +9,10 @@ // Ensure a catch-all generates: // - `catchpad ... [ptr null]` on Wasm (otherwise LLVM gets confused) // - `catchpad ... [ptr null, i32 64, ptr null]` on Windows (otherwise we catch SEH exceptions) +// +// Unlike on windows, on Wasm, we specifically do want to catch foreign +// exceptions. To catch only C++ exceptions we'd need to call +// @llvm.wasm.get.exception and @llvm.wasm.get.ehselector in the catchpad. #![feature(no_core, lang_items, rustc_attrs)] #![crate_type = "lib"] @@ -36,8 +40,14 @@ fn panic_cannot_unwind() -> ! { #[no_mangle] #[rustc_nounwind] pub fn doesnt_unwind() { + // CHECK: catchswitch within none [label %{{.*}}] unwind to caller // emscripten: %catchpad = catchpad within %catchswitch [ptr null] // wasi: %catchpad = catchpad within %catchswitch [ptr null] // seh: %catchpad = catchpad within %catchswitch [ptr null, i32 64, ptr null] + // + // We don't call these intrinsics on wasm targets so we generate a catch_all + // instruction which also picks up foreign exceptions + // NOT: @llvm.wasm.get.exception + // NOT: @llvm.wasm.get.ehselector unwinds(); } From 783afe9978eefe779a7135833ec525421911ff10 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Tue, 24 Feb 2026 20:29:37 +0100 Subject: [PATCH 07/19] `is_ty_must_use`: do not require a `span` argument All callers of `is_ty_must_use()`, recursive or not, pass `span` as equal to `expr.span` alongside `expr`. The `span` parameter can be safely removed. --- compiler/rustc_lint/src/unused/must_use.rs | 31 +++++++++++----------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_lint/src/unused/must_use.rs b/compiler/rustc_lint/src/unused/must_use.rs index f2d621c2ad5ed..f37cf4c8dc8c0 100644 --- a/compiler/rustc_lint/src/unused/must_use.rs +++ b/compiler/rustc_lint/src/unused/must_use.rs @@ -151,7 +151,6 @@ pub fn is_ty_must_use<'tcx>( cx: &LateContext<'tcx>, ty: Ty<'tcx>, expr: &hir::Expr<'_>, - span: Span, simplify_uninhabited: bool, ) -> IsTyMustUse { if ty.is_unit() { @@ -165,12 +164,12 @@ pub fn is_ty_must_use<'tcx>( match *ty.kind() { _ if is_uninhabited(ty) => IsTyMustUse::Trivial, ty::Adt(..) if let Some(boxed) = ty.boxed_ty() => { - is_ty_must_use(cx, boxed, expr, span, simplify_uninhabited) + is_ty_must_use(cx, boxed, expr, simplify_uninhabited) .map(|inner| MustUsePath::Boxed(Box::new(inner))) } ty::Adt(def, args) if cx.tcx.is_lang_item(def.did(), LangItem::Pin) => { let pinned_ty = args.type_at(0); - is_ty_must_use(cx, pinned_ty, expr, span, simplify_uninhabited) + is_ty_must_use(cx, pinned_ty, expr, simplify_uninhabited) .map(|inner| MustUsePath::Pinned(Box::new(inner))) } // Consider `Result` (e.g. `Result<(), !>`) equivalent to `T`. @@ -180,7 +179,7 @@ pub fn is_ty_must_use<'tcx>( && is_uninhabited(args.type_at(1)) => { let ok_ty = args.type_at(0); - is_ty_must_use(cx, ok_ty, expr, span, simplify_uninhabited) + is_ty_must_use(cx, ok_ty, expr, simplify_uninhabited) .map(|path| MustUsePath::Result(Box::new(path))) } // Consider `ControlFlow` (e.g. `ControlFlow`) equivalent to `T`. @@ -190,7 +189,7 @@ pub fn is_ty_must_use<'tcx>( && is_uninhabited(args.type_at(0)) => { let continue_ty = args.type_at(1); - is_ty_must_use(cx, continue_ty, expr, span, simplify_uninhabited) + is_ty_must_use(cx, continue_ty, expr, simplify_uninhabited) .map(|path| MustUsePath::ControlFlow(Box::new(path))) } // Suppress warnings on `Result<(), Uninhabited>` (e.g. `Result<(), !>`). @@ -210,7 +209,7 @@ pub fn is_ty_must_use<'tcx>( IsTyMustUse::Trivial } ty::Adt(def, _) => { - is_def_must_use(cx, def.did(), span).map_or(IsTyMustUse::No, IsTyMustUse::Yes) + is_def_must_use(cx, def.did(), expr.span).map_or(IsTyMustUse::No, IsTyMustUse::Yes) } ty::Alias(ty::Opaque | ty::Projection, ty::AliasTy { def_id: def, .. }) => { elaborate(cx.tcx, cx.tcx.explicit_item_self_bounds(def).iter_identity_copied()) @@ -223,7 +222,7 @@ pub fn is_ty_must_use<'tcx>( { let def_id = poly_trait_predicate.trait_ref.def_id; - is_def_must_use(cx, def_id, span) + is_def_must_use(cx, def_id, expr.span) } else { None } @@ -236,7 +235,7 @@ pub fn is_ty_must_use<'tcx>( .find_map(|predicate| { if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { let def_id = trait_ref.def_id; - is_def_must_use(cx, def_id, span) + is_def_must_use(cx, def_id, expr.span) .map(|inner| MustUsePath::TraitObject(Box::new(inner))) } else { None @@ -260,9 +259,7 @@ pub fn is_ty_must_use<'tcx>( .zip(elem_exprs) .enumerate() .filter_map(|(i, (ty, expr))| { - is_ty_must_use(cx, ty, expr, expr.span, simplify_uninhabited) - .yes() - .map(|path| (i, path)) + is_ty_must_use(cx, ty, expr, simplify_uninhabited).yes().map(|path| (i, path)) }) .collect::>(); @@ -276,21 +273,23 @@ pub fn is_ty_must_use<'tcx>( // If the array is empty we don't lint, to avoid false positives Some(0) | None => IsTyMustUse::No, // If the array is definitely non-empty, we can do `#[must_use]` checking. - Some(len) => is_ty_must_use(cx, ty, expr, span, simplify_uninhabited) + Some(len) => is_ty_must_use(cx, ty, expr, simplify_uninhabited) .map(|inner| MustUsePath::Array(Box::new(inner), len)), }, - ty::Closure(..) | ty::CoroutineClosure(..) => IsTyMustUse::Yes(MustUsePath::Closure(span)), + ty::Closure(..) | ty::CoroutineClosure(..) => { + IsTyMustUse::Yes(MustUsePath::Closure(expr.span)) + } ty::Coroutine(def_id, ..) => { // async fn should be treated as "implementor of `Future`" if cx.tcx.coroutine_is_async(def_id) && let Some(def_id) = cx.tcx.lang_items().future_trait() { IsTyMustUse::Yes(MustUsePath::Opaque(Box::new( - is_def_must_use(cx, def_id, span) + is_def_must_use(cx, def_id, expr.span) .expect("future trait is marked as `#[must_use]`"), ))) } else { - IsTyMustUse::Yes(MustUsePath::Coroutine(span)) + IsTyMustUse::Yes(MustUsePath::Coroutine(expr.span)) } } _ => IsTyMustUse::No, @@ -339,7 +338,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { let ty = cx.typeck_results().expr_ty(expr); - let must_use_result = is_ty_must_use(cx, ty, expr, expr.span, false); + let must_use_result = is_ty_must_use(cx, ty, expr, false); let type_lint_emitted_or_trivial = match must_use_result { IsTyMustUse::Yes(path) => { emit_must_use_untranslated(cx, &path, "", "", 1, false, expr_is_from_block); From f4407f241d8770ba88b6c8052fff71d0201d2b6d Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Wed, 25 Feb 2026 03:59:51 +0100 Subject: [PATCH 08/19] Update books --- src/doc/reference | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/reference b/src/doc/reference index 442cbef910566..50a1075e879be 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 442cbef9105662887d5eae2882ca551f3726bf28 +Subproject commit 50a1075e879be75aeec436252c84eef0fad489f4 From d13924caa729c14131ee4dd88f35c080095e1b05 Mon Sep 17 00:00:00 2001 From: Redddy Date: Wed, 25 Feb 2026 03:16:17 +0000 Subject: [PATCH 09/19] mGCA: Reject negated non-integer literals in const args --- compiler/rustc_ast_lowering/src/lib.rs | 21 ++++---- .../mgca/array-expr-complex.stderr | 8 ++-- .../mgca/explicit_anon_consts.stderr | 16 +++---- .../mgca/nonsensical-negated-literal.rs | 17 ++++--- .../mgca/nonsensical-negated-literal.stderr | 48 +++++++++++-------- 5 files changed, 61 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 24a7215ddb385..ee21f0df5e217 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2521,16 +2521,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ExprKind::Block(block, _) => { if let [stmt] = block.stmts.as_slice() && let StmtKind::Expr(expr) = &stmt.kind - && matches!( - expr.kind, - ExprKind::Block(..) - | ExprKind::Path(..) - | ExprKind::Struct(..) - | ExprKind::Call(..) - | ExprKind::Tup(..) - | ExprKind::Array(..) - | ExprKind::ConstBlock(..) - ) { return self.lower_expr_to_const_arg_direct(expr); } @@ -2553,6 +2543,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let span = expr.span; let literal = self.lower_lit(literal, span); + if !matches!(literal.node, LitKind::Int(..)) { + let err = + self.dcx().struct_span_err(expr.span, "negated literal must be an integer"); + + return ConstArg { + hir_id: self.next_id(), + kind: hir::ConstArgKind::Error(err.emit()), + span, + }; + } + ConstArg { hir_id: self.lower_node_id(expr.id), kind: hir::ConstArgKind::Literal { lit: literal.node, negated: true }, diff --git a/tests/ui/const-generics/mgca/array-expr-complex.stderr b/tests/ui/const-generics/mgca/array-expr-complex.stderr index beac1aa232f2f..544b0f05b4e44 100644 --- a/tests/ui/const-generics/mgca/array-expr-complex.stderr +++ b/tests/ui/const-generics/mgca/array-expr-complex.stderr @@ -5,16 +5,16 @@ LL | takes_array::<{ [1, 2, 1 + 2] }>(); | ^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/array-expr-complex.rs:10:19 + --> $DIR/array-expr-complex.rs:10:21 | LL | takes_array::<{ [X; 3] }>(); - | ^^^^^^^^^^ + | ^^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/array-expr-complex.rs:12:19 + --> $DIR/array-expr-complex.rs:12:21 | LL | takes_array::<{ [0; Y] }>(); - | ^^^^^^^^^^ + | ^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts.stderr index 714d7a804d111..1c72afce52c7d 100644 --- a/tests/ui/const-generics/mgca/explicit_anon_consts.stderr +++ b/tests/ui/const-generics/mgca/explicit_anon_consts.stderr @@ -1,8 +1,8 @@ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:13:33 + --> $DIR/explicit_anon_consts.rs:13:35 | LL | type Adt4 = Foo<{ 1 + 1 }>; - | ^^^^^^^^^ + | ^^^^^ error: complex const arguments must be placed inside of a `const` block --> $DIR/explicit_anon_consts.rs:21:34 @@ -17,22 +17,22 @@ LL | let _4 = [(); 1 + 1]; | ^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:45:43 + --> $DIR/explicit_anon_consts.rs:45:45 | LL | type const ITEM4: usize = { 1 + 1 }; - | ^^^^^^^^^ + | ^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:62:23 + --> $DIR/explicit_anon_consts.rs:62:25 | LL | T4: Trait, - | ^^^^^^^^^ + | ^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:71:50 + --> $DIR/explicit_anon_consts.rs:71:52 | LL | struct Default4; - | ^^^^^^^^^ + | ^^^^^ error: generic parameters may not be used in const operations --> $DIR/explicit_anon_consts.rs:42:51 diff --git a/tests/ui/const-generics/mgca/nonsensical-negated-literal.rs b/tests/ui/const-generics/mgca/nonsensical-negated-literal.rs index cd68a2c0d4301..4a3efb801cb01 100644 --- a/tests/ui/const-generics/mgca/nonsensical-negated-literal.rs +++ b/tests/ui/const-generics/mgca/nonsensical-negated-literal.rs @@ -1,4 +1,4 @@ -#![feature(adt_const_params, min_generic_const_args)] +#![feature(adt_const_params, min_generic_const_args, unsized_const_params)] #![expect(incomplete_features)] use std::marker::ConstParamTy; @@ -10,17 +10,22 @@ struct Foo { fn foo() {} +fn bar() {} + fn main() { foo::<{ Foo { field: -1_usize } }>(); //~^ ERROR: type annotations needed for the literal foo::<{ Foo { field: { -1_usize } } }>(); - //~^ ERROR: complex const arguments must be placed inside of a `const` block + //~^ ERROR: type annotations needed for the literal foo::<{ Foo { field: -true } }>(); - //~^ ERROR: the constant `true` is not of type `isize` + //~^ ERROR negated literal must be an integer foo::<{ Foo { field: { -true } } }>(); - //~^ ERROR: complex const arguments must be placed inside of a `const` block + //~^ ERROR negated literal must be an integer foo::<{ Foo { field: -"<3" } }>(); - //~^ ERROR: the constant `"<3"` is not of type `isize` + //~^ ERROR negated literal must be an integer foo::<{ Foo { field: { -"<3" } } }>(); - //~^ ERROR: complex const arguments must be placed inside of a `const` block + //~^ ERROR negated literal must be an integer + + bar::<{ -"hi" }>(); + //~^ ERROR: negated literal must be an integer } diff --git a/tests/ui/const-generics/mgca/nonsensical-negated-literal.stderr b/tests/ui/const-generics/mgca/nonsensical-negated-literal.stderr index 43ed4b71e33e7..60c559d1d5ba9 100644 --- a/tests/ui/const-generics/mgca/nonsensical-negated-literal.stderr +++ b/tests/ui/const-generics/mgca/nonsensical-negated-literal.stderr @@ -1,38 +1,44 @@ -error: complex const arguments must be placed inside of a `const` block - --> $DIR/nonsensical-negated-literal.rs:16:26 +error: negated literal must be an integer + --> $DIR/nonsensical-negated-literal.rs:20:26 | -LL | foo::<{ Foo { field: { -1_usize } } }>(); - | ^^^^^^^^^^^^ +LL | foo::<{ Foo { field: -true } }>(); + | ^^^^^ -error: complex const arguments must be placed inside of a `const` block - --> $DIR/nonsensical-negated-literal.rs:20:26 +error: negated literal must be an integer + --> $DIR/nonsensical-negated-literal.rs:22:28 | LL | foo::<{ Foo { field: { -true } } }>(); - | ^^^^^^^^^ + | ^^^^^ -error: complex const arguments must be placed inside of a `const` block +error: negated literal must be an integer --> $DIR/nonsensical-negated-literal.rs:24:26 | +LL | foo::<{ Foo { field: -"<3" } }>(); + | ^^^^^ + +error: negated literal must be an integer + --> $DIR/nonsensical-negated-literal.rs:26:28 + | LL | foo::<{ Foo { field: { -"<3" } } }>(); - | ^^^^^^^^^ + | ^^^^^ + +error: negated literal must be an integer + --> $DIR/nonsensical-negated-literal.rs:29:13 + | +LL | bar::<{ -"hi" }>(); + | ^^^^^ error: type annotations needed for the literal - --> $DIR/nonsensical-negated-literal.rs:14:26 + --> $DIR/nonsensical-negated-literal.rs:16:26 | LL | foo::<{ Foo { field: -1_usize } }>(); | ^^^^^^^^ -error: the constant `true` is not of type `isize` - --> $DIR/nonsensical-negated-literal.rs:18:13 - | -LL | foo::<{ Foo { field: -true } }>(); - | ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `bool` - -error: the constant `"<3"` is not of type `isize` - --> $DIR/nonsensical-negated-literal.rs:22:13 +error: type annotations needed for the literal + --> $DIR/nonsensical-negated-literal.rs:18:28 | -LL | foo::<{ Foo { field: -"<3" } }>(); - | ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `&'static str` +LL | foo::<{ Foo { field: { -1_usize } } }>(); + | ^^^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors From 51271084000fc9bcf1dc39be1c528767da6aa95c Mon Sep 17 00:00:00 2001 From: Redddy Date: Wed, 25 Feb 2026 04:05:12 +0000 Subject: [PATCH 10/19] mGCA: drop literal anon-const special case in parser --- compiler/rustc_parse/src/parser/path.rs | 22 ++++-------------- ...const-projections-in-assoc-const-ty.stderr | 21 ++++------------- ...array-expr-type-mismatch-in-where-bound.rs | 2 +- ...y-expr-type-mismatch-in-where-bound.stderr | 5 ++-- .../type_const-inherent-const-omitted-type.rs | 1 + ...e_const-inherent-const-omitted-type.stderr | 8 ++++++- .../mgca/type_const-mismatched-types.rs | 3 +-- .../mgca/type_const-mismatched-types.stderr | 23 ++++--------------- .../type_const-only-in-impl-omitted-type.rs | 1 + ...ype_const-only-in-impl-omitted-type.stderr | 10 ++++++-- 10 files changed, 34 insertions(+), 62 deletions(-) diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 9196d8d156d8e..f9a882c371d59 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -919,24 +919,10 @@ impl<'a> Parser<'a> { Ok((expr, mgca_disambiguation)) } - /// Under `min_generic_const_args` we still allow *some* anon consts to be written without - /// a `const` block as it makes things quite a lot nicer. This function is useful for contexts - /// where we would like to use `MgcaDisambiguation::Direct` but need to fudge it to be `AnonConst` - /// in the presence of literals. - // - /// FIXME(min_generic_const_args): In the long term it would be nice to have a way to directly - /// represent literals in `hir::ConstArgKind` so that we can remove this special case by not - /// needing an anon const. - pub fn mgca_direct_lit_hack(&self, expr: &Expr) -> MgcaDisambiguation { - match &expr.kind { - ast::ExprKind::Lit(_) => MgcaDisambiguation::AnonConst, - ast::ExprKind::Unary(ast::UnOp::Neg, expr) - if matches!(expr.kind, ast::ExprKind::Lit(_)) => - { - MgcaDisambiguation::AnonConst - } - _ => MgcaDisambiguation::Direct, - } + /// Under `min_generic_const_args`, prefer direct const arguments rather than + /// wrapping literals in anon consts. + pub fn mgca_direct_lit_hack(&self, _expr: &Expr) -> MgcaDisambiguation { + MgcaDisambiguation::Direct } /// Parse a generic argument in a path segment. diff --git a/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-const-projections-in-assoc-const-ty.stderr b/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-const-projections-in-assoc-const-ty.stderr index cc08c25906b66..7443c2977d54d 100644 --- a/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-const-projections-in-assoc-const-ty.stderr +++ b/tests/ui/const-generics/associated-const-bindings/dyn-compat-self-const-projections-in-assoc-const-ty.stderr @@ -1,27 +1,14 @@ -error[E0277]: the trait bound `FreshTy(0): A` is not satisfied +error: type annotations needed for the literal --> $DIR/dyn-compat-self-const-projections-in-assoc-const-ty.rs:32:33 | LL | let _: dyn A; - | ^ the trait `A` is not implemented for `FreshTy(0)` - | -help: the trait `A` is implemented for `()` - --> $DIR/dyn-compat-self-const-projections-in-assoc-const-ty.rs:20:1 - | -LL | impl A for () { - | ^^^^^^^^^^^^^ + | ^ -error[E0277]: the trait bound `FreshTy(0): A` is not satisfied +error: type annotations needed for the literal --> $DIR/dyn-compat-self-const-projections-in-assoc-const-ty.rs:34:34 | LL | let _: &dyn A = &(); - | ^ the trait `A` is not implemented for `FreshTy(0)` - | -help: the trait `A` is implemented for `()` - --> $DIR/dyn-compat-self-const-projections-in-assoc-const-ty.rs:20:1 - | -LL | impl A for () { - | ^^^^^^^^^^^^^ + | ^ error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/const-generics/mgca/array-expr-type-mismatch-in-where-bound.rs b/tests/ui/const-generics/mgca/array-expr-type-mismatch-in-where-bound.rs index cda519b96d4d8..98feccfc99c74 100644 --- a/tests/ui/const-generics/mgca/array-expr-type-mismatch-in-where-bound.rs +++ b/tests/ui/const-generics/mgca/array-expr-type-mismatch-in-where-bound.rs @@ -14,7 +14,7 @@ where fn bar() where - T: Trait2<3>, //~ ERROR: mismatched types + T: Trait2<3>, //~ ERROR: type annotations needed for the literal { } diff --git a/tests/ui/const-generics/mgca/array-expr-type-mismatch-in-where-bound.stderr b/tests/ui/const-generics/mgca/array-expr-type-mismatch-in-where-bound.stderr index be40e44742267..169282547fc1d 100644 --- a/tests/ui/const-generics/mgca/array-expr-type-mismatch-in-where-bound.stderr +++ b/tests/ui/const-generics/mgca/array-expr-type-mismatch-in-where-bound.stderr @@ -4,12 +4,11 @@ error: expected `usize`, found const array LL | T: Trait1<{ [] }>, | ^^ -error[E0308]: mismatched types +error: type annotations needed for the literal --> $DIR/array-expr-type-mismatch-in-where-bound.rs:17:15 | LL | T: Trait2<3>, - | ^ expected `[u8; 3]`, found integer + | ^ error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.rs b/tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.rs index 3262e79478bdb..c57121a4a26a0 100644 --- a/tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.rs +++ b/tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.rs @@ -6,6 +6,7 @@ struct A; impl A { type const B = 4; //~^ ERROR: missing type for `const` item + //~| ERROR: type annotations needed for the literal } fn main() {} diff --git a/tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.stderr b/tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.stderr index 77e54ab2f2e93..7fbb7461a4911 100644 --- a/tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.stderr +++ b/tests/ui/const-generics/mgca/type_const-inherent-const-omitted-type.stderr @@ -9,5 +9,11 @@ help: provide a type for the item LL | type const B: = 4; | ++++++++ -error: aborting due to 1 previous error +error: type annotations needed for the literal + --> $DIR/type_const-inherent-const-omitted-type.rs:7:20 + | +LL | type const B = 4; + | ^ + +error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/mgca/type_const-mismatched-types.rs b/tests/ui/const-generics/mgca/type_const-mismatched-types.rs index c73785f9a3e38..b17a5b2b978a6 100644 --- a/tests/ui/const-generics/mgca/type_const-mismatched-types.rs +++ b/tests/ui/const-generics/mgca/type_const-mismatched-types.rs @@ -3,7 +3,6 @@ type const FREE: u32 = 5_usize; //~^ ERROR the constant `5` is not of type `u32` -//~| ERROR mismatched types type const FREE2: isize = FREE; //~^ ERROR the constant `5` is not of type `isize` @@ -14,7 +13,7 @@ trait Tr { impl Tr for () { type const N: usize = false; - //~^ ERROR mismatched types + //~^ ERROR the constant `false` is not of type `usize` } fn main() {} diff --git a/tests/ui/const-generics/mgca/type_const-mismatched-types.stderr b/tests/ui/const-generics/mgca/type_const-mismatched-types.stderr index f7f64c535f602..e2c916cf6d05a 100644 --- a/tests/ui/const-generics/mgca/type_const-mismatched-types.stderr +++ b/tests/ui/const-generics/mgca/type_const-mismatched-types.stderr @@ -5,29 +5,16 @@ LL | type const FREE: u32 = 5_usize; | ^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `usize` error: the constant `5` is not of type `isize` - --> $DIR/type_const-mismatched-types.rs:8:1 + --> $DIR/type_const-mismatched-types.rs:7:1 | LL | type const FREE2: isize = FREE; | ^^^^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `usize` -error[E0308]: mismatched types - --> $DIR/type_const-mismatched-types.rs:16:27 +error: the constant `false` is not of type `usize` + --> $DIR/type_const-mismatched-types.rs:15:5 | LL | type const N: usize = false; - | ^^^^^ expected `usize`, found `bool` + | ^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool` -error[E0308]: mismatched types - --> $DIR/type_const-mismatched-types.rs:4:24 - | -LL | type const FREE: u32 = 5_usize; - | ^^^^^^^ expected `u32`, found `usize` - | -help: change the type of the numeric literal from `usize` to `u32` - | -LL - type const FREE: u32 = 5_usize; -LL + type const FREE: u32 = 5_u32; - | - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.rs b/tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.rs index a7ff9f0ce03f7..c8c7788eb135a 100644 --- a/tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.rs +++ b/tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.rs @@ -10,6 +10,7 @@ struct GoodS; impl BadTr for GoodS { type const NUM: = 84; //~^ ERROR: missing type for `const` item + //~| ERROR: type annotations needed for the literal } diff --git a/tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.stderr b/tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.stderr index 11a60246f6a68..99dc6398170db 100644 --- a/tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.stderr +++ b/tests/ui/const-generics/mgca/type_const-only-in-impl-omitted-type.stderr @@ -5,12 +5,18 @@ LL | type const NUM: = 84; | ^ help: provide a type for the associated constant: `usize` error: use of trait associated const not defined as `type const` - --> $DIR/type_const-only-in-impl-omitted-type.rs:16:43 + --> $DIR/type_const-only-in-impl-omitted-type.rs:17:43 | LL | fn accept_bad_tr>(_x: &T) {} | ^^^^^^^^^^^ | = note: the declaration in the trait must begin with `type const` not just `const` alone -error: aborting due to 2 previous errors +error: type annotations needed for the literal + --> $DIR/type_const-only-in-impl-omitted-type.rs:11:23 + | +LL | type const NUM: = 84; + | ^^ + +error: aborting due to 3 previous errors From 8eed8bd7bbf80ad06fc3262824aa39dd335eaa36 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 24 Feb 2026 08:42:04 +1100 Subject: [PATCH 11/19] Rename `pass_by_value` lint as `disallowed_pass_by_ref`. The name `pass_by_value` is completely wrong. The lint actually checks for the use of pass by reference for types marked with `rustc_pass_by_value`. The hardest part of this was choosing the new name. The `disallowed_` part of the name closely matches the following clippy lints: - `disallowed_macros` - `disallowed_methods` - `disallowed_names` - `disallowed_script_idents` - `disallowed_types` The `pass_by_value` part of the name aligns with the following clippy lints: - `needless_pass_by_value` - `needless_pass_by_ref_mut` - `trivially_copy_pass_by_ref` - `large_types_passed_by_value` (less so) --- compiler/rustc_ast/src/visit.rs | 6 +++-- ..._by_value.rs => disallowed_pass_by_ref.rs} | 24 +++++++++---------- compiler/rustc_lint/src/lib.rs | 10 ++++---- compiler/rustc_lint/src/lints.rs | 4 ++-- compiler/rustc_macros/src/query.rs | 8 +++---- compiler/rustc_mir_transform/src/gvn.rs | 3 ++- .../internal-lints/rustc_pass_by_value.rs | 4 ++-- .../internal-lints/rustc_pass_by_value.stderr | 4 ++-- .../rustc_pass_by_value_self.rs | 2 +- .../rustc_pass_by_value_self.stderr | 4 ++-- 10 files changed, 35 insertions(+), 34 deletions(-) rename compiler/rustc_lint/src/{pass_by_value.rs => disallowed_pass_by_ref.rs} (75%) diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 8556e8288670f..ff389607457d4 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -757,9 +757,11 @@ macro_rules! common_visitor_and_walkers { ) -> V::Result; } - // this is only used by the MutVisitor. We include this symmetry here to make writing other functions easier + // This is only used by the MutVisitor. We include this symmetry here to make writing other + // functions easier. $(${ignore($lt)} - #[expect(unused, rustc::pass_by_value)] + #[cfg_attr(not(bootstrap), expect(unused, rustc::disallowed_pass_by_ref))] + #[cfg_attr(bootstrap, expect(unused, rustc::pass_by_value))] #[inline] )? fn visit_span<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, span: &$($lt)? $($mut)? Span) -> V::Result { diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/disallowed_pass_by_ref.rs similarity index 75% rename from compiler/rustc_lint/src/pass_by_value.rs rename to compiler/rustc_lint/src/disallowed_pass_by_ref.rs index 5a4eb29433815..2a572a5a76bdb 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/disallowed_pass_by_ref.rs @@ -3,34 +3,34 @@ use rustc_hir::{self as hir, AmbigArg, GenericArg, PathSegment, QPath, TyKind, f use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::lints::PassByValueDiag; +use crate::lints::DisallowedPassByRefDiag; use crate::{LateContext, LateLintPass, LintContext}; declare_tool_lint! { - /// The `rustc_pass_by_value` lint marks a type with `#[rustc_pass_by_value]` requiring it to - /// always be passed by value. This is usually used for types that are thin wrappers around - /// references, so there is no benefit to an extra layer of indirection. (Example: `Ty` which - /// is a reference to an `Interned`) - pub rustc::PASS_BY_VALUE, + /// The `disallowed_pass_by_ref` lint detects if types marked with `#[rustc_pass_by_value]` are + /// passed by reference. Types with this marker are usually thin wrappers around references, so + /// there is no benefit to an extra layer of indirection. (Example: `Ty` which is a reference + /// to an `Interned`) + pub rustc::DISALLOWED_PASS_BY_REF, Warn, "pass by reference of a type flagged as `#[rustc_pass_by_value]`", report_in_external_macro: true } -declare_lint_pass!(PassByValue => [PASS_BY_VALUE]); +declare_lint_pass!(DisallowedPassByRef => [DISALLOWED_PASS_BY_REF]); -impl<'tcx> LateLintPass<'tcx> for PassByValue { +impl<'tcx> LateLintPass<'tcx> for DisallowedPassByRef { 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 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) { + if let Some(t) = path_for_rustc_pass_by_value(cx, inner_ty) { cx.emit_span_lint( - PASS_BY_VALUE, + DISALLOWED_PASS_BY_REF, ty.span, - PassByValueDiag { ty: t, suggestion: ty.span }, + DisallowedPassByRefDiag { ty: t, suggestion: ty.span }, ); } } @@ -39,7 +39,7 @@ impl<'tcx> LateLintPass<'tcx> for PassByValue { } } -fn path_for_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option { +fn path_for_rustc_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option { if let TyKind::Path(QPath::Resolved(_, path)) = &ty.kind { match path.res { Res::Def(_, def_id) if find_attr!(cx.tcx, def_id, RustcPassByValue(_)) => { diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index a5c3a889826c7..4c847671a070d 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -37,6 +37,7 @@ mod context; mod dangling; mod default_could_be_derived; mod deref_into_dyn_supertrait; +mod disallowed_pass_by_ref; mod drop_forget_useless; mod early; mod enum_intrinsics_non_enums; @@ -65,7 +66,6 @@ mod non_local_def; mod nonstandard_style; mod noop_method_call; mod opaque_hidden_inferred_bound; -mod pass_by_value; mod passes; mod precedence; mod ptr_nulls; @@ -88,6 +88,7 @@ use builtin::*; use dangling::*; use default_could_be_derived::DefaultCouldBeDerived; use deref_into_dyn_supertrait::*; +use disallowed_pass_by_ref::*; use drop_forget_useless::*; use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums; use for_loops_over_fallibles::*; @@ -109,7 +110,6 @@ use non_local_def::*; use nonstandard_style::*; use noop_method_call::*; use opaque_hidden_inferred_bound::*; -use pass_by_value::*; use precedence::*; use ptr_nulls::*; use redundant_semicolon::*; @@ -657,8 +657,8 @@ fn register_internals(store: &mut LintStore) { store.register_late_mod_pass(|_| Box::new(TypeIr)); store.register_lints(&BadOptAccess::lint_vec()); store.register_late_mod_pass(|_| Box::new(BadOptAccess)); - store.register_lints(&PassByValue::lint_vec()); - store.register_late_mod_pass(|_| Box::new(PassByValue)); + store.register_lints(&DisallowedPassByRef::lint_vec()); + store.register_late_mod_pass(|_| Box::new(DisallowedPassByRef)); store.register_lints(&SpanUseEqCtxt::lint_vec()); store.register_late_mod_pass(|_| Box::new(SpanUseEqCtxt)); store.register_lints(&SymbolInternStringLiteral::lint_vec()); @@ -676,7 +676,7 @@ fn register_internals(store: &mut LintStore) { LintId::of(POTENTIAL_QUERY_INSTABILITY), LintId::of(UNTRACKED_QUERY_INFORMATION), LintId::of(USAGE_OF_TY_TYKIND), - LintId::of(PASS_BY_VALUE), + LintId::of(DISALLOWED_PASS_BY_REF), LintId::of(LINT_PASS_IMPL_WITHOUT_MACRO), LintId::of(USAGE_OF_QUALIFIED_TY), LintId::of(NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT), diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 5627f34f82e97..b2ee01a9a0ee6 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1806,10 +1806,10 @@ pub(crate) struct AmbiguousNegativeLiteralsCurrentBehaviorSuggestion { pub end_span: Span, } -// pass_by_value.rs +// disallowed_pass_by_ref.rs #[derive(LintDiagnostic)] #[diag("passing `{$ty}` by reference")] -pub(crate) struct PassByValueDiag { +pub(crate) struct DisallowedPassByRefDiag { pub ty: String, #[suggestion("try passing by value", code = "{ty}", applicability = "maybe-incorrect")] pub suggestion: Span, diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 346604a46ef7d..9799d5b430868 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -293,12 +293,10 @@ fn make_helpers_for_query(query: &Query, streams: &mut HelperTokenStreams) { // Generate a function to check whether we should cache the query to disk, for some key. if let Some(CacheOnDiskIf { block, .. }) = modifiers.cache_on_disk_if.as_ref() { - // `pass_by_value`: some keys are marked with `rustc_pass_by_value`, but we take keys by - // reference here. - // FIXME: `pass_by_value` is badly named; `allow(rustc::pass_by_value)` actually means - // "allow pass by reference of `rustc_pass_by_value` types". + // `disallowed_pass_by_ref` is needed because some keys are `rustc_pass_by_value`. streams.cache_on_disk_if_fns_stream.extend(quote! { - #[allow(unused_variables, rustc::pass_by_value)] + #[cfg_attr(not(bootstrap), allow(unused_variables, rustc::disallowed_pass_by_ref))] + #[cfg_attr(bootstrap, allow(unused_variables, rustc::pass_by_value))] #[inline] pub fn #erased_name<'tcx>(tcx: TyCtxt<'tcx>, #key_pat: &#key_ty) -> bool #block diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 4e38b9dd6534b..0ef9a1348527d 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -300,7 +300,8 @@ impl<'a, 'tcx> ValueSet<'a, 'tcx> { /// Insert a `(Value, Ty)` pair to be deduplicated. /// Returns `true` as second tuple field if this value did not exist previously. - #[allow(rustc::pass_by_value)] // closures take `&VnIndex` + #[cfg_attr(not(bootstrap), allow(rustc::disallowed_pass_by_ref))] // closures take `&VnIndex` + #[cfg_attr(bootstrap, allow(rustc::pass_by_value))] fn insert(&mut self, ty: Ty<'tcx>, value: Value<'a, 'tcx>) -> (VnIndex, bool) { debug_assert!(match value { Value::Opaque(_) | Value::Address { .. } => false, diff --git a/tests/ui-fulldeps/internal-lints/rustc_pass_by_value.rs b/tests/ui-fulldeps/internal-lints/rustc_pass_by_value.rs index 06d2232be5179..42d75be966840 100644 --- a/tests/ui-fulldeps/internal-lints/rustc_pass_by_value.rs +++ b/tests/ui-fulldeps/internal-lints/rustc_pass_by_value.rs @@ -1,8 +1,8 @@ //@ compile-flags: -Z unstable-options - +//@ ignore-stage1 (this can be removed when nightly goes to 1.96) #![feature(rustc_attrs)] #![feature(rustc_private)] -#![deny(rustc::pass_by_value)] +#![deny(rustc::disallowed_pass_by_ref)] #![allow(unused)] extern crate rustc_middle; diff --git a/tests/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr b/tests/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr index 69cf20656d7b1..b2906ea1e1195 100644 --- a/tests/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr +++ b/tests/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr @@ -7,8 +7,8 @@ LL | ty_ref: &Ty<'_>, note: the lint level is defined here --> $DIR/rustc_pass_by_value.rs:5:9 | -LL | #![deny(rustc::pass_by_value)] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rustc::disallowed_pass_by_ref)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: passing `TyCtxt<'_>` by reference --> $DIR/rustc_pass_by_value.rs:16:18 diff --git a/tests/ui/internal-lints/rustc_pass_by_value_self.rs b/tests/ui/internal-lints/rustc_pass_by_value_self.rs index d2e0e272025f6..695c617d32f82 100644 --- a/tests/ui/internal-lints/rustc_pass_by_value_self.rs +++ b/tests/ui/internal-lints/rustc_pass_by_value_self.rs @@ -5,7 +5,7 @@ // Considering that all other `internal-lints` are tested here // this seems like the cleaner solution though. #![feature(rustc_attrs)] -#![deny(rustc::pass_by_value)] +#![deny(rustc::disallowed_pass_by_ref)] #![allow(unused)] #[rustc_pass_by_value] diff --git a/tests/ui/internal-lints/rustc_pass_by_value_self.stderr b/tests/ui/internal-lints/rustc_pass_by_value_self.stderr index fb39ed60b8235..d9e9f7e48506b 100644 --- a/tests/ui/internal-lints/rustc_pass_by_value_self.stderr +++ b/tests/ui/internal-lints/rustc_pass_by_value_self.stderr @@ -7,8 +7,8 @@ LL | fn by_ref(&self) {} note: the lint level is defined here --> $DIR/rustc_pass_by_value_self.rs:8:9 | -LL | #![deny(rustc::pass_by_value)] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rustc::disallowed_pass_by_ref)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: passing `Ty<'tcx>` by reference --> $DIR/rustc_pass_by_value_self.rs:30:21 From d2619b5dcfdcef4ad55d73cbb21ed2d031c128cd Mon Sep 17 00:00:00 2001 From: Redddy Date: Wed, 25 Feb 2026 04:19:38 +0000 Subject: [PATCH 12/19] Remove mgca_direct_lit_hack indirection --- compiler/rustc_parse/src/parser/expr.rs | 3 +-- compiler/rustc_parse/src/parser/item.rs | 4 +--- compiler/rustc_parse/src/parser/path.rs | 9 +-------- compiler/rustc_parse/src/parser/ty.rs | 3 +-- 4 files changed, 4 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 52dcade91aeaf..44e8f13dd2364 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1628,8 +1628,7 @@ impl<'a> Parser<'a> { let first_expr = self.parse_expr()?; if self.eat(exp!(Semi)) { // Repeating array syntax: `[ 0; 512 ]` - let count = - self.parse_expr_anon_const(|this, expr| this.mgca_direct_lit_hack(expr))?; + let count = self.parse_expr_anon_const(|_, _| MgcaDisambiguation::Direct)?; self.expect(close)?; ExprKind::Repeat(first_expr, count) } else if self.eat(exp!(Comma)) { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 69610d062919d..2ca4fac7fc46b 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1587,9 +1587,7 @@ impl<'a> Parser<'a> { let rhs = match (self.eat(exp!(Eq)), const_arg) { (true, true) => ConstItemRhsKind::TypeConst { - rhs: Some( - self.parse_expr_anon_const(|this, expr| this.mgca_direct_lit_hack(expr))?, - ), + rhs: Some(self.parse_expr_anon_const(|_, _| MgcaDisambiguation::Direct)?), }, (true, false) => ConstItemRhsKind::Body { rhs: Some(self.parse_expr()?) }, (false, true) => ConstItemRhsKind::TypeConst { rhs: None }, diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index f9a882c371d59..e514a08c8fb3a 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -915,14 +915,7 @@ impl<'a> Parser<'a> { }); } - let mgca_disambiguation = self.mgca_direct_lit_hack(&expr); - Ok((expr, mgca_disambiguation)) - } - - /// Under `min_generic_const_args`, prefer direct const arguments rather than - /// wrapping literals in anon consts. - pub fn mgca_direct_lit_hack(&self, _expr: &Expr) -> MgcaDisambiguation { - MgcaDisambiguation::Direct + Ok((expr, MgcaDisambiguation::Direct)) } /// Parse a generic argument in a path segment. diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 6ff165eb22b71..40335ef1b1bc7 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -658,8 +658,7 @@ impl<'a> Parser<'a> { }; let ty = if self.eat(exp!(Semi)) { - let mut length = - self.parse_expr_anon_const(|this, expr| this.mgca_direct_lit_hack(expr))?; + let mut length = self.parse_expr_anon_const(|_, _| MgcaDisambiguation::Direct)?; if let Err(e) = self.expect(exp!(CloseBracket)) { // Try to recover from `X` when `X::` works From b76b26db3b1388564044339909bfc153b95abf38 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 25 Feb 2026 14:03:17 +1100 Subject: [PATCH 13/19] Remove `QuerySystemFns`. It has a single use and doesn't provide any real value. Removing it allows the removal of two `for<'tcx>` qualifiers. --- .../rustc_middle/src/query/on_disk_cache.rs | 2 +- compiler/rustc_middle/src/query/plumbing.rs | 22 ++++++++----------- compiler/rustc_query_impl/src/lib.rs | 12 +++++----- compiler/rustc_query_impl/src/plumbing.rs | 6 ++--- 4 files changed, 18 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index e874e7e22b5c9..a9f4aee4049a7 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -261,7 +261,7 @@ impl OnDiskCache { tcx.sess.time("encode_query_results", || { let enc = &mut encoder; let qri = &mut query_result_index; - (tcx.query_system.fns.encode_query_results)(tcx, enc, qri); + (tcx.query_system.encode_query_results)(tcx, enc, qri); }); // Encode side effects. diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 9141f49bd45de..6d5be3213f2df 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -216,17 +216,6 @@ impl<'tcx, C: QueryCache> QueryVTable<'tcx, C> { } } -pub struct QuerySystemFns { - pub local_providers: Providers, - pub extern_providers: ExternProviders, - pub encode_query_results: for<'tcx> fn( - tcx: TyCtxt<'tcx>, - encoder: &mut CacheEncoder<'_, 'tcx>, - query_result_index: &mut EncodedDepNodeIndex, - ), - pub try_mark_green: for<'tcx> fn(tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool, -} - pub struct QuerySystem<'tcx> { pub arenas: WorkerLocal>, pub query_vtables: QueryVTables<'tcx>, @@ -237,7 +226,14 @@ pub struct QuerySystem<'tcx> { /// This is `None` if we are not incremental compilation mode pub on_disk_cache: Option, - pub fns: QuerySystemFns, + pub local_providers: Providers, + pub extern_providers: ExternProviders, + pub encode_query_results: fn( + tcx: TyCtxt<'tcx>, + encoder: &mut CacheEncoder<'_, 'tcx>, + query_result_index: &mut EncodedDepNodeIndex, + ), + pub try_mark_green: fn(tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool, pub jobs: AtomicU64, } @@ -329,7 +325,7 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn try_mark_green(self, dep_node: &dep_graph::DepNode) -> bool { - (self.query_system.fns.try_mark_green)(self, dep_node) + (self.query_system.try_mark_green)(self, dep_node) } } diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 890c0b2ef92c7..dc7dca4208b52 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -12,7 +12,7 @@ use rustc_data_structures::sync::AtomicU64; use rustc_middle::dep_graph; use rustc_middle::queries::{self, ExternProviders, Providers}; use rustc_middle::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex, OnDiskCache}; -use rustc_middle::query::plumbing::{QuerySystem, QuerySystemFns, QueryVTable}; +use rustc_middle::query::plumbing::{QuerySystem, QueryVTable}; use rustc_middle::query::{AsLocalKey, QueryCache, QueryMode}; use rustc_middle::ty::TyCtxt; use rustc_span::Span; @@ -59,12 +59,10 @@ pub fn query_system<'tcx>( arenas: Default::default(), query_vtables: make_query_vtables(incremental), on_disk_cache, - fns: QuerySystemFns { - local_providers, - extern_providers, - encode_query_results: encode_all_query_results, - try_mark_green, - }, + local_providers, + extern_providers, + encode_query_results: encode_all_query_results, + try_mark_green, jobs: AtomicU64::new(1), } } diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 7b5fd76c31958..275fe5b63d8b0 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -226,13 +226,13 @@ macro_rules! hash_result { macro_rules! call_provider { ([][$tcx:expr, $name:ident, $key:expr]) => {{ - ($tcx.query_system.fns.local_providers.$name)($tcx, $key) + ($tcx.query_system.local_providers.$name)($tcx, $key) }}; ([(separate_provide_extern) $($rest:tt)*][$tcx:expr, $name:ident, $key:expr]) => {{ if let Some(key) = $key.as_local_key() { - ($tcx.query_system.fns.local_providers.$name)($tcx, key) + ($tcx.query_system.local_providers.$name)($tcx, key) } else { - ($tcx.query_system.fns.extern_providers.$name)($tcx, $key) + ($tcx.query_system.extern_providers.$name)($tcx, $key) } }}; ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { From 608d85f989a35a10b9730a3ac50417dfad37419c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 25 Feb 2026 14:20:11 +1100 Subject: [PATCH 14/19] Move two functions into `hooks`. `QuerySystem` has two function pointers: `encode_query_results` and `try_mark_green`. These exist so that `rustc_middle` can call functions from upstream crates. But we have a more general mechanism for that: hooks. So this commit converts these two cases into hooks. --- compiler/rustc_middle/src/hooks/mod.rs | 8 ++++++++ compiler/rustc_middle/src/query/on_disk_cache.rs | 13 ++++++++++--- compiler/rustc_middle/src/query/plumbing.rs | 13 +------------ compiler/rustc_query_impl/src/lib.rs | 4 ++-- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs index c926604a41952..0ddcdac817b80 100644 --- a/compiler/rustc_middle/src/hooks/mod.rs +++ b/compiler/rustc_middle/src/hooks/mod.rs @@ -9,6 +9,7 @@ use rustc_span::def_id::{CrateNum, LocalDefId}; use rustc_span::{ExpnHash, ExpnId}; use crate::mir; +use crate::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex}; use crate::ty::{Ty, TyCtxt}; macro_rules! declare_hooks { @@ -107,6 +108,13 @@ declare_hooks! { /// /// Creates the MIR for a given `DefId`, including unreachable code. hook build_mir_inner_impl(def: LocalDefId) -> mir::Body<'tcx>; + + hook try_mark_green(dep_node: &crate::dep_graph::DepNode) -> bool; + + hook encode_all_query_results( + encoder: &mut CacheEncoder<'_, 'tcx>, + query_result_index: &mut EncodedDepNodeIndex + ) -> (); } #[cold] diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index a9f4aee4049a7..8db48fc2f9956 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -1,6 +1,6 @@ use std::collections::hash_map::Entry; -use std::mem; use std::sync::Arc; +use std::{fmt, mem}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::memmap::Mmap; @@ -261,7 +261,7 @@ impl OnDiskCache { tcx.sess.time("encode_query_results", || { let enc = &mut encoder; let qri = &mut query_result_index; - (tcx.query_system.encode_query_results)(tcx, enc, qri); + tcx.encode_all_query_results(enc, qri); }); // Encode side effects. @@ -508,7 +508,7 @@ impl<'a, 'tcx> CacheDecoder<'a, 'tcx> { // tag matches and the correct amount of bytes was read. fn decode_tagged(decoder: &mut D, expected_tag: T) -> V where - T: Decodable + Eq + std::fmt::Debug, + T: Decodable + Eq + fmt::Debug, V: Decodable, D: Decoder, { @@ -829,6 +829,13 @@ pub struct CacheEncoder<'a, 'tcx> { symbol_index_table: FxHashMap, } +impl<'a, 'tcx> fmt::Debug for CacheEncoder<'a, 'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Add more details here if/when necessary. + f.write_str("CacheEncoder") + } +} + impl<'a, 'tcx> CacheEncoder<'a, 'tcx> { #[inline] fn source_file_index(&mut self, source_file: Arc) -> SourceFileIndex { diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 6d5be3213f2df..c2d524d200dee 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -11,11 +11,10 @@ use rustc_macros::HashStable; use rustc_span::{ErrorGuaranteed, Span}; pub use sealed::IntoQueryParam; -use crate::dep_graph; use crate::dep_graph::{DepKind, DepNode, DepNodeIndex, SerializedDepNodeIndex}; use crate::ich::StableHashingContext; use crate::queries::{ExternProviders, Providers, QueryArenas, QueryVTables}; -use crate::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex, OnDiskCache}; +use crate::query::on_disk_cache::OnDiskCache; use crate::query::stack::{QueryStackDeferred, QueryStackFrame, QueryStackFrameExtra}; use crate::query::{QueryCache, QueryInfo, QueryJob}; use crate::ty::TyCtxt; @@ -228,12 +227,6 @@ pub struct QuerySystem<'tcx> { pub local_providers: Providers, pub extern_providers: ExternProviders, - pub encode_query_results: fn( - tcx: TyCtxt<'tcx>, - encoder: &mut CacheEncoder<'_, 'tcx>, - query_result_index: &mut EncodedDepNodeIndex, - ), - pub try_mark_green: fn(tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool, pub jobs: AtomicU64, } @@ -323,10 +316,6 @@ impl<'tcx> TyCtxt<'tcx> { pub fn at(self, span: Span) -> TyCtxtAt<'tcx> { TyCtxtAt { tcx: self, span } } - - pub fn try_mark_green(self, dep_node: &dep_graph::DepNode) -> bool { - (self.query_system.try_mark_green)(self, dep_node) - } } macro_rules! query_helper_param_ty { diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index dc7dca4208b52..afb41f69b5ebb 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -61,8 +61,6 @@ pub fn query_system<'tcx>( on_disk_cache, local_providers, extern_providers, - encode_query_results: encode_all_query_results, - try_mark_green, jobs: AtomicU64::new(1), } } @@ -72,4 +70,6 @@ rustc_middle::rustc_with_all_queries! { define_queries! } pub fn provide(providers: &mut rustc_middle::util::Providers) { providers.hooks.alloc_self_profile_query_strings = alloc_self_profile_query_strings; providers.hooks.query_key_hash_verify_all = query_key_hash_verify_all; + providers.hooks.encode_all_query_results = encode_all_query_results; + providers.hooks.try_mark_green = try_mark_green; } From f1ec10ecbd8628f315bee531ddee87f57cdb8096 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 8 Jan 2026 12:17:55 +0000 Subject: [PATCH 15/19] deprecate `Eq::assert_receiver_is_total_eq` and emit a FCW on manual impls --- .../src/deriving/cmp/eq.rs | 5 +- compiler/rustc_lint/src/builtin.rs | 64 ++++++++++++++++++- compiler/rustc_lint/src/lib.rs | 1 + compiler/rustc_lint/src/lints.rs | 5 ++ compiler/rustc_span/src/symbol.rs | 2 + library/core/src/cmp.rs | 14 +++- tests/ui/deriving/deriving-all-codegen.stdout | 48 +++++--------- .../internal_eq_trait_method_impls.rs | 48 ++++++++++++++ .../internal_eq_trait_method_impls.stderr | 41 ++++++++++++ tests/ui/stats/macro-stats.stderr | 2 +- 10 files changed, 188 insertions(+), 42 deletions(-) create mode 100644 tests/ui/deriving/internal_eq_trait_method_impls.rs create mode 100644 tests/ui/deriving/internal_eq_trait_method_impls.stderr diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index d9b82e97cb462..650e6262b35e8 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -26,15 +26,14 @@ pub(crate) fn expand_deriving_eq( additional_bounds: Vec::new(), supports_unions: true, methods: vec![MethodDef { - name: sym::assert_receiver_is_total_eq, + name: sym::assert_fields_are_eq, generics: Bounds::empty(), explicit_self: true, nonself_args: vec![], ret_ty: Unit, attributes: thin_vec![ - cx.attr_word(sym::inline, span), cx.attr_nested_word(sym::doc, sym::hidden, span), - cx.attr_nested_word(sym::coverage, sym::off, span) + cx.attr_nested_word(sym::coverage, sym::off, span), ], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(Box::new(|a, b, c| { diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 22636959f0db5..e0590263737cb 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -24,12 +24,11 @@ use rustc_ast_pretty::pprust::expr_to_string; use rustc_attr_parsing::AttributeParser; use rustc_errors::{Applicability, LintDiagnostic, msg}; use rustc_feature::GateIssue; -use rustc_hir as hir; use rustc_hir::attrs::{AttributeKind, DocAttribute}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_hir::intravisit::FnKind as HirFnKind; -use rustc_hir::{Body, FnDecl, ImplItemImplKind, PatKind, PredicateOrigin, find_attr}; +use rustc_hir::{self as hir, Body, FnDecl, ImplItemImplKind, PatKind, PredicateOrigin, find_attr}; use rustc_middle::bug; use rustc_middle::lint::LevelAndSource; use rustc_middle::ty::layout::LayoutOf; @@ -59,7 +58,7 @@ use crate::lints::{ BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasBounds, BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit, BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment, - BuiltinUnusedDocCommentSub, BuiltinWhileTrue, InvalidAsmLabel, + BuiltinUnusedDocCommentSub, BuiltinWhileTrue, EqInternalMethodImplemented, InvalidAsmLabel, }; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext}; declare_lint! { @@ -3184,3 +3183,62 @@ impl EarlyLintPass for SpecialModuleName { } } } + +declare_lint! { + /// The `internal_eq_trait_method_impls` lint detects manual + /// implementations of `Eq::assert_receiver_is_total_eq`. + /// + /// ### Example + /// + /// ```rust + /// #[derive(PartialEq)] + /// pub struct Foo; + /// + /// impl Eq for Foo { + /// fn assert_receiver_is_total_eq(&self) {} + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This method existed so that `#[derive(Eq)]` could check that all + /// fields of a type implement `Eq`. Other users were never supposed + /// to implement it and it was hidden from documentation. + /// + /// Unfortunately, it was not explicitly marked as unstable and some + /// people have now mistakenly assumed they had to implement this method. + /// + /// As the method is never called by the standard library, you can safely + /// remove any implementations of the method and just write `impl Eq for Foo {}`. + /// + /// This is a [future-incompatible] lint to transition this to a hard + /// error in the future. See [issue #152336] for more details. + /// + /// [issue #152336]: https://github.com/rust-lang/rust/issues/152336 + pub INTERNAL_EQ_TRAIT_METHOD_IMPLS, + Warn, + "manual implementation of the internal `Eq::assert_receiver_is_total_eq` method", + @future_incompatible = FutureIncompatibleInfo { + reason: fcw!(FutureReleaseError #152336), + report_in_deps: false, + }; +} + +declare_lint_pass!(InternalEqTraitMethodImpls => [INTERNAL_EQ_TRAIT_METHOD_IMPLS]); + +impl<'tcx> LateLintPass<'tcx> for InternalEqTraitMethodImpls { + fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx rustc_hir::ImplItem<'tcx>) { + if let ImplItemImplKind::Trait { defaultness: _, trait_item_def_id: Ok(trait_item_def_id) } = + item.impl_kind + && cx.tcx.is_diagnostic_item(sym::assert_receiver_is_total_eq, trait_item_def_id) + { + cx.emit_span_lint( + INTERNAL_EQ_TRAIT_METHOD_IMPLS, + item.span, + EqInternalMethodImplemented, + ); + } + } +} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index cd0d8765dd933..4fcc2051fb393 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -250,6 +250,7 @@ late_lint_methods!( FunctionCastsAsInteger: FunctionCastsAsInteger, CheckTransmutes: CheckTransmutes, LifetimeSyntax: LifetimeSyntax, + InternalEqTraitMethodImpls: InternalEqTraitMethodImpls, ] ] ); diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 285a7b7f52935..3c57382e6b173 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3926,3 +3926,8 @@ pub(crate) struct MalformedOnConstAttrLint { #[label("invalid option found here")] pub span: Span, } + +#[derive(LintDiagnostic)] +#[diag("`Eq::assert_receiver_is_total_eq` should never be implemented by hand")] +#[note("this method was used to add checks to the `Eq` derive macro")] +pub(crate) struct EqInternalMethodImplemented; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 3d40b7317459b..422a15b060cc0 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -432,6 +432,7 @@ symbols! { assert, assert_eq, assert_eq_macro, + assert_fields_are_eq, assert_inhabited, assert_macro, assert_mem_uninitialized_valid, @@ -1089,6 +1090,7 @@ symbols! { integer_: "integer", // underscore to avoid clashing with the function `sym::integer` below integral, internal, + internal_eq_trait_method_impls, internal_features, into_async_iter_into_iter, into_future, diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 78ea1f1113258..b3dc435dda176 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -336,16 +336,24 @@ pub macro PartialEq($item:item) { #[rustc_diagnostic_item = "Eq"] #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] pub const trait Eq: [const] PartialEq + PointeeSized { - // this method is used solely by `impl Eq or #[derive(Eq)]` to assert that every component of a - // type implements `Eq` itself. The current deriving infrastructure means doing this assertion - // without using a method on this trait is nearly impossible. + // This method was used solely by `#[derive(Eq)]` to assert that every component of a + // type implements `Eq` itself. // // This should never be implemented by hand. #[doc(hidden)] #[coverage(off)] #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_diagnostic_item = "assert_receiver_is_total_eq"] + #[deprecated(since = "1.95.0", note = "implementation detail of `#[derive(Eq)]`")] fn assert_receiver_is_total_eq(&self) {} + + // FIXME (#152504): this method is used solely by `#[derive(Eq)]` to assert that + // every component of a type implements `Eq` itself. It will be removed again soon. + #[doc(hidden)] + #[coverage(off)] + #[unstable(feature = "derive_eq_internals", issue = "none")] + fn assert_fields_are_eq(&self) {} } /// Derive macro generating an impl of the trait [`Eq`]. diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout index 2a05d77f8f6da..19c8090e8de8b 100644 --- a/tests/ui/deriving/deriving-all-codegen.stdout +++ b/tests/ui/deriving/deriving-all-codegen.stdout @@ -62,10 +62,9 @@ impl ::core::cmp::PartialEq for Empty { } #[automatically_derived] impl ::core::cmp::Eq for Empty { - #[inline] #[doc(hidden)] #[coverage(off)] - fn assert_receiver_is_total_eq(&self) {} + fn assert_fields_are_eq(&self) {} } #[automatically_derived] impl ::core::cmp::PartialOrd for Empty { @@ -139,10 +138,9 @@ impl ::core::cmp::PartialEq for Point { } #[automatically_derived] impl ::core::cmp::Eq for Point { - #[inline] #[doc(hidden)] #[coverage(off)] - fn assert_receiver_is_total_eq(&self) { + fn assert_fields_are_eq(&self) { let _: ::core::cmp::AssertParamIsEq; } } @@ -227,10 +225,9 @@ impl ::core::cmp::PartialEq for PackedPoint { } #[automatically_derived] impl ::core::cmp::Eq for PackedPoint { - #[inline] #[doc(hidden)] #[coverage(off)] - fn assert_receiver_is_total_eq(&self) { + fn assert_fields_are_eq(&self) { let _: ::core::cmp::AssertParamIsEq; } } @@ -310,10 +307,9 @@ impl ::core::cmp::PartialEq for TupleSingleField { } #[automatically_derived] impl ::core::cmp::Eq for TupleSingleField { - #[inline] #[doc(hidden)] #[coverage(off)] - fn assert_receiver_is_total_eq(&self) { + fn assert_fields_are_eq(&self) { let _: ::core::cmp::AssertParamIsEq; } } @@ -385,10 +381,9 @@ impl ::core::cmp::PartialEq for SingleField { } #[automatically_derived] impl ::core::cmp::Eq for SingleField { - #[inline] #[doc(hidden)] #[coverage(off)] - fn assert_receiver_is_total_eq(&self) { + fn assert_fields_are_eq(&self) { let _: ::core::cmp::AssertParamIsEq; } } @@ -490,10 +485,9 @@ impl ::core::cmp::PartialEq for Big { } #[automatically_derived] impl ::core::cmp::Eq for Big { - #[inline] #[doc(hidden)] #[coverage(off)] - fn assert_receiver_is_total_eq(&self) { + fn assert_fields_are_eq(&self) { let _: ::core::cmp::AssertParamIsEq; } } @@ -754,10 +748,9 @@ impl ::core::cmp::PartialEq for Unsized { } #[automatically_derived] impl ::core::cmp::Eq for Unsized { - #[inline] #[doc(hidden)] #[coverage(off)] - fn assert_receiver_is_total_eq(&self) { + fn assert_fields_are_eq(&self) { let _: ::core::cmp::AssertParamIsEq<[u32]>; } } @@ -849,10 +842,9 @@ impl #[automatically_derived] impl ::core::cmp::Eq for Generic where T::A: ::core::cmp::Eq { - #[inline] #[doc(hidden)] #[coverage(off)] - fn assert_receiver_is_total_eq(&self) { + fn assert_fields_are_eq(&self) { let _: ::core::cmp::AssertParamIsEq; let _: ::core::cmp::AssertParamIsEq; let _: ::core::cmp::AssertParamIsEq; @@ -971,10 +963,9 @@ impl ::core::cmp::Eq for PackedGeneric where T::A: ::core::cmp::Eq + ::core::marker::Copy { - #[inline] #[doc(hidden)] #[coverage(off)] - fn assert_receiver_is_total_eq(&self) { + fn assert_fields_are_eq(&self) { let _: ::core::cmp::AssertParamIsEq; let _: ::core::cmp::AssertParamIsEq; let _: ::core::cmp::AssertParamIsEq; @@ -1056,10 +1047,9 @@ impl ::core::cmp::PartialEq for Enum0 { } #[automatically_derived] impl ::core::cmp::Eq for Enum0 { - #[inline] #[doc(hidden)] #[coverage(off)] - fn assert_receiver_is_total_eq(&self) {} + fn assert_fields_are_eq(&self) {} } #[automatically_derived] impl ::core::cmp::PartialOrd for Enum0 { @@ -1126,10 +1116,9 @@ impl ::core::cmp::PartialEq for Enum1 { } #[automatically_derived] impl ::core::cmp::Eq for Enum1 { - #[inline] #[doc(hidden)] #[coverage(off)] - fn assert_receiver_is_total_eq(&self) { + fn assert_fields_are_eq(&self) { let _: ::core::cmp::AssertParamIsEq; } } @@ -1192,10 +1181,9 @@ impl ::core::cmp::PartialEq for Fieldless1 { } #[automatically_derived] impl ::core::cmp::Eq for Fieldless1 { - #[inline] #[doc(hidden)] #[coverage(off)] - fn assert_receiver_is_total_eq(&self) {} + fn assert_fields_are_eq(&self) {} } #[automatically_derived] impl ::core::cmp::PartialOrd for Fieldless1 { @@ -1269,10 +1257,9 @@ impl ::core::cmp::PartialEq for Fieldless { } #[automatically_derived] impl ::core::cmp::Eq for Fieldless { - #[inline] #[doc(hidden)] #[coverage(off)] - fn assert_receiver_is_total_eq(&self) {} + fn assert_fields_are_eq(&self) {} } #[automatically_derived] impl ::core::cmp::PartialOrd for Fieldless { @@ -1379,10 +1366,9 @@ impl ::core::cmp::PartialEq for Mixed { } #[automatically_derived] impl ::core::cmp::Eq for Mixed { - #[inline] #[doc(hidden)] #[coverage(off)] - fn assert_receiver_is_total_eq(&self) { + fn assert_fields_are_eq(&self) { let _: ::core::cmp::AssertParamIsEq; let _: ::core::cmp::AssertParamIsEq>; let _: ::core::cmp::AssertParamIsEq>; @@ -1577,10 +1563,9 @@ impl ::core::cmp::PartialEq for Fielded { } #[automatically_derived] impl ::core::cmp::Eq for Fielded { - #[inline] #[doc(hidden)] #[coverage(off)] - fn assert_receiver_is_total_eq(&self) { + fn assert_fields_are_eq(&self) { let _: ::core::cmp::AssertParamIsEq; let _: ::core::cmp::AssertParamIsEq; let _: ::core::cmp::AssertParamIsEq>; @@ -1699,10 +1684,9 @@ impl #[automatically_derived] impl ::core::cmp::Eq for EnumGeneric { - #[inline] #[doc(hidden)] #[coverage(off)] - fn assert_receiver_is_total_eq(&self) { + fn assert_fields_are_eq(&self) { let _: ::core::cmp::AssertParamIsEq; let _: ::core::cmp::AssertParamIsEq; } diff --git a/tests/ui/deriving/internal_eq_trait_method_impls.rs b/tests/ui/deriving/internal_eq_trait_method_impls.rs new file mode 100644 index 0000000000000..b2605fe3c8668 --- /dev/null +++ b/tests/ui/deriving/internal_eq_trait_method_impls.rs @@ -0,0 +1,48 @@ +#![deny(deprecated, internal_eq_trait_method_impls)] +pub struct Bad; + +impl PartialEq for Bad { + fn eq(&self, _: &Self) -> bool { + true + } +} + +impl Eq for Bad { + fn assert_receiver_is_total_eq(&self) {} + //~^ ERROR: `Eq::assert_receiver_is_total_eq` should never be implemented by hand [internal_eq_trait_method_impls] + //~| WARN: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +} + +#[derive(PartialEq, Eq)] +pub struct Good; + +#[derive(PartialEq)] +pub struct Good2; + +impl Eq for Good2 {} + +pub struct Foo; + +pub trait SameName { + fn assert_receiver_is_total_eq(&self) {} +} + +impl SameName for Foo { + fn assert_receiver_is_total_eq(&self) {} +} + +pub fn main() { + Foo.assert_receiver_is_total_eq(); + Good2.assert_receiver_is_total_eq(); + //~^ ERROR: use of deprecated method `std::cmp::Eq::assert_receiver_is_total_eq`: implementation detail of `#[derive(Eq)]` [deprecated] + Good.assert_receiver_is_total_eq(); + //~^ ERROR: use of deprecated method `std::cmp::Eq::assert_receiver_is_total_eq`: implementation detail of `#[derive(Eq)]` [deprecated] + Bad.assert_receiver_is_total_eq(); + //~^ ERROR: use of deprecated method `std::cmp::Eq::assert_receiver_is_total_eq`: implementation detail of `#[derive(Eq)]` [deprecated] +} + +#[forbid(internal_eq_trait_method_impls)] +mod forbid { + #[derive(PartialEq, Eq)] + pub struct Foo; +} diff --git a/tests/ui/deriving/internal_eq_trait_method_impls.stderr b/tests/ui/deriving/internal_eq_trait_method_impls.stderr new file mode 100644 index 0000000000000..8ff8fe337a78c --- /dev/null +++ b/tests/ui/deriving/internal_eq_trait_method_impls.stderr @@ -0,0 +1,41 @@ +error: use of deprecated method `std::cmp::Eq::assert_receiver_is_total_eq`: implementation detail of `#[derive(Eq)]` + --> $DIR/internal_eq_trait_method_impls.rs:36:11 + | +LL | Good2.assert_receiver_is_total_eq(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/internal_eq_trait_method_impls.rs:1:9 + | +LL | #![deny(deprecated, internal_eq_trait_method_impls)] + | ^^^^^^^^^^ + +error: use of deprecated method `std::cmp::Eq::assert_receiver_is_total_eq`: implementation detail of `#[derive(Eq)]` + --> $DIR/internal_eq_trait_method_impls.rs:38:10 + | +LL | Good.assert_receiver_is_total_eq(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: use of deprecated method `std::cmp::Eq::assert_receiver_is_total_eq`: implementation detail of `#[derive(Eq)]` + --> $DIR/internal_eq_trait_method_impls.rs:40:9 + | +LL | Bad.assert_receiver_is_total_eq(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `Eq::assert_receiver_is_total_eq` should never be implemented by hand + --> $DIR/internal_eq_trait_method_impls.rs:11:5 + | +LL | fn assert_receiver_is_total_eq(&self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #152336 + = note: this method was used to add checks to the `Eq` derive macro +note: the lint level is defined here + --> $DIR/internal_eq_trait_method_impls.rs:1:21 + | +LL | #![deny(deprecated, internal_eq_trait_method_impls)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/stats/macro-stats.stderr b/tests/ui/stats/macro-stats.stderr index a48940460f91e..4a94b81452a90 100644 --- a/tests/ui/stats/macro-stats.stderr +++ b/tests/ui/stats/macro-stats.stderr @@ -8,7 +8,7 @@ macro-stats #[derive(Hash)] 2 17 8.5 macro-stats q! 1 26 26.0 519 519.0 macro-stats #[derive(Ord)] 1 15 15.0 503 503.0 macro-stats #[derive(Default)] 2 16 8.0 403 201.5 -macro-stats #[derive(Eq)] 1 11 11.0 319 319.0 +macro-stats #[derive(Eq)] 1 10 10.0 298 298.0 macro-stats #[derive(Debug)] 1 8 8.0 277 277.0 macro-stats #[derive(PartialEq)] 1 9 9.0 267 267.0 macro-stats #[derive(Copy)] 1 2 2.0 61 61.0 From 82e5ed66de87aa65bd801f5d9798b6e6fb07a749 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 Feb 2026 15:03:29 +0100 Subject: [PATCH 16/19] interpret: avoid dummy spans in the stacktrace --- compiler/rustc_const_eval/src/const_eval/error.rs | 2 +- .../rustc_const_eval/src/interpret/eval_context.rs | 2 +- compiler/rustc_const_eval/src/interpret/stack.rs | 11 +++++++++-- src/tools/miri/src/diagnostics.rs | 5 +++-- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 7efef74e70aa3..75954449ef0a9 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -110,7 +110,7 @@ pub fn get_span_and_frames<'tcx>( tcx: TyCtxtAt<'tcx>, stack: &[Frame<'tcx, impl Provenance, impl Sized>], ) -> (Span, Vec) { - let mut stacktrace = Frame::generate_stacktrace_from_stack(stack); + let mut stacktrace = Frame::generate_stacktrace_from_stack(stack, *tcx); // Filter out `requires_caller_location` frames. stacktrace.retain(|frame| !frame.instance.def.requires_caller_location(*tcx)); let span = stacktrace.last().map(|f| f.span).unwrap_or(tcx.span); diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index c2f772d560752..3a887f8afaa57 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -635,7 +635,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { #[must_use] pub fn generate_stacktrace(&self) -> Vec> { - Frame::generate_stacktrace_from_stack(self.stack()) + Frame::generate_stacktrace_from_stack(self.stack(), *self.tcx) } pub fn adjust_nan(&self, f: F2, inputs: &[F1]) -> F2 diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs index a55bea60cd6e2..6da6ed2ec757a 100644 --- a/compiler/rustc_const_eval/src/interpret/stack.rs +++ b/compiler/rustc_const_eval/src/interpret/stack.rs @@ -321,12 +321,15 @@ impl<'tcx, Prov: Provenance, Extra> Frame<'tcx, Prov, Extra> { } #[must_use] - pub fn generate_stacktrace_from_stack(stack: &[Self]) -> Vec> { + pub fn generate_stacktrace_from_stack( + stack: &[Self], + tcx: TyCtxt<'tcx>, + ) -> Vec> { let mut frames = Vec::new(); // This deliberately does *not* honor `requires_caller_location` since it is used for much // more than just panics. for frame in stack.iter().rev() { - let span = match frame.loc { + let mut span = match frame.loc { Left(loc) => { // If the stacktrace passes through MIR-inlined source scopes, add them. let mir::SourceInfo { mut span, scope } = *frame.body.source_info(loc); @@ -340,6 +343,10 @@ impl<'tcx, Prov: Provenance, Extra> Frame<'tcx, Prov, Extra> { } Right(span) => span, }; + if span.is_dummy() { + // Some statements lack a proper span; point at the function instead. + span = tcx.def_span(frame.instance.def_id()); + } frames.push(FrameInfo { span, instance: frame.instance }); } trace!("generate stacktrace: {:#?}", frames); diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 71ec9723de8e9..35217da37e5b5 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -257,7 +257,7 @@ pub fn report_result<'tcx>( // The "active" thread might actually be terminated, so we ignore it. let mut any_pruned = false; for (thread, stack) in ecx.machine.threads.all_blocked_stacks() { - let stacktrace = Frame::generate_stacktrace_from_stack(stack); + let stacktrace = Frame::generate_stacktrace_from_stack(stack, *ecx.tcx); let (stacktrace, was_pruned) = prune_stacktrace(stacktrace, &ecx.machine); any_pruned |= was_pruned; report_msg( @@ -633,7 +633,8 @@ impl<'tcx> MiriMachine<'tcx> { pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) { use NonHaltingDiagnostic::*; - let stacktrace = Frame::generate_stacktrace_from_stack(self.threads.active_thread_stack()); + let stacktrace = + Frame::generate_stacktrace_from_stack(self.threads.active_thread_stack(), self.tcx); let (stacktrace, _was_pruned) = prune_stacktrace(stacktrace, self); let (label, diag_level) = match &e { From ff0f239bb15805f8137b66bd2a27dcfb16b5ba0e Mon Sep 17 00:00:00 2001 From: mu001999 Date: Sun, 22 Feb 2026 23:16:58 +0800 Subject: [PATCH 17/19] Remove redundant self usages --- compiler/rustc_attr_parsing/src/attributes/stability.rs | 2 +- compiler/rustc_attr_parsing/src/session_diagnostics.rs | 2 +- compiler/rustc_builtin_macros/src/cmdline_attrs.rs | 2 +- .../src/debuginfo/metadata/enums/cpp_like.rs | 2 +- .../rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs | 2 +- .../src/debuginfo/metadata/enums/native.rs | 5 ++--- .../rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs | 2 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 2 +- compiler/rustc_hir_typeck/src/fallback.rs | 2 +- compiler/rustc_lint/src/builtin.rs | 2 +- compiler/rustc_lint/src/map_unit_fn.rs | 2 +- compiler/rustc_lint/src/reference_casting.rs | 2 +- compiler/rustc_lint/src/transmute.rs | 2 +- compiler/rustc_lint/src/unqualified_local_imports.rs | 2 +- compiler/rustc_middle/src/ty/codec.rs | 3 +-- compiler/rustc_middle/src/ty/context/impl_interner.rs | 2 +- compiler/rustc_middle/src/ty/pattern.rs | 4 +--- compiler/rustc_mir_build/src/builder/expr/as_constant.rs | 2 +- .../rustc_mir_transform/src/lint_tail_expr_drop_order.rs | 2 +- compiler/rustc_parse/src/parser/item.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 2 +- .../rustc_trait_selection/src/error_reporting/infer/mod.rs | 2 +- library/alloc/src/vec/drain.rs | 3 +-- library/alloc/src/vec/into_iter.rs | 3 +-- library/alloc/src/vec/spec_extend.rs | 2 +- library/alloc/src/vec/spec_from_iter.rs | 2 +- library/alloc/src/vec/splice.rs | 3 +-- library/coretests/tests/cmp.rs | 2 +- library/coretests/tests/iter/adapters/array_chunks.rs | 2 +- library/test/src/formatters/junit.rs | 2 +- library/test/src/term.rs | 2 +- src/librustdoc/html/render/type_layout.rs | 3 +-- src/librustdoc/scrape_examples.rs | 2 +- .../clippy/clippy_lints/src/methods/iter_out_of_bounds.rs | 2 +- src/tools/clippy/clippy_lints/src/methods/manual_contains.rs | 2 +- src/tools/clippy/clippy_lints/src/types/linked_list.rs | 2 +- src/tools/clippy/clippy_lints/src/types/owned_cow.rs | 2 +- src/tools/lld-wrapper/src/main.rs | 3 +-- src/tools/rust-analyzer/crates/base-db/src/lib.rs | 2 +- .../rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs | 2 +- src/tools/rust-analyzer/crates/hir-ty/src/lower.rs | 2 +- .../ide-assists/src/handlers/promote_local_to_const.rs | 2 +- .../rust-analyzer/crates/rust-analyzer/src/tracing/config.rs | 2 +- 43 files changed, 44 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index 941885d232c27..e35c10996ceb2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -9,7 +9,7 @@ use rustc_hir::{ use super::prelude::*; use super::util::parse_version; -use crate::session_diagnostics::{self}; +use crate::session_diagnostics; macro_rules! reject_outside_std { ($cx: ident) => { diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index e98969dda300b..987c0cb04c84d 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -1,6 +1,6 @@ use std::num::IntErrorKind; -use rustc_ast::{self as ast}; +use rustc_ast as ast; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs index 423b6a15b646d..b294328b0bb17 100644 --- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs +++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs @@ -1,6 +1,6 @@ //! Attributes injected into the crate root from command line using `-Z crate-attr`. -use rustc_ast::{self as ast}; +use rustc_ast as ast; use rustc_errors::Diag; use rustc_parse::parser::attr::InnerAttrPolicy; use rustc_parse::{parse_in, source_str_to_stream}; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs index 4ecc3086e1bdf..348c54b00ba97 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs @@ -21,8 +21,8 @@ use crate::debuginfo::metadata::{ size_and_align_of, type_di_node, unknown_file_metadata, visibility_di_flags, }; use crate::debuginfo::utils::DIB; +use crate::llvm; use crate::llvm::debuginfo::{DIFile, DIFlags, DIType}; -use crate::llvm::{self}; // The names of the associated constants in each variant wrapper struct. // These have to match up with the names being used in `intrinsic.natvis`. diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs index caff358607974..556158c286a84 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs @@ -21,8 +21,8 @@ use crate::debuginfo::metadata::{ file_metadata_from_def_id, type_di_node, unknown_file_metadata, }; use crate::debuginfo::utils::{DIB, create_DIArray, get_namespace_for_item}; +use crate::llvm; use crate::llvm::debuginfo::{DIFlags, DIType}; -use crate::llvm::{self}; mod cpp_like; mod native; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs index 1ae6e6e5eecab..a3299af35ac21 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs @@ -5,9 +5,8 @@ use rustc_abi::{Size, TagEncoding, VariantIdx, Variants}; use rustc_codegen_ssa::debuginfo::type_names::compute_debuginfo_type_name; use rustc_codegen_ssa::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo}; use rustc_codegen_ssa::traits::{ConstCodegenMethods, MiscCodegenMethods}; -use rustc_middle::bug; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; -use rustc_middle::ty::{self}; +use rustc_middle::{bug, ty}; use smallvec::smallvec; use crate::common::{AsCCharPtr, CodegenCx}; @@ -18,8 +17,8 @@ use crate::debuginfo::metadata::{ unknown_file_metadata, visibility_di_flags, }; use crate::debuginfo::utils::{DIB, create_DIArray, get_namespace_for_item}; +use crate::llvm; use crate::llvm::debuginfo::{DIFile, DIFlags, DIType}; -use crate::llvm::{self}; /// Build the debuginfo node for an enum type. The listing below shows how such a /// type looks like at the LLVM IR/DWARF level. It is a `DW_TAG_structure_type` diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs index 37200fdc41afa..316ec9cb73e78 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs @@ -12,8 +12,8 @@ use rustc_middle::ty::{self, ExistentialTraitRef, Ty, TyCtxt}; use super::{DefinitionLocation, SmallVec, UNKNOWN_LINE_NUMBER, unknown_file_metadata}; use crate::common::CodegenCx; use crate::debuginfo::utils::{DIB, create_DIArray, debug_context}; +use crate::llvm; use crate::llvm::debuginfo::{DIFlags, DIScope, DIType}; -use crate::llvm::{self}; mod private { use rustc_macros::HashStable; diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 6bcc8135f35e8..854fbbcea3ee1 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -13,8 +13,8 @@ use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue}; use rustc_codegen_ssa::traits::*; use rustc_data_structures::assert_matches; +use rustc_hir as hir; use rustc_hir::def_id::LOCAL_CRATE; -use rustc_hir::{self as hir}; use rustc_middle::mir::BinOp; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, LayoutOf}; use rustc_middle::ty::offload_meta::OffloadMetadata; diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index c10e7f3bfb8b9..f7ecfb6cd09cb 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -2,8 +2,8 @@ use std::cell::OnceCell; use std::ops::ControlFlow; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::graph; use rustc_data_structures::graph::vec_graph::VecGraph; -use rustc_data_structures::graph::{self}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir as hir; use rustc_hir::HirId; diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 22636959f0db5..5e0a9b3d32197 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -44,9 +44,9 @@ use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, Ident, InnerSpan, Span, Symbol, kw, sym}; use rustc_target::asm::InlineAsmArch; use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt}; +use rustc_trait_selection::traits; use rustc_trait_selection::traits::misc::type_allowed_to_implement_copy; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; -use rustc_trait_selection::traits::{self}; use crate::errors::BuiltinEllipsisInclusiveRangePatterns; use crate::lints::{ diff --git a/compiler/rustc_lint/src/map_unit_fn.rs b/compiler/rustc_lint/src/map_unit_fn.rs index 18a947dc1ee06..50471b40ecdea 100644 --- a/compiler/rustc_lint/src/map_unit_fn.rs +++ b/compiler/rustc_lint/src/map_unit_fn.rs @@ -1,5 +1,5 @@ use rustc_hir::{Expr, ExprKind, Stmt, StmtKind}; -use rustc_middle::ty::{self}; +use rustc_middle::ty; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::sym; diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs index 6ef9d4e9769ce..6052a16a7f117 100644 --- a/compiler/rustc_lint/src/reference_casting.rs +++ b/compiler/rustc_lint/src/reference_casting.rs @@ -1,7 +1,7 @@ use rustc_ast::Mutability; use rustc_hir::{Expr, ExprKind, UnOp}; +use rustc_middle::ty; use rustc_middle::ty::layout::{LayoutOf as _, TyAndLayout}; -use rustc_middle::ty::{self}; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::sym; diff --git a/compiler/rustc_lint/src/transmute.rs b/compiler/rustc_lint/src/transmute.rs index b55d209130b02..570f069eeee94 100644 --- a/compiler/rustc_lint/src/transmute.rs +++ b/compiler/rustc_lint/src/transmute.rs @@ -1,8 +1,8 @@ use rustc_ast::LitKind; use rustc_errors::Applicability; +use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::LocalDefId; -use rustc_hir::{self as hir}; use rustc_macros::Diagnostic; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint, impl_lint_pass}; diff --git a/compiler/rustc_lint/src/unqualified_local_imports.rs b/compiler/rustc_lint/src/unqualified_local_imports.rs index 0076cae3cff3c..d3aff05123763 100644 --- a/compiler/rustc_lint/src/unqualified_local_imports.rs +++ b/compiler/rustc_lint/src/unqualified_local_imports.rs @@ -1,4 +1,4 @@ -use rustc_hir::{self as hir}; +use rustc_hir as hir; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::kw; diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 4856df3a6222a..5f78f414a742a 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -21,9 +21,8 @@ use crate::arena::ArenaAllocatable; use crate::infer::canonical::{CanonicalVarKind, CanonicalVarKinds}; use crate::mir::interpret::{AllocId, ConstAllocation, CtfeProvenance}; use crate::mir::mono::MonoItem; -use crate::mir::{self}; -use crate::traits; use crate::ty::{self, AdtDef, GenericArgsRef, Ty, TyCtxt}; +use crate::{mir, traits}; /// The shorthand encoding uses an enum's variant index `usize` /// and is offset by this value so it never matches a real variant. diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index a4aeaacbf05db..317efbd777b1d 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -5,10 +5,10 @@ use std::fmt; use rustc_abi::ExternAbi; use rustc_data_structures::debug_assert_matches; use rustc_errors::ErrorGuaranteed; +use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; -use rustc_hir::{self as hir}; use rustc_span::{DUMMY_SP, Span, Symbol}; use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem}; use rustc_type_ir::{CollectAndApply, Interner, TypeFoldable, search_graph}; diff --git a/compiler/rustc_middle/src/ty/pattern.rs b/compiler/rustc_middle/src/ty/pattern.rs index 6acf0aff800fd..935e5da68e823 100644 --- a/compiler/rustc_middle/src/ty/pattern.rs +++ b/compiler/rustc_middle/src/ty/pattern.rs @@ -3,9 +3,7 @@ use std::fmt; use rustc_data_structures::intern::Interned; use rustc_macros::HashStable; use rustc_type_ir::ir_print::IrPrint; -use rustc_type_ir::{ - FlagComputation, Flags, {self as ir}, -}; +use rustc_type_ir::{self as ir, FlagComputation, Flags}; use super::TyCtxt; use crate::ty; diff --git a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs index ed5f0b2e8f759..ad6c1f7dce5b8 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs @@ -1,7 +1,7 @@ //! See docs in builder/expr/mod.rs use rustc_abi::Size; -use rustc_ast::{self as ast}; +use rustc_ast as ast; use rustc_hir::LangItem; use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, Scalar}; use rustc_middle::mir::*; diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs index 667a702e40565..03c459c312b67 100644 --- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs +++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs @@ -23,8 +23,8 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex}; use rustc_mir_dataflow::{Analysis, MaybeReachable, ResultsCursor}; +use rustc_session::lint; use rustc_session::lint::builtin::TAIL_EXPR_DROP_ORDER; -use rustc_session::lint::{self}; use rustc_span::{DUMMY_SP, Span, Symbol}; use tracing::debug; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 69610d062919d..8c34c1f24f732 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2,11 +2,11 @@ use std::fmt::Write; use std::mem; use ast::token::IdentIsRaw; +use rustc_ast as ast; use rustc_ast::ast::*; use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_ast::util::case::Case; -use rustc_ast::{self as ast}; use rustc_ast_pretty::pprust; use rustc_errors::codes::*; use rustc_errors::{Applicability, PResult, StashKey, msg, struct_span_code_err}; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 45cbc0b3c828d..b88227264537f 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -25,7 +25,7 @@ use std::cell::Ref; use std::collections::BTreeSet; -use std::fmt::{self}; +use std::fmt; use std::ops::ControlFlow; use std::sync::Arc; diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 165e563ebad50..22342a956710f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -53,11 +53,11 @@ use std::{cmp, fmt, iter}; use rustc_abi::ExternAbi; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::{Applicability, Diag, DiagStyledString, IntoDiagArg, StringPart, pluralize}; +use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; -use rustc_hir::{self as hir}; use rustc_infer::infer::DefineOpaqueTypes; use rustc_macros::extension; use rustc_middle::bug; diff --git a/library/alloc/src/vec/drain.rs b/library/alloc/src/vec/drain.rs index 8705a9c3d2679..9a6bfa823f2a5 100644 --- a/library/alloc/src/vec/drain.rs +++ b/library/alloc/src/vec/drain.rs @@ -1,8 +1,7 @@ -use core::fmt; use core::iter::{FusedIterator, TrustedLen}; use core::mem::{self, ManuallyDrop, SizedTypeProperties}; use core::ptr::{self, NonNull}; -use core::slice::{self}; +use core::{fmt, slice}; use super::Vec; use crate::alloc::{Allocator, Global}; diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index af1bd53179739..4f67a2c04fefc 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -9,8 +9,7 @@ use core::num::NonZero; use core::ops::Deref; use core::panic::UnwindSafe; use core::ptr::{self, NonNull}; -use core::slice::{self}; -use core::{array, fmt}; +use core::{array, fmt, slice}; #[cfg(not(no_global_oom_handling))] use super::AsVecIntoIter; diff --git a/library/alloc/src/vec/spec_extend.rs b/library/alloc/src/vec/spec_extend.rs index 7c908841c90ec..de6ef3d803263 100644 --- a/library/alloc/src/vec/spec_extend.rs +++ b/library/alloc/src/vec/spec_extend.rs @@ -1,6 +1,6 @@ use core::clone::TrivialClone; use core::iter::TrustedLen; -use core::slice::{self}; +use core::slice; use super::{IntoIter, Vec}; use crate::alloc::Allocator; diff --git a/library/alloc/src/vec/spec_from_iter.rs b/library/alloc/src/vec/spec_from_iter.rs index e1f0b639bdfd6..ccbc2936fb4e8 100644 --- a/library/alloc/src/vec/spec_from_iter.rs +++ b/library/alloc/src/vec/spec_from_iter.rs @@ -1,5 +1,5 @@ use core::mem::ManuallyDrop; -use core::ptr::{self}; +use core::ptr; use super::{IntoIter, SpecExtend, SpecFromIterNested, Vec}; diff --git a/library/alloc/src/vec/splice.rs b/library/alloc/src/vec/splice.rs index 46611f611dc2c..3eb8ca44a9d14 100644 --- a/library/alloc/src/vec/splice.rs +++ b/library/alloc/src/vec/splice.rs @@ -1,5 +1,4 @@ -use core::ptr::{self}; -use core::slice::{self}; +use core::{ptr, slice}; use super::{Drain, Vec}; use crate::alloc::{Allocator, Global}; diff --git a/library/coretests/tests/cmp.rs b/library/coretests/tests/cmp.rs index 55e35a4a7250e..0a14470060c3d 100644 --- a/library/coretests/tests/cmp.rs +++ b/library/coretests/tests/cmp.rs @@ -1,5 +1,5 @@ +use core::cmp; use core::cmp::Ordering::{self, *}; -use core::cmp::{self}; #[test] fn test_int_totalord() { diff --git a/library/coretests/tests/iter/adapters/array_chunks.rs b/library/coretests/tests/iter/adapters/array_chunks.rs index e6e279b14e626..480d3138bdb35 100644 --- a/library/coretests/tests/iter/adapters/array_chunks.rs +++ b/library/coretests/tests/iter/adapters/array_chunks.rs @@ -1,4 +1,4 @@ -use core::iter::{self}; +use core::iter; use super::*; diff --git a/library/test/src/formatters/junit.rs b/library/test/src/formatters/junit.rs index 74d99e0f1270e..2772222a05c9a 100644 --- a/library/test/src/formatters/junit.rs +++ b/library/test/src/formatters/junit.rs @@ -1,5 +1,5 @@ +use std::io; use std::io::prelude::Write; -use std::io::{self}; use std::time::Duration; use super::OutputFormatter; diff --git a/library/test/src/term.rs b/library/test/src/term.rs index d9880a776406d..1e4c7bc879cf7 100644 --- a/library/test/src/term.rs +++ b/library/test/src/term.rs @@ -12,8 +12,8 @@ #![deny(missing_docs)] +use std::io; use std::io::prelude::*; -use std::io::{self}; pub(crate) use terminfo::TerminfoTerminal; #[cfg(windows)] diff --git a/src/librustdoc/html/render/type_layout.rs b/src/librustdoc/html/render/type_layout.rs index fb1f0271c2ad7..5d5b8d5df685b 100644 --- a/src/librustdoc/html/render/type_layout.rs +++ b/src/librustdoc/html/render/type_layout.rs @@ -3,9 +3,8 @@ use std::fmt; use askama::Template; use rustc_abi::{Primitive, TagEncoding, Variants}; use rustc_hir::def_id::DefId; -use rustc_middle::span_bug; use rustc_middle::ty::layout::LayoutError; -use rustc_middle::ty::{self}; +use rustc_middle::{span_bug, ty}; use rustc_span::symbol::Symbol; use crate::html::render::Context; diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index 1b3c96d82b410..cc78dec4eafa3 100644 --- a/src/librustdoc/scrape_examples.rs +++ b/src/librustdoc/scrape_examples.rs @@ -5,8 +5,8 @@ use std::path::PathBuf; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::DiagCtxtHandle; +use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{self as hir}; use rustc_macros::{Decodable, Encodable}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, TyCtxt}; diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs b/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs index f7d7df267967b..a8ea43cf73e32 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs @@ -5,7 +5,7 @@ use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_middle::ty::{self}; +use rustc_middle::ty; use super::ITER_OUT_OF_BOUNDS; diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_contains.rs b/src/tools/clippy/clippy_lints/src/methods/manual_contains.rs index 8ba0f835d3ddc..d2906b2776f8c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_contains.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_contains.rs @@ -8,7 +8,7 @@ use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{BinOpKind, Body, Expr, ExprKind, HirId, QPath}; use rustc_lint::LateContext; -use rustc_middle::ty::{self}; +use rustc_middle::ty; use rustc_span::source_map::Spanned; use super::MANUAL_CONTAINS; diff --git a/src/tools/clippy/clippy_lints/src/types/linked_list.rs b/src/tools/clippy/clippy_lints/src/types/linked_list.rs index 96126d3d4320a..abd6138655d76 100644 --- a/src/tools/clippy/clippy_lints/src/types/linked_list.rs +++ b/src/tools/clippy/clippy_lints/src/types/linked_list.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::sym; use rustc_hir::def_id::DefId; -use rustc_hir::{self as hir}; +use rustc_hir as hir; use rustc_lint::LateContext; use super::LINKEDLIST; diff --git a/src/tools/clippy/clippy_lints/src/types/owned_cow.rs b/src/tools/clippy/clippy_lints/src/types/owned_cow.rs index e70348b481c8e..3a806cfef691e 100644 --- a/src/tools/clippy/clippy_lints/src/types/owned_cow.rs +++ b/src/tools/clippy/clippy_lints/src/types/owned_cow.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet_opt; use clippy_utils::sym; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; -use rustc_hir::{self as hir}; +use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::Span; diff --git a/src/tools/lld-wrapper/src/main.rs b/src/tools/lld-wrapper/src/main.rs index 2f756ae3022f6..299f0329b940e 100644 --- a/src/tools/lld-wrapper/src/main.rs +++ b/src/tools/lld-wrapper/src/main.rs @@ -12,10 +12,9 @@ //! On Windows it spawns a `..\rust-lld.exe` child process. use std::env::consts::EXE_SUFFIX; -use std::env::{self}; use std::fmt::Display; use std::path::{Path, PathBuf}; -use std::process; +use std::{env, process}; trait UnwrapOrExitWith { fn unwrap_or_exit_with(self, context: &str) -> T; diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index 24f6dd59a9c50..5baf4ce6f907f 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -32,7 +32,7 @@ pub use crate::{ }, }; use dashmap::{DashMap, mapref::entry::Entry}; -pub use query_group::{self}; +pub use query_group; use rustc_hash::{FxHashSet, FxHasher}; use salsa::{Durability, Setter}; pub use semver::{BuildMetadata, Prerelease, Version, VersionReq}; diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs index 3029bca1d51fe..ae8eef2bbb5d9 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs @@ -7,7 +7,7 @@ use cfg::CfgExpr; use either::Either; use intern::{ Symbol, - sym::{self}, + sym, }; use itertools::Itertools; use mbe::{DelimiterKind, expect_fragment}; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index 1290874177ac4..a0945c3bdce66 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -40,7 +40,7 @@ use rustc_hash::FxHashSet; use rustc_type_ir::{ AliasTyKind, BoundVarIndexKind, ConstKind, DebruijnIndex, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, Interner, OutlivesPredicate, TermKind, - TyKind::{self}, + TyKind, TypeFoldable, TypeVisitableExt, Upcast, UpcastFrom, elaborate, inherent::{Clause as _, GenericArgs as _, IntoKind as _, Region as _, Ty as _}, }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs index 547d3686e3909..483c90d1032e5 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/promote_local_to_const.rs @@ -8,7 +8,7 @@ use syntax::{ use crate::{ assist_context::{AssistContext, Assists}, - utils::{self}, + utils, }; // Assist: promote_local_to_const diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs index ca897aeb3eed6..2bc9f3c34a5ba 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs @@ -1,7 +1,7 @@ //! Simple logger that logs either to stderr or to a file, using `tracing_subscriber` //! filter syntax and `tracing_appender` for non blocking output. -use std::io::{self}; +use std::io; use anyhow::Context; use tracing::level_filters::LevelFilter; From 696a7a1f04ce7969a80ea5be45195d32d705ed72 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 25 Feb 2026 08:09:43 -0800 Subject: [PATCH 18/19] Simplify `AppendOnlyVec` iterators --- compiler/rustc_data_structures/src/sync/vec.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_data_structures/src/sync/vec.rs b/compiler/rustc_data_structures/src/sync/vec.rs index afbb0cef9f956..d35e2c61f1e19 100644 --- a/compiler/rustc_data_structures/src/sync/vec.rs +++ b/compiler/rustc_data_structures/src/sync/vec.rs @@ -46,20 +46,17 @@ impl AppendOnlyVec { } pub fn iter_enumerated(&self) -> impl Iterator { - (0..) - .map(|i| (i, self.get(i))) - .take_while(|(_, o)| o.is_some()) - .filter_map(|(i, o)| Some((i, o?))) + (0..).map_while(|i| Some((i, self.get(i)?))) } pub fn iter(&self) -> impl Iterator { - (0..).map(|i| self.get(i)).take_while(|o| o.is_some()).flatten() + (0..).map_while(|i| self.get(i)) } } impl AppendOnlyVec { pub fn contains(&self, val: T) -> bool { - self.iter_enumerated().any(|(_, v)| v == val) + self.iter().any(|v| v == val) } } From 8fcf512f36bf41ec32a200282fdd7fd763aab4f4 Mon Sep 17 00:00:00 2001 From: arferreira Date: Wed, 25 Feb 2026 17:06:08 -0500 Subject: [PATCH 19/19] Refactor url_parts to return is_absolute instead of out param --- src/librustdoc/html/format.rs | 43 +++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 30dacde94cf03..2070a24f60c81 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -459,15 +459,15 @@ fn generate_item_def_id_path( let shortty = ItemType::from_def_id(def_id, tcx); let module_fqp = to_module_fqp(shortty, &fqp); - let mut is_absolute = false; - let url_parts = url_parts(cx.cache(), def_id, module_fqp, &cx.current, &mut is_absolute)?; - let mut url_parts = make_href(root_path, shortty, url_parts, &fqp, is_absolute); + let (parts, is_absolute) = url_parts(cx.cache(), def_id, module_fqp, &cx.current)?; + let mut url = make_href(root_path, shortty, parts, &fqp, is_absolute); + if def_id != original_def_id { let kind = ItemType::from_def_id(original_def_id, tcx); - url_parts = format!("{url_parts}#{kind}.{}", tcx.item_name(original_def_id)) + url = format!("{url}#{kind}.{}", tcx.item_name(original_def_id)) }; - Ok(HrefInfo { url: url_parts, kind: shortty, rust_path: fqp }) + Ok(HrefInfo { url, kind: shortty, rust_path: fqp }) } /// Checks if the given defid refers to an item that is unnamable, such as one defined in a const block. @@ -511,16 +511,14 @@ fn url_parts( def_id: DefId, module_fqp: &[Symbol], relative_to: &[Symbol], - is_absolute: &mut bool, -) -> Result { +) -> Result<(UrlPartsBuilder, bool), HrefError> { match cache.extern_locations[&def_id.krate] { - ExternalLocation::Remote { ref url, is_absolute: abs } => { - *is_absolute = abs; - let mut builder = remote_url_prefix(url, abs, relative_to.len()); + ExternalLocation::Remote { ref url, is_absolute } => { + let mut builder = remote_url_prefix(url, is_absolute, relative_to.len()); builder.extend(module_fqp.iter().copied()); - Ok(builder) + Ok((builder, is_absolute)) } - ExternalLocation::Local => Ok(href_relative_parts(module_fqp, relative_to)), + ExternalLocation::Local => Ok((href_relative_parts(module_fqp, relative_to), false)), ExternalLocation::Unknown => Err(HrefError::DocumentationNotBuilt), } } @@ -596,13 +594,17 @@ pub(crate) fn href_with_root_path( } } - let mut is_absolute = false; - let (fqp, shortty, url_parts) = match cache.paths.get(&did) { - Some(&(ref fqp, shortty)) => (fqp, shortty, { - let module_fqp = to_module_fqp(shortty, fqp.as_slice()); - debug!(?fqp, ?shortty, ?module_fqp); - href_relative_parts(module_fqp, relative_to) - }), + let (fqp, shortty, url_parts, is_absolute) = match cache.paths.get(&did) { + Some(&(ref fqp, shortty)) => ( + fqp, + shortty, + { + let module_fqp = to_module_fqp(shortty, fqp.as_slice()); + debug!(?fqp, ?shortty, ?module_fqp); + href_relative_parts(module_fqp, relative_to) + }, + false, + ), None => { // Associated items are handled differently with "jump to def". The anchor is generated // directly here whereas for intra-doc links, we have some extra computation being @@ -610,7 +612,8 @@ pub(crate) fn href_with_root_path( let def_id_to_get = if root_path.is_some() { original_did } else { did }; if let Some(&(ref fqp, shortty)) = cache.external_paths.get(&def_id_to_get) { let module_fqp = to_module_fqp(shortty, fqp); - (fqp, shortty, url_parts(cache, did, module_fqp, relative_to, &mut is_absolute)?) + let (parts, is_absolute) = url_parts(cache, did, module_fqp, relative_to)?; + (fqp, shortty, parts, is_absolute) } else if matches!(def_kind, DefKind::Macro(_)) { return generate_macro_def_id_path(did, cx, root_path); } else if did.is_local() {